shithub: riscv

Download patch

ref: 638b4a1ec113adebdd6a85d647574a46e0b7feab
parent: 691370a08dbfda305f0302023618211ffbfbce7a
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Wed Apr 18 21:08:51 EDT 2018

devip: add "reflect" ctl message, fix memory leaks in icmpv6, fix source address for icmpttlexceeded, cleanup

--- a/sys/man/3/ip
+++ b/sys/man/3/ip
@@ -194,16 +194,19 @@
 The mtu is the maximum size of the packet including any
 medium-specific headers.
 .TP
-.BI reassemble
-Reassemble IP fragments before forwarding to this interface
-.TP
 .BI iprouting\  n
 Allow
 .RI ( n
 is missing or non-zero) or disallow
 .RI ( n
-is 0) forwarding packets between this interface and
-others.
+is 0) forwarding packets between this interface and others.
+.TP
+.BI reflect\  n
+When forwarding, allow packets from this interface to be
+echoed back on the same interface.
+.TP
+.BI reassemble\  n
+Reassemble IP fragments before forwarding to this interface
 .
 .\" remainder from netif.c (thus called from devether.c),
 .\" except add6 and ra6 from ipifc.c
--- a/sys/src/9/ip/arp.c
+++ b/sys/src/9/ip/arp.c
@@ -629,7 +629,8 @@
 
 	for(; xp != nil; xp = next){
 		next = xp->list;
-		icmphostunr(f, ifc, xp, Icmp6_adr_unreach, 1);
+		icmphostunr6(f, ifc, xp, Icmp6_adr_unreach, 1);
+		freeblist(xp);
 	}
 
 	return nrxt;
--- a/sys/src/9/ip/icmp.c
+++ b/sys/src/9/ip/icmp.c
@@ -215,22 +215,25 @@
 }
 
 void
-icmpttlexceeded(Fs *f, uchar *ia, Block *bp)
+icmpttlexceeded(Fs *f, Ipifc *ifc, Block *bp)
 {
 	Block	*nbp;
 	Icmp	*p, *np;
+	uchar	ia[IPv4addrlen];
 
 	p = (Icmp *)bp->rp;
-	if(!ip4reply(f, p->src))
+	if(!ip4reply(f, p->src) || !ipv4local(ifc, ia, p->src))
 		return;
 
-	netlog(f, Logicmp, "sending icmpttlexceeded -> %V\n", p->src);
+	netlog(f, Logicmp, "sending icmpttlexceeded %V -> src %V dst %V\n",
+		ia, p->src, p->dst);
+
 	nbp = allocb(ICMP_IPSIZE + ICMP_HDRSIZE + ICMP_IPSIZE + 8);
 	nbp->wp += ICMP_IPSIZE + ICMP_HDRSIZE + ICMP_IPSIZE + 8;
 	np = (Icmp *)nbp->rp;
 	np->vihl = IP_VER4;
+	memmove(np->src, ia, sizeof(np->src));
 	memmove(np->dst, p->src, sizeof(np->dst));
-	v6tov4(np->src, ia);
 	memmove(np->data, bp->rp, ICMP_IPSIZE + 8);
 	np->type = TimeExceed;
 	np->code = 0;
--- a/sys/src/9/ip/icmp6.c
+++ b/sys/src/9/ip/icmp6.c
@@ -426,7 +426,7 @@
 }
 
 void
-icmphostunr(Fs *f, Ipifc *ifc, Block *bp, int code, int free)
+icmphostunr6(Fs *f, Ipifc *ifc, Block *bp, int code, int tome)
 {
 	int osz = BLEN(bp);
 	int sz = MIN(IPICMPSZ + osz, v6MINTU);
@@ -435,25 +435,18 @@
 	Ip6hdr *p;
 	Proto *icmp = f->t2p[ICMPv6];
 	Icmppriv6 *ipriv = icmp->priv;
+	uchar ia[IPaddrlen];
 
 	p = (Ip6hdr *)bp->rp;
+	if(isv6mcast(p->src) || !ipv6local(ifc, ia, p->src))
+		return;
 
-	if(isv6mcast(p->src))
-		goto freebl;
+	netlog(f, Logicmp, "send icmphostunr %I -> src %I dst %I\n",
+		ia, p->src, p->dst);
 
 	nbp = newIPICMP(sz);
 	np = (IPICMP *)nbp->rp;
-
-	rlock(ifc);
-	if(ipv6local(ifc, np->src, p->src))
-		netlog(f, Logicmp, "send icmphostunr -> src %I dst %I\n", p->src, p->dst);
-	else {
-		netlog(f, Logicmp, "icmphostunr fail -> src %I dst %I\n", p->src, p->dst);
-		runlock(ifc);
-		freeblist(nbp);
-		goto freebl;
-	}
-
+	ipmove(np->src, ia);
 	ipmove(np->dst, p->src);
 	np->type = UnreachableV6;
 	np->code = code;
@@ -463,14 +456,10 @@
 	np->vcf[0] = 0x06 << 4;
 	ipriv->out[UnreachableV6]++;
 
-	if(free)
+	if(tome)
 		ipiput6(f, ifc, nbp);
 	else 
 		ipoput6(f, nbp, 0, MAXTTL, DFLTTOS, nil);
-	runlock(ifc);
-freebl:
-	if(free)
-		freeblist(bp);
 }
 
 void
