devip: more v6 improvements

ipv4local() and ipv6local() now take remote address argument,
returning the closest local address to the source. this
implements the standartized source address selection rules
instead of just returning the first local v4 or v6 address.

the source address selection was broken for esp, rudp an udp,
blindly assuming ifc->lifc->local being a valid v4 address.
use ipv6local() instead.

the v6 routing code used to lookup source address route to
decide to drop the packet instead of checking the interface
on the destination route.

factor out the route hint from Conv and put it in Routehint
structure. avoiding stack bloat in v4 routing. implement the
same trick for v6 avoiding second route lookup in ipoput6.

fix memory leak in icmpv6 router solicitation handling.

remove old unfinished handling of multiple v6 routers. should
implement source specific routes instead.

avoid duplication, use common convipvers() function.

use isv4() instead of memcmp v4prefix.
This commit is contained in:
cinap_lenrek 2018-03-18 07:50:48 +01:00
parent 8ce98a0b32
commit 71f807873b
13 changed files with 208 additions and 298 deletions

View file

@ -539,7 +539,6 @@ arpread(Arp *arp, char *p, ulong offset, int len)
extern int extern int
rxmitsols(Arp *arp) rxmitsols(Arp *arp)
{ {
uint sflag;
Block *next, *xp; Block *next, *xp;
Arpent *a, *b, **l; Arpent *a, *b, **l;
Fs *f; Fs *f;
@ -582,8 +581,8 @@ rxmitsols(Arp *arp)
qunlock(arp); /* for icmpns */ qunlock(arp); /* for icmpns */
if((sflag = ipv6anylocal(ifc, ipsrc)) != SRC_UNSPEC) if(ipv6local(ifc, ipsrc, a->ip))
icmpns(f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac); icmpns(f, ipsrc, SRC_UNI, a->ip, TARG_MULTI, ifc->mac);
runlock(ifc); runlock(ifc);
qlock(arp); qlock(arp);

View file

@ -919,12 +919,7 @@ Fsstdconnect(Conv *c, char *argv[], int argc)
return p; return p;
} }
if( (memcmp(c->raddr, v4prefix, IPv4off) == 0 && c->ipversion = convipvers(c);
memcmp(c->laddr, v4prefix, IPv4off) == 0)
|| ipcmp(c->raddr, IPnoaddr) == 0)
c->ipversion = V4;
else
c->ipversion = V6;
return nil; return nil;
} }
@ -1150,12 +1145,6 @@ ipwrite(Chan* ch, void *v, long n, vlong off)
if (parseip(ia, cb->f[1]) == -1) if (parseip(ia, cb->f[1]) == -1)
error(Ebadip); error(Ebadip);
ipifcremmulti(c, c->raddr, ia); ipifcremmulti(c, c->raddr, ia);
} else if(strcmp(cb->f[0], "maxfragsize") == 0){
if(cb->nf < 2)
error("maxfragsize needs size");
c->maxfragsize = (int)strtol(cb->f[1], nil, 0);
} else if(x->ctl != nil) { } else if(x->ctl != nil) {
p = x->ctl(c, cb->f, cb->nf); p = x->ctl(c, cb->f, cb->nf);
if(p != nil) if(p != nil)
@ -1329,7 +1318,6 @@ retry:
c->lport = 0; c->lport = 0;
c->rport = 0; c->rport = 0;
c->restricted = 0; c->restricted = 0;
c->maxfragsize = 0;
c->ttl = MAXTTL; c->ttl = MAXTTL;
qreopen(c->rq); qreopen(c->rq);
qreopen(c->wq); qreopen(c->wq);

View file

@ -266,17 +266,6 @@ espclose(Conv *c)
memset(ecb, 0, sizeof(Espcb)); memset(ecb, 0, sizeof(Espcb));
} }
static int
convipvers(Conv *c)
{
if((memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
memcmp(c->laddr, v4prefix, IPv4off) == 0) ||
ipcmp(c->raddr, IPnoaddr) == 0)
return V4;
else
return V6;
}
static int static int
pktipvers(Fs *f, Block **bpp) pktipvers(Fs *f, Block **bpp)
{ {

View file

@ -477,7 +477,7 @@ sendarp(Ipifc *ifc, Arpent *a)
memset(bp->rp, 0, n); memset(bp->rp, 0, n);
e = (Etherarp*)bp->rp; e = (Etherarp*)bp->rp;
memmove(e->tpa, a->ip+IPv4off, sizeof(e->tpa)); memmove(e->tpa, a->ip+IPv4off, sizeof(e->tpa));
ipv4local(ifc, e->spa); ipv4local(ifc, e->spa, e->tpa);
memmove(e->sha, ifc->mac, sizeof(e->sha)); memmove(e->sha, ifc->mac, sizeof(e->sha));
memset(e->d, 0xff, sizeof(e->d)); /* ethernet broadcast */ memset(e->d, 0xff, sizeof(e->d)); /* ethernet broadcast */
memmove(e->s, ifc->mac, sizeof(e->s)); memmove(e->s, ifc->mac, sizeof(e->s));
@ -496,7 +496,6 @@ sendarp(Ipifc *ifc, Arpent *a)
static void static void
resolveaddr6(Ipifc *ifc, Arpent *a) resolveaddr6(Ipifc *ifc, Arpent *a)
{ {
int sflag;
Block *bp; Block *bp;
Etherrock *er = ifc->arg; Etherrock *er = ifc->arg;
uchar ipsrc[IPaddrlen]; uchar ipsrc[IPaddrlen];
@ -526,8 +525,8 @@ resolveaddr6(Ipifc *ifc, Arpent *a)
a->rxtsrem--; a->rxtsrem--;
arprelease(er->f->arp, a); arprelease(er->f->arp, a);
if(sflag = ipv6anylocal(ifc, ipsrc)) if(ipv6local(ifc, ipsrc, a->ip))
icmpns(er->f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac); icmpns(er->f, ipsrc, SRC_UNI, a->ip, TARG_MULTI, ifc->mac);
} }
/* /*

View file

@ -331,7 +331,7 @@ mkechoreply6(Block *bp, Ipifc *ifc)
ipmove(addr, p->src); ipmove(addr, p->src);
if(!isv6mcast(p->dst)) if(!isv6mcast(p->dst))
ipmove(p->src, p->dst); ipmove(p->src, p->dst);
else if (!ipv6anylocal(ifc, p->src)) else if (!ipv6local(ifc, p->src, addr))
return nil; return nil;
ipmove(p->dst, addr); ipmove(p->dst, addr);
p->type = EchoReplyV6; p->type = EchoReplyV6;
@ -440,7 +440,7 @@ icmphostunr(Fs *f, Ipifc *ifc, Block *bp, int code, int free)
np = (IPICMP *)nbp->rp; np = (IPICMP *)nbp->rp;
rlock(ifc); rlock(ifc);
if(ipv6anylocal(ifc, np->src)) if(ipv6local(ifc, np->src, p->src))
netlog(f, Logicmp, "send icmphostunr -> src %I dst %I\n", p->src, p->dst); netlog(f, Logicmp, "send icmphostunr -> src %I dst %I\n", p->src, p->dst);
else { else {
netlog(f, Logicmp, "icmphostunr fail -> src %I dst %I\n", p->src, p->dst); netlog(f, Logicmp, "icmphostunr fail -> src %I dst %I\n", p->src, p->dst);
@ -487,7 +487,7 @@ icmpttlexceeded6(Fs *f, Ipifc *ifc, Block *bp)
nbp = newIPICMP(sz); nbp = newIPICMP(sz);
np = (IPICMP *) nbp->rp; np = (IPICMP *) nbp->rp;
if(ipv6anylocal(ifc, np->src)) if(ipv6local(ifc, np->src, p->src))
netlog(f, Logicmp, "send icmpttlexceeded6 -> src %I dst %I\n", netlog(f, Logicmp, "send icmpttlexceeded6 -> src %I dst %I\n",
p->src, p->dst); p->src, p->dst);
else { else {
@ -526,7 +526,7 @@ icmppkttoobig6(Fs *f, Ipifc *ifc, Block *bp)
nbp = newIPICMP(sz); nbp = newIPICMP(sz);
np = (IPICMP *)nbp->rp; np = (IPICMP *)nbp->rp;
if(ipv6anylocal(ifc, np->src)) if(ipv6local(ifc, np->src, p->src))
netlog(f, Logicmp, "send icmppkttoobig6 -> src %I dst %I\n", netlog(f, Logicmp, "send icmppkttoobig6 -> src %I dst %I\n",
p->src, p->dst); p->src, p->dst);
else { else {
@ -778,18 +778,11 @@ icmpiput6(Proto *icmp, Ipifc *ipifc, Block *bp)
} }
bp->rp -= IPICMPSZ; bp->rp -= IPICMPSZ;
} }
goticmpkt6(icmp, bp, 0); goticmpkt6(icmp, bp, 0);
break; break;
case RouterAdvert: case RouterAdvert:
case RouterSolicit: case RouterSolicit:
/* using lsrc as a temp, munge hdr for goticmp6 */
if (0) {
memmove(lsrc, p->src, IPaddrlen);
memmove(p->src, p->dst, IPaddrlen);
memmove(p->dst, lsrc, IPaddrlen);
}
goticmpkt6(icmp, bp, p->type); goticmpkt6(icmp, bp, p->type);
break; break;
@ -809,21 +802,21 @@ icmpiput6(Proto *icmp, Ipifc *ipifc, Block *bp)
8*np->olen-2, 0); 8*np->olen-2, 0);
pktflags |= Sflag; pktflags |= Sflag;
} }
if(ipv6local(ipifc, lsrc)) if(!ipv6local(ipifc, lsrc, np->src))
break;
icmpna(icmp->f, lsrc, icmpna(icmp->f, lsrc,
(ipcmp(np->src, v6Unspecified) == 0? (ipcmp(np->src, v6Unspecified) == 0?
v6allnodesL: np->src), v6allnodesL: np->src),
np->target, ipifc->mac, pktflags); np->target, ipifc->mac, pktflags);
else
freeblist(bp);
break; break;
case Tunitent: case Tunitent:
/* not clear what needs to be done. send up /*
* an icmp mesg saying don't use this address? */ * not clear what needs to be done. send up
default: * an icmp mesg saying don't use this address?
freeblist(bp); */
break;
} }
freeblist(bp);
break; break;
case NbrAdvert: case NbrAdvert:
@ -839,8 +832,7 @@ icmpiput6(Proto *icmp, Ipifc *ipifc, Block *bp)
lifc = iplocalonifc(ipifc, np->target); lifc = iplocalonifc(ipifc, np->target);
if(lifc && lifc->tentative) if(lifc && lifc->tentative)
refresh = 0; refresh = 0;
arpenter(icmp->f, V6, np->target, np->lnaddr, 8*np->olen-2, arpenter(icmp->f, V6, np->target, np->lnaddr, 8*np->olen-2, refresh);
refresh);
freeblist(bp); freeblist(bp);
break; break;

