changelog shortlog tags branches files raw gz bz2 help

Mercurial > hg > plan9front / changeset: devip: use the routing table for local source ip address selection

changeset 7430: 88a2f67638e2
parent 7429: 1dd6759b578b
child 7431: 8f9f3ee2eacf
author: cinap_lenrek@felloff.net
date: Sun, 10 Nov 2019 19:50:46 +0100
files: sys/src/9/ip/arp.c sys/src/9/ip/ethermedium.c sys/src/9/ip/icmp.c sys/src/9/ip/icmp6.c sys/src/9/ip/ip.h sys/src/9/ip/ipifc.c sys/src/9/ip/iproute.c sys/src/9/ip/rudp.c sys/src/9/ip/udp.c
description: devip: use the routing table for local source ip address selection

when making outgoing connections, the source ip was selected
by just iterating from the first to the last interface and
trying each local address until a route was found. the result
was kind of hard to predict as it depends on the interface
order.

this change replaces the algorithm with the route lookup algorithm
that we already have which takes more specific desination and
source prefixes into account. so the order of interfaces does
not matter anymore.
     1.1--- a/sys/src/9/ip/arp.c
     1.2+++ b/sys/src/9/ip/arp.c
     1.3@@ -401,7 +401,7 @@ arpwrite(Fs *fs, char *s, int len)
     1.4 		if((ifc = findipifc(fs, ia, ia, Runi)) == nil)
     1.5 			error("no interface");
     1.6 		rlock(ifc);
     1.7-		if(!ipv6local(ifc, ia, ip) || arpenter(fs, V6, ip, mac, n, ia, ifc, 0) < 0){
     1.8+		if(!ipv6local(ifc, ia, 0, ip) || arpenter(fs, V6, ip, mac, n, ia, ifc, 0) < 0){
     1.9 			runlock(ifc);
    1.10 			error("destination unreachable");
    1.11 		}
    1.12@@ -450,7 +450,7 @@ arpread(Arp *arp, char *s, ulong offset,
    1.13 		qlock(arp);
    1.14 		state = arpstate[a->state];
    1.15 		ipmove(ip, a->ip);
    1.16-		if(ifc->m == nil || a->ifcid != ifc->ifcid || !ipv6local(ifc, ia, ip)){
    1.17+		if(ifc->m == nil || a->ifcid != ifc->ifcid || !ipv6local(ifc, ia, 0, ip)){
    1.18 			qunlock(arp);
    1.19 			runlock(ifc);
    1.20 			continue;
    1.21@@ -507,7 +507,7 @@ ndpsendsol(Fs *f, Ipifc *ifc, Arpent *a)
    1.22 	} else {
    1.23 		arprelease(f->arp, a);
    1.24 	}
    1.25-	if(!ipv6local(ifc, src, targ))
    1.26+	if(!ipv6local(ifc, src, 0, targ))
    1.27 		return;
    1.28 send:
    1.29 	if(!waserror()){
     2.1--- a/sys/src/9/ip/ethermedium.c
     2.2+++ b/sys/src/9/ip/ethermedium.c
     2.3@@ -462,7 +462,7 @@ sendarp(Ipifc *ifc, Arpent *a)
     2.4 	memmove(targ, a->ip+IPv4off, IPv4addrlen);
     2.5 	arprelease(er->f->arp, a);
     2.6 
     2.7-	if(!ipv4local(ifc, src, targ))
     2.8+	if(!ipv4local(ifc, src, 0, targ))
     2.9 		return;
    2.10 
    2.11 	n = sizeof(Etherarp);
     3.1--- a/sys/src/9/ip/icmp.c
     3.2+++ b/sys/src/9/ip/icmp.c
     3.3@@ -218,7 +218,7 @@ icmpttlexceeded(Fs *f, Ipifc *ifc, Block
     3.4 	uchar	ia[IPv4addrlen];
     3.5 
     3.6 	p = (Icmp *)bp->rp;
     3.7-	if(!ip4reply(f, p->src) || !ipv4local(ifc, ia, p->src))
     3.8+	if(!ip4reply(f, p->src) || !ipv4local(ifc, ia, 0, p->src))
     3.9 		return;
    3.10 
    3.11 	netlog(f, Logicmp, "sending icmpttlexceeded %V -> src %V dst %V\n",
     4.1--- a/sys/src/9/ip/icmp6.c
     4.2+++ b/sys/src/9/ip/icmp6.c
     4.3@@ -332,7 +332,7 @@ mkechoreply6(Block *bp, Ipifc *ifc)
     4.4 	ipmove(addr, p->src);
     4.5 	if(!isv6mcast(p->dst))
     4.6 		ipmove(p->src, p->dst);
     4.7-	else if (!ipv6local(ifc, p->src, addr))
     4.8+	else if (!ipv6local(ifc, p->src, 0, addr))
     4.9 		return nil;
    4.10 	ipmove(p->dst, addr);
    4.11 	p->type = EchoReplyV6;
    4.12@@ -434,7 +434,7 @@ icmphostunr6(Fs *f, Ipifc *ifc, Block *b
    4.13 	uchar ia[IPaddrlen];
    4.14 
    4.15 	p = (Ip6hdr *)bp->rp;
    4.16-	if(isv6mcast(p->dst) || isv6mcast(p->src) || !ipv6local(ifc, ia, p->src))
    4.17+	if(isv6mcast(p->dst) || isv6mcast(p->src) || !ipv6local(ifc, ia, 0, p->src))
    4.18 		return;
    4.19 
    4.20 	netlog(f, Logicmp, "send icmphostunr %I -> src %I dst %I\n",
    4.21@@ -471,7 +471,7 @@ icmpttlexceeded6(Fs *f, Ipifc *ifc, Bloc
    4.22 	uchar ia[IPaddrlen];
    4.23 
    4.24 	p = (Ip6hdr *)bp->rp;
    4.25-	if(isv6mcast(p->dst) || isv6mcast(p->src) || !ipv6local(ifc, ia, p->src))
    4.26+	if(isv6mcast(p->dst) || isv6mcast(p->src) || !ipv6local(ifc, ia, 0, p->src))
    4.27 		return;
    4.28 
    4.29 	netlog(f, Logicmp, "send icmpttlexceeded6 %I -> src %I dst %I\n",
    4.30@@ -504,7 +504,7 @@ icmppkttoobig6(Fs *f, Ipifc *ifc, Block 
    4.31 	uchar ia[IPaddrlen];
    4.32 
    4.33 	p = (Ip6hdr *)bp->rp;
    4.34-	if(isv6mcast(p->dst) || isv6mcast(p->src) || !ipv6local(ifc, ia, p->src))
    4.35+	if(isv6mcast(p->dst) || isv6mcast(p->src) || !ipv6local(ifc, ia, 0, p->src))
    4.36 		return;
    4.37 
    4.38 	netlog(f, Logicmp, "send icmppkttoobig6 %I -> src %I dst %I\n",
    4.39@@ -769,7 +769,7 @@ icmpiput6(Proto *icmp, Ipifc *ifc, Block
    4.40 			/* fall through */
    4.41 
    4.42 		case Tuniproxy:
    4.43-			if(ipv6local(ifc, ia, np->src)) {
    4.44+			if(ipv6local(ifc, ia, 0, np->src)) {
    4.45 				if(arpenter(icmp->f, V6, np->src, np->lnaddr, 8*np->olen-2, ia, ifc, 0) < 0)
    4.46 					break;
    4.47 				pktflags |= Sflag;
    4.48@@ -801,7 +801,7 @@ icmpiput6(Proto *icmp, Ipifc *ifc, Block
    4.49 		lifc = iplocalonifc(ifc, np->target);
    4.50 		if(lifc != nil && lifc->tentative)
    4.51 			arpenter(icmp->f, V6, np->target, np->lnaddr, 8*np->olen-2, np->target, ifc, 0);
    4.52-		else if(ipv6local(ifc, ia, np->target))
    4.53+		else if(ipv6local(ifc, ia, 0, np->target))
    4.54 			arpenter(icmp->f, V6, np->target, np->lnaddr, 8*np->olen-2, ia, ifc, 1);
    4.55 		freeblist(bp);
    4.56 		break;
     5.1--- a/sys/src/9/ip/ip.h
     5.2+++ b/sys/src/9/ip/ip.h
     5.3@@ -567,6 +567,8 @@ extern void	addroute(Fs *f, uchar *a, uc
     5.4 extern void	remroute(Fs *f, uchar *a, uchar *mask, uchar *s, uchar *smask, uchar *gate, int type, Ipifc *ifc, char *tag);
     5.5 extern Route*	v4lookup(Fs *f, uchar *a, uchar *s, Routehint *h);
     5.6 extern Route*	v6lookup(Fs *f, uchar *a, uchar *s, Routehint *h);
     5.7+extern Route*	v4source(Fs *f, uchar *a, uchar *s);
     5.8+extern Route*	v6source(Fs *f, uchar *a, uchar *s);
     5.9 extern long	routeread(Fs *f, char*, ulong, int);
    5.10 extern long	routewrite(Fs *f, Chan*, char*, int);
    5.11 extern void	routetype(int type, char p[8]);
    5.12@@ -664,8 +666,8 @@ extern int	ipismulticast(uchar *ip);
    5.13 extern Ipifc*	findipifc(Fs*, uchar *local, uchar *remote, int type);
    5.14 extern Ipifc*	findipifcstr(Fs *f, char *s);
    5.15 extern void	findlocalip(Fs*, uchar *local, uchar *remote);
    5.16-extern int	ipv4local(Ipifc *ifc, uchar *local, uchar *remote);
    5.17-extern int	ipv6local(Ipifc *ifc, uchar *local, uchar *remote);
    5.18+extern int	ipv4local(Ipifc *ifc, uchar *local, int prefixlen, uchar *remote);
    5.19+extern int	ipv6local(Ipifc *ifc, uchar *local, int prefixlen, uchar *remote);
    5.20 extern Iplifc*	iplocalonifc(Ipifc *ifc, uchar *ip);
    5.21 extern Iplifc*	ipremoteonifc(Ipifc *ifc, uchar *ip);
    5.22 extern int	ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip);
     6.1--- a/sys/src/9/ip/ipifc.c
     6.2+++ b/sys/src/9/ip/ipifc.c
     6.3@@ -1263,10 +1263,17 @@ findprimaryipv4(Fs *f, uchar *local)
     6.4 }
     6.5 
     6.6 /*
     6.7- *  return v4 address associated with an interface close to remote
     6.8+ * ipv4local, ipv6local:
     6.9+ *  return a local address associated with an interface close to remote.
    6.10+ *  prefixlen is the number of leading bits in the local address that
    6.11+ *  have to match an interface address to be considered. this is used
    6.12+ *  by source specific routes to filter on the source address.
    6.13+ *  return non-zero on success or zero when no address was found.
    6.14+ *
    6.15+ *  for ipv4local, all addresses are 4 byte format.
    6.16  */
    6.17 int
    6.18-ipv4local(Ipifc *ifc, uchar *local, uchar *remote)
    6.19+ipv4local(Ipifc *ifc, uchar *local, int prefixlen, uchar *remote)
    6.20 {
    6.21 	Iplifc *lifc;
    6.22 	int a, b;
    6.23@@ -1275,6 +1282,10 @@ ipv4local(Ipifc *ifc, uchar *local, ucha
    6.24 	for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
    6.25 		if((lifc->type & Rv4) == 0 || ipcmp(lifc->local, IPnoaddr) == 0)
    6.26 			continue;
    6.27+
    6.28+		if(prefixlen && comprefixlen(lifc->local+IPv4off, local, IPv4addrlen) < prefixlen)
    6.29+			continue;
    6.30+		
    6.31 		a = comprefixlen(lifc->local+IPv4off, remote, IPv4addrlen);
    6.32 		if(a > b){
    6.33 			b = a;
    6.34@@ -1284,11 +1295,8 @@ ipv4local(Ipifc *ifc, uchar *local, ucha
    6.35 	return b >= 0;
    6.36 }
    6.37 
    6.38-/*
    6.39- *  return v6 address associated with an interface close to remote
    6.40- */
    6.41 int
    6.42-ipv6local(Ipifc *ifc, uchar *local, uchar *remote)
    6.43+ipv6local(Ipifc *ifc, uchar *local, int prefixlen, uchar *remote)
    6.44 {
    6.45 	struct {
    6.46 		int	atype;
    6.47@@ -1300,12 +1308,13 @@ ipv6local(Ipifc *ifc, uchar *local, ucha
    6.48 	Iplifc *lifc;
    6.49 
    6.50 	if(isv4(remote)){
    6.51-		ipmove(local, v4prefix);
    6.52-		return ipv4local(ifc, local+IPv4off, remote+IPv4off);
    6.53+		memmove(local, v4prefix, IPv4off);
    6.54+		if((prefixlen -= IPv4off*8) < 0)
    6.55+			prefixlen = 0;
    6.56+		return ipv4local(ifc, local+IPv4off, prefixlen, remote+IPv4off);
    6.57 	}
    6.58 
    6.59 	atype = v6addrtype(remote);
    6.60-	ipmove(local, v6Unspecified);
    6.61 	b.atype = unknownv6;
    6.62 	b.deprecated = 1;
    6.63 	b.comprefixlen = 0;
    6.64@@ -1315,6 +1324,9 @@ ipv6local(Ipifc *ifc, uchar *local, ucha
    6.65 		if(lifc->tentative)
    6.66 			continue;
    6.67 
    6.68+		if(prefixlen && comprefixlen(lifc->local, local, IPaddrlen) < prefixlen)
    6.69+			continue;
    6.70+
    6.71 		a.atype = v6addrtype(lifc->local);
    6.72 		a.deprecated = lifc->preflt != ~0UL && lifc->preflt < now-lifc->origint;
    6.73 		a.comprefixlen = comprefixlen(lifc->local, remote, IPaddrlen);
    6.74@@ -1347,54 +1359,22 @@ ipv6local(Ipifc *ifc, uchar *local, ucha
    6.75 	return b.atype >= atype;
    6.76 }
    6.77 
    6.78+/*
    6.79+ *  find the local address for a remote destination
    6.80+ */
    6.81 void
    6.82 findlocalip(Fs *f, uchar *local, uchar *remote)
    6.83 {
    6.84-	Route *r;
    6.85-	Iplifc *lifc;
    6.86-	Ipifc *ifc, *nifc;
    6.87-	Conv **cp;
    6.88-
    6.89-	for(cp = f->ipifc->conv; *cp != nil; cp++){
    6.90-		ifc = (Ipifc*)(*cp)->ptcl;
    6.91-		rlock(ifc);
    6.92-		for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
    6.93-			if(lifc->tentative)
    6.94-				continue;
    6.95-
    6.96-			r = v6lookup(f, remote, lifc->local, nil);
    6.97-			if(r == nil || (nifc = r->ifc) == nil)
    6.98-				continue;
    6.99-			if(r->type & Runi){
   6.100-				ipmove(local, remote);
   6.101-				runlock(ifc);
   6.102-				return;
   6.103-			}
   6.104-			if(nifc != ifc) rlock(nifc);
   6.105-			if((r->type & (Rifc|Rbcast|Rmulti|Rv4)) == Rv4){
   6.106-				ipmove(local, v4prefix);
   6.107-				if(ipv4local(nifc, local+IPv4off, r->v4.gate)){
   6.108-					if(nifc != ifc) runlock(nifc);
   6.109-					runlock(ifc);
   6.110-					return;
   6.111-				}
   6.112-			}
   6.113-			if(ipv6local(nifc, local, remote)){
   6.114-				if(nifc != ifc) runlock(nifc);
   6.115-				runlock(ifc);
   6.116-				return;
   6.117-			}
   6.118-			if(nifc != ifc) runlock(nifc);
   6.119-		}
   6.120-		runlock(ifc);
   6.121+	if(isv4(remote)) {
   6.122+		memmove(local, v4prefix, IPv4off);
   6.123+		if(v4source(f, remote+IPv4off, local+IPv4off) == nil)
   6.124+			findprimaryipv4(f, local);
   6.125+	} else {
   6.126+		if(v6source(f, remote, local) == nil)
   6.127+			findprimaryipv6(f, local);
   6.128 	}
   6.129-	if(isv4(remote))
   6.130-		findprimaryipv4(f, local);
   6.131-	else
   6.132-		findprimaryipv6(f, local);
   6.133 }
   6.134 
   6.135-
   6.136 /*
   6.137  *  see if this address is bound to the interface
   6.138  */
     7.1--- a/sys/src/9/ip/iproute.c
     7.2+++ b/sys/src/9/ip/iproute.c
     7.3@@ -535,10 +535,64 @@ remroute(Fs *f, uchar *a, uchar *mask, u
     7.4 	wunlock(&routelock);
     7.5 }
     7.6 
     7.7+/* get the outgoing interface for route r */
     7.8+static Ipifc*
     7.9+routefindipifc(Route *r, Fs *f)
    7.10+{
    7.11+	uchar local[IPaddrlen], gate[IPaddrlen];
    7.12+	Ipifc *ifc;
    7.13+	int i;
    7.14+
    7.15+	ifc = r->ifc;
    7.16+	if(ifc != nil && ifc->ifcid == r->ifcid)
    7.17+		return ifc;
    7.18+
    7.19+	if(r->type & Rsrc) {
    7.20+		if(r->type & Rv4) {
    7.21+			hnputl(local+IPv4off, r->v4.source);
    7.22+			memmove(local, v4prefix, IPv4off);
    7.23+		} else {
    7.24+			for(i = 0; i < IPllen; i++)
    7.25+				hnputl(local+4*i, r->v6.source[i]);
    7.26+		}
    7.27+	} else {
    7.28+		ipmove(local, IPnoaddr);
    7.29+	}
    7.30+
    7.31+	if(r->type & Rifc) {
    7.32+		if(r->type & Rv4) {
    7.33+			hnputl(gate+IPv4off, r->v4.address);
    7.34+			memmove(gate, v4prefix, IPv4off);
    7.35+		} else {
    7.36+			for(i = 0; i < IPllen; i++)
    7.37+				hnputl(gate+4*i, r->v6.address[i]);
    7.38+		}
    7.39+	} else {
    7.40+		if(r->type & Rv4)
    7.41+			v4tov6(gate, r->v4.gate);
    7.42+		else
    7.43+			ipmove(gate, r->v6.gate);
    7.44+	}
    7.45+
    7.46+	if((ifc = findipifc(f, local, gate, r->type)) == nil)
    7.47+		return nil;
    7.48+
    7.49+	r->ifc = ifc;
    7.50+	r->ifcid = ifc->ifcid;
    7.51+	return ifc;
    7.52+}
    7.53+
    7.54+/*
    7.55+ * v4lookup, v6lookup:
    7.56+ *  lookup a route to destination address a from source address s
    7.57+ *  and return the route. returns nil if no route was found.
    7.58+ *  an optional Routehint can be passed in rh to cache the lookup.
    7.59+ *
    7.60+ *  for v4lookup, addresses are in 4 byte format.
    7.61+ */
    7.62 Route*
    7.63 v4lookup(Fs *f, uchar *a, uchar *s, Routehint *rh)
    7.64 {
    7.65-	uchar local[IPaddrlen], gate[IPaddrlen];
    7.66 	ulong la, ls;
    7.67 	Route *p, *q;
    7.68 	Ipifc *ifc;
    7.69@@ -577,23 +631,9 @@ v4lookup(Fs *f, uchar *a, uchar *s, Rout
    7.70 		p = p->mid;
    7.71 	}
    7.72 
    7.73-	if(q == nil || q->ref == 0)
    7.74+	if(q == nil || q->ref == 0 || routefindipifc(q, f) == nil)
    7.75 		return nil;
    7.76 
    7.77-	if(q->ifc == nil || q->ifcid != q->ifc->ifcid){
    7.78-		if(q->type & Rifc) {
    7.79-			hnputl(gate+IPv4off, q->v4.address);
    7.80-			memmove(gate, v4prefix, IPv4off);
    7.81-		} else
    7.82-			v4tov6(gate, q->v4.gate);
    7.83-		v4tov6(local, s);
    7.84-		ifc = findipifc(f, local, gate, q->type);
    7.85-		if(ifc == nil)
    7.86-			return nil;
    7.87-		q->ifc = ifc;
    7.88-		q->ifcid = ifc->ifcid;
    7.89-	}
    7.90-
    7.91 	if(rh != nil){
    7.92 		rh->r = q;
    7.93 		rh->rgen = v4routegeneration;
    7.94@@ -605,7 +645,6 @@ v4lookup(Fs *f, uchar *a, uchar *s, Rout
    7.95 Route*
    7.96 v6lookup(Fs *f, uchar *a, uchar *s, Routehint *rh)
    7.97 {
    7.98-	uchar gate[IPaddrlen];
    7.99 	ulong la[IPllen], ls[IPllen];
   7.100 	ulong x, y;
   7.101 	Route *p, *q;
   7.102@@ -684,22 +723,9 @@ v6lookup(Fs *f, uchar *a, uchar *s, Rout
   7.103 next:		;
   7.104 	}
   7.105 
   7.106-	if(q == nil || q->ref == 0)
   7.107+	if(q == nil || q->ref == 0 || routefindipifc(q, f) == nil)
   7.108 		return nil;
   7.109 
   7.110-	if(q->ifc == nil || q->ifcid != q->ifc->ifcid){
   7.111-		if(q->type & Rifc) {
   7.112-			for(h = 0; h < IPllen; h++)
   7.113-				hnputl(gate+4*h, q->v6.address[h]);
   7.114-			ifc = findipifc(f, s, gate, q->type);
   7.115-		} else
   7.116-			ifc = findipifc(f, s, q->v6.gate, q->type);
   7.117-		if(ifc == nil)
   7.118-			return nil;
   7.119-		q->ifc = ifc;
   7.120-		q->ifcid = ifc->ifcid;
   7.121-	}
   7.122-
   7.123 	if(rh != nil){
   7.124 		rh->r = q;
   7.125 		rh->rgen = v6routegeneration;
   7.126@@ -708,6 +734,119 @@ next:		;
   7.127 	return q;
   7.128 }
   7.129 
   7.130+/*
   7.131+ * v4source, v6source:
   7.132+ *  lookup a route to destination address a and also find
   7.133+ *  a suitable source address s on the outgoing interface.
   7.134+ *  return the route on success or nil when no route
   7.135+ *  was found.
   7.136+ *
   7.137+ *  for v4source, addresses are in 4 byte format.
   7.138+ */
   7.139+Route*
   7.140+v4source(Fs *f, uchar *a, uchar *s)
   7.141+{
   7.142+	uchar src[IPv4addrlen];
   7.143+	int splen;
   7.144+	ulong x, la;
   7.145+	Route *p, *q;
   7.146+	Ipifc *ifc;
   7.147+
   7.148+	q = nil;
   7.149+	la = nhgetl(a);
   7.150+	rlock(&routelock);
   7.151+	for(p = f->v4root[V4H(la)]; p != nil;){
   7.152+		if(la < p->v4.address){
   7.153+			p = p->left;
   7.154+			continue;
   7.155+		}
   7.156+		if(la > p->v4.endaddress){
   7.157+			p = p->right;
   7.158+			continue;
   7.159+		}
   7.160+		splen = 0;
   7.161+		if(p->type & Rsrc){
   7.162+			/* calculate local prefix length for source specific routes */
   7.163+			for(x = ~(p->v4.endsource ^ p->v4.source); x & 0x80000000UL; x <<= 1)
   7.164+				splen++;
   7.165+			hnputl(src, p->v4.source);
   7.166+		}
   7.167+		if((ifc = routefindipifc(p, f)) == nil
   7.168+		|| !ipv4local(ifc, src, splen, (p->type & (Rifc|Rbcast|Rmulti|Rv4))==Rv4? p->v4.gate: a)){
   7.169+			p = p->mid;
   7.170+			continue;
   7.171+		}
   7.172+		memmove(s, src, IPv4addrlen);
   7.173+		q = p;
   7.174+		p = p->mid;
   7.175+	}
   7.176+	runlock(&routelock);
   7.177+	return q;
   7.178+}
   7.179+
   7.180+Route*
   7.181+v6source(Fs *f, uchar *a, uchar *s)
   7.182+{
   7.183+	uchar src[IPaddrlen];
   7.184+	int splen, h;
   7.185+	ulong x, y, la[IPllen];
   7.186+	Route *p, *q;
   7.187+	Ipifc *ifc;
   7.188+
   7.189+	q = nil;
   7.190+	for(h = 0; h < IPllen; h++)
   7.191+		la[h] = nhgetl(a+4*h);
   7.192+	rlock(&routelock);
   7.193+	for(p = f->v6root[V6H(la)]; p != nil;){
   7.194+		for(h = 0; h < IPllen; h++){
   7.195+			x = la[h];
   7.196+			y = p->v6.address[h];
   7.197+			if(x == y)
   7.198+				continue;
   7.199+			if(x < y){
   7.200+				p = p->left;
   7.201+				goto next;
   7.202+			}
   7.203+			break;
   7.204+		}
   7.205+		for(h = 0; h < IPllen; h++){
   7.206+			x = la[h];
   7.207+			y = p->v6.endaddress[h];
   7.208+			if(x == y)
   7.209+				continue;
   7.210+			if(x > y){
   7.211+				p = p->right;
   7.212+				goto next;
   7.213+			}
   7.214+			break;
   7.215+		}
   7.216+		splen = 0;
   7.217+		if(p->type & Rsrc){
   7.218+			/* calculate local prefix length for source specific routes */
   7.219+			for(h = 0; h < IPllen; h++){
   7.220+				hnputl(src+4*h, p->v6.source[h]);
   7.221+				if((x = ~(p->v6.endsource[h] ^ p->v6.source[h])) != ~0UL){
   7.222+					for(; x & 0x80000000UL; x <<= 1)
   7.223+						splen++;
   7.224+					break;
   7.225+				}
   7.226+				splen += 32;
   7.227+			}
   7.228+		}
   7.229+		if((ifc = routefindipifc(p, f)) == nil
   7.230+		|| !ipv6local(ifc, src, splen, a)){
   7.231+			p = p->mid;
   7.232+			continue;
   7.233+		}
   7.234+		ipmove(s, src);
   7.235+		q = p;
   7.236+		p = p->mid;
   7.237+next:		;
   7.238+	}
   7.239+	runlock(&routelock);
   7.240+	return q;
   7.241+}
   7.242+
   7.243 static int
   7.244 parseroutetype(char *p)
   7.245 {
     8.1--- a/sys/src/9/ip/rudp.c
     8.2+++ b/sys/src/9/ip/rudp.c
     8.3@@ -559,15 +559,12 @@ rudpiput(Proto *rudp, Ipifc *ifc, Block 
     8.4 	default:
     8.5 		/* connection oriented rudp */
     8.6 		if(ipcmp(c->raddr, IPnoaddr) == 0){
     8.7-			/* save the src address in the conversation */
     8.8+			/* reply with the same ip address (if not broadcast) */
     8.9+			if(ipforme(f, laddr) != Runi)
    8.10+				ipv6local(ifc, laddr, 0, raddr);
    8.11+			ipmove(c->laddr, laddr);
    8.12 		 	ipmove(c->raddr, raddr);
    8.13 			c->rport = rport;
    8.14-
    8.15-			/* reply with the same ip address (if not broadcast) */
    8.16-			if(ipforme(f, laddr) != Runi)
    8.17-				ipv6local(ifc, c->laddr, c->raddr);
    8.18-			else
    8.19-				ipmove(c->laddr, laddr);
    8.20 		}
    8.21 		break;
    8.22 	}
     9.1--- a/sys/src/9/ip/udp.c
     9.2+++ b/sys/src/9/ip/udp.c
     9.3@@ -423,7 +423,7 @@ udpiput(Proto *udp, Ipifc *ifc, Block *b
     9.4 		if(ucb->headers == 0){
     9.5 			/* create a new conversation */
     9.6 			if(ipforme(f, laddr) != Runi)
     9.7-				ipv6local(ifc, laddr, raddr);
     9.8+				ipv6local(ifc, laddr, 0, raddr);
     9.9 			c = Fsnewcall(c, raddr, rport, laddr, lport, version);
    9.10 			if(c == nil){
    9.11 				qunlock(udp);