@@ -483,24 +472,18 @@
 	Ip6hdr *p;
 	Proto *icmp = f->t2p[ICMPv6];
 	Icmppriv6 *ipriv = icmp->priv;
+	uchar ia[IPaddrlen];
 
 	p = (Ip6hdr *)bp->rp;
-
-	if(isv6mcast(p->src))
+	if(isv6mcast(p->src) || !ipv6local(ifc, ia, p->src))
 		return;
 
+	netlog(f, Logicmp, "send icmpttlexceeded6 %I -> src %I dst %I\n",
+		ia, p->src, p->dst);
+
 	nbp = newIPICMP(sz);
 	np = (IPICMP *) nbp->rp;
-
-	if(ipv6local(ifc, np->src, p->src))
-		netlog(f, Logicmp, "send icmpttlexceeded6 -> src %I dst %I\n",
-			p->src, p->dst);
-	else {
-		netlog(f, Logicmp, "icmpttlexceeded6 fail -> src %I dst %I\n",
-			p->src, p->dst);
-		return;
-	}
-
+	ipmove(np->src, ia);
 	ipmove(np->dst, p->src);
 	np->type = TimeExceedV6;
 	np->code = 0;
@@ -522,24 +505,18 @@
 	Ip6hdr *p;
 	Proto *icmp = f->t2p[ICMPv6];
 	Icmppriv6 *ipriv = icmp->priv;
+	uchar ia[IPaddrlen];
 
 	p = (Ip6hdr *)bp->rp;
-
-	if(isv6mcast(p->src))
+	if(isv6mcast(p->src) || !ipv6local(ifc, ia, p->src))
 		return;
 
+	netlog(f, Logicmp, "send icmppkttoobig6 %I -> src %I dst %I\n",
+		ia, p->src, p->dst);
+
 	nbp = newIPICMP(sz);
 	np = (IPICMP *)nbp->rp;
-
-	if(ipv6local(ifc, np->src, p->src))
-		netlog(f, Logicmp, "send icmppkttoobig6 -> src %I dst %I\n",
-			p->src, p->dst);
-	else {
-		netlog(f, Logicmp, "icmppkttoobig6 fail -> src %I dst %I\n",
-			p->src, p->dst);
-		return;
-	}
-
+	ipmove(np->src, ia);
 	ipmove(np->dst, p->src);
 	np->type = PacketTooBigV6;
 	np->code = 0;
--- a/sys/src/9/ip/ip.c
+++ b/sys/src/9/ip/ip.c
@@ -333,8 +333,7 @@
 	if((bp->flag & Bipck) == 0 && ipcsum(&h->vihl)) {
 		ip->stats[InHdrErrors]++;
 		netlog(f, Logip, "ip: checksum error %V\n", h->src);
-		freeblist(bp);
-		return;
+		goto drop;
 	}
 	v4tov6(v6dst, h->dst);
 	notforme = ipforme(f, v6dst) == 0;
