devip: implement network address translation routes
This adds a new route "t"-flag that enables network address translation, replacing the source address (and local port) of a forwarded packet to one of the outgoing interface. The state for a translation is kept in a new Translation structure, which contains two Iphash entries, so it can be inserted into the per protocol 4-tuple hash table, requiering no extra lookups. Translations have a low overhead (~200 bytes on amd64), so we can have many of them. They get reused after 5 minutes of inactivity or when the per protocol limit of 1000 entries is reached (then the one with longest inactivity is reused). The protocol needs to export a "forward" function that is responsible for modifying the forwarded packet, and then handle translations in its input function for iphash hits with Iphash.trans != 0. This patch also fixes a few minor things found during development: - Include the Iphash in the Conv structure, avoiding estra malloc - Fix ttl exceeded check (ttl < 1 -> ttl <= 1) - Router should not reply with ttl exceeded for multicast flows - Extra checks for icmp advice to avoid protocol confusions.
This commit is contained in:
parent
c14ea9fdd1
commit
d2a7d88662
15 changed files with 890 additions and 356 deletions
|
@ -411,6 +411,9 @@ multicast route
|
||||||
.TP
|
.TP
|
||||||
.B p
|
.B p
|
||||||
point-to-point route
|
point-to-point route
|
||||||
|
.TP
|
||||||
|
.B t
|
||||||
|
network address translation on source
|
||||||
.PD
|
.PD
|
||||||
.PP
|
.PP
|
||||||
The tag is an arbitrary, up to 4 character, string. It is normally used to
|
The tag is an arbitrary, up to 4 character, string. It is normally used to
|
||||||
|
@ -442,7 +445,7 @@ with all subsequent routes added via this file descriptor.
|
||||||
.TP
|
.TP
|
||||||
.BI add\ "target mask nexthop tag interface source smask"
|
.BI add\ "target mask nexthop tag interface source smask"
|
||||||
.TP
|
.TP
|
||||||
.BI add\ "target mask nexthop type tag interface source smask"
|
.BI add\ "target mask nexthop flags tag interface source smask"
|
||||||
Add the route to the table. If one already exists with the
|
Add the route to the table. If one already exists with the
|
||||||
same target and mask, replace it. The
|
same target and mask, replace it. The
|
||||||
.I interface
|
.I interface
|
||||||
|
@ -461,7 +464,7 @@ IP address on the desired interface.
|
||||||
.TP
|
.TP
|
||||||
.BI remove\ "target mask nexthop tag interface source smask"
|
.BI remove\ "target mask nexthop tag interface source smask"
|
||||||
.TP
|
.TP
|
||||||
.BI remove\ "target mask nexthop type tag interface source smask"
|
.BI remove\ "target mask nexthop flags tag interface source smask"
|
||||||
Remove the matching route.
|
Remove the matching route.
|
||||||
.
|
.
|
||||||
.SS "Address resolution
|
.SS "Address resolution
|
||||||
|
|
|
@ -737,6 +737,7 @@ setladdr(Conv* c)
|
||||||
char*
|
char*
|
||||||
setluniqueport(Conv* c, int lport)
|
setluniqueport(Conv* c, int lport)
|
||||||
{
|
{
|
||||||
|
Translation *q;
|
||||||
Proto *p;
|
Proto *p;
|
||||||
Conv *xp;
|
Conv *xp;
|
||||||
int x;
|
int x;
|
||||||
|
@ -754,14 +755,22 @@ setluniqueport(Conv* c, int lport)
|
||||||
&& xp->lport == lport
|
&& xp->lport == lport
|
||||||
&& xp->rport == c->rport
|
&& xp->rport == c->rport
|
||||||
&& ipcmp(xp->raddr, c->raddr) == 0
|
&& ipcmp(xp->raddr, c->raddr) == 0
|
||||||
&& ipcmp(xp->laddr, c->laddr) == 0){
|
&& ipcmp(xp->laddr, c->laddr) == 0)
|
||||||
qunlock(p);
|
goto Inuse;
|
||||||
return "address in use";
|
|
||||||
}
|
}
|
||||||
|
for(q = p->translations; q != nil; q = q->next){
|
||||||
|
if(q->backward.lport == lport
|
||||||
|
&& q->backward.rport == c->rport
|
||||||
|
&& ipcmp(q->backward.raddr, c->raddr) == 0
|
||||||
|
&& ipcmp(q->backward.laddr, c->laddr) == 0)
|
||||||
|
goto Inuse;
|
||||||
}
|
}
|
||||||
c->lport = lport;
|
c->lport = lport;
|
||||||
qunlock(p);
|
qunlock(p);
|
||||||
return nil;
|
return nil;
|
||||||
|
Inuse:
|
||||||
|
qunlock(p);
|
||||||
|
return "address in use";
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -770,18 +779,51 @@ setluniqueport(Conv* c, int lport)
|
||||||
static int
|
static int
|
||||||
lportinuse(Proto *p, ushort lport)
|
lportinuse(Proto *p, ushort lport)
|
||||||
{
|
{
|
||||||
|
Translation *q;
|
||||||
int x;
|
int x;
|
||||||
|
|
||||||
for(x = 0; x < p->nc && p->conv[x]; x++)
|
for(x = 0; x < p->nc && p->conv[x]; x++)
|
||||||
if(p->conv[x]->lport == lport)
|
if(p->conv[x]->lport == lport)
|
||||||
return 1;
|
return 1;
|
||||||
|
for(q = p->translations; q != nil; q = q->next)
|
||||||
|
if(q->backward.lport == lport)
|
||||||
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* find a unused loacal port for a protocol.
|
||||||
|
*
|
||||||
|
* p needs to be locked
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
unusedlport(Proto *p)
|
||||||
|
{
|
||||||
|
ushort port;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unrestricted ports are chosen randomly
|
||||||
|
* between 2^15 and 2^16. There are at most
|
||||||
|
* 4*Nchan = 4096 ports in use at any given time,
|
||||||
|
* so even in the worst case, a random probe has a
|
||||||
|
* 1 - 4096/2^15 = 87% chance of success.
|
||||||
|
* If 64 successive probes fail, there is a bug somewhere
|
||||||
|
* (or a once in 10^58 event has happened, but that's
|
||||||
|
* less likely than a venti collision).
|
||||||
|
*/
|
||||||
|
for(i=0; i<64; i++){
|
||||||
|
port = (1<<15) + nrand(1<<15);
|
||||||
|
if(!lportinuse(p, port))
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* pick a local port and set it
|
* pick a local port and set it
|
||||||
*/
|
*/
|
||||||
char *
|
static char *
|
||||||
setlport(Conv* c)
|
setlport(Conv* c)
|
||||||
{
|
{
|
||||||
Proto *p;
|
Proto *p;
|
||||||
|
@ -799,22 +841,10 @@ setlport(Conv* c)
|
||||||
goto chosen;
|
goto chosen;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
/*
|
port = unusedlport(p);
|
||||||
* Unrestricted ports are chosen randomly
|
if(port > 0)
|
||||||
* between 2^15 and 2^16. There are at most
|
|
||||||
* 4*Nchan = 4096 ports in use at any given time,
|
|
||||||
* so even in the worst case, a random probe has a
|
|
||||||
* 1 - 4096/2^15 = 87% chance of success.
|
|
||||||
* If 64 successive probes fail, there is a bug somewhere
|
|
||||||
* (or a once in 10^58 event has happened, but that's
|
|
||||||
* less likely than a venti collision).
|
|
||||||
*/
|
|
||||||
for(i=0; i<64; i++){
|
|
||||||
port = (1<<15) + nrand(1<<15);
|
|
||||||
if(!lportinuse(p, port))
|
|
||||||
goto chosen;
|
goto chosen;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
qunlock(p);
|
qunlock(p);
|
||||||
return "no ports available";
|
return "no ports available";
|
||||||
|
|
||||||
|
|
|
@ -99,6 +99,8 @@ struct Icmppriv
|
||||||
/* message counts */
|
/* message counts */
|
||||||
ulong in[Maxtype+1];
|
ulong in[Maxtype+1];
|
||||||
ulong out[Maxtype+1];
|
ulong out[Maxtype+1];
|
||||||
|
|
||||||
|
Ipht ht;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void icmpkick(void *x, Block*);
|
static void icmpkick(void *x, Block*);
|
||||||
|
@ -192,9 +194,9 @@ ip4reply(Fs *f, uchar ip4[4])
|
||||||
uchar addr[IPaddrlen];
|
uchar addr[IPaddrlen];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
v4tov6(addr, ip4);
|
if(isv4mcast(ip4))
|
||||||
if(ipismulticast(addr))
|
|
||||||
return 0;
|
return 0;
|
||||||
|
v4tov6(addr, ip4);
|
||||||
i = ipforme(f, addr);
|
i = ipforme(f, addr);
|
||||||
return i == 0 || i == Runi;
|
return i == 0 || i == Runi;
|
||||||
}
|
}
|
||||||
|
@ -204,9 +206,9 @@ ip4me(Fs *f, uchar ip4[4])
|
||||||
{
|
{
|
||||||
uchar addr[IPaddrlen];
|
uchar addr[IPaddrlen];
|
||||||
|
|
||||||
v4tov6(addr, ip4);
|
if(isv4mcast(ip4))
|
||||||
if(ipismulticast(addr))
|
|
||||||
return 0;
|
return 0;
|
||||||
|
v4tov6(addr, ip4);
|
||||||
return ipforme(f, addr) == Runi;
|
return ipforme(f, addr) == Runi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,7 +220,7 @@ icmpttlexceeded(Fs *f, Ipifc *ifc, Block *bp)
|
||||||
uchar ia[IPv4addrlen];
|
uchar ia[IPv4addrlen];
|
||||||
|
|
||||||
p = (Icmp *)bp->rp;
|
p = (Icmp *)bp->rp;
|
||||||
if(!ip4reply(f, p->src) || !ipv4local(ifc, ia, 0, p->src))
|
if(isv4mcast(p->dst) || !ip4reply(f, p->src) || !ipv4local(ifc, ia, 0, p->src))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
netlog(f, Logicmp, "sending icmpttlexceeded %V -> src %V dst %V\n",
|
netlog(f, Logicmp, "sending icmpttlexceeded %V -> src %V dst %V\n",
|
||||||
|
@ -249,7 +251,7 @@ icmpunreachable(Fs *f, Ipifc *ifc, Block *bp, int code, int seq)
|
||||||
uchar ia[IPv4addrlen];
|
uchar ia[IPv4addrlen];
|
||||||
|
|
||||||
p = (Icmp *)bp->rp;
|
p = (Icmp *)bp->rp;
|
||||||
if(!ip4reply(f, p->src))
|
if(isv4mcast(p->dst) || !ip4reply(f, p->src))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(ifc == nil){
|
if(ifc == nil){
|
||||||
|
@ -302,9 +304,10 @@ icmpcantfrag(Fs *f, Block *bp, int mtu)
|
||||||
static void
|
static void
|
||||||
goticmpkt(Proto *icmp, Block *bp)
|
goticmpkt(Proto *icmp, Block *bp)
|
||||||
{
|
{
|
||||||
ushort recid;
|
|
||||||
uchar dst[IPaddrlen], src[IPaddrlen];
|
uchar dst[IPaddrlen], src[IPaddrlen];
|
||||||
|
ushort recid;
|
||||||
Conv **c, *s;
|
Conv **c, *s;
|
||||||
|
Iphash *iph;
|
||||||
Icmp *p;
|
Icmp *p;
|
||||||
|
|
||||||
p = (Icmp *)bp->rp;
|
p = (Icmp *)bp->rp;
|
||||||
|
@ -312,11 +315,32 @@ goticmpkt(Proto *icmp, Block *bp)
|
||||||
v4tov6(src, p->src);
|
v4tov6(src, p->src);
|
||||||
recid = nhgets(p->icmpid);
|
recid = nhgets(p->icmpid);
|
||||||
|
|
||||||
|
qlock(icmp);
|
||||||
|
iph = iphtlook(&((Icmppriv*)icmp->priv)->ht, src, recid, dst, recid);
|
||||||
|
if(iph != nil){
|
||||||
|
Translation *q;
|
||||||
|
int hop = p->ttl;
|
||||||
|
|
||||||
|
if(hop <= 1 || (q = transbackward(icmp, iph)) == nil)
|
||||||
|
goto raise;
|
||||||
|
memmove(p->dst, q->forward.raddr+IPv4off, IPv4addrlen);
|
||||||
|
hnputs_csum(p->icmpid, q->forward.rport, p->cksum);
|
||||||
|
|
||||||
|
/* only use route-hint when from original desination */
|
||||||
|
if(memcmp(p->src, q->forward.laddr+IPv4off, IPv4addrlen) != 0)
|
||||||
|
q = nil;
|
||||||
|
qunlock(icmp);
|
||||||
|
|
||||||
|
ipoput4(icmp->f, bp, 1, hop - 1, p->tos, q);
|
||||||
|
return;
|
||||||
|
}
|
||||||
for(c = icmp->conv; (s = *c) != nil; c++){
|
for(c = icmp->conv; (s = *c) != nil; c++){
|
||||||
if(s->lport == recid)
|
if(s->lport == recid)
|
||||||
if(ipcmp(s->laddr, dst) == 0 || ipcmp(s->raddr, src) == 0)
|
if(ipcmp(s->laddr, dst) == 0 || ipcmp(s->raddr, src) == 0)
|
||||||
qpass(s->rq, copyblock(bp, blocklen(bp)));
|
qpass(s->rq, copyblock(bp, blocklen(bp)));
|
||||||
}
|
}
|
||||||
|
raise:
|
||||||
|
qunlock(icmp);
|
||||||
freeblist(bp);
|
freeblist(bp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -404,31 +428,6 @@ icmpiput(Proto *icmp, Ipifc*, Block *bp)
|
||||||
ipriv->out[EchoReply]++;
|
ipriv->out[EchoReply]++;
|
||||||
ipoput4(icmp->f, r, 0, MAXTTL, DFLTTOS, nil);
|
ipoput4(icmp->f, r, 0, MAXTTL, DFLTTOS, nil);
|
||||||
break;
|
break;
|
||||||
case Unreachable:
|
|
||||||
if(p->code >= nelem(unreachcode)) {
|
|
||||||
snprint(m2, sizeof m2, "unreachable %V -> %V code %d",
|
|
||||||
p->src, p->dst, p->code);
|
|
||||||
msg = m2;
|
|
||||||
} else
|
|
||||||
msg = unreachcode[p->code];
|
|
||||||
|
|
||||||
Advise:
|
|
||||||
bp->rp += ICMP_IPSIZE+ICMP_HDRSIZE;
|
|
||||||
if(BLEN(bp) < MinAdvise){
|
|
||||||
ipriv->stats[LenErrs]++;
|
|
||||||
goto raise;
|
|
||||||
}
|
|
||||||
p = (Icmp *)bp->rp;
|
|
||||||
if((nhgets(p->frag) & IP_FO) == 0){
|
|
||||||
pr = Fsrcvpcolx(icmp->f, p->proto);
|
|
||||||
if(pr != nil && pr->advise != nil) {
|
|
||||||
(*pr->advise)(pr, bp, msg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bp->rp -= ICMP_IPSIZE+ICMP_HDRSIZE;
|
|
||||||
goticmpkt(icmp, bp);
|
|
||||||
break;
|
|
||||||
case TimeExceed:
|
case TimeExceed:
|
||||||
if(p->code == 0){
|
if(p->code == 0){
|
||||||
snprint(msg = m2, sizeof m2, "ttl exceeded at %V", p->src);
|
snprint(msg = m2, sizeof m2, "ttl exceeded at %V", p->src);
|
||||||
|
@ -436,29 +435,117 @@ icmpiput(Proto *icmp, Ipifc*, Block *bp)
|
||||||
}
|
}
|
||||||
goticmpkt(icmp, bp);
|
goticmpkt(icmp, bp);
|
||||||
break;
|
break;
|
||||||
|
case Unreachable:
|
||||||
|
if(p->code >= nelem(unreachcode)) {
|
||||||
|
snprint(m2, sizeof m2, "unreachable %V -> %V code %d",
|
||||||
|
p->src, p->dst, p->code);
|
||||||
|
msg = m2;
|
||||||
|
} else
|
||||||
|
msg = unreachcode[p->code];
|
||||||
|
Advise:
|
||||||
|
bp->rp += ICMP_IPSIZE+ICMP_HDRSIZE;
|
||||||
|
if(BLEN(bp) < MinAdvise){
|
||||||
|
ipriv->stats[LenErrs]++;
|
||||||
|
goto raise;
|
||||||
|
}
|
||||||
|
p = (Icmp *)bp->rp;
|
||||||
|
if(p->vihl == (IP_VER4|IP_HLEN4) /* advise() does not expect options */
|
||||||
|
&& (nhgets(p->frag) & IP_FO) == 0 /* first fragment */
|
||||||
|
&& ipcsum(&p->vihl) == 0){
|
||||||
|
pr = Fsrcvpcolx(icmp->f, p->proto);
|
||||||
|
if(pr != nil && pr->advise != nil) {
|
||||||
|
netlog(icmp->f, Logicmp, "advising %s!%V -> %V: %s\n", pr->name, p->src, p->dst, msg);
|
||||||
|
(*pr->advise)(pr, bp, msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bp->rp -= ICMP_IPSIZE+ICMP_HDRSIZE;
|
||||||
|
/* wet floor */
|
||||||
default:
|
default:
|
||||||
goticmpkt(icmp, bp);
|
goticmpkt(icmp, bp);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
raise:
|
raise:
|
||||||
freeblist(bp);
|
freeblist(bp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* called from protocol advice handlers when the advice
|
||||||
|
* is actually for someone we source translate (ip4).
|
||||||
|
* the caller has fixed up the ip address and ports
|
||||||
|
* in the inner header, so we just restore the outer
|
||||||
|
* ip/icmp headers, recalculating icmp checksum
|
||||||
|
* and send the advice to ip4.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
icmpproxyadvice(Fs *f, Block *bp, uchar *ip4)
|
||||||
|
{
|
||||||
|
Icmp *p;
|
||||||
|
int hop;
|
||||||
|
|
||||||
|
/* inner header */
|
||||||
|
p = (Icmp *) bp->rp;
|
||||||
|
if(p->vihl != (IP_VER4|IP_HLEN4))
|
||||||
|
goto drop;
|
||||||
|
if(ipcsum(&p->vihl) != 0)
|
||||||
|
goto drop;
|
||||||
|
|
||||||
|
/* outer header */
|
||||||
|
bp->rp -= ICMP_IPSIZE+ICMP_HDRSIZE;
|
||||||
|
p = (Icmp *) bp->rp;
|
||||||
|
if(p->vihl != (IP_VER4|(ICMP_IPSIZE>>2)))
|
||||||
|
goto drop;
|
||||||
|
|
||||||
|
hop = p->ttl;
|
||||||
|
if(hop <= 1)
|
||||||
|
goto drop;
|
||||||
|
|
||||||
|
netlog(f, Logicmp|Logtrans, "proxying icmp advice from %V to %V->%V\n",
|
||||||
|
p->src, p->dst, ip4);
|
||||||
|
memmove(p->dst, ip4, IPv4addrlen);
|
||||||
|
|
||||||
|
/* recalculate ICMP checksum */
|
||||||
|
memset(p->cksum, 0, sizeof(p->cksum));
|
||||||
|
hnputs(p->cksum, ptclcsum(bp, ICMP_IPSIZE, blocklen(bp) - ICMP_IPSIZE));
|
||||||
|
|
||||||
|
ipoput4(f, bp, 1, hop - 1, p->tos, nil);
|
||||||
|
return;
|
||||||
|
drop:
|
||||||
|
freeblist(bp);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
icmpadvise(Proto *icmp, Block *bp, char *msg)
|
icmpadvise(Proto *icmp, Block *bp, char *msg)
|
||||||
{
|
{
|
||||||
ushort recid;
|
|
||||||
uchar dst[IPaddrlen], src[IPaddrlen];
|
uchar dst[IPaddrlen], src[IPaddrlen];
|
||||||
|
ushort recid;
|
||||||
Conv **c, *s;
|
Conv **c, *s;
|
||||||
Icmp *p;
|
Icmp *p;
|
||||||
|
Iphash *iph;
|
||||||
|
|
||||||
p = (Icmp *) bp->rp;
|
p = (Icmp *) bp->rp;
|
||||||
v4tov6(dst, p->dst);
|
v4tov6(dst, p->dst);
|
||||||
v4tov6(src, p->src);
|
v4tov6(src, p->src);
|
||||||
recid = nhgets(p->icmpid);
|
recid = nhgets(p->icmpid);
|
||||||
|
|
||||||
|
qlock(icmp);
|
||||||
|
iph = iphtlook(&((Icmppriv*)icmp->priv)->ht, dst, recid, src, recid);
|
||||||
|
if(iph != nil){
|
||||||
|
Translation *q;
|
||||||
|
|
||||||
|
if((q = transbackward(icmp, iph)) == nil)
|
||||||
|
goto raise;
|
||||||
|
|
||||||
|
hnputs_csum(p->src+0, nhgets(q->forward.raddr+IPv4off+0), p->ipcksum);
|
||||||
|
hnputs_csum(p->src+2, nhgets(q->forward.raddr+IPv4off+2), p->ipcksum);
|
||||||
|
|
||||||
|
hnputs_csum(p->icmpid, q->forward.rport, p->cksum);
|
||||||
|
qunlock(icmp);
|
||||||
|
|
||||||
|
icmpproxyadvice(icmp->f, bp, p->src);
|
||||||
|
return;
|
||||||
|
}
|
||||||
for(c = icmp->conv; (s = *c) != nil; c++){
|
for(c = icmp->conv; (s = *c) != nil; c++){
|
||||||
if(s->lport == recid)
|
if(s->lport == recid)
|
||||||
if(ipcmp(s->laddr, src) == 0)
|
if(ipcmp(s->laddr, src) == 0)
|
||||||
|
@ -470,9 +557,38 @@ icmpadvise(Proto *icmp, Block *bp, char *msg)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
raise:
|
||||||
|
qunlock(icmp);
|
||||||
freeblist(bp);
|
freeblist(bp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Block*
|
||||||
|
icmpforward(Proto *icmp, Block *bp, Route *r)
|
||||||
|
{
|
||||||
|
uchar da[IPaddrlen], sa[IPaddrlen];
|
||||||
|
ushort id;
|
||||||
|
Icmp *p;
|
||||||
|
Translation *q;
|
||||||
|
|
||||||
|
p = (Icmp*)(bp->rp);
|
||||||
|
v4tov6(sa, p->src);
|
||||||
|
v4tov6(da, p->dst);
|
||||||
|
id = nhgets(p->icmpid);
|
||||||
|
|
||||||
|
qlock(icmp);
|
||||||
|
q = transforward(icmp, &((Icmppriv*)icmp->priv)->ht, sa, id, da, id, r);
|
||||||
|
if(q == nil){
|
||||||
|
qunlock(icmp);
|
||||||
|
freeblist(bp);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
memmove(p->src, q->backward.laddr+IPv4off, IPv4addrlen);
|
||||||
|
hnputs_csum(p->icmpid, q->backward.lport, p->cksum);
|
||||||
|
qunlock(icmp);
|
||||||
|
|
||||||
|
return bp;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
icmpstats(Proto *icmp, char *buf, int len)
|
icmpstats(Proto *icmp, char *buf, int len)
|
||||||
{
|
{
|
||||||
|
@ -511,6 +627,7 @@ icmpinit(Fs *fs)
|
||||||
icmp->stats = icmpstats;
|
icmp->stats = icmpstats;
|
||||||
icmp->ctl = nil;
|
icmp->ctl = nil;
|
||||||
icmp->advise = icmpadvise;
|
icmp->advise = icmpadvise;
|
||||||
|
icmp->forward = icmpforward;
|
||||||
icmp->gc = nil;
|
icmp->gc = nil;
|
||||||
icmp->ipproto = IP_ICMPPROTO;
|
icmp->ipproto = IP_ICMPPROTO;
|
||||||
icmp->nc = 128;
|
icmp->nc = 128;
|
||||||
|
|
|
@ -711,9 +711,8 @@ icmpiput6(Proto *icmp, Ipifc *ifc, Block *bp)
|
||||||
goto raise;
|
goto raise;
|
||||||
}
|
}
|
||||||
p = (IPICMP *)bp->rp;
|
p = (IPICMP *)bp->rp;
|
||||||
|
|
||||||
/* get rid of fragment header if this is the first fragment */
|
/* get rid of fragment header if this is the first fragment */
|
||||||
if(p->proto == FH && BLEN(bp) >= MinAdvise+IP6FHDR && MinAdvise > IP6HDR){
|
if((p->vcf[0] & 0xF0) == IP_VER6 && p->proto == FH && BLEN(bp) >= MinAdvise+IP6FHDR && MinAdvise > IP6HDR){
|
||||||
Fraghdr6 *fh = (Fraghdr6*)(bp->rp + IP6HDR);
|
Fraghdr6 *fh = (Fraghdr6*)(bp->rp + IP6HDR);
|
||||||
if((nhgets(fh->offsetRM) & ~7) == 0){ /* first fragment */
|
if((nhgets(fh->offsetRM) & ~7) == 0){ /* first fragment */
|
||||||
p->proto = fh->nexthdr;
|
p->proto = fh->nexthdr;
|
||||||
|
@ -725,9 +724,10 @@ icmpiput6(Proto *icmp, Ipifc *ifc, Block *bp)
|
||||||
bp->rp -= IP6HDR;
|
bp->rp -= IP6HDR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(p->proto != FH){
|
if((p->vcf[0] & 0xF0) == IP_VER6 && p->proto != FH){
|
||||||
pr = Fsrcvpcolx(icmp->f, p->proto);
|
pr = Fsrcvpcolx(icmp->f, p->proto);
|
||||||
if(pr != nil && pr->advise != nil) {
|
if(pr != nil && pr->advise != nil) {
|
||||||
|
netlog(icmp->f, Logicmp, "advising %s!%I -> %I: %s\n", pr->name, p->src, p->dst, msg);
|
||||||
(*pr->advise)(pr, bp, msg);
|
(*pr->advise)(pr, bp, msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -308,8 +308,8 @@ illocalclose(Conv *c)
|
||||||
ic = (Ilcb*)c->ptcl;
|
ic = (Ilcb*)c->ptcl;
|
||||||
ic->state = Ilclosed;
|
ic->state = Ilclosed;
|
||||||
iphtrem(&ipriv->ht, c);
|
iphtrem(&ipriv->ht, c);
|
||||||
ipmove(c->laddr, IPnoaddr);
|
|
||||||
c->lport = 0;
|
c->lport = 0;
|
||||||
|
ipmove(c->laddr, IPnoaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -544,6 +544,7 @@ iliput(Proto *il, Ipifc*, Block *bp)
|
||||||
uchar laddr[IPaddrlen];
|
uchar laddr[IPaddrlen];
|
||||||
ushort sp, dp, csum;
|
ushort sp, dp, csum;
|
||||||
int plen, illen;
|
int plen, illen;
|
||||||
|
Iphash *iph;
|
||||||
Conv *new, *s;
|
Conv *new, *s;
|
||||||
Ilpriv *ipriv;
|
Ilpriv *ipriv;
|
||||||
|
|
||||||
|
@ -584,14 +585,14 @@ iliput(Proto *il, Ipifc*, Block *bp)
|
||||||
}
|
}
|
||||||
|
|
||||||
qlock(il);
|
qlock(il);
|
||||||
s = iphtlook(&ipriv->ht, raddr, dp, laddr, sp);
|
iph = iphtlook(&ipriv->ht, raddr, dp, laddr, sp);
|
||||||
if(s == nil){
|
if(iph == nil){
|
||||||
if(ih->iltype == Ilsync)
|
if(ih->iltype == Ilsync)
|
||||||
ilreject(il->f, ih); /* no listener */
|
ilreject(il->f, ih); /* no listener */
|
||||||
qunlock(il);
|
qunlock(il);
|
||||||
goto raise;
|
goto raise;
|
||||||
}
|
}
|
||||||
|
s = iphconv(iph);
|
||||||
ic = (Ilcb*)s->ptcl;
|
ic = (Ilcb*)s->ptcl;
|
||||||
if(ic->state == Illistening){
|
if(ic->state == Illistening){
|
||||||
if(ih->iltype != Ilsync){
|
if(ih->iltype != Ilsync){
|
||||||
|
|
|
@ -252,7 +252,7 @@ free:
|
||||||
void
|
void
|
||||||
ipiput4(Fs *f, Ipifc *ifc, Block *bp)
|
ipiput4(Fs *f, Ipifc *ifc, Block *bp)
|
||||||
{
|
{
|
||||||
int hl, len, hop, tos;
|
int hl, len, hop;
|
||||||
uchar v6dst[IPaddrlen];
|
uchar v6dst[IPaddrlen];
|
||||||
ushort frag;
|
ushort frag;
|
||||||
Ip4hdr *h;
|
Ip4hdr *h;
|
||||||
|
@ -327,14 +327,42 @@ ipiput4(Fs *f, Ipifc *ifc, Block *bp)
|
||||||
|
|
||||||
/* 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, bp);
|
icmpttlexceeded(f, ifc, bp);
|
||||||
goto drop;
|
goto drop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* reassemble if the interface expects it */
|
if(r->type & Rtrans) {
|
||||||
if(nifc->reassemble){
|
p = Fsrcvpcolx(f, h->proto);
|
||||||
|
if(p == nil || p->forward == nil){
|
||||||
|
ip->stats[OutDiscards]++;
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(hl > IP4HDR) {
|
||||||
|
hl -= IP4HDR;
|
||||||
|
len -= hl;
|
||||||
|
bp->rp += hl;
|
||||||
|
memmove(bp->rp, h, IP4HDR);
|
||||||
|
h = (Ip4hdr*)bp->rp;
|
||||||
|
h->vihl = IP_VER4|IP_HLEN4;
|
||||||
|
hnputs(h->length, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
frag = nhgets(h->frag);
|
||||||
|
if(frag & (IP_MF|IP_FO)) {
|
||||||
|
bp = ip4reassemble(ip, frag, bp);
|
||||||
|
if(bp == nil)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bp = (*p->forward)(p, bp, r);
|
||||||
|
if(bp == nil)
|
||||||
|
return;
|
||||||
|
h = (Ip4hdr*)bp->rp;
|
||||||
|
} else if(nifc->reassemble) {
|
||||||
|
/* reassemble as the interface expects it */
|
||||||
frag = nhgets(h->frag);
|
frag = nhgets(h->frag);
|
||||||
if(frag & (IP_MF|IP_FO)) {
|
if(frag & (IP_MF|IP_FO)) {
|
||||||
bp = ip4reassemble(ip, frag, bp);
|
bp = ip4reassemble(ip, frag, bp);
|
||||||
|
@ -345,9 +373,7 @@ ipiput4(Fs *f, Ipifc *ifc, Block *bp)
|
||||||
}
|
}
|
||||||
|
|
||||||
ip->stats[ForwDatagrams]++;
|
ip->stats[ForwDatagrams]++;
|
||||||
tos = h->tos;
|
ipoput4(f, bp, 1, hop - 1, h->tos, &rh);
|
||||||
hop = h->ttl;
|
|
||||||
ipoput4(f, bp, 1, hop - 1, tos, &rh);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ typedef struct Arpent Arpent;
|
||||||
typedef struct Arp Arp;
|
typedef struct Arp Arp;
|
||||||
typedef struct Route Route;
|
typedef struct Route Route;
|
||||||
typedef struct Routehint Routehint;
|
typedef struct Routehint Routehint;
|
||||||
|
typedef struct Translation Translation;
|
||||||
|
|
||||||
typedef struct Routerparams Routerparams;
|
typedef struct Routerparams Routerparams;
|
||||||
typedef struct Hostparams Hostparams;
|
typedef struct Hostparams Hostparams;
|
||||||
|
@ -177,6 +178,71 @@ struct Routehint
|
||||||
Arpent *a; /* last arp entry used */
|
Arpent *a; /* last arp entry used */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hash table for 2 ip addresses + 2 ports
|
||||||
|
*/
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
Nipht= 521, /* convenient prime */
|
||||||
|
|
||||||
|
IPmatchexact= 0, /* match on 4 tuple */
|
||||||
|
IPmatchany, /* *!* */
|
||||||
|
IPmatchport, /* *!port */
|
||||||
|
IPmatchaddr, /* addr!* */
|
||||||
|
IPmatchpa, /* addr!port */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Iphash
|
||||||
|
{
|
||||||
|
Iphash *nextiphash;
|
||||||
|
|
||||||
|
uchar trans; /* 0 = conv, 1 = foward, 2 = backward */
|
||||||
|
uchar match;
|
||||||
|
ushort lport; /* local port number */
|
||||||
|
ushort rport; /* remote port number */
|
||||||
|
uchar laddr[IPaddrlen]; /* local IP address */
|
||||||
|
uchar raddr[IPaddrlen]; /* remote IP address */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Ipht
|
||||||
|
{
|
||||||
|
Lock;
|
||||||
|
Iphash *tab[Nipht];
|
||||||
|
};
|
||||||
|
|
||||||
|
void iphtadd(Ipht*, Iphash*);
|
||||||
|
void iphtrem(Ipht*, Iphash*);
|
||||||
|
Iphash *iphtlook(Ipht *ht, uchar *sa, ushort sp, uchar *da, ushort dp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NAT entry.
|
||||||
|
*
|
||||||
|
* This holds the 5 tuple as two Iphashes.
|
||||||
|
* The "forward" hash matches the the packets from
|
||||||
|
* the source that need to be translated and
|
||||||
|
* "backward" matches the packets coming back
|
||||||
|
* from the destination.
|
||||||
|
*/
|
||||||
|
struct Translation
|
||||||
|
{
|
||||||
|
Translation *next;
|
||||||
|
Translation **link;
|
||||||
|
|
||||||
|
ulong time;
|
||||||
|
|
||||||
|
Iphash forward;
|
||||||
|
#define iphforward(h) ((Translation*)((char*)(h) - (char*)&((Translation*)0)->forward))
|
||||||
|
|
||||||
|
Iphash backward;
|
||||||
|
#define iphbackward(h) ((Translation*)((char*)(h) - (char*)&((Translation*)0)->backward))
|
||||||
|
|
||||||
|
/* used for forwarding to the source */
|
||||||
|
Routehint;
|
||||||
|
};
|
||||||
|
|
||||||
|
Translation *transforward(Proto *p, Ipht *ht, uchar *sa, int sp, uchar *da, int dp, Route *r);
|
||||||
|
Translation *transbackward(Proto *p, Iphash *iph);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* one per conversation directory
|
* one per conversation directory
|
||||||
*/
|
*/
|
||||||
|
@ -187,16 +253,15 @@ struct Conv
|
||||||
int x; /* conversation index */
|
int x; /* conversation index */
|
||||||
Proto* p;
|
Proto* p;
|
||||||
|
|
||||||
int restricted; /* remote port is restricted */
|
|
||||||
int ignoreadvice; /* don't terminate connection on icmp errors */
|
|
||||||
uint ttl; /* max time to live */
|
uint ttl; /* max time to live */
|
||||||
uint tos; /* type of service */
|
uint tos; /* type of service */
|
||||||
|
|
||||||
|
uchar restricted; /* remote port is restricted */
|
||||||
|
uchar ignoreadvice; /* don't terminate connection on icmp errors */
|
||||||
uchar ipversion;
|
uchar ipversion;
|
||||||
uchar laddr[IPaddrlen]; /* local IP address */
|
|
||||||
uchar raddr[IPaddrlen]; /* remote IP address */
|
Iphash;
|
||||||
ushort lport; /* local port number */
|
#define iphconv(h) ((Conv*)((char*)(h) - (char*)&((Conv*)0)->Iphash))
|
||||||
ushort rport; /* remote port number */
|
|
||||||
|
|
||||||
char *owner; /* protections */
|
char *owner; /* protections */
|
||||||
int perm;
|
int perm;
|
||||||
|
@ -206,7 +271,6 @@ struct Conv
|
||||||
|
|
||||||
/* udp specific */
|
/* udp specific */
|
||||||
int headers; /* data src/dst headers in udp */
|
int headers; /* data src/dst headers in udp */
|
||||||
int reliable; /* true if reliable udp */
|
|
||||||
|
|
||||||
Conv* incall; /* calls waiting to be listened for */
|
Conv* incall; /* calls waiting to be listened for */
|
||||||
Conv* next;
|
Conv* next;
|
||||||
|
@ -351,34 +415,6 @@ struct Ipmulti
|
||||||
Ipmulti *next;
|
Ipmulti *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* hash table for 2 ip addresses + 2 ports
|
|
||||||
*/
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
Nipht= 521, /* convenient prime */
|
|
||||||
|
|
||||||
IPmatchexact= 0, /* match on 4 tuple */
|
|
||||||
IPmatchany, /* *!* */
|
|
||||||
IPmatchport, /* *!port */
|
|
||||||
IPmatchaddr, /* addr!* */
|
|
||||||
IPmatchpa, /* addr!port */
|
|
||||||
};
|
|
||||||
struct Iphash
|
|
||||||
{
|
|
||||||
Iphash *next;
|
|
||||||
Conv *c;
|
|
||||||
int match;
|
|
||||||
};
|
|
||||||
struct Ipht
|
|
||||||
{
|
|
||||||
Lock;
|
|
||||||
Iphash *tab[Nipht];
|
|
||||||
};
|
|
||||||
void iphtadd(Ipht*, Conv*);
|
|
||||||
void iphtrem(Ipht*, Conv*);
|
|
||||||
Conv* iphtlook(Ipht *ht, uchar *sa, ushort sp, uchar *da, ushort dp);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* one per multiplexed protocol
|
* one per multiplexed protocol
|
||||||
*/
|
*/
|
||||||
|
@ -412,9 +448,15 @@ struct Proto
|
||||||
Qid qid; /* qid for protocol directory */
|
Qid qid; /* qid for protocol directory */
|
||||||
ushort nextrport;
|
ushort nextrport;
|
||||||
|
|
||||||
|
/* network address translation */
|
||||||
|
Translation* translations;
|
||||||
|
Block* (*forward)(Proto*, Block*, Route*);
|
||||||
|
|
||||||
void *priv;
|
void *priv;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int unusedlport(Proto *p);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* one per IP protocol stack
|
* one per IP protocol stack
|
||||||
|
@ -489,6 +531,7 @@ enum
|
||||||
Logrudpmsg= 1<<16,
|
Logrudpmsg= 1<<16,
|
||||||
Logesp= 1<<17,
|
Logesp= 1<<17,
|
||||||
Logtcpwin= 1<<18,
|
Logtcpwin= 1<<18,
|
||||||
|
Logtrans= 1<<19,
|
||||||
};
|
};
|
||||||
|
|
||||||
void netloginit(Fs*);
|
void netloginit(Fs*);
|
||||||
|
@ -522,7 +565,9 @@ enum
|
||||||
Rbcast= (1<<4), /* a broadcast self address */
|
Rbcast= (1<<4), /* a broadcast self address */
|
||||||
Rmulti= (1<<5), /* a multicast self address */
|
Rmulti= (1<<5), /* a multicast self address */
|
||||||
Rproxy= (1<<6), /* this route should be proxied */
|
Rproxy= (1<<6), /* this route should be proxied */
|
||||||
Rsrc= (1<<7), /* source specific route */
|
Rtrans= (1<<7), /* this route translates source address (NAT) */
|
||||||
|
|
||||||
|
Rsrc= (1<<8), /* source specific route */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RouteTree
|
struct RouteTree
|
||||||
|
@ -533,7 +578,7 @@ struct RouteTree
|
||||||
Ipifc *ifc;
|
Ipifc *ifc;
|
||||||
uchar ifcid; /* must match ifc->id */
|
uchar ifcid; /* must match ifc->id */
|
||||||
uchar depth;
|
uchar depth;
|
||||||
uchar type;
|
ushort type;
|
||||||
char tag[4];
|
char tag[4];
|
||||||
int ref;
|
int ref;
|
||||||
};
|
};
|
||||||
|
@ -641,10 +686,13 @@ extern int isv4(uchar*);
|
||||||
extern void v4tov6(uchar *v6, uchar *v4);
|
extern void v4tov6(uchar *v6, uchar *v4);
|
||||||
extern int v6tov4(uchar *v4, uchar *v6);
|
extern int v6tov4(uchar *v4, uchar *v6);
|
||||||
extern int eipfmt(Fmt*);
|
extern int eipfmt(Fmt*);
|
||||||
|
extern int ipismulticast(uchar *ip);
|
||||||
extern int convipvers(Conv *c);
|
extern int convipvers(Conv *c);
|
||||||
|
extern void hnputs_csum(void *p, ushort v, uchar *pcsum);
|
||||||
|
|
||||||
#define ipmove(x, y) memmove(x, y, IPaddrlen)
|
#define ipmove(x, y) memmove(x, y, IPaddrlen)
|
||||||
#define ipcmp(x, y) ( (x)[IPaddrlen-1] != (y)[IPaddrlen-1] || memcmp(x, y, IPaddrlen) )
|
#define ipcmp(x, y) ( (x)[IPaddrlen-1] != (y)[IPaddrlen-1] || memcmp(x, y, IPaddrlen) )
|
||||||
|
#define isv4mcast(ip4) ((ip4)[0] >= 0xe0 && (ip4)[0] < 0xf0)
|
||||||
|
|
||||||
extern uchar IPv4bcast[IPaddrlen];
|
extern uchar IPv4bcast[IPaddrlen];
|
||||||
extern uchar IPv4bcastobs[IPaddrlen];
|
extern uchar IPv4bcastobs[IPaddrlen];
|
||||||
|
@ -670,7 +718,6 @@ extern Medium* ipfindmedium(char *name);
|
||||||
extern void addipmedium(Medium *med);
|
extern void addipmedium(Medium *med);
|
||||||
extern void ipifcoput(Ipifc *ifc, Block *bp, int version, uchar *ip, Routehint *rh);
|
extern void ipifcoput(Ipifc *ifc, Block *bp, int version, uchar *ip, Routehint *rh);
|
||||||
extern int ipforme(Fs*, uchar *addr);
|
extern int ipforme(Fs*, uchar *addr);
|
||||||
extern int ipismulticast(uchar *ip);
|
|
||||||
extern Ipifc* findipifc(Fs*, uchar *local, uchar *remote, int type);
|
extern Ipifc* findipifc(Fs*, uchar *local, uchar *remote, int type);
|
||||||
extern Ipifc* findipifcstr(Fs *f, char *s);
|
extern Ipifc* findipifcstr(Fs *f, char *s);
|
||||||
extern void findlocalip(Fs*, uchar *local, uchar *remote);
|
extern void findlocalip(Fs*, uchar *local, uchar *remote);
|
||||||
|
@ -694,6 +741,8 @@ extern void icmpnohost(Fs*, Ipifc*, Block*);
|
||||||
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*, Ipifc*, Block*);
|
extern void icmpttlexceeded(Fs*, Ipifc*, Block*);
|
||||||
|
extern void icmpproxyadvice(Fs *, Block*, uchar*);
|
||||||
|
|
||||||
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*);
|
||||||
|
|
|
@ -203,7 +203,6 @@ ipv62smcast(uchar *smcast, uchar *a)
|
||||||
smcast[15] = a[15];
|
smcast[15] = a[15];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* parse a hex mac address
|
* parse a hex mac address
|
||||||
*/
|
*/
|
||||||
|
@ -233,140 +232,23 @@ parsemac(uchar *to, char *from, int len)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* hashing tcp, udp, ... connections
|
* return multicast version if any
|
||||||
*/
|
*/
|
||||||
ulong
|
int
|
||||||
iphash(uchar *sa, ushort sp, uchar *da, ushort dp)
|
ipismulticast(uchar *ip)
|
||||||
{
|
{
|
||||||
return ((sa[IPaddrlen-1]<<24) ^ (sp << 16) ^ (da[IPaddrlen-1]<<8) ^ dp ) % Nipht;
|
if(isv4(ip)){
|
||||||
|
if(isv4mcast(&ip[IPv4off]))
|
||||||
|
return V4;
|
||||||
|
}
|
||||||
|
else if(isv6mcast(ip))
|
||||||
|
return V6;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
/*
|
||||||
iphtadd(Ipht *ht, Conv *c)
|
* return ip version of a connection
|
||||||
{
|
|
||||||
ulong hv;
|
|
||||||
Iphash *h;
|
|
||||||
|
|
||||||
hv = iphash(c->raddr, c->rport, c->laddr, c->lport);
|
|
||||||
h = smalloc(sizeof(*h));
|
|
||||||
if(ipcmp(c->raddr, IPnoaddr) != 0)
|
|
||||||
h->match = IPmatchexact;
|
|
||||||
else {
|
|
||||||
if(ipcmp(c->laddr, IPnoaddr) != 0){
|
|
||||||
if(c->lport == 0)
|
|
||||||
h->match = IPmatchaddr;
|
|
||||||
else
|
|
||||||
h->match = IPmatchpa;
|
|
||||||
} else {
|
|
||||||
if(c->lport == 0)
|
|
||||||
h->match = IPmatchany;
|
|
||||||
else
|
|
||||||
h->match = IPmatchport;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
h->c = c;
|
|
||||||
|
|
||||||
lock(ht);
|
|
||||||
h->next = ht->tab[hv];
|
|
||||||
ht->tab[hv] = h;
|
|
||||||
unlock(ht);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
iphtrem(Ipht *ht, Conv *c)
|
|
||||||
{
|
|
||||||
ulong hv;
|
|
||||||
Iphash **l, *h;
|
|
||||||
|
|
||||||
hv = iphash(c->raddr, c->rport, c->laddr, c->lport);
|
|
||||||
lock(ht);
|
|
||||||
for(l = &ht->tab[hv]; (*l) != nil; l = &(*l)->next)
|
|
||||||
if((*l)->c == c){
|
|
||||||
h = *l;
|
|
||||||
(*l) = h->next;
|
|
||||||
free(h);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
unlock(ht);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* look for a matching conversation with the following precedence
|
|
||||||
* connected && raddr,rport,laddr,lport
|
|
||||||
* announced && laddr,lport
|
|
||||||
* announced && *,lport
|
|
||||||
* announced && laddr,*
|
|
||||||
* announced && *,*
|
|
||||||
*/
|
*/
|
||||||
Conv*
|
|
||||||
iphtlook(Ipht *ht, uchar *sa, ushort sp, uchar *da, ushort dp)
|
|
||||||
{
|
|
||||||
ulong hv;
|
|
||||||
Iphash *h;
|
|
||||||
Conv *c;
|
|
||||||
|
|
||||||
/* exact 4 pair match (connection) */
|
|
||||||
hv = iphash(sa, sp, da, dp);
|
|
||||||
lock(ht);
|
|
||||||
for(h = ht->tab[hv]; h != nil; h = h->next){
|
|
||||||
if(h->match != IPmatchexact)
|
|
||||||
continue;
|
|
||||||
c = h->c;
|
|
||||||
if(sp == c->rport && dp == c->lport
|
|
||||||
&& ipcmp(sa, c->raddr) == 0 && ipcmp(da, c->laddr) == 0){
|
|
||||||
unlock(ht);
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* match local address and port */
|
|
||||||
hv = iphash(IPnoaddr, 0, da, dp);
|
|
||||||
for(h = ht->tab[hv]; h != nil; h = h->next){
|
|
||||||
if(h->match != IPmatchpa)
|
|
||||||
continue;
|
|
||||||
c = h->c;
|
|
||||||
if(dp == c->lport && ipcmp(da, c->laddr) == 0){
|
|
||||||
unlock(ht);
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* match just port */
|
|
||||||
hv = iphash(IPnoaddr, 0, IPnoaddr, dp);
|
|
||||||
for(h = ht->tab[hv]; h != nil; h = h->next){
|
|
||||||
if(h->match != IPmatchport)
|
|
||||||
continue;
|
|
||||||
c = h->c;
|
|
||||||
if(dp == c->lport){
|
|
||||||
unlock(ht);
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* match local address */
|
|
||||||
hv = iphash(IPnoaddr, 0, da, 0);
|
|
||||||
for(h = ht->tab[hv]; h != nil; h = h->next){
|
|
||||||
if(h->match != IPmatchaddr)
|
|
||||||
continue;
|
|
||||||
c = h->c;
|
|
||||||
if(ipcmp(da, c->laddr) == 0){
|
|
||||||
unlock(ht);
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* look for something that matches anything */
|
|
||||||
hv = iphash(IPnoaddr, 0, IPnoaddr, 0);
|
|
||||||
for(h = ht->tab[hv]; h != nil; h = h->next){
|
|
||||||
if(h->match != IPmatchany)
|
|
||||||
continue;
|
|
||||||
c = h->c;
|
|
||||||
unlock(ht);
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
unlock(ht);
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
convipvers(Conv *c)
|
convipvers(Conv *c)
|
||||||
{
|
{
|
||||||
|
@ -375,3 +257,313 @@ convipvers(Conv *c)
|
||||||
else
|
else
|
||||||
return V6;
|
return V6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hashing tcp, udp, ... connections
|
||||||
|
*/
|
||||||
|
static ulong
|
||||||
|
iphash(uchar *sa, ushort sp, uchar *da, ushort dp)
|
||||||
|
{
|
||||||
|
return ((sa[IPaddrlen-1]<<24) ^ (sp << 16) ^ (da[IPaddrlen-1]<<8) ^ dp ) % Nipht;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
iphtadd(Ipht *ht, Iphash *h)
|
||||||
|
{
|
||||||
|
ulong hv;
|
||||||
|
|
||||||
|
if(ipcmp(h->raddr, IPnoaddr) != 0)
|
||||||
|
h->match = IPmatchexact;
|
||||||
|
else {
|
||||||
|
if(ipcmp(h->laddr, IPnoaddr) != 0){
|
||||||
|
if(h->lport == 0)
|
||||||
|
h->match = IPmatchaddr;
|
||||||
|
else
|
||||||
|
h->match = IPmatchpa;
|
||||||
|
} else {
|
||||||
|
if(h->lport == 0)
|
||||||
|
h->match = IPmatchany;
|
||||||
|
else
|
||||||
|
h->match = IPmatchport;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lock(ht);
|
||||||
|
hv = iphash(h->raddr, h->rport, h->laddr, h->lport);
|
||||||
|
h->nextiphash = ht->tab[hv];
|
||||||
|
ht->tab[hv] = h;
|
||||||
|
unlock(ht);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
iphtrem(Ipht *ht, Iphash *h)
|
||||||
|
{
|
||||||
|
ulong hv;
|
||||||
|
Iphash **l;
|
||||||
|
|
||||||
|
lock(ht);
|
||||||
|
hv = iphash(h->raddr, h->rport, h->laddr, h->lport);
|
||||||
|
for(l = &ht->tab[hv]; (*l) != nil; l = &(*l)->nextiphash)
|
||||||
|
if(*l == h){
|
||||||
|
(*l) = h->nextiphash;
|
||||||
|
h->nextiphash = nil;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
unlock(ht);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* look for a matching iphash with the following precedence
|
||||||
|
* raddr,rport,laddr,lport
|
||||||
|
* laddr,lport
|
||||||
|
* *,lport
|
||||||
|
* laddr,*
|
||||||
|
* *,*
|
||||||
|
*/
|
||||||
|
Iphash*
|
||||||
|
iphtlook(Ipht *ht, uchar *sa, ushort sp, uchar *da, ushort dp)
|
||||||
|
{
|
||||||
|
ulong hv;
|
||||||
|
Iphash *h;
|
||||||
|
|
||||||
|
lock(ht);
|
||||||
|
/* exact 4 pair match (connection) */
|
||||||
|
hv = iphash(sa, sp, da, dp);
|
||||||
|
for(h = ht->tab[hv]; h != nil; h = h->nextiphash){
|
||||||
|
if(h->match != IPmatchexact)
|
||||||
|
continue;
|
||||||
|
if(sp == h->rport && dp == h->lport
|
||||||
|
&& ipcmp(sa, h->raddr) == 0 && ipcmp(da, h->laddr) == 0){
|
||||||
|
unlock(ht);
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* match local address and port */
|
||||||
|
hv = iphash(IPnoaddr, 0, da, dp);
|
||||||
|
for(h = ht->tab[hv]; h != nil; h = h->nextiphash){
|
||||||
|
if(h->match != IPmatchpa)
|
||||||
|
continue;
|
||||||
|
if(dp == h->lport && ipcmp(da, h->laddr) == 0){
|
||||||
|
unlock(ht);
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* match just port */
|
||||||
|
hv = iphash(IPnoaddr, 0, IPnoaddr, dp);
|
||||||
|
for(h = ht->tab[hv]; h != nil; h = h->nextiphash){
|
||||||
|
if(h->match != IPmatchport)
|
||||||
|
continue;
|
||||||
|
if(dp == h->lport){
|
||||||
|
unlock(ht);
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* match local address */
|
||||||
|
hv = iphash(IPnoaddr, 0, da, 0);
|
||||||
|
for(h = ht->tab[hv]; h != nil; h = h->nextiphash){
|
||||||
|
if(h->match != IPmatchaddr)
|
||||||
|
continue;
|
||||||
|
if(ipcmp(da, h->laddr) == 0){
|
||||||
|
unlock(ht);
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* look for something that matches anything */
|
||||||
|
hv = iphash(IPnoaddr, 0, IPnoaddr, 0);
|
||||||
|
for(h = ht->tab[hv]; h != nil; h = h->nextiphash){
|
||||||
|
if(h->match != IPmatchany)
|
||||||
|
continue;
|
||||||
|
unlock(ht);
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
unlock(ht);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Move entry to front of Proto.translations
|
||||||
|
* and update the timestamp.
|
||||||
|
*
|
||||||
|
* Proto is locked.
|
||||||
|
*/
|
||||||
|
static Translation*
|
||||||
|
transupdate(Proto *p, Translation *q)
|
||||||
|
{
|
||||||
|
q->time = NOW;
|
||||||
|
|
||||||
|
/* unlink */
|
||||||
|
if(q->link != nil && (*q->link = q->next) != nil)
|
||||||
|
q->next->link = q->link;
|
||||||
|
|
||||||
|
/* link to front */
|
||||||
|
if((q->next = p->translations) != nil)
|
||||||
|
q->next->link = &q->next;
|
||||||
|
p->translations = q;
|
||||||
|
q->link = &p->translations;
|
||||||
|
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called with the 4-tuple (sa,sp,da,dp)
|
||||||
|
* that should be source translated,
|
||||||
|
* returning the translation.
|
||||||
|
*
|
||||||
|
* Proto is locked.
|
||||||
|
*/
|
||||||
|
Translation*
|
||||||
|
transforward(Proto *p, Ipht *ht, uchar *sa, int sp, uchar *da, int dp, Route *r)
|
||||||
|
{
|
||||||
|
uchar ia[IPaddrlen];
|
||||||
|
Routehint rh;
|
||||||
|
Translation *q;
|
||||||
|
Iphash *iph;
|
||||||
|
Ipifc *ifc;
|
||||||
|
int lport;
|
||||||
|
ulong now;
|
||||||
|
int num;
|
||||||
|
|
||||||
|
/* Translation already exists? */
|
||||||
|
iph = iphtlook(ht, sa, sp, da, dp);
|
||||||
|
if(iph != nil) {
|
||||||
|
if(iph->trans != 1)
|
||||||
|
return nil;
|
||||||
|
return transupdate(p, iphforward(iph));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bad source address? */
|
||||||
|
if(ipismulticast(sa) || ipforme(p->f, sa) != 0){
|
||||||
|
netlog(p->f, Logtrans, "trans: bad source address: %s!%I!%d -> %I!%d\n",
|
||||||
|
p->name, sa, sp, da, dp);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bad forward route? */
|
||||||
|
if(r == nil || (ifc = r->ifc) == nil){
|
||||||
|
netlog(p->f, Logtrans, "trans: no forward route: %s!%I!%d -> %I!%d\n",
|
||||||
|
p->name, sa, sp, da, dp);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find a source address on the destination interface */
|
||||||
|
rlock(ifc);
|
||||||
|
memmove(ia, v4prefix, IPv4off);
|
||||||
|
if(!ipv4local(ifc, ia+IPv4off, 0, (r->type & (Rifc|Runi|Rbcast|Rmulti))? da+IPv4off: r->v4.gate)){
|
||||||
|
runlock(ifc);
|
||||||
|
netlog(p->f, Logtrans, "trans: no source ip: %s!%I!%d -> %I!%d\n",
|
||||||
|
p->name, sa, sp, da, dp);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
runlock(ifc);
|
||||||
|
|
||||||
|
/* Check backward route */
|
||||||
|
rh.a = nil;
|
||||||
|
rh.r = nil;
|
||||||
|
if(ipismulticast(da))
|
||||||
|
r = v4lookup(p->f, sa+IPv4off, ia+IPv4off, nil);
|
||||||
|
else
|
||||||
|
r = v4lookup(p->f, sa+IPv4off, da+IPv4off, &rh);
|
||||||
|
if(r == nil || (r->ifc == ifc && !ifc->reflect)){
|
||||||
|
netlog(p->f, Logtrans, "trans: bad backward route: %s!%I!%d <- %I <- %I!%d\n",
|
||||||
|
p->name, sa, sp, ia, da, dp);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find local port */
|
||||||
|
lport = unusedlport(p);
|
||||||
|
if(lport <= 0){
|
||||||
|
netlog(p->f, Logtrans, "trans: no local port: %s!%I!%d <- %I <- %I!%d\n",
|
||||||
|
p->name, sa, sp, ia, da, dp);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reuse expired entries */
|
||||||
|
num = 0;
|
||||||
|
now = NOW;
|
||||||
|
for(q = p->translations; q != nil; q = q->next) {
|
||||||
|
if(++num >= 1000 || (now - q->time) >= 5*60*1000){
|
||||||
|
netlog(p->f, Logtrans, "trans: removing %s!%I!%d -> %I!%d -> %I!%d\n",
|
||||||
|
p->name,
|
||||||
|
q->forward.raddr, q->forward.rport,
|
||||||
|
q->backward.laddr, q->backward.lport,
|
||||||
|
q->forward.laddr, q->forward.lport);
|
||||||
|
|
||||||
|
iphtrem(ht, &q->forward);
|
||||||
|
iphtrem(ht, &q->backward);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(q == nil){
|
||||||
|
q = malloc(sizeof(*q));
|
||||||
|
if(q == nil)
|
||||||
|
return nil;
|
||||||
|
q->link = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Match what needs to be forwarded */
|
||||||
|
q->forward.trans = 1;
|
||||||
|
q->forward.lport = dp;
|
||||||
|
q->forward.rport = sp;
|
||||||
|
ipmove(q->forward.laddr, da);
|
||||||
|
ipmove(q->forward.raddr, sa);
|
||||||
|
|
||||||
|
/* Match what comes back to us */
|
||||||
|
q->backward.trans = 2;
|
||||||
|
q->backward.lport = lport;
|
||||||
|
ipmove(q->backward.laddr, ia);
|
||||||
|
if(p->ipproto == 1 || ipismulticast(da)){
|
||||||
|
q->backward.rport = 0;
|
||||||
|
ipmove(q->backward.raddr, IPnoaddr);
|
||||||
|
} else {
|
||||||
|
q->backward.rport = dp;
|
||||||
|
ipmove(q->backward.raddr, da);
|
||||||
|
}
|
||||||
|
memmove(&q->Routehint, &rh, sizeof(rh));
|
||||||
|
|
||||||
|
netlog(p->f, Logtrans, "trans: adding %s!%I!%d -> %I!%d -> %I!%d\n",
|
||||||
|
p->name,
|
||||||
|
q->forward.raddr, q->forward.rport,
|
||||||
|
q->backward.laddr, q->backward.lport,
|
||||||
|
q->forward.laddr, q->forward.lport);
|
||||||
|
|
||||||
|
iphtadd(ht, &q->forward);
|
||||||
|
iphtadd(ht, &q->backward);
|
||||||
|
|
||||||
|
return transupdate(p, q);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if backward translation is valid and
|
||||||
|
* update timestamp.
|
||||||
|
*
|
||||||
|
* Proto is locked.
|
||||||
|
*/
|
||||||
|
Translation*
|
||||||
|
transbackward(Proto *p, Iphash *iph)
|
||||||
|
{
|
||||||
|
if(iph == nil || iph->trans != 2)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
return transupdate(p, iphbackward(iph));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checksum adjusting hnputs()
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
hnputs_csum(void *p, ushort v, uchar *pcsum)
|
||||||
|
{
|
||||||
|
ulong csum;
|
||||||
|
|
||||||
|
assert((((uchar*)p - pcsum) & 1) == 0);
|
||||||
|
|
||||||
|
csum = nhgets(pcsum)^0xFFFF;
|
||||||
|
csum += nhgets(p)^0xFFFF;
|
||||||
|
csum += v;
|
||||||
|
hnputs(p, v);
|
||||||
|
while(v = csum >> 16)
|
||||||
|
csum = (csum & 0xFFFF) + v;
|
||||||
|
hnputs(pcsum, csum^0xFFFF);
|
||||||
|
}
|
||||||
|
|
|
@ -1435,21 +1435,6 @@ ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip)
|
||||||
return ipremoteonifc(ifc, ip) != nil;
|
return ipremoteonifc(ifc, ip) != nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* return multicast version if any
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
ipismulticast(uchar *ip)
|
|
||||||
{
|
|
||||||
if(isv4(ip)){
|
|
||||||
if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
|
|
||||||
return V4;
|
|
||||||
}
|
|
||||||
else if(ip[0] == 0xff)
|
|
||||||
return V6;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* add a multicast address to an interface.
|
* add a multicast address to an interface.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -875,6 +875,9 @@ parseroutetype(char *p)
|
||||||
case 'p':
|
case 'p':
|
||||||
if(((type ^= Rptpt) & Rptpt) != Rptpt) return -1;
|
if(((type ^= Rptpt) & Rptpt) != Rptpt) return -1;
|
||||||
break;
|
break;
|
||||||
|
case 't':
|
||||||
|
if(((type ^= Rtrans) & Rtrans) != Rtrans) return -1;
|
||||||
|
break;
|
||||||
case '\0':
|
case '\0':
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
@ -900,6 +903,10 @@ routetype(int type, char p[8])
|
||||||
|
|
||||||
if(type & Rptpt)
|
if(type & Rptpt)
|
||||||
*p++ = 'p';
|
*p++ = 'p';
|
||||||
|
|
||||||
|
if(type & Rtrans)
|
||||||
|
*p++ = 't';
|
||||||
|
|
||||||
*p = 0;
|
*p = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -278,7 +278,7 @@ ipiput6(Fs *f, Ipifc *ifc, Block *bp)
|
||||||
|
|
||||||
/* 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]++;
|
||||||
icmpttlexceeded6(f, ifc, bp);
|
icmpttlexceeded6(f, ifc, bp);
|
||||||
goto drop;
|
goto drop;
|
||||||
|
@ -292,7 +292,6 @@ ipiput6(Fs *f, Ipifc *ifc, Block *bp)
|
||||||
ip->stats[ForwDatagrams]++;
|
ip->stats[ForwDatagrams]++;
|
||||||
h = (Ip6hdr*)bp->rp;
|
h = (Ip6hdr*)bp->rp;
|
||||||
tos = (h->vcf[0]&0x0F)<<2 | (h->vcf[1]&0xF0)>>2;
|
tos = (h->vcf[0]&0x0F)<<2 | (h->vcf[1]&0xF0)>>2;
|
||||||
hop = h->ttl;
|
|
||||||
ipoput6(f, bp, 1, hop - 1, tos, &rh);
|
ipoput6(f, bp, 1, hop - 1, tos, &rh);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ static Netlogflag flags[] =
|
||||||
{ "udpmsg", Logudp|Logudpmsg, },
|
{ "udpmsg", Logudp|Logudpmsg, },
|
||||||
{ "ipmsg", Logip|Logipmsg, },
|
{ "ipmsg", Logip|Logipmsg, },
|
||||||
{ "esp", Logesp, },
|
{ "esp", Logesp, },
|
||||||
|
{ "trans", Logtrans, },
|
||||||
{ nil, 0, },
|
{ nil, 0, },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -220,9 +220,10 @@ rudpconnect(Conv *c, char **argv, int argc)
|
||||||
rudpstartackproc(c->p);
|
rudpstartackproc(c->p);
|
||||||
e = Fsstdconnect(c, argv, argc);
|
e = Fsstdconnect(c, argv, argc);
|
||||||
Fsconnected(c, e);
|
Fsconnected(c, e);
|
||||||
iphtadd(&upriv->ht, c);
|
if(e != nil)
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
|
iphtadd(&upriv->ht, c);
|
||||||
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -256,7 +257,6 @@ rudpannounce(Conv *c, char** argv, int argc)
|
||||||
return e;
|
return e;
|
||||||
Fsconnected(c, nil);
|
Fsconnected(c, nil);
|
||||||
iphtadd(&upriv->ht, c);
|
iphtadd(&upriv->ht, c);
|
||||||
|
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,10 +289,11 @@ rudpclose(Conv *c)
|
||||||
qclose(c->rq);
|
qclose(c->rq);
|
||||||
qclose(c->wq);
|
qclose(c->wq);
|
||||||
qclose(c->eq);
|
qclose(c->eq);
|
||||||
ipmove(c->laddr, IPnoaddr);
|
|
||||||
ipmove(c->raddr, IPnoaddr);
|
|
||||||
c->lport = 0;
|
c->lport = 0;
|
||||||
|
ipmove(c->laddr, IPnoaddr);
|
||||||
c->rport = 0;
|
c->rport = 0;
|
||||||
|
ipmove(c->raddr, IPnoaddr);
|
||||||
|
|
||||||
ucb->headers = 0;
|
ucb->headers = 0;
|
||||||
ucb->randdrop = 0;
|
ucb->randdrop = 0;
|
||||||
|
@ -460,11 +461,12 @@ rudpkick(void *x)
|
||||||
void
|
void
|
||||||
rudpiput(Proto *rudp, Ipifc *ifc, Block *bp)
|
rudpiput(Proto *rudp, Ipifc *ifc, Block *bp)
|
||||||
{
|
{
|
||||||
int len, olen, ottl;
|
int len, olen;
|
||||||
Udphdr *uh;
|
Udphdr *uh;
|
||||||
|
Iphash *iph;
|
||||||
Conv *c;
|
Conv *c;
|
||||||
Rudpcb *ucb;
|
Rudpcb *ucb;
|
||||||
uchar raddr[IPaddrlen], laddr[IPaddrlen];
|
uchar raddr[IPaddrlen], laddr[IPaddrlen], ottl;
|
||||||
ushort rport, lport;
|
ushort rport, lport;
|
||||||
Rudppriv *upriv;
|
Rudppriv *upriv;
|
||||||
Fs *f;
|
Fs *f;
|
||||||
|
@ -503,9 +505,8 @@ rudpiput(Proto *rudp, Ipifc *ifc, Block *bp)
|
||||||
}
|
}
|
||||||
|
|
||||||
qlock(rudp);
|
qlock(rudp);
|
||||||
|
iph = iphtlook(&upriv->ht, raddr, rport, laddr, lport);
|
||||||
c = iphtlook(&upriv->ht, raddr, rport, laddr, lport);
|
if(iph == nil){
|
||||||
if(c == nil){
|
|
||||||
/* no conversation found */
|
/* no conversation found */
|
||||||
upriv->ustats.rudpNoPorts++;
|
upriv->ustats.rudpNoPorts++;
|
||||||
qunlock(rudp);
|
qunlock(rudp);
|
||||||
|
@ -517,6 +518,7 @@ rudpiput(Proto *rudp, Ipifc *ifc, Block *bp)
|
||||||
freeblist(bp);
|
freeblist(bp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
c = iphconv(iph);
|
||||||
ucb = (Rudpcb*)c->ptcl;
|
ucb = (Rudpcb*)c->ptcl;
|
||||||
qlock(ucb);
|
qlock(ucb);
|
||||||
qunlock(rudp);
|
qunlock(rudp);
|
||||||
|
|
|
@ -126,7 +126,7 @@ struct Tcp4hdr
|
||||||
uchar length[2]; /* packet length */
|
uchar length[2]; /* packet length */
|
||||||
uchar id[2]; /* Identification */
|
uchar id[2]; /* Identification */
|
||||||
uchar frag[2]; /* Fragment information */
|
uchar frag[2]; /* Fragment information */
|
||||||
uchar Unused;
|
uchar ttl;
|
||||||
uchar proto;
|
uchar proto;
|
||||||
uchar tcplen[2];
|
uchar tcplen[2];
|
||||||
uchar tcpsrc[4];
|
uchar tcpsrc[4];
|
||||||
|
@ -1814,9 +1814,7 @@ tcpincoming(Conv *s, Tcp *segp, uchar *src, uchar *dst, uchar version)
|
||||||
}
|
}
|
||||||
|
|
||||||
tcpsetstate(new, Established);
|
tcpsetstate(new, Established);
|
||||||
|
|
||||||
iphtadd(&tpriv->ht, new);
|
iphtadd(&tpriv->ht, new);
|
||||||
|
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2068,10 +2066,11 @@ tcpiput(Proto *tcp, Ipifc*, Block *bp)
|
||||||
Tcp seg;
|
Tcp seg;
|
||||||
Tcp4hdr *h4;
|
Tcp4hdr *h4;
|
||||||
Tcp6hdr *h6;
|
Tcp6hdr *h6;
|
||||||
int hdrlen;
|
|
||||||
Tcpctl *tcb;
|
Tcpctl *tcb;
|
||||||
ushort length, csum;
|
int hdrlen;
|
||||||
|
ushort length;
|
||||||
uchar source[IPaddrlen], dest[IPaddrlen];
|
uchar source[IPaddrlen], dest[IPaddrlen];
|
||||||
|
Iphash *iph;
|
||||||
Conv *s;
|
Conv *s;
|
||||||
Fs *f;
|
Fs *f;
|
||||||
Tcppriv *tpriv;
|
Tcppriv *tpriv;
|
||||||
|
@ -2087,21 +2086,32 @@ tcpiput(Proto *tcp, Ipifc*, Block *bp)
|
||||||
h6 = (Tcp6hdr*)(bp->rp);
|
h6 = (Tcp6hdr*)(bp->rp);
|
||||||
|
|
||||||
if((h4->vihl&0xF0)==IP_VER4) {
|
if((h4->vihl&0xF0)==IP_VER4) {
|
||||||
|
int ttl = h4->ttl;
|
||||||
|
|
||||||
version = V4;
|
version = V4;
|
||||||
length = nhgets(h4->length);
|
length = nhgets(h4->length);
|
||||||
|
if(length < TCP4_PKT){
|
||||||
|
tpriv->stats[HlenErrs]++;
|
||||||
|
tpriv->stats[InErrs]++;
|
||||||
|
netlog(f, Logtcp, "bad tcp len\n");
|
||||||
|
freeblist(bp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
length -= TCP4_PKT;
|
||||||
v4tov6(dest, h4->tcpdst);
|
v4tov6(dest, h4->tcpdst);
|
||||||
v4tov6(source, h4->tcpsrc);
|
v4tov6(source, h4->tcpsrc);
|
||||||
|
|
||||||
h4->Unused = 0;
|
h4->ttl = 0;
|
||||||
hnputs(h4->tcplen, length-TCP4_PKT);
|
hnputs(h4->tcplen, length);
|
||||||
if(!(bp->flag & Btcpck) && (h4->tcpcksum[0] || h4->tcpcksum[1]) &&
|
if(!(bp->flag & Btcpck) && (h4->tcpcksum[0] || h4->tcpcksum[1])
|
||||||
ptclcsum(bp, TCP4_IPLEN, length-TCP4_IPLEN)) {
|
&& ptclcsum(bp, TCP4_IPLEN, length + TCP4_PKT - TCP4_IPLEN)) {
|
||||||
tpriv->stats[CsumErrs]++;
|
tpriv->stats[CsumErrs]++;
|
||||||
tpriv->stats[InErrs]++;
|
tpriv->stats[InErrs]++;
|
||||||
netlog(f, Logtcp, "bad tcp proto cksum\n");
|
netlog(f, Logtcp, "bad tcp proto cksum\n");
|
||||||
freeblist(bp);
|
freeblist(bp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
h4->ttl = ttl;
|
||||||
|
|
||||||
hdrlen = ntohtcp4(&seg, &bp);
|
hdrlen = ntohtcp4(&seg, &bp);
|
||||||
if(hdrlen < 0){
|
if(hdrlen < 0){
|
||||||
|
@ -2110,16 +2120,8 @@ tcpiput(Proto *tcp, Ipifc*, Block *bp)
|
||||||
netlog(f, Logtcp, "bad tcp hdr len\n");
|
netlog(f, Logtcp, "bad tcp hdr len\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
length -= hdrlen;
|
||||||
/* trim the packet to the size claimed by the datagram */
|
hdrlen += TCP4_PKT;
|
||||||
length -= hdrlen+TCP4_PKT;
|
|
||||||
bp = trimblock(bp, hdrlen+TCP4_PKT, length);
|
|
||||||
if(bp == nil){
|
|
||||||
tpriv->stats[LenErrs]++;
|
|
||||||
tpriv->stats[InErrs]++;
|
|
||||||
netlog(f, Logtcp, "tcp len < 0 after trim\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int ttl = h6->ttl;
|
int ttl = h6->ttl;
|
||||||
|
@ -2133,13 +2135,13 @@ tcpiput(Proto *tcp, Ipifc*, Block *bp)
|
||||||
h6->ploadlen[0] = h6->ploadlen[1] = h6->proto = 0;
|
h6->ploadlen[0] = h6->ploadlen[1] = h6->proto = 0;
|
||||||
h6->ttl = proto;
|
h6->ttl = proto;
|
||||||
hnputl(h6->vcf, length);
|
hnputl(h6->vcf, length);
|
||||||
if((h6->tcpcksum[0] || h6->tcpcksum[1]) &&
|
if((h6->tcpcksum[0] || h6->tcpcksum[1])
|
||||||
(csum = ptclcsum(bp, TCP6_IPLEN, length+TCP6_PHDRSIZE)) != 0) {
|
&& ptclcsum(bp, TCP6_IPLEN, length+TCP6_PHDRSIZE) != 0) {
|
||||||
tpriv->stats[CsumErrs]++;
|
tpriv->stats[CsumErrs]++;
|
||||||
tpriv->stats[InErrs]++;
|
tpriv->stats[InErrs]++;
|
||||||
netlog(f, Logtcp,
|
netlog(f, Logtcp,
|
||||||
"bad tcpv6 proto cksum: got %#ux, computed %#ux\n",
|
"bad tcpv6 proto cksum: got %#ux\n",
|
||||||
h6->tcpcksum[0]<<8 | h6->tcpcksum[1], csum);
|
h6->tcpcksum[0]<<8 | h6->tcpcksum[1]);
|
||||||
freeblist(bp);
|
freeblist(bp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2154,24 +2156,16 @@ tcpiput(Proto *tcp, Ipifc*, Block *bp)
|
||||||
netlog(f, Logtcp, "bad tcpv6 hdr len\n");
|
netlog(f, Logtcp, "bad tcpv6 hdr len\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* trim the packet to the size claimed by the datagram */
|
|
||||||
length -= hdrlen;
|
length -= hdrlen;
|
||||||
bp = trimblock(bp, hdrlen+TCP6_PKT, length);
|
hdrlen += TCP6_PKT;
|
||||||
if(bp == nil){
|
|
||||||
tpriv->stats[LenErrs]++;
|
|
||||||
tpriv->stats[InErrs]++;
|
|
||||||
netlog(f, Logtcp, "tcpv6 len < 0 after trim\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* lock protocol while searching for a conversation */
|
/* lock protocol while searching for a conversation */
|
||||||
qlock(tcp);
|
qlock(tcp);
|
||||||
|
|
||||||
/* Look for a matching conversation */
|
/* Look for a matching conversation */
|
||||||
s = iphtlook(&tpriv->ht, source, seg.source, dest, seg.dest);
|
iph = iphtlook(&tpriv->ht, source, seg.source, dest, seg.dest);
|
||||||
if(s == nil){
|
if(iph == nil){
|
||||||
netlog(f, Logtcp, "iphtlook(src %I!%d, dst %I!%d) failed\n",
|
netlog(f, Logtcp, "iphtlook(src %I!%d, dst %I!%d) failed\n",
|
||||||
source, seg.source, dest, seg.dest);
|
source, seg.source, dest, seg.dest);
|
||||||
reset:
|
reset:
|
||||||
|
@ -2180,6 +2174,30 @@ reset:
|
||||||
sndrst(tcp, source, dest, length, &seg, version, "no conversation", nil);
|
sndrst(tcp, source, dest, length, &seg, version, "no conversation", nil);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if(iph->trans){
|
||||||
|
Translation *q;
|
||||||
|
int hop = h4->ttl;
|
||||||
|
|
||||||
|
if(hop <= 1 || (q = transbackward(tcp, iph)) == nil)
|
||||||
|
goto reset;
|
||||||
|
hnputs_csum(h4->tcpdst+0, nhgets(q->forward.raddr+IPv4off+0), h4->tcpcksum);
|
||||||
|
hnputs_csum(h4->tcpdst+2, nhgets(q->forward.raddr+IPv4off+2), h4->tcpcksum);
|
||||||
|
hnputs_csum(h4->tcpdport, q->forward.rport, h4->tcpcksum);
|
||||||
|
qunlock(tcp);
|
||||||
|
ipoput4(f, bp, 1, hop - 1, h4->tos, q);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s = iphconv(iph);
|
||||||
|
|
||||||
|
/* trim off ip and tcp headers */
|
||||||
|
bp = trimblock(bp, hdrlen, length);
|
||||||
|
if(bp == nil){
|
||||||
|
tpriv->stats[LenErrs]++;
|
||||||
|
tpriv->stats[InErrs]++;
|
||||||
|
netlog(f, Logtcp, "tcp bad length after header trim off\n");
|
||||||
|
qunlock(tcp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* if it's a listener, look for the right flags and get a new conv */
|
/* if it's a listener, look for the right flags and get a new conv */
|
||||||
tcb = (Tcpctl*)s->ptcl;
|
tcb = (Tcpctl*)s->ptcl;
|
||||||
|
@ -3200,11 +3218,12 @@ tcpadvise(Proto *tcp, Block *bp, char *msg)
|
||||||
{
|
{
|
||||||
Tcp4hdr *h4;
|
Tcp4hdr *h4;
|
||||||
Tcp6hdr *h6;
|
Tcp6hdr *h6;
|
||||||
Tcpctl *tcb;
|
|
||||||
uchar source[IPaddrlen];
|
uchar source[IPaddrlen];
|
||||||
uchar dest[IPaddrlen];
|
uchar dest[IPaddrlen];
|
||||||
ushort psource, pdest;
|
ushort psource, pdest;
|
||||||
Conv *s, **p;
|
Iphash *iph;
|
||||||
|
Tcpctl *tcb;
|
||||||
|
Conv *s;
|
||||||
|
|
||||||
h4 = (Tcp4hdr*)(bp->rp);
|
h4 = (Tcp4hdr*)(bp->rp);
|
||||||
h6 = (Tcp6hdr*)(bp->rp);
|
h6 = (Tcp6hdr*)(bp->rp);
|
||||||
|
@ -3221,33 +3240,73 @@ tcpadvise(Proto *tcp, Block *bp, char *msg)
|
||||||
pdest = nhgets(h6->tcpdport);
|
pdest = nhgets(h6->tcpdport);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Look for a connection */
|
/* Look for a connection (source/dest reversed; this is the original packet we sent) */
|
||||||
qlock(tcp);
|
qlock(tcp);
|
||||||
for(p = tcp->conv; (s = *p) != nil; p++) {
|
iph = iphtlook(&((Tcppriv*)tcp->priv)->ht, dest, pdest, source, psource);
|
||||||
tcb = (Tcpctl*)s->ptcl;
|
if(iph == nil)
|
||||||
if(s->rport == pdest)
|
goto raise;
|
||||||
if(s->lport == psource)
|
if(iph->trans){
|
||||||
if(tcb->state != Closed)
|
Translation *q;
|
||||||
if(ipcmp(s->raddr, dest) == 0)
|
|
||||||
if(ipcmp(s->laddr, source) == 0){
|
if((q = transbackward(tcp, iph)) == nil)
|
||||||
if(s->ignoreadvice)
|
goto raise;
|
||||||
break;
|
|
||||||
|
/* h4->tcplen is the ip header checksum */
|
||||||
|
hnputs_csum(h4->tcpsrc+0, nhgets(q->forward.raddr+IPv4off+0), h4->tcplen);
|
||||||
|
hnputs_csum(h4->tcpsrc+2, nhgets(q->forward.raddr+IPv4off+2), h4->tcplen);
|
||||||
|
|
||||||
|
/* dont bother fixing tcp checksum, packet is most likely truncated */
|
||||||
|
hnputs(h4->tcpsport, q->forward.rport);
|
||||||
|
qunlock(tcp);
|
||||||
|
|
||||||
|
icmpproxyadvice(tcp->f, bp, h4->tcpsrc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s = iphconv(iph);
|
||||||
|
if(s->ignoreadvice || s->state == Closed)
|
||||||
|
goto raise;
|
||||||
qlock(s);
|
qlock(s);
|
||||||
qunlock(tcp);
|
qunlock(tcp);
|
||||||
switch(tcb->state){
|
tcb = (Tcpctl*)s->ptcl;
|
||||||
case Syn_sent:
|
if(tcb->state == Syn_sent)
|
||||||
localclose(s, msg);
|
localclose(s, msg);
|
||||||
break;
|
|
||||||
}
|
|
||||||
qunlock(s);
|
qunlock(s);
|
||||||
freeblist(bp);
|
freeblist(bp);
|
||||||
return;
|
return;
|
||||||
}
|
raise:
|
||||||
}
|
|
||||||
qunlock(tcp);
|
qunlock(tcp);
|
||||||
freeblist(bp);
|
freeblist(bp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Block*
|
||||||
|
tcpforward(Proto *tcp, Block *bp, Route *r)
|
||||||
|
{
|
||||||
|
uchar da[IPaddrlen], sa[IPaddrlen];
|
||||||
|
ushort dp, sp;
|
||||||
|
Tcp4hdr *h4;
|
||||||
|
Translation *q;
|
||||||
|
|
||||||
|
h4 = (Tcp4hdr*)(bp->rp);
|
||||||
|
v4tov6(da, h4->tcpdst);
|
||||||
|
v4tov6(sa, h4->tcpsrc);
|
||||||
|
dp = nhgets(h4->tcpdport);
|
||||||
|
sp = nhgets(h4->tcpsport);
|
||||||
|
|
||||||
|
qlock(tcp);
|
||||||
|
q = transforward(tcp, &((Tcppriv*)tcp->priv)->ht, sa, sp, da, dp, r);
|
||||||
|
if(q == nil){
|
||||||
|
qunlock(tcp);
|
||||||
|
freeblist(bp);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
hnputs_csum(h4->tcpsrc+0, nhgets(q->backward.laddr+IPv4off+0), h4->tcpcksum);
|
||||||
|
hnputs_csum(h4->tcpsrc+2, nhgets(q->backward.laddr+IPv4off+2), h4->tcpcksum);
|
||||||
|
hnputs_csum(h4->tcpsport, q->backward.lport, h4->tcpcksum);
|
||||||
|
qunlock(tcp);
|
||||||
|
|
||||||
|
return bp;
|
||||||
|
}
|
||||||
|
|
||||||
static char*
|
static char*
|
||||||
tcpporthogdefensectl(char *val)
|
tcpporthogdefensectl(char *val)
|
||||||
{
|
{
|
||||||
|
@ -3371,6 +3430,7 @@ tcpinit(Fs *fs)
|
||||||
tcp->close = tcpclose;
|
tcp->close = tcpclose;
|
||||||
tcp->rcv = tcpiput;
|
tcp->rcv = tcpiput;
|
||||||
tcp->advise = tcpadvise;
|
tcp->advise = tcpadvise;
|
||||||
|
tcp->forward = tcpforward;
|
||||||
tcp->stats = tcpstats;
|
tcp->stats = tcpstats;
|
||||||
tcp->inuse = tcpinuse;
|
tcp->inuse = tcpinuse;
|
||||||
tcp->gc = tcpgc;
|
tcp->gc = tcpgc;
|
||||||
|
|
|
@ -39,7 +39,7 @@ struct Udp4hdr
|
||||||
uchar length[2]; /* packet length */
|
uchar length[2]; /* packet length */
|
||||||
uchar id[2]; /* Identification */
|
uchar id[2]; /* Identification */
|
||||||
uchar frag[2]; /* Fragment information */
|
uchar frag[2]; /* Fragment information */
|
||||||
uchar Unused;
|
uchar ttl; /* Time to live */
|
||||||
uchar udpproto; /* Protocol */
|
uchar udpproto; /* Protocol */
|
||||||
uchar udpplen[2]; /* Header plus data length */
|
uchar udpplen[2]; /* Header plus data length */
|
||||||
uchar udpsrc[IPv4addrlen]; /* Ip source */
|
uchar udpsrc[IPv4addrlen]; /* Ip source */
|
||||||
|
@ -91,7 +91,6 @@ struct Udppriv
|
||||||
ulong lenerr; /* short packet */
|
ulong lenerr; /* short packet */
|
||||||
};
|
};
|
||||||
|
|
||||||
void (*etherprofiler)(char *name, int qlen);
|
|
||||||
void udpkick(void *x, Block *bp);
|
void udpkick(void *x, Block *bp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -114,7 +113,6 @@ udpconnect(Conv *c, char **argv, int argc)
|
||||||
Fsconnected(c, e);
|
Fsconnected(c, e);
|
||||||
if(e != nil)
|
if(e != nil)
|
||||||
return e;
|
return e;
|
||||||
|
|
||||||
iphtadd(&upriv->ht, c);
|
iphtadd(&upriv->ht, c);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
@ -142,7 +140,6 @@ udpannounce(Conv *c, char** argv, int argc)
|
||||||
return e;
|
return e;
|
||||||
Fsconnected(c, nil);
|
Fsconnected(c, nil);
|
||||||
iphtadd(&upriv->ht, c);
|
iphtadd(&upriv->ht, c);
|
||||||
|
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,10 +163,10 @@ udpclose(Conv *c)
|
||||||
qclose(c->rq);
|
qclose(c->rq);
|
||||||
qclose(c->wq);
|
qclose(c->wq);
|
||||||
qclose(c->eq);
|
qclose(c->eq);
|
||||||
ipmove(c->laddr, IPnoaddr);
|
|
||||||
ipmove(c->raddr, IPnoaddr);
|
|
||||||
c->lport = 0;
|
c->lport = 0;
|
||||||
|
ipmove(c->laddr, IPnoaddr);
|
||||||
c->rport = 0;
|
c->rport = 0;
|
||||||
|
ipmove(c->raddr, IPnoaddr);
|
||||||
|
|
||||||
ucb = (Udpcb*)c->ptcl;
|
ucb = (Udpcb*)c->ptcl;
|
||||||
ucb->headers = 0;
|
ucb->headers = 0;
|
||||||
|
@ -238,7 +235,7 @@ udpkick(void *x, Block *bp)
|
||||||
bp = padblock(bp, UDP4_IPHDR_SZ+UDP_UDPHDR_SZ);
|
bp = padblock(bp, UDP4_IPHDR_SZ+UDP_UDPHDR_SZ);
|
||||||
uh4 = (Udp4hdr *)(bp->rp);
|
uh4 = (Udp4hdr *)(bp->rp);
|
||||||
ptcllen = dlen + UDP_UDPHDR_SZ;
|
ptcllen = dlen + UDP_UDPHDR_SZ;
|
||||||
uh4->Unused = 0;
|
uh4->ttl = 0;
|
||||||
uh4->udpproto = IP_UDPPROTO;
|
uh4->udpproto = IP_UDPPROTO;
|
||||||
uh4->frag[0] = 0;
|
uh4->frag[0] = 0;
|
||||||
uh4->frag[1] = 0;
|
uh4->frag[1] = 0;
|
||||||
|
@ -319,6 +316,7 @@ udpiput(Proto *udp, Ipifc *ifc, Block *bp)
|
||||||
int len;
|
int len;
|
||||||
Udp4hdr *uh4;
|
Udp4hdr *uh4;
|
||||||
Udp6hdr *uh6;
|
Udp6hdr *uh6;
|
||||||
|
Iphash *iph;
|
||||||
Conv *c;
|
Conv *c;
|
||||||
Udpcb *ucb;
|
Udpcb *ucb;
|
||||||
uchar raddr[IPaddrlen], laddr[IPaddrlen];
|
uchar raddr[IPaddrlen], laddr[IPaddrlen];
|
||||||
|
@ -334,14 +332,15 @@ udpiput(Proto *udp, Ipifc *ifc, Block *bp)
|
||||||
upriv->ustats.udpInDatagrams++;
|
upriv->ustats.udpInDatagrams++;
|
||||||
|
|
||||||
uh4 = (Udp4hdr*)(bp->rp);
|
uh4 = (Udp4hdr*)(bp->rp);
|
||||||
|
uh6 = (Udp6hdr*)(bp->rp);
|
||||||
version = ((uh4->vihl&0xF0)==IP_VER6) ? V6 : V4;
|
version = ((uh4->vihl&0xF0)==IP_VER6) ? V6 : V4;
|
||||||
|
|
||||||
/* Put back pseudo header for checksum
|
/* Put back pseudo header for checksum
|
||||||
* (remember old values for icmpnoconv()) */
|
* (remember old values for icmpnoconv()) */
|
||||||
switch(version) {
|
switch(version) {
|
||||||
case V4:
|
case V4:
|
||||||
ottl = uh4->Unused;
|
ottl = uh4->ttl;
|
||||||
uh4->Unused = 0;
|
uh4->ttl = 0;
|
||||||
len = nhgets(uh4->udplen);
|
len = nhgets(uh4->udplen);
|
||||||
olen = nhgets(uh4->udpplen);
|
olen = nhgets(uh4->udpplen);
|
||||||
hnputs(uh4->udpplen, len);
|
hnputs(uh4->udpplen, len);
|
||||||
|
@ -360,11 +359,10 @@ udpiput(Proto *udp, Ipifc *ifc, Block *bp)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uh4->Unused = ottl;
|
uh4->ttl = ottl;
|
||||||
hnputs(uh4->udpplen, olen);
|
hnputs(uh4->udpplen, olen);
|
||||||
break;
|
break;
|
||||||
case V6:
|
case V6:
|
||||||
uh6 = (Udp6hdr*)(bp->rp);
|
|
||||||
len = nhgets(uh6->udplen);
|
len = nhgets(uh6->udplen);
|
||||||
oviclfl = nhgetl(uh6->viclfl);
|
oviclfl = nhgetl(uh6->viclfl);
|
||||||
olen = nhgets(uh6->len);
|
olen = nhgets(uh6->len);
|
||||||
|
@ -394,9 +392,8 @@ udpiput(Proto *udp, Ipifc *ifc, Block *bp)
|
||||||
}
|
}
|
||||||
|
|
||||||
qlock(udp);
|
qlock(udp);
|
||||||
|
iph = iphtlook(&upriv->ht, raddr, rport, laddr, lport);
|
||||||
c = iphtlook(&upriv->ht, raddr, rport, laddr, lport);
|
if(iph == nil){
|
||||||
if(c == nil){
|
|
||||||
/* no conversation found */
|
/* no conversation found */
|
||||||
upriv->ustats.udpNoPorts++;
|
upriv->ustats.udpNoPorts++;
|
||||||
qunlock(udp);
|
qunlock(udp);
|
||||||
|
@ -417,6 +414,26 @@ udpiput(Proto *udp, Ipifc *ifc, Block *bp)
|
||||||
freeblist(bp);
|
freeblist(bp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if(iph->trans){
|
||||||
|
Translation *q;
|
||||||
|
int hop = uh4->ttl;
|
||||||
|
if(hop <= 1 || (q = transbackward(udp, iph)) == nil){
|
||||||
|
qunlock(udp);
|
||||||
|
freeblist(bp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
hnputs_csum(uh4->udpdst+0, nhgets(q->forward.raddr+IPv4off+0), uh4->udpcksum);
|
||||||
|
hnputs_csum(uh4->udpdst+2, nhgets(q->forward.raddr+IPv4off+2), uh4->udpcksum);
|
||||||
|
hnputs_csum(uh4->udpdport, q->forward.rport, uh4->udpcksum);
|
||||||
|
|
||||||
|
/* only use route-hint when from original desination */
|
||||||
|
if(memcmp(uh4->udpsrc, q->forward.laddr+IPv4off, IPv4addrlen) != 0)
|
||||||
|
q = nil;
|
||||||
|
qunlock(udp);
|
||||||
|
ipoput4(f, bp, 1, hop - 1, uh4->tos, q);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
c = iphconv(iph);
|
||||||
ucb = (Udpcb*)c->ptcl;
|
ucb = (Udpcb*)c->ptcl;
|
||||||
|
|
||||||
if(c->state == Announced){
|
if(c->state == Announced){
|
||||||
|
@ -487,7 +504,6 @@ udpiput(Proto *udp, Ipifc *ifc, Block *bp)
|
||||||
qpass(c->rq, concatblock(bp));
|
qpass(c->rq, concatblock(bp));
|
||||||
}
|
}
|
||||||
qunlock(c);
|
qunlock(c);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char*
|
char*
|
||||||
|
@ -517,7 +533,8 @@ udpadvise(Proto *udp, Block *bp, char *msg)
|
||||||
Udp6hdr *h6;
|
Udp6hdr *h6;
|
||||||
uchar source[IPaddrlen], dest[IPaddrlen];
|
uchar source[IPaddrlen], dest[IPaddrlen];
|
||||||
ushort psource, pdest;
|
ushort psource, pdest;
|
||||||
Conv *s, **p;
|
Iphash *iph;
|
||||||
|
Conv *s;
|
||||||
|
|
||||||
h4 = (Udp4hdr*)(bp->rp);
|
h4 = (Udp4hdr*)(bp->rp);
|
||||||
h6 = (Udp6hdr*)(bp->rp);
|
h6 = (Udp6hdr*)(bp->rp);
|
||||||
|
@ -534,15 +551,31 @@ udpadvise(Proto *udp, Block *bp, char *msg)
|
||||||
pdest = nhgets(h6->udpdport);
|
pdest = nhgets(h6->udpdport);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Look for a connection */
|
/* Look for a connection (source/dest reversed; this is the original packet we sent) */
|
||||||
qlock(udp);
|
qlock(udp);
|
||||||
for(p = udp->conv; (s = *p) != nil; p++) {
|
iph = iphtlook(&((Udppriv*)udp->priv)->ht, dest, pdest, source, psource);
|
||||||
if(s->rport == pdest)
|
if(iph == nil)
|
||||||
if(s->lport == psource)
|
goto raise;
|
||||||
if(ipcmp(s->raddr, dest) == 0)
|
if(iph->trans){
|
||||||
if(ipcmp(s->laddr, source) == 0){
|
Translation *q;
|
||||||
|
|
||||||
|
if((q = transbackward(udp, iph)) == nil)
|
||||||
|
goto raise;
|
||||||
|
|
||||||
|
/* h4->udpplen is the ip header checksum */
|
||||||
|
hnputs_csum(h4->udpsrc+0, nhgets(q->forward.raddr+IPv4off+0), h4->udpplen);
|
||||||
|
hnputs_csum(h4->udpsrc+2, nhgets(q->forward.raddr+IPv4off+2), h4->udpplen);
|
||||||
|
|
||||||
|
/* dont bother fixing udp checksum, packet is most likely truncated */
|
||||||
|
hnputs(h4->udpsport, q->forward.rport);
|
||||||
|
qunlock(udp);
|
||||||
|
|
||||||
|
icmpproxyadvice(udp->f, bp, h4->udpsrc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s = iphconv(iph);
|
||||||
if(s->ignoreadvice)
|
if(s->ignoreadvice)
|
||||||
break;
|
goto raise;
|
||||||
qlock(s);
|
qlock(s);
|
||||||
qunlock(udp);
|
qunlock(udp);
|
||||||
qhangup(s->rq, msg);
|
qhangup(s->rq, msg);
|
||||||
|
@ -550,12 +583,40 @@ udpadvise(Proto *udp, Block *bp, char *msg)
|
||||||
qunlock(s);
|
qunlock(s);
|
||||||
freeblist(bp);
|
freeblist(bp);
|
||||||
return;
|
return;
|
||||||
}
|
raise:
|
||||||
}
|
|
||||||
qunlock(udp);
|
qunlock(udp);
|
||||||
freeblist(bp);
|
freeblist(bp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Block*
|
||||||
|
udpforward(Proto *udp, Block *bp, Route *r)
|
||||||
|
{
|
||||||
|
uchar da[IPaddrlen], sa[IPaddrlen];
|
||||||
|
ushort dp, sp;
|
||||||
|
Udp4hdr *uh4;
|
||||||
|
Translation *q;
|
||||||
|
|
||||||
|
uh4 = (Udp4hdr*)(bp->rp);
|
||||||
|
v4tov6(sa, uh4->udpsrc);
|
||||||
|
v4tov6(da, uh4->udpdst);
|
||||||
|
dp = nhgets(uh4->udpdport);
|
||||||
|
sp = nhgets(uh4->udpsport);
|
||||||
|
|
||||||
|
qlock(udp);
|
||||||
|
q = transforward(udp, &((Udppriv*)udp->priv)->ht, sa, sp, da, dp, r);
|
||||||
|
if(q == nil){
|
||||||
|
qunlock(udp);
|
||||||
|
freeblist(bp);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
hnputs_csum(uh4->udpsrc+0, nhgets(q->backward.laddr+IPv4off+0), uh4->udpcksum);
|
||||||
|
hnputs_csum(uh4->udpsrc+2, nhgets(q->backward.laddr+IPv4off+2), uh4->udpcksum);
|
||||||
|
hnputs_csum(uh4->udpsport, q->backward.lport, uh4->udpcksum);
|
||||||
|
qunlock(udp);
|
||||||
|
|
||||||
|
return bp;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
udpstats(Proto *udp, char *buf, int len)
|
udpstats(Proto *udp, char *buf, int len)
|
||||||
{
|
{
|
||||||
|
@ -586,6 +647,7 @@ udpinit(Fs *fs)
|
||||||
udp->close = udpclose;
|
udp->close = udpclose;
|
||||||
udp->rcv = udpiput;
|
udp->rcv = udpiput;
|
||||||
udp->advise = udpadvise;
|
udp->advise = udpadvise;
|
||||||
|
udp->forward = udpforward;
|
||||||
udp->stats = udpstats;
|
udp->stats = udpstats;
|
||||||
udp->ipproto = IP_UDPPROTO;
|
udp->ipproto = IP_UDPPROTO;
|
||||||
udp->nc = Nchans;
|
udp->nc = Nchans;
|
||||||
|
|
Loading…
Reference in a new issue