3 * Copyright (c) 2015 Steven Barth <cyrus@openwrt.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2
7 * as published by the Free Software Foundation
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
15 #include <netinet/icmp6.h>
16 #include <netinet/in.h>
17 #include <sys/socket.h>
18 #include <arpa/inet.h>
26 int main(int argc
, const char *argv
[])
28 char buf
[INET6_ADDRSTRLEN
], prefix
[INET6_ADDRSTRLEN
+ 4];
32 fprintf(stderr
, "Usage: %s <name> [ifname] [ipv6prefix] [ipv4addr] [ipv6addr]\n", argv
[0]);
36 snprintf(buf
, sizeof(buf
), "/var/run/%s.pid", argv
[1]);
37 FILE *fp
= fopen(buf
, "r");
39 fscanf(fp
, "%d", &pid
);
48 if (!argv
[3] || !argv
[4] || !(fp
= fopen(buf
, "wx")))
51 prefix
[sizeof(prefix
) - 1] = 0;
52 strncpy(prefix
, argv
[3], sizeof(prefix
) - 1);
55 struct addrinfo hints
= { .ai_family
= AF_INET6
}, *res
;
56 if (getaddrinfo("ipv4only.arpa", NULL
, &hints
, &res
) || !res
) {
58 if (getaddrinfo("ipv4only.arpa", NULL
, &hints
, &res
) || !res
)
62 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)res
->ai_addr
;
63 inet_ntop(AF_INET6
, &sin6
->sin6_addr
, prefix
, sizeof(prefix
) - 4);
64 strcat(prefix
, "/96");
68 struct sockaddr_in6 saddr
= {.sin6_family
= AF_INET6
, .sin6_addr
= {{{0x20, 0x01, 0x0d, 0xb8}}}};
69 socklen_t saddrlen
= sizeof(saddr
);
70 int sock
= socket(AF_INET6
, SOCK_RAW
, IPPROTO_ICMPV6
);
71 struct icmp6_filter filt
;
72 ICMP6_FILTER_SETBLOCKALL(&filt
);
73 setsockopt(sock
, IPPROTO_ICMPV6
, ICMP6_FILTER
, &filt
, sizeof(filt
));
74 setsockopt(sock
, SOL_SOCKET
, SO_BINDTODEVICE
, argv
[2], strlen(argv
[2]));
75 if (connect(sock
, (struct sockaddr
*)&saddr
, sizeof(saddr
)) ||
76 getsockname(sock
, (struct sockaddr
*)&saddr
, &saddrlen
))
79 struct ipv6_mreq mreq
= {saddr
.sin6_addr
, if_nametoindex(argv
[2])};
81 srandom(mreq
.ipv6mr_multiaddr
.s6_addr32
[0] ^ mreq
.ipv6mr_multiaddr
.s6_addr32
[1] ^
82 mreq
.ipv6mr_multiaddr
.s6_addr32
[2] ^ mreq
.ipv6mr_multiaddr
.s6_addr32
[3]);
83 mreq
.ipv6mr_multiaddr
.s6_addr32
[2] = random();
84 mreq
.ipv6mr_multiaddr
.s6_addr32
[3] = random();
85 } else if (inet_pton(AF_INET6
, argv
[5], &mreq
.ipv6mr_multiaddr
) != 1) {
89 if (setsockopt(sock
, SOL_IPV6
, IPV6_JOIN_ANYCAST
, &mreq
, sizeof(mreq
)))
92 inet_ntop(AF_INET6
, &mreq
.ipv6mr_multiaddr
, buf
, sizeof(buf
));
97 FILE *nat46
= fopen("/proc/net/nat46/control", "w");
98 if (!nat46
|| fprintf(nat46
, "add %s\nconfig %s local.style NONE local.v4 %s/32 local.v6 %s/128 "
99 "remote.style RFC6052 remote.v6 %s\n", argv
[1], argv
[1], argv
[4], buf
, prefix
) < 0 ||
103 if (!(pid
= fork())) {
112 fprintf(fp
, "%d\n", pid
);