iproute.c (14918B)
1 #include "u.h" 2 #include "lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "error.h" 7 8 #include "ip.h" 9 10 static void walkadd(Fs*, Route**, Route*); 11 static void addnode(Fs*, Route**, Route*); 12 static void calcd(Route*); 13 14 /* these are used for all instances of IP */ 15 static Route* v4freelist; 16 static Route* v6freelist; 17 static RWlock routelock; 18 static ulong v4routegeneration, v6routegeneration; 19 20 static void 21 freeroute(Route *r) 22 { 23 Route **l; 24 25 r->left = nil; 26 r->right = nil; 27 if(r->type & Rv4) 28 l = &v4freelist; 29 else 30 l = &v6freelist; 31 r->mid = *l; 32 *l = r; 33 } 34 35 static Route* 36 allocroute(int type) 37 { 38 Route *r; 39 int n; 40 Route **l; 41 42 if(type & Rv4){ 43 n = sizeof(RouteTree) + sizeof(V4route); 44 l = &v4freelist; 45 } else { 46 n = sizeof(RouteTree) + sizeof(V6route); 47 l = &v6freelist; 48 } 49 50 r = *l; 51 if(r != nil){ 52 *l = r->mid; 53 } else { 54 r = malloc(n); 55 if(r == nil) 56 panic("out of routing nodes"); 57 } 58 memset(r, 0, n); 59 r->type = type; 60 r->ifc = nil; 61 r->ref = 1; 62 63 return r; 64 } 65 66 static void 67 addqueue(Route **q, Route *r) 68 { 69 Route *l; 70 71 if(r == nil) 72 return; 73 74 l = allocroute(r->type); 75 l->mid = *q; 76 *q = l; 77 l->left = r; 78 } 79 80 /* 81 * compare 2 v6 addresses 82 */ 83 static int 84 lcmp(ulong *a, ulong *b) 85 { 86 int i; 87 88 for(i = 0; i < IPllen; i++){ 89 if(a[i] > b[i]) 90 return 1; 91 if(a[i] < b[i]) 92 return -1; 93 } 94 return 0; 95 } 96 97 /* 98 * compare 2 v4 or v6 ranges 99 */ 100 enum 101 { 102 Rpreceeds, 103 Rfollows, 104 Requals, 105 Rcontains, 106 Rcontained, 107 }; 108 109 static int 110 rangecompare(Route *a, Route *b) 111 { 112 if(a->type & Rv4){ 113 if(a->v4.endaddress < b->v4.address) 114 return Rpreceeds; 115 116 if(a->v4.address > b->v4.endaddress) 117 return Rfollows; 118 119 if(a->v4.address <= b->v4.address 120 && a->v4.endaddress >= b->v4.endaddress){ 121 if(a->v4.address == b->v4.address 122 && a->v4.endaddress == b->v4.endaddress) 123 return Requals; 124 return Rcontains; 125 } 126 return Rcontained; 127 } 128 129 if(lcmp(a->v6.endaddress, b->v6.address) < 0) 130 return Rpreceeds; 131 132 if(lcmp(a->v6.address, b->v6.endaddress) > 0) 133 return Rfollows; 134 135 if(lcmp(a->v6.address, b->v6.address) <= 0 136 && lcmp(a->v6.endaddress, b->v6.endaddress) >= 0){ 137 if(lcmp(a->v6.address, b->v6.address) == 0 138 && lcmp(a->v6.endaddress, b->v6.endaddress) == 0) 139 return Requals; 140 return Rcontains; 141 } 142 143 return Rcontained; 144 } 145 146 static void 147 copygate(Route *old, Route *new) 148 { 149 if(new->type & Rv4) 150 memmove(old->v4.gate, new->v4.gate, IPv4addrlen); 151 else 152 memmove(old->v6.gate, new->v6.gate, IPaddrlen); 153 } 154 155 /* 156 * walk down a tree adding nodes back in 157 */ 158 static void 159 walkadd(Fs *f, Route **root, Route *p) 160 { 161 Route *l, *r; 162 163 l = p->left; 164 r = p->right; 165 p->left = 0; 166 p->right = 0; 167 addnode(f, root, p); 168 if(l) 169 walkadd(f, root, l); 170 if(r) 171 walkadd(f, root, r); 172 } 173 174 /* 175 * calculate depth 176 */ 177 static void 178 calcd(Route *p) 179 { 180 Route *q; 181 int d; 182 183 if(p) { 184 d = 0; 185 q = p->left; 186 if(q) 187 d = q->depth; 188 q = p->right; 189 if(q && q->depth > d) 190 d = q->depth; 191 q = p->mid; 192 if(q && q->depth > d) 193 d = q->depth; 194 p->depth = d+1; 195 } 196 } 197 198 /* 199 * balance the tree at the current node 200 */ 201 static void 202 balancetree(Route **cur) 203 { 204 Route *p, *l, *r; 205 int dl, dr; 206 207 /* 208 * if left and right are 209 * too out of balance, 210 * rotate tree node 211 */ 212 p = *cur; 213 dl = 0; if((l = p->left) != nil) dl = l->depth; 214 dr = 0; if((r = p->right) != nil) dr = r->depth; 215 216 if(dl > dr+1) { 217 p->left = l->right; 218 l->right = p; 219 *cur = l; 220 calcd(p); 221 calcd(l); 222 } else 223 if(dr > dl+1) { 224 p->right = r->left; 225 r->left = p; 226 *cur = r; 227 calcd(p); 228 calcd(r); 229 } else 230 calcd(p); 231 } 232 233 /* 234 * add a new node to the tree 235 */ 236 static void 237 addnode(Fs *f, Route **cur, Route *new) 238 { 239 Route *p; 240 241 p = *cur; 242 if(p == 0) { 243 *cur = new; 244 new->depth = 1; 245 return; 246 } 247 248 switch(rangecompare(new, p)){ 249 case Rpreceeds: 250 addnode(f, &p->left, new); 251 break; 252 case Rfollows: 253 addnode(f, &p->right, new); 254 break; 255 case Rcontains: 256 /* 257 * if new node is superset 258 * of tree node, 259 * replace tree node and 260 * queue tree node to be 261 * merged into root. 262 */ 263 *cur = new; 264 new->depth = 1; 265 addqueue(&f->queue, p); 266 break; 267 case Requals: 268 /* 269 * supercede the old entry if the old one isn't 270 * a local interface. 271 */ 272 if((p->type & Rifc) == 0){ 273 p->type = new->type; 274 p->ifcid = -1; 275 copygate(p, new); 276 } else if(new->type & Rifc) 277 p->ref++; 278 freeroute(new); 279 break; 280 case Rcontained: 281 addnode(f, &p->mid, new); 282 break; 283 } 284 285 balancetree(cur); 286 } 287 288 #define V4H(a) ((a&0x07ffffff)>>(32-Lroot-5)) 289 290 void 291 v4addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type) 292 { 293 Route *p; 294 ulong sa; 295 ulong m; 296 ulong ea; 297 int h, eh; 298 299 m = nhgetl(mask); 300 sa = nhgetl(a) & m; 301 ea = sa | ~m; 302 303 eh = V4H(ea); 304 for(h=V4H(sa); h<=eh; h++) { 305 p = allocroute(Rv4 | type); 306 p->v4.address = sa; 307 p->v4.endaddress = ea; 308 memmove(p->v4.gate, gate, sizeof(p->v4.gate)); 309 memmove(p->tag, tag, sizeof(p->tag)); 310 311 wlock(&routelock); 312 addnode(f, &f->v4root[h], p); 313 while((p = f->queue) != nil) { 314 f->queue = p->mid; 315 walkadd(f, &f->v4root[h], p->left); 316 freeroute(p); 317 } 318 wunlock(&routelock); 319 } 320 v4routegeneration++; 321 322 ipifcaddroute(f, Rv4, a, mask, gate, type); 323 } 324 325 #define V6H(a) (((a)[IPllen-1] & 0x07ffffff)>>(32-Lroot-5)) 326 #define ISDFLT(a, mask, tag) ((ipcmp((a),v6Unspecified)==0) && (ipcmp((mask),v6Unspecified)==0) && (strcmp((tag), "ra")!=0)) 327 328 void 329 v6addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type) 330 { 331 Route *p; 332 ulong sa[IPllen], ea[IPllen]; 333 ulong x, y; 334 int h, eh; 335 336 /* 337 if(ISDFLT(a, mask, tag)) 338 f->v6p->cdrouter = -1; 339 */ 340 341 342 for(h = 0; h < IPllen; h++){ 343 x = nhgetl(a+4*h); 344 y = nhgetl(mask+4*h); 345 sa[h] = x & y; 346 ea[h] = x | ~y; 347 } 348 349 eh = V6H(ea); 350 for(h = V6H(sa); h <= eh; h++) { 351 p = allocroute(type); 352 memmove(p->v6.address, sa, IPaddrlen); 353 memmove(p->v6.endaddress, ea, IPaddrlen); 354 memmove(p->v6.gate, gate, IPaddrlen); 355 memmove(p->tag, tag, sizeof(p->tag)); 356 357 wlock(&routelock); 358 addnode(f, &f->v6root[h], p); 359 while((p = f->queue) != nil) { 360 f->queue = p->mid; 361 walkadd(f, &f->v6root[h], p->left); 362 freeroute(p); 363 } 364 wunlock(&routelock); 365 } 366 v6routegeneration++; 367 368 ipifcaddroute(f, 0, a, mask, gate, type); 369 } 370 371 Route** 372 looknode(Route **cur, Route *r) 373 { 374 Route *p; 375 376 for(;;){ 377 p = *cur; 378 if(p == 0) 379 return 0; 380 381 switch(rangecompare(r, p)){ 382 case Rcontains: 383 return 0; 384 case Rpreceeds: 385 cur = &p->left; 386 break; 387 case Rfollows: 388 cur = &p->right; 389 break; 390 case Rcontained: 391 cur = &p->mid; 392 break; 393 case Requals: 394 return cur; 395 } 396 } 397 } 398 399 void 400 v4delroute(Fs *f, uchar *a, uchar *mask, int dolock) 401 { 402 Route **r, *p; 403 Route rt; 404 int h, eh; 405 ulong m; 406 407 m = nhgetl(mask); 408 rt.v4.address = nhgetl(a) & m; 409 rt.v4.endaddress = rt.v4.address | ~m; 410 rt.type = Rv4; 411 412 eh = V4H(rt.v4.endaddress); 413 for(h=V4H(rt.v4.address); h<=eh; h++) { 414 if(dolock) 415 wlock(&routelock); 416 r = looknode(&f->v4root[h], &rt); 417 if(r) { 418 p = *r; 419 if(--(p->ref) == 0){ 420 *r = 0; 421 addqueue(&f->queue, p->left); 422 addqueue(&f->queue, p->mid); 423 addqueue(&f->queue, p->right); 424 freeroute(p); 425 while((p = f->queue) != nil) { 426 f->queue = p->mid; 427 walkadd(f, &f->v4root[h], p->left); 428 freeroute(p); 429 } 430 } 431 } 432 if(dolock) 433 wunlock(&routelock); 434 } 435 v4routegeneration++; 436 437 ipifcremroute(f, Rv4, a, mask); 438 } 439 440 void 441 v6delroute(Fs *f, uchar *a, uchar *mask, int dolock) 442 { 443 Route **r, *p; 444 Route rt; 445 int h, eh; 446 ulong x, y; 447 448 for(h = 0; h < IPllen; h++){ 449 x = nhgetl(a+4*h); 450 y = nhgetl(mask+4*h); 451 rt.v6.address[h] = x & y; 452 rt.v6.endaddress[h] = x | ~y; 453 } 454 rt.type = 0; 455 456 eh = V6H(rt.v6.endaddress); 457 for(h=V6H(rt.v6.address); h<=eh; h++) { 458 if(dolock) 459 wlock(&routelock); 460 r = looknode(&f->v6root[h], &rt); 461 if(r) { 462 p = *r; 463 if(--(p->ref) == 0){ 464 *r = 0; 465 addqueue(&f->queue, p->left); 466 addqueue(&f->queue, p->mid); 467 addqueue(&f->queue, p->right); 468 freeroute(p); 469 while((p = f->queue) != nil) { 470 f->queue = p->mid; 471 walkadd(f, &f->v6root[h], p->left); 472 freeroute(p); 473 } 474 } 475 } 476 if(dolock) 477 wunlock(&routelock); 478 } 479 v6routegeneration++; 480 481 ipifcremroute(f, 0, a, mask); 482 } 483 484 Route* 485 v4lookup(Fs *f, uchar *a, Conv *c) 486 { 487 Route *p, *q; 488 ulong la; 489 uchar gate[IPaddrlen]; 490 Ipifc *ifc; 491 492 if(c != nil && c->r != nil && c->r->ifc != nil && c->rgen == v4routegeneration) 493 return c->r; 494 495 la = nhgetl(a); 496 q = nil; 497 for(p=f->v4root[V4H(la)]; p;) 498 if(la >= p->v4.address) { 499 if(la <= p->v4.endaddress) { 500 q = p; 501 p = p->mid; 502 } else 503 p = p->right; 504 } else 505 p = p->left; 506 507 if(q && (q->ifc == nil || q->ifcid != q->ifc->ifcid)){ 508 if(q->type & Rifc) { 509 hnputl(gate+IPv4off, q->v4.address); 510 memmove(gate, v4prefix, IPv4off); 511 } else 512 v4tov6(gate, q->v4.gate); 513 ifc = findipifc(f, gate, q->type); 514 if(ifc == nil) 515 return nil; 516 q->ifc = ifc; 517 q->ifcid = ifc->ifcid; 518 } 519 520 if(c != nil){ 521 c->r = q; 522 c->rgen = v4routegeneration; 523 } 524 525 return q; 526 } 527 528 Route* 529 v6lookup(Fs *f, uchar *a, Conv *c) 530 { 531 Route *p, *q; 532 ulong la[IPllen]; 533 int h; 534 ulong x, y; 535 uchar gate[IPaddrlen]; 536 Ipifc *ifc; 537 538 if(memcmp(a, v4prefix, IPv4off) == 0){ 539 q = v4lookup(f, a+IPv4off, c); 540 if(q != nil) 541 return q; 542 } 543 544 if(c != nil && c->r != nil && c->r->ifc != nil && c->rgen == v6routegeneration) 545 return c->r; 546 547 for(h = 0; h < IPllen; h++) 548 la[h] = nhgetl(a+4*h); 549 550 q = 0; 551 for(p=f->v6root[V6H(la)]; p;){ 552 for(h = 0; h < IPllen; h++){ 553 x = la[h]; 554 y = p->v6.address[h]; 555 if(x == y) 556 continue; 557 if(x < y){ 558 p = p->left; 559 goto next; 560 } 561 break; 562 } 563 for(h = 0; h < IPllen; h++){ 564 x = la[h]; 565 y = p->v6.endaddress[h]; 566 if(x == y) 567 continue; 568 if(x > y){ 569 p = p->right; 570 goto next; 571 } 572 break; 573 } 574 q = p; 575 p = p->mid; 576 next: ; 577 } 578 579 if(q && (q->ifc == nil || q->ifcid != q->ifc->ifcid)){ 580 if(q->type & Rifc) { 581 for(h = 0; h < IPllen; h++) 582 hnputl(gate+4*h, q->v6.address[h]); 583 ifc = findipifc(f, gate, q->type); 584 } else 585 ifc = findipifc(f, q->v6.gate, q->type); 586 if(ifc == nil) 587 return nil; 588 q->ifc = ifc; 589 q->ifcid = ifc->ifcid; 590 } 591 if(c != nil){ 592 c->r = q; 593 c->rgen = v6routegeneration; 594 } 595 596 return q; 597 } 598 599 void 600 routetype(int type, char *p) 601 { 602 memset(p, ' ', 4); 603 p[4] = 0; 604 if(type & Rv4) 605 *p++ = '4'; 606 else 607 *p++ = '6'; 608 if(type & Rifc) 609 *p++ = 'i'; 610 if(type & Runi) 611 *p++ = 'u'; 612 else if(type & Rbcast) 613 *p++ = 'b'; 614 else if(type & Rmulti) 615 *p++ = 'm'; 616 if(type & Rptpt) 617 *p = 'p'; 618 } 619 620 static char *rformat = "%-15I %-4M %-15I %4.4s %4.4s %3s\n"; 621 622 void 623 convroute(Route *r, uchar *addr, uchar *mask, uchar *gate, char *t, int *nifc) 624 { 625 int i; 626 627 if(r->type & Rv4){ 628 memmove(addr, v4prefix, IPv4off); 629 hnputl(addr+IPv4off, r->v4.address); 630 memset(mask, 0xff, IPv4off); 631 hnputl(mask+IPv4off, ~(r->v4.endaddress ^ r->v4.address)); 632 memmove(gate, v4prefix, IPv4off); 633 memmove(gate+IPv4off, r->v4.gate, IPv4addrlen); 634 } else { 635 for(i = 0; i < IPllen; i++){ 636 hnputl(addr + 4*i, r->v6.address[i]); 637 hnputl(mask + 4*i, ~(r->v6.endaddress[i] ^ r->v6.address[i])); 638 } 639 memmove(gate, r->v6.gate, IPaddrlen); 640 } 641 642 routetype(r->type, t); 643 644 if(r->ifc) 645 *nifc = r->ifc->conv->x; 646 else 647 *nifc = -1; 648 } 649 650 /* 651 * this code is not in rr to reduce stack size 652 */ 653 static void 654 sprintroute(Route *r, Routewalk *rw) 655 { 656 int nifc, n; 657 char t[5], *iname, ifbuf[5]; 658 uchar addr[IPaddrlen], mask[IPaddrlen], gate[IPaddrlen]; 659 char *p; 660 661 convroute(r, addr, mask, gate, t, &nifc); 662 iname = "-"; 663 if(nifc != -1) { 664 iname = ifbuf; 665 snprint(ifbuf, sizeof ifbuf, "%d", nifc); 666 } 667 p = seprint(rw->p, rw->e, rformat, addr, mask, gate, t, r->tag, iname); 668 if(rw->o < 0){ 669 n = p - rw->p; 670 if(n > -rw->o){ 671 memmove(rw->p, rw->p-rw->o, n+rw->o); 672 rw->p = p + rw->o; 673 } 674 rw->o += n; 675 } else 676 rw->p = p; 677 } 678 679 /* 680 * recurse descending tree, applying the function in Routewalk 681 */ 682 static int 683 rr(Route *r, Routewalk *rw) 684 { 685 int h; 686 687 if(rw->e <= rw->p) 688 return 0; 689 if(r == nil) 690 return 1; 691 692 if(rr(r->left, rw) == 0) 693 return 0; 694 695 if(r->type & Rv4) 696 h = V4H(r->v4.address); 697 else 698 h = V6H(r->v6.address); 699 700 if(h == rw->h) 701 rw->walk(r, rw); 702 703 if(rr(r->mid, rw) == 0) 704 return 0; 705 706 return rr(r->right, rw); 707 } 708 709 void 710 ipwalkroutes(Fs *f, Routewalk *rw) 711 { 712 rlock(&routelock); 713 if(rw->e > rw->p) { 714 for(rw->h = 0; rw->h < nelem(f->v4root); rw->h++) 715 if(rr(f->v4root[rw->h], rw) == 0) 716 break; 717 } 718 if(rw->e > rw->p) { 719 for(rw->h = 0; rw->h < nelem(f->v6root); rw->h++) 720 if(rr(f->v6root[rw->h], rw) == 0) 721 break; 722 } 723 runlock(&routelock); 724 } 725 726 long 727 routeread(Fs *f, char *p, ulong offset, int n) 728 { 729 Routewalk rw; 730 731 rw.p = p; 732 rw.e = p+n; 733 rw.o = -offset; 734 rw.walk = sprintroute; 735 736 ipwalkroutes(f, &rw); 737 738 return rw.p - p; 739 } 740 741 /* 742 * this code is not in routeflush to reduce stack size 743 */ 744 void 745 delroute(Fs *f, Route *r, int dolock) 746 { 747 uchar addr[IPaddrlen]; 748 uchar mask[IPaddrlen]; 749 uchar gate[IPaddrlen]; 750 char t[5]; 751 int nifc; 752 753 convroute(r, addr, mask, gate, t, &nifc); 754 if(r->type & Rv4) 755 v4delroute(f, addr+IPv4off, mask+IPv4off, dolock); 756 else 757 v6delroute(f, addr, mask, dolock); 758 } 759 760 /* 761 * recurse until one route is deleted 762 * returns 0 if nothing is deleted, 1 otherwise 763 */ 764 int 765 routeflush(Fs *f, Route *r, char *tag) 766 { 767 if(r == nil) 768 return 0; 769 if(routeflush(f, r->mid, tag)) 770 return 1; 771 if(routeflush(f, r->left, tag)) 772 return 1; 773 if(routeflush(f, r->right, tag)) 774 return 1; 775 if((r->type & Rifc) == 0){ 776 if(tag == nil || strncmp(tag, r->tag, sizeof(r->tag)) == 0){ 777 delroute(f, r, 0); 778 return 1; 779 } 780 } 781 return 0; 782 } 783 784 long 785 routewrite(Fs *f, Chan *c, char *p, int n) 786 { 787 int h, changed; 788 char *tag; 789 Cmdbuf *cb; 790 uchar addr[IPaddrlen]; 791 uchar mask[IPaddrlen]; 792 uchar gate[IPaddrlen]; 793 IPaux *a, *na; 794 795 cb = parsecmd(p, n); 796 if(waserror()){ 797 free(cb); 798 nexterror(); 799 } 800 801 if(strcmp(cb->f[0], "flush") == 0){ 802 tag = cb->f[1]; 803 for(h = 0; h < nelem(f->v4root); h++) 804 for(changed = 1; changed;){ 805 wlock(&routelock); 806 changed = routeflush(f, f->v4root[h], tag); 807 wunlock(&routelock); 808 } 809 for(h = 0; h < nelem(f->v6root); h++) 810 for(changed = 1; changed;){ 811 wlock(&routelock); 812 changed = routeflush(f, f->v6root[h], tag); 813 wunlock(&routelock); 814 } 815 } else if(strcmp(cb->f[0], "remove") == 0){ 816 if(cb->nf < 3) 817 error(Ebadarg); 818 if (parseip(addr, cb->f[1]) == -1) 819 error(Ebadip); 820 parseipmask(mask, cb->f[2]); 821 if(memcmp(addr, v4prefix, IPv4off) == 0) 822 v4delroute(f, addr+IPv4off, mask+IPv4off, 1); 823 else 824 v6delroute(f, addr, mask, 1); 825 } else if(strcmp(cb->f[0], "add") == 0){ 826 if(cb->nf < 4) 827 error(Ebadarg); 828 if(parseip(addr, cb->f[1]) == -1 || 829 parseip(gate, cb->f[3]) == -1) 830 error(Ebadip); 831 parseipmask(mask, cb->f[2]); 832 tag = "none"; 833 if(c != nil){ 834 a = c->aux; 835 tag = a->tag; 836 } 837 if(memcmp(addr, v4prefix, IPv4off) == 0) 838 v4addroute(f, tag, addr+IPv4off, mask+IPv4off, gate+IPv4off, 0); 839 else 840 v6addroute(f, tag, addr, mask, gate, 0); 841 } else if(strcmp(cb->f[0], "tag") == 0) { 842 if(cb->nf < 2) 843 error(Ebadarg); 844 845 a = c->aux; 846 na = newipaux(a->owner, cb->f[1]); 847 c->aux = na; 848 free(a); 849 } 850 851 poperror(); 852 free(cb); 853 return n; 854 }