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");
76 struct sockaddr_in6 saddr
;
79 socklen_t saddrlen
= sizeof(saddr
);
80 struct icmp6_filter filt
;
82 sock
= socket(AF_INET6
, SOCK_RAW
, IPPROTO_ICMPV6
);
83 ICMP6_FILTER_SETBLOCKALL(&filt
);
84 setsockopt(sock
, IPPROTO_ICMPV6
, ICMP6_FILTER
, &filt
, sizeof(filt
));
85 setsockopt(sock
, SOL_SOCKET
, SO_BINDTODEVICE
, argv
[2], strlen(argv
[2]));
86 memset(&saddr
, 0, sizeof(saddr
));
87 saddr
.sin6_family
= AF_INET6
;
88 saddr
.sin6_addr
.s6_addr32
[0] = htonl(0x2001);
89 saddr
.sin6_addr
.s6_addr32
[1] = htonl(0xdb8);
90 if (connect(sock
, (struct sockaddr
*)&saddr
, sizeof(saddr
)) ||
91 getsockname(sock
, (struct sockaddr
*)&saddr
, &saddrlen
))
94 if (!IN6_IS_ADDR_LINKLOCAL(&saddr
.sin6_addr
) || argv
[5])
102 struct ipv6_mreq mreq
= {saddr
.sin6_addr
, if_nametoindex(argv
[2])};
104 if (IN6_IS_ADDR_LINKLOCAL(&mreq
.ipv6mr_multiaddr
))
107 srandom(mreq
.ipv6mr_multiaddr
.s6_addr32
[0] ^ mreq
.ipv6mr_multiaddr
.s6_addr32
[1] ^
108 mreq
.ipv6mr_multiaddr
.s6_addr32
[2] ^ mreq
.ipv6mr_multiaddr
.s6_addr32
[3]);
109 mreq
.ipv6mr_multiaddr
.s6_addr32
[2] = random();
110 mreq
.ipv6mr_multiaddr
.s6_addr32
[3] = random();
111 } else if (inet_pton(AF_INET6
, argv
[5], &mreq
.ipv6mr_multiaddr
) != 1) {
115 if (setsockopt(sock
, SOL_IPV6
, IPV6_JOIN_ANYCAST
, &mreq
, sizeof(mreq
)))
118 inet_ntop(AF_INET6
, &mreq
.ipv6mr_multiaddr
, buf
, sizeof(buf
));
123 FILE *nat46
= fopen("/proc/net/nat46/control", "w");
124 if (!nat46
|| fprintf(nat46
, "add %s\nconfig %s local.style NONE local.v4 %s/32 local.v6 %s/128 "
125 "remote.style RFC6052 remote.v6 %s\n", argv
[1], argv
[1], argv
[4], buf
, prefix
) < 0 ||
129 if (!(pid
= fork())) {
138 nat46
= fopen("/proc/net/nat46/control", "w");
140 fprintf(nat46
, "del %s\n", argv
[1]);
144 fprintf(fp
, "%d\n", pid
);