12 * definitions that are innately tied to BSD
25 Infinity= 16, /* infinite hop count */
26 Maxpacket= 488, /* largest packet body */
33 typedef struct Rip Rip;
42 typedef struct Ripmsg Ripmsg;
48 Rip rip[1]; /* the rest of the packet consists of routes */
53 Maxroutes= (Maxpacket-4)/sizeof(Ripmsg),
61 Nroute= 2048, /* this has to be smaller than what /ip has */
62 Nhash= 256, /* routing hash buckets */
66 typedef struct Route Route;
82 Route def; /* default route (immutable by us) */
85 typedef struct Ifc Ifc;
89 uchar addr[Pasize]; /* my address */
90 uchar mask[Pasize]; /* subnet mask */
91 uchar net[Pasize]; /* subnet */
92 uchar *cmask; /* class mask */
93 uchar cnet[Pasize]; /* class net */
101 * specific networks to broadcast on
103 typedef struct Bnet Bnet;
119 void readroutes(void);
121 void considerroute(Route*);
122 void installroute(Route*);
123 void removeroute(Route*);
124 uchar *getmask(uchar*);
125 void broadcast(void);
126 void timeoutroutes(void);
129 fatal(int syserr, char *fmt, ...)
131 char buf[ERRMAX], sysbuf[ERRMAX];
135 vseprint(buf, buf+sizeof(buf), fmt, arg);
138 errstr(sysbuf, sizeof sysbuf);
139 fprint(2, "routed: %s: %s\n", buf, sysbuf);
142 fprint(2, "routed: %s\n", buf);
147 v4parseipmask(uchar *ip, char *p)
150 uchar v6ip[IPaddrlen];
152 x = parseipmask(v6ip, p);
153 memmove(ip, v6ip+IPv4off, 4);
160 uchar v6ip[IPaddrlen];
168 v4maskip(uchar *from, uchar *mask, uchar *to)
172 for(i = 0; i < Pasize; i++)
173 *to++ = *from++ & *mask++;
177 v6tov4mask(uchar *v4, uchar *v6)
179 memmove(v4, v6+IPv4off, 4);
182 #define equivip(a, b) (memcmp((a), (b), Pasize) == 0)
185 ding(void *u, char *msg)
189 if(strstr(msg, "alarm"))
197 fprint(2, "usage: %s [-bnd] [-x netmtpt]\n", argv0);
202 main(int argc, char *argv[])
204 int dobroadcast, i, n;
216 setnetmtpt(netdir, sizeof(netdir), nil);
232 setnetmtpt(netdir, sizeof(netdir), p);
238 /* specific broadcast nets */
241 bn = (Bnet*)malloc(sizeof(Bnet));
243 fatal(1, "out of mem");
244 v4parseip(bn->addr, *argv);
252 /* command returns */
254 switch(rfork(RFNOTEG|RFPROC|RFFDG|RFNOWAIT)) {
264 fmtinstall('E', eipfmt);
265 fmtinstall('V', eipfmt);
267 snprint(routefile, sizeof(routefile), "%s/iproute", netdir);
268 snprint(buf, sizeof(buf), "%s/iproute", netdir);
278 diff = btime - time(0);
284 btime = time(0) + 2*60;
288 n = read(ripfd, buf, sizeof(buf));
293 n = (n - Udphdrsize - 4) / sizeof(Rip);
298 m = (Ripmsg*)(buf+Udphdrsize);
299 if(m->type != Response || m->vers != Version)
301 v6tov4(raddr, up->raddr);
303 /* ignore our own messages */
304 for(i = 0; i < ialloc.nifc; i++)
305 if(equivip(ialloc.ifc[i].addr, raddr))
309 for(r = m->rip; r < &m->rip[n]; r++){
310 memmove(route.gate, raddr, Pasize);
311 memmove(route.mask, getmask(r->addr), Pasize);
312 v4maskip(r->addr, route.mask, route.dest);
313 route.metric = nhgetl(r->metric) + 1;
316 considerroute(&route);
326 char data[128], devdir[40];
328 snprint(data, sizeof(data), "%s/udp!*!rip", netdir);
329 ripctl = announce(data, devdir);
331 fatal(1, "can't announce");
332 if(fprint(ripctl, "headers") < 0)
333 fatal(1, "can't set header mode");
335 sprint(data, "%s/data", devdir);
336 rip = open(data, ORDWR);
338 fatal(1, "open udp data");
354 ifcs = readipifc(netdir, ifcs, -1);
356 for(ifc = ifcs; ifc != nil; ifc = ifc->next){
357 for(lifc = ifc->lifc; lifc != nil && i < Nifc; lifc = lifc->next){
358 // ignore any interfaces that aren't v4
359 if(memcmp(lifc->ip, v4prefix, IPaddrlen-IPv4addrlen) != 0)
361 ip = &ialloc.ifc[i++];
362 v6tov4(ip->addr, lifc->ip);
363 v6tov4mask(ip->mask, lifc->mask);
364 v6tov4(ip->net, lifc->net);
365 ip->cmask = v4defmask(ip->net);
366 v4maskip(ip->net, ip->cmask, ip->cnet);
370 memmove(route.mask, ip->mask, Pasize);
371 memmove(route.dest, ip->net, Pasize);
372 memset(route.gate, 0, Pasize);
374 considerroute(&route);
376 /* mark as broadcast */
379 else for(bn = bnets; bn; bn = bn->next)
380 if(memcmp(bn->addr, ip->net, Pasize) == 0){
398 b = Bopen(routefile, OREAD);
401 while(p = Brdline(b, '\n')){
402 p[Blinelen(b)-1] = 0;
403 n = getfields(p, f, 6, 1, " \t");
406 v4parseip(route.dest, f[0]);
407 v4parseipmask(route.mask, f[1]);
408 v4parseip(route.gate, f[2]);
409 route.metric = Infinity;
410 if(equivip(route.dest, ralloc.def.dest)
411 && equivip(route.mask, ralloc.def.mask))
412 memmove(ralloc.def.gate, route.gate, Pasize);
413 else if(!equivip(route.dest, route.gate) && strchr(f[3], 'i') == 0)
414 considerroute(&route);
420 * route's hashed by net, not subnet
428 v4maskip(d, v4defmask(d), net);
429 h = net[0] + net[1] + net[2];
434 * consider installing a route. Do so only if it is better than what
438 considerroute(Route *r)
444 fprint(2, "consider %16V & %16V -> %16V %d\n", r->dest, r->mask, r->gate, r->metric);
450 /* don't allow our default route to be highjacked */
451 if(equivip(r->dest, ralloc.def.dest) || equivip(r->mask, ralloc.def.mask))
455 for(hp = ralloc.hash[h]; hp; hp = hp->next){
456 if(equivip(hp->dest, r->dest)){
458 * found a match, replace if better (or much newer)
460 if(r->metric < hp->metric || now-hp->time > 5*60){
462 memmove(hp->mask, r->mask, Pasize);
463 memmove(hp->gate, r->gate, Pasize);
464 hp->metric = r->metric;
467 if(equivip(hp->gate, r->gate))
474 * no match, look for space
476 for(hp = ralloc.route; hp < &ralloc.route[Nroute]; hp++)
481 fatal(0, "no more routes");
483 memmove(hp, r, sizeof(Route));
484 hp->next = ralloc.hash[h];
490 removeroute(Route *r)
494 fd = open(routefile, ORDWR);
496 fprint(2, "can't open oproute\n");
500 fprint(fd, "delete %V", r->dest);
502 fprint(2, "removeroute %V\n", r->dest);
507 * pass a route to the kernel or /ip. Don't bother if it is just the default
511 installroute(Route *r)
519 * don't install routes whose gateway is 00000000
521 if(equivip(r->gate, ralloc.def.dest))
524 fd = open(routefile, ORDWR);
526 fprint(2, "can't open oproute\n");
532 * if the gateway is the same as the default gateway
533 * we may be able to avoid a entry in the kernel
535 if(equivip(r->gate, ralloc.def.gate)){
537 * look for a less specific match
539 for(hp = ralloc.hash[h]; hp; hp = hp->next){
540 v4maskip(hp->mask, r->dest, net);
541 if(equivip(net, hp->dest) && !equivip(hp->gate, ralloc.def.gate))
545 * if no less specific match, just use the default
549 fprint(fd, "delete %V", r->dest);
551 fprint(2, "delete %V\n", r->dest);
557 fprint(fd, "add %V %V %V", r->dest, r->mask, r->gate);
559 fprint(2, "add %V & %V -> %V\n", r->dest, r->mask, r->gate);
564 * return true of dest is on net
567 onnet(uchar *dest, uchar *net, uchar *netmask)
571 v4maskip(dest, netmask, dnet);
572 return equivip(dnet, net);
576 * figure out what mask to use, if we have a direct connected network
577 * with the same class net use its subnet mask.
589 for(i = 0; i < ialloc.nifc; i++){
591 if(onnet(dest, ip->cnet, ip->cmask)){
592 nmask = nhgetl(ip->mask);
606 * broadcast routes onto all networks
612 uchar raddr[Pasize], mbuf[Udphdrsize+512];
618 for(n = 0; n < Pasize; n++)
619 raddr[n] = ip->net[n] | ~(ip->mask[n]);
620 v4tov6(u->raddr, raddr);
621 hnputs(u->rport, 520);
622 m = (Ripmsg*)(mbuf+Udphdrsize);
626 fprint(2, "to %V\n", u->raddr);
629 for(h = 0; h < Nhash; h++){
630 for(r = ralloc.hash[h]; r; r = r->next){
632 * don't send any route back to the net
635 if(onnet(r->gate, ip->net, ip->mask))
639 * don't tell a network about itself
641 if(equivip(r->dest, ip->net))
645 * don't tell nets about other net's subnets
647 if(!equivip(r->mask, v4defmask(r->dest))
648 && !equivip(ip->cmask, v4defmask(r->dest)))
651 memset(&m->rip[n], 0, sizeof(m->rip[n]));
652 memmove(m->rip[n].addr, r->dest, Pasize);
654 hnputl(m->rip[n].metric, 1);
656 hnputl(m->rip[n].metric, r->metric);
657 hnputs(m->rip[n].family, AF_INET);
660 fprint(2, " %16V & %16V -> %16V %2d\n",
661 r->dest, r->mask, r->gate, r->metric);
663 if(++n == Maxroutes && !readonly){
664 write(ripfd, mbuf, Udphdrsize + 4 + n*20);
671 write(ripfd, mbuf, Udphdrsize+4+n*20);
679 for(i = 0; i < ialloc.nifc; i++){
680 if(ialloc.ifc[i].bcast)
681 sendto(&ialloc.ifc[i]);
686 * timeout any routes that haven't been refreshed and aren't wired
697 for(h = 0; h < Nhash; h++){
699 for(r = *l; r; r = *l){
700 if(r->metric < Infinity && now - r->time > 10*60){