1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "../port/error.h" 7 8 #include "ip.h" 9 #define DPRINT if(0)print 10 11 typedef struct Ipmuxrock Ipmuxrock; 12 typedef struct Ipmux Ipmux; 13 typedef struct Ip4hdr Ip4hdr; 14 typedef struct Ip6hdr Ip6hdr; 15 16 enum 17 { 18 IPHDR = 20, /* sizeof(Ip4hdr) */ 19 }; 20 21 struct Ip4hdr 22 { 23 uchar vihl; /* Version and header length */ 24 uchar tos; /* Type of service */ 25 uchar length[2]; /* packet length */ 26 uchar id[2]; /* ip->identification */ 27 uchar frag[2]; /* Fragment information */ 28 uchar ttl; /* Time to live */ 29 uchar proto; /* Protocol */ 30 uchar cksum[2]; /* Header checksum */ 31 uchar src[4]; /* IP source */ 32 uchar dst[4]; /* IP destination */ 33 uchar data[1]; /* start of data */ 34 }; 35 36 struct Ip6hdr 37 { 38 uchar vcf[4]; /* version, class label, and flow label */ 39 uchar ploadlen[2]; /* payload length */ 40 uchar proto; /* next header, i.e. proto */ 41 uchar ttl; /* hop limit, i.e. ttl */ 42 uchar src[16]; /* IP source */ 43 uchar dst[16]; /* IP destination */ 44 }; 45 46 47 enum 48 { 49 Tproto, 50 Tdata, 51 Tiph, 52 Tdst, 53 Tsrc, 54 Tifc, 55 56 Cother = 0, 57 Cbyte, /* single byte */ 58 Cmbyte, /* single byte with mask */ 59 Cshort, /* single short */ 60 Cmshort, /* single short with mask */ 61 Clong, /* single long */ 62 Cmlong, /* single long with mask */ 63 Cifc, 64 Cmifc, 65 }; 66 67 char *ftname[] = 68 { 69 [Tproto] "proto", 70 [Tdata] "data", 71 [Tiph] "iph", 72 [Tdst] "dst", 73 [Tsrc] "src", 74 [Tifc] "ifc", 75 }; 76 77 /* 78 * a node in the decision tree 79 */ 80 struct Ipmux 81 { 82 Ipmux *yes; 83 Ipmux *no; 84 uchar type; /* type of field(Txxxx) */ 85 uchar ctype; /* tupe of comparison(Cxxxx) */ 86 uchar len; /* length in bytes of item to compare */ 87 uchar n; /* number of items val points to */ 88 short off; /* offset of comparison */ 89 short eoff; /* end offset of comparison */ 90 uchar skiphdr; /* should offset start after ipheader */ 91 uchar *val; 92 uchar *mask; 93 uchar *e; /* val+n*len*/ 94 95 int ref; /* so we can garbage collect */ 96 Conv *conv; 97 }; 98 99 /* 100 * someplace to hold per conversation data 101 */ 102 struct Ipmuxrock 103 { 104 Ipmux *chain; 105 }; 106 107 static int ipmuxsprint(Ipmux*, int, char*, int); 108 static void ipmuxkick(void *x); 109 110 static char* 111 skipwhite(char *p) 112 { 113 while(*p == ' ' || *p == '\t') 114 p++; 115 return p; 116 } 117 118 static char* 119 follows(char *p, char c) 120 { 121 char *f; 122 123 f = strchr(p, c); 124 if(f == nil) 125 return nil; 126 *f++ = 0; 127 f = skipwhite(f); 128 if(*f == 0) 129 return nil; 130 return f; 131 } 132 133 static Ipmux* 134 parseop(char **pp) 135 { 136 char *p = *pp; 137 int type, off, end, len; 138 Ipmux *f; 139 140 p = skipwhite(p); 141 if(strncmp(p, "dst", 3) == 0){ 142 type = Tdst; 143 off = offsetof(Ip4hdr, dst[0]); 144 len = IPv4addrlen; 145 p += 3; 146 } 147 else if(strncmp(p, "src", 3) == 0){ 148 type = Tsrc; 149 off = offsetof(Ip4hdr, src[0]); 150 len = IPv4addrlen; 151 p += 3; 152 } 153 else if(strncmp(p, "ifc", 3) == 0){ 154 type = Tifc; 155 off = -IPv4addrlen; 156 len = IPv4addrlen; 157 p += 3; 158 } 159 else if(strncmp(p, "proto", 5) == 0){ 160 type = Tproto; 161 off = offsetof(Ip4hdr, proto); 162 len = 1; 163 p += 5; 164 } 165 else if(strncmp(p, "data", 4) == 0 || strncmp(p, "iph", 3) == 0){ 166 if(strncmp(p, "data", 4) == 0) { 167 type = Tdata; 168 p += 4; 169 } 170 else { 171 type = Tiph; 172 p += 3; 173 } 174 p = skipwhite(p); 175 if(*p != '[') 176 return nil; 177 p++; 178 off = strtoul(p, &p, 0); 179 if(off < 0 || off > (64-IPHDR)) 180 return nil; 181 p = skipwhite(p); 182 if(*p != ':') 183 end = off; 184 else { 185 p++; 186 p = skipwhite(p); 187 end = strtoul(p, &p, 0); 188 if(end < off) 189 return nil; 190 p = skipwhite(p); 191 } 192 if(*p != ']') 193 return nil; 194 p++; 195 len = end - off + 1; 196 } 197 else 198 return nil; 199 200 f = smalloc(sizeof(*f)); 201 f->type = type; 202 f->len = len; 203 f->off = off; 204 f->val = nil; 205 f->mask = nil; 206 f->n = 1; 207 f->ref = 1; 208 if(type == Tdata) 209 f->skiphdr = 1; 210 else 211 f->skiphdr = 0; 212 213 return f; 214 } 215 216 static int 217 htoi(char x) 218 { 219 if(x >= '0' && x <= '9') 220 x -= '0'; 221 else if(x >= 'a' && x <= 'f') 222 x -= 'a' - 10; 223 else if(x >= 'A' && x <= 'F') 224 x -= 'A' - 10; 225 else 226 x = 0; 227 return x; 228 } 229 230 static int 231 hextoi(char *p) 232 { 233 return (htoi(p[0])<<4) | htoi(p[1]); 234 } 235 236 static void 237 parseval(uchar *v, char *p, int len) 238 { 239 while(*p && len-- > 0){ 240 *v++ = hextoi(p); 241 p += 2; 242 } 243 } 244 245 static Ipmux* 246 parsemux(char *p) 247 { 248 int n, nomask; 249 Ipmux *f; 250 char *val; 251 char *mask; 252 char *vals[20]; 253 uchar *v; 254 255 /* parse operand */ 256 f = parseop(&p); 257 if(f == nil) 258 return nil; 259 260 /* find value */ 261 val = follows(p, '='); 262 if(val == nil) 263 goto parseerror; 264 265 /* parse mask */ 266 mask = follows(val, '&'); 267 if(mask != nil){ 268 switch(f->type){ 269 case Tsrc: 270 case Tdst: 271 case Tifc: 272 f->mask = smalloc(f->len); 273 v4parseip(f->mask, mask); 274 break; 275 case Tdata: 276 case Tiph: 277 f->mask = smalloc(f->len); 278 parseval(f->mask, mask, f->len); 279 break; 280 default: 281 goto parseerror; 282 } 283 nomask = 0; 284 } else { 285 nomask = 1; 286 f->mask = smalloc(f->len); 287 memset(f->mask, 0xff, f->len); 288 } 289 290 /* parse vals */ 291 f->n = getfields(val, vals, sizeof(vals)/sizeof(char*), 1, "|"); 292 if(f->n == 0) 293 goto parseerror; 294 f->val = smalloc(f->n*f->len); 295 v = f->val; 296 for(n = 0; n < f->n; n++){ 297 switch(f->type){ 298 case Tsrc: 299 case Tdst: 300 case Tifc: 301 v4parseip(v, vals[n]); 302 break; 303 case Tproto: 304 case Tdata: 305 case Tiph: 306 parseval(v, vals[n], f->len); 307 break; 308 } 309 v += f->len; 310 } 311 312 f->eoff = f->off + f->len; 313 f->e = f->val + f->n*f->len; 314 f->ctype = Cother; 315 if(f->n == 1){ 316 switch(f->len){ 317 case 1: 318 f->ctype = nomask ? Cbyte : Cmbyte; 319 break; 320 case 2: 321 f->ctype = nomask ? Cshort : Cmshort; 322 break; 323 case 4: 324 if(f->type == Tifc) 325 f->ctype = nomask ? Cifc : Cmifc; 326 else 327 f->ctype = nomask ? Clong : Cmlong; 328 break; 329 } 330 } 331 return f; 332 333 parseerror: 334 if(f->mask) 335 free(f->mask); 336 if(f->val) 337 free(f->val); 338 free(f); 339 return nil; 340 } 341 342 /* 343 * Compare relative ordering of two ipmuxs. This doesn't compare the 344 * values, just the fields being looked at. 345 * 346 * returns: <0 if a is a more specific match 347 * 0 if a and b are matching on the same fields 348 * >0 if b is a more specific match 349 */ 350 static int 351 ipmuxcmp(Ipmux *a, Ipmux *b) 352 { 353 int n; 354 355 /* compare types, lesser ones are more important */ 356 n = a->type - b->type; 357 if(n != 0) 358 return n; 359 360 /* compare offsets, call earlier ones more specific */ 361 n = (a->off+((int)a->skiphdr)*offsetof(Ip4hdr, data[0])) - 362 (b->off+((int)b->skiphdr)*offsetof(Ip4hdr, data[0])); 363 if(n != 0) 364 return n; 365 366 /* compare match lengths, longer ones are more specific */ 367 n = b->len - a->len; 368 if(n != 0) 369 return n; 370 371 /* 372 * if we get here we have two entries matching 373 * the same bytes of the record. Now check 374 * the mask for equality. Longer masks are 375 * more specific. 376 */ 377 if(a->mask != nil && b->mask == nil) 378 return -1; 379 if(a->mask == nil && b->mask != nil) 380 return 1; 381 if(a->mask != nil && b->mask != nil){ 382 n = memcmp(b->mask, a->mask, a->len); 383 if(n != 0) 384 return n; 385 } 386 return 0; 387 } 388 389 /* 390 * Compare the values of two ipmuxs. We're assuming that ipmuxcmp 391 * returned 0 comparing them. 392 */ 393 static int 394 ipmuxvalcmp(Ipmux *a, Ipmux *b) 395 { 396 int n; 397 398 n = b->len*b->n - a->len*a->n; 399 if(n != 0) 400 return n; 401 return memcmp(a->val, b->val, a->len*a->n); 402 } 403 404 /* 405 * add onto an existing ipmux chain in the canonical comparison 406 * order 407 */ 408 static void 409 ipmuxchain(Ipmux **l, Ipmux *f) 410 { 411 for(; *l; l = &(*l)->yes) 412 if(ipmuxcmp(f, *l) < 0) 413 break; 414 f->yes = *l; 415 *l = f; 416 } 417 418 /* 419 * copy a tree 420 */ 421 static Ipmux* 422 ipmuxcopy(Ipmux *f) 423 { 424 Ipmux *nf; 425 426 if(f == nil) 427 return nil; 428 nf = smalloc(sizeof *nf); 429 *nf = *f; 430 nf->no = ipmuxcopy(f->no); 431 nf->yes = ipmuxcopy(f->yes); 432 nf->val = smalloc(f->n*f->len); 433 nf->e = nf->val + f->len*f->n; 434 memmove(nf->val, f->val, f->n*f->len); 435 return nf; 436 } 437 438 static void 439 ipmuxfree(Ipmux *f) 440 { 441 if(f->val != nil) 442 free(f->val); 443 free(f); 444 } 445 446 static void 447 ipmuxtreefree(Ipmux *f) 448 { 449 if(f == nil) 450 return; 451 if(f->no != nil) 452 ipmuxfree(f->no); 453 if(f->yes != nil) 454 ipmuxfree(f->yes); 455 ipmuxfree(f); 456 } 457 458 /* 459 * merge two trees 460 */ 461 static Ipmux* 462 ipmuxmerge(Ipmux *a, Ipmux *b) 463 { 464 int n; 465 Ipmux *f; 466 467 if(a == nil) 468 return b; 469 if(b == nil) 470 return a; 471 n = ipmuxcmp(a, b); 472 if(n < 0){ 473 f = ipmuxcopy(b); 474 a->yes = ipmuxmerge(a->yes, b); 475 a->no = ipmuxmerge(a->no, f); 476 return a; 477 } 478 if(n > 0){ 479 f = ipmuxcopy(a); 480 b->yes = ipmuxmerge(b->yes, a); 481 b->no = ipmuxmerge(b->no, f); 482 return b; 483 } 484 if(ipmuxvalcmp(a, b) == 0){ 485 a->yes = ipmuxmerge(a->yes, b->yes); 486 a->no = ipmuxmerge(a->no, b->no); 487 a->ref++; 488 ipmuxfree(b); 489 return a; 490 } 491 a->no = ipmuxmerge(a->no, b); 492 return a; 493 } 494 495 /* 496 * remove a chain from a demux tree. This is like merging accept that 497 * we remove instead of insert. 498 */ 499 static int 500 ipmuxremove(Ipmux **l, Ipmux *f) 501 { 502 int n, rv; 503 Ipmux *ft; 504 505 if(f == nil) 506 return 0; /* we've removed it all */ 507 if(*l == nil) 508 return -1; 509 510 ft = *l; 511 n = ipmuxcmp(ft, f); 512 if(n < 0){ 513 /* *l is maching an earlier field, descend both paths */ 514 rv = ipmuxremove(&ft->yes, f); 515 rv += ipmuxremove(&ft->no, f); 516 return rv; 517 } 518 if(n > 0){ 519 /* f represents an earlier field than *l, this should be impossible */ 520 return -1; 521 } 522 523 /* if we get here f and *l are comparing the same fields */ 524 if(ipmuxvalcmp(ft, f) != 0){ 525 /* different values mean mutually exclusive */ 526 return ipmuxremove(&ft->no, f); 527 } 528 529 /* we found a match */ 530 if(--(ft->ref) == 0){ 531 /* 532 * a dead node implies the whole yes side is also dead. 533 * since our chain is constrained to be on that side, 534 * we're done. 535 */ 536 ipmuxtreefree(ft->yes); 537 *l = ft->no; 538 ipmuxfree(ft); 539 return 0; 540 } 541 542 /* 543 * free the rest of the chain. it is constrained to match the 544 * yes side. 545 */ 546 return ipmuxremove(&ft->yes, f->yes); 547 } 548 549 /* 550 * connection request is a semi separated list of filters 551 * e.g. proto=17;dat[0:4]=11aa22bb;ifc=135.104.9.2&255.255.255.0 552 * 553 * there's no protection against overlapping specs. 554 */ 555 static char* 556 ipmuxconnect(Conv *c, char **argv, int argc) 557 { 558 int i, n; 559 char *field[10]; 560 Ipmux *mux, *chain; 561 Ipmuxrock *r; 562 Fs *f; 563 564 f = c->p->f; 565 566 if(argc != 2) 567 return Ebadarg; 568 569 n = getfields(argv[1], field, nelem(field), 1, ";"); 570 if(n <= 0) 571 return Ebadarg; 572 573 chain = nil; 574 mux = nil; 575 for(i = 0; i < n; i++){ 576 mux = parsemux(field[i]); 577 if(mux == nil){ 578 ipmuxtreefree(chain); 579 return Ebadarg; 580 } 581 ipmuxchain(&chain, mux); 582 } 583 if(chain == nil) 584 return Ebadarg; 585 mux->conv = c; 586 587 /* save a copy of the chain so we can later remove it */ 588 mux = ipmuxcopy(chain); 589 r = (Ipmuxrock*)(c->ptcl); 590 r->chain = chain; 591 592 /* add the chain to the protocol demultiplexor tree */ 593 wlock(f); 594 f->ipmux->priv = ipmuxmerge(f->ipmux->priv, mux); 595 wunlock(f); 596 597 Fsconnected(c, nil); 598 return nil; 599 } 600 601 static int 602 ipmuxstate(Conv *c, char *state, int n) 603 { 604 Ipmuxrock *r; 605 606 r = (Ipmuxrock*)(c->ptcl); 607 return ipmuxsprint(r->chain, 0, state, n); 608 } 609 610 static void 611 ipmuxcreate(Conv *c) 612 { 613 Ipmuxrock *r; 614 615 c->rq = qopen(64*1024, Qmsg, 0, c); 616 c->wq = qopen(64*1024, Qkick, ipmuxkick, c); 617 r = (Ipmuxrock*)(c->ptcl); 618 r->chain = nil; 619 } 620 621 static char* 622 ipmuxannounce(Conv*, char**, int) 623 { 624 return "ipmux does not support announce"; 625 } 626 627 static void 628 ipmuxclose(Conv *c) 629 { 630 Ipmuxrock *r; 631 Fs *f = c->p->f; 632 633 r = (Ipmuxrock*)(c->ptcl); 634 635 qclose(c->rq); 636 qclose(c->wq); 637 qclose(c->eq); 638 ipmove(c->laddr, IPnoaddr); 639 ipmove(c->raddr, IPnoaddr); 640 c->lport = 0; 641 c->rport = 0; 642 643 wlock(f); 644 ipmuxremove(&(c->p->priv), r->chain); 645 wunlock(f); 646 ipmuxtreefree(r->chain); 647 r->chain = nil; 648 } 649 650 /* 651 * takes a fully formed ip packet and just passes it down 652 * the stack 653 */ 654 static void 655 ipmuxkick(void *x) 656 { 657 Conv *c = x; 658 Block *bp; 659 660 bp = qget(c->wq); 661 if(bp == nil) 662 return; 663 else { 664 Ip4hdr *ih4 = (Ip4hdr*)(bp->rp); 665 if((ih4->vihl)&0xF0 != 0x60) 666 ipoput4(c->p->f, bp, 0, ih4->ttl, ih4->tos, nil); 667 else { 668 Ip6hdr *ih6 = (Ip6hdr*)(bp->rp); 669 ipoput6(c->p->f, bp, 0, ih6->ttl, 0, nil); 670 } 671 } 672 } 673 674 static void 675 ipmuxiput(Proto *p, Ipifc *ifc, Block *bp) 676 { 677 int len, hl; 678 Fs *f = p->f; 679 uchar *m, *h, *v, *e, *ve, *hp; 680 Conv *c; 681 Ipmux *mux; 682 Ip4hdr *ip; 683 Ip6hdr *ip6; 684 685 ip = (Ip4hdr*)bp->rp; 686 hl = (ip->vihl&0x0F)<<2; 687 688 if(p->priv == nil) 689 goto nomatch; 690 691 h = bp->rp; 692 len = BLEN(bp); 693 694 /* run the v4 filter */ 695 rlock(f); 696 c = nil; 697 mux = f->ipmux->priv; 698 while(mux != nil){ 699 if(mux->eoff > len){ 700 mux = mux->no; 701 continue; 702 } 703 hp = h + mux->off + ((int)mux->skiphdr)*hl; 704 switch(mux->ctype){ 705 case Cbyte: 706 if(*mux->val == *hp) 707 goto yes; 708 break; 709 case Cmbyte: 710 if((*hp & *mux->mask) == *mux->val) 711 goto yes; 712 break; 713 case Cshort: 714 if(*((ushort*)mux->val) == *(ushort*)hp) 715 goto yes; 716 break; 717 case Cmshort: 718 if((*(ushort*)hp & (*((ushort*)mux->mask))) == *((ushort*)mux->val)) 719 goto yes; 720 break; 721 case Clong: 722 if(*((ulong*)mux->val) == *(ulong*)hp) 723 goto yes; 724 break; 725 case Cmlong: 726 if((*(ulong*)hp & (*((ulong*)mux->mask))) == *((ulong*)mux->val)) 727 goto yes; 728 break; 729 case Cifc: 730 if(*((ulong*)mux->val) == *(ulong*)(ifc->lifc->local + IPv4off)) 731 goto yes; 732 break; 733 case Cmifc: 734 if((*(ulong*)(ifc->lifc->local + IPv4off) & (*((ulong*)mux->mask))) == *((ulong*)mux->val)) 735 goto yes; 736 break; 737 default: 738 v = mux->val; 739 for(e = mux->e; v < e; v = ve){ 740 m = mux->mask; 741 hp = h + mux->off; 742 for(ve = v + mux->len; v < ve; v++){ 743 if((*hp++ & *m++) != *v) 744 break; 745 } 746 if(v == ve) 747 goto yes; 748 } 749 } 750 mux = mux->no; 751 continue; 752 yes: 753 if(mux->conv != nil) 754 c = mux->conv; 755 mux = mux->yes; 756 } 757 runlock(f); 758 759 if(c != nil){ 760 /* tack on interface address */ 761 bp = padblock(bp, IPaddrlen); 762 ipmove(bp->rp, ifc->lifc->local); 763 bp = concatblock(bp); 764 if(bp != nil) 765 if(qpass(c->rq, bp) < 0) 766 print("Q"); 767 return; 768 } 769 770 nomatch: 771 /* doesn't match any filter, hand it to the specific protocol handler */ 772 ip = (Ip4hdr*)bp->rp; 773 if((ip->vihl&0xF0)==0x40) { 774 p = f->t2p[ip->proto]; 775 } else { 776 ip6 = (Ip6hdr*)bp->rp; 777 p = f->t2p[ip6->proto]; 778 } 779 if(p && p->rcv) 780 (*p->rcv)(p, ifc, bp); 781 else 782 freeblist(bp); 783 return; 784 } 785 786 static int 787 ipmuxsprint(Ipmux *mux, int level, char *buf, int len) 788 { 789 int i, j, n; 790 uchar *v; 791 792 n = 0; 793 for(i = 0; i < level; i++) 794 n += snprint(buf+n, len-n, " "); 795 if(mux == nil){ 796 n += snprint(buf+n, len-n, "\n"); 797 return n; 798 } 799 n += snprint(buf+n, len-n, "h[%d:%d]&", 800 mux->off+((int)mux->skiphdr)*((int)offsetof(Ip4hdr, data[0])), 801 mux->off+(((int)mux->skiphdr)*((int)offsetof(Ip4hdr, data[0])))+mux->len-1); 802 for(i = 0; i < mux->len; i++) 803 n += snprint(buf+n, len - n, "%2.2ux", mux->mask[i]); 804 n += snprint(buf+n, len-n, "="); 805 v = mux->val; 806 for(j = 0; j < mux->n; j++){ 807 for(i = 0; i < mux->len; i++) 808 n += snprint(buf+n, len - n, "%2.2ux", *v++); 809 n += snprint(buf+n, len-n, "|"); 810 } 811 n += snprint(buf+n, len-n, "\n"); 812 level++; 813 n += ipmuxsprint(mux->no, level, buf+n, len-n); 814 n += ipmuxsprint(mux->yes, level, buf+n, len-n); 815 return n; 816 } 817 818 static int 819 ipmuxstats(Proto *p, char *buf, int len) 820 { 821 int n; 822 Fs *f = p->f; 823 824 rlock(f); 825 n = ipmuxsprint(p->priv, 0, buf, len); 826 runlock(f); 827 828 return n; 829 } 830 831 void 832 ipmuxinit(Fs *f) 833 { 834 Proto *ipmux; 835 836 ipmux = smalloc(sizeof(Proto)); 837 ipmux->priv = nil; 838 ipmux->name = "ipmux"; 839 ipmux->connect = ipmuxconnect; 840 ipmux->announce = ipmuxannounce; 841 ipmux->state = ipmuxstate; 842 ipmux->create = ipmuxcreate; 843 ipmux->close = ipmuxclose; 844 ipmux->rcv = ipmuxiput; 845 ipmux->ctl = nil; 846 ipmux->advise = nil; 847 ipmux->stats = ipmuxstats; 848 ipmux->ipproto = -1; 849 ipmux->nc = 64; 850 ipmux->ptclsize = sizeof(Ipmuxrock); 851 852 f->ipmux = ipmux; /* hack for Fsrcvpcol */ 853 854 Fsproto(f, ipmux); 855 } 856