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

This commit is contained in:
cinap_lenrek 2018-04-19 01:08:51 +02:00
parent 691370a08d
commit 638b4a1ec1
10 changed files with 80 additions and 105 deletions

View file

@ -194,16 +194,19 @@ Set the maximum transfer unit for this device to
The mtu is the maximum size of the packet including any The mtu is the maximum size of the packet including any
medium-specific headers. medium-specific headers.
.TP .TP
.BI reassemble
Reassemble IP fragments before forwarding to this interface
.TP
.BI iprouting\ n .BI iprouting\ n
Allow Allow
.RI ( n .RI ( n
is missing or non-zero) or disallow is missing or non-zero) or disallow
.RI ( n .RI ( n
is 0) forwarding packets between this interface and is 0) forwarding packets between this interface and others.
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), .\" remainder from netif.c (thus called from devether.c),
.\" except add6 and ra6 from ipifc.c .\" except add6 and ra6 from ipifc.c

View file

@ -629,7 +629,8 @@ dodrops:
for(; xp != nil; xp = next){ for(; xp != nil; xp = next){
next = xp->list; next = xp->list;
icmphostunr(f, ifc, xp, Icmp6_adr_unreach, 1); icmphostunr6(f, ifc, xp, Icmp6_adr_unreach, 1);
freeblist(xp);
} }
return nrxt; return nrxt;

View file

@ -215,22 +215,25 @@ ip4me(Fs *f, uchar ip4[4])
} }
void void
icmpttlexceeded(Fs *f, uchar *ia, Block *bp) icmpttlexceeded(Fs *f, Ipifc *ifc, Block *bp)
{ {
Block *nbp; Block *nbp;
Icmp *p, *np; Icmp *p, *np;
uchar ia[IPv4addrlen];
p = (Icmp *)bp->rp; p = (Icmp *)bp->rp;
if(!ip4reply(f, p->src)) if(!ip4reply(f, p->src) || !ipv4local(ifc, ia, p->src))
return; 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 = allocb(ICMP_IPSIZE + ICMP_HDRSIZE + ICMP_IPSIZE + 8);
nbp->wp += ICMP_IPSIZE + ICMP_HDRSIZE + ICMP_IPSIZE + 8; nbp->wp += ICMP_IPSIZE + ICMP_HDRSIZE + ICMP_IPSIZE + 8;
np = (Icmp *)nbp->rp; np = (Icmp *)nbp->rp;
np->vihl = IP_VER4; np->vihl = IP_VER4;
memmove(np->src, ia, sizeof(np->src));
memmove(np->dst, p->src, sizeof(np->dst)); memmove(np->dst, p->src, sizeof(np->dst));
v6tov4(np->src, ia);
memmove(np->data, bp->rp, ICMP_IPSIZE + 8); memmove(np->data, bp->rp, ICMP_IPSIZE + 8);
np->type = TimeExceed; np->type = TimeExceed;
np->code = 0; np->code = 0;

View file

@ -426,7 +426,7 @@ icmpna(Fs *f, uchar* src, uchar* dst, uchar* targ, uchar* mac, uchar flags)
} }
void 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 osz = BLEN(bp);
int sz = MIN(IPICMPSZ + osz, v6MINTU); int sz = MIN(IPICMPSZ + osz, v6MINTU);
@ -435,25 +435,18 @@ icmphostunr(Fs *f, Ipifc *ifc, Block *bp, int code, int free)
Ip6hdr *p; Ip6hdr *p;
Proto *icmp = f->t2p[ICMPv6]; Proto *icmp = f->t2p[ICMPv6];
Icmppriv6 *ipriv = icmp->priv; Icmppriv6 *ipriv = icmp->priv;
uchar ia[IPaddrlen];
p = (Ip6hdr *)bp->rp; p = (Ip6hdr *)bp->rp;
if(isv6mcast(p->src) || !ipv6local(ifc, ia, p->src))
return;
if(isv6mcast(p->src)) netlog(f, Logicmp, "send icmphostunr %I -> src %I dst %I\n",
goto freebl; ia, p->src, p->dst);
nbp = newIPICMP(sz); nbp = newIPICMP(sz);
np = (IPICMP *)nbp->rp; np = (IPICMP *)nbp->rp;
ipmove(np->src, ia);
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->dst, p->src); ipmove(np->dst, p->src);
np->type = UnreachableV6; np->type = UnreachableV6;
np->code = code; np->code = code;
@ -463,14 +456,10 @@ icmphostunr(Fs *f, Ipifc *ifc, Block *bp, int code, int free)
np->vcf[0] = 0x06 << 4; np->vcf[0] = 0x06 << 4;
ipriv->out[UnreachableV6]++; ipriv->out[UnreachableV6]++;
if(free) if(tome)
ipiput6(f, ifc, nbp); ipiput6(f, ifc, nbp);
else else
ipoput6(f, nbp, 0, MAXTTL, DFLTTOS, nil); ipoput6(f, nbp, 0, MAXTTL, DFLTTOS, nil);
runlock(ifc);
freebl:
if(free)
freeblist(bp);
} }
void void
@ -483,24 +472,18 @@ icmpttlexceeded6(Fs *f, Ipifc *ifc, Block *bp)
Ip6hdr *p; Ip6hdr *p;
Proto *icmp = f->t2p[ICMPv6]; Proto *icmp = f->t2p[ICMPv6];
Icmppriv6 *ipriv = icmp->priv; Icmppriv6 *ipriv = icmp->priv;
uchar ia[IPaddrlen];
p = (Ip6hdr *)bp->rp; p = (Ip6hdr *)bp->rp;
if(isv6mcast(p->src) || !ipv6local(ifc, ia, p->src))
if(isv6mcast(p->src))
return; return;
netlog(f, Logicmp, "send icmpttlexceeded6 %I -> src %I dst %I\n",
ia, p->src, p->dst);
nbp = newIPICMP(sz); nbp = newIPICMP(sz);
np = (IPICMP *) nbp->rp; np = (IPICMP *) nbp->rp;
ipmove(np->src, ia);
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->dst, p->src); ipmove(np->dst, p->src);
np->type = TimeExceedV6; np->type = TimeExceedV6;
np->code = 0; np->code = 0;
@ -522,24 +505,18 @@ icmppkttoobig6(Fs *f, Ipifc *ifc, Block *bp)
Ip6hdr *p; Ip6hdr *p;
Proto *icmp = f->t2p[ICMPv6]; Proto *icmp = f->t2p[ICMPv6];
Icmppriv6 *ipriv = icmp->priv; Icmppriv6 *ipriv = icmp->priv;
uchar ia[IPaddrlen];
p = (Ip6hdr *)bp->rp; p = (Ip6hdr *)bp->rp;
if(isv6mcast(p->src) || !ipv6local(ifc, ia, p->src))
if(isv6mcast(p->src))
return; return;
netlog(f, Logicmp, "send icmppkttoobig6 %I -> src %I dst %I\n",
ia, p->src, p->dst);
nbp = newIPICMP(sz); nbp = newIPICMP(sz);
np = (IPICMP *)nbp->rp; np = (IPICMP *)nbp->rp;
ipmove(np->src, ia);
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->dst, p->src); ipmove(np->dst, p->src);
np->type = PacketTooBigV6; np->type = PacketTooBigV6;
np->code = 0; np->code = 0;

