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