1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <ip.h>
5
6 enum
7 {
8 Version= 1,
9 Pasize= 4,
10
11 /*
12 * definitions that are innately tied to BSD
13 */
14 AF_INET= 2,
15 AF_UNSPEC= 0,
16
17 /*
18 * Packet types.
19 */
20 Request= 1,
21 Response= 2,
22 Traceon= 3,
23 Traceoff= 4,
24
25 Infinity= 16, /* infinite hop count */
26 Maxpacket= 488, /* largest packet body */
27 };
28
29
30 /*
31 * network info
32 */
33 typedef struct Rip Rip;
34 struct Rip
35 {
36 uchar family[2];
37 uchar port[2];
38 uchar addr[Pasize];
39 uchar pad[8];
40 uchar metric[4];
41 };
42 typedef struct Ripmsg Ripmsg;
43 struct Ripmsg
44 {
45 uchar type;
46 uchar vers;
47 uchar pad[2];
48 Rip rip[1]; /* the rest of the packet consists of routes */
49 };
50
51 enum
52 {
53 Maxroutes= (Maxpacket-4)/sizeof(Ripmsg),
54 };
55
56 /*
57 * internal route info
58 */
59 enum
60 {
61 Nroute= 2048, /* this has to be smaller than what /ip has */
62 Nhash= 256, /* routing hash buckets */
63 Nifc= 16,
64 };
65
66 typedef struct Route Route;
67 struct Route
68 {
69 Route *next;
70
71 uchar dest[Pasize];
72 uchar mask[Pasize];
73 uchar gate[Pasize];
74 int metric;
75 int inuse;
76 long time;
77 };
78 struct {
79 Route route[Nroute];
80 Route *hash[Nhash];
81 int nroute;
82 Route def; /* default route (immutable by us) */
83 } ralloc;
84
85 typedef struct Ifc Ifc;
86 struct Ifc
87 {
88 int bcast;
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 */
94 };
95 struct {
96 Ifc ifc[Nifc];
97 int nifc;
98 } ialloc;
99
100 /*
101 * specific networks to broadcast on
102 */
103 typedef struct Bnet Bnet;
104 struct Bnet
105 {
106 Bnet *next;
107 uchar addr[Pasize];
108 };
109 Bnet *bnets;
110
111 int ripfd;
112 long now;
113 int debug;
114 int readonly;
115 char routefile[256];
116 char netdir[256];
117
118 int openport(void);
119 void readroutes(void);
120 void readifcs(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);
127
128 void
fatal(int syserr,char * fmt,...)129 fatal(int syserr, char *fmt, ...)
130 {
131 char buf[ERRMAX], sysbuf[ERRMAX];
132 va_list arg;
133
134 va_start(arg, fmt);
135 vseprint(buf, buf+sizeof(buf), fmt, arg);
136 va_end(arg);
137 if(syserr) {
138 errstr(sysbuf, sizeof sysbuf);
139 fprint(2, "routed: %s: %s\n", buf, sysbuf);
140 }
141 else
142 fprint(2, "routed: %s\n", buf);
143 exits(buf);
144 }
145
146 ulong
v4parseipmask(uchar * ip,char * p)147 v4parseipmask(uchar *ip, char *p)
148 {
149 ulong x;
150 uchar v6ip[IPaddrlen];
151
152 x = parseipmask(v6ip, p);
153 memmove(ip, v6ip+IPv4off, 4);
154 return x;
155 }
156
157 uchar*
v4defmask(uchar * ip)158 v4defmask(uchar *ip)
159 {
160 uchar v6ip[IPaddrlen];
161
162 v4tov6(v6ip, ip);
163 ip = defmask(v6ip);
164 return ip+IPv4off;
165 }
166
167 void
v4maskip(uchar * from,uchar * mask,uchar * to)168 v4maskip(uchar *from, uchar *mask, uchar *to)
169 {
170 int i;
171
172 for(i = 0; i < Pasize; i++)
173 *to++ = *from++ & *mask++;
174 }
175
176 void
v6tov4mask(uchar * v4,uchar * v6)177 v6tov4mask(uchar *v4, uchar *v6)
178 {
179 memmove(v4, v6+IPv4off, 4);
180 }
181
182 #define equivip(a, b) (memcmp((a), (b), Pasize) == 0)
183
184 void
ding(void * u,char * msg)185 ding(void *u, char *msg)
186 {
187 USED(u);
188
189 if(strstr(msg, "alarm"))
190 noted(NCONT);
191 noted(NDFLT);
192 }
193
194 void
usage(void)195 usage(void)
196 {
197 fprint(2, "usage: %s [-bnd] [-x netmtpt]\n", argv0);
198 exits("usage");
199 }
200
201 void
main(int argc,char * argv[])202 main(int argc, char *argv[])
203 {
204 int dobroadcast, i, n;
205 long diff;
206 char *p;
207 char buf[2*1024];
208 uchar raddr[Pasize];
209 Bnet *bn, **l;
210 Udphdr *up;
211 Rip *r;
212 Ripmsg *m;
213 Route route;
214 static long btime;
215
216 setnetmtpt(netdir, sizeof(netdir), nil);
217 dobroadcast = 0;
218 ARGBEGIN{
219 case 'b':
220 dobroadcast++;
221 break;
222 case 'd':
223 debug++;
224 break;
225 case 'n':
226 readonly++;
227 break;
228 case 'x':
229 p = ARGF();
230 if(p == nil)
231 usage();
232 setnetmtpt(netdir, sizeof(netdir), p);
233 break;
234 default:
235 usage();
236 }ARGEND
237
238 /* specific broadcast nets */
239 l = &bnets;
240 while(argc > 0){
241 bn = (Bnet*)malloc(sizeof(Bnet));
242 if(bn == 0)
243 fatal(1, "out of mem");
244 v4parseip(bn->addr, *argv);
245 *l = bn;
246 l = &bn->next;
247 argc--;
248 argv++;
249 dobroadcast++;
250 }
251
252 /* command returns */
253 if(!debug)
254 switch(rfork(RFNOTEG|RFPROC|RFFDG|RFNOWAIT)) {
255 case -1:
256 fatal(1, "fork");
257 case 0:
258 break;
259 default:
260 exits(0);
261 }
262
263
264 fmtinstall('E', eipfmt);
265 fmtinstall('V', eipfmt);
266
267 snprint(routefile, sizeof(routefile), "%s/iproute", netdir);
268 snprint(buf, sizeof(buf), "%s/iproute", netdir);
269
270 now = time(0);
271 readifcs();
272 readroutes();
273
274 notify(ding);
275
276 ripfd = openport();
277 for(;;) {
278 diff = btime - time(0);
279 if(diff <= 0){
280 if(dobroadcast)
281 broadcast();
282 timeoutroutes();
283
284 btime = time(0) + 2*60;
285 diff = 2*60;
286 }
287 alarm(diff*1000);
288 n = read(ripfd, buf, sizeof(buf));
289 alarm(0);
290 if(n <= 0)
291 continue;
292
293 n = (n - Udphdrsize - 4) / sizeof(Rip);
294 if(n <= 0)
295 continue;
296
297 up = (Udphdr*)buf;
298 m = (Ripmsg*)(buf+Udphdrsize);
299 if(m->type != Response || m->vers != Version)
300 continue;
301 v6tov4(raddr, up->raddr);
302
303 /* ignore our own messages */
304 for(i = 0; i < ialloc.nifc; i++)
305 if(equivip(ialloc.ifc[i].addr, raddr))
306 continue;
307
308 now = time(0);
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;
314 if(route.metric < 1)
315 continue;
316 considerroute(&route);
317 }
318 }
319 /* not reached */
320 }
321
322 int
openport(void)323 openport(void)
324 {
325 int ripctl, rip;
326 char data[128], devdir[40];
327
328 snprint(data, sizeof(data), "%s/udp!*!rip", netdir);
329 ripctl = announce(data, devdir);
330 if(ripctl < 0)
331 fatal(1, "can't announce");
332 if(fprint(ripctl, "headers") < 0)
333 fatal(1, "can't set header mode");
334
335 sprint(data, "%s/data", devdir);
336 rip = open(data, ORDWR);
337 if(rip < 0)
338 fatal(1, "open udp data");
339 return rip;
340 }
341
342 Ipifc *ifcs;
343
344 void
readifcs(void)345 readifcs(void)
346 {
347 Ipifc *ifc;
348 Iplifc *lifc;
349 Ifc *ip;
350 Bnet *bn;
351 Route route;
352 int i;
353
354 ifcs = readipifc(netdir, ifcs, -1);
355 i = 0;
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)
360 continue;
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);
367 ip->bcast = 0;
368
369 /* add as a route */
370 memmove(route.mask, ip->mask, Pasize);
371 memmove(route.dest, ip->net, Pasize);
372 memset(route.gate, 0, Pasize);
373 route.metric = 0;
374 considerroute(&route);
375
376 /* mark as broadcast */
377 if(bnets == 0)
378 ip->bcast = 1;
379 else for(bn = bnets; bn; bn = bn->next)
380 if(memcmp(bn->addr, ip->net, Pasize) == 0){
381 ip->bcast = 1;
382 break;
383 }
384 }
385 }
386 ialloc.nifc = i;
387 }
388
389 void
readroutes(void)390 readroutes(void)
391 {
392 int n;
393 char *p;
394 Biobuf *b;
395 char *f[6];
396 Route route;
397
398 b = Bopen(routefile, OREAD);
399 if(b == 0)
400 return;
401 while(p = Brdline(b, '\n')){
402 p[Blinelen(b)-1] = 0;
403 n = getfields(p, f, 6, 1, " \t");
404 if(n < 5)
405 continue;
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);
415 }
416 Bterm(b);
417 }
418
419 /*
420 * route's hashed by net, not subnet
421 */
422 ulong
rhash(uchar * d)423 rhash(uchar *d)
424 {
425 ulong h;
426 uchar net[Pasize];
427
428 v4maskip(d, v4defmask(d), net);
429 h = net[0] + net[1] + net[2];
430 return h % Nhash;
431 }
432
433 /*
434 * consider installing a route. Do so only if it is better than what
435 * we have.
436 */
437 void
considerroute(Route * r)438 considerroute(Route *r)
439 {
440 ulong h;
441 Route *hp;
442
443 if(debug)
444 fprint(2, "consider %16V & %16V -> %16V %d\n", r->dest, r->mask, r->gate, r->metric);
445
446 r->next = 0;
447 r->time = now;
448 r->inuse = 1;
449
450 /* don't allow our default route to be highjacked */
451 if(equivip(r->dest, ralloc.def.dest) || equivip(r->mask, ralloc.def.mask))
452 return;
453
454 h = rhash(r->dest);
455 for(hp = ralloc.hash[h]; hp; hp = hp->next){
456 if(equivip(hp->dest, r->dest)){
457 /*
458 * found a match, replace if better (or much newer)
459 */
460 if(r->metric < hp->metric || now-hp->time > 5*60){
461 removeroute(hp);
462 memmove(hp->mask, r->mask, Pasize);
463 memmove(hp->gate, r->gate, Pasize);
464 hp->metric = r->metric;
465 installroute(hp);
466 }
467 if(equivip(hp->gate, r->gate))
468 hp->time = now;
469 return;
470 }
471 }
472
473 /*
474 * no match, look for space
475 */
476 for(hp = ralloc.route; hp < &ralloc.route[Nroute]; hp++)
477 if(hp->inuse == 0)
478 break;
479
480 if(hp == 0)
481 fatal(0, "no more routes");
482
483 memmove(hp, r, sizeof(Route));
484 hp->next = ralloc.hash[h];
485 ralloc.hash[h] = hp;
486 installroute(hp);
487 }
488
489 void
removeroute(Route * r)490 removeroute(Route *r)
491 {
492 int fd;
493
494 fd = open(routefile, ORDWR);
495 if(fd < 0){
496 fprint(2, "can't open oproute\n");
497 return;
498 }
499 if(!readonly)
500 fprint(fd, "delete %V", r->dest);
501 if(debug)
502 fprint(2, "removeroute %V\n", r->dest);
503 close(fd);
504 }
505
506 /*
507 * pass a route to the kernel or /ip. Don't bother if it is just the default
508 * gateway.
509 */
510 void
installroute(Route * r)511 installroute(Route *r)
512 {
513 int fd;
514 ulong h;
515 Route *hp;
516 uchar net[Pasize];
517
518 /*
519 * don't install routes whose gateway is 00000000
520 */
521 if(equivip(r->gate, ralloc.def.dest))
522 return;
523
524 fd = open(routefile, ORDWR);
525 if(fd < 0){
526 fprint(2, "can't open oproute\n");
527 return;
528 }
529 h = rhash(r->dest);
530
531 /*
532 * if the gateway is the same as the default gateway
533 * we may be able to avoid a entry in the kernel
534 */
535 if(equivip(r->gate, ralloc.def.gate)){
536 /*
537 * look for a less specific match
538 */
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))
542 break;
543 }
544 /*
545 * if no less specific match, just use the default
546 */
547 if(hp == 0){
548 if(!readonly)
549 fprint(fd, "delete %V", r->dest);
550 if(debug)
551 fprint(2, "delete %V\n", r->dest);
552 close(fd);
553 return;
554 }
555 }
556 if(!readonly)
557 fprint(fd, "add %V %V %V", r->dest, r->mask, r->gate);
558 if(debug)
559 fprint(2, "add %V & %V -> %V\n", r->dest, r->mask, r->gate);
560 close(fd);
561 }
562
563 /*
564 * return true of dest is on net
565 */
566 int
onnet(uchar * dest,uchar * net,uchar * netmask)567 onnet(uchar *dest, uchar *net, uchar *netmask)
568 {
569 uchar dnet[Pasize];
570
571 v4maskip(dest, netmask, dnet);
572 return equivip(dnet, net);
573 }
574
575 /*
576 * figure out what mask to use, if we have a direct connected network
577 * with the same class net use its subnet mask.
578 */
579 uchar*
getmask(uchar * dest)580 getmask(uchar *dest)
581 {
582 int i;
583 Ifc *ip;
584 ulong mask, nmask;
585 uchar *m;
586
587 m = 0;
588 mask = 0xffffffff;
589 for(i = 0; i < ialloc.nifc; i++){
590 ip = &ialloc.ifc[i];
591 if(onnet(dest, ip->cnet, ip->cmask)){
592 nmask = nhgetl(ip->mask);
593 if(nmask < mask){
594 mask = nmask;
595 m = ip->mask;
596 }
597 }
598 }
599
600 if(m == 0)
601 m = v4defmask(dest);
602 return m;
603 }
604
605 /*
606 * broadcast routes onto all networks
607 */
608 void
sendto(Ifc * ip)609 sendto(Ifc *ip)
610 {
611 int h, n;
612 uchar raddr[Pasize], mbuf[Udphdrsize+512];
613 Ripmsg *m;
614 Route *r;
615 Udphdr *u;
616
617 u = (Udphdr*)mbuf;
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);
623 m->type = Response;
624 m->vers = Version;
625 if(debug)
626 fprint(2, "to %V\n", u->raddr);
627
628 n = 0;
629 for(h = 0; h < Nhash; h++){
630 for(r = ralloc.hash[h]; r; r = r->next){
631 /*
632 * don't send any route back to the net
633 * it came from
634 */
635 if(onnet(r->gate, ip->net, ip->mask))
636 continue;
637
638 /*
639 * don't tell a network about itself
640 */
641 if(equivip(r->dest, ip->net))
642 continue;
643
644 /*
645 * don't tell nets about other net's subnets
646 */
647 if(!equivip(r->mask, v4defmask(r->dest))
648 && !equivip(ip->cmask, v4defmask(r->dest)))
649 continue;
650
651 memset(&m->rip[n], 0, sizeof(m->rip[n]));
652 memmove(m->rip[n].addr, r->dest, Pasize);
653 if(r->metric < 1)
654 hnputl(m->rip[n].metric, 1);
655 else
656 hnputl(m->rip[n].metric, r->metric);
657 hnputs(m->rip[n].family, AF_INET);
658
659 if(debug)
660 fprint(2, " %16V & %16V -> %16V %2d\n",
661 r->dest, r->mask, r->gate, r->metric);
662
663 if(++n == Maxroutes && !readonly){
664 write(ripfd, mbuf, Udphdrsize + 4 + n*20);
665 n = 0;
666 }
667 }
668 }
669
670 if(n && !readonly)
671 write(ripfd, mbuf, Udphdrsize+4+n*20);
672 }
673 void
broadcast(void)674 broadcast(void)
675 {
676 int i;
677
678 readifcs();
679 for(i = 0; i < ialloc.nifc; i++){
680 if(ialloc.ifc[i].bcast)
681 sendto(&ialloc.ifc[i]);
682 }
683 }
684
685 /*
686 * timeout any routes that haven't been refreshed and aren't wired
687 */
688 void
timeoutroutes(void)689 timeoutroutes(void)
690 {
691 int h;
692 long now;
693 Route *r, **l;
694
695 now = time(0);
696
697 for(h = 0; h < Nhash; h++){
698 l = &ralloc.hash[h];
699 for(r = *l; r; r = *l){
700 if(r->metric < Infinity && now - r->time > 10*60){
701 removeroute(r);
702 r->inuse = 0;
703 *l = r->next;
704 continue;
705 }
706 l = &r->next;
707 }
708 }
709 }
710