ipv6.c 20 KB

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