6in4.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /*
  2. * 6in4 - tunnel client for automatic 6to4 or configured v6-in-v4 tunnels
  3. */
  4. #include <u.h>
  5. #include <libc.h>
  6. #include <ip.h>
  7. enum {
  8. IP_IPV6PROTO = 41,
  9. V6to4pfx = 0x2002,
  10. };
  11. int anysender;
  12. int gateway;
  13. uchar local6[IPaddrlen];
  14. uchar remote6[IPaddrlen];
  15. uchar remote4[IPaddrlen];
  16. uchar localmask[IPaddrlen];
  17. uchar localnet[IPaddrlen];
  18. uchar myip[IPaddrlen];
  19. /* magic anycast address from rfc3068 */
  20. uchar anycast6to4[IPv4addrlen] = { 192, 88, 99, 1 };
  21. static char *net = "/net";
  22. static int badipv4(uchar*);
  23. static int badipv6(uchar*);
  24. static void ip2tunnel(int, int);
  25. static void tunnel2ip(int, int);
  26. static void
  27. usage(void)
  28. {
  29. fprint(2, "usage: %s [-ag] [-x mtpt] [local6[/mask]] [remote4 [remote6]]\n",
  30. argv0);
  31. exits("Usage");
  32. }
  33. void
  34. main(int argc, char **argv)
  35. {
  36. int n, tunnel, ifc, cfd;
  37. char *p, *cl, *ir, *loc6;
  38. char buf[128], path[64];
  39. fmtinstall('I', eipfmt);
  40. fmtinstall('V', eipfmt);
  41. fmtinstall('M', eipfmt);
  42. ARGBEGIN {
  43. case 'a':
  44. anysender++;
  45. break;
  46. case 'g':
  47. gateway++;
  48. break;
  49. case 'x':
  50. net = EARGF(usage());
  51. break;
  52. default:
  53. usage();
  54. } ARGEND
  55. if (myipaddr(myip, net) < 0)
  56. sysfatal("can't find my ipv4 address on %s", net);
  57. if (argc < 1)
  58. loc6 = smprint("%ux:%2.2x%2.2x:%2.2x%2.2x::1/48",
  59. V6to4pfx,
  60. myip[IPaddrlen - IPv4addrlen],
  61. myip[IPaddrlen - IPv4addrlen + 1],
  62. myip[IPaddrlen - IPv4addrlen + 2],
  63. myip[IPaddrlen - IPv4addrlen + 3]);
  64. else {
  65. loc6 = argv[0];
  66. argv++;
  67. argc--;
  68. }
  69. /* local v6 address (mask defaults to /128) */
  70. memcpy(localmask, IPallbits, sizeof localmask);
  71. p = strchr(loc6, '/');
  72. if (p != nil) {
  73. parseipmask(localmask, p);
  74. *p = 0;
  75. }
  76. parseip(local6, loc6);
  77. if (isv4(local6))
  78. usage();
  79. if (argc >= 1 && argv[0][0] == '/') {
  80. parseipmask(localmask, argv[0]);
  81. argv++;
  82. argc--;
  83. }
  84. /* remote v4 address (defaults to anycast 6to4) */
  85. if (argc >= 1) {
  86. parseip(remote4, argv[0]);
  87. if (!isv4(remote4))
  88. usage();
  89. argv++;
  90. argc--;
  91. } else {
  92. v4tov6(remote4, anycast6to4);
  93. anysender++;
  94. }
  95. /* remote v6 address (defaults to link-local w/ v4 as interface part) */
  96. if (argc >= 1) {
  97. parseip(remote6, argv[0]);
  98. if (isv4(remote4))
  99. usage();
  100. argv++;
  101. argc--;
  102. } else {
  103. remote6[0] = 0xFE; /* link local */
  104. remote6[1] = 0x80;
  105. memcpy(remote6 + IPv4off, remote4 + IPv4off, IPv4addrlen);
  106. }
  107. USED(argv);
  108. if (argc != 0)
  109. usage();
  110. maskip(local6, localmask, localnet);
  111. /*
  112. * open IPv6-in-IPv4 tunnel
  113. */
  114. p = seprint(buf, buf + sizeof buf, "ipmux!proto=%2.2x;dst=%V",
  115. IP_IPV6PROTO, myip + IPv4off);
  116. if (!anysender)
  117. seprint(p, buf + sizeof buf, ";src=%V", remote4 + IPv4off);
  118. tunnel = dial(buf, 0, 0, 0);
  119. if (tunnel < 0)
  120. sysfatal("can't make 6in4 tunnel with dial str %s: %r", buf);
  121. /*
  122. * open local IPv6 interface (as a packet interface)
  123. */
  124. cl = smprint("%s/ipifc/clone", net);
  125. cfd = open(cl, ORDWR); /* allocate a conversation */
  126. free(cl);
  127. n = 0;
  128. if (cfd < 0 || (n = read(cfd, buf, sizeof buf - 1)) <= 0)
  129. sysfatal("can't make packet interface: %r");
  130. buf[n] = 0;
  131. snprint(path, sizeof path, "%s/ipifc/%s/data", net, buf);
  132. ifc = open(path, ORDWR);
  133. if (ifc < 0 || fprint(cfd, "bind pkt") < 0)
  134. sysfatal("can't bind packet interface: %r");
  135. /* 1280 is MTU, apparently from rfc2460 */
  136. if (fprint(cfd, "add %I /128 %I 1280", local6, remote6) <= 0)
  137. sysfatal("can't set local ipv6 address: %r");
  138. close(cfd);
  139. if (gateway) {
  140. /* route global addresses through the tunnel to remote6 */
  141. ir = smprint("%s/iproute", net);
  142. cfd = open(ir, OWRITE);
  143. free(ir);
  144. if (cfd < 0 || fprint(cfd, "add 2000:: /3 %I", remote6) <= 0)
  145. sysfatal("can't set default global route: %r");
  146. }
  147. /* run the tunnel copying in the background */
  148. switch (rfork(RFPROC|RFNOWAIT|RFMEM|RFNOTEG)) {
  149. default:
  150. exits(nil);
  151. case 0:
  152. break;
  153. case -1:
  154. sysfatal("rfork");
  155. }
  156. switch (rfork(RFPROC|RFNOWAIT|RFMEM)) {
  157. default:
  158. tunnel2ip(tunnel, ifc);
  159. break;
  160. case 0:
  161. ip2tunnel(ifc, tunnel);
  162. break;
  163. case -1:
  164. sysfatal("rfork");
  165. }
  166. exits("tunnel gone");
  167. }
  168. typedef struct Iphdr Iphdr;
  169. struct Iphdr
  170. {
  171. uchar vihl; /* Version and header length */
  172. uchar tos; /* Type of service */
  173. uchar length[2]; /* packet length */
  174. uchar id[2]; /* Identification */
  175. uchar frag[2]; /* Fragment information */
  176. uchar ttl; /* Time to live */
  177. uchar proto; /* Protocol */
  178. uchar cksum[2]; /* Header checksum */
  179. uchar src[4]; /* Ip source (uchar ordering unimportant) */
  180. uchar dst[4]; /* Ip destination (uchar ordering unimportant) */
  181. };
  182. #define STFHDR (sizeof(Iphdr))
  183. static void
  184. ip2tunnel(int in, int out)
  185. {
  186. int n, m;
  187. char buf[64*1024];
  188. Iphdr *op;
  189. Ip6hdr *ip;
  190. op = (Iphdr*)buf;
  191. op->vihl = 0x45; /* v4, hdr is 5 longs? */
  192. memcpy(op->src, myip + IPv4off, sizeof op->src);
  193. op->proto = IP_IPV6PROTO;
  194. op->ttl = 100;
  195. /* get a V6 packet destined for the tunnel */
  196. while ((n = read(in, buf + STFHDR, sizeof buf - STFHDR)) > 0) {
  197. /* if not IPV6, drop it */
  198. ip = (Ip6hdr*)(buf + STFHDR);
  199. if ((ip->vcf[0]&0xF0) != 0x60)
  200. continue;
  201. /* check length: drop if too short, trim if too long */
  202. m = nhgets(ip->ploadlen) + sizeof(Ip6hdr);
  203. if (m > n)
  204. continue;
  205. if (m < n)
  206. n = m;
  207. /* drop if v6 source or destination address is naughty */
  208. if (badipv6(ip->src) ||
  209. (!equivip6(ip->dst, remote6) && badipv6(ip->dst))) {
  210. syslog(0, "6in4", "egress filtered %I -> %I",
  211. ip->src, ip->dst);
  212. continue;
  213. }
  214. /* send 6to4 packets directly to ipv4 target */
  215. if ((ip->dst[0]<<8 | ip->dst[1]) == V6to4pfx)
  216. memcpy(op->dst, ip->dst+2, sizeof op->dst);
  217. else
  218. memcpy(op->dst, remote4+IPv4off, sizeof op->dst);
  219. n += STFHDR;
  220. /* pass packet to the other end of the tunnel */
  221. if (write(out, op, n) != n) {
  222. syslog(0, "6in4", "error writing to tunnel (%r), giving up");
  223. break;
  224. }
  225. }
  226. }
  227. static void
  228. tunnel2ip(int in, int out)
  229. {
  230. int n, m;
  231. char buf[64*1024];
  232. uchar a[IPaddrlen];
  233. Ip6hdr *op;
  234. Iphdr *ip;
  235. for (;;) {
  236. /* get a packet from the tunnel */
  237. n = read(in, buf, sizeof buf);
  238. ip = (Iphdr*)(buf + IPaddrlen);
  239. n -= IPaddrlen;
  240. if (n <= 0) {
  241. syslog(0, "6in4", "error reading from tunnel (%r), giving up");
  242. break;
  243. }
  244. /* if not IPv4 nor IP protocol IPv6, drop it */
  245. if ((ip->vihl&0xF0) != 0x40 || ip->proto != IP_IPV6PROTO)
  246. continue;
  247. /* check length: drop if too short, trim if too long */
  248. m = nhgets(ip->length);
  249. if (m > n)
  250. continue;
  251. if (m < n)
  252. n = m;
  253. op = (Ip6hdr*)(buf + IPaddrlen + STFHDR);
  254. n -= STFHDR;
  255. /* don't relay: just accept packets for local host/subnet */
  256. /* (this blocks link-local and multicast addresses as well) */
  257. maskip(op->dst, localmask, a);
  258. if (!equivip6(a, localnet)) {
  259. syslog(0, "6in4", "ingress filtered %I -> %I",
  260. op->src, op->dst);
  261. continue;
  262. }
  263. /* pass V6 packet to the interface */
  264. write(out, op, n);
  265. }
  266. }
  267. static int
  268. badipv4(uchar *a)
  269. {
  270. switch (a[0]) {
  271. case 0: /* unassigned */
  272. case 10: /* private */
  273. case 127: /* loopback */
  274. return 1;
  275. case 172:
  276. return a[1] >= 16; /* 172.16.0.0/12 private */
  277. case 192:
  278. return a[1] == 168; /* 192.168.0.0/16 private */
  279. case 169:
  280. return a[1] == 254; /* 169.254.0.0/16 DHCP link-local */
  281. }
  282. /* 224.0.0.0/4 multicast, 240.0.0.0/4 reserved, broadcast */
  283. return a[0] >= 240;
  284. }
  285. /*
  286. * 0x0000/16 prefix = v4 compatible, v4 mapped, loopback, unspecified...
  287. * site-local is now deprecated, rfc3879
  288. */
  289. static int
  290. badipv6(uchar *a)
  291. {
  292. int h = a[0]<<8 | a[1];
  293. return h == 0 || ISIPV6MCAST(a) || ISIPV6LINKLOCAL(a) ||
  294. h == V6to4pfx && badipv4(a+2);
  295. }