6in4.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. /*
  2. * 6in4 - tunnel client for automatic 6to4 or configured v6-in-v4 tunnels.
  3. * see rfc3056.
  4. */
  5. #include <u.h>
  6. #include <libc.h>
  7. #include <ip.h>
  8. /*
  9. * IPv6 and related IP protocols & their numbers:
  10. *
  11. * ipv6 41 IPv6 # Internet Protocol, version 6
  12. * ipv6-route 43 IPv6-Route # Routing Header for IPv6
  13. * ipv6-frag 44 IPv6-Frag # Fragment Header for IPv6
  14. * esp 50 ESP # Encapsulating Security Payload
  15. * ah 51 AH # Authentication Header
  16. * ipv6-icmp 58 IPv6-ICMP icmp6 # ICMP version 6
  17. * ipv6-nonxt 59 IPv6-NoNxt # No Next Header for IPv6
  18. * ipv6-opts 60 IPv6-Opts # Destination Options for IPv6
  19. */
  20. enum {
  21. IP_IPV6PROTO = 41, /* IPv4 protocol number for IPv6 */
  22. IP_ESPPROTO = 50, /* IP v4 and v6 protocol number */
  23. IP_AHPROTO = 51, /* IP v4 and v6 protocol number */
  24. IP_ICMPV6PROTO = 58,
  25. V6to4pfx = 0x2002,
  26. };
  27. typedef struct Iphdr Iphdr;
  28. struct Iphdr
  29. {
  30. uchar vihl; /* Version and header length */
  31. uchar tos; /* Type of service */
  32. uchar length[2]; /* packet length */
  33. uchar id[2]; /* Identification */
  34. uchar frag[2]; /* Fragment information */
  35. uchar ttl; /* Time to live */
  36. uchar proto; /* Protocol */
  37. uchar cksum[2]; /* Header checksum */
  38. uchar src[4]; /* Ip source (uchar ordering unimportant) */
  39. uchar dst[4]; /* Ip destination (uchar ordering unimportant) */
  40. uchar payload[];
  41. };
  42. #define STFHDR offsetof(Iphdr, payload[0])
  43. int anysender;
  44. int gateway;
  45. int debug;
  46. uchar local6[IPaddrlen];
  47. uchar remote6[IPaddrlen];
  48. uchar remote4[IPaddrlen];
  49. uchar localmask[IPaddrlen];
  50. uchar localnet[IPaddrlen];
  51. uchar myip[IPaddrlen];
  52. /* magic anycast address from rfc3068 */
  53. uchar anycast6to4[IPv4addrlen] = { 192, 88, 99, 1 };
  54. static char *net = "/net";
  55. static int badipv4(uchar*);
  56. static int badipv6(uchar*);
  57. static void ip2tunnel(int, int);
  58. static void tunnel2ip(int, int);
  59. static void
  60. usage(void)
  61. {
  62. fprint(2, "usage: %s [-ag] [-x mtpt] [local6[/mask]] [remote4 [remote6]]\n",
  63. argv0);
  64. exits("Usage");
  65. }
  66. static char *
  67. defv6addr(void)
  68. {
  69. uchar *ipv4 = &myip[IPaddrlen - IPv4addrlen];
  70. return smprint("%ux:%2.2x%2.2x:%2.2x%2.2x::1/48", V6to4pfx,
  71. ipv4[0], ipv4[1], ipv4[2], ipv4[3]);
  72. }
  73. /* process non-option arguments */
  74. static void
  75. procargs(int argc, char **argv)
  76. {
  77. char *p, *loc6;
  78. if (argc < 1)
  79. loc6 = defv6addr();
  80. else if (strcmp(argv[0], "-") == 0) {
  81. loc6 = defv6addr();
  82. argv++;
  83. argc--;
  84. } else {
  85. loc6 = *argv++;
  86. argc--;
  87. }
  88. /* local v6 address (mask defaults to /128) */
  89. memcpy(localmask, IPallbits, sizeof localmask);
  90. p = strchr(loc6, '/');
  91. if (p != nil) {
  92. parseipmask(localmask, p);
  93. *p = 0;
  94. }
  95. if (parseip(local6, loc6) == -1)
  96. sysfatal("bad local v6 address %s", loc6);
  97. if (isv4(local6))
  98. usage();
  99. if (argc >= 1 && argv[0][0] == '/') {
  100. parseipmask(localmask, *argv++);
  101. argc--;
  102. }
  103. if (debug)
  104. fprint(2, "local6 %I %M\n", local6, localmask);
  105. /* remote v4 address (defaults to anycast 6to4) */
  106. if (argc >= 1) {
  107. if (parseip(remote4, *argv++) == -1)
  108. sysfatal("bad remote v4 address %s", argv[-1]);
  109. argc--;
  110. if (!isv4(remote4))
  111. usage();
  112. } else {
  113. v4tov6(remote4, anycast6to4);
  114. anysender++;
  115. }
  116. if (debug)
  117. fprint(2, "remote4 %I\n", remote4);
  118. /* remote v6 address (defaults to link-local w/ v4 as interface part) */
  119. if (argc >= 1) {
  120. if (parseip(remote6, *argv++) == -1)
  121. sysfatal("bad remote v6 address %s", argv[-1]);
  122. argc--;
  123. } else {
  124. remote6[0] = 0xFE; /* link local */
  125. remote6[1] = 0x80;
  126. memcpy(remote6 + IPv4off, remote4 + IPv4off, IPv4addrlen);
  127. }
  128. USED(argv);
  129. if (argc != 0)
  130. usage();
  131. maskip(local6, localmask, localnet);
  132. if (debug)
  133. fprint(2, "localnet %I remote6 %I\n", localnet, remote6);
  134. }
  135. static void
  136. setup(int *v6net, int *tunp)
  137. {
  138. int n, cfd;
  139. char *p, *cl, *ir;
  140. char buf[128], path[64];
  141. /*
  142. * gain access to IPv6-in-IPv4 packets via ipmux
  143. */
  144. p = seprint(buf, buf + sizeof buf, "%s/ipmux!proto=%2.2x|%2.2x;dst=%V",
  145. net, IP_IPV6PROTO, IP_ICMPV6PROTO, myip + IPv4off);
  146. if (!anysender)
  147. seprint(p, buf + sizeof buf, ";src=%V", remote4 + IPv4off);
  148. *tunp = dial(buf, 0, 0, 0);
  149. if (*tunp < 0)
  150. sysfatal("can't access ipv6-in-ipv4 with dial str %s: %r", buf);
  151. if (debug)
  152. fprint(2, "dialed %s for v6-in-v4 access\n", buf);
  153. /*
  154. * open local IPv6 interface (as a packet interface)
  155. */
  156. cl = smprint("%s/ipifc/clone", net);
  157. cfd = open(cl, ORDWR); /* allocate a conversation */
  158. n = 0;
  159. if (cfd < 0 || (n = read(cfd, buf, sizeof buf - 1)) <= 0)
  160. sysfatal("can't make packet interface %s: %r", cl);
  161. if (debug)
  162. fprint(2, "cloned %s as local v6 interface\n", cl);
  163. free(cl);
  164. buf[n] = 0;
  165. snprint(path, sizeof path, "%s/ipifc/%s/data", net, buf);
  166. *v6net = open(path, ORDWR);
  167. if (*v6net < 0 || fprint(cfd, "bind pkt") < 0)
  168. sysfatal("can't bind packet interface: %r");
  169. /* 1280 is MTU, apparently from rfc2460 */
  170. if (fprint(cfd, "add %I /128 %I 1280", local6, remote6) <= 0)
  171. sysfatal("can't set local ipv6 address: %r");
  172. close(cfd);
  173. if (debug)
  174. fprint(2, "opened & bound %s as local v6 interface\n", path);
  175. if (gateway) {
  176. /* route global addresses through the tunnel to remote6 */
  177. ir = smprint("%s/iproute", net);
  178. cfd = open(ir, OWRITE);
  179. if (cfd >= 0 && debug)
  180. fprint(2, "injected 2000::/3 %I into %s\n", remote6, ir);
  181. free(ir);
  182. if (cfd < 0 || fprint(cfd, "add 2000:: /3 %I", remote6) <= 0)
  183. sysfatal("can't set default global route: %r");
  184. }
  185. }
  186. static void
  187. runtunnel(int v6net, int tunnel)
  188. {
  189. /* run the tunnel copying in the background */
  190. switch (rfork(RFPROC|RFNOWAIT|RFMEM|RFNOTEG)) {
  191. case -1:
  192. sysfatal("rfork");
  193. default:
  194. exits(nil);
  195. case 0:
  196. break;
  197. }
  198. switch (rfork(RFPROC|RFNOWAIT|RFMEM)) {
  199. case -1:
  200. sysfatal("rfork");
  201. default:
  202. tunnel2ip(tunnel, v6net);
  203. break;
  204. case 0:
  205. ip2tunnel(v6net, tunnel);
  206. break;
  207. }
  208. exits("tunnel gone");
  209. }
  210. void
  211. main(int argc, char **argv)
  212. {
  213. int tunnel, v6net;
  214. fmtinstall('I', eipfmt);
  215. fmtinstall('V', eipfmt);
  216. fmtinstall('M', eipfmt);
  217. ARGBEGIN {
  218. case 'a':
  219. anysender++;
  220. break;
  221. case 'd':
  222. debug++;
  223. break;
  224. case 'g':
  225. gateway++;
  226. break;
  227. case 'x':
  228. net = EARGF(usage());
  229. break;
  230. default:
  231. usage();
  232. } ARGEND
  233. if (myipaddr(myip, net) < 0)
  234. sysfatal("can't find my ipv4 address on %s", net);
  235. if (!isv4(myip))
  236. sysfatal("my ip, %I, is not a v4 address", myip);
  237. procargs(argc, argv);
  238. setup(&v6net, &tunnel);
  239. runtunnel(v6net, tunnel);
  240. exits(0);
  241. }
  242. /*
  243. * based on libthread's threadsetname, but drags in less library code.
  244. * actually just sets the arguments displayed.
  245. */
  246. void
  247. procsetname(char *fmt, ...)
  248. {
  249. int fd;
  250. char *cmdname;
  251. char buf[128];
  252. va_list arg;
  253. va_start(arg, fmt);
  254. cmdname = vsmprint(fmt, arg);
  255. va_end(arg);
  256. if (cmdname == nil)
  257. return;
  258. snprint(buf, sizeof buf, "#p/%d/args", getpid());
  259. if((fd = open(buf, OWRITE)) >= 0){
  260. write(fd, cmdname, strlen(cmdname)+1);
  261. close(fd);
  262. }
  263. free(cmdname);
  264. }
  265. /*
  266. * encapsulate v6 packets from the packet interface in v4 ones
  267. * and send them into the tunnel.
  268. */
  269. static void
  270. ip2tunnel(int in, int out)
  271. {
  272. int n, m;
  273. char buf[64*1024];
  274. Iphdr *op;
  275. Ip6hdr *ip;
  276. if (anysender)
  277. procsetname("v6 %I -> tunnel", local6);
  278. else
  279. procsetname("v6 %I -> tunnel %I %I", local6, remote4, remote6);
  280. /* populate v4 header */
  281. op = (Iphdr*)buf;
  282. op->vihl = IP_VER4 | 5; /* hdr is 5 longs? */
  283. memcpy(op->src, myip + IPv4off, sizeof op->src);
  284. op->proto = IP_IPV6PROTO; /* inner protocol */
  285. op->ttl = 100;
  286. /* get a V6 packet destined for the tunnel */
  287. ip = (Ip6hdr*)(buf + STFHDR);
  288. while ((n = read(in, ip, sizeof buf - STFHDR)) > 0) {
  289. /* if not IPV6, drop it */
  290. if ((ip->vcf[0] & 0xF0) != IP_VER6)
  291. continue;
  292. /* check length: drop if too short, trim if too long */
  293. m = nhgets(ip->ploadlen) + IPV6HDR_LEN;
  294. if (m > n)
  295. continue;
  296. if (m < n)
  297. n = m;
  298. /* drop if v6 source or destination address is naughty */
  299. if (badipv6(ip->src)) {
  300. syslog(0, "6in4", "egress filtered %I -> %I; bad src",
  301. ip->src, ip->dst);
  302. continue;
  303. }
  304. if ((!equivip6(ip->dst, remote6) && badipv6(ip->dst))) {
  305. syslog(0, "6in4", "egress filtered %I -> %I; "
  306. "bad dst not remote", ip->src, ip->dst);
  307. continue;
  308. }
  309. if (debug > 1)
  310. fprint(2, "v6 to tunnel %I -> %I\n", ip->src, ip->dst);
  311. /* send 6to4 packets directly to ipv4 target */
  312. if ((ip->dst[0]<<8 | ip->dst[1]) == V6to4pfx)
  313. memcpy(op->dst, ip->dst+2, sizeof op->dst);
  314. else
  315. memcpy(op->dst, remote4+IPv4off, sizeof op->dst);
  316. n += STFHDR;
  317. /* pass packet to the other end of the tunnel */
  318. if (write(out, op, n) != n) {
  319. syslog(0, "6in4", "error writing to tunnel (%r), giving up");
  320. break;
  321. }
  322. }
  323. }
  324. /*
  325. * decapsulate v6 packets from v4 ones from the tunnel
  326. * and forward them to the packet interface
  327. */
  328. static void
  329. tunnel2ip(int in, int out)
  330. {
  331. int n, m;
  332. char buf[64*1024];
  333. uchar a[IPaddrlen];
  334. Ip6hdr *op;
  335. Iphdr *ip;
  336. if (anysender)
  337. procsetname("tunnel -> v6 %I", local6);
  338. else
  339. procsetname("tunnel %I %I -> v6 %I", remote4, remote6, local6);
  340. for (;;) {
  341. /* get a packet from the tunnel */
  342. n = read(in, buf, sizeof buf);
  343. ip = (Iphdr*)(buf + IPaddrlen);
  344. n -= IPaddrlen;
  345. if (n <= 0) {
  346. syslog(0, "6in4", "error reading from tunnel (%r), giving up");
  347. break;
  348. }
  349. /* if not IPv4 nor IPv4 protocol IPv6 nor ICMPv6, drop it */
  350. if ((ip->vihl & 0xF0) != IP_VER4 ||
  351. ip->proto != IP_IPV6PROTO && ip->proto != IP_ICMPV6PROTO) {
  352. syslog(0, "6in4",
  353. "dropping pkt from tunnel with inner proto %d",
  354. ip->proto);
  355. continue;
  356. }
  357. /* check length: drop if too short, trim if too long */
  358. m = nhgets(ip->length);
  359. if (m > n)
  360. continue;
  361. if (m < n)
  362. n = m;
  363. op = (Ip6hdr*)(buf + IPaddrlen + STFHDR);
  364. n -= STFHDR;
  365. /*
  366. * don't relay: just accept packets for local host/subnet
  367. * (this blocks link-local and multicast addresses as well)
  368. */
  369. maskip(op->dst, localmask, a);
  370. if (!equivip6(a, localnet)) {
  371. syslog(0, "6in4", "ingress filtered %I -> %I; "
  372. "dst not on local net", op->src, op->dst);
  373. continue;
  374. }
  375. if (debug > 1)
  376. fprint(2, "tunnel to v6 %I -> %I\n", op->src, op->dst);
  377. /* pass V6 packet to the interface */
  378. if (write(out, op, n) != n) {
  379. syslog(0, "6in4", "error writing to packet interface (%r), giving up");
  380. break;
  381. }
  382. }
  383. }
  384. static int
  385. badipv4(uchar *a)
  386. {
  387. switch (a[0]) {
  388. case 0: /* unassigned */
  389. case 10: /* private */
  390. case 127: /* loopback */
  391. return 1;
  392. case 172:
  393. return a[1] >= 16; /* 172.16.0.0/12 private */
  394. case 192:
  395. return a[1] == 168; /* 192.168.0.0/16 private */
  396. case 169:
  397. return a[1] == 254; /* 169.254.0.0/16 DHCP link-local */
  398. }
  399. /* 224.0.0.0/4 multicast, 240.0.0.0/4 reserved, broadcast */
  400. return a[0] >= 240;
  401. }
  402. /*
  403. * 0x0000/16 prefix = v4 compatible, v4 mapped, loopback, unspecified...
  404. * site-local is now deprecated, rfc3879
  405. */
  406. static int
  407. badipv6(uchar *a)
  408. {
  409. int h = a[0]<<8 | a[1];
  410. return h == 0 || ISIPV6MCAST(a) || ISIPV6LINKLOCAL(a) ||
  411. h == V6to4pfx && badipv4(a+2);
  412. }