View file

@ -63,8 +63,6 @@ ip_init_6(Fs *f)
v6p->hp.rxmithost = 1000; /* v6 RETRANS_TIMER */ v6p->hp.rxmithost = 1000; /* v6 RETRANS_TIMER */
v6p->cdrouter = -1;
f->v6p = v6p; f->v6p = v6p;
} }
@ -118,7 +116,7 @@ iprouting(Fs *f, int on)
} }
int int
ipoput4(Fs *f, Block *bp, int gating, int ttl, int tos, Conv *c) ipoput4(Fs *f, Block *bp, int gating, int ttl, int tos, Routehint *rh)
{ {
Ipifc *ifc; Ipifc *ifc;
uchar *gate; uchar *gate;
@ -156,7 +154,7 @@ ipoput4(Fs *f, Block *bp, int gating, int ttl, int tos, Conv *c)
goto free; goto free;
} }
r = v4lookup(f, eh->dst, c); r = v4lookup(f, eh->dst, rh);
if(r == nil){ if(r == nil){
ip->stats[OutNoRoutes]++; ip->stats[OutNoRoutes]++;
netlog(f, Logip, "no interface %V\n", eh->dst); netlog(f, Logip, "no interface %V\n", eh->dst);
@ -193,9 +191,6 @@ ipoput4(Fs *f, Block *bp, int gating, int ttl, int tos, Conv *c)
goto raise; goto raise;
/* If we dont need to fragment just send it */ /* If we dont need to fragment just send it */
if(c && c->maxfragsize && c->maxfragsize < ifc->maxtu)
medialen = c->maxfragsize - ifc->m->hsize;
else
medialen = ifc->maxtu - ifc->m->hsize; medialen = ifc->maxtu - ifc->m->hsize;
if(len <= medialen) { if(len <= medialen) {
if(!gating) if(!gating)
@ -315,8 +310,6 @@ ipiput4(Fs *f, Ipifc *ifc, Block *bp)
int notforme; int notforme;
uchar *dp, v6dst[IPaddrlen]; uchar *dp, v6dst[IPaddrlen];
IP *ip; IP *ip;
Route *r;
Conv conv;
if(BLKIPVER(bp) != IP_VER4) { if(BLKIPVER(bp) != IP_VER4) {
ipiput6(f, ifc, bp); ipiput6(f, ifc, bp);
@ -377,15 +370,17 @@ ipiput4(Fs *f, Ipifc *ifc, Block *bp)
/* route */ /* route */
if(notforme) { if(notforme) {
Route *r;
Routehint rh;
if(!ip->iprouting){ if(!ip->iprouting){
freeblist(bp); freeblist(bp);
return; return;
} }
/* don't forward to source's network */ /* don't forward to source's network */
memmove(&conv, ifc->conv, sizeof conv); rh.r = nil;
conv.r = nil; r = v4lookup(f, h->dst, &rh);
r = v4lookup(f, h->dst, &conv);
if(r == nil || r->ifc == ifc){ if(r == nil || r->ifc == ifc){
ip->stats[OutDiscards]++; ip->stats[OutDiscards]++;
freeblist(bp); freeblist(bp);
@ -419,7 +414,7 @@ if(r->ifc == nil) panic("nil route ifc");
ip->stats[ForwDatagrams]++; ip->stats[ForwDatagrams]++;
tos = h->tos; tos = h->tos;
hop = h->ttl; hop = h->ttl;
ipoput4(f, bp, 1, hop - 1, tos, &conv); ipoput4(f, bp, 1, hop - 1, tos, &rh);
return; return;
} }

View file

@ -21,10 +21,10 @@ typedef struct Proto Proto;
typedef struct Arpent Arpent; typedef struct Arpent Arpent;
typedef struct Arp Arp; typedef struct Arp Arp;
typedef struct Route Route; typedef struct Route Route;
typedef struct Routehint Routehint;
typedef struct Routerparams Routerparams; typedef struct Routerparams Routerparams;
typedef struct Hostparams Hostparams; typedef struct Hostparams Hostparams;
typedef struct v6router v6router;
typedef struct v6params v6params; typedef struct v6params v6params;
#pragma incomplete Arp #pragma incomplete Arp
@ -164,6 +164,12 @@ struct Ip4hdr
uchar dst[4]; /* IP destination */ uchar dst[4]; /* IP destination */
}; };
struct Routehint
{
Route *r; /* last route used */
ulong rgen; /* routetable generation for *r */
};
/* /*
* one per conversation directory * one per conversation directory
*/ */
@ -191,8 +197,6 @@ struct Conv
int length; int length;
int state; int state;
int maxfragsize; /* If set, used for fragmentation */
/* udp specific */ /* udp specific */
int headers; /* data src/dst headers in udp */ int headers; /* data src/dst headers in udp */
int reliable; /* true if reliable udp */ int reliable; /* true if reliable udp */
@ -217,8 +221,7 @@ struct Conv
void* ptcl; /* protocol specific stuff */ void* ptcl; /* protocol specific stuff */
Route *r; /* last route used */ Routehint;
ulong rgen; /* routetable generation for *r */
}; };
struct Medium struct Medium
@ -443,23 +446,10 @@ struct Fs
long ndbmtime; long ndbmtime;
}; };
/* one per default router known to host */
struct v6router {
uchar inuse;
Ipifc *ifc;
int ifcid;
uchar routeraddr[IPaddrlen];
long ltorigin;
Routerparams rp;
};
struct v6params struct v6params
{ {
Routerparams rp; /* v6 params, one copy per node now */ Routerparams rp; /* v6 params, one copy per node now */
Hostparams hp; Hostparams hp;
v6router v6rlist[3]; /* max 3 default routers, currently */
int cdrouter; /* uses only v6rlist[cdrouter] if */
/* cdrouter >= 0. */
}; };
@ -586,8 +576,8 @@ extern void v4addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int
extern void v6addroute(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 v4delroute(Fs *f, uchar *a, uchar *mask, int dolock);
extern void v6delroute(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, Conv *c); extern Route* v4lookup(Fs *f, uchar *a, Routehint *h);
extern Route* v6lookup(Fs *f, uchar *a, Conv *c); extern Route* v6lookup(Fs *f, uchar *a, Routehint *h);
extern long routeread(Fs *f, char*, ulong, int); extern long routeread(Fs *f, char*, ulong, int);
extern long routewrite(Fs *f, Chan*, char*, int); extern long routewrite(Fs *f, Chan*, char*, int);
extern void routetype(int, char*); extern void routetype(int, char*);
@ -654,6 +644,7 @@ extern int isv4(uchar*);
extern void v4tov6(uchar *v6, uchar *v4); extern void v4tov6(uchar *v6, uchar *v4);
extern int v6tov4(uchar *v4, uchar *v6); extern int v6tov4(uchar *v4, uchar *v6);
extern int eipfmt(Fmt*); extern int eipfmt(Fmt*);
extern int convipvers(Conv *c);
#define ipmove(x, y) memmove(x, y, IPaddrlen) #define ipmove(x, y) memmove(x, y, IPaddrlen)
#define ipcmp(x, y) ( (x)[IPaddrlen-1] != (y)[IPaddrlen-1] || memcmp(x, y, IPaddrlen) ) #define ipcmp(x, y) ( (x)[IPaddrlen-1] != (y)[IPaddrlen-1] || memcmp(x, y, IPaddrlen) )
@ -686,9 +677,8 @@ extern int ipisbm(uchar *);
extern int ipismulticast(uchar *); extern int ipismulticast(uchar *);
extern Ipifc* findipifc(Fs*, uchar *remote, int type); extern Ipifc* findipifc(Fs*, uchar *remote, int type);
extern void findlocalip(Fs*, uchar *local, uchar *remote); extern void findlocalip(Fs*, uchar *local, uchar *remote);
extern int ipv4local(Ipifc *ifc, uchar *addr); extern int ipv4local(Ipifc *ifc, uchar *local, uchar *remote);
extern int ipv6local(Ipifc *ifc, uchar *addr); extern int ipv6local(Ipifc *ifc, uchar *local, uchar *remote);
extern int ipv6anylocal(Ipifc *ifc, uchar *addr);
extern Iplifc* iplocalonifc(Ipifc *ifc, uchar *ip); extern Iplifc* iplocalonifc(Ipifc *ifc, uchar *ip);
extern int ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip); extern int ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip);
extern int ipismulticast(uchar *ip); extern int ipismulticast(uchar *ip);
@ -714,8 +704,8 @@ extern void icmpttlexceeded(Fs*, uchar*, Block*);
extern ushort ipcsum(uchar*); extern ushort ipcsum(uchar*);
extern void ipiput4(Fs*, Ipifc*, Block*); extern void ipiput4(Fs*, Ipifc*, Block*);
extern void ipiput6(Fs*, Ipifc*, Block*); extern void ipiput6(Fs*, Ipifc*, Block*);
extern int ipoput4(Fs*, Block*, int, int, int, Conv*); extern int ipoput4(Fs*, Block*, int, int, int, Routehint*);
extern int ipoput6(Fs*, Block*, int, int, int, Conv*); extern int ipoput6(Fs*, Block*, int, int, int, Routehint*);
extern int ipstats(Fs*, char*, int); extern int ipstats(Fs*, char*, int);
extern ushort ptclbsum(uchar*, int); extern ushort ptclbsum(uchar*, int);
extern ushort ptclcsum(Block*, int, int); extern ushort ptclcsum(Block*, int, int);

View file

@ -366,3 +366,12 @@ iphtlook(Ipht *ht, uchar *sa, ushort sp, uchar *da, ushort dp)
unlock(ht); unlock(ht);
return nil; return nil;
} }
int
convipvers(Conv *c)
{
if(isv4(c->raddr) && isv4(c->laddr) || ipcmp(c->raddr, IPnoaddr) == 0)
return V4;
else
return V6;
}