@@ -345,8 +344,7 @@
 		if(hl < (IP_HLEN4<<2)) {
 			ip->stats[InHdrErrors]++;
 			netlog(f, Logip, "ip: %V bad hivl %ux\n", h->src, h->vihl);
-			freeblist(bp);
-			return;
+			goto drop;
 		}
 		/* If this is not routed strip off the options */
 		if(notforme == 0) {
@@ -364,19 +362,18 @@
 	if(notforme) {
 		Route *r;
 		Routehint rh;
+		Ipifc *toifc;
 
-		if(!ip->iprouting){
-			freeblist(bp);
-			return;
-		}
+		if(!ip->iprouting)
+			goto drop;
 
 		/* don't forward to source's network */
 		rh.r = nil;
 		r = v4lookup(f, h->dst, h->src, &rh);
-		if(r == nil || r->ifc == ifc){
+		if(r == nil || (toifc = r->ifc) == nil
+		|| (toifc == ifc && !ifc->reflect)){
 			ip->stats[OutDiscards]++;
-			freeblist(bp);
-			return;
+			goto drop;
 		}
 
 		/* don't forward if packet has timed out */
@@ -383,14 +380,12 @@
 		hop = h->ttl;
 		if(hop < 1) {
 			ip->stats[InHdrErrors]++;
-			icmpttlexceeded(f, ifc->lifc->local, bp);
-			freeblist(bp);
-			return;
+			icmpttlexceeded(f, ifc, bp);
+			goto drop;
 		}
 
 		/* reassemble if the interface expects it */
-if(r->ifc == nil) panic("nil route ifc");
-		if(r->ifc->reassemble){
+		if(toifc->reassemble){
 			frag = nhgets(h->frag);
 			if(frag & ~IP_DF) {
 				h->tos = 0;
@@ -434,6 +429,7 @@
 	}
 	ip->stats[InDiscards]++;
 	ip->stats[InUnknownProtos]++;
+drop:
 	freeblist(bp);
 }
 
--- a/sys/src/9/ip/ip.h
+++ b/sys/src/9/ip/ip.h
@@ -258,7 +258,7 @@
 	uchar	mask[IPaddrlen];
 	uchar	remote[IPaddrlen];
 	uchar	net[IPaddrlen];
-	uchar	type;		/* ruoute type */
+	uchar	type;		/* route type */
 	uchar	tentative;	/* =1 => v6 dup disc on, =0 => confirmed unique */
 	uchar	onlink;		/* =1 => onlink, =0 offlink. */
 	uchar	autoflag;	/* v6 autonomous flag */
@@ -310,14 +310,11 @@
 	int	maxtu;		/* Maximum transfer unit */
 	int	mintu;		/* Minumum tranfer unit */
 	void	*arg;		/* medium specific */
-	int	reassemble;	/* reassemble IP packets before forwarding */
 
-	/* these are used so that we can unbind on the fly */
-	Lock	idlock;
+	uchar	reflect;	/* allow forwarded packets to go out the same interface */
+	uchar	reassemble;	/* reassemble IP packets before forwarding to this interface */
+	
 	uchar	ifcid;		/* incremented each 'bind/unbind/add/remove' */
-	int	ref;		/* number of proc's using this ipifc */
-	Rendez	wait;		/* where unbinder waits for ref == 0 */
-	int	unbinding;
 
 	uchar	mac[MAClen];	/* MAC address */
 
@@ -680,7 +677,7 @@
 extern void	iprouting(Fs*, int);
 extern void	icmpnoconv(Fs*, Block*);
 extern void	icmpcantfrag(Fs*, Block*, int);
-extern void	icmpttlexceeded(Fs*, uchar*, Block*);
+extern void	icmpttlexceeded(Fs*, Ipifc*, Block*);
 extern ushort	ipcsum(uchar*);
 extern void	ipiput4(Fs*, Ipifc*, Block*);
 extern void	ipiput6(Fs*, Ipifc*, Block*);
--- a/sys/src/9/ip/ipifc.c
+++ b/sys/src/9/ip/ipifc.c
@@ -231,6 +231,8 @@
 		(*ifc->m->unbind)(ifc);
 	memset(ifc->dev, 0, sizeof(ifc->dev));
 	ifc->arg = nil;
+
+	ifc->reflect = 0;
 	ifc->reassemble = 0;
 
 	/* close queues to stop queuing of packets */
@@ -357,8 +359,8 @@
 		error(Enomem);
 	ifc = (Ipifc*)c->ptcl;
 	ifc->conv = c;
-	ifc->unbinding = 0;
 	ifc->m = nil;
+	ifc->reflect = 0;
 	ifc->reassemble = 0;
 }
 
@@ -764,7 +766,6 @@
 ipifcctl(Conv* c, char **argv, int argc)
 {
 	Ipifc *ifc;
-	int i;
 
 	ifc = (Ipifc*)c->ptcl;
 	if(strcmp(argv[0], "add") == 0)
@@ -777,15 +778,16 @@
 		return ipifcunbind(ifc);
 	else if(strcmp(argv[0], "mtu") == 0)
 		return ipifcsetmtu(ifc, argv, argc);
-	else if(strcmp(argv[0], "reassemble") == 0){
-		ifc->reassemble = 1;
+	else if(strcmp(argv[0], "iprouting") == 0){
+		iprouting(c->p->f, argc>1? atoi(argv[1]): 1);
 		return nil;
 	}
-	else if(strcmp(argv[0], "iprouting") == 0){
-		i = 1;
-		if(argc > 1)
-			i = atoi(argv[1]);
-		iprouting(c->p->f, i);
+	else if(strcmp(argv[0], "reflect") == 0){
+		ifc->reflect = argc>1? atoi(argv[1]): 1;
+		return nil;
+	}
+	else if(strcmp(argv[0], "reassemble") == 0){
+		ifc->reassemble = argc>1? atoi(argv[1]): 1;
 		return nil;
 	}
 	else if(strcmp(argv[0], "add6") == 0)
--- a/sys/src/9/ip/ipv6.c
+++ b/sys/src/9/ip/ipv6.c
@@ -116,7 +116,7 @@
 		return 0;
 	}
 
-	if(gating && ifc->reassemble <= 0) {
+	if(gating && !ifc->reassemble) {
 		/*
 		 * v6 intermediate nodes are not supposed to fragment pkts;
 		 * we fragment if ifc->reassemble is turned on; an exception
@@ -248,8 +248,7 @@
 
 	if(tentative && h->proto != ICMPv6) {
 		print("tentative addr, drop\n");
-		freeblist(bp);
-		return;
+		goto drop;
 	}
 
 	/* Check header version */
@@ -256,8 +255,7 @@
 	if(BLKIPVER(bp) != IP_VER6) {
 		ip->stats[InHdrErrors]++;
 		netlog(f, Logip, "ip: bad version %ux\n", (h->vcf[0]&0xF0)>>2);
-		freeblist(bp);
-		return;
+		goto drop;
 	}
 
 	/* route */
@@ -264,27 +262,25 @@
 	if(notforme) {
 		Route *r;
 		Routehint rh;
+		Ipifc *toifc;
 
-		if(!ip->iprouting){
-			freeblist(bp);
-			return;
-		}
+		if(!ip->iprouting)
+			goto drop;
 
 		/* don't forward to link-local destinations */
 		if(islinklocal(h->dst) ||
 		   (isv6mcast(h->dst) && (h->dst[1]&0xF) <= Link_local_scop)){
 			ip->stats[OutDiscards]++;
-			freeblist(bp);
-			return;
+			goto drop;
 		}
 			
 		/* don't forward to source's network */
 		rh.r = nil;
 		r  = v6lookup(f, h->dst, h->src, &rh);
-		if(r == nil || (r->type & Rv4) != 0 || r->ifc == ifc){
+		if(r == nil || (toifc = r->ifc) == nil || (r->type & Rv4) != 0
+		|| (toifc == ifc && !ifc->reflect)){
 			ip->stats[OutDiscards]++;
-			freeblist(bp);
-			return;
+			goto drop;
 		}
 
 		/* don't forward if packet has timed out */
@@ -292,12 +288,11 @@
 		if(hop < 1) {
 			ip->stats[InHdrErrors]++;
 			icmpttlexceeded6(f, ifc, bp);
-			freeblist(bp);
-			return;
+			goto drop;
 		}
 
 		/* process headers & reassemble if the interface expects it */
-		bp = procxtns(ip, bp, r->ifc->reassemble);
+		bp = procxtns(ip, bp, toifc->reassemble);
 		if(bp == nil)
 			return;
 
@@ -325,6 +320,7 @@
 
 	ip->stats[InDiscards]++;
 	ip->stats[InUnknownProtos]++;
+drop:
 	freeblist(bp);
 }
 
--- a/sys/src/9/ip/ipv6.h
+++ b/sys/src/9/ip/ipv6.h
@@ -185,4 +185,4 @@
 void icmpna(Fs *f, uchar* src, uchar* dst, uchar* targ, uchar* mac, uchar flags);
 void icmpttlexceeded6(Fs *f, Ipifc *ifc, Block *bp);
 void icmppkttoobig6(Fs *f, Ipifc *ifc, Block *bp);
-void icmphostunr(Fs *f, Ipifc *ifc, Block *bp, int code, int free);
+void icmphostunr6(Fs *f, Ipifc *ifc, Block *bp, int code, int tome);
--- a/sys/src/9/ip/udp.c
+++ b/sys/src/9/ip/udp.c
@@ -404,7 +404,7 @@
 			icmpnoconv(f, bp);
 			break;
 		case V6:
-			icmphostunr(f, ifc, bp, Icmp6_port_unreach, 0);
+			icmphostunr6(f, ifc, bp, Icmp6_port_unreach, 0);
 			break;
 		default:
 			panic("udpiput2: version %d", version);