diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2022-03-12 20:53:17 +0000 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2022-03-12 20:53:17 +0000 |
commit | d2a7d886624c56673a6d7ba7d6a7958d2be5b867 (patch) | |
tree | 483c16a36a4fcb97f66708a0d11f1e43f6fcbddf /sys/src/9/ip/devip.c | |
parent | c14ea9fdd1521ff9322f9af71b801e016622c0cd (diff) |
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.
Diffstat (limited to 'sys/src/9/ip/devip.c')
-rw-r--r-- | sys/src/9/ip/devip.c | 70 |
1 files changed, 50 insertions, 20 deletions
diff --git a/sys/src/9/ip/devip.c b/sys/src/9/ip/devip.c index 403faa083..cb6be1d1c 100644 --- a/sys/src/9/ip/devip.c +++ b/sys/src/9/ip/devip.c @@ -737,6 +737,7 @@ setladdr(Conv* c) char* setluniqueport(Conv* c, int lport) { + Translation *q; Proto *p; Conv *xp; int x; @@ -754,14 +755,22 @@ setluniqueport(Conv* c, int lport) && xp->lport == lport && xp->rport == c->rport && ipcmp(xp->raddr, c->raddr) == 0 - && ipcmp(xp->laddr, c->laddr) == 0){ - qunlock(p); - return "address in use"; - } + && ipcmp(xp->laddr, c->laddr) == 0) + goto Inuse; + } + 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; qunlock(p); return nil; +Inuse: + qunlock(p); + return "address in use"; } /* @@ -770,18 +779,51 @@ setluniqueport(Conv* c, int lport) static int lportinuse(Proto *p, ushort lport) { + Translation *q; int x; for(x = 0; x < p->nc && p->conv[x]; x++) if(p->conv[x]->lport == lport) return 1; + for(q = p->translations; q != nil; q = q->next) + if(q->backward.lport == lport) + return 1; 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 */ -char * +static char * setlport(Conv* c) { Proto *p; @@ -799,21 +841,9 @@ setlport(Conv* c) goto chosen; } }else{ - /* - * 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)) - goto chosen; - } + port = unusedlport(p); + if(port > 0) + goto chosen; } qunlock(p); return "no ports available"; |