3 * Copyright (c) 2015 Steven Barth <cyrus@openwrt.org>
4 * Copyright (c) 2017 Hans Dedecker <dedeckeh@gmail.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 #include <netinet/icmp6.h>
17 #include <netinet/in.h>
18 #include <sys/socket.h>
19 #include <arpa/inet.h>
27 static void sighandler(__attribute__((unused
)) int signal
)
31 int main(int argc
, const char *argv
[])
33 char buf
[INET6_ADDRSTRLEN
], prefix
[INET6_ADDRSTRLEN
+ 4];
37 fprintf(stderr
, "Usage: %s <name> [ifname] [ipv6prefix] [ipv4addr] [ipv6addr]\n", argv
[0]);
41 snprintf(buf
, sizeof(buf
), "/var/run/%s.pid", argv
[1]);
42 FILE *fp
= fopen(buf
, "r");
44 if (fscanf(fp
, "%d", &pid
) == 1)
54 if (!argv
[3] || !argv
[4] || !(fp
= fopen(buf
, "wx")))
57 signal(SIGTERM
, SIG_DFL
);
58 setvbuf(fp
, NULL
, _IOLBF
, 0);
59 fprintf(fp
, "%d\n", getpid());
61 prefix
[sizeof(prefix
) - 1] = 0;
62 strncpy(prefix
, argv
[3], sizeof(prefix
) - 1);
65 struct addrinfo hints
= { .ai_family
= AF_INET6
}, *res
;
66 if (getaddrinfo("ipv4only.arpa", NULL
, &hints
, &res
) || !res
) {
68 if (getaddrinfo("ipv4only.arpa", NULL
, &hints
, &res
) || !res
)
72 struct sockaddr_in6
*sin6
= (struct sockaddr_in6
*)res
->ai_addr
;
73 inet_ntop(AF_INET6
, &sin6
->sin6_addr
, prefix
, sizeof(prefix
) - 4);
74 strcat(prefix
, "/96");
80 struct sockaddr_in6 saddr
;
83 socklen_t saddrlen
= sizeof(saddr
);
84 struct icmp6_filter filt
;
86 sock
= socket(AF_INET6
, SOCK_RAW
, IPPROTO_ICMPV6
);
87 ICMP6_FILTER_SETBLOCKALL(&filt
);
88 setsockopt(sock
, IPPROTO_ICMPV6
, ICMP6_FILTER
, &filt
, sizeof(filt
));
89 setsockopt(sock
, SOL_SOCKET
, SO_BINDTODEVICE
, argv
[2], strlen(argv
[2]));
90 memset(&saddr
, 0, sizeof(saddr
));
91 saddr
.sin6_family
= AF_INET6
;
92 saddr
.sin6_addr
.s6_addr32
[0] = htonl(0x2001);
93 saddr
.sin6_addr
.s6_addr32
[1] = htonl(0xdb8);
94 if (connect(sock
, (struct sockaddr
*)&saddr
, sizeof(saddr
)) ||
95 getsockname(sock
, (struct sockaddr
*)&saddr
, &saddrlen
))
98 if (!IN6_IS_ADDR_LINKLOCAL(&saddr
.sin6_addr
) || argv
[5])
106 struct ipv6_mreq mreq
= {saddr
.sin6_addr
, if_nametoindex(argv
[2])};
108 if (IN6_IS_ADDR_LINKLOCAL(&mreq
.ipv6mr_multiaddr
))
111 srandom(mreq
.ipv6mr_multiaddr
.s6_addr32
[0] ^ mreq
.ipv6mr_multiaddr
.s6_addr32
[1] ^
112 mreq
.ipv6mr_multiaddr
.s6_addr32
[2] ^ mreq
.ipv6mr_multiaddr
.s6_addr32
[3]);
113 mreq
.ipv6mr_multiaddr
.s6_addr32
[2] = random();
114 mreq
.ipv6mr_multiaddr
.s6_addr32
[3] = random();
115 } else if (inet_pton(AF_INET6
, argv
[5], &mreq
.ipv6mr_multiaddr
) != 1) {
119 if (setsockopt(sock
, SOL_IPV6
, IPV6_JOIN_ANYCAST
, &mreq
, sizeof(mreq
)))
122 inet_ntop(AF_INET6
, &mreq
.ipv6mr_multiaddr
, buf
, sizeof(buf
));
127 FILE *nat46
= fopen("/proc/net/nat46/control", "w");
128 if (!nat46
|| fprintf(nat46
, "add %s\nconfig %s local.style NONE local.v4 %s/32 local.v6 %s/128 "
129 "remote.style RFC6052 remote.v6 %s\n", argv
[1], argv
[1], argv
[4], buf
, prefix
) < 0 ||
133 if (!(pid
= fork())) {
140 signal(SIGTERM
, sighandler
);
143 nat46
= fopen("/proc/net/nat46/control", "w");
145 fprintf(nat46
, "del %s\n", argv
[1]);
150 fprintf(fp
, "%d\n", pid
);