From 638b4a1ec113adebdd6a85d647574a46e0b7feab Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Thu, 19 Apr 2018 01:08:51 +0200 Subject: [PATCH] devip: add "reflect" ctl message, fix memory leaks in icmpv6, fix source address for icmpttlexceeded, cleanup --- sys/man/3/ip | 13 +++++---- sys/src/9/ip/arp.c | 3 ++- sys/src/9/ip/icmp.c | 11 +++++--- sys/src/9/ip/icmp6.c | 63 ++++++++++++++------------------------------ sys/src/9/ip/ip.c | 28 +++++++++----------- sys/src/9/ip/ip.h | 13 ++++----- sys/src/9/ip/ipifc.c | 20 +++++++------- sys/src/9/ip/ipv6.c | 30 +++++++++------------ sys/src/9/ip/ipv6.h | 2 +- sys/src/9/ip/udp.c | 2 +- 10 files changed, 80 insertions(+), 105 deletions(-) diff --git a/sys/man/3/ip b/sys/man/3/ip index 10e48d371..76430cd01 100644 --- a/sys/man/3/ip +++ b/sys/man/3/ip @@ -194,16 +194,19 @@ Set the maximum transfer unit for this device to 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 diff --git a/sys/src/9/ip/arp.c b/sys/src/9/ip/arp.c index 894ed922f..72e71a9f2 100644 --- a/sys/src/9/ip/arp.c +++ b/sys/src/9/ip/arp.c @@ -629,7 +629,8 @@ dodrops: 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; diff --git a/sys/src/9/ip/icmp.c b/sys/src/9/ip/icmp.c index 2a2d3e21b..0da844a17 100644 --- a/sys/src/9/ip/icmp.c +++ b/sys/src/9/ip/icmp.c @@ -215,22 +215,25 @@ ip4me(Fs *f, uchar ip4[4]) } 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; diff --git a/sys/src/9/ip/icmp6.c b/sys/src/9/ip/icmp6.c index c246b6edc..dc2abe497 100644 --- a/sys/src/9/ip/icmp6.c +++ b/sys/src/9/ip/icmp6.c @@ -426,7 +426,7 @@ icmpna(Fs *f, uchar* src, uchar* dst, uchar* targ, uchar* mac, uchar flags) } 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 @@ icmphostunr(Fs *f, Ipifc *ifc, Block *bp, int code, int free) 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 @@ icmphostunr(Fs *f, Ipifc *ifc, Block *bp, int code, int free) 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 @@ icmpttlexceeded6(Fs *f, Ipifc *ifc, Block *bp) 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 @@ icmppkttoobig6(Fs *f, Ipifc *ifc, Block *bp) 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; diff --git a/sys/src/9/ip/ip.c b/sys/src/9/ip/ip.c index d296c2ed0..948125737 100644 --- a/sys/src/9/ip/ip.c +++ b/sys/src/9/ip/ip.c @@ -333,8 +333,7 @@ ipiput4(Fs *f, Ipifc *ifc, Block *bp) 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 @@ ipiput4(Fs *f, Ipifc *ifc, Block *bp) 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,33 +362,30 @@ ipiput4(Fs *f, Ipifc *ifc, Block *bp) 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 */ 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 @@ if(r->ifc == nil) panic("nil route ifc"); } ip->stats[InDiscards]++; ip->stats[InUnknownProtos]++; +drop: freeblist(bp); } diff --git a/sys/src/9/ip/ip.h b/sys/src/9/ip/ip.h index 92ed960f1..6047acb2a 100644 --- a/sys/src/9/ip/ip.h +++ b/sys/src/9/ip/ip.h @@ -258,7 +258,7 @@ struct Iplifc 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 @@ struct Ipifc 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 char* ipifcadd6(Ipifc *ifc, char**argv, int argc); 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*); diff --git a/sys/src/9/ip/ipifc.c b/sys/src/9/ip/ipifc.c index 8e316446c..371812127 100644 --- a/sys/src/9/ip/ipifc.c +++ b/sys/src/9/ip/ipifc.c @@ -231,6 +231,8 @@ ipifcunbind(Ipifc *ifc) (*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 @@ ipifccreate(Conv *c) 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 @@ static char* 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 @@ ipifcctl(Conv* c, char **argv, int argc) 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) diff --git a/sys/src/9/ip/ipv6.c b/sys/src/9/ip/ipv6.c index 7fb1d1323..a2836d7ae 100644 --- a/sys/src/9/ip/ipv6.c +++ b/sys/src/9/ip/ipv6.c @@ -116,7 +116,7 @@ ipoput6(Fs *f, Block *bp, int gating, int ttl, int tos, Routehint *rh) 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,43 +248,39 @@ ipiput6(Fs *f, Ipifc *ifc, Block *bp) if(tentative && h->proto != ICMPv6) { print("tentative addr, drop\n"); - freeblist(bp); - return; + goto drop; } /* Check header version */ 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 */ 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 @@ ipiput6(Fs *f, Ipifc *ifc, Block *bp) 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 @@ ipiput6(Fs *f, Ipifc *ifc, Block *bp) ip->stats[InDiscards]++; ip->stats[InUnknownProtos]++; +drop: freeblist(bp); } diff --git a/sys/src/9/ip/ipv6.h b/sys/src/9/ip/ipv6.h index e4a0144b4..f7a408216 100644 --- a/sys/src/9/ip/ipv6.h +++ b/sys/src/9/ip/ipv6.h @@ -185,4 +185,4 @@ void icmpns(Fs *f, uchar* src, int suni, uchar* targ, int tuni, uchar* mac); 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); diff --git a/sys/src/9/ip/udp.c b/sys/src/9/ip/udp.c index fbaabd634..cfa002116 100644 --- a/sys/src/9/ip/udp.c +++ b/sys/src/9/ip/udp.c @@ -404,7 +404,7 @@ udpiput(Proto *udp, Ipifc *ifc, Block *bp) 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);