summaryrefslogtreecommitdiff
path: root/sys/src/9/ip/devip.c
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2022-03-12 20:53:17 +0000
committercinap_lenrek <cinap_lenrek@felloff.net>2022-03-12 20:53:17 +0000
commitd2a7d886624c56673a6d7ba7d6a7958d2be5b867 (patch)
tree483c16a36a4fcb97f66708a0d11f1e43f6fcbddf /sys/src/9/ip/devip.c
parentc14ea9fdd1521ff9322f9af71b801e016622c0cd (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.c70
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";