📄 ipmux.c
字号:
*nf = *f; nf->no = ipmuxcopy(f->no); nf->yes = ipmuxcopy(f->yes); nf->val = smalloc(f->n*f->len); nf->e = nf->val + f->len*f->n; memmove(nf->val, f->val, f->n*f->len); return nf;}static voidipmuxfree(Ipmux *f){ if(f->val != nil) free(f->val); free(f);}static voidipmuxtreefree(Ipmux *f){ if(f == nil) return; if(f->no != nil) ipmuxfree(f->no); if(f->yes != nil) ipmuxfree(f->yes); ipmuxfree(f);}/* * merge two trees */static Ipmux*ipmuxmerge(Ipmux *a, Ipmux *b){ int n; Ipmux *f; if(a == nil) return b; if(b == nil) return a; n = ipmuxcmp(a, b); if(n < 0){ f = ipmuxcopy(b); a->yes = ipmuxmerge(a->yes, b); a->no = ipmuxmerge(a->no, f); return a; } if(n > 0){ f = ipmuxcopy(a); b->yes = ipmuxmerge(b->yes, a); b->no = ipmuxmerge(b->no, f); return b; } if(ipmuxvalcmp(a, b) == 0){ a->yes = ipmuxmerge(a->yes, b->yes); a->no = ipmuxmerge(a->no, b->no); a->ref++; ipmuxfree(b); return a; } a->no = ipmuxmerge(a->no, b); return a;}/* * remove a chain from a demux tree. This is like merging accept that * we remove instead of insert. */static intipmuxremove(Ipmux **l, Ipmux *f){ int n, rv; Ipmux *ft; if(f == nil) return 0; /* we've removed it all */ if(*l == nil) return -1; ft = *l; n = ipmuxcmp(ft, f); if(n < 0){ /* *l is maching an earlier field, descend both paths */ rv = ipmuxremove(&ft->yes, f); rv += ipmuxremove(&ft->no, f); return rv; } if(n > 0){ /* f represents an earlier field than *l, this should be impossible */ return -1; } /* if we get here f and *l are comparing the same fields */ if(ipmuxvalcmp(ft, f) != 0){ /* different values mean mutually exclusive */ return ipmuxremove(&ft->no, f); } /* we found a match */ if(--(ft->ref) == 0){ /* * a dead node implies the whole yes side is also dead. * since our chain is constrained to be on that side, * we're done. */ ipmuxtreefree(ft->yes); *l = ft->no; ipmuxfree(ft); return 0; } /* * free the rest of the chain. it is constrained to match the * yes side. */ return ipmuxremove(&ft->yes, f->yes);}/* * connection request is a semi separated list of filters * e.g. proto=17;dat[0:4]=11aa22bb;ifc=135.104.9.2&255.255.255.0 * * there's no protection against overlapping specs. */static char*ipmuxconnect(Conv *c, char **argv, int argc){ int i, n; char *field[10]; Ipmux *mux, *chain; Ipmuxrock *r; Fs *f; f = c->p->f; if(argc != 2) return Ebadarg; n = getfields(argv[1], field, nelem(field), 1, ";"); if(n <= 0) return Ebadarg; chain = nil; mux = nil; for(i = 0; i < n; i++){ mux = parsemux(field[i]); if(mux == nil){ ipmuxtreefree(chain); return Ebadarg; } ipmuxchain(&chain, mux); } if(chain == nil) return Ebadarg; mux->conv = c; /* save a copy of the chain so we can later remove it */ mux = ipmuxcopy(chain); r = (Ipmuxrock*)(c->ptcl); r->chain = chain; /* add the chain to the protocol demultiplexor tree */ wlock(f); f->ipmux->priv = ipmuxmerge(f->ipmux->priv, mux); wunlock(f); Fsconnected(c, nil); return nil;}static intipmuxstate(Conv *c, char *state, int n){ Ipmuxrock *r; r = (Ipmuxrock*)(c->ptcl); return ipmuxsprint(r->chain, 0, state, n);}static voidipmuxcreate(Conv *c){ Ipmuxrock *r; c->rq = qopen(64*1024, Qmsg, 0, c); c->wq = qopen(64*1024, Qkick, ipmuxkick, c); r = (Ipmuxrock*)(c->ptcl); r->chain = nil;}static char*ipmuxannounce(Conv*, char**, int){ return "ipmux does not support announce";}static voidipmuxclose(Conv *c){ Ipmuxrock *r; Fs *f = c->p->f; r = (Ipmuxrock*)(c->ptcl); qclose(c->rq); qclose(c->wq); qclose(c->eq); ipmove(c->laddr, IPnoaddr); ipmove(c->raddr, IPnoaddr); c->lport = 0; c->rport = 0; wlock(f); ipmuxremove(&(c->p->priv), r->chain); wunlock(f); ipmuxtreefree(r->chain); r->chain = nil;}/* * takes a fully formed ip packet and just passes it down * the stack */static voidipmuxkick(void *x){ Conv *c = x; Block *bp; struct Ip6hdr *ih6; bp = qget(c->wq); if(bp == nil) return; else { Ip4hdr *ih4 = (Ip4hdr*)(bp->rp); if((ih4->vihl)&0xF0 != 0x60) ipoput4(c->p->f, bp, 0, ih4->ttl, ih4->tos, nil); else { ih6 = (struct Ip6hdr*)ih4; ipoput6(c->p->f, bp, 0, ih6->ttl, 0, nil); } }}static voidipmuxiput(Proto *p, Ipifc *ifc, Block *bp){ int len, hl; Fs *f = p->f; uchar *m, *h, *v, *e, *ve, *hp; Conv *c; Ipmux *mux; Ip4hdr *ip; Ip6hdr *ip6; ip = (Ip4hdr*)bp->rp; hl = (ip->vihl&0x0F)<<2; if(p->priv == nil) goto nomatch; h = bp->rp; len = BLEN(bp); /* run the v4 filter */ rlock(f); c = nil; mux = f->ipmux->priv; while(mux != nil){ if(mux->eoff > len){ mux = mux->no; continue; } hp = h + mux->off + ((int)mux->skiphdr)*hl; switch(mux->ctype){ case Cbyte: if(*mux->val == *hp) goto yes; break; case Cmbyte: if((*hp & *mux->mask) == *mux->val) goto yes; break; case Cshort: if(*((ushort*)mux->val) == *(ushort*)hp) goto yes; break; case Cmshort: if((*(ushort*)hp & (*((ushort*)mux->mask))) == *((ushort*)mux->val)) goto yes; break; case Clong: if(*((ulong*)mux->val) == *(ulong*)hp) goto yes; break; case Cmlong: if((*(ulong*)hp & (*((ulong*)mux->mask))) == *((ulong*)mux->val)) goto yes; break; case Cifc: if(*((ulong*)mux->val) == *(ulong*)(ifc->lifc->local + IPv4off)) goto yes; break; case Cmifc: if((*(ulong*)(ifc->lifc->local + IPv4off) & (*((ulong*)mux->mask))) == *((ulong*)mux->val)) goto yes; break; default: v = mux->val; for(e = mux->e; v < e; v = ve){ m = mux->mask; hp = h + mux->off; for(ve = v + mux->len; v < ve; v++){ if((*hp++ & *m++) != *v) break; } if(v == ve) goto yes; } } mux = mux->no; continue;yes: if(mux->conv != nil) c = mux->conv; mux = mux->yes; } runlock(f); if(c != nil){ /* tack on interface address */ bp = padblock(bp, IPaddrlen); ipmove(bp->rp, ifc->lifc->local); bp = concatblock(bp); if(bp != nil) if(qpass(c->rq, bp) < 0) print("Q"); return; }nomatch: /* doesn't match any filter, hand it to the specific protocol handler */ ip = (Ip4hdr*)bp->rp; if((ip->vihl&0xF0)==0x40) { p = f->t2p[ip->proto]; } else { ip6 = (Ip6hdr*)bp->rp; p = f->t2p[ip6->proto]; } if(p && p->rcv) (*p->rcv)(p, ifc, bp); else freeblist(bp); return;}static intipmuxsprint(Ipmux *mux, int level, char *buf, int len){ int i, j, n; uchar *v; n = 0; for(i = 0; i < level; i++) n += snprint(buf+n, len-n, " "); if(mux == nil){ n += snprint(buf+n, len-n, "\n"); return n; } n += snprint(buf+n, len-n, "h[%d:%d]&", mux->off+((int)mux->skiphdr)*((int)ipoff->data), mux->off+(((int)mux->skiphdr)*((int)ipoff->data))+mux->len-1); for(i = 0; i < mux->len; i++) n += snprint(buf+n, len - n, "%2.2ux", mux->mask[i]); n += snprint(buf+n, len-n, "="); v = mux->val; for(j = 0; j < mux->n; j++){ for(i = 0; i < mux->len; i++) n += snprint(buf+n, len - n, "%2.2ux", *v++); n += snprint(buf+n, len-n, "|"); } n += snprint(buf+n, len-n, "\n"); level++; n += ipmuxsprint(mux->no, level, buf+n, len-n); n += ipmuxsprint(mux->yes, level, buf+n, len-n); return n;}static intipmuxstats(Proto *p, char *buf, int len){ int n; Fs *f = p->f; rlock(f); n = ipmuxsprint(p->priv, 0, buf, len); runlock(f); return n;}voidipmuxinit(Fs *f){ Proto *ipmux; ipmux = smalloc(sizeof(Proto)); ipmux->priv = nil; ipmux->name = "ipmux"; ipmux->connect = ipmuxconnect; ipmux->announce = ipmuxannounce; ipmux->state = ipmuxstate; ipmux->create = ipmuxcreate; ipmux->close = ipmuxclose; ipmux->rcv = ipmuxiput; ipmux->ctl = nil; ipmux->advise = nil; ipmux->stats = ipmuxstats; ipmux->ipproto = -1; ipmux->nc = 64; ipmux->ptclsize = sizeof(Ipmuxrock); f->ipmux = ipmux; /* hack for Fsrcvpcol */ Fsproto(f, ipmux);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -