ipv6.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924
  1. /*
  2. * ipconfig for IPv6
  3. */
  4. #include <u.h>
  5. #include <libc.h>
  6. #include <bio.h>
  7. #include <ip.h>
  8. typedef struct Block Block;
  9. typedef struct Fs Fs;
  10. #include "/sys/src/9/ip/ipv6.h"
  11. #include "ipconfig.h"
  12. #include "../icmp.h"
  13. #pragma varargck argpos ralog 1
  14. #define RALOG "v6routeradv"
  15. #define NetS(x) (((uchar*)x)[0]<< 8 | ((uchar*)x)[1])
  16. #define NetL(x) (((uchar*)x)[0]<<24 | ((uchar*)x)[1]<<16 | \
  17. ((uchar*)x)[2]<< 8 | ((uchar*)x)[3])
  18. enum {
  19. ICMP6LEN= 4,
  20. };
  21. typedef struct Hdr Hdr;
  22. struct Hdr /* ICMP v4 & v6 header */
  23. {
  24. uchar type;
  25. uchar code;
  26. uchar cksum[2]; /* Checksum */
  27. uchar data[1];
  28. };
  29. char *icmpmsg6[Maxtype6+1] =
  30. {
  31. [EchoReply] "EchoReply",
  32. [UnreachableV6] "UnreachableV6",
  33. [PacketTooBigV6] "PacketTooBigV6",
  34. [TimeExceedV6] "TimeExceedV6",
  35. [Redirect] "Redirect",
  36. [EchoRequest] "EchoRequest",
  37. [TimeExceed] "TimeExceed",
  38. [InParmProblem] "InParmProblem",
  39. [Timestamp] "Timestamp",
  40. [TimestampReply] "TimestampReply",
  41. [InfoRequest] "InfoRequest",
  42. [InfoReply] "InfoReply",
  43. [AddrMaskRequest] "AddrMaskRequest",
  44. [AddrMaskReply] "AddrMaskReply",
  45. [EchoRequestV6] "EchoRequestV6",
  46. [EchoReplyV6] "EchoReplyV6",
  47. [RouterSolicit] "RouterSolicit",
  48. [RouterAdvert] "RouterAdvert",
  49. [NbrSolicit] "NbrSolicit",
  50. [NbrAdvert] "NbrAdvert",
  51. [RedirectV6] "RedirectV6",
  52. };
  53. static char *icmp6opts[] =
  54. {
  55. [0] "unknown opt",
  56. [SRC_LLADDR] "sll_addr",
  57. [TARGET_LLADDR] "tll_addr",
  58. [PREFIX_INFO] "pref_opt",
  59. [REDIR_HEADER] "redirect",
  60. [MTU_OPTION] "mtu_opt",
  61. };
  62. uchar v6allroutersL[IPaddrlen] = {
  63. 0xff, 0x02, 0, 0,
  64. 0, 0, 0, 0,
  65. 0, 0, 0, 0,
  66. 0, 0, 0, 0x02
  67. };
  68. uchar v6allnodesL[IPaddrlen] = {
  69. 0xff, 0x02, 0, 0,
  70. 0, 0, 0, 0,
  71. 0, 0, 0, 0,
  72. 0, 0, 0, 0x01
  73. };
  74. uchar v6Unspecified[IPaddrlen] = {
  75. 0, 0, 0, 0,
  76. 0, 0, 0, 0,
  77. 0, 0, 0, 0,
  78. 0, 0, 0, 0
  79. };
  80. uchar v6glunicast[IPaddrlen] = {
  81. 0x08, 0, 0, 0,
  82. 0, 0, 0, 0,
  83. 0, 0, 0, 0,
  84. 0, 0, 0, 0
  85. };
  86. uchar v6linklocal[IPaddrlen] = {
  87. 0xfe, 0x80, 0, 0,
  88. 0, 0, 0, 0,
  89. 0, 0, 0, 0,
  90. 0, 0, 0, 0
  91. };
  92. uchar v6solpfx[IPaddrlen] = {
  93. 0xff, 0x02, 0, 0,
  94. 0, 0, 0, 0,
  95. 0, 0, 0, 1,
  96. /* last 3 bytes filled with low-order bytes of addr being solicited */
  97. 0xff, 0, 0, 0,
  98. };
  99. uchar v6defmask[IPaddrlen] = {
  100. 0xff, 0xff, 0xff, 0xff,
  101. 0xff, 0xff, 0xff, 0xff,
  102. 0, 0, 0, 0,
  103. 0, 0, 0, 0
  104. };
  105. enum
  106. {
  107. Vadd,
  108. Vremove,
  109. Vunbind,
  110. Vaddpref6,
  111. Vra6,
  112. };
  113. static void
  114. ralog(char *fmt, ...)
  115. {
  116. char msg[512];
  117. va_list arg;
  118. va_start(arg, fmt);
  119. vseprint(msg, msg+sizeof msg, fmt, arg);
  120. va_end(arg);
  121. syslog(debug, RALOG, msg);
  122. }
  123. extern void
  124. ea2lla(uchar *lla, uchar *ea)
  125. {
  126. assert(IPaddrlen == 16);
  127. memset(lla, 0, IPaddrlen);
  128. lla[0] = 0xFE;
  129. lla[1] = 0x80;
  130. lla[8] = ea[0] | 0x2;
  131. lla[9] = ea[1];
  132. lla[10] = ea[2];
  133. lla[11] = 0xFF;
  134. lla[12] = 0xFE;
  135. lla[13] = ea[3];
  136. lla[14] = ea[4];
  137. lla[15] = ea[5];
  138. }
  139. extern void
  140. ipv62smcast(uchar *smcast, uchar *a)
  141. {
  142. assert(IPaddrlen == 16);
  143. memset(smcast, 0, IPaddrlen);
  144. smcast[0] = 0xFF;
  145. smcast[1] = 0x02;
  146. smcast[11] = 0x1;
  147. smcast[12] = 0xFF;
  148. smcast[13] = a[13];
  149. smcast[14] = a[14];
  150. smcast[15] = a[15];
  151. }
  152. void
  153. v6paraminit(void)
  154. {
  155. conf.sendra = conf.recvra = 0;
  156. conf.mflag = 0;
  157. conf.oflag = 0;
  158. conf.maxraint = MAX_INIT_RTR_ADVERT_INTVL;
  159. conf.minraint = MAX_INIT_RTR_ADVERT_INTVL / 4;
  160. conf.linkmtu = 1500;
  161. conf.reachtime = REACHABLE_TIME;
  162. conf.rxmitra = RETRANS_TIMER;
  163. conf.ttl = MAXTTL;
  164. conf.routerlt = 0;
  165. conf.force = 0;
  166. conf.prefixlen = 64;
  167. conf.onlink = 0;
  168. conf.autoflag = 0;
  169. conf.validlt = conf.preflt = ~0L;
  170. }
  171. static char*
  172. opt_seprint(uchar *ps, uchar *pe, char *sps, char *spe)
  173. {
  174. int otype, osz, pktsz;
  175. uchar *a;
  176. char *p = sps, *e = spe;
  177. a = ps;
  178. for (pktsz = pe - ps; pktsz > 0; pktsz -= osz) {
  179. otype = a[0];
  180. osz = a[1] * 8;
  181. switch (otype) {
  182. default:
  183. return seprint(p, e, " option=%s ", icmp6opts[otype]);
  184. case SRC_LLADDR:
  185. case TARGET_LLADDR:
  186. if (pktsz < osz || osz != 8)
  187. return seprint(p, e, " option=%s bad size=%d",
  188. icmp6opts[otype], osz);
  189. p = seprint(p, e, " option=%s maddr=%E",
  190. icmp6opts[otype], a+2);
  191. break;
  192. case PREFIX_INFO:
  193. if (pktsz < osz || osz != 32)
  194. return seprint(p, e, " option=%s: bad size=%d",
  195. icmp6opts[otype], osz);
  196. p = seprint(p, e, " option=%s pref=%I preflen=%3.3d"
  197. " lflag=%1.1d aflag=%1.1d unused1=%1.1d"
  198. " validlt=%ud preflt=%ud unused2=%1.1d",
  199. icmp6opts[otype], a+16, (int)(*(a+2)),
  200. (*(a+3) & (1 << 7)) != 0,
  201. (*(a+3) & (1 << 6)) != 0,
  202. (*(a+3) & 63) != 0,
  203. NetL(a+4), NetL(a+8), NetL(a+12)!=0);
  204. break;
  205. }
  206. a += osz;
  207. }
  208. return p;
  209. }
  210. static void
  211. pkt2str(uchar *ps, uchar *pe, char *sps, char *spe)
  212. {
  213. int pktlen;
  214. char *tn, *p, *e;
  215. uchar *a;
  216. Hdr *h;
  217. h = (Hdr*)ps;
  218. a = ps + 4;
  219. p = sps;
  220. e = spe;
  221. pktlen = pe - ps;
  222. if(pktlen < ICMP6LEN) {
  223. seprint(sps, spe, "short pkt");
  224. return;
  225. }
  226. tn = icmpmsg6[h->type];
  227. if(tn == nil)
  228. p = seprint(p, e, "t=%ud c=%d ck=%4.4ux", h->type,
  229. h->code, (ushort)NetS(h->cksum));
  230. else
  231. p = seprint(p, e, "t=%s c=%d ck=%4.4ux", tn,
  232. h->code, (ushort)NetS(h->cksum));
  233. switch(h->type){
  234. case RouterSolicit:
  235. ps += 8;
  236. p = seprint(p, e, " unused=%1.1d ", NetL(a)!=0);
  237. opt_seprint(ps, pe, p, e);
  238. break;
  239. case RouterAdvert:
  240. ps += 16;
  241. p = seprint(p, e, " hoplim=%3.3d mflag=%1.1d oflag=%1.1d"
  242. " unused=%1.1d routerlt=%d reachtime=%d rxmtimer=%d",
  243. a[0],
  244. (*(a+1) & (1 << 7)) != 0,
  245. (*(a+1) & (1 << 6)) != 0,
  246. (*(a+1) & 63) != 0,
  247. NetS(a+2), NetL(a+4), NetL(a+8));
  248. opt_seprint(ps, pe, p, e);
  249. break;
  250. default:
  251. seprint(p, e, " unexpected icmp6 pkt type");
  252. break;
  253. }
  254. }
  255. static void
  256. catch(void *a, char *msg)
  257. {
  258. USED(a);
  259. if(strstr(msg, "alarm"))
  260. noted(NCONT);
  261. else
  262. noted(NDFLT);
  263. }
  264. /*
  265. * based on libthread's threadsetname, but drags in less library code.
  266. * actually just sets the arguments displayed.
  267. */
  268. void
  269. procsetname(char *fmt, ...)
  270. {
  271. int fd;
  272. char *cmdname;
  273. char buf[128];
  274. va_list arg;
  275. va_start(arg, fmt);
  276. cmdname = vsmprint(fmt, arg);
  277. va_end(arg);
  278. if (cmdname == nil)
  279. return;
  280. snprint(buf, sizeof buf, "#p/%d/args", getpid());
  281. if((fd = open(buf, OWRITE)) >= 0){
  282. write(fd, cmdname, strlen(cmdname)+1);
  283. close(fd);
  284. }
  285. free(cmdname);
  286. }
  287. int
  288. dialicmp(uchar *dst, int dport, int *ctlfd)
  289. {
  290. int fd, cfd, n, m;
  291. char cmsg[100], name[128], connind[40];
  292. char hdrs[] = "headers";
  293. snprint(name, sizeof name, "%s/icmpv6/clone", conf.mpoint);
  294. cfd = open(name, ORDWR);
  295. if(cfd < 0)
  296. sysfatal("dialicmp: can't open %s: %r", name);
  297. n = snprint(cmsg, sizeof cmsg, "connect %I!%d!r %d", dst, dport, dport);
  298. m = write(cfd, cmsg, n);
  299. if (m < n)
  300. sysfatal("dialicmp: can't write %s to %s: %r", cmsg, name);
  301. seek(cfd, 0, 0);
  302. n = read(cfd, connind, sizeof connind);
  303. if (n < 0)
  304. connind[0] = 0;
  305. else if (n < sizeof connind)
  306. connind[n] = 0;
  307. else
  308. connind[sizeof connind - 1] = 0;
  309. snprint(name, sizeof name, "%s/icmpv6/%s/data", conf.mpoint, connind);
  310. fd = open(name, ORDWR);
  311. if(fd < 0)
  312. sysfatal("dialicmp: can't open %s: %r", name);
  313. n = sizeof hdrs - 1;
  314. if(write(cfd, hdrs, n) < n)
  315. sysfatal("dialicmp: can't write `%s' to %s: %r", hdrs, name);
  316. *ctlfd = cfd;
  317. return fd;
  318. }
  319. /* add ipv6 addr to an interface */
  320. int
  321. ip6cfg(int autoconf)
  322. {
  323. int dupfound = 0, n;
  324. char *p;
  325. char buf[256];
  326. uchar ethaddr[6];
  327. Biobuf *bp;
  328. if (autoconf) { /* create link-local addr */
  329. if (myetheraddr(ethaddr, conf.dev) < 0)
  330. sysfatal("myetheraddr w/ %s failed: %r", conf.dev);
  331. ea2lla(conf.laddr, ethaddr);
  332. }
  333. if (dupl_disc)
  334. n = sprint(buf, "try");
  335. else
  336. n = sprint(buf, "add");
  337. n += snprint(buf+n, sizeof buf-n, " %I", conf.laddr);
  338. if(!validip(conf.mask))
  339. ipmove(conf.mask, v6defmask);
  340. n += snprint(buf+n, sizeof buf-n, " %M", conf.mask);
  341. if(validip(conf.raddr)){
  342. n += snprint(buf+n, sizeof buf-n, " %I", conf.raddr);
  343. if(conf.mtu != 0)
  344. n += snprint(buf+n, sizeof buf-n, " %d", conf.mtu);
  345. }
  346. if(write(conf.cfd, buf, n) < 0){
  347. fprint(2, "%s: write(%s): %r\n", argv0, buf);
  348. return -1;
  349. }
  350. if (!dupl_disc)
  351. return 0;
  352. sleep(3000);
  353. /* read arp table, look for addr duplication */
  354. snprint(buf, sizeof buf, "%s/arp", conf.mpoint);
  355. bp = Bopen(buf, OREAD);
  356. if (bp == 0) {
  357. fprint(2, "%s: couldn't open %s/arp: %r\n", argv0, conf.mpoint);
  358. return -1;
  359. }
  360. snprint(buf, sizeof buf, "%I", conf.laddr);
  361. while(p = Brdline(bp, '\n')){
  362. p[Blinelen(bp)-1] = 0;
  363. if(cistrstr(p, buf) != 0) {
  364. fprint(2, "%s: found dup entry in arp cache\n", argv0);
  365. dupfound = 1;
  366. break;
  367. }
  368. }
  369. Bterm(bp);
  370. if (dupfound)
  371. doremove();
  372. else {
  373. n = sprint(buf, "add %I %M", conf.laddr, conf.mask);
  374. if(validip(conf.raddr)){
  375. n += snprint(buf+n, sizeof buf-n, " %I", conf.raddr);
  376. if(conf.mtu != 0)
  377. n += snprint(buf+n, sizeof buf-n, " %d",
  378. conf.mtu);
  379. }
  380. write(conf.cfd, buf, n);
  381. }
  382. return 0;
  383. }
  384. static int
  385. recvra6on(char *net, int conn)
  386. {
  387. Ipifc* ifc;
  388. ifc = readipifc(net, nil, conn);
  389. if (ifc == nil)
  390. return 0;
  391. else if (ifc->sendra6 > 0)
  392. return IsRouter;
  393. else if (ifc->recvra6 > 0)
  394. return IsHostRecv;
  395. else
  396. return IsHostNoRecv;
  397. }
  398. static void
  399. sendrs(int fd)
  400. {
  401. Routersol *rs;
  402. uchar buff[sizeof *rs];
  403. memset(buff, 0, sizeof buff);
  404. rs = (Routersol *)buff;
  405. memmove(rs->dst, v6allroutersL, IPaddrlen);
  406. memmove(rs->src, v6Unspecified, IPaddrlen);
  407. rs->type = ICMP6_RS;
  408. if(write(fd, rs, sizeof buff) < sizeof buff)
  409. ralog("sendrs: write failed, pkt size %d", sizeof buff);
  410. }
  411. /*
  412. * a router receiving a router adv from another
  413. * router calls this; it is basically supposed to
  414. * log the information in the ra and raise a flag
  415. * if any parameter value is different from its configured values.
  416. *
  417. * doing nothing for now since I don't know where to log this yet.
  418. */
  419. static void
  420. recvrarouter(uchar buf[], int pktlen)
  421. {
  422. USED(buf, pktlen);
  423. ralog("i am a router and got a router advert");
  424. }
  425. /* host receiving a router advertisement calls this */
  426. static void
  427. recvrahost(uchar buf[], int pktlen)
  428. {
  429. int arpfd, m, n;
  430. char abuf[100], configcmd[256];
  431. uchar optype;
  432. Lladdropt *llao;
  433. Mtuopt *mtuo;
  434. Prefixopt *prfo;
  435. Routeradv *ra;
  436. ra = (Routeradv*)buf;
  437. memmove(conf.v6gaddr, ra->src, IPaddrlen);
  438. conf.force = 0;
  439. conf.ttl = ra->cttl;
  440. conf.mflag = (MFMASK & ra->mor);
  441. conf.oflag = (OCMASK & ra->mor);
  442. conf.routerlt = nhgets(ra->routerlt);
  443. conf.reachtime = nhgetl(ra->rchbltime);
  444. conf.rxmitra = nhgetl(ra->rxmtimer);
  445. n = snprint(configcmd, sizeof configcmd, "%s %I %d %d %d %d %d %d %d",
  446. "gate6", conf.v6gaddr, conf.force, conf.ttl, conf.mflag,
  447. conf.oflag, conf.routerlt, conf.reachtime, conf.rxmitra);
  448. if (write(conf.cfd, configcmd, n) < 0)
  449. ralog("write (%s) failed", configcmd);
  450. m = sizeof *ra;
  451. while (pktlen - m > 0) {
  452. optype = buf[m];
  453. switch (optype) {
  454. case SRC_LLADDR:
  455. llao = (Lladdropt *)&buf[m];
  456. m += 8 * buf[m+1];
  457. if (llao->len != 1) {
  458. ralog(
  459. "recvrahost: illegal len(%d) for source link layer address option",
  460. llao->len);
  461. return;
  462. }
  463. if (memcmp(ra->src, v6linklocal, 2) != 0) {
  464. ralog(
  465. "recvrahost: non-linklocal src addr for router adv %I",
  466. ra->src);
  467. return;
  468. }
  469. snprint(abuf, sizeof abuf, "%s/arp", conf.mpoint);
  470. arpfd = open(abuf, OWRITE);
  471. if (arpfd < 0) {
  472. ralog(
  473. "recvrahost: couldn't open %s/arp to write: %r",
  474. conf.mpoint);
  475. return;
  476. }
  477. n = snprint(abuf, sizeof abuf, "add ether %I %E",
  478. ra->src, llao->lladdr);
  479. if (write(arpfd, abuf, n) < n)
  480. ralog("recvrahost: couldn't write to %s/arp",
  481. conf.mpoint);
  482. close(arpfd);
  483. break;
  484. case TARGET_LLADDR:
  485. case REDIR_HEADER:
  486. m += 8 * buf[m+1];
  487. ralog("ignoring unexpected optype %s in Routeradv",
  488. icmp6opts[optype]);
  489. break;
  490. case MTU_OPTION:
  491. mtuo = (Mtuopt*)&buf[m];
  492. m += 8 * mtuo->len;
  493. conf.linkmtu = nhgetl(mtuo->mtu);
  494. break;
  495. case PREFIX_INFO:
  496. prfo = (Prefixopt*)&buf[m];
  497. m += 8 * prfo->len;
  498. if (prfo->len != 4) {
  499. ralog("illegal len(%d) for prefix option",
  500. prfo->len);
  501. return;
  502. }
  503. memmove(conf.v6pref, prfo->pref, IPaddrlen);
  504. conf.prefixlen = prfo->plen;
  505. conf.onlink = ((prfo->lar & OLMASK) != 0);
  506. conf.autoflag = ((prfo->lar & AFMASK) != 0);
  507. conf.validlt = nhgetl(prfo->validlt);
  508. conf.preflt = nhgetl(prfo->preflt);
  509. n = snprint(configcmd, sizeof configcmd,
  510. "%s %I %d %d %d %uld %uld",
  511. "addpref6", conf.v6pref, conf.prefixlen,
  512. conf.onlink, conf.autoflag,
  513. conf.validlt, conf.preflt);
  514. if (write(conf.cfd, configcmd, n) < 0)
  515. ralog("write (%s) failed", configcmd);
  516. break;
  517. default:
  518. m += 8 * buf[m+1];
  519. ralog("ignoring optype %s in Routeradv", icmp6opts[0]);
  520. break;
  521. }
  522. }
  523. }
  524. /*
  525. * daemon to receive router adverisements
  526. */
  527. void
  528. recvra6(void)
  529. {
  530. int fd, cfd, n, sendrscnt, sleepfor;
  531. uchar buf[4096];
  532. fd = dialicmp(v6allnodesL, ICMP6_RA, &cfd);
  533. if (fd < 0)
  534. sysfatal("can't open icmp_ra connection: %r");
  535. notify(catch);
  536. sendrscnt = MAX_RTR_SOLICITS;
  537. switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){
  538. case -1:
  539. sysfatal("can't fork: %r");
  540. default:
  541. return;
  542. case 0:
  543. procsetname("recvra6 on %s", conf.dev);
  544. ralog("recvra6 on %s", conf.dev);
  545. sleepfor = nrand(10);
  546. for (;;) {
  547. alarm(sleepfor);
  548. n = read(fd, buf, sizeof buf);
  549. alarm(0);
  550. if (n <= 0) {
  551. if (sendrscnt > 0) {
  552. sendrscnt--;
  553. if (recvra6on(conf.mpoint, myifc) ==
  554. IsHostRecv)
  555. sendrs(fd);
  556. sleepfor = RTR_SOLICIT_INTVL+nrand(100);
  557. }
  558. if (sendrscnt == 0) {
  559. sendrscnt--;
  560. sleepfor = 0;
  561. ralog(
  562. "recvra6: no router advs after %d sols on %s",
  563. MAX_RTR_SOLICITS, conf.dev);
  564. }
  565. continue;
  566. }
  567. sleepfor = 0;
  568. switch (recvra6on(conf.mpoint, myifc)) {
  569. case IsRouter:
  570. recvrarouter(buf, n);
  571. break;
  572. case IsHostRecv:
  573. recvrahost(buf, n);
  574. break;
  575. case IsHostNoRecv:
  576. ralog("recvra6: recvra off, quitting");
  577. close(fd);
  578. exits(0);
  579. default:
  580. ralog(
  581. "recvra6: unable to read router status on %s",
  582. conf.dev);
  583. break;
  584. }
  585. }
  586. }
  587. }
  588. /*
  589. * return -1 -- error, reading/writing some file,
  590. * 0 -- no arptable updates
  591. * 1 -- successful arptable update
  592. */
  593. int
  594. recvrs(uchar *buf, int pktlen, uchar *sol)
  595. {
  596. int n, optsz, arpfd;
  597. char abuf[256];
  598. Routersol *rs;
  599. Lladdropt *llao;
  600. rs = (Routersol *)buf;
  601. n = sizeof *rs;
  602. optsz = pktlen - n;
  603. pkt2str(buf, buf+pktlen, abuf, abuf+nelem(abuf));
  604. if (optsz != sizeof *llao)
  605. return 0;
  606. if (buf[n] != SRC_LLADDR || 8*buf[n+1] != sizeof *llao) {
  607. ralog("rs opt err %s", abuf);
  608. return -1;
  609. }
  610. ralog("rs recv %s", abuf);
  611. if (memcmp(rs->src, v6Unspecified, IPaddrlen) == 0)
  612. return 0;
  613. snprint(abuf, sizeof abuf, "%s/arp", conf.mpoint);
  614. arpfd = open(abuf, OWRITE);
  615. if (arpfd < 0) {
  616. ralog("recvrs: can't open %s/arp to write: %r", conf.mpoint);
  617. return -1;
  618. }
  619. llao = (Lladdropt *)buf[n];
  620. n = snprint(abuf, sizeof abuf, "add ether %I %E", rs->src, llao->lladdr);
  621. if (write(arpfd, abuf, n) < n) {
  622. ralog("recvrs: can't write to %s/arp: %r", conf.mpoint);
  623. close(arpfd);
  624. return -1;
  625. }
  626. memmove(sol, rs->src, IPaddrlen);
  627. close(arpfd);
  628. return 1;
  629. }
  630. void
  631. sendra(int fd, uchar *dst, int rlt)
  632. {
  633. int pktsz, preflen;
  634. char abuf[1024], tmp[40];
  635. uchar buf[1024], macaddr[6], src[IPaddrlen];
  636. Ipifc *ifc = nil;
  637. Iplifc *lifc, *nlifc;
  638. Lladdropt *llao;
  639. Prefixopt *prfo;
  640. Routeradv *ra;
  641. memset(buf, 0, sizeof buf);
  642. ra = (Routeradv *)buf;
  643. myetheraddr(macaddr, conf.dev);
  644. ea2lla(src, macaddr);
  645. memmove(ra->src, src, IPaddrlen);
  646. memmove(ra->dst, dst, IPaddrlen);
  647. ra->type = ICMP6_RA;
  648. ra->cttl = conf.ttl;
  649. if (conf.mflag > 0)
  650. ra->mor |= MFMASK;
  651. if (conf.oflag > 0)
  652. ra->mor |= OCMASK;
  653. if (rlt > 0)
  654. hnputs(ra->routerlt, conf.routerlt);
  655. else
  656. hnputs(ra->routerlt, 0);
  657. hnputl(ra->rchbltime, conf.reachtime);
  658. hnputl(ra->rxmtimer, conf.rxmitra);
  659. pktsz = sizeof *ra;
  660. /* include all global unicast prefixes on interface in prefix options */
  661. ifc = readipifc(conf.mpoint, ifc, myifc);
  662. for (lifc = (ifc? ifc->lifc: nil); lifc; lifc = nlifc) {
  663. nlifc = lifc->next;
  664. prfo = (Prefixopt *)(buf + pktsz);
  665. if (isv6global(lifc->ip)) {
  666. memmove(prfo->pref, lifc->net, IPaddrlen);
  667. /* hack to find prefix length */
  668. snprint(tmp, sizeof tmp, "%M", lifc->mask);
  669. preflen = atoi(&tmp[1]);
  670. prfo->plen = preflen & 0xff;
  671. if (prfo->plen == 0)
  672. continue;
  673. prfo->type = PREFIX_INFO;
  674. prfo->len = 4;
  675. prfo->lar = AFMASK;
  676. hnputl(prfo->validlt, lifc->validlt);
  677. hnputl(prfo->preflt, lifc->preflt);
  678. pktsz += sizeof *prfo;
  679. }
  680. }
  681. /*
  682. * include link layer address (mac address for now) in
  683. * link layer address option
  684. */
  685. llao = (Lladdropt *)(buf + pktsz);
  686. llao->type = SRC_LLADDR;
  687. llao->len = 1;
  688. memmove(llao->lladdr, macaddr, sizeof macaddr);
  689. pktsz += sizeof *llao;
  690. pkt2str(buf+40, buf+pktsz, abuf, abuf+1024);
  691. if(write(fd, buf, pktsz) < pktsz)
  692. ralog("ra wr fail %s", abuf);
  693. else
  694. ralog("ra wr succ %s", abuf);
  695. }
  696. /*
  697. * daemon to send router advertisements
  698. */
  699. void
  700. sendra6(void)
  701. {
  702. int fd, cfd, n, dstknown = 0, sendracnt, sleepfor, nquitmsgs;
  703. long lastra, ctime;
  704. uchar buf[4096], dst[IPaddrlen];
  705. Ipifc *ifc = nil;
  706. fd = dialicmp(v6allnodesL, ICMP6_RS, &cfd);
  707. if (fd < 0)
  708. sysfatal("can't open icmp_rs connection: %r");
  709. notify(catch);
  710. sendracnt = MAX_INIT_RTR_ADVERTS;
  711. nquitmsgs = MAX_FINAL_RTR_ADVERTS;
  712. switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){
  713. case -1:
  714. sysfatal("can't fork: %r");
  715. default:
  716. return;
  717. case 0:
  718. procsetname("sendra6 on %s", conf.dev);
  719. ralog("sendra6 on %s", conf.dev);
  720. sleepfor = nrand(10);
  721. for (;;) {
  722. lastra = time(0);
  723. alarm(sleepfor);
  724. n = read(fd, buf, sizeof buf);
  725. alarm(0);
  726. ifc = readipifc(conf.mpoint, ifc, myifc);
  727. if (ifc == nil) {
  728. ralog("sendra6: unable to read router pars on %s",
  729. conf.mpoint);
  730. continue;
  731. }
  732. if (ifc->sendra6 <= 0)
  733. if (nquitmsgs > 0) {
  734. sendra(fd, v6allnodesL, 0);
  735. nquitmsgs--;
  736. sleepfor = MIN_DELAY_BETWEEN_RAS +
  737. nrand(10);
  738. continue;
  739. } else {
  740. ralog("sendra6: quitting");
  741. exits(0);
  742. }
  743. nquitmsgs = MAX_FINAL_RTR_ADVERTS;
  744. if (n <= 0) { /* no router solicitations */
  745. if (sendracnt > 0)
  746. sendracnt--;
  747. sleepfor = ifc->rp.minraint +
  748. nrand(ifc->rp.maxraint + 1 -
  749. ifc->rp.minraint);
  750. } else { /* respond to router solicit'n */
  751. dstknown = recvrs(buf, n, dst);
  752. ctime = time(0);
  753. if (ctime - lastra < MIN_DELAY_BETWEEN_RAS) {
  754. /* too close, skip */
  755. sleepfor = lastra +
  756. MIN_DELAY_BETWEEN_RAS +
  757. nrand(10) - ctime;
  758. continue;
  759. }
  760. sleepfor = ifc->rp.minraint +
  761. nrand(ifc->rp.maxraint + 1 -
  762. ifc->rp.minraint);
  763. sleep(nrand(10));
  764. }
  765. if (dstknown > 0)
  766. sendra(fd, dst, 1);
  767. else
  768. sendra(fd, v6allnodesL, 1);
  769. }
  770. }
  771. }
  772. void
  773. ra6(void)
  774. {
  775. static char routeon[] = "iprouting 1";
  776. if (conf.recvra > 0)
  777. recvra6();
  778. if (conf.sendra > 0) {
  779. if (write(conf.cfd, routeon, sizeof routeon - 1) < 0) {
  780. fprint(2, "%s: write (iprouting 1) failed\n", argv0);
  781. return;
  782. }
  783. sendra6();
  784. if (conf.recvra <= 0)
  785. recvra6();
  786. }
  787. }
  788. void
  789. dov6stuff(int what)
  790. {
  791. char buf[256];
  792. int n;
  793. nip = nipifcs(conf.mpoint);
  794. if(!noconfig){
  795. lookforip(conf.mpoint);
  796. controldevice();
  797. binddevice();
  798. }
  799. switch (what) {
  800. default:
  801. fprint(2, "%s: unknown IPv6 verb\n", argv0);
  802. break;
  803. case Vaddpref6:
  804. n = snprint(buf, sizeof buf, "addpref6 %I %d %d %d %uld %uld",
  805. conf.v6pref, conf.prefixlen, conf.onlink, conf.autoflag,
  806. conf.validlt, conf.preflt);
  807. if (write(conf.cfd, buf, n) < n)
  808. fprint(2, "%s: write (%s) failed\n", argv0, buf);
  809. break;
  810. case Vra6:
  811. n = snprint(buf, sizeof buf,
  812. "ra6 sendra %d recvra %d mflag %d oflag %d"
  813. " maxraint %d minraint %d linkmtu %d reachtime %d"
  814. " rxmitra %d ttl %d routerlt %d",
  815. conf.sendra, conf.recvra, conf.mflag, conf.oflag,
  816. conf.maxraint, conf.minraint, conf.linkmtu,
  817. conf.reachtime, conf.rxmitra, conf.ttl, conf.routerlt);
  818. if (write(conf.cfd, buf, n) < n)
  819. fprint(2, "%s: write (%s) failed\n", argv0, buf);
  820. ra6();
  821. break;
  822. }
  823. }