1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- /*
- * ipconfig for IPv6
- * RS means Router Solicitation
- * RA means Router Advertisement
- */
- #include <u.h>
- #include <libc.h>
- #include <bio.h>
- #include <ip.h>
- #include "ipconfig.h"
- #include "../icmp.h"
- //#pragma varargck argpos ralog 1
- #define RALOG "v6routeradv"
- #define NetS(x) (((unsigned char*)x)[0]<< 8 | ((unsigned char*)x)[1])
- #define NetL(x) (((unsigned char*)x)[0]<<24 | ((unsigned char*)x)[1]<<16 | \
- ((unsigned char*)x)[2]<< 8 | ((unsigned char*)x)[3])
- enum {
- ICMP6LEN= 4,
- };
- typedef struct Hdr Hdr;
- struct Hdr /* ICMP v4 & v6 header */
- {
- uint8_t type;
- uint8_t code;
- uint8_t cksum[2]; /* Checksum */
- uint8_t data[];
- };
- char *icmpmsg6[Maxtype6+1] =
- {
- [EchoReply] = "EchoReply",
- [UnreachableV6] = "UnreachableV6",
- [PacketTooBigV6] = "PacketTooBigV6",
- [TimeExceedV6] = "TimeExceedV6",
- [Redirect] = "Redirect",
- [EchoRequest] = "EchoRequest",
- [TimeExceed] = "TimeExceed",
- [InParmProblem] = "InParmProblem",
- [Timestamp] = "Timestamp",
- [TimestampReply] = "TimestampReply",
- [InfoRequest] = "InfoRequest",
- [InfoReply] = "InfoReply",
- [AddrMaskRequest] = "AddrMaskRequest",
- [AddrMaskReply] = "AddrMaskReply",
- [EchoRequestV6] = "EchoRequestV6",
- [EchoReplyV6] = "EchoReplyV6",
- [RouterSolicit] = "RouterSolicit",
- [RouterAdvert] = "RouterAdvert",
- [NbrSolicit] = "NbrSolicit",
- [NbrAdvert] = "NbrAdvert",
- [RedirectV6] = "RedirectV6",
- };
- static char *icmp6opts[] =
- {
- [0] = "unknown option",
- [V6nd_srclladdr] = "srcll_addr",
- [V6nd_targlladdr] = "targll_addr",
- [V6nd_pfxinfo] = "prefix",
- [V6nd_redirhdr] = "redirect",
- [V6nd_mtu] = "mtu",
- [V6nd_home] = "home",
- [V6nd_srcaddrs] = "src_addrs",
- [V6nd_ip] = "ip",
- [V6nd_rdns] = "rdns",
- [V6nd_9fs] = "9fs",
- [V6nd_9auth] = "9auth",
- };
- uint8_t v6allroutersL[IPaddrlen] = {
- 0xff, 0x02, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0x02
- };
- uint8_t v6allnodesL[IPaddrlen] = {
- 0xff, 0x02, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0x01
- };
- uint8_t v6Unspecified[IPaddrlen] = {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0
- };
- uint8_t v6loopback[IPaddrlen] = {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 1
- };
- uint8_t v6glunicast[IPaddrlen] = {
- 0x08, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0
- };
- uint8_t v6linklocal[IPaddrlen] = {
- 0xfe, 0x80, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0
- };
- uint8_t v6solpfx[IPaddrlen] = {
- 0xff, 0x02, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 1,
- /* last 3 bytes filled with low-order bytes of addr being solicited */
- 0xff, 0, 0, 0,
- };
- uint8_t v6defmask[IPaddrlen] = {
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0, 0, 0, 0,
- 0, 0, 0, 0
- };
- enum
- {
- Vadd,
- Vremove,
- Vunbind,
- Vaddpref6,
- Vra6,
- };
- static void
- ralog(char *fmt, ...)
- {
- char msg[512];
- va_list arg;
- va_start(arg, fmt);
- vseprint(msg, msg+sizeof msg, fmt, arg);
- va_end(arg);
- syslog(debug, RALOG, msg);
- }
- extern void
- ea2lla(uint8_t *lla, uint8_t *ea)
- {
- assert(IPaddrlen == 16);
- memset(lla, 0, IPaddrlen);
- lla[0] = 0xFE;
- lla[1] = 0x80;
- lla[8] = ea[0] | 0x2;
- lla[9] = ea[1];
- lla[10] = ea[2];
- lla[11] = 0xFF;
- lla[12] = 0xFE;
- lla[13] = ea[3];
- lla[14] = ea[4];
- lla[15] = ea[5];
- }
- extern void
- ipv62smcast(uint8_t *smcast, uint8_t *a)
- {
- assert(IPaddrlen == 16);
- memset(smcast, 0, IPaddrlen);
- smcast[0] = 0xFF;
- smcast[1] = 0x02;
- smcast[11] = 0x1;
- smcast[12] = 0xFF;
- smcast[13] = a[13];
- smcast[14] = a[14];
- smcast[15] = a[15];
- }
- void
- v6paraminit(Conf *cf)
- {
- cf->sendra = cf->recvra = 0;
- cf->mflag = 0;
- cf->oflag = 0;
- cf->maxraint = Maxv6initraintvl;
- cf->minraint = Maxv6initraintvl / 4;
- cf->linkmtu = 1500;
- cf->reachtime = V6reachabletime;
- cf->rxmitra = V6retranstimer;
- cf->ttl = MAXTTL;
- cf->routerlt = 0;
- cf->prefixlen = 64;
- cf->onlink = 0;
- cf->autoflag = 0;
- cf->validlt = cf->preflt = ~0L;
- }
- static char *
- optname(unsigned opt)
- {
- static char buf[32];
- if (opt >= nelem(icmp6opts) || icmp6opts[opt] == nil) {
- snprint(buf, sizeof buf, "unknown option %d", opt);
- return buf;
- } else
- return icmp6opts[opt];
- }
- static char*
- opt_seprint(uint8_t *ps, uint8_t *pe, char *sps, char *spe)
- {
- int otype, osz, pktsz;
- uint8_t *a;
- char *p = sps, *e = spe;
- a = ps;
- for (pktsz = pe - ps; pktsz > 0; pktsz -= osz) {
- otype = a[0];
- osz = a[1] * 8;
- switch (otype) {
- default:
- return seprint(p, e, " option=%s ", optname(otype));
- case V6nd_srclladdr:
- case V6nd_targlladdr:
- if (pktsz < osz || osz != 8)
- return seprint(p, e, " option=%s bad size=%d",
- optname(otype), osz);
- p = seprint(p, e, " option=%s maddr=%E", optname(otype),
- a+2);
- break;
- case V6nd_pfxinfo:
- if (pktsz < osz || osz != 32)
- return seprint(p, e, " option=%s: bad size=%d",
- optname(otype), osz);
- p = seprint(p, e, " option=%s pref=%I preflen=%3.3d"
- " lflag=%1.1d aflag=%1.1d unused1=%1.1d"
- " validlt=%u preflt=%u unused2=%1.1d",
- optname(otype), a+16, (int)(*(a+2)),
- (*(a+3) & (1 << 7)) != 0,
- (*(a+3) & (1 << 6)) != 0,
- (*(a+3) & 63) != 0,
- NetL(a+4), NetL(a+8), NetL(a+12)!=0);
- break;
- }
- a += osz;
- }
- return p;
- }
- static void
- pkt2str(uint8_t *ps, uint8_t *pe, char *sps, char *spe)
- {
- int pktlen;
- char *tn, *p, *e;
- uint8_t *a;
- Hdr *h;
- h = (Hdr*)ps;
- a = ps + 4;
- p = sps;
- e = spe;
- pktlen = pe - ps;
- if(pktlen < ICMP6LEN) {
- seprint(sps, spe, "short pkt");
- return;
- }
- tn = icmpmsg6[h->type];
- if(tn == nil)
- p = seprint(p, e, "t=%u c=%d ck=%4.4x", h->type,
- h->code, (uint16_t)NetS(h->cksum));
- else
- p = seprint(p, e, "t=%s c=%d ck=%4.4x", tn,
- h->code, (uint16_t)NetS(h->cksum));
- switch(h->type){
- case RouterSolicit:
- ps += 8;
- p = seprint(p, e, " unused=%1.1d ", NetL(a)!=0);
- opt_seprint(ps, pe, p, e);
- break;
- case RouterAdvert:
- ps += 16;
- p = seprint(p, e, " hoplim=%3.3d mflag=%1.1d oflag=%1.1d"
- " unused=%1.1d routerlt=%d reachtime=%d rxmtimer=%d",
- a[0],
- (*(a+1) & (1 << 7)) != 0,
- (*(a+1) & (1 << 6)) != 0,
- (*(a+1) & 63) != 0,
- NetS(a+2), NetL(a+4), NetL(a+8));
- opt_seprint(ps, pe, p, e);
- break;
- default:
- seprint(p, e, " unexpected icmp6 pkt type");
- break;
- }
- }
- static void
- catch(void *a, char *msg)
- {
- USED(a);
- if(strstr(msg, "alarm"))
- noted(NCONT);
- else
- noted(NDFLT);
- }
- /*
- * based on libthread's threadsetname, but drags in less library code.
- * actually just sets the arguments displayed.
- */
- void
- procsetname(char *fmt, ...)
- {
- int fd;
- char *cmdname;
- char buf[128];
- va_list arg;
- va_start(arg, fmt);
- cmdname = vsmprint(fmt, arg);
- va_end(arg);
- if (cmdname == nil)
- return;
- snprint(buf, sizeof buf, "#p/%d/args", getpid());
- if((fd = open(buf, OWRITE)) >= 0){
- write(fd, cmdname, strlen(cmdname)+1);
- close(fd);
- }
- free(cmdname);
- }
- int
- dialicmp(uint8_t *dst, int dport, int *ctlfd)
- {
- int fd, cfd, n, m;
- char cmsg[100], name[128], connind[40];
- char hdrs[] = "headers";
- snprint(name, sizeof name, "%s/icmpv6/clone", conf.mpoint);
- cfd = open(name, ORDWR);
- if(cfd < 0)
- sysfatal("dialicmp: can't open %s: %r", name);
- n = snprint(cmsg, sizeof cmsg, "connect %I!%d!r %d", dst, dport, dport);
- m = write(cfd, cmsg, n);
- if (m < n)
- sysfatal("dialicmp: can't write %s to %s: %r", cmsg, name);
- seek(cfd, 0, 0);
- n = read(cfd, connind, sizeof connind);
- if (n < 0)
- connind[0] = 0;
- else if (n < sizeof connind)
- connind[n] = 0;
- else
- connind[sizeof connind - 1] = 0;
- snprint(name, sizeof name, "%s/icmpv6/%s/data", conf.mpoint, connind);
- fd = open(name, ORDWR);
- if(fd < 0)
- sysfatal("dialicmp: can't open %s: %r", name);
- n = sizeof hdrs - 1;
- if(write(cfd, hdrs, n) < n)
- sysfatal("dialicmp: can't write `%s' to %s: %r", hdrs, name);
- *ctlfd = cfd;
- return fd;
- }
- /* add ipv6 addr to an interface */
- int
- ip6cfg(int autoconf)
- {
- int dupfound = 0, n;
- char *p;
- char buf[256];
- uint8_t ethaddr[6];
- Biobuf *bp;
- if (autoconf) { /* create link-local addr */
- if (myetheraddr(ethaddr, conf.dev) < 0)
- sysfatal("myetheraddr w/ %s failed: %r", conf.dev);
- ea2lla(conf.laddr, ethaddr);
- }
- if (dupl_disc)
- n = sprint(buf, "try");
- else
- n = sprint(buf, "add");
- n += snprint(buf+n, sizeof buf-n, " %I", conf.laddr);
- if(!validip(conf.mask))
- ipmove(conf.mask, v6defmask);
- n += snprint(buf+n, sizeof buf-n, " %M", conf.mask);
- if(validip(conf.raddr)){
- n += snprint(buf+n, sizeof buf-n, " %I", conf.raddr);
- if(conf.mtu != 0)
- n += snprint(buf+n, sizeof buf-n, " %d", conf.mtu);
- }
- if(write(conf.cfd, buf, n) < 0){
- warning("write(%s): %r", buf);
- return -1;
- }
- if (!dupl_disc)
- return 0;
- sleep(3000);
- /* read arp table, look for addr duplication */
- snprint(buf, sizeof buf, "%s/arp", conf.mpoint);
- bp = Bopen(buf, OREAD);
- if (bp == 0) {
- warning("couldn't open %s: %r", buf);
- return -1;
- }
- snprint(buf, sizeof buf, "%I", conf.laddr);
- while(p = Brdline(bp, '\n')){
- p[Blinelen(bp)-1] = 0;
- if(cistrstr(p, buf) != 0) {
- warning("found dup entry in arp cache");
- dupfound = 1;
- break;
- }
- }
- Bterm(bp);
- if (dupfound)
- doremove();
- else {
- n = sprint(buf, "add %I %M", conf.laddr, conf.mask);
- if(validip(conf.raddr)){
- n += snprint(buf+n, sizeof buf-n, " %I", conf.raddr);
- if(conf.mtu != 0)
- n += snprint(buf+n, sizeof buf-n, " %d",
- conf.mtu);
- }
- write(conf.cfd, buf, n);
- }
- return 0;
- }
- static int
- recvra6on(char *net, int conn)
- {
- Ipifc* ifc;
- ifc = readipifc(net, nil, conn);
- if (ifc == nil)
- return 0;
- else if (ifc->sendra6 > 0)
- return IsRouter;
- else if (ifc->recvra6 > 0)
- return IsHostRecv;
- else
- return IsHostNoRecv;
- }
- /* send icmpv6 router solicitation to multicast address for all routers */
- static void
- sendrs(int fd)
- {
- Routersol *rs;
- uint8_t buff[sizeof *rs];
- memset(buff, 0, sizeof buff);
- rs = (Routersol *)buff;
- memmove(rs->dst, v6allroutersL, IPaddrlen);
- memmove(rs->src, v6Unspecified, IPaddrlen);
- rs->type = ICMP6_RS;
- if(write(fd, rs, sizeof buff) < sizeof buff)
- ralog("sendrs: write failed, pkt size %d", sizeof buff);
- else
- ralog("sendrs: sent solicitation to %I from %I on %s",
- rs->dst, rs->src, conf.dev);
- }
- /*
- * a router receiving a router adv from another
- * router calls this; it is basically supposed to
- * log the information in the ra and raise a flag
- * if any parameter value is different from its configured values.
- *
- * doing nothing for now since I don't know where to log this yet.
- */
- static void
- recvrarouter(uint8_t buf[], int pktlen)
- {
- USED(buf); USED(pktlen);
- ralog("i am a router and got a router advert");
- }
- /* host receiving a router advertisement calls this */
- static void
- ewrite(int fd, char *str)
- {
- int n;
- n = strlen(str);
- if (write(fd, str, n) != n)
- ralog("write(%s) failed: %r", str);
- }
- static void
- issuebasera6(Conf *cf)
- {
- char *cfg;
- cfg = smprint("ra6 mflag %d oflag %d reachtime %d rxmitra %d "
- "ttl %d routerlt %d",
- cf->mflag, cf->oflag, cf->reachtime, cf->rxmitra,
- cf->ttl, cf->routerlt);
- ewrite(cf->cfd, cfg);
- free(cfg);
- }
- static void
- issuerara6(Conf *cf)
- {
- char *cfg;
- cfg = smprint("ra6 sendra %d recvra %d maxraint %d minraint %d "
- "linkmtu %d",
- cf->sendra, cf->recvra, cf->maxraint, cf->minraint,
- cf->linkmtu);
- ewrite(cf->cfd, cfg);
- free(cfg);
- }
- static void
- issueadd6(Conf *cf)
- {
- char *cfg;
- cfg = smprint("add6 %I %d %d %d %lu %lu", cf->v6pref, cf->prefixlen,
- cf->onlink, cf->autoflag, cf->validlt, cf->preflt);
- ewrite(cf->cfd, cfg);
- free(cfg);
- }
- static void
- recvrahost(uint8_t buf[], int pktlen)
- {
- int arpfd, m, n;
- char abuf[100];
- uint8_t optype;
- Lladdropt *llao;
- Mtuopt *mtuo;
- Prefixopt *prfo;
- Routeradv *ra;
- static int first = 1;
- ra = (Routeradv*)buf;
- // memmove(conf.v6gaddr, ra->src, IPaddrlen);
- conf.ttl = ra->cttl;
- conf.mflag = (MFMASK & ra->mor);
- conf.oflag = (OCMASK & ra->mor);
- conf.routerlt = nhgets(ra->routerlt);
- conf.reachtime = nhgetl(ra->rchbltime);
- conf.rxmitra = nhgetl(ra->rxmtimer);
- // issueadd6(&conf); /* for conf.v6gaddr? */
- if (fprint(conf.cfd, "ra6 recvra 1") < 0)
- ralog("write(ra6 recvra 1) failed: %r");
- issuebasera6(&conf);
- m = sizeof *ra;
- while (pktlen - m > 0) {
- optype = buf[m];
- switch (optype) {
- case V6nd_srclladdr:
- llao = (Lladdropt *)&buf[m];
- m += 8 * buf[m+1];
- if (llao->len != 1) {
- ralog("recvrahost: illegal len (%d) for source "
- "link layer address option", llao->len);
- return;
- }
- if (!ISIPV6LINKLOCAL(ra->src)) {
- ralog("recvrahost: non-link-local src addr for "
- "router adv %I", ra->src);
- return;
- }
- snprint(abuf, sizeof abuf, "%s/arp", conf.mpoint);
- arpfd = open(abuf, OWRITE);
- if (arpfd < 0) {
- ralog("recvrahost: couldn't open %s to write: %r",
- abuf);
- return;
- }
- n = snprint(abuf, sizeof abuf, "add ether %I %E",
- ra->src, llao->lladdr);
- if (write(arpfd, abuf, n) < n)
- ralog("recvrahost: couldn't write to %s/arp",
- conf.mpoint);
- close(arpfd);
- break;
- case V6nd_targlladdr:
- case V6nd_redirhdr:
- m += 8 * buf[m+1];
- ralog("ignoring unexpected option type `%s' in Routeradv",
- optname(optype));
- break;
- case V6nd_mtu:
- mtuo = (Mtuopt*)&buf[m];
- m += 8 * mtuo->len;
- conf.linkmtu = nhgetl(mtuo->mtu);
- break;
- case V6nd_pfxinfo:
- prfo = (Prefixopt*)&buf[m];
- m += 8 * prfo->len;
- if (prfo->len != 4) {
- ralog("illegal len (%d) for prefix option",
- prfo->len);
- return;
- }
- memmove(conf.v6pref, prfo->pref, IPaddrlen);
- conf.prefixlen = prfo->plen;
- conf.onlink = ((prfo->lar & OLMASK) != 0);
- conf.autoflag = ((prfo->lar & AFMASK) != 0);
- conf.validlt = nhgetl(prfo->validlt);
- conf.preflt = nhgetl(prfo->preflt);
- issueadd6(&conf);
- if (first) {
- first = 0;
- ralog("got initial RA from %I on %s; pfx %I",
- ra->src, conf.dev, prfo->pref);
- }
- break;
- default:
- if (debug)
- ralog("ignoring optype %d in Routeradv from %I",
- optype, ra->src);
- /* fall through */
- case V6nd_srcaddrs:
- /* netsbd sends this, so quietly ignore it for now */
- m += 8 * buf[m+1];
- break;
- }
- }
- }
- /*
- * daemon to receive router advertisements from routers
- */
- void
- recvra6(void)
- {
- int fd, cfd, n, sendrscnt, sleepfor;
- uint8_t buf[4096];
- /* TODO: why not v6allroutersL? */
- fd = dialicmp(v6allnodesL, ICMP6_RA, &cfd);
- if (fd < 0)
- sysfatal("can't open icmp_ra connection: %r");
- notify(catch);
- sendrscnt = Maxv6rss;
- switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){
- case -1:
- sysfatal("can't fork: %r");
- default:
- return;
- case 0:
- break;
- }
- procsetname("recvra6 on %s", conf.dev);
- ralog("recvra6 on %s", conf.dev);
- sleepfor = jitter();
- for (;;) {
- /*
- * We only get 3 (Maxv6rss) tries, so make sure we
- * wait long enough to be certain that at least one RA
- * will be transmitted.
- */
- if (sleepfor < 7000)
- sleepfor = 7000;
- alarm(sleepfor);
- n = read(fd, buf, sizeof buf);
- alarm(0);
- if (n <= 0) {
- if (sendrscnt > 0) {
- sendrscnt--;
- if (recvra6on(conf.mpoint, myifc) == IsHostRecv)
- sendrs(fd);
- sleepfor = V6rsintvl + nrand(100);
- }
- if (sendrscnt == 0) {
- sendrscnt--;
- sleepfor = 0;
- ralog("recvra6: no router advs after %d sols on %s",
- Maxv6rss, conf.dev);
- }
- continue;
- }
- sleepfor = 0;
- sendrscnt = -1; /* got at least initial ra; no whining */
- switch (recvra6on(conf.mpoint, myifc)) {
- case IsRouter:
- recvrarouter(buf, n);
- break;
- case IsHostRecv:
- recvrahost(buf, n);
- break;
- case IsHostNoRecv:
- ralog("recvra6: recvra off, quitting on %s", conf.dev);
- close(fd);
- exits(0);
- default:
- ralog("recvra6: unable to read router status on %s",
- conf.dev);
- break;
- }
- }
- }
- /*
- * return -1 -- error, reading/writing some file,
- * 0 -- no arp table updates
- * 1 -- successful arp table update
- */
- int
- recvrs(uint8_t *buf, int pktlen, uint8_t *sol)
- {
- int n, optsz, arpfd;
- char abuf[256];
- Routersol *rs;
- Lladdropt *llao;
- rs = (Routersol *)buf;
- n = sizeof *rs;
- optsz = pktlen - n;
- pkt2str(buf, buf+pktlen, abuf, abuf+nelem(abuf));
- if (optsz != sizeof *llao)
- return 0;
- if (buf[n] != V6nd_srclladdr || 8*buf[n+1] != sizeof *llao) {
- ralog("rs opt err %s", abuf);
- return -1;
- }
- ralog("rs recv %s", abuf);
- if (memcmp(rs->src, v6Unspecified, IPaddrlen) == 0)
- return 0;
- snprint(abuf, sizeof abuf, "%s/arp", conf.mpoint);
- arpfd = open(abuf, OWRITE);
- if (arpfd < 0) {
- ralog("recvrs: can't open %s/arp to write: %r", conf.mpoint);
- return -1;
- }
- llao = (Lladdropt *)(uint64_t)buf[n];
- n = snprint(abuf, sizeof abuf, "add ether %I %E", rs->src, llao->lladdr);
- if (write(arpfd, abuf, n) < n) {
- ralog("recvrs: can't write to %s/arp: %r", conf.mpoint);
- close(arpfd);
- return -1;
- }
- memmove(sol, rs->src, IPaddrlen);
- close(arpfd);
- return 1;
- }
- void
- sendra(int fd, uint8_t *dst, int rlt)
- {
- int pktsz, preflen;
- char abuf[1024], tmp[40];
- uint8_t buf[1024], macaddr[6], src[IPaddrlen];
- Ipifc *ifc = nil;
- Iplifc *lifc, *nlifc;
- Lladdropt *llao;
- Prefixopt *prfo;
- Routeradv *ra;
- memset(buf, 0, sizeof buf);
- ra = (Routeradv *)buf;
- myetheraddr(macaddr, conf.dev);
- ea2lla(src, macaddr);
- memmove(ra->src, src, IPaddrlen);
- memmove(ra->dst, dst, IPaddrlen);
- ra->type = ICMP6_RA;
- ra->cttl = conf.ttl;
- if (conf.mflag > 0)
- ra->mor |= MFMASK;
- if (conf.oflag > 0)
- ra->mor |= OCMASK;
- if (rlt > 0)
- hnputs(ra->routerlt, conf.routerlt);
- else
- hnputs(ra->routerlt, 0);
- hnputl(ra->rchbltime, conf.reachtime);
- hnputl(ra->rxmtimer, conf.rxmitra);
- pktsz = sizeof *ra;
- /* include all global unicast prefixes on interface in prefix options */
- ifc = readipifc(conf.mpoint, ifc, myifc);
- for (lifc = (ifc? ifc->lifc: nil); lifc; lifc = nlifc) {
- nlifc = lifc->next;
- prfo = (Prefixopt *)(buf + pktsz);
- /* global unicast address? */
- if (!ISIPV6LINKLOCAL(lifc->ip) && !ISIPV6MCAST(lifc->ip) &&
- memcmp(lifc->ip, IPnoaddr, IPaddrlen) != 0 &&
- memcmp(lifc->ip, v6loopback, IPaddrlen) != 0 &&
- !isv4(lifc->ip)) {
- memmove(prfo->pref, lifc->net, IPaddrlen);
- /* hack to find prefix length */
- snprint(tmp, sizeof tmp, "%M", lifc->mask);
- preflen = atoi(&tmp[1]);
- prfo->plen = preflen & 0xff;
- if (prfo->plen == 0)
- continue;
- prfo->type = V6nd_pfxinfo;
- prfo->len = 4;
- prfo->lar = AFMASK;
- hnputl(prfo->validlt, lifc->validlt);
- hnputl(prfo->preflt, lifc->preflt);
- pktsz += sizeof *prfo;
- }
- }
- /*
- * include link layer address (mac address for now) in
- * link layer address option
- */
- llao = (Lladdropt *)(buf + pktsz);
- llao->type = V6nd_srclladdr;
- llao->len = 1;
- memmove(llao->lladdr, macaddr, sizeof macaddr);
- pktsz += sizeof *llao;
- pkt2str(buf+40, buf+pktsz, abuf, abuf+1024);
- if(write(fd, buf, pktsz) < pktsz)
- ralog("sendra fail %s: %r", abuf);
- else if (debug)
- ralog("sendra succ %s", abuf);
- }
- /*
- * daemon to send router advertisements to hosts
- */
- void
- sendra6(void)
- {
- int fd, cfd, n, dstknown = 0, sendracnt, sleepfor, nquitmsgs;
- int32_t lastra, now;
- uint8_t buf[4096], dst[IPaddrlen];
- Ipifc *ifc = nil;
- fd = dialicmp(v6allnodesL, ICMP6_RS, &cfd);
- if (fd < 0)
- sysfatal("can't open icmp_rs connection: %r");
- notify(catch);
- sendracnt = Maxv6initras;
- nquitmsgs = Maxv6finalras;
- switch(rfork(RFPROC|RFMEM|RFFDG|RFNOWAIT|RFNOTEG)){
- case -1:
- sysfatal("can't fork: %r");
- default:
- return;
- case 0:
- break;
- }
- procsetname("sendra6 on %s", conf.dev);
- ralog("sendra6 on %s", conf.dev);
- sleepfor = jitter();
- for (;;) {
- lastra = time(0);
- if (sleepfor < 0)
- sleepfor = 0;
- alarm(sleepfor);
- n = read(fd, buf, sizeof buf);
- alarm(0);
- ifc = readipifc(conf.mpoint, ifc, myifc);
- if (ifc == nil) {
- ralog("sendra6: can't read router params on %s",
- conf.mpoint);
- continue;
- }
- if (ifc->sendra6 <= 0)
- if (nquitmsgs > 0) {
- sendra(fd, v6allnodesL, 0);
- nquitmsgs--;
- sleepfor = Minv6interradelay + jitter();
- continue;
- } else {
- ralog("sendra6: sendra off, quitting on %s",
- conf.dev);
- exits(0);
- }
- nquitmsgs = Maxv6finalras;
- if (n <= 0) { /* no RS */
- if (sendracnt > 0)
- sendracnt--;
- } else { /* respond to RS */
- dstknown = recvrs(buf, n, dst);
- now = time(0);
- if (now - lastra < Minv6interradelay) {
- /* too close, skip */
- sleepfor = lastra + Minv6interradelay +
- jitter() - now;
- continue;
- }
- sleep(jitter());
- }
- sleepfor = randint(ifc->rp.minraint, ifc->rp.maxraint);
- if (dstknown > 0)
- sendra(fd, dst, 1);
- else
- sendra(fd, v6allnodesL, 1);
- }
- }
- void
- startra6(void)
- {
- static char routeon[] = "iprouting 1";
- if (conf.recvra > 0)
- recvra6();
- if (conf.sendra > 0) {
- if (write(conf.cfd, routeon, sizeof routeon - 1) < 0) {
- warning("write (iprouting 1) failed: %r");
- return;
- }
- sendra6();
- if (conf.recvra <= 0)
- recvra6();
- }
- }
- void
- doipv6(int what)
- {
- nip = nipifcs(conf.mpoint);
- if(!noconfig){
- lookforip(conf.mpoint);
- controldevice();
- binddevice();
- }
- switch (what) {
- default:
- sysfatal("unknown IPv6 verb");
- case Vaddpref6:
- issueadd6(&conf);
- break;
- case Vra6:
- issuebasera6(&conf);
- issuerara6(&conf);
- dolog = 1;
- startra6();
- break;
- }
- }
|