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);