View file

@ -1095,7 +1095,7 @@ iptentative(Fs *f, uchar *addr)
* 0 - no match * 0 - no match
* Runi * Runi
* Rbcast * Rbcast
* Rmcast * Rmulti
*/ */
int int
ipforme(Fs *f, uchar *addr) ipforme(Fs *f, uchar *addr)
@ -1163,7 +1163,6 @@ findipifc(Fs *f, uchar *remote, int type)
enum { enum {
unknownv6, /* UGH */ unknownv6, /* UGH */
// multicastv6,
unspecifiedv6, unspecifiedv6,
linklocalv6, linklocalv6,
globalv6, globalv6,
@ -1237,142 +1236,137 @@ findprimaryipv4(Fs *f, uchar *local)
return; return;
} }
} }
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;
} }
/* /*
* find the local address 'closest' to the remote system, copy it to * return v4 address associated with an interface close to remote
* local and return the ifc for that address */
int
ipv4local(Ipifc *ifc, uchar *local, uchar *remote)
{
Iplifc *lifc;
int a, b;
b = -1;
for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
if(!isv4(lifc->local))
continue;
a = comprefixlen(lifc->local+IPv4off, remote, IPv4addrlen);
if(a > b){
b = a;
memmove(local, lifc->local+IPv4off, IPv4addrlen);
}
}
return b >= 0;
}
/*
* return v6 address associated with an interface close to remote
*/
int
ipv6local(Ipifc *ifc, uchar *local, uchar *remote)
{
struct {
int atype;
int deprecated;
int comprefixlen;
} a, b;
int atype;
Iplifc *lifc;
if(isv4(remote)){
ipmove(local, v4prefix);
return ipv4local(ifc, local+IPv4off, remote+IPv4off);
}
atype = v6addrtype(remote);
ipmove(local, v6Unspecified);
b.atype = unknownv6;
b.deprecated = 1;
b.comprefixlen = 0;
for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
if(lifc->tentative)
continue;
a.atype = v6addrtype(lifc->local);
a.deprecated = !v6addrcurr(lifc);
a.comprefixlen = comprefixlen(lifc->local, remote, IPaddrlen);
/* prefer appropriate scope */
if(a.atype != b.atype){
if(a.atype > b.atype && b.atype < atype ||
a.atype < b.atype && b.atype > atype)
goto Good;
continue;
}
/* prefer non-deprecated addresses */
if(a.deprecated != b.deprecated){
if(b.deprecated)
goto Good;
continue;
}
/* prefer longer common prefix */
if(a.comprefixlen != b.comprefixlen){
if(a.comprefixlen > b.comprefixlen)
goto Good;
continue;
}
continue;
Good:
b = a;
ipmove(local, lifc->local);
}
return b.atype >= atype;
}
/*
* find the local address 'closest' to the remote system, copy it to local
*/ */
void void
findlocalip(Fs *f, uchar *local, uchar *remote) findlocalip(Fs *f, uchar *local, uchar *remote)
{ {
int version, atype = unspecifiedv6, atypel = unknownv6;
int atyper, deprecated;
uchar gate[IPaddrlen], gnet[IPaddrlen];
Ipifc *ifc;
Iplifc *lifc;
Route *r; Route *r;
USED(atype);
USED(atypel);
qlock(f->ipifc); qlock(f->ipifc);
r = v6lookup(f, remote, nil); if((r = v6lookup(f, remote, nil)) != nil){
version = (memcmp(remote, v4prefix, IPv4off) == 0)? V4: V6; if(r->type & Runi){
ipmove(local, remote);
if(r != nil){
ifc = r->ifc;
if(r->type & Rv4)
v4tov6(gate, r->v4.gate);
else {
ipmove(gate, r->v6.gate);
ipmove(local, v6Unspecified);
}
switch(version) {
case V4:
/* find ifc address closest to the gateway to use */
for(lifc = ifc->lifc; lifc; lifc = lifc->next){
maskip(gate, lifc->mask, gnet);
if(ipcmp(gnet, lifc->net) == 0){
ipmove(local, lifc->local);
goto out; goto out;
} }
} if((r->type & (Rifc|Rbcast|Rmulti|Rv4)) == Rv4){
break; ipmove(local, v4prefix);
case V6: if(ipv4local(r->ifc, local+IPv4off, r->v4.gate))
/* find ifc address with scope matching the destination */
atyper = v6addrtype(remote);
deprecated = 0;
for(lifc = ifc->lifc; lifc; lifc = lifc->next){
atypel = v6addrtype(lifc->local);
/* prefer appropriate scope */
if(atypel > atype && atype < atyper ||
atypel < atype && atype > atyper){
ipmove(local, lifc->local);
deprecated = !v6addrcurr(lifc);
atype = atypel;
} else if(atypel == atype){
/* avoid deprecated addresses */
if(deprecated && v6addrcurr(lifc)){
ipmove(local, lifc->local);
atype = atypel;
deprecated = 0;
}
}
if(atype == atyper && !deprecated)
goto out; goto out;
} }
if(atype >= atyper) if(ipv6local(r->ifc, local, remote))
goto out; goto out;
break;
default:
panic("findlocalip: version %d", version);
} }
} if(isv4(remote))
switch(version){
case V4:
findprimaryipv4(f, local); findprimaryipv4(f, local);
break; else
case V6:
findprimaryipv6(f, local); findprimaryipv6(f, local);
break;
default:
panic("findlocalip2: version %d", version);
}
out: out:
qunlock(f->ipifc); qunlock(f->ipifc);
} }
/*
* return first v4 address associated with an interface
*/
int
ipv4local(Ipifc *ifc, uchar *addr)
{
Iplifc *lifc;
for(lifc = ifc->lifc; lifc; lifc = lifc->next){
if(isv4(lifc->local)){
memmove(addr, lifc->local+IPv4off, IPv4addrlen);
return 1;
}
}
return 0;
}
/*
* return first v6 address associated with an interface
*/
int
ipv6local(Ipifc *ifc, uchar *addr)
{
Iplifc *lifc;
for(lifc = ifc->lifc; lifc; lifc = lifc->next){
if(!isv4(lifc->local) && !(lifc->tentative)){
ipmove(addr, lifc->local);
return 1;
}
}
return 0;
}
int
ipv6anylocal(Ipifc *ifc, uchar *addr)
{
Iplifc *lifc;
for(lifc = ifc->lifc; lifc; lifc = lifc->next){
if(!isv4(lifc->local)){
ipmove(addr, lifc->local);
return SRC_UNI;
}
}
return SRC_UNSPEC;
}
/* /*
* see if this address is bound to the interface * see if this address is bound to the interface
*/ */
@ -1605,29 +1599,6 @@ ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip)
} }
} }
/* added for new v6 mesg types */
static void
adddefroute6(Fs *f, uchar *gate, int force)
{
Route *r;
r = v6lookup(f, v6Unspecified, nil);
/*
* route entries generated by all other means take precedence
* over router announcements.
*/
if (r && !force && strcmp(r->tag, "ra") != 0)
return;
v6delroute(f, v6Unspecified, v6Unspecified, 1);
v6addroute(f, "ra", v6Unspecified, v6Unspecified, gate, 0);
}
enum {
Ngates = 3,
};
char* char*
ipifcadd6(Ipifc *ifc, char**argv, int argc) ipifcadd6(Ipifc *ifc, char**argv, int argc)
{ {

View file

@ -323,7 +323,6 @@ v4addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type)
} }
#define V6H(a) (((a)[IPllen-1] & 0x07ffffff)>>(32-Lroot-5)) #define V6H(a) (((a)[IPllen-1] & 0x07ffffff)>>(32-Lroot-5))
#define ISDFLT(a, mask, tag) ((ipcmp((a),v6Unspecified)==0) && (ipcmp((mask),v6Unspecified)==0) && (strcmp((tag), "ra")!=0))
void void
v6addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type) v6addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type)
@ -333,12 +332,6 @@ v6addroute(Fs *f, char *tag, uchar *a, uchar *mask, uchar *gate, int type)
ulong x, y; ulong x, y;
int h, eh; int h, eh;
/*
if(ISDFLT(a, mask, tag))
f->v6p->cdrouter = -1;
*/
for(h = 0; h < IPllen; h++){ for(h = 0; h < IPllen; h++){
x = nhgetl(a+4*h); x = nhgetl(a+4*h);
y = nhgetl(mask+4*h); y = nhgetl(mask+4*h);
@ -482,15 +475,15 @@ v6delroute(Fs *f, uchar *a, uchar *mask, int dolock)
} }
Route* Route*
v4lookup(Fs *f, uchar *a, Conv *c) v4lookup(Fs *f, uchar *a, Routehint *rh)
{ {
Route *p, *q; Route *p, *q;
ulong la; ulong la;
uchar gate[IPaddrlen]; uchar gate[IPaddrlen];
Ipifc *ifc; Ipifc *ifc;
if(c != nil && c->r != nil && c->r->ifc != nil && c->rgen == v4routegeneration) if(rh != nil && rh->r != nil && rh->r->ifc != nil && rh->rgen == v4routegeneration)
return c->r; return rh->r;
la = nhgetl(a); la = nhgetl(a);
q = nil; q = nil;
@ -517,16 +510,16 @@ v4lookup(Fs *f, uchar *a, Conv *c)
q->ifcid = ifc->ifcid; q->ifcid = ifc->ifcid;
} }
if(c != nil){ if(rh != nil){
c->r = q; rh->r = q;
c->rgen = v4routegeneration; rh->rgen = v4routegeneration;
} }
return q; return q;
} }
Route* Route*
v6lookup(Fs *f, uchar *a, Conv *c) v6lookup(Fs *f, uchar *a, Routehint *rh)
{ {
Route *p, *q; Route *p, *q;
ulong la[IPllen]; ulong la[IPllen];
@ -536,18 +529,18 @@ v6lookup(Fs *f, uchar *a, Conv *c)
Ipifc *ifc; Ipifc *ifc;
if(memcmp(a, v4prefix, IPv4off) == 0){ if(memcmp(a, v4prefix, IPv4off) == 0){
q = v4lookup(f, a+IPv4off, c); q = v4lookup(f, a+IPv4off, rh);
if(q != nil) if(q != nil)
return q; return q;
} }
if(c != nil && c->r != nil && c->r->ifc != nil && c->rgen == v6routegeneration) if(rh != nil && rh->r != nil && rh->r->ifc != nil && rh->rgen == v6routegeneration)
return c->r; return rh->r;
for(h = 0; h < IPllen; h++) for(h = 0; h < IPllen; h++)
la[h] = nhgetl(a+4*h); la[h] = nhgetl(a+4*h);
q = 0; q = nil;
for(p=f->v6root[V6H(la)]; p;){ for(p=f->v6root[V6H(la)]; p;){
for(h = 0; h < IPllen; h++){ for(h = 0; h < IPllen; h++){
x = la[h]; x = la[h];
@ -588,9 +581,10 @@ next: ;
q->ifc = ifc; q->ifc = ifc;
q->ifcid = ifc->ifcid; q->ifcid = ifc->ifcid;
} }
if(c != nil){
c->r = q; if(rh != nil){
c->rgen = v6routegeneration; rh->r = q;
rh->rgen = v6routegeneration;
} }
return q; return q;

View file

@ -28,7 +28,7 @@ static Block* procxtns(IP *ip, Block *bp, int doreasm);
int unfraglen(Block *bp, uchar *nexthdr, int setfh); int unfraglen(Block *bp, uchar *nexthdr, int setfh);
int int
ipoput6(Fs *f, Block *bp, int gating, int ttl, int tos, Conv *c) ipoput6(Fs *f, Block *bp, int gating, int ttl, int tos, Routehint *rh)
{ {
int medialen, len, chunk, uflen, flen, seglen, lid, offset, fragoff; int medialen, len, chunk, uflen, flen, seglen, lid, offset, fragoff;
int morefrags, blklen, rv = 0, tentative; int morefrags, blklen, rv = 0, tentative;
@ -74,9 +74,8 @@ ipoput6(Fs *f, Block *bp, int gating, int ttl, int tos, Conv *c)
goto free; goto free;
} }
r = v6lookup(f, eh->dst, c); r = v6lookup(f, eh->dst, rh);
if(r == nil){ if(r == nil){
// print("no route for %I, src %I free\n", eh->dst, eh->src);
ip->stats[OutNoRoutes]++; ip->stats[OutNoRoutes]++;
netlog(f, Logip, "no interface %I\n", eh->dst); netlog(f, Logip, "no interface %I\n", eh->dst);
rv = -1; rv = -1;
@ -231,7 +230,6 @@ ipiput6(Fs *f, Ipifc *ifc, Block *bp)
IP *ip; IP *ip;
Ip6hdr *h; Ip6hdr *h;
Proto *p; Proto *p;
Route *r, *sr;
ip = f->ip; ip = f->ip;
ip->stats[InReceives]++; ip->stats[InReceives]++;
@ -274,6 +272,9 @@ ipiput6(Fs *f, Ipifc *ifc, Block *bp)
/* route */ /* route */
if(notforme) { if(notforme) {
Route *r;
Routehint rh;
if(!ip->iprouting){ if(!ip->iprouting){
freeblist(bp); freeblist(bp);
return; return;
@ -288,10 +289,9 @@ ipiput6(Fs *f, Ipifc *ifc, Block *bp)
} }
/* don't forward to source's network */ /* don't forward to source's network */
sr = v6lookup(f, h->src, nil); rh.r = nil;
r = v6lookup(f, h->dst, nil); r = v6lookup(f, h->dst, &rh);
if(r == nil || r->ifc == ifc){
if(r == nil || sr == r){
ip->stats[OutDiscards]++; ip->stats[OutDiscards]++;
freeblist(bp); freeblist(bp);
return; return;
@ -315,7 +315,7 @@ ipiput6(Fs *f, Ipifc *ifc, Block *bp)
h = (Ip6hdr *)bp->rp; h = (Ip6hdr *)bp->rp;
tos = IPV6CLASS(h); tos = IPV6CLASS(h);
hop = h->ttl; hop = h->ttl;
ipoput6(f, bp, 1, hop-1, tos, nil); ipoput6(f, bp, 1, hop-1, tos, &rh);
return; return;
} }

View file

@ -567,7 +567,7 @@ rudpiput(Proto *rudp, Ipifc *ifc, Block *bp)
if(ipforme(f, laddr) == Runi) if(ipforme(f, laddr) == Runi)
ipmove(c->laddr, laddr); ipmove(c->laddr, laddr);
else else
v4tov6(c->laddr, ifc->lifc->local); ipv6local(ifc, c->laddr, c->raddr);
} }
break; break;
} }

View file

@ -189,7 +189,7 @@ udpkick(void *x, Block *bp)
Udppriv *upriv; Udppriv *upriv;
Fs *f; Fs *f;
int version; int version;
Conv *rc; Routehint *rh;
upriv = c->p->priv; upriv = c->p->priv;
f = c->p->f; f = c->p->f;
@ -222,18 +222,12 @@ udpkick(void *x, Block *bp)
} }
if(ucb->headers) { if(ucb->headers) {
if(memcmp(laddr, v4prefix, IPv4off) == 0 if(isv4(laddr) || ipcmp(laddr, IPnoaddr) == 0)
|| ipcmp(laddr, IPnoaddr) == 0) version = V4;
version = 4;
else else
version = 6; version = V6;
} else { } else {
if( (memcmp(c->raddr, v4prefix, IPv4off) == 0 && version = convipvers(c);
memcmp(c->laddr, v4prefix, IPv4off) == 0)
|| ipcmp(c->raddr, IPnoaddr) == 0)
version = 4;
else
version = 6;
} }
dlen = blocklen(bp); dlen = blocklen(bp);
@ -253,14 +247,14 @@ udpkick(void *x, Block *bp)
v6tov4(uh4->udpdst, raddr); v6tov4(uh4->udpdst, raddr);
hnputs(uh4->udpdport, rport); hnputs(uh4->udpdport, rport);
v6tov4(uh4->udpsrc, laddr); v6tov4(uh4->udpsrc, laddr);
rc = nil; rh = nil;
} else { } else {
v6tov4(uh4->udpdst, c->raddr); v6tov4(uh4->udpdst, c->raddr);
hnputs(uh4->udpdport, c->rport); hnputs(uh4->udpdport, c->rport);
if(ipcmp(c->laddr, IPnoaddr) == 0) if(ipcmp(c->laddr, IPnoaddr) == 0)
findlocalip(f, c->laddr, c->raddr); findlocalip(f, c->laddr, c->raddr);
v6tov4(uh4->udpsrc, c->laddr); v6tov4(uh4->udpsrc, c->laddr);
rc = c; rh = c;
} }
hnputs(uh4->udpsport, c->lport); hnputs(uh4->udpsport, c->lport);
hnputs(uh4->udplen, ptcllen); hnputs(uh4->udplen, ptcllen);
@ -269,7 +263,7 @@ udpkick(void *x, Block *bp)
hnputs(uh4->udpcksum, hnputs(uh4->udpcksum,
ptclcsum(bp, UDP4_PHDR_OFF, dlen+UDP_UDPHDR_SZ+UDP4_PHDR_SZ)); ptclcsum(bp, UDP4_PHDR_OFF, dlen+UDP_UDPHDR_SZ+UDP4_PHDR_SZ));
uh4->vihl = IP_VER4; uh4->vihl = IP_VER4;
ipoput4(f, bp, 0, c->ttl, c->tos, rc); ipoput4(f, bp, 0, c->ttl, c->tos, rh);
break; break;
case V6: case V6:
@ -287,14 +281,14 @@ udpkick(void *x, Block *bp)
ipmove(uh6->udpdst, raddr); ipmove(uh6->udpdst, raddr);
hnputs(uh6->udpdport, rport); hnputs(uh6->udpdport, rport);
ipmove(uh6->udpsrc, laddr); ipmove(uh6->udpsrc, laddr);
rc = nil; rh = nil;
} else { } else {
ipmove(uh6->udpdst, c->raddr); ipmove(uh6->udpdst, c->raddr);
hnputs(uh6->udpdport, c->rport); hnputs(uh6->udpdport, c->rport);
if(ipcmp(c->laddr, IPnoaddr) == 0) if(ipcmp(c->laddr, IPnoaddr) == 0)
findlocalip(f, c->laddr, c->raddr); findlocalip(f, c->laddr, c->raddr);
ipmove(uh6->udpsrc, c->laddr); ipmove(uh6->udpsrc, c->laddr);
rc = c; rh = c;
} }
hnputs(uh6->udpsport, c->lport); hnputs(uh6->udpsport, c->lport);
hnputs(uh6->udplen, ptcllen); hnputs(uh6->udplen, ptcllen);
@ -306,7 +300,7 @@ udpkick(void *x, Block *bp)
uh6->viclfl[0] = IP_VER6; uh6->viclfl[0] = IP_VER6;
hnputs(uh6->len, ptcllen); hnputs(uh6->len, ptcllen);
uh6->nextheader = IP_UDPPROTO; uh6->nextheader = IP_UDPPROTO;
ipoput6(f, bp, 0, c->ttl, c->tos, rc); ipoput6(f, bp, 0, c->ttl, c->tos, rh);
break; break;
default: default:
@ -336,7 +330,7 @@ udpiput(Proto *udp, Ipifc *ifc, Block *bp)
upriv->ustats.udpInDatagrams++; upriv->ustats.udpInDatagrams++;
uh4 = (Udp4hdr*)(bp->rp); uh4 = (Udp4hdr*)(bp->rp);
version = ((uh4->vihl&0xF0)==IP_VER6) ? 6 : 4; version = ((uh4->vihl&0xF0)==IP_VER6) ? V6 : V4;
/* Put back pseudo header for checksum /* Put back pseudo header for checksum
* (remember old values for icmpnoconv()) */ * (remember old values for icmpnoconv()) */
@ -424,18 +418,8 @@ udpiput(Proto *udp, Ipifc *ifc, Block *bp)
if(c->state == Announced){ if(c->state == Announced){
if(ucb->headers == 0){ if(ucb->headers == 0){
/* create a new conversation */ /* create a new conversation */
if(ipforme(f, laddr) != Runi) { if(ipforme(f, laddr) != Runi)
switch(version){ ipv6local(ifc, laddr, raddr);
case V4:
v4tov6(laddr, ifc->lifc->local);
break;
case V6:
ipmove(laddr, ifc->lifc->local);
break;
default:
panic("udpiput3: version %d", version);
}
}
c = Fsnewcall(c, raddr, rport, laddr, lport, version); c = Fsnewcall(c, raddr, rport, laddr, lport, version);
if(c == nil){ if(c == nil){
qunlock(udp); qunlock(udp);
@ -533,7 +517,7 @@ udpadvise(Proto *udp, Block *bp, char *msg)
int version; int version;
h4 = (Udp4hdr*)(bp->rp); h4 = (Udp4hdr*)(bp->rp);
version = ((h4->vihl&0xF0)==IP_VER6) ? 6 : 4; version = ((h4->vihl&0xF0)==IP_VER6) ? V6 : V4;
switch(version) { switch(version) {
case V4: case V4: