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

front
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
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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