View file

@ -333,8 +333,7 @@ ipiput4(Fs *f, Ipifc *ifc, Block *bp)
if((bp->flag & Bipck) == 0 && ipcsum(&h->vihl)) { if((bp->flag & Bipck) == 0 && ipcsum(&h->vihl)) {
ip->stats[InHdrErrors]++; ip->stats[InHdrErrors]++;
netlog(f, Logip, "ip: checksum error %V\n", h->src); netlog(f, Logip, "ip: checksum error %V\n", h->src);
freeblist(bp); goto drop;
return;
} }
v4tov6(v6dst, h->dst); v4tov6(v6dst, h->dst);
notforme = ipforme(f, v6dst) == 0; notforme = ipforme(f, v6dst) == 0;
@ -345,8 +344,7 @@ ipiput4(Fs *f, Ipifc *ifc, Block *bp)
if(hl < (IP_HLEN4<<2)) { if(hl < (IP_HLEN4<<2)) {
ip->stats[InHdrErrors]++; ip->stats[InHdrErrors]++;
netlog(f, Logip, "ip: %V bad hivl %ux\n", h->src, h->vihl); netlog(f, Logip, "ip: %V bad hivl %ux\n", h->src, h->vihl);
freeblist(bp); goto drop;
return;
} }
/* If this is not routed strip off the options */ /* If this is not routed strip off the options */
if(notforme == 0) { if(notforme == 0) {
@ -364,33 +362,30 @@ ipiput4(Fs *f, Ipifc *ifc, Block *bp)
if(notforme) { if(notforme) {
Route *r; Route *r;
Routehint rh; Routehint rh;
Ipifc *toifc;
if(!ip->iprouting){ if(!ip->iprouting)
freeblist(bp); goto drop;
return;
}
/* don't forward to source's network */ /* don't forward to source's network */
rh.r = nil; rh.r = nil;
r = v4lookup(f, h->dst, h->src, &rh); 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]++; ip->stats[OutDiscards]++;
freeblist(bp); goto drop;
return;
} }
/* don't forward if packet has timed out */ /* don't forward if packet has timed out */
hop = h->ttl; hop = h->ttl;
if(hop < 1) { if(hop < 1) {
ip->stats[InHdrErrors]++; ip->stats[InHdrErrors]++;
icmpttlexceeded(f, ifc->lifc->local, bp); icmpttlexceeded(f, ifc, bp);
freeblist(bp); goto drop;
return;
} }
/* reassemble if the interface expects it */ /* reassemble if the interface expects it */
if(r->ifc == nil) panic("nil route ifc"); if(toifc->reassemble){
if(r->ifc->reassemble){
frag = nhgets(h->frag); frag = nhgets(h->frag);
if(frag & ~IP_DF) { if(frag & ~IP_DF) {
h->tos = 0; h->tos = 0;
@ -434,6 +429,7 @@ if(r->ifc == nil) panic("nil route ifc");
} }
ip->stats[InDiscards]++; ip->stats[InDiscards]++;
ip->stats[InUnknownProtos]++; ip->stats[InUnknownProtos]++;
drop:
freeblist(bp); freeblist(bp);
} }

View file

@ -258,7 +258,7 @@ struct Iplifc
uchar mask[IPaddrlen]; uchar mask[IPaddrlen];
uchar remote[IPaddrlen]; uchar remote[IPaddrlen];
uchar net[IPaddrlen]; uchar net[IPaddrlen];
uchar type; /* ruoute type */ uchar type; /* route type */
uchar tentative; /* =1 => v6 dup disc on, =0 => confirmed unique */ uchar tentative; /* =1 => v6 dup disc on, =0 => confirmed unique */
uchar onlink; /* =1 => onlink, =0 offlink. */ uchar onlink; /* =1 => onlink, =0 offlink. */
uchar autoflag; /* v6 autonomous flag */ uchar autoflag; /* v6 autonomous flag */
@ -310,14 +310,11 @@ struct Ipifc
int maxtu; /* Maximum transfer unit */ int maxtu; /* Maximum transfer unit */
int mintu; /* Minumum tranfer unit */ int mintu; /* Minumum tranfer unit */
void *arg; /* medium specific */ void *arg; /* medium specific */
int reassemble; /* reassemble IP packets before forwarding */
/* these are used so that we can unbind on the fly */ uchar reflect; /* allow forwarded packets to go out the same interface */
Lock idlock; uchar reassemble; /* reassemble IP packets before forwarding to this interface */
uchar ifcid; /* incremented each 'bind/unbind/add/remove' */ 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 */ 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 iprouting(Fs*, int);
extern void icmpnoconv(Fs*, Block*); extern void icmpnoconv(Fs*, Block*);
extern void icmpcantfrag(Fs*, Block*, int); extern void icmpcantfrag(Fs*, Block*, int);
extern void icmpttlexceeded(Fs*, uchar*, Block*); extern void icmpttlexceeded(Fs*, Ipifc*, 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*);

View file

@ -231,6 +231,8 @@ ipifcunbind(Ipifc *ifc)
(*ifc->m->unbind)(ifc); (*ifc->m->unbind)(ifc);
memset(ifc->dev, 0, sizeof(ifc->dev)); memset(ifc->dev, 0, sizeof(ifc->dev));
ifc->arg = nil; ifc->arg = nil;
ifc->reflect = 0;
ifc->reassemble = 0; ifc->reassemble = 0;
/* close queues to stop queuing of packets */ /* close queues to stop queuing of packets */
@ -357,8 +359,8 @@ ipifccreate(Conv *c)
error(Enomem); error(Enomem);
ifc = (Ipifc*)c->ptcl; ifc = (Ipifc*)c->ptcl;
ifc->conv = c; ifc->conv = c;
ifc->unbinding = 0;
ifc->m = nil; ifc->m = nil;
ifc->reflect = 0;
ifc->reassemble = 0; ifc->reassemble = 0;
} }
@ -764,7 +766,6 @@ static char*
ipifcctl(Conv* c, char **argv, int argc) ipifcctl(Conv* c, char **argv, int argc)
{ {
Ipifc *ifc; Ipifc *ifc;
int i;
ifc = (Ipifc*)c->ptcl; ifc = (Ipifc*)c->ptcl;
if(strcmp(argv[0], "add") == 0) if(strcmp(argv[0], "add") == 0)
@ -777,15 +778,16 @@ ipifcctl(Conv* c, char **argv, int argc)
return ipifcunbind(ifc); return ipifcunbind(ifc);
else if(strcmp(argv[0], "mtu") == 0) else if(strcmp(argv[0], "mtu") == 0)
return ipifcsetmtu(ifc, argv, argc); return ipifcsetmtu(ifc, argv, argc);
else if(strcmp(argv[0], "reassemble") == 0){ else if(strcmp(argv[0], "iprouting") == 0){
ifc->reassemble = 1; iprouting(c->p->f, argc>1? atoi(argv[1]): 1);
return nil; return nil;
} }
else if(strcmp(argv[0], "iprouting") == 0){ else if(strcmp(argv[0], "reflect") == 0){
i = 1; ifc->reflect = argc>1? atoi(argv[1]): 1;
if(argc > 1) return nil;
i = atoi(argv[1]); }
iprouting(c->p->f, i); else if(strcmp(argv[0], "reassemble") == 0){
ifc->reassemble = argc>1? atoi(argv[1]): 1;
return nil; return nil;
} }
else if(strcmp(argv[0], "add6") == 0) else if(strcmp(argv[0], "add6") == 0)

View file

@ -116,7 +116,7 @@ ipoput6(Fs *f, Block *bp, int gating, int ttl, int tos, Routehint *rh)
return 0; return 0;
} }
if(gating && ifc->reassemble <= 0) { if(gating && !ifc->reassemble) {
/* /*
* v6 intermediate nodes are not supposed to fragment pkts; * v6 intermediate nodes are not supposed to fragment pkts;
* we fragment if ifc->reassemble is turned on; an exception * 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) { if(tentative && h->proto != ICMPv6) {
print("tentative addr, drop\n"); print("tentative addr, drop\n");
freeblist(bp); goto drop;
return;
} }
/* Check header version */ /* Check header version */
if(BLKIPVER(bp) != IP_VER6) { if(BLKIPVER(bp) != IP_VER6) {
ip->stats[InHdrErrors]++; ip->stats[InHdrErrors]++;
netlog(f, Logip, "ip: bad version %ux\n", (h->vcf[0]&0xF0)>>2); netlog(f, Logip, "ip: bad version %ux\n", (h->vcf[0]&0xF0)>>2);
freeblist(bp); goto drop;
return;
} }
/* route */ /* route */
if(notforme) { if(notforme) {
Route *r; Route *r;
Routehint rh; Routehint rh;
Ipifc *toifc;
if(!ip->iprouting){ if(!ip->iprouting)
freeblist(bp); goto drop;
return;
}
/* don't forward to link-local destinations */ /* don't forward to link-local destinations */
if(islinklocal(h->dst) || if(islinklocal(h->dst) ||
(isv6mcast(h->dst) && (h->dst[1]&0xF) <= Link_local_scop)){ (isv6mcast(h->dst) && (h->dst[1]&0xF) <= Link_local_scop)){
ip->stats[OutDiscards]++; ip->stats[OutDiscards]++;
freeblist(bp); goto drop;
return;
} }
/* don't forward to source's network */ /* don't forward to source's network */
rh.r = nil; rh.r = nil;
r = v6lookup(f, h->dst, h->src, &rh); 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]++; ip->stats[OutDiscards]++;
freeblist(bp); goto drop;
return;
} }
/* don't forward if packet has timed out */ /* don't forward if packet has timed out */
@ -292,12 +288,11 @@ ipiput6(Fs *f, Ipifc *ifc, Block *bp)
if(hop < 1) { if(hop < 1) {
ip->stats[InHdrErrors]++; ip->stats[InHdrErrors]++;
icmpttlexceeded6(f, ifc, bp); icmpttlexceeded6(f, ifc, bp);
freeblist(bp); goto drop;
return;
} }
/* process headers & reassemble if the interface expects it */ /* process headers & reassemble if the interface expects it */
bp = procxtns(ip, bp, r->ifc->reassemble); bp = procxtns(ip, bp, toifc->reassemble);
if(bp == nil) if(bp == nil)
return; return;
@ -325,6 +320,7 @@ ipiput6(Fs *f, Ipifc *ifc, Block *bp)
ip->stats[InDiscards]++; ip->stats[InDiscards]++;
ip->stats[InUnknownProtos]++; ip->stats[InUnknownProtos]++;
drop:
freeblist(bp); freeblist(bp);
} }

View file

@ -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 icmpna(Fs *f, uchar* src, uchar* dst, uchar* targ, uchar* mac, uchar flags);
void icmpttlexceeded6(Fs *f, Ipifc *ifc, Block *bp); void icmpttlexceeded6(Fs *f, Ipifc *ifc, Block *bp);
void icmppkttoobig6(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);

View file

@ -404,7 +404,7 @@ udpiput(Proto *udp, Ipifc *ifc, Block *bp)
icmpnoconv(f, bp); icmpnoconv(f, bp);
break; break;
case V6: case V6:
icmphostunr(f, ifc, bp, Icmp6_port_unreach, 0); icmphostunr6(f, ifc, bp, Icmp6_port_unreach, 0);
break; break;
default: default:
panic("udpiput2: version %d", version); panic("udpiput2: version %d", version);