diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2018-04-08 21:15:00 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2018-04-08 21:15:00 +0200 |
commit | c2dd9b1da7659c9ac42e7612e5621e9426956c73 (patch) | |
tree | 8c191ea02792997669a87965419aac936243104f | |
parent | dc8432d4593c7a4b0a187d0174d4e4e603e456f6 (diff) |
devip: implement source specific routing
-rw-r--r-- | sys/src/9/ip/arp.c | 203 | ||||
-rw-r--r-- | sys/src/9/ip/devip.c | 2 | ||||
-rw-r--r-- | sys/src/9/ip/ethermedium.c | 64 | ||||
-rw-r--r-- | sys/src/9/ip/icmp.c | 10 | ||||
-rw-r--r-- | sys/src/9/ip/icmp6.c | 69 | ||||
-rw-r--r-- | sys/src/9/ip/ip.c | 20 | ||||
-rw-r--r-- | sys/src/9/ip/ip.h | 79 | ||||
-rw-r--r-- | sys/src/9/ip/ipifc.c | 675 | ||||
-rw-r--r-- | sys/src/9/ip/iproute.c | 855 | ||||
-rw-r--r-- | sys/src/9/ip/ipv6.c | 28 | ||||
-rw-r--r-- | sys/src/9/ip/rudp.c | 6 | ||||
-rw-r--r-- | sys/src/9/ip/tcp.c | 9 |
12 files changed, 1043 insertions, 977 deletions
diff --git a/sys/src/9/ip/arp.c b/sys/src/9/ip/arp.c index e8b1b831e..894ed922f 100644 --- a/sys/src/9/ip/arp.c +++ b/sys/src/9/ip/arp.c @@ -74,7 +74,7 @@ freeblistchain(Block *bp) } /* - * create a new arp entry for an ip address. + * create a new arp entry for an ip address on ifc. */ static Arpent* newarp6(Arp *arp, uchar *ip, Ipifc *ifc, int addrxt) @@ -82,7 +82,6 @@ newarp6(Arp *arp, uchar *ip, Ipifc *ifc, int addrxt) uint t; Block *xp; Arpent *a, *e, *f, **l; - Medium *m = ifc->m; int empty; /* find oldest entry */ @@ -128,10 +127,9 @@ newarp6(Arp *arp, uchar *ip, Ipifc *ifc, int addrxt) a->hash = *l; *l = a; - memmove(a->ip, ip, sizeof(a->ip)); + ipmove(a->ip, ip); a->utime = NOW; a->ctime = 0; - a->type = m; a->rtime = NOW + ReTransTimer; a->rxtsrem = MAX_MULTICAST_SOLICIT; @@ -172,8 +170,10 @@ cleanarpent(Arp *arp, Arpent *a) a->utime = 0; a->ctime = 0; - a->type = 0; a->state = 0; + + a->ifc = nil; + a->ifcid = 0; /* take out of current chain */ l = &arp->hash[haship(a->ip)]; @@ -198,7 +198,6 @@ cleanarpent(Arp *arp, Arpent *a) a->hash = nil; freeblistchain(a->hold); a->hold = a->last = nil; - a->ifc = nil; } /* @@ -212,7 +211,6 @@ arpget(Arp *arp, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *mac) { int hash; Arpent *a; - Medium *type = ifc->m; uchar v6ip[IPaddrlen]; if(version == V4){ @@ -223,11 +221,9 @@ arpget(Arp *arp, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *mac) qlock(arp); hash = haship(ip); for(a = arp->hash[hash]; a != nil; a = a->hash){ - if(ipcmp(ip, a->ip) == 0) - if(type == a->type) + if(a->ifc == ifc && a->ifcid == ifc->ifcid && ipcmp(ip, a->ip) == 0) break; } - if(a == nil){ a = newarp6(arp, ip, ifc, (version != V4)); a->state = AWAIT; @@ -245,7 +241,7 @@ arpget(Arp *arp, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *mac) return a; /* return with arp qlocked */ } - memmove(mac, a->mac, a->type->maclen); + memmove(mac, a->mac, ifc->m->maclen); /* remove old entries */ if(NOW - a->ctime > 15*60*1000) @@ -286,63 +282,53 @@ arpresolve(Arp *arp, Arpent *a, Medium *type, uchar *mac) l = &f->nextrxt; } } - memmove(a->mac, mac, type->maclen); - a->type = type; a->state = AOK; a->utime = NOW; bp = a->hold; - assert(bp->list == nil); a->hold = a->last = nil; qunlock(arp); return bp; } -void -arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, int refresh) +int +arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, uchar *src, int refresh) { Arp *arp; Route *r; Arpent *a, *f, **l; Ipifc *ifc; - Medium *type; Block *bp, *next; + Medium *m; uchar v6ip[IPaddrlen]; arp = fs->arp; - - if(n != 6) - return; - switch(version){ case V4: - r = v4lookup(fs, ip, nil); + r = v4lookup(fs, ip, src, nil); v4tov6(v6ip, ip); ip = v6ip; break; case V6: - r = v6lookup(fs, ip, nil); + r = v6lookup(fs, ip, src, nil); break; default: panic("arpenter: version %d", version); - return; /* to supress warnings */ + return -1; /* to supress warnings */ } - - if(r == nil) - return; - - ifc = r->ifc; - type = ifc->m; + if(r == nil || (ifc = r->ifc) == nil || (m = ifc->m) == nil || m->maclen != n || m->maclen == 0) + return -1; qlock(arp); for(a = arp->hash[haship(ip)]; a != nil; a = a->hash){ - if(a->type != type || (a->state != AWAIT && a->state != AOK)) + if(a->state != AWAIT && a->state != AOK) + continue; + if(a->ifc != ifc || a->ifcid != ifc->ifcid) continue; - if(ipcmp(a->ip, ip) == 0){ a->state = AOK; - memmove(a->mac, mac, type->maclen); + memmove(a->mac, mac, n); if(version == V6){ /* take out of re-transmit chain */ @@ -356,8 +342,6 @@ arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, int refresh) } } - a->ifc = ifc; - a->ifcid = ifc->ifcid; bp = a->hold; a->hold = a->last = nil; if(version == V4) @@ -367,46 +351,52 @@ arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, int refresh) qunlock(arp); while(bp != nil){ + if(!canrlock(ifc)){ + freeblistchain(bp); + break; + } + if(ifc->m != m){ + runlock(ifc); + freeblistchain(bp); + break; + } next = bp->list; + bp->list = nil; if(waserror()){ - freeblistchain(next); runlock(ifc); - nexterror(); + freeblistchain(next); + break; } - rlock(ifc); - if(ifc->m != nil) - ifc->m->bwrite(ifc, concatblock(bp), version, ip); - else - freeblist(bp); + m->bwrite(ifc, concatblock(bp), version, ip); runlock(ifc); poperror(); bp = next; } - return; + + return 1; } } if(refresh == 0){ a = newarp6(arp, ip, ifc, 0); a->state = AOK; - a->type = type; a->ctime = NOW; - memmove(a->mac, mac, type->maclen); + memmove(a->mac, mac, n); } qunlock(arp); + return refresh == 0; } int arpwrite(Fs *fs, char *s, int len) { int n; - Route *r; Arp *arp; - Arpent *a; + Arpent *a, *x; Medium *m; - char *f[4], buf[256]; - uchar ip[IPaddrlen], mac[MAClen]; + char *f[5], buf[256]; + uchar ip[IPaddrlen], src[IPaddrlen], mac[MAClen]; arp = fs->arp; @@ -419,7 +409,7 @@ arpwrite(Fs *fs, char *s, int len) if(len > 0 && buf[len-1] == '\n') buf[len-1] = 0; - n = getfields(buf, f, 4, 1, " "); + n = getfields(buf, f, nelem(f), 1, " "); if(strcmp(f[0], "flush") == 0){ qlock(arp); for(a = arp->cache; a < &arp->cache[NCACHE]; a++){ @@ -428,6 +418,8 @@ arpwrite(Fs *fs, char *s, int len) a->hash = nil; a->state = 0; a->utime = 0; + a->ifc = nil; + a->ifcid = 0; freeblistchain(a->hold); a->hold = a->last = nil; } @@ -442,47 +434,49 @@ arpwrite(Fs *fs, char *s, int len) default: error(Ebadarg); case 3: - if (parseip(ip, f[1]) == -1) + if(parseip(ip, f[1]) == -1) error(Ebadip); - if(isv4(ip)) - r = v4lookup(fs, ip+IPv4off, nil); - else - r = v6lookup(fs, ip, nil); - if(r == nil) - error("Destination unreachable"); - m = r->ifc->m; - n = parsemac(mac, f[2], m->maclen); + if((n = parsemac(mac, f[2], sizeof(mac))) <= 0) + error(Ebadarp); + findlocalip(fs, src, ip); break; case 4: m = ipfindmedium(f[1]); - if(m == nil) + if(m == nil || m->maclen == 0) + error(Ebadarp); + if(parseip(ip, f[2]) == -1) + error(Ebadip); + if((n = parsemac(mac, f[3], sizeof(mac))) != m->maclen) + error(Ebadarp); + findlocalip(fs, src, ip); + break; + case 5: + m = ipfindmedium(f[1]); + if(m == nil || m->maclen == 0) error(Ebadarp); - if (parseip(ip, f[2]) == -1) + if(parseip(ip, f[2]) == -1) + error(Ebadip); + if((n = parsemac(mac, f[3], sizeof(mac))) != m->maclen) + error(Ebadarp); + if(parseip(src, f[4]) == -1) error(Ebadip); - n = parsemac(mac, f[3], m->maclen); break; } - - if(m->ares == nil) - error(Ebadarp); - - m->ares(fs, V6, ip, mac, n, 0); + if(arpenter(fs, V6, ip, mac, n, src, 0) <= 0) + error("destination unreachable"); } else if(strcmp(f[0], "del") == 0){ - if(n != 2) + if (n != 2) error(Ebadarg); - if (parseip(ip, f[1]) == -1) error(Ebadip); - qlock(arp); - for(a = arp->hash[haship(ip)]; a != nil; a = a->hash) - if(memcmp(ip, a->ip, sizeof(a->ip)) == 0) - break; - - if(a != nil){ - cleanarpent(arp, a); - memset(a->ip, 0, sizeof(a->ip)); - memset(a->mac, 0, sizeof(a->mac)); + for(a = arp->hash[haship(ip)]; a != nil; a = x){ + x = a->hash; + if(ipcmp(ip, a->ip) == 0){ + cleanarpent(arp, a); + memset(a->ip, 0, sizeof(a->ip)); + memset(a->mac, 0, sizeof(a->mac)); + } } qunlock(arp); } else @@ -491,13 +485,6 @@ arpwrite(Fs *fs, char *s, int len) return len; } -enum -{ - Alinelen= 90, -}; - -char *aformat = "%-6.6s %-8.8s %-40.40I %-32.32s\n"; - static void convmac(char *p, uchar *mac, int n) { @@ -506,34 +493,40 @@ convmac(char *p, uchar *mac, int n) } int -arpread(Arp *arp, char *p, ulong offset, int len) +arpread(Arp *arp, char *s, ulong offset, int len) { + uchar ip[IPaddrlen], src[IPaddrlen]; + char mac[2*MAClen+1], *p, *state; + Ipifc *ifc; Arpent *a; - int n; - char mac[2*MAClen+1]; + long n, o; - if(offset % Alinelen) - return 0; - - offset = offset/Alinelen; - len = len/Alinelen; - - n = 0; + p = s; + o = -offset; for(a = arp->cache; len > 0 && a < &arp->cache[NCACHE]; a++){ - if(a->state == 0) + if(a->state == 0 || (ifc = a->ifc) == nil || a->ifcid != ifc->ifcid) continue; - if(offset > 0){ - offset--; - continue; - } - len--; + qlock(arp); - convmac(mac, a->mac, a->type->maclen); - n += sprint(p+n, aformat, a->type->name, arpstate[a->state], a->ip, mac); + state = arpstate[a->state]; + ipmove(ip, a->ip); + convmac(mac, a->mac, ifc->m->maclen); qunlock(arp); + + ipv6local(ifc, src, ip); + n = snprint(p, len, "%-6.6s %-4.4s %-40.40I %-16.16s %I\n", + ifc->m->name, state, ip, mac, src); + if(o < 0) { + if(n > -o) + memmove(p, p-o, n+o); + o += n; + } else { + len -= n; + p += n; + } } - return n; + return p - s; } void @@ -547,7 +540,7 @@ ndpsendsol(Fs *f, Ipifc *ifc, Arpent *a) ipmove(src, ((Ip6hdr*)a->last->rp)->src); arprelease(f->arp, a); - if(iplocalonifc(ifc, src) || ipproxyifc(f, ifc, src)) + if(iplocalonifc(ifc, src) != nil || ipproxyifc(f, ifc, src)) goto send; } else { arprelease(f->arp, a); diff --git a/sys/src/9/ip/devip.c b/sys/src/9/ip/devip.c index 18dbf54ff..6a08a0491 100644 --- a/sys/src/9/ip/devip.c +++ b/sys/src/9/ip/devip.c @@ -848,7 +848,7 @@ setladdrport(Conv* c, char* str, int announcing) else { if(parseip(addr, str) == -1) return Ebadip; - if(ipforme(c->p->f, addr) || ipismulticast(addr)) + if(ipforme(c->p->f, addr) != 0 || ipismulticast(addr)) ipmove(c->laddr, addr); else return "not a local IP address"; diff --git a/sys/src/9/ip/ethermedium.c b/sys/src/9/ip/ethermedium.c index 9b1962450..0532457de 100644 --- a/sys/src/9/ip/ethermedium.c +++ b/sys/src/9/ip/ethermedium.c @@ -33,9 +33,9 @@ static void etherunbind(Ipifc *ifc); static void etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip); static void etheraddmulti(Ipifc *ifc, uchar *a, uchar *ia); static void etherremmulti(Ipifc *ifc, uchar *a, uchar *ia); +static void etherareg(Fs *f, Ipifc *ifc, uchar *ip, uchar *proxy); static Block* multicastarp(Fs *f, Arpent *a, Medium*, uchar *mac); static void sendarp(Ipifc *ifc, Arpent *a); -static void sendgarp(Ipifc *ifc, uchar*); static int multicastea(uchar *ea, uchar *ip); static void recvarpproc(void*); static void resolveaddr6(Ipifc *ifc, Arpent *a); @@ -53,8 +53,7 @@ Medium ethermedium = .bwrite= etherbwrite, .addmulti= etheraddmulti, .remmulti= etherremmulti, -.ares= arpenter, -.areg= sendgarp, +.areg= etherareg, .pref2addr= etherpref2addr, }; @@ -70,8 +69,7 @@ Medium gbemedium = .bwrite= etherbwrite, .addmulti= etheraddmulti, .remmulti= etherremmulti, -.ares= arpenter, -.areg= sendgarp, +.areg= etherareg, .pref2addr= etherpref2addr, }; @@ -271,7 +269,7 @@ etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip) /* get mac address of destination */ a = arpget(er->f->arp, bp, version, ifc, ip, mac); - if(a){ + if(a != nil){ /* check for broadcast or multicast */ bp = multicastarp(er->f, a, ifc->m, mac); if(bp==nil){ @@ -471,8 +469,8 @@ sendarp(Ipifc *ifc, Arpent *a) arprelease(er->f->arp, a); n = sizeof(Etherarp); - if(n < a->type->mintu) - n = a->type->mintu; + if(n < ifc->m->mintu) + n = ifc->m->mintu; bp = allocb(n); memset(bp->rp, 0, n); e = (Etherarp*)bp->rp; @@ -536,10 +534,6 @@ sendgarp(Ipifc *ifc, uchar *ip) Etherarp *e; Etherrock *er = ifc->arg; - /* don't arp for our initial non address */ - if(ipcmp(ip, IPnoaddr) == 0) - return; - n = sizeof(Etherarp); if(n < ifc->m->mintu) n = ifc->m->mintu; @@ -585,7 +579,7 @@ recvarp(Ipifc *ifc) case ARPREPLY: /* check for machine using my ip address */ v4tov6(ip, e->spa); - if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){ + if(iplocalonifc(ifc, ip) != nil || ipproxyifc(er->f, ifc, ip)){ if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){ print("arprep: 0x%E/0x%E also has ip addr %V\n", e->s, e->sha, e->spa); @@ -594,14 +588,13 @@ recvarp(Ipifc *ifc) } /* make sure we're not entering broadcast addresses */ - if(ipcmp(ip, ipbroadcast) == 0 || - !memcmp(e->sha, etherbroadcast, sizeof(e->sha))){ + if(ipcmp(ip, ipbroadcast) == 0 || memcmp(e->sha, etherbroadcast, sizeof(e->sha)) == 0){ print("arprep: 0x%E/0x%E cannot register broadcast address %I\n", e->s, e->sha, e->spa); break; } - arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 0); + arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), e->tpa, 0); break; case ARPREQUEST: @@ -611,9 +604,9 @@ recvarp(Ipifc *ifc) /* check for machine using my ip or ether address */ v4tov6(ip, e->spa); - if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){ + if(iplocalonifc(ifc, ip) != nil || ipproxyifc(er->f, ifc, ip)){ if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){ - if (memcmp(eprinted, e->spa, sizeof(e->spa))){ + if(memcmp(eprinted, e->spa, sizeof(e->spa)) != 0){ /* print only once */ print("arpreq: 0x%E also has ip addr %V\n", e->sha, e->spa); memmove(eprinted, e->spa, sizeof(e->spa)); @@ -627,12 +620,11 @@ recvarp(Ipifc *ifc) } /* refresh what we know about sender */ - arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 1); + arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), e->tpa, 1); /* answer only requests for our address or systems we're proxying for */ v4tov6(ip, e->tpa); - if(!iplocalonifc(ifc, ip)) - if(!ipproxyifc(er->f, ifc, ip)) + if(iplocalonifc(ifc, ip) == nil && !ipproxyifc(er->f, ifc, ip)) break; n = sizeof(Etherarp); @@ -742,7 +734,7 @@ ethermediumlink(void) static void etherpref2addr(uchar *pref, uchar *ea) { - pref[8] = ea[0] | 0x2; + pref[8] = ea[0] ^ 0x2; pref[9] = ea[1]; pref[10] = ea[2]; pref[11] = 0xFF; @@ -751,3 +743,31 @@ etherpref2addr(uchar *pref, uchar *ea) pref[14] = ea[4]; pref[15] = ea[5]; } + +static void +etherareg(Fs *f, Ipifc *ifc, uchar *ip, uchar *proxy) +{ + static char tdad[] = "dad6"; + uchar mcast[IPaddrlen]; + + if(ipcmp(ip, IPnoaddr) == 0) + return; + + if(isv4(ip)){ + sendgarp(ifc, ip); + return; + } + + if(!iptentative(f, ip)){ + icmpna(f, proxy, v6allnodesL, ip, ifc->mac, 1<<5); + return; + } + + /* temporarily add route for duplicate address detection */ + ipv62smcast(mcast, ip); + addroute(f, mcast, IPallbits, v6Unspecified, IPallbits, ip, Rmulti, ifc, tdad); + + icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac); + + remroute(f, mcast, IPallbits, v6Unspecified, IPallbits, ip, Rmulti, ifc, tdad); +} diff --git a/sys/src/9/ip/icmp.c b/sys/src/9/ip/icmp.c index 21f226c7f..2a2d3e21b 100644 --- a/sys/src/9/ip/icmp.c +++ b/sys/src/9/ip/icmp.c @@ -200,7 +200,7 @@ ip4reply(Fs *f, uchar ip4[4]) if(ipismulticast(addr)) return 0; i = ipforme(f, addr); - return i == 0 || (i & Runi) != 0; + return i == 0 || i == Runi; } static int @@ -211,7 +211,7 @@ ip4me(Fs *f, uchar ip4[4]) v4tov6(addr, ip4); if(ipismulticast(addr)) return 0; - return (ipforme(f, addr) & Runi) != 0; + return ipforme(f, addr) == Runi; } void @@ -401,7 +401,7 @@ icmpiput(Proto *icmp, Ipifc*, Block *bp) break; case Unreachable: if(p->code >= nelem(unreachcode)) { - snprint(m2, sizeof m2, "unreachable %V->%V code %d", + snprint(m2, sizeof m2, "unreachable %V -> %V code %d", p->src, p->dst, p->code); msg = m2; } else @@ -452,7 +452,7 @@ raise: freeblist(bp); } -void +static void icmpadvise(Proto *icmp, Block *bp, char *msg) { Conv **c, *s; @@ -478,7 +478,7 @@ icmpadvise(Proto *icmp, Block *bp, char *msg) freeblist(bp); } -int +static int icmpstats(Proto *icmp, char *buf, int len) { Icmppriv *priv; diff --git a/sys/src/9/ip/icmp6.c b/sys/src/9/ip/icmp6.c index 617370472..c246b6edc 100644 --- a/sys/src/9/ip/icmp6.c +++ b/sys/src/9/ip/icmp6.c @@ -211,7 +211,7 @@ newIPICMP(int packetlen) return nbp; } -void +static void icmpadvise6(Proto *icmp, Block *bp, char *msg) { ushort recid; @@ -223,7 +223,8 @@ icmpadvise6(Proto *icmp, Block *bp, char *msg) for(c = icmp->conv; *c; c++) { s = *c; - if(s->lport == recid && ipcmp(s->raddr, p->dst) == 0){ + if(s->lport == recid) + if(ipcmp(s->laddr, p->dst) == 0 || ipcmp(s->raddr, p->dst) == 0){ if(s->ignoreadvice) break; qhangup(s->rq, msg); @@ -280,7 +281,7 @@ icmpkick6(void *x, Block *bp) ipoput6(c->p->f, bp, 0, c->ttl, c->tos, nil); } -char* +static char* icmpctl6(Conv *c, char **argv, int argc) { Icmpcb6 *icb; @@ -311,10 +312,14 @@ goticmpkt6(Proto *icmp, Block *bp, int muxkey) for(c = icmp->conv; *c; c++){ s = *c; - if(s->lport == recid && ipcmp(s->raddr, addr) == 0){ + if(s->lport != recid) + continue; + if(ipcmp(s->laddr, addr) == 0){ qpass(s->rq, concatblock(bp)); return; } + if(ipcmp(s->raddr, addr) == 0) + qpass(s->rq, copyblock(bp, blocklen(bp))); } freeblist(bp); @@ -416,7 +421,7 @@ icmpna(Fs *f, uchar* src, uchar* dst, uchar* targ, uchar* mac, uchar flags) np->ttl = HOP_LIMIT; np->vcf[0] = 0x06 << 4; ipriv->out[NbrAdvert]++; - netlog(f, Logicmp, "sending neighbor advertisement %I\n", src); + netlog(f, Logicmp, "sending neighbor advertisement %I\n", targ); ipoput6(f, nbp, 0, MAXTTL, DFLTTOS, nil); } @@ -692,26 +697,19 @@ targettype(Fs *f, Ipifc *ifc, uchar *target) int t; rlock(ifc); - if(ipproxyifc(f, ifc, target)) { - runlock(ifc); - return Tuniproxy; - } - - for(lifc = ifc->lifc; lifc; lifc = lifc->next) - if(ipcmp(lifc->local, target) == 0) { - t = (lifc->tentative)? Tunitent: Tunirany; - runlock(ifc); - return t; - } - + if((lifc = iplocalonifc(ifc, target)) != nil) + t = lifc->tentative? Tunitent: Tunirany; + else if(ipproxyifc(f, ifc, target)) + t = Tuniproxy; + else + t = 0; runlock(ifc); - return 0; + return t; } static void icmpiput6(Proto *icmp, Ipifc *ipifc, Block *bp) { - int refresh = 1; char *msg, m2[128]; uchar pktflags; uchar *packet = bp->rp; @@ -797,16 +795,12 @@ icmpiput6(Proto *icmp, Ipifc *ipifc, Block *bp) /* fall through */ case Tuniproxy: - if(ipcmp(np->src, v6Unspecified) != 0) { - arpenter(icmp->f, V6, np->src, np->lnaddr, - 8*np->olen-2, 0); + if(ipv6local(ipifc, lsrc, np->src)) { + arpenter(icmp->f, V6, np->src, np->lnaddr, 8*np->olen-2, lsrc, 0); pktflags |= Sflag; - } - if(!ipv6local(ipifc, lsrc, np->src)) - break; - icmpna(icmp->f, lsrc, - (ipcmp(np->src, v6Unspecified) == 0? - v6allnodesL: np->src), + } else + ipmove(lsrc, np->target); + icmpna(icmp->f, lsrc, (pktflags & Sflag) ? np->src : v6allnodesL, np->target, ipifc->mac, pktflags); break; case Tunitent: @@ -830,9 +824,10 @@ icmpiput6(Proto *icmp, Ipifc *ipifc, Block *bp) * the arp table. */ lifc = iplocalonifc(ipifc, np->target); - if(lifc && lifc->tentative) - refresh = 0; - arpenter(icmp->f, V6, np->target, np->lnaddr, 8*np->olen-2, refresh); + if(lifc != nil && lifc->tentative) + arpenter(icmp->f, V6, np->target, np->lnaddr, 8*np->olen-2, np->target, 0); + else if(ipv6local(ipifc, lsrc, np->target)) + arpenter(icmp->f, V6, np->target, np->lnaddr, 8*np->olen-2, lsrc, 1); freeblist(bp); break; @@ -846,7 +841,7 @@ raise: freeblist(bp); } -int +static int icmpstats6(Proto *icmp6, char *buf, int len) { Icmppriv6 *priv; @@ -872,6 +867,14 @@ extern char* icmpannounce(Conv *c, char **argv, int argc); extern char* icmpconnect(Conv *c, char **argv, int argc); extern void icmpclose(Conv *c); +static void +icmpclose6(Conv *c) +{ + Icmpcb6 *icb = (Icmpcb6*)c->ptcl; + icb->headers = 0; + icmpclose(c); +} + void icmp6init(Fs *fs) { @@ -883,7 +886,7 @@ icmp6init(Fs *fs) icmp6->announce = icmpannounce; icmp6->state = icmpstate; icmp6->create = icmpcreate6; - icmp6->close = icmpclose; + icmp6->close = icmpclose6; icmp6->rcv = icmpiput6; icmp6->stats = icmpstats6; icmp6->ctl = icmpctl6; diff --git a/sys/src/9/ip/ip.c b/sys/src/9/ip/ip.c index 6c4d02992..d296c2ed0 100644 --- a/sys/src/9/ip/ip.c +++ b/sys/src/9/ip/ip.c @@ -124,7 +124,7 @@ ipoput4(Fs *f, Block *bp, int gating, int ttl, int tos, Routehint *rh) Block *xp, *nb; Ip4hdr *eh, *feh; int lid, len, seglen, chunk, dlen, blklen, offset, medialen; - Route *r, *sr; + Route *r; IP *ip; int rv = 0; @@ -154,25 +154,17 @@ ipoput4(Fs *f, Block *bp, int gating, int ttl, int tos, Routehint *rh) goto free; } - r = v4lookup(f, eh->dst, rh); - if(r == nil){ + r = v4lookup(f, eh->dst, eh->src, rh); + if(r == nil || (ifc = r->ifc) == nil){ ip->stats[OutNoRoutes]++; - netlog(f, Logip, "no interface %V\n", eh->dst); + netlog(f, Logip, "no interface %V -> %V\n", eh->src, eh->dst); rv = -1; goto free; } - ifc = r->ifc; - if(r->type & (Rifc|Runi)) + if(r->type & (Rifc|Runi|Rbcast|Rmulti)) gate = eh->dst; else - if(r->type & (Rbcast|Rmulti)) { - gate = eh->dst; - sr = v4lookup(f, eh->src, nil); - if(sr != nil && (sr->type & Runi)) - ifc = sr->ifc; - } - else gate = r->v4.gate; if(!gating) @@ -380,7 +372,7 @@ ipiput4(Fs *f, Ipifc *ifc, Block *bp) /* don't forward to source's network */ rh.r = nil; - r = v4lookup(f, h->dst, &rh); + r = v4lookup(f, h->dst, h->src, &rh); if(r == nil || r->ifc == ifc){ ip->stats[OutDiscards]++; freeblist(bp); diff --git a/sys/src/9/ip/ip.h b/sys/src/9/ip/ip.h index 5b3e41967..b7991ebe0 100644 --- a/sys/src/9/ip/ip.h +++ b/sys/src/9/ip/ip.h @@ -39,7 +39,7 @@ enum Maxproto= 20, Maxincall= 10, Nchans= 1024, - MAClen= 16, /* longest mac address */ + MAClen= 8, /* longest mac address */ MAXTTL= 255, DFLTTOS= 0, @@ -242,18 +242,8 @@ struct Medium /* process packets written to 'data' */ void (*pktin)(Fs *f, Ipifc *ifc, Block *bp); - /* routes for router boards */ - void (*addroute)(Ipifc *ifc, int, uchar*, uchar*, uchar*, int); - void (*remroute)(Ipifc *ifc, int, uchar*, uchar*); - void (*flushroutes)(Ipifc *ifc); - - /* for routing multicast groups */ - void (*joinmulti)(Ipifc *ifc, uchar *a, uchar *ia); - void (*leavemulti)(Ipifc *ifc, uchar *a, uchar *ia); - /* address resolution */ - void (*ares)(Fs*, int, uchar*, uchar*, int, int); /* resolve */ - void (*areg)(Ipifc*, uchar*); /* register */ + void (*areg)(Fs *f, Ipifc *ifc, uchar *ip, uchar *proxy); /* register */ /* v6 address generation */ void (*pref2addr)(uchar *pref, uchar *ea); @@ -268,6 +258,7 @@ struct Iplifc uchar mask[IPaddrlen]; uchar remote[IPaddrlen]; uchar net[IPaddrlen]; + uchar type; /* ruoute type */ uchar tentative; /* =1 => v6 dup disc on, =0 => confirmed unique */ uchar onlink; /* =1 => onlink, =0 offlink. */ uchar autoflag; /* v6 autonomous flag */ @@ -509,13 +500,11 @@ void ifclogclose(Fs*, Chan*); * iproute.c */ typedef struct RouteTree RouteTree; -typedef struct Routewalk Routewalk; typedef struct V4route V4route; typedef struct V6route V6route; enum { - /* type bits */ Rv4= (1<<0), /* this is a version 4 route */ Rifc= (1<<1), /* this route is a directly connected interface */ @@ -524,27 +513,18 @@ enum Rbcast= (1<<4), /* a broadcast self address */ Rmulti= (1<<5), /* a multicast self address */ Rproxy= (1<<6), /* this route should be proxied */ -}; - -struct Routewalk -{ - int o; - int h; - char* p; - char* e; - void* state; - void (*walk)(Route*, Routewalk*); + Rsrc= (1<<7), /* source specific route */ }; struct RouteTree { - Route* right; - Route* left; - Route* mid; + Route *mid; + Route *left; + Route *right; + Ipifc *ifc; + uchar ifcid; /* must match ifc->id */ uchar depth; uchar type; - uchar ifcid; /* must match ifc->id */ - Ipifc *ifc; char tag[4]; int ref; }; @@ -553,6 +533,10 @@ struct V4route { ulong address; ulong endaddress; + + ulong source; + ulong endsource; + uchar gate[IPv4addrlen]; }; @@ -560,6 +544,10 @@ struct V6route { ulong address[IPllen]; ulong endaddress[IPllen]; + + ulong source[IPllen]; + ulong endsource[IPllen]; + uchar gate[IPaddrlen]; }; @@ -572,17 +560,14 @@ struct Route V4route v4; }; }; -extern void v4addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type); -extern void v6addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type); -extern void v4delroute(Fs *f, uchar *a, uchar *mask, int dolock); -extern void v6delroute(Fs *f, uchar *a, uchar *mask, int dolock); -extern Route* v4lookup(Fs *f, uchar *a, Routehint *h); -extern Route* v6lookup(Fs *f, uchar *a, Routehint *h); + +extern void addroute(Fs *f, uchar *a, uchar *mask, uchar *s, uchar *smask, uchar *gate, int type, Ipifc *ifc, char *tag); +extern void remroute(Fs *f, uchar *a, uchar *mask, uchar *s, uchar *smask, uchar *gate, int type, Ipifc *ifc, char *tag); +extern Route* v4lookup(Fs *f, uchar *a, uchar *s, Routehint *h); +extern Route* v6lookup(Fs *f, uchar *a, uchar *s, Routehint *h); extern long routeread(Fs *f, char*, ulong, int); extern long routewrite(Fs *f, Chan*, char*, int); -extern void routetype(int, char*); -extern void ipwalkroutes(Fs*, Routewalk*); -extern void convroute(Route*, uchar*, uchar*, uchar*, char*, int*); +extern void routetype(int type, char p[8]); /* * devip.c @@ -607,7 +592,6 @@ struct Arpent { uchar ip[IPaddrlen]; uchar mac[MAClen]; - Medium *type; /* media type */ Arpent* hash; Block* hold; Block* last; @@ -627,7 +611,7 @@ extern int arpwrite(Fs*, char*, int); extern Arpent* arpget(Arp*, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *h); extern void arprelease(Arp*, Arpent *a); extern Block* arpresolve(Arp*, Arpent *a, Medium *type, uchar *mac); -extern void arpenter(Fs*, int version, uchar *ip, uchar *mac, int len, int norefresh); +extern int arpenter(Fs*, int version, uchar *ip, uchar *mac, int n, uchar *src, int norefresh); extern void ndpsendsol(Fs*, Ipifc*, Arpent*); /* @@ -674,21 +658,16 @@ extern Medium* ipfindmedium(char *name); extern void addipmedium(Medium *med); extern int ipforme(Fs*, uchar *addr); extern int iptentative(Fs*, uchar *addr); -extern int ipisbm(uchar *); -extern int ipismulticast(uchar *); -extern Ipifc* findipifc(Fs*, uchar *remote, int type); +extern int ipisbm(uchar *ip); +extern int ipismulticast(uchar *ip); +extern Ipifc* findipifc(Fs*, uchar *local, uchar *remote, int type); +extern Ipifc* findipifcstr(Fs *f, char *s); extern void findlocalip(Fs*, uchar *local, uchar *remote); extern int ipv4local(Ipifc *ifc, uchar *local, uchar *remote); extern int ipv6local(Ipifc *ifc, uchar *local, uchar *remote); extern Iplifc* iplocalonifc(Ipifc *ifc, uchar *ip); +extern Iplifc* ipremoteonifc(Ipifc *ifc, uchar *ip); extern int ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip); -extern int ipismulticast(uchar *ip); -extern int ipisbooting(void); -extern int ipifccheckin(Ipifc *ifc, Medium *med); -extern void ipifccheckout(Ipifc *ifc); -extern int ipifcgrab(Ipifc *ifc); -extern void ipifcaddroute(Fs*, int, uchar*, uchar*, uchar*, int); -extern void ipifcremroute(Fs*, int, uchar*, uchar*); extern void ipifcremmulti(Conv *c, uchar *ma, uchar *ia); extern void ipifcaddmulti(Conv *c, uchar *ma, uchar *ia); extern char* ipifcrem(Ipifc *ifc, char **argv, int argc); diff --git a/sys/src/9/ip/ipifc.c b/sys/src/9/ip/ipifc.c index 3ed24fa60..d08a81672 100644 --- a/sys/src/9/ip/ipifc.c +++ b/sys/src/9/ip/ipifc.c @@ -61,10 +61,53 @@ static char tifc[] = "ifc "; static void addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type); static void remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a); -static char* ipifcjoinmulti(Ipifc *ifc, char **argv, int argc); -static char* ipifcleavemulti(Ipifc *ifc, char **argv, int argc); -static void ipifcregisterproxy(Fs*, Ipifc*, uchar*); -static char* ipifcremlifc(Ipifc*, Iplifc*); +static void ipifcregisterproxy(Fs*, Ipifc*, uchar*, int); +static char* ipifcremlifc(Ipifc*, Iplifc**); + +enum { + unknownv6, /* UGH */ + unspecifiedv6, + linklocalv6, + globalv6, +}; + +static int +v6addrtype(uchar *addr) +{ + if(isv4(addr) || ipcmp(addr, IPnoaddr) == 0) + return unknownv6; + else if(islinklocal(addr) || + isv6mcast(addr) && (addr[1] & 0xF) <= Link_local_scop) + return linklocalv6; + else + return globalv6; +} + +#define v6addrcurr(lifc) ((lifc)->preflt == ~0L || \ + (lifc)->origint + (lifc)->preflt >= NOW/1000) + +static uchar* +defsmask(uchar *a) +{ + if(v6addrtype(a) == linklocalv6) + return IPallbits; + return IPnoaddr; +} + +static int +comprefixlen(uchar *a, uchar *b, int n) +{ + int i, c; + + for(i = 0; i < n; i++){ + if((c = a[i] ^ b[i]) == 0) + continue; + for(i <<= 3; (c & 0x80) == 0; i++) + c <<= 1; + return i; + } + return i << 3; +} /* * link in a new medium @@ -181,18 +224,18 @@ ipifcunbind(Ipifc *ifc) } /* disassociate logical interfaces (before zeroing ifc->arg) */ - while(ifc->lifc){ - err = ipifcremlifc(ifc, ifc->lifc); + while(ifc->lifc != nil){ + err = ipifcremlifc(ifc, &ifc->lifc); /* * note: err non-zero means lifc not found, * which can't happen in this case. */ - if(err) + if(err != nil) error(err); } /* disassociate device */ - if(ifc->m && ifc->m->unbind) + if(ifc->m != nil && ifc->m->unbind != nil) (*ifc->m->unbind)(ifc); memset(ifc->dev, 0, sizeof(ifc->dev)); ifc->arg = nil; @@ -257,9 +300,9 @@ ipifclocal(Conv *c, char *state, int n) m = 0; rlock(ifc); - for(lifc = ifc->lifc; lifc; lifc = lifc->next){ + for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){ m += snprint(state+m, n - m, "%-40.40I ->", lifc->local); - for(link = lifc->link; link; link = link->lifclink) + for(link = lifc->link; link != nil; link = link->lifclink) m += snprint(state+m, n - m, " %-40.40I", link->self->a); m += snprint(state+m, n - m, "\n"); } @@ -299,7 +342,7 @@ ipifckick(void *x) runlock(ifc); nexterror(); } - if(ifc->m && ifc->m->pktin) + if(ifc->m != nil && ifc->m->pktin != nil) (*ifc->m->pktin)(c->p->f, ifc, bp); else freeb(bp); @@ -335,11 +378,9 @@ static void ipifcclose(Conv *c) { Ipifc *ifc; - Medium *m; ifc = (Ipifc*)c->ptcl; - m = ifc->m; - if(m && m->unbindonclose) + if(ifc->m != nil && ifc->m->unbindonclose) ipifcunbind(ifc); } @@ -366,13 +407,14 @@ ipifcsetmtu(Ipifc *ifc, char **argv, int argc) char* ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp) { - int i, type, mtu, sendnbrdisc = 0; uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen]; uchar bcast[IPaddrlen], net[IPaddrlen]; Iplifc *lifc, **l; + int i, type, mtu; + Medium *m; Fs *f; - if(ifc->m == nil) + if((m = ifc->m) == nil) return "ipifc not yet bound to device"; f = ifc->conv->p->f; @@ -388,7 +430,7 @@ ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp) /* fall through */ case 5: mtu = strtoul(argv[4], 0, 0); - if(mtu >= ifc->m->mintu && mtu <= ifc->m->maxtu) + if(mtu >= m->mintu && mtu <= m->maxtu) ifc->maxtu = mtu; /* fall through */ case 4: @@ -414,8 +456,16 @@ ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp) default: return Ebadarg; } - if(isv4(ip)) + + /* check for point-to-point interface */ + if(ipcmp(ip, v6loopback) != 0) /* skip v6 loopback, it's a special address */ + if(ipcmp(mask, IPallbits) == 0) + type |= Rptpt; + + if(isv4(ip) || ipcmp(ip, IPnoaddr) == 0){ + type |= Rv4; tentative = 0; + } wlock(ifc); if(waserror()){ @@ -424,19 +474,21 @@ ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp) } /* ignore if this is already a local address for this ifc */ - for(lifc = ifc->lifc; lifc; lifc = lifc->next) { - if(ipcmp(lifc->local, ip) == 0) { - if(lifc->tentative != tentative) - lifc->tentative = tentative; - if(lifcp) { - lifc->onlink = lifcp->onlink; - lifc->autoflag = lifcp->autoflag; - lifc->validlt = lifcp->validlt; - lifc->preflt = lifcp->preflt; - lifc->origint = lifcp->origint; - } - goto out; + if((lifc = iplocalonifc(ifc, ip)) != nil){ + if(lifcp != nil) { + lifc->onlink = lifcp->onlink; + lifc->autoflag = lifcp->autoflag; + lifc->validlt = lifcp->validlt; + lifc->preflt = lifcp->preflt; + lifc->origint = lifcp->origint; } + if(lifc->tentative != tentative){ + lifc->tentative = tentative; + goto done; + } + wunlock(ifc); + poperror(); + return nil; } /* add the address to the list of logical ifc's for this ifc */ @@ -445,8 +497,9 @@ ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp) ipmove(lifc->mask, mask); ipmove(lifc->remote, rem); ipmove(lifc->net, net); + lifc->type = type; lifc->tentative = tentative; - if(lifcp) { + if(lifcp != nil) { lifc->onlink = lifcp->onlink; lifc->autoflag = lifcp->autoflag; lifc->validlt = lifcp->validlt; @@ -459,29 +512,22 @@ ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp) } lifc->next = nil; - for(l = &ifc->lifc; *l; l = &(*l)->next) + for(l = &ifc->lifc; *l != nil; l = &(*l)->next) ; *l = lifc; - /* check for point-to-point interface */ - if(ipcmp(ip, v6loopback)) /* skip v6 loopback, it's a special address */ - if(ipcmp(mask, IPallbits) == 0) - type |= Rptpt; - - /* add local routes */ - if(isv4(ip)) - v4addroute(f, tifc, rem+IPv4off, mask+IPv4off, rem+IPv4off, type); - else - v6addroute(f, tifc, rem, mask, rem, type); + addroute(f, rem, mask, ip, defsmask(ip), rem, type, ifc, tifc); addselfcache(f, ifc, lifc, ip, Runi); - if((type & (Rproxy|Rptpt)) == (Rproxy|Rptpt)){ - ipifcregisterproxy(f, ifc, rem); - goto out; + /* register proxy */ + if(type & Rptpt){ + if(type & Rproxy) + ipifcregisterproxy(f, ifc, rem, 1); + goto done; } - if(isv4(ip) || ipcmp(ip, IPnoaddr) == 0) { + if(type & Rv4) { /* add subnet directed broadcast address to the self cache */ for(i = 0; i < IPaddrlen; i++) bcast[i] = (ip[i] & mask[i]) | ~mask[i]; @@ -505,45 +551,37 @@ ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp) addselfcache(f, ifc, lifc, bcast, Rbcast); addselfcache(f, ifc, lifc, IPv4bcast, Rbcast); - } - else { + } else { if(ipcmp(ip, v6loopback) == 0) { /* add node-local mcast address */ addselfcache(f, ifc, lifc, v6allnodesN, Rmulti); /* add route for all node multicast */ - v6addroute(f, tifc, v6allnodesN, v6allnodesNmask, - v6allnodesN, Rmulti); + addroute(f, v6allnodesN, v6allnodesNmask, + ip, IPallbits, + v6allnodesN, Rmulti, ifc, tifc); } /* add all nodes multicast address */ addselfcache(f, ifc, lifc, v6allnodesL, Rmulti); /* add route for all nodes multicast */ - v6addroute(f, tifc, v6allnodesL, v6allnodesLmask, v6allnodesL, - Rmulti); + addroute(f, v6allnodesL, v6allnodesLmask, + ip, IPallbits, + v6allnodesL, Rmulti, ifc, tifc); /* add solicited-node multicast address */ ipv62smcast(bcast, ip); addselfcache(f, ifc, lifc, bcast, Rmulti); - - sendnbrdisc = 1; } - /* register the address on this network for address resolution */ - if(isv4(ip) && ifc->m->areg) - (*ifc->m->areg)(ifc, ip); - -out: +done: wunlock(ifc); poperror(); - if(!isv4(ip) && ipcmp(ip, IPnoaddr) != 0){ - if(!tentative) - arpenter(f, V6, ip, ifc->mac, 6, 0); - else if(sendnbrdisc) - icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac); - } + /* register the address on this network for address resolution */ + if(m->areg != nil) + (*m->areg)(f, ifc, ip, ip); return nil; } @@ -553,41 +591,44 @@ out: * always called with ifc wlock'd */ static char* -ipifcremlifc(Ipifc *ifc, Iplifc *lifc) +ipifcremlifc(Ipifc *ifc, Iplifc **l) { - Iplifc **l; - Fs *f; + Iplifc *lifc = *l; + Fs *f = ifc->conv->p->f; - f = ifc->conv->p->f; - - /* - * find address on this interface and remove from chain. - * for pt to pt we actually specify the remote address as the - * addresss to remove. - */ - for(l = &ifc->lifc; *l != nil && *l != lifc; l = &(*l)->next) - ; - if(*l == nil) + if(lifc == nil) return "address not on this interface"; *l = lifc->next; /* disassociate any addresses */ - while(lifc->link) + while(lifc->link != nil) remselfcache(f, ifc, lifc, lifc->link->self->a); /* remove the route for this logical interface */ - if(isv4(lifc->local)) - v4delroute(f, lifc->remote+IPv4off, lifc->mask+IPv4off, 1); - else { - v6delroute(f, lifc->remote, lifc->mask, 1); + remroute(f, lifc->remote, lifc->mask, + lifc->local, defsmask(lifc->local), + lifc->remote, lifc->type, ifc, tifc); + + /* unregister proxy */ + if(lifc->type & Rptpt){ + if(lifc->type & Rproxy) + ipifcregisterproxy(f, ifc, lifc->remote, 0); + goto done; + } + + /* remove route for all nodes multicast */ + if((lifc->type & Rv4) == 0){ if(ipcmp(lifc->local, v6loopback) == 0) - /* remove route for all node multicast */ - v6delroute(f, v6allnodesN, v6allnodesNmask, 1); - else if(memcmp(lifc->local, v6linklocal, v6llpreflen) == 0) - /* remove route for all link multicast */ - v6delroute(f, v6allnodesL, v6allnodesLmask, 1); + remroute(f, v6allnodesN, v6allnodesNmask, + lifc->local, IPallbits, + v6allnodesN, Rmulti, ifc, tifc); + + remroute(f, v6allnodesL, v6allnodesLmask, + lifc->local, IPallbits, + v6allnodesL, Rmulti, ifc, tifc); } +done: free(lifc); return nil; } @@ -601,19 +642,17 @@ ipifcrem(Ipifc *ifc, char **argv, int argc) { char *rv; uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen]; - Iplifc *lifc; + Iplifc *lifc, **l; if(argc < 3) return Ebadarg; - - if (parseip(ip, argv[1]) == -1) + if(parseip(ip, argv[1]) == -1) return Ebadip; parseipmask(mask, argv[2]); if(argc < 4) maskip(ip, mask, rem); - else - if (parseip(rem, argv[3]) == -1) - return Ebadip; + else if(parseip(rem, argv[3]) == -1) + return Ebadip; /* * find address on this interface and remove from chain. @@ -621,62 +660,20 @@ ipifcrem(Ipifc *ifc, char **argv, int argc) * addresss to remove. */ wlock(ifc); + l = &ifc->lifc; for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next) { - if (memcmp(ip, lifc->local, IPaddrlen) == 0 - && memcmp(mask, lifc->mask, IPaddrlen) == 0 - && memcmp(rem, lifc->remote, IPaddrlen) == 0) + if(ipcmp(ip, lifc->local) == 0 + && ipcmp(mask, lifc->mask) == 0 + && ipcmp(rem, lifc->remote) == 0) break; + l = &lifc->next; } - rv = ipifcremlifc(ifc, lifc); + rv = ipifcremlifc(ifc, l); wunlock(ifc); return rv; } /* - * distribute routes to active interfaces like the - * TRIP linecards - */ -void -ipifcaddroute(Fs *f, int vers, uchar *addr, uchar *mask, uchar *gate, int type) -{ - Medium *m; - Conv **cp, **e; - Ipifc *ifc; - - e = &f->ipifc->conv[f->ipifc->nc]; - for(cp = f->ipifc->conv; cp < e; cp++){ - if(*cp != nil) { - ifc = (Ipifc*)(*cp)->ptcl; - m = ifc->m; - if(m && m->addroute) - (*m->addroute)(ifc, vers, addr, mask, gate, type); - } - } -} - -void -ipifcremroute(Fs *f, int vers, uchar *addr, uchar *mask) -{ - Medium *m; - Conv **cp, **e; - Ipifc *ifc; - - e = &f->ipifc->conv[f->ipifc->nc]; - for(cp = f->ipifc->conv; cp < e; cp++){ - if(*cp != nil) { - ifc = (Ipifc*)(*cp)->ptcl; - m = ifc->m; - if(m && m->remroute){ - if(!waserror()){ - (*m->remroute)(ifc, vers, addr, mask); - poperror(); - } - } - } - } -} - -/* * associate an address with the interface. This wipes out any previous * addresses. This is a macro that means, remove all the old interfaces * and add a new one. @@ -693,9 +690,9 @@ ipifcconnect(Conv* c, char **argv, int argc) return "ipifc not yet bound to device"; wlock(ifc); - while(ifc->lifc){ - err = ipifcremlifc(ifc, ifc->lifc); - if(err){ + while(ifc->lifc != nil){ + err = ipifcremlifc(ifc, &ifc->lifc); + if(err != nil){ wunlock(ifc); return err; } @@ -765,7 +762,7 @@ ipifcra6(Ipifc *ifc, char **argv, int argc) * called with c->car locked. */ static char* -ipifcctl(Conv* c, char**argv, int argc) +ipifcctl(Conv* c, char **argv, int argc) { Ipifc *ifc; int i; @@ -779,10 +776,6 @@ ipifcctl(Conv* c, char**argv, int argc) return ipifcrem(ifc, argv, argc); else if(strcmp(argv[0], "unbind") == 0) return ipifcunbind(ifc); - else if(strcmp(argv[0], "joinmulti") == 0) - return ipifcjoinmulti(ifc, argv, argc); - else if(strcmp(argv[0], "leavemulti") == 0) - return ipifcleavemulti(ifc, argv, argc); else if(strcmp(argv[0], "mtu") == 0) return ipifcsetmtu(ifc, argv, argc); else if(strcmp(argv[0], "reassemble") == 0){ @@ -845,10 +838,12 @@ ipifcinit(Fs *f) static void addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type) { - Ipself *p; Iplink *lp; + Ipself *p; int h; + type |= (lifc->type & Rv4); + qlock(f->self); if(waserror()){ qunlock(f->self); @@ -857,8 +852,8 @@ addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type) /* see if the address already exists */ h = hashipa(a); - for(p = f->self->hash[h]; p; p = p->next) - if(memcmp(a, p->a, IPaddrlen) == 0) + for(p = f->self->hash[h]; p != nil; p = p->next) + if(ipcmp(a, p->a) == 0) break; /* allocate a local address and add to hash chain */ @@ -875,7 +870,7 @@ addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type) } /* look for a link for this lifc */ - for(lp = p->link; lp; lp = lp->selflink) + for(lp = p->link; lp != nil; lp = lp->selflink) if(lp->lifc == lifc) break; @@ -891,13 +886,11 @@ addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type) lifc->link = lp; /* add to routing table */ - if(isv4(a)) - v4addroute(f, tifc, a+IPv4off, IPallbits+IPv4off, - a+IPv4off, type); - else - v6addroute(f, tifc, a, IPallbits, a, type); + addroute(f, a, IPallbits, + lifc->local, defsmask(a), + a, type, ifc, tifc); - if((type & Rmulti) && ifc->m->addmulti) + if((type & Rmulti) && ifc->m->addmulti != nil) (*ifc->m->addmulti)(ifc, a, lifc->local); } else lp->ref++; @@ -922,8 +915,8 @@ iplinkfree(Iplink *p) ulong now = NOW; l = &freeiplink; - for(np = *l; np; np = *l){ - if(np->expire > now){ + for(np = *l; np != nil; np = *l){ + if((long)(now - np->expire) >= 0){ *l = np->next; free(np); continue; @@ -942,8 +935,8 @@ ipselffree(Ipself *p) ulong now = NOW; l = &freeipself; - for(np = *l; np; np = *l){ - if(np->expire > now){ + for(np = *l; np != nil; np = *l){ + if((long)(now - np->expire) >= 0){ *l = np->next; free(np); continue; @@ -970,7 +963,7 @@ remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a) /* find the unique selftab entry */ l = &f->self->hash[hashipa(a)]; - for(p = *l; p; p = *l){ + for(p = *l; p != nil; p = *l){ if(ipcmp(p->a, a) == 0) break; l = &p->next; @@ -984,7 +977,7 @@ remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a) * that matches the selftab entry */ l_lifc = &lifc->link; - for(link = *l_lifc; link; link = *l_lifc){ + for(link = *l_lifc; link != nil; link = *l_lifc){ if(link->self == p) break; l_lifc = &link->lifclink; @@ -998,7 +991,7 @@ remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a) * the one we just found */ l_self = &p->link; - for(link = *l_self; link; link = *l_self){ + for(link = *l_self; link != nil; link = *l_self){ if(link == *l_lifc) break; l_self = &link->selflink; @@ -1010,7 +1003,12 @@ remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a) if(--(link->ref) != 0) goto out; - if((p->type & Rmulti) && ifc->m->remmulti){ + /* remove from routing table */ + remroute(f, a, IPallbits, + lifc->local, defsmask(a), + a, p->type, ifc, tifc); + + if((p->type & Rmulti) && ifc->m->remmulti != nil){ if(!waserror()){ (*ifc->m->remmulti)(ifc, a, lifc->local); poperror(); @@ -1025,30 +1023,18 @@ remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a) if(p->link != nil) goto out; - /* remove from routing table */ - if(isv4(a)) - v4delroute(f, a+IPv4off, IPallbits+IPv4off, 1); - else - v6delroute(f, a, IPallbits, 1); + /* if null address, forget */ + if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0) + f->self->acceptall = 0; /* no more links, remove from hash and free */ *l = p->next; ipselffree(p); - /* if IPnoaddr, forget */ - if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0) - f->self->acceptall = 0; - out: qunlock(f->self); } -static char *stformat = "%-44.44I %2.2d %4.4s\n"; -enum -{ - Nstformat= 41, -}; - long ipselftabread(Fs *f, char *cp, ulong offset, int n) { @@ -1063,10 +1049,11 @@ ipselftabread(Fs *f, char *cp, ulong offset, int n) for(i = 0; i < NHASH && m < n; i++){ for(p = f->self->hash[i]; p != nil && m < n; p = p->next){ nifc = 0; - for(link = p->link; link; link = link->selflink) + for(link = p->link; link != nil; link = link->selflink) nifc++; routetype(p->type, state); - m += snprint(cp + m, n - m, stformat, p->a, nifc, state); + m += snprint(cp + m, n - m, "%-44.44I %2.2d %4.4s\n", + p->a, nifc, state); if(off > 0){ off -= m; m = 0; @@ -1082,11 +1069,10 @@ iptentative(Fs *f, uchar *addr) { Ipself *p; - p = f->self->hash[hashipa(addr)]; - for(; p; p = p->next){ + for(p = f->self->hash[hashipa(addr)]; p != nil; p = p->next) if(ipcmp(addr, p->a) == 0) return p->link->lifc->tentative; - } + return 0; } @@ -1102,15 +1088,14 @@ ipforme(Fs *f, uchar *addr) { Ipself *p; - p = f->self->hash[hashipa(addr)]; - for(; p; p = p->next){ + for(p = f->self->hash[hashipa(addr)]; p != nil; p = p->next) if(ipcmp(addr, p->a) == 0) - return p->type; - } + return p->type & (Runi|Rbcast|Rmulti); /* hack to say accept anything */ if(f->self->acceptall) return Runi; + return 0; } @@ -1119,70 +1104,64 @@ ipforme(Fs *f, uchar *addr) * return nil. */ Ipifc* -findipifc(Fs *f, uchar *remote, int type) +findipifc(Fs *f, uchar *local, uchar *remote, int type) { + uchar gnet[IPaddrlen]; Ipifc *ifc, *x; Iplifc *lifc; Conv **cp, **e; - uchar gnet[IPaddrlen], xmask[IPaddrlen]; + int spec, xspec; x = nil; - memset(xmask, 0, IPaddrlen); + xspec = 0; /* find most specific match */ e = &f->ipifc->conv[f->ipifc->nc]; for(cp = f->ipifc->conv; cp < e; cp++){ - if(*cp == 0) + if(*cp == nil) continue; ifc = (Ipifc*)(*cp)->ptcl; - for(lifc = ifc->lifc; lifc; lifc = lifc->next){ + for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){ + if(type & Runi){ + if(ipcmp(remote, lifc->local) == 0) + return ifc; + } else if(type & (Rbcast|Rmulti)) { + if(ipcmp(local, lifc->local) == 0) + return ifc; + } maskip(remote, lifc->mask, gnet); if(ipcmp(gnet, lifc->net) == 0){ - if(x == nil || ipcmp(lifc->mask, xmask) > 0){ + spec = comprefixlen(remote, lifc->local, IPaddrlen); + if(spec > xspec){ x = ifc; - ipmove(xmask, lifc->mask); + xspec = spec; } } } } - if(x != nil) - return x; - - /* for now for broadcast and multicast, just use first interface */ - if(type & (Rbcast|Rmulti)){ - for(cp = f->ipifc->conv; cp < e; cp++){ - if(*cp == 0) - continue; - ifc = (Ipifc*)(*cp)->ptcl; - if(ifc->lifc != nil) - return ifc; - } - } - return nil; + return x; } -enum { - unknownv6, /* UGH */ - unspecifiedv6, - linklocalv6, - globalv6, -}; - -int -v6addrtype(uchar *addr) +Ipifc* +findipifcstr(Fs *f, char *s) { - if(isv4(addr) || ipcmp(addr, IPnoaddr) == 0) - return unknownv6; - else if(islinklocal(addr) || - isv6mcast(addr) && (addr[1] & 0xF) <= Link_local_scop) - return linklocalv6; - else - return globalv6; + uchar ip[IPaddrlen]; + Conv *c; + char *p; + long x; + + x = strtol(s, &p, 10); + if(p > s && *p == '\0'){ + if(x < 0) + return nil; + if(x < f->ipifc->nc && (c = f->ipifc->conv[x]) != nil) + return (Ipifc*)c->ptcl; + } + if(parseip(ip, s) != -1) + return findipifc(f, IPnoaddr, ip, Runi); + return nil; } -#define v6addrcurr(lifc) ((lifc)->preflt == ~0L || \ - (lifc)->origint + (lifc)->preflt >= NOW/1000) - static void findprimaryipv6(Fs *f, uchar *local) { @@ -1200,10 +1179,10 @@ findprimaryipv6(Fs *f, uchar *local) */ e = &f->ipifc->conv[f->ipifc->nc]; for(cp = f->ipifc->conv; cp < e; cp++){ - if(*cp == 0) + if(*cp == nil) continue; ifc = (Ipifc*)(*cp)->ptcl; - for(lifc = ifc->lifc; lifc; lifc = lifc->next){ + for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){ atypel = v6addrtype(lifc->local); if(atypel > atype && v6addrcurr(lifc)) { ipmove(local, lifc->local); @@ -1216,7 +1195,7 @@ findprimaryipv6(Fs *f, uchar *local) } /* - * returns first ip address configured + * returns first v4 address configured */ static void findprimaryipv4(Fs *f, uchar *local) @@ -1228,10 +1207,10 @@ findprimaryipv4(Fs *f, uchar *local) /* find first ifc local address */ e = &f->ipifc->conv[f->ipifc->nc]; for(cp = f->ipifc->conv; cp < e; cp++){ - if(*cp == 0) + if(*cp == nil) continue; ifc = (Ipifc*)(*cp)->ptcl; - if((lifc = ifc->lifc) != nil){ + if((lifc = ifc->lifc) != nil && (lifc->type & Rv4) != 0){ ipmove(local, lifc->local); return; } @@ -1239,21 +1218,6 @@ findprimaryipv4(Fs *f, uchar *local) ipmove(local, IPnoaddr); } -static int -comprefixlen(uchar *a, uchar *b, int n) -{ - int i, c; - - for(i = 0; i < n; i++){ - if((c = a[i] ^ b[i]) == 0) - continue; - for(i <<= 3; (c & 0x80) == 0; i++) - c <<= 1; - return i; - } - return i << 3; -} - /* * return v4 address associated with an interface close to remote */ @@ -1265,7 +1229,7 @@ ipv4local(Ipifc *ifc, uchar *local, uchar *remote) b = -1; for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){ - if(!isv4(lifc->local)) + if((lifc->type & Rv4) == 0) continue; a = comprefixlen(lifc->local+IPv4off, remote, IPv4addrlen); if(a > b){ @@ -1337,27 +1301,38 @@ ipv6local(Ipifc *ifc, uchar *local, uchar *remote) return b.atype >= atype; } -/* - * find the local address 'closest' to the remote system, copy it to local - */ void findlocalip(Fs *f, uchar *local, uchar *remote) { Route *r; + Ipifc *ifc; + Iplifc *lifc; + Conv **cp, **e; qlock(f->ipifc); - if((r = v6lookup(f, remote, nil)) != nil){ - if(r->type & Runi){ - ipmove(local, remote); - goto out; - } - if((r->type & (Rifc|Rbcast|Rmulti|Rv4)) == Rv4){ - ipmove(local, v4prefix); - if(ipv4local(r->ifc, local+IPv4off, r->v4.gate)) + e = &f->ipifc->conv[f->ipifc->nc]; + for(cp = f->ipifc->conv; cp < e; cp++){ + if(*cp == nil) + continue; + ifc = (Ipifc*)(*cp)->ptcl; + for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){ + if(lifc->tentative) + continue; + r = v6lookup(f, remote, lifc->local, nil); + if(r == nil || (ifc = r->ifc) == nil) + continue; + if(r->type & Runi){ + ipmove(local, remote); + goto out; + } + if((r->type & (Rifc|Rbcast|Rmulti|Rv4)) == Rv4){ + ipmove(local, v4prefix); + if(ipv4local(ifc, local+IPv4off, r->v4.gate)) + goto out; + } + if(ipv6local(ifc, local, remote)) goto out; } - if(ipv6local(r->ifc, local, remote)) - goto out; } if(isv4(remote)) findprimaryipv4(f, local); @@ -1367,6 +1342,7 @@ out: qunlock(f->ipifc); } + /* * see if this address is bound to the interface */ @@ -1375,9 +1351,24 @@ iplocalonifc(Ipifc *ifc, uchar *ip) { Iplifc *lifc; - for(lifc = ifc->lifc; lifc; lifc = lifc->next) + for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next) if(ipcmp(ip, lifc->local) == 0) return lifc; + + return nil; +} + +Iplifc* +ipremoteonifc(Ipifc *ifc, uchar *ip) +{ + uchar net[IPaddrlen]; + Iplifc *lifc; + + for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){ + maskip(ip, lifc->mask, net); + if(ipcmp(net, lifc->remote) == 0) + return lifc; + } return nil; } @@ -1389,21 +1380,13 @@ int ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip) { Route *r; - uchar net[IPaddrlen]; - Iplifc *lifc; /* see if this is a direct connected pt to pt address */ - r = v6lookup(f, ip, nil); + r = v6lookup(f, ip, ip, nil); if(r == nil || (r->type & (Rifc|Rproxy)) != (Rifc|Rproxy)) return 0; - /* see if this is on the right interface */ - for(lifc = ifc->lifc; lifc; lifc = lifc->next){ - maskip(ip, lifc->mask, net); - if(ipcmp(net, lifc->remote) == 0) - return 1; - } - return 0; + return ipremoteonifc(ifc, ip) != nil; } /* @@ -1441,15 +1424,15 @@ ipisbm(uchar *ip) void ipifcaddmulti(Conv *c, uchar *ma, uchar *ia) { - Ipifc *ifc; - Iplifc *lifc; - Conv **p; Ipmulti *multi, **l; + Conv **cp, **e; + Iplifc *lifc; + Ipifc *ifc; Fs *f; f = c->p->f; - for(l = &c->multi; *l; l = &(*l)->next) + for(l = &c->multi; *l != nil; l = &(*l)->next) if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0) return; /* it's already there */ @@ -1458,18 +1441,18 @@ ipifcaddmulti(Conv *c, uchar *ma, uchar *ia) ipmove(multi->ia, ia); multi->next = nil; - for(p = f->ipifc->conv; *p; p++){ - if((*p)->inuse == 0) + e = &f->ipifc->conv[f->ipifc->nc]; + for(cp = f->ipifc->conv; cp < e; cp++){ + if((*cp) == nil || (*cp)->inuse == 0) continue; - ifc = (Ipifc*)(*p)->ptcl; + ifc = (Ipifc*)(*cp)->ptcl; wlock(ifc); if(waserror()){ wunlock(ifc); nexterror(); } - for(lifc = ifc->lifc; lifc; lifc = lifc->next) - if(ipcmp(ia, lifc->local) == 0) - addselfcache(f, ifc, lifc, ma, Rmulti); + if((lifc = iplocalonifc(ifc, ia)) != nil) + addselfcache(f, ifc, lifc, ma, Rmulti); wunlock(ifc); poperror(); } @@ -1483,14 +1466,14 @@ void ipifcremmulti(Conv *c, uchar *ma, uchar *ia) { Ipmulti *multi, **l; + Conv **cp, **e; Iplifc *lifc; - Conv **p; Ipifc *ifc; Fs *f; f = c->p->f; - for(l = &c->multi; *l; l = &(*l)->next) + for(l = &c->multi; *l != nil; l = &(*l)->next) if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0) break; @@ -1500,102 +1483,62 @@ ipifcremmulti(Conv *c, uchar *ma, uchar *ia) *l = multi->next; - for(p = f->ipifc->conv; *p; p++){ - if((*p)->inuse == 0) + e = &f->ipifc->conv[f->ipifc->nc]; + for(cp = f->ipifc->conv; cp < e; cp++){ + if((*cp) == nil || (*cp)->inuse == 0) continue; - - ifc = (Ipifc*)(*p)->ptcl; + ifc = (Ipifc*)(*cp)->ptcl; wlock(ifc); - for(lifc = ifc->lifc; lifc; lifc = lifc->next) - if(ipcmp(ia, lifc->local) == 0) - remselfcache(f, ifc, lifc, ma); + if(waserror()){ + wunlock(ifc); + nexterror(); + } + if((lifc = iplocalonifc(ifc, ia)) != nil) + remselfcache(f, ifc, lifc, ma); wunlock(ifc); + poperror(); } free(multi); } -/* - * make lifc's join and leave multicast groups - */ -static char* -ipifcjoinmulti(Ipifc *ifc, char **argv, int argc) -{ - USED(ifc, argv, argc); - return nil; -} - -static char* -ipifcleavemulti(Ipifc *ifc, char **argv, int argc) -{ - USED(ifc, argv, argc); - return nil; -} - static void -ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip) +ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip, int add) { + uchar proxy[IPaddrlen]; Conv **cp, **e; - Ipifc *nifc; Iplifc *lifc; + Ipifc *nifc; Medium *m; - uchar net[IPaddrlen]; - /* register the address on any network that will proxy for us */ + /* register the address on any interface that will proxy for the ip */ e = &f->ipifc->conv[f->ipifc->nc]; + for(cp = f->ipifc->conv; cp < e; cp++){ + if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc) + continue; - if(!isv4(ip)) { /* V6 */ - for(cp = f->ipifc->conv; cp < e; cp++){ - if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc) - continue; - rlock(nifc); - m = nifc->m; - if(m == nil || m->addmulti == nil) { - runlock(nifc); - continue; - } - if(waserror()){ - runlock(nifc); - nexterror(); - } - for(lifc = nifc->lifc; lifc; lifc = lifc->next){ - maskip(ip, lifc->mask, net); - if(ipcmp(net, lifc->remote) == 0) { - /* add solicited-node multicast addr */ - ipv62smcast(net, ip); - addselfcache(f, nifc, lifc, net, Rmulti); - arpenter(f, V6, ip, nifc->mac, 6, 0); - break; - } - } - runlock(nifc); - poperror(); + wlock(nifc); + m = nifc->m; + if(m == nil || m->areg == nil || waserror()){ + wunlock(nifc); + continue; } - } - else { /* V4 */ - for(cp = f->ipifc->conv; cp < e; cp++){ - if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc) - continue; - rlock(nifc); - m = nifc->m; - if(m == nil || m->areg == nil){ - runlock(nifc); - continue; - } - if(waserror()){ - runlock(nifc); - nexterror(); - } - for(lifc = nifc->lifc; lifc; lifc = lifc->next){ - maskip(ip, lifc->mask, net); - if(ipcmp(net, lifc->remote) == 0){ - (*m->areg)(nifc, ip); - break; - } + if((lifc = ipremoteonifc(nifc, ip)) != nil){ + if((lifc->type & Rv4) == 0){ + /* add solicited-node multicast addr */ + ipv62smcast(proxy, ip); + if(add) + addselfcache(f, nifc, lifc, proxy, Rmulti); + else + remselfcache(f, nifc, lifc, proxy); } - runlock(nifc); - poperror(); + ipmove(proxy, lifc->local); } + wunlock(nifc); + poperror(); + + if(add && lifc != nil) + (*m->areg)(f, nifc, ip, proxy); } } diff --git a/sys/src/9/ip/iproute.c b/sys/src/9/ip/iproute.c index f6a4be7f1..ef59b2f5f 100644 --- a/sys/src/9/ip/iproute.c +++ b/sys/src/9/ip/iproute.c @@ -35,9 +35,8 @@ freeroute(Route *r) static Route* allocroute(int type) { - Route *r; + Route *r, **l; int n; - Route **l; if(type & Rv4){ n = sizeof(RouteTree) + sizeof(V4route); @@ -72,9 +71,9 @@ addqueue(Route **q, Route *r) return; l = allocroute(r->type); + l->left = r; l->mid = *q; *q = l; - l->left = r; } /* @@ -99,11 +98,11 @@ lcmp(ulong *a, ulong *b) */ enum { - Rpreceeds, - Rfollows, - Requals, - Rcontains, - Rcontained, + Rpreceeds, /* a left of b */ + Rfollows, /* a right of b */ + Requals, /* a equals b */ + Rcontains, /* a contians b */ + Roverlaps, /* a overlaps b */ }; static int @@ -112,44 +111,87 @@ rangecompare(Route *a, Route *b) if(a->type & Rv4){ if(a->v4.endaddress < b->v4.address) return Rpreceeds; - if(a->v4.address > b->v4.endaddress) return Rfollows; - if(a->v4.address <= b->v4.address && a->v4.endaddress >= b->v4.endaddress){ if(a->v4.address == b->v4.address - && a->v4.endaddress == b->v4.endaddress) - return Requals; + && a->v4.endaddress == b->v4.endaddress){ + if(a->v4.source <= b->v4.source + && a->v4.endsource >= b->v4.endsource){ + if(a->v4.source == b->v4.source + && a->v4.endsource == b->v4.endsource) + return Requals; + return Rcontains; + } + return Roverlaps; + } return Rcontains; } - return Rcontained; + return Roverlaps; } if(lcmp(a->v6.endaddress, b->v6.address) < 0) return Rpreceeds; - if(lcmp(a->v6.address, b->v6.endaddress) > 0) return Rfollows; - if(lcmp(a->v6.address, b->v6.address) <= 0 && lcmp(a->v6.endaddress, b->v6.endaddress) >= 0){ if(lcmp(a->v6.address, b->v6.address) == 0 - && lcmp(a->v6.endaddress, b->v6.endaddress) == 0) - return Requals; + && lcmp(a->v6.endaddress, b->v6.endaddress) == 0){ + if(lcmp(a->v6.source, b->v6.source) <= 0 + && lcmp(a->v6.endsource, b->v6.endsource) >= 0){ + if(lcmp(a->v6.source, b->v6.source) == 0 + && lcmp(a->v6.endsource, b->v6.endsource) == 0) + return Requals; + return Rcontains; + } + return Roverlaps; + } return Rcontains; } + return Roverlaps; +} + +/* return 1 if a matches b, otherwise 0 */ +static int +matchroute(Route *a, Route *b) +{ + if(a == b) + return 1; + + if((a->type^b->type) & (Rifc|Runi|Rmulti|Rbcast)) + return 0; + + if(a->type & Rv4){ + if(memcmp(a->v4.gate, IPnoaddr+IPv4off, IPv4addrlen) != 0 + && memcmp(a->v4.gate, b->v4.gate, IPv4addrlen) != 0) + return 0; + } else { + if(ipcmp(a->v6.gate, IPnoaddr) != 0 + && ipcmp(a->v6.gate, b->v6.gate) != 0) + return 0; + } + + if(a->ifc != nil && b->ifc != nil && (a->ifc != b->ifc || a->ifcid != b->ifcid)) + return 0; - return Rcontained; + if(*a->tag != 0 && strncmp(a->tag, b->tag, sizeof(a->tag)) != 0) + return 0; + + return 1; } static void copygate(Route *old, Route *new) { + old->type = new->type; + old->ifc = new->ifc; + old->ifcid = new->ifcid; if(new->type & Rv4) memmove(old->v4.gate, new->v4.gate, IPv4addrlen); else - memmove(old->v6.gate, new->v6.gate, IPaddrlen); + ipmove(old->v6.gate, new->v6.gate); } /* @@ -162,12 +204,12 @@ walkadd(Fs *f, Route **root, Route *p) l = p->left; r = p->right; - p->left = 0; - p->right = 0; + p->left = nil; + p->right = nil; addnode(f, root, p); - if(l) + if(l != nil) walkadd(f, root, l); - if(r) + if(r != nil) walkadd(f, root, r); } @@ -180,16 +222,16 @@ calcd(Route *p) Route *q; int d; - if(p) { + if(p != nil) { d = 0; q = p->left; - if(q) + if(q != nil) d = q->depth; q = p->right; - if(q && q->depth > d) + if(q != nil && q->depth > d) d = q->depth; q = p->mid; - if(q && q->depth > d) + if(q != nil && q->depth > d) d = q->depth; p->depth = d+1; } @@ -210,8 +252,8 @@ balancetree(Route **cur) * rotate tree node */ p = *cur; - dl = 0; if(l = p->left) dl = l->depth; - dr = 0; if(r = p->right) dr = r->depth; + dl = 0; if((l = p->left) != nil) dl = l->depth; + dr = 0; if((r = p->right) != nil) dr = r->depth; if(dl > dr+1) { p->left = l->right; @@ -239,7 +281,7 @@ addnode(Fs *f, Route **cur, Route *new) Route *p; p = *cur; - if(p == 0) { + if(p == nil) { *cur = new; new->depth = 1; return; @@ -269,15 +311,13 @@ addnode(Fs *f, Route **cur, Route *new) * supercede the old entry if the old one isn't * a local interface. */ - if((p->type & Rifc) == 0){ - p->type = new->type; - p->ifcid = -1; + if((p->type & Rifc) == 0) copygate(p, new); - } else if(new->type & Rifc) + else if(new->type & Rifc) p->ref++; freeroute(new); break; - case Rcontained: + case Roverlaps: addnode(f, &p->mid, new); break; } @@ -285,225 +325,259 @@ addnode(Fs *f, Route **cur, Route *new) balancetree(cur); } -#define V4H(a) ((a&0x07ffffff)>>(32-Lroot-5)) - -void -v4addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type) +/* + * find node matching r + */ +static Route** +looknode(Route **cur, Route *r) { Route *p; - ulong sa; - ulong m; - ulong ea; - int h, eh; - - m = nhgetl(mask); - sa = nhgetl(a) & m; - ea = sa | ~m; - - eh = V4H(ea); - for(h=V4H(sa); h<=eh; h++) { - p = allocroute(Rv4 | type); - p->v4.address = sa; - p->v4.endaddress = ea; - memmove(p->v4.gate, gate, sizeof(p->v4.gate)); - memmove(p->tag, tag, sizeof(p->tag)); - wlock(&routelock); - addnode(f, &f->v4root[h], p); - while(p = f->queue) { - f->queue = p->mid; - walkadd(f, &f->v4root[h], p->left); - freeroute(p); + for(;;){ + p = *cur; + if(p == nil) + return nil; + switch(rangecompare(r, p)){ + case Rcontains: + return nil; + case Rpreceeds: + cur = &p->left; + break; + case Rfollows: + cur = &p->right; + break; + case Roverlaps: + cur = &p->mid; + break; + case Requals: + if((p->type & Rifc) == 0 && !matchroute(r, p)) + return nil; + return cur; } - wunlock(&routelock); } - v4routegeneration++; +} - ipifcaddroute(f, Rv4, a, mask, gate, type); +static Route* +looknodetag(Route *r, char *tag) +{ + Route *x; + + if(r == nil) + return nil; + + if((x = looknodetag(r->mid, tag)) != nil) + return x; + if((x = looknodetag(r->left, tag)) != nil) + return x; + if((x = looknodetag(r->right, tag)) != nil) + return x; + + if((r->type & Rifc) == 0){ + if(tag == nil || strncmp(tag, r->tag, sizeof(r->tag)) == 0) + return r; + } + + return nil; } -#define V6H(a) (((a)[IPllen-1] & 0x07ffffff)>>(32-Lroot-5)) +#define V4H(a) ((a&0x07ffffff)>>(32-Lroot-5)) +#define V6H(a) (((a)[IPllen-1]&0x07ffffff)>>(32-Lroot-5)) -void -v6addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type) +static void +routeadd(Fs *f, Route *r) { - Route *p; - ulong sa[IPllen], ea[IPllen]; - ulong x, y; - int h, eh; + Route **h, **e, *p; - for(h = 0; h < IPllen; h++){ - x = nhgetl(a+4*h); - y = nhgetl(mask+4*h); - sa[h] = x & y; - ea[h] = x | ~y; + if(r->type & Rv4){ + h = &f->v4root[V4H(r->v4.address)]; + e = &f->v4root[V4H(r->v4.endaddress)]; + } else { + h = &f->v6root[V6H(r->v6.address)]; + e = &f->v6root[V6H(r->v6.endaddress)]; } - eh = V6H(ea); - for(h = V6H(sa); h <= eh; h++) { - p = allocroute(type); - memmove(p->v6.address, sa, IPaddrlen); - memmove(p->v6.endaddress, ea, IPaddrlen); - memmove(p->v6.gate, gate, IPaddrlen); - memmove(p->tag, tag, sizeof(p->tag)); + for(; h <= e; h++) { + p = allocroute(r->type); - wlock(&routelock); - addnode(f, &f->v6root[h], p); - while(p = f->queue) { + p->ifc = r->ifc; + p->ifcid = r->ifcid; + + if(r->type & Rv4) + memmove(&p->v4, &r->v4, sizeof(r->v4)); + else + memmove(&p->v6, &r->v6, sizeof(r->v6)); + + memmove(p->tag, r->tag, sizeof(r->tag)); + + addnode(f, h, p); + while((p = f->queue) != nil) { f->queue = p->mid; - walkadd(f, &f->v6root[h], p->left); + walkadd(f, h, p->left); freeroute(p); } - wunlock(&routelock); } - v6routegeneration++; - ipifcaddroute(f, 0, a, mask, gate, type); + if(r->type & Rv4) + v4routegeneration++; + else + v6routegeneration++; } -Route** -looknode(Route **cur, Route *r) +static void +routerem(Fs *f, Route *r) { - Route *p; + Route **h, **e, **l, *p; - for(;;){ - p = *cur; - if(p == 0) - return 0; - - switch(rangecompare(r, p)){ - case Rcontains: - return 0; - case Rpreceeds: - cur = &p->left; - break; - case Rfollows: - cur = &p->right; - break; - case Rcontained: - cur = &p->mid; - break; - case Requals: - return cur; - } + if(r->type & Rv4){ + h = &f->v4root[V4H(r->v4.address)]; + e = &f->v4root[V4H(r->v4.endaddress)]; + } else { + h = &f->v6root[V6H(r->v6.address)]; + e = &f->v6root[V6H(r->v6.endaddress)]; } -} -void -v4delroute(Fs *f, uchar *a, uchar *mask, int dolock) -{ - Route **r, *p; - Route rt; - int h, eh; - ulong m; - - m = nhgetl(mask); - rt.v4.address = nhgetl(a) & m; - rt.v4.endaddress = rt.v4.address | ~m; - rt.type = Rv4; - - eh = V4H(rt.v4.endaddress); - for(h=V4H(rt.v4.address); h<=eh; h++) { - if(dolock) - wlock(&routelock); - r = looknode(&f->v4root[h], &rt); - if(r) { - p = *r; - if(--(p->ref) == 0){ - *r = 0; - addqueue(&f->queue, p->left); - addqueue(&f->queue, p->mid); - addqueue(&f->queue, p->right); - freeroute(p); - while(p = f->queue) { - f->queue = p->mid; - walkadd(f, &f->v4root[h], p->left); - freeroute(p); - } - } + for(; h <= e; h++) { + if((l = looknode(h, r)) == nil) + continue; + p = *l; + if(--(p->ref) != 0) + continue; + *l = nil; + addqueue(&f->queue, p->left); + addqueue(&f->queue, p->mid); + addqueue(&f->queue, p->right); + freeroute(p); + + while((p = f->queue) != nil) { + f->queue = p->mid; + walkadd(f, h, p->left); + freeroute(p); } - if(dolock) - wunlock(&routelock); } - v4routegeneration++; - ipifcremroute(f, Rv4, a, mask); + if(r->type & Rv4) + v4routegeneration++; + else + v6routegeneration++; } -void -v6delroute(Fs *f, uchar *a, uchar *mask, int dolock) +static Route +mkroute(uchar *a, uchar *mask, uchar *s, uchar *smask, uchar *gate, int type, Ipifc *ifc, char *tag) { - Route **r, *p; - Route rt; - int h, eh; ulong x, y; + Route r; + int h; - for(h = 0; h < IPllen; h++){ - x = nhgetl(a+4*h); - y = nhgetl(mask+4*h); - rt.v6.address[h] = x & y; - rt.v6.endaddress[h] = x | ~y; - } - rt.type = 0; - - eh = V6H(rt.v6.endaddress); - for(h=V6H(rt.v6.address); h<=eh; h++) { - if(dolock) - wlock(&routelock); - r = looknode(&f->v6root[h], &rt); - if(r) { - p = *r; - if(--(p->ref) == 0){ - *r = 0; - addqueue(&f->queue, p->left); - addqueue(&f->queue, p->mid); - addqueue(&f->queue, p->right); - freeroute(p); - while(p = f->queue) { - f->queue = p->mid; - walkadd(f, &f->v6root[h], p->left); - freeroute(p); - } - } + memset(&r, 0, sizeof(r)); + + r.type = type; + + if(type & Rv4){ + x = nhgetl(a+IPv4off); + y = nhgetl(mask+IPv4off); + r.v4.address = x & y; + r.v4.endaddress = x | ~y; + + x = nhgetl(s+IPv4off); + y = nhgetl(smask+IPv4off); + if(y != 0) + r.type |= Rsrc; + r.v4.source = x & y; + r.v4.endsource = x | ~y; + + memmove(r.v4.gate, gate+IPv4off, IPv4addrlen); + } else { + for(h = 0; h < IPllen; h++){ + x = nhgetl(a+4*h); + y = nhgetl(mask+4*h); + r.v6.address[h] = x & y; + r.v6.endaddress[h] = x | ~y; + + x = nhgetl(s+4*h); + y = nhgetl(smask+4*h); + if(y != 0) + r.type |= Rsrc; + r.v6.source[h] = x & y; + r.v6.endsource[h] = x | ~y; } - if(dolock) - wunlock(&routelock); + + memmove(r.v6.gate, gate, IPaddrlen); } - v6routegeneration++; - ipifcremroute(f, 0, a, mask); + if(ifc != nil){ + r.ifc = ifc; + r.ifcid = ifc->ifcid; + } + + if(tag != nil) + strncpy(r.tag, tag, sizeof(r.tag)); + + return r; +} + +void +addroute(Fs *f, uchar *a, uchar *mask, uchar *s, uchar *smask, uchar *gate, int type, Ipifc *ifc, char *tag) +{ + Route r = mkroute(a, mask, s, smask, gate, type, ifc, tag); + wlock(&routelock); + routeadd(f, &r); + wunlock(&routelock); +} + +void +remroute(Fs *f, uchar *a, uchar *mask, uchar *s, uchar *smask, uchar *gate, int type, Ipifc *ifc, char *tag) +{ + Route r = mkroute(a, mask, s, smask, gate, type, ifc, tag); + wlock(&routelock); + routerem(f, &r); + wunlock(&routelock); } Route* -v4lookup(Fs *f, uchar *a, Routehint *rh) +v4lookup(Fs *f, uchar *a, uchar *s, Routehint *rh) { + uchar local[IPaddrlen], gate[IPaddrlen]; + ulong la, ls; Route *p, *q; - ulong la; - uchar gate[IPaddrlen]; Ipifc *ifc; if(rh != nil && rh->r != nil && rh->r->ifc != nil && rh->rgen == v4routegeneration) return rh->r; la = nhgetl(a); + ls = nhgetl(s); q = nil; - for(p=f->v4root[V4H(la)]; p;) - if(la >= p->v4.address) { - if(la <= p->v4.endaddress) { - q = p; - p = p->mid; - } else - p = p->right; - } else + for(p = f->v4root[V4H(la)]; p != nil;){ + if(la < p->v4.address){ p = p->left; + continue; + } + if(la > p->v4.endaddress){ + p = p->right; + continue; + } + if(p->type & Rsrc){ + if(ls < p->v4.source){ + p = p->mid; + continue; + } + if(ls > p->v4.endsource){ + p = p->mid; + continue; + } + } + q = p; + p = p->mid; + } - if(q && (q->ifc == nil || q->ifcid != q->ifc->ifcid)){ + if(q != nil && (q->ifc == nil || q->ifcid != q->ifc->ifcid)){ if(q->type & Rifc) { hnputl(gate+IPv4off, q->v4.address); memmove(gate, v4prefix, IPv4off); } else v4tov6(gate, q->v4.gate); - ifc = findipifc(f, gate, q->type); + v4tov6(local, s); + ifc = findipifc(f, local, gate, q->type); if(ifc == nil) return nil; q->ifc = ifc; @@ -519,29 +593,30 @@ v4lookup(Fs *f, uchar *a, Routehint *rh) } Route* -v6lookup(Fs *f, uchar *a, Routehint *rh) +v6lookup(Fs *f, uchar *a, uchar *s, Routehint *rh) { - Route *p, *q; - ulong la[IPllen]; - int h; - ulong x, y; uchar gate[IPaddrlen]; + ulong la[IPllen], ls[IPllen]; + ulong x, y; + Route *p, *q; Ipifc *ifc; + int h; - if(memcmp(a, v4prefix, IPv4off) == 0){ - q = v4lookup(f, a+IPv4off, rh); - if(q != nil) - return q; - } + if(isv4(a) && isv4(s)) + return v4lookup(f, a+IPv4off, s+IPv4off, rh); + if(isv4(s)) + return nil; if(rh != nil && rh->r != nil && rh->r->ifc != nil && rh->rgen == v6routegeneration) return rh->r; - for(h = 0; h < IPllen; h++) + for(h = 0; h < IPllen; h++){ la[h] = nhgetl(a+4*h); + ls[h] = nhgetl(s+4*h); + } q = nil; - for(p=f->v6root[V6H(la)]; p;){ + for(p = f->v6root[V6H(la)]; p != nil;){ for(h = 0; h < IPllen; h++){ x = la[h]; y = p->v6.address[h]; @@ -564,18 +639,42 @@ v6lookup(Fs *f, uchar *a, Routehint *rh) } break; } + if(p->type & Rsrc){ + for(h = 0; h < IPllen; h++){ + x = ls[h]; + y = p->v6.source[h]; + if(x == y) + continue; + if(x < y){ + p = p->mid; + goto next; + } + break; + } + for(h = 0; h < IPllen; h++){ + x = ls[h]; + y = p->v6.endsource[h]; + if(x == y) + continue; + if(x > y){ + p = p->mid; + goto next; + } + break; + } + } q = p; p = p->mid; next: ; } - if(q && (q->ifc == nil || q->ifcid != q->ifc->ifcid)){ + if(q != nil && (q->ifc == nil || q->ifcid != q->ifc->ifcid)){ if(q->type & Rifc) { for(h = 0; h < IPllen; h++) hnputl(gate+4*h, q->v6.address[h]); - ifc = findipifc(f, gate, q->type); + ifc = findipifc(f, s, gate, q->type); } else - ifc = findipifc(f, q->v6.gate, q->type); + ifc = findipifc(f, s, q->v6.gate, q->type); if(ifc == nil) return nil; q->ifc = ifc; @@ -590,201 +689,266 @@ next: ; return q; } +static int +parseroutetype(char *p) +{ + int type = 0; + switch(*p++){ + default: return -1; + case '4': type |= Rv4; + case '6': break; + } + for(;;) switch(*p++){ + default: + return -1; + case 'i': + if(((type ^= Rifc) & Rifc) != Rifc) return -1; + break; + case 'u': + if(((type ^= Runi) & (Runi|Rbcast|Rmulti)) != Runi) return -1; + break; + case 'b': + if(((type ^= Rbcast) & (Runi|Rbcast|Rmulti)) != Rbcast) return -1; + break; + case 'm': + if(((type ^= Rmulti) & (Runi|Rbcast|Rmulti)) != Rmulti) return -1; + break; + case 'p': + if(((type ^= Rptpt) & Rptpt) != Rptpt) return -1; + break; + case '\0': + return type; + } +} + void -routetype(int type, char *p) +routetype(int type, char p[8]) { - memset(p, ' ', 4); - p[4] = 0; if(type & Rv4) *p++ = '4'; else *p++ = '6'; + if(type & Rifc) *p++ = 'i'; + if(type & Runi) *p++ = 'u'; else if(type & Rbcast) *p++ = 'b'; else if(type & Rmulti) *p++ = 'm'; + if(type & Rptpt) - *p = 'p'; + *p++ = 'p'; + *p = 0; } -static char *rformat = "%-15I %-4M %-15I %4.4s %4.4s %3s\n"; - -void -convroute(Route *r, uchar *addr, uchar *mask, uchar *gate, char *t, int *nifc) +static void +convroute(Route *r, uchar *addr, uchar *mask, uchar *src, uchar *smask, uchar *gate) { int i; if(r->type & Rv4){ memmove(addr, v4prefix, IPv4off); hnputl(addr+IPv4off, r->v4.address); + memset(mask, 0xff, IPv4off); hnputl(mask+IPv4off, ~(r->v4.endaddress ^ r->v4.address)); + + memmove(src, v4prefix, IPv4off); + hnputl(src+IPv4off, r->v4.source); + + memset(smask, 0xff, IPv4off); + hnputl(smask+IPv4off, ~(r->v4.endsource ^ r->v4.source)); + memmove(gate, v4prefix, IPv4off); memmove(gate+IPv4off, r->v4.gate, IPv4addrlen); } else { for(i = 0; i < IPllen; i++){ hnputl(addr + 4*i, r->v6.address[i]); hnputl(mask + 4*i, ~(r->v6.endaddress[i] ^ r->v6.address[i])); + hnputl(src + 4*i, r->v6.source[i]); + hnputl(smask + 4*i, ~(r->v6.endsource[i] ^ r->v6.source[i])); } memmove(gate, r->v6.gate, IPaddrlen); } +} - routetype(r->type, t); +static char* +seprintroute(char *p, char *e, Route *r) +{ + uchar addr[IPaddrlen], mask[IPaddrlen], src[IPaddrlen], smask[IPaddrlen], gate[IPaddrlen]; + char type[8], ifbuf[4], *iname; - if(r->ifc) - *nifc = r->ifc->conv->x; + convroute(r, addr, mask, src, smask, gate); + routetype(r->type, type); + if(r->ifc != nil && r->ifcid == r->ifc->ifcid) + snprint(iname = ifbuf, sizeof ifbuf, "%d", r->ifc->conv->x); else - *nifc = -1; + iname = "-"; + return seprint(p, e, "%-15I %-4M %-15I %-4s %4.4s %3s %-15I %-4M\n", + addr, mask, gate, type, r->tag, iname, src, smask); } -/* - * this code is not in rr to reduce stack size - */ -static void -sprintroute(Route *r, Routewalk *rw) +typedef struct Routewalk Routewalk; +struct Routewalk { - int nifc, n; - char t[5], *iname, ifbuf[5]; - uchar addr[IPaddrlen], mask[IPaddrlen], gate[IPaddrlen]; - char *p; - - convroute(r, addr, mask, gate, t, &nifc); - iname = "-"; - if(nifc != -1) { - iname = ifbuf; - snprint(ifbuf, sizeof ifbuf, "%d", nifc); - } - p = seprint(rw->p, rw->e, rformat, addr, mask, gate, t, r->tag, iname); + int o; + int h; + char* p; + char* e; +}; + +static int +rr1(Routewalk *rw, Route *r) +{ + int n = seprintroute(rw->p, rw->e, r) - rw->p; if(rw->o < 0){ - n = p - rw->p; if(n > -rw->o){ - memmove(rw->p, rw->p-rw->o, n+rw->o); - rw->p = p + rw->o; + memmove(rw->p, rw->p - rw->o, n + rw->o); + rw->p += n + rw->o; } rw->o += n; } else - rw->p = p; + rw->p += n; + return rw->p < rw->e; } -/* - * recurse descending tree, applying the function in Routewalk - */ static int rr(Route *r, Routewalk *rw) { int h; - if(rw->e <= rw->p) - return 0; if(r == nil) return 1; - if(rr(r->left, rw) == 0) return 0; - if(r->type & Rv4) h = V4H(r->v4.address); else h = V6H(r->v6.address); - - if(h == rw->h) - rw->walk(r, rw); - + if(h == rw->h){ + if(rr1(rw, r) == 0) + return 0; + } if(rr(r->mid, rw) == 0) return 0; - return rr(r->right, rw); } -void -ipwalkroutes(Fs *f, Routewalk *rw) +long +routeread(Fs *f, char *p, ulong offset, int n) { + Routewalk rw[1]; + + rw->p = p; + rw->e = p+n; + rw->o = -offset; + if(rw->o > 0) + return 0; + rlock(&routelock); - if(rw->e > rw->p) { + if(rw->p < rw->e) { for(rw->h = 0; rw->h < nelem(f->v4root); rw->h++) if(rr(f->v4root[rw->h], rw) == 0) break; } - if(rw->e > rw->p) { + if(rw->p < rw->e) { for(rw->h = 0; rw->h < nelem(f->v6root); rw->h++) if(rr(f->v6root[rw->h], rw) == 0) break; } runlock(&routelock); -} - -long -routeread(Fs *f, char *p, ulong offset, int n) -{ - Routewalk rw; - - rw.p = p; - rw.e = p+n; - rw.o = -offset; - rw.walk = sprintroute; - ipwalkroutes(f, &rw); - - return rw.p - p; + return rw->p - p; } /* - * this code is not in routeflush to reduce stack size + * 4 add addr mask gate + * 5 add addr mask gate ifc + * 6 add addr mask gate src smask + * 7 add addr mask gate ifc src smask + * 8 add addr mask gate tag ifc src smask + * 9 add addr mask gate type tag ifc src smask + * 3 remove addr mask + * 4 remove addr mask gate + * 5 remove addr mask src smask + * 6 remove addr mask gate src smask + * 7 remove addr mask gate ifc src smask + * 8 remove addr mask gate tag ifc src smask + * 9 remove addr mask gate type tag ifc src smask */ -void -delroute(Fs *f, Route *r, int dolock) +static Route +parseroute(Fs *f, char **argv, int argc) { - uchar addr[IPaddrlen]; - uchar mask[IPaddrlen]; + uchar addr[IPaddrlen], mask[IPaddrlen]; + uchar src[IPaddrlen], smask[IPaddrlen]; uchar gate[IPaddrlen]; - char t[5]; - int nifc; + Ipifc *ifc; + char *tag; + int type; - convroute(r, addr, mask, gate, t, &nifc); - if(r->type & Rv4) - v4delroute(f, addr+IPv4off, mask+IPv4off, dolock); - else - v6delroute(f, addr, mask, dolock); -} + type = 0; + tag = nil; + ifc = nil; + ipmove(gate, IPnoaddr); + ipmove(src, IPnoaddr); + ipmove(smask, IPnoaddr); -/* - * recurse until one route is deleted - * returns 0 if nothing is deleted, 1 otherwise - */ -int -routeflush(Fs *f, Route *r, char *tag) -{ - if(r == nil) - return 0; - if(routeflush(f, r->mid, tag)) - return 1; - if(routeflush(f, r->left, tag)) - return 1; - if(routeflush(f, r->right, tag)) - return 1; - if((r->type & Rifc) == 0){ - if(tag == nil || strncmp(tag, r->tag, sizeof(r->tag)) == 0){ - delroute(f, r, 0); - return 1; - } + if(argc < 3) + error(Ebadctl); + if(parseip(addr, argv[1]) == -1) + error(Ebadip); + parseipmask(mask, argv[2]); + + if(strcmp(argv[0], "add") == 0 || (argc > 3 && argc != 5)){ + if(argc < 4) + error(Ebadctl); + if(parseip(gate, argv[3]) == -1) + error(Ebadip); } - return 0; + if(argc > 4 && (strcmp(argv[0], "add") != 0 || argc != 5)){ + if(parseip(src, argv[argc-2]) == -1) + error(Ebadip); + parseipmask(smask, argv[argc-1]); + } + if(argc == 5 && strcmp(argv[0], "add") == 0) + ifc = findipifcstr(f, argv[4]); + if(argc > 6) + ifc = findipifcstr(f, argv[argc-3]); + if(argc > 7) + tag = argv[argc-4]; + if(argc > 8){ + if((type = parseroutetype(argv[argc-5])) < 0) + error(Ebadctl); + } else { + if(isv4(addr)) + type |= Rv4; + } + if(argc > 9) + error(Ebadctl); + + if(type & Rv4){ + if(!isv4(addr)) + error(Ebadip); + if(ipcmp(smask, IPnoaddr) != 0 && !isv4(src)) + error(Ebadip); + if(ipcmp(gate, IPnoaddr) != 0 && !isv4(gate)) + error(Ebadip); + } else { + if(isv4(addr)) + error(Ebadip); + } + + return mkroute(addr, mask, src, smask, gate, type, ifc, tag); } long routewrite(Fs *f, Chan *c, char *p, int n) { - int h, changed; - char *tag; Cmdbuf *cb; - uchar addr[IPaddrlen]; - uchar mask[IPaddrlen]; - uchar gate[IPaddrlen]; - IPaux *a, *na; + IPaux *a; cb = parsecmd(p, n); if(waserror()){ @@ -794,52 +958,35 @@ routewrite(Fs *f, Chan *c, char *p, int n) if(cb->nf < 1) error("short control request"); if(strcmp(cb->f[0], "flush") == 0){ - tag = cb->f[1]; + char *tag = cb->nf < 2 ? nil : cb->f[1]; + Route *x; + int h; + + wlock(&routelock); for(h = 0; h < nelem(f->v4root); h++) - for(changed = 1; changed;){ - wlock(&routelock); - changed = routeflush(f, f->v4root[h], tag); - wunlock(&routelock); - } + while((x = looknodetag(f->v4root[h], tag)) != nil) + routerem(f, x); for(h = 0; h < nelem(f->v6root); h++) - for(changed = 1; changed;){ - wlock(&routelock); - changed = routeflush(f, f->v6root[h], tag); - wunlock(&routelock); - } - } else if(strcmp(cb->f[0], "remove") == 0){ - if(cb->nf < 3) - error(Ebadarg); - if (parseip(addr, cb->f[1]) == -1) - error(Ebadip); - parseipmask(mask, cb->f[2]); - if(memcmp(addr, v4prefix, IPv4off) == 0) - v4delroute(f, addr+IPv4off, mask+IPv4off, 1); - else - v6delroute(f, addr, mask, 1); - } else if(strcmp(cb->f[0], "add") == 0){ - if(cb->nf < 4) - error(Ebadarg); - if(parseip(addr, cb->f[1]) == -1 || - parseip(gate, cb->f[3]) == -1) - error(Ebadip); - parseipmask(mask, cb->f[2]); - tag = "none"; - if(c != nil){ + while((x = looknodetag(f->v6root[h], tag)) != nil) + routerem(f, x); + wunlock(&routelock); + } else if(strcmp(cb->f[0], "add") == 0 || strcmp(cb->f[0], "remove") == 0){ + Route r = parseroute(f, cb->f, cb->nf); + if(*r.tag == 0){ a = c->aux; - tag = a->tag; + strncpy(r.tag, a->tag, sizeof(r.tag)); } - if(memcmp(addr, v4prefix, IPv4off) == 0) - v4addroute(f, tag, addr+IPv4off, mask+IPv4off, gate+IPv4off, 0); + wlock(&routelock); + if(strcmp(cb->f[0], "add") == 0) + routeadd(f, &r); else - v6addroute(f, tag, addr, mask, gate, 0); + routerem(f, &r); + wunlock(&routelock); } else if(strcmp(cb->f[0], "tag") == 0) { if(cb->nf < 2) error(Ebadarg); - a = c->aux; - na = newipaux(a->owner, cb->f[1]); - c->aux = na; + c->aux = newipaux(a->owner, cb->f[1]); free(a); } else error(Ebadctl); diff --git a/sys/src/9/ip/ipv6.c b/sys/src/9/ip/ipv6.c index 1fbfedc34..7fb1d1323 100644 --- a/sys/src/9/ip/ipv6.c +++ b/sys/src/9/ip/ipv6.c @@ -38,7 +38,7 @@ ipoput6(Fs *f, Block *bp, int gating, int ttl, int tos, Routehint *rh) IP *ip; Ip6hdr *eh; Ipifc *ifc; - Route *r, *sr; + Route *r; ip = f->ip; @@ -74,23 +74,16 @@ ipoput6(Fs *f, Block *bp, int gating, int ttl, int tos, Routehint *rh) goto free; } - r = v6lookup(f, eh->dst, rh); - if(r == nil){ + r = v6lookup(f, eh->dst, eh->src, rh); + if(r == nil || (r->type & Rv4) != 0 || (ifc = r->ifc) == nil){ ip->stats[OutNoRoutes]++; - netlog(f, Logip, "no interface %I\n", eh->dst); + netlog(f, Logip, "no interface %I -> %I\n", eh->src, eh->dst); rv = -1; goto free; } - ifc = r->ifc; - if(r->type & (Rifc|Runi)) + if(r->type & (Rifc|Runi|Rbcast|Rmulti)) gate = eh->dst; - else if(r->type & (Rbcast|Rmulti)) { - gate = eh->dst; - sr = v6lookup(f, eh->src, nil); - if(sr && (sr->type & Runi)) - ifc = sr->ifc; - } else gate = r->v6.gate; @@ -226,7 +219,6 @@ ipiput6(Fs *f, Ipifc *ifc, Block *bp) { int hl, hop, tos, notforme, tentative; uchar proto; - uchar v6dst[IPaddrlen]; IP *ip; Ip6hdr *h; Proto *p; @@ -251,10 +243,8 @@ ipiput6(Fs *f, Ipifc *ifc, Block *bp) } h = (Ip6hdr *)bp->rp; - - memmove(&v6dst[0], &h->dst[0], IPaddrlen); - notforme = ipforme(f, v6dst) == 0; - tentative = iptentative(f, v6dst); + notforme = ipforme(f, h->dst) == 0; + tentative = iptentative(f, h->dst); if(tentative && h->proto != ICMPv6) { print("tentative addr, drop\n"); @@ -290,8 +280,8 @@ ipiput6(Fs *f, Ipifc *ifc, Block *bp) /* don't forward to source's network */ rh.r = nil; - r = v6lookup(f, h->dst, &rh); - if(r == nil || r->ifc == ifc){ + r = v6lookup(f, h->dst, h->src, &rh); + if(r == nil || (r->type & Rv4) != 0 || r->ifc == ifc){ ip->stats[OutDiscards]++; freeblist(bp); return; diff --git a/sys/src/9/ip/rudp.c b/sys/src/9/ip/rudp.c index bbf779b02..0f8fbbe96 100644 --- a/sys/src/9/ip/rudp.c +++ b/sys/src/9/ip/rudp.c @@ -564,10 +564,10 @@ rudpiput(Proto *rudp, Ipifc *ifc, Block *bp) c->rport = rport; /* reply with the same ip address (if not broadcast) */ - if(ipforme(f, laddr) == Runi) - ipmove(c->laddr, laddr); - else + if(ipforme(f, laddr) != Runi) ipv6local(ifc, c->laddr, c->raddr); + else + ipmove(c->laddr, laddr); } break; } diff --git a/sys/src/9/ip/tcp.c b/sys/src/9/ip/tcp.c index f241a5c8e..95c03be1e 100644 --- a/sys/src/9/ip/tcp.c +++ b/sys/src/9/ip/tcp.c @@ -864,8 +864,7 @@ tcpmtu(Route *r, int version, uint *scale) * otherwise, we use the default MSS which assumes a * safe minimum MTU of 1280 bytes for V6. */ - if(r != nil){ - ifc = r->ifc; + if(r != nil && (ifc = r->ifc) != nil){ mtu = ifc->maxtu - ifc->m->hsize; if(version == V4) return mtu - (TCP4_PKT + TCP4_HDRSIZE); @@ -1314,7 +1313,7 @@ tcpsndsyn(Conv *s, Tcpctl *tcb) tcb->sndsyntime = NOW; /* set desired mss and scale */ - tcb->mss = tcpmtu(v6lookup(s->p->f, s->raddr, s), s->ipversion, &tcb->scale); + tcb->mss = tcpmtu(v6lookup(s->p->f, s->raddr, s->laddr, s), s->ipversion, &tcb->scale); tpriv = s->p->priv; tpriv->stats[Mss] = tcb->mss; } @@ -1492,7 +1491,7 @@ sndsynack(Proto *tcp, Limbo *lp) seg.ack = lp->irs+1; seg.flags = SYN|ACK; seg.urg = 0; - seg.mss = tcpmtu(v6lookup(tcp->f, lp->raddr, nil), lp->version, &scale); + seg.mss = tcpmtu(v6lookup(tcp->f, lp->raddr, lp->laddr, nil), lp->version, &scale); seg.wnd = QMAX; /* if the other side set scale, we should too */ @@ -1768,7 +1767,7 @@ tcpincoming(Conv *s, Tcp *segp, uchar *src, uchar *dst, uchar version) tcb->flags |= SYNACK; /* set desired mss and scale */ - tcb->mss = tcpmtu(v6lookup(s->p->f, src, s), version, &tcb->scale); + tcb->mss = tcpmtu(v6lookup(s->p->f, src, dst, s), version, &tcb->scale); /* our sending max segment size cannot be bigger than what he asked for */ if(lp->mss != 0 && lp->mss < tcb->mss) |