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 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 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* 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 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 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 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 195 usage(void) 196 { 197 fprint(2, "usage: %s [-bnd] [-x netmtpt]\n", argv0); 198 exits("usage"); 199 } 200 201 void 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 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 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 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 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 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 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 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 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* 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 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 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 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