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 static void sighandler(__attribute__((unused
)) int signal
)
30 int main(int argc
, const char *argv
[])
32 char buf
[INET6_ADDRSTRLEN
], prefix
[INET6_ADDRSTRLEN
+ 4];
36 fprintf(stderr
, "Usage: %s <name> [ifname] [ipv6prefix] [ipv4addr] [ipv6addr]\n", argv
[0]);
40 snprintf(buf
, sizeof(buf
), "/var/run/%s.pid", argv
[1]);
41 FILE *fp
= fopen(buf
, "r");
43 fscanf(fp
, "%d", &pid
);
52 if (!argv
[3] || !argv
[4] || !(fp
= fopen(buf
, "wx")))
55 signal(SIGTERM
, sighandler
);
57 prefix
[sizeof(prefix
) - 1] = 0;
58 strncpy(prefix
, argv
[3], sizeof(prefix
) - 1);
61 struct addrinfo hints
= { .ai_family
= AF_INET6
}, *res
;
62 if (getaddrinfo("ipv4only.arpa", NULL
, &hints
, &res
) || !res
) {
64 if (getaddrinfo("ipv4only.arpa", NULL
, &hints
, &res
) || !res
)
68 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)res
->ai_addr
;
69 inet_ntop(AF_INET6
, &sin6
->sin6_addr
, prefix
, sizeof(prefix
) - 4);
70 strcat(prefix
, "/96");
74 struct sockaddr_in6 saddr
= {.sin6_family
= AF_INET6
, .sin6_addr
= {{{0x20, 0x01, 0x0d, 0xb8}}}};
75 socklen_t saddrlen
= sizeof(saddr
);
76 int sock
= socket(AF_INET6
, SOCK_RAW
, IPPROTO_ICMPV6
);
77 struct icmp6_filter filt
;
78 ICMP6_FILTER_SETBLOCKALL(&filt
);
79 setsockopt(sock
, IPPROTO_ICMPV6
, ICMP6_FILTER
, &filt
, sizeof(filt
));
80 setsockopt(sock
, SOL_SOCKET
, SO_BINDTODEVICE
, argv
[2], strlen(argv
[2]));
81 if (connect(sock
, (struct sockaddr
*)&saddr
, sizeof(saddr
)) ||
82 getsockname(sock
, (struct sockaddr
*)&saddr
, &saddrlen
))
85 struct ipv6_mreq mreq
= {saddr
.sin6_addr
, if_nametoindex(argv
[2])};
87 srandom(mreq
.ipv6mr_multiaddr
.s6_addr32
[0] ^ mreq
.ipv6mr_multiaddr
.s6_addr32
[1] ^
88 mreq
.ipv6mr_multiaddr
.s6_addr32
[2] ^ mreq
.ipv6mr_multiaddr
.s6_addr32
[3]);
89 mreq
.ipv6mr_multiaddr
.s6_addr32
[2] = random();
90 mreq
.ipv6mr_multiaddr
.s6_addr32
[3] = random();
91 } else if (inet_pton(AF_INET6
, argv
[5], &mreq
.ipv6mr_multiaddr
) != 1) {
95 if (setsockopt(sock
, SOL_IPV6
, IPV6_JOIN_ANYCAST
, &mreq
, sizeof(mreq
)))
98 inet_ntop(AF_INET6
, &mreq
.ipv6mr_multiaddr
, buf
, sizeof(buf
));
103 FILE *nat46
= fopen("/proc/net/nat46/control", "w");
104 if (!nat46
|| fprintf(nat46
, "add %s\nconfig %s local.style NONE local.v4 %s/32 local.v6 %s/128 "
105 "remote.style RFC6052 remote.v6 %s\n", argv
[1], argv
[1], argv
[4], buf
, prefix
) < 0 ||
109 if (!(pid
= fork())) {
118 nat46
= fopen("/proc/net/nat46/control", "w");
120 fprintf(nat46
, "del %s\n", argv
[1]);
124 fprintf(fp
, "%d\n", pid
);