ref: d8b894afc0ff3c81fc750826ac0016250e4f81e4
parent: fa18daa2f56b306b151781523e877bd07d62f799
author: 9ferno <gophone2015@gmail.com>
date: Thu Aug 12 23:08:35 EDT 2021
imported 9legacy NAT patch imported NAT patches from 9legacy http://9legacy.org/patch.html http://9legacy.org/9legacy/patch/nat.diff http://9legacy.org/9legacy/patch/nat-conf.diff Should this patch be changed to use a pktmedium? This is a NAT implementation for Plan 9 from Bell Labs. * Introduction This is a NAPT (Network Address Port Translation) implementation, also known under the name "IP masquerade". This is an early work, don't expect too much from it. Improvements will come in the next future. * Installation First, apply the patches with the "apply" script: /n/sources/contrib/djc/nat/apply Then, add "nat" to you kernel configuration file, under section dev/ip. Finally, compile and install your kernel. * Documentation First, enable routing: echo iprouting > /net/ipifc/clone Then, enable NAT: echo nat add <src> <mask> <dst> > /net/ipifc/<ifc>/ctl Where: - <src> is the address of the source network or machine allowed to pass through the NAT - <mask> is the corresponding mask - <dst> is the address to be translated to, which must exist on the specified interface - <ifc> is your network physical interface number. You can add or remove any NAT rule you want. * Performance The current implementation can handle up to 800 TCP connections per second on a Soekris net5501-70, but the performance quickly decrease as the table grows. * Future We plan to implement the following features in the next future: - improve performance - improve garbage collector - handling of TCP and IL connection states - IPv6 support - port forwarding (you can currently use trampoline(8) instead) - FTP proxy - statistics * History The work began in June 2010 and quickly evolved to the current state. Erik Quanstrom offered his help in March 2011 with code review and suggestions. We thank him much. * Contact David du Colombier <0intro@gmail.com> With the help of Jean-Baptiste Campesato <camjelemon@gmail.com> > But, I could not get the routing to work. Just want to check if you do > not mind sharing the ip configuration that made the patch work. > > Thanks so much for the patch, Personally, on my NAT gateway, I was running: bind -a '#'l1 /net ip/ipconfig ether /net/ether1 <dst> 255.255.255.0 echo iprouting > /net/ipifc/clone Where #l1 (which provides /net/ether1) is the internal LAN interface and <dst> is the public WAN address (on /net/ether0). Then, you have to enable iprouting, so the packets can pass through the NAT.
--- a/os/ip/devip.c
+++ b/os/ip/devip.c
@@ -59,7 +59,7 @@
extern void nullmediumlink(void);
extern void pktmediumlink(void);
static long ndbwrite(Fs*, char*, ulong, int);
-static void closeconv(Conv*);
+extern void closeconv(Conv*);
static int
ip3gen(Chan *c, int i, Dir *dp)
@@ -550,7 +550,7 @@
return n;
}
-static void
+extern void
closeconv(Conv *cv)
{
Conv *nc;
@@ -773,7 +773,7 @@
/*
* pick a local port and set it
*/
-static void
+extern void
setlport(Conv* c)
{
Proto *p;
@@ -811,7 +811,7 @@
break;
}
}
- if(!found)
+ if(found == 0)
break;
}
c->lport = (*pp)++;
--- a/os/ip/icmp.c
+++ b/os/ip/icmp.c
@@ -463,7 +463,13 @@
}
return p - buf;
}
-
+
+int
+icmpgc(Proto *icmp)
+{
+ return natgc(icmp->ipproto);
+}
+
void
icmpinit(Fs *fs)
{
@@ -481,7 +487,7 @@
icmp->stats = icmpstats;
icmp->ctl = nil;
icmp->advise = icmpadvise;
- icmp->gc = nil;
+ icmp->gc = icmpgc;
icmp->ipproto = IP_ICMPPROTO;
icmp->nc = 128;
icmp->ptclsize = 0;
--- a/os/ip/il.c
+++ b/os/ip/il.c
@@ -1380,6 +1380,12 @@
}
}
+int
+ilgc(Proto *il)
+{
+ return natgc(il->ipproto);
+}
+
void
ilinit(Fs *f)
{
@@ -1400,7 +1406,7 @@
il->advise = iladvise;
il->stats = ilxstats;
il->inuse = ilinuse;
- il->gc = nil;
+ il->gc = ilgc;
il->ipproto = IP_ILPROTO;
il->nc = scalednconv();
il->ptclsize = sizeof(Ilcb);
--- a/os/ip/ip.c
+++ b/os/ip/ip.c
@@ -7,7 +7,6 @@
#include "ip.h"
-typedef struct Ip4hdr Ip4hdr;
typedef struct IP IP;
typedef struct Fragment4 Fragment4;
typedef struct Fragment6 Fragment6;
@@ -26,20 +25,6 @@
#define BLKIPVER(xp) (((Ip4hdr*)((xp)->rp))->vihl&0xF0)
-struct Ip4hdr
-{
- uchar vihl; /* Version and header length */
- uchar tos; /* Type of service */
- uchar length[2]; /* packet length */
- uchar id[2]; /* ip->identification */
- uchar frag[2]; /* Fragment information */
- uchar ttl; /* Time to live */
- uchar proto; /* Protocol */
- uchar cksum[2]; /* Header checksum */
- uchar src[4]; /* IP source */
- uchar dst[4]; /* IP destination */
-};
-
/* MIB II counters */
enum
{
@@ -295,6 +280,10 @@
if(ifc->m == nil)
goto raise;
+ /* Output NAT */
+ if(nato(bp, ifc, f) != 0)
+ goto raise;
+
/* If we dont need to fragment just send it */
medialen = ifc->maxtu - ifc->m->hsize;
if(len <= medialen) {
@@ -442,6 +431,9 @@
}
h = (Ip4hdr*)(bp->rp);
+
+ /* Input NAT */
+ nati(bp, ifc);
/* dump anything that whose header doesn't checksum */
if((bp->flag & Bipck) == 0 && ipcsum(&h->vihl)) {
--- a/os/ip/ip.h
+++ b/os/ip/ip.h
@@ -25,6 +25,9 @@
typedef struct V6router V6router;
typedef struct V6params V6params;
+typedef struct Ip4hdr Ip4hdr;
+typedef struct Nat Nat;
+
#pragma incomplete Arp
#pragma incomplete Ifclog
#pragma incomplete Ipself
@@ -38,7 +41,7 @@
Maxproto= 20,
Nhash= 64,
Maxincall= 5,
- Nchans= 256,
+ Nchans= 16383,
MAClen= 16, /* longest mac address */
MAXTTL= 255,
@@ -70,6 +73,22 @@
Connected= 4,
};
+/* on the wire packet header */
+struct Ip4hdr
+{
+ uchar vihl; /* Version and header length */
+ uchar tos; /* Type of service */
+ uchar length[2]; /* packet length */
+ uchar id[2]; /* ip->identification */
+ uchar frag[2]; /* Fragment information */
+ uchar ttl; /* Time to live */
+ uchar proto; /* Protocol */
+ uchar cksum[2]; /* Header checksum */
+ uchar src[4]; /* IP source */
+ uchar dst[4]; /* IP destination */
+ uchar data[1]; /* start of data */
+};
+
/*
* one per conversation directory
*/
@@ -390,6 +409,7 @@
char* Fsstdannounce(Conv*, char**, int);
char* Fsstdbind(Conv*, char**, int);
ulong scalednconv(void);
+void closeconv(Conv*);
/*
* logging
@@ -414,6 +434,7 @@
Logrudpmsg= 1<<16,
Logesp= 1<<17,
Logtcpwin= 1<<18,
+ Lognat= 1<<19,
};
void netloginit(Fs*);
@@ -522,6 +543,7 @@
};
extern IPaux* newipaux(char*, char*);
+extern void setlport(Conv*);
/*
* arp.c
@@ -570,6 +592,9 @@
#define ipmove(x, y) memmove(x, y, IPaddrlen)
#define ipcmp(x, y) ( (x)[IPaddrlen-1] != (y)[IPaddrlen-1] || memcmp(x, y, IPaddrlen) )
+
+#define ip4move(x, y) memmove(x, y, IPv4addrlen)
+#define ip4cmp(x, y) ( (x)[IPv4addrlen-1] != (y)[IPv4addrlen-1] || memcmp(x, y, IPv4addrlen) )
extern uchar IPv4bcast[IPaddrlen];
extern uchar IPv4bcastobs[IPaddrlen];
@@ -670,3 +695,15 @@
* global to all of the stack
*/
extern void (*igmpreportfn)(Ipifc*, uchar*);
+
+/*
+ * nat.c
+ */
+extern int nato(Block*, Ipifc*, Fs*);
+extern void nati(Block*, Ipifc*);
+extern int natgc(uchar);
+
+extern int addnataddr(uchar*, uchar*, Iplifc*);
+extern int removenataddr(uchar*, uchar*, Iplifc*);
+extern void shownataddr(void);
+extern void flushnataddr(void);
--- a/os/ip/ipifc.c
+++ b/os/ip/ipifc.c
@@ -784,6 +784,50 @@
return nil;
}
+char*
+ipifcnat(Ipifc *ifc, char **argv, int argc)
+{
+ uchar src[IPaddrlen], mask[IPaddrlen], dst[IPaddrlen];
+ Iplifc *lifc;
+
+ if(argc == 2){
+ if((strcmp(argv[1], "show") == 0)){
+ shownataddr();
+ return nil;
+ }else if((strcmp(argv[1], "flush") == 0)){
+ flushnataddr();
+ return nil;
+ }else
+ return Ebadarg;
+ }
+
+ if(argc != 5)
+ return Ebadarg;
+
+ if (parseip(src, argv[2]) == -1)
+ return Ebadip;
+
+ if (parseipmask(mask, argv[3]) == -1)
+ return Ebadip;
+
+ if (parseip(dst, argv[4]) == -1)
+ return Ebadip;
+
+ if((lifc=iplocalonifc(ifc, dst)) == nil)
+ return Ebadip;
+
+ if(strcmp(argv[1], "add") == 0){
+ if(addnataddr(src, mask, lifc) != 0)
+ return Ebadarg;
+ }else if(strcmp(argv[1], "remove") == 0){
+ if(removenataddr(src, mask, lifc) != 0)
+ return Ebadarg;
+ }else
+ return Ebadarg;
+
+ return nil;
+}
+
/*
* non-standard control messages.
* called with c locked.
@@ -830,6 +874,8 @@
return ipifcsendra6(ifc, argv, argc);
else if(strcmp(argv[0], "recvra6") == 0)
return ipifcrecvra6(ifc, argv, argc);
+ else if(strcmp(argv[0], "nat") == 0)
+ return ipifcnat(ifc, argv, argc);
return "unsupported ctl";
}
--- a/os/ip/ipmux.c
+++ b/os/ip/ipmux.c
@@ -10,27 +10,11 @@
typedef struct Ipmuxrock Ipmuxrock;
typedef struct Ipmux Ipmux;
-typedef struct Ip4hdr Ip4hdr;
typedef struct Ip6hdr Ip6hdr;
enum
{
IPHDR = 20, /* sizeof(Ip4hdr) */
-};
-
-struct Ip4hdr
-{
- uchar vihl; /* Version and header length */
- uchar tos; /* Type of service */
- uchar length[2]; /* packet length */
- uchar id[2]; /* ip->identification */
- uchar frag[2]; /* Fragment information */
- uchar ttl; /* Time to live */
- uchar proto; /* Protocol */
- uchar cksum[2]; /* Header checksum */
- uchar src[4]; /* IP source */
- uchar dst[4]; /* IP destination */
- uchar data[1]; /* start of data */
};
struct Ip6hdr
--- /dev/null
+++ b/os/ip/nat.c
@@ -1,0 +1,549 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+
+#include "ip.h"
+
+typedef struct NatProto NatProto;
+typedef struct NatAddr NatAddr;
+
+/*
+ * NAT.
+ */
+struct Nat
+{
+ uchar src[IPv4addrlen]; /* Source address */
+ uchar sport[2]; /* Source port */
+ uchar lport[2]; /* Local port */
+ uchar proto; /* Protocol */
+ long time; /* Time */
+ Conv *conv; /* Conversation */
+ Nat *next; /* Next node */
+};
+
+/*
+ * Protocol list.
+ */
+struct NatProto
+{
+ uchar proto; /* Protocol */
+ int sport; /* Source port offset */
+ int dport; /* Destination port offset */
+ int cksum; /* Checksum offset */
+ int timeout; /* Timeout */
+};
+
+/*
+ * Address list.
+ */
+struct NatAddr
+{
+ uchar src[IPaddrlen]; /* Source address */
+ uchar mask[IPaddrlen]; /* Source address mask */
+ uchar net[IPaddrlen]; /* Source network address */
+ Iplifc *dst; /* Destination interface */
+ NatAddr *next; /* Next node */
+};
+
+static Nat *head = nil;
+static NatAddr *addrhead = nil;
+
+/*
+ * Timeouts for ICMP, TCP and UDP are respectively confirmed
+ * in RFC 5508, RFC 5382 and RFC 4787.
+ */
+static NatProto prototab[] =
+{
+ { 1, 4, 4, 2, 60*1000 }, /* ICMP */
+ { 6, 0, 2, 16, (2*60*60+4*60)*1000 }, /* TCP */
+ { 17, 0, 2, 6, 2*60*1000 }, /* UDP */
+ { 40, 6, 8, 0, 10*30*1000 }, /* IL */
+ { 255, 0, 2, 6, 2*60*1000 }, /* RUDP */
+ { 0 }
+};
+
+NatProto* parseproto(uchar);
+void natprepend(Nat*);
+Nat* natexistout(uchar*, uchar, uchar*);
+Nat* natexistin(uchar, uchar*);
+int natdelete(uchar*, uchar, uchar*);
+int natpurge(uchar);
+Nat* natlport(Proto*, Ip4hdr*, uchar*);
+int natgc(uchar);
+void checksumadjust(uchar*, uchar*, int, uchar*, int);
+Iplifc* natonifco(Ipifc*, Ip4hdr*);
+Iplifc* natonifci(Ipifc*);
+void nataddrprepend(NatAddr*);
+NatAddr* nataddrexist(uchar*, uchar*, Iplifc*);
+int addnataddr(uchar*, uchar*, Iplifc*);
+int removenataddr(uchar*, uchar*, Iplifc*);
+void shownataddr(void);
+void flushnataddr(void);
+
+/*
+ * Return protocol attributes if known.
+ */
+NatProto*
+parseproto(uchar proto)
+{
+ NatProto *np;
+
+ for(np = prototab; np->proto; np++)
+ if(proto == np->proto)
+ return np;
+
+ return nil;
+}
+
+/*
+ * Output NAT.
+ * Return -1 if the packet must be NATed but the protocol is unknown.
+ */
+int
+nato(Block *b, Ipifc *ifc, Fs *f)
+{
+ Nat *n; /* NAT table */
+ NatProto *np; /* Protocol list */
+ Iplifc *lifc; /* Logical interface */
+ Ip4hdr *h; /* Source IPv4 header */
+ Proto *p; /* New protocol */
+ uchar *laddr; /* Local address on Iplifc */
+ uchar *sport; /* Source port */
+ uchar *cksum; /* Source checksum */
+
+ h = (Ip4hdr*)(b->rp);
+
+ /* Verify on which logical interface NAT is enabled,
+ and if this source address must be translated */
+ if((lifc=natonifco(ifc, h)) == nil)
+ return 0;
+
+ laddr = lifc->local+IPv4off;
+ p = Fsrcvpcolx(f, h->proto);
+
+ if(ip4cmp(h->src, laddr) != 0){
+ if((np=parseproto(h->proto)) != nil){
+ /* Protocol layer */
+ sport = (b->rp)+sizeof(Ip4hdr)+np->sport;
+ cksum = (b->rp)+sizeof(Ip4hdr)+np->cksum;
+ if((n = natlport(p, h, sport)) == nil)
+ return -1;
+ memmove(sport, n->lport, 2);
+ checksumadjust(cksum, n->sport, 2, n->lport, 2);
+ if(np->proto != 1)
+ /* ICMP checksum doesn't include IP header */
+ checksumadjust(cksum, n->src, IPv4addrlen,
+ laddr, IPv4addrlen);
+ /* IP layer */
+ ip4move(h->src, laddr);
+ checksumadjust(h->cksum, n->src, IPv4addrlen,
+ h->src, IPv4addrlen);
+ return 0;
+ }else{
+ netlog(f, Lognat, "nat: unknown protocol %d\n", h->proto);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Input NAT.
+ */
+void
+nati(Block *b, Ipifc *ifc)
+{
+ Nat *n; /* NAT table */
+ NatProto *np; /* Protocol list */
+ Ip4hdr *h; /* Source IPv4 header */
+ uchar *lport; /* Our local port, and dst port for the packet */
+ uchar *cksum; /* Source checksum */
+
+ h = (Ip4hdr*)(b->rp);
+
+ /* Verify if NAT is enabled on this interface */
+ if(natonifci(ifc) == nil)
+ return;
+
+ if((np=parseproto(h->proto)) != nil){
+ lport = (b->rp)+sizeof(Ip4hdr)+np->dport;
+ if((n=natexistin(h->proto, lport)) != nil){
+ /* Protocol layer */
+ cksum = (b->rp)+sizeof(Ip4hdr)+np->cksum;
+ checksumadjust(cksum, lport, 2, n->sport, 2);
+ memmove(lport, n->sport, 2);
+ if(np->proto != 1)
+ /* ICMP checksum doesn't include IP header */
+ checksumadjust(cksum, h->dst, IPv4addrlen,
+ n->src, IPv4addrlen);
+ /* IP layer */
+ checksumadjust(h->cksum, h->dst, IPv4addrlen,
+ n->src, IPv4addrlen);
+ ip4move(h->dst, n->src);
+ }
+ }
+}
+
+/*
+ * Add Nat to Nat list.
+ */
+void
+natprepend(Nat *n)
+{
+ n->next = head;
+ head = n;
+}
+
+/*
+ * Return Nat if it exists in Nat list.
+ */
+Nat*
+natexistout(uchar *src, uchar proto, uchar *sport)
+{
+ Nat *c; /* Current node */
+
+ for(c=head; c!=nil; c=c->next)
+ if(ip4cmp(src, c->src) == 0 &&
+ memcmp(sport, c->sport, 2) == 0 &&
+ proto == c->proto){
+ c->time = NOW;
+ return c;
+ }
+
+ return nil;
+}
+
+/*
+ * Return Nat if it exists in Nat list.
+ */
+Nat*
+natexistin(uchar proto, uchar *lport)
+{
+ Nat *c; /* Current node */
+
+ for(c=head; c!=nil; c=c->next)
+ if(memcmp(lport, c->lport, 2) == 0 &&
+ proto == c->proto){
+ c->time = NOW;
+ return c;
+ }
+
+ return nil;
+}
+
+/*
+ * Delete Nat in Nat list.
+ * Return -1 if it doesn't exist.
+ */
+int
+natdelete(uchar src[IPv4addrlen], uchar proto, uchar sport[2])
+{
+ Nat *p; /* Precedent node */
+ Nat *c; /* Current node */
+
+ for(p=nil, c=head; c!=nil; p=c, c=c->next)
+ if(ip4cmp(src, c->src) == 0 &&
+ memcmp(sport, c->sport, 2) == 0 &&
+ proto == c->proto)
+ break;
+
+ if(c == nil)
+ return -1;
+
+ if(p == nil)
+ head = head->next;
+ else
+ p->next = c->next;
+
+ closeconv(c->conv);
+ free(c);
+
+ return 0;
+}
+
+/*
+ * Purge Nat list.
+ */
+int
+natpurge(uchar proto)
+{
+ Nat *c; /* Current node */
+ int n; /* Number of purged connections */
+
+ for(n = 0;; n++){
+ do{
+ if((c = head) == nil)
+ return n;
+ head = head->next;
+ }while(c->proto != proto);
+ closeconv(c->conv);
+ free(c);
+ }
+}
+
+/*
+ * Create a new Nat if necessary.
+ */
+Nat*
+natlport(Proto *p, Ip4hdr *h, uchar *sport)
+{
+ Nat *n; /* New NAT node */
+ Conv *s; /* New conversation */
+
+ if((n=natexistout(h->src, h->proto, sport)) == nil){
+ qlock(p);
+ s = Fsprotoclone(p, "network");
+ qunlock(p);
+ if(s == nil){
+ error(Enodev);
+ return nil;
+ }
+ setlport(s);
+ n = malloc(sizeof(Nat));
+ ip4move(n->src, h->src);
+ memmove(n->sport, sport, 2);
+ memmove(n->lport, &s->lport, 2);
+ n->proto = h->proto;
+ n->time = NOW;
+ n->conv = s;
+ natprepend(n);
+ }
+
+ return n;
+}
+
+/*
+ * Nat list garbage collector.
+ */
+int
+natgc(uchar proto){
+ Nat *p; /* Precedent node */
+ Nat *c; /* Current node */
+ NatProto *np; /* Protocol list */
+ int n; /* Number of garbage collected connections */
+
+ n = 0;
+ p = nil;
+ c = head;
+
+ np = parseproto(proto);
+
+ while(c != nil){
+ if(NOW - c->time > np->timeout){
+ if(p == nil){
+ head = head->next;
+ if(proto == c->proto)
+ n++;
+ closeconv(c->conv);
+ free(c);
+ p = nil;
+ c = head;
+ }else{
+ p->next = c->next;
+ if(proto == c->proto)
+ n++;
+ closeconv(c->conv);
+ free(c);
+ c = p->next;
+ }
+ }else{
+ p = c;
+ c = c->next;
+ }
+ }
+
+ if(n == 0) /* Prevent Conv saturation */
+ n = natpurge(proto);
+
+ return n;
+}
+
+/*
+ * Function checksumadjust from RFC 3022.
+ */
+void
+checksumadjust(uchar *chksum, uchar *optr, int olen, uchar *nptr, int nlen)
+{
+ long x, old, new;
+
+ x=chksum[0]*256+chksum[1];
+ x=~x & 0xffff;
+ while(olen){
+ old=optr[0]*256+optr[1];
+ optr+=2;
+ x-=old & 0xffff;
+ if(x<=0){
+ x--;
+ x&=0xffff;
+ }
+ olen-=2;
+ }
+ while(nlen){
+ new=nptr[0]*256+nptr[1];
+ nptr+=2;
+ x+=new & 0xffff;
+ if(x & 0x10000){
+ x++;
+ x&=0xffff;
+ }
+ nlen-=2;
+ }
+ x=~x & 0xffff;
+ chksum[0]=x/256;
+ chksum[1]=x & 0xff;
+}
+
+/*
+ * Add NatAddr to NatAddr list.
+ */
+void
+nataddrprepend(NatAddr *na)
+{
+ na->next = addrhead;
+ addrhead = na;
+}
+
+/*
+ * Return NatAddr if it exists in NatAddr list.
+ */
+NatAddr*
+nataddrexist(uchar *src, uchar *mask, Iplifc *dst)
+{
+ NatAddr *c; /* Current node */
+
+ for(c=addrhead; c!=nil; c=c->next)
+ if(ipcmp(src, c->src) == 0 &&
+ ipcmp(mask, c->mask) == 0 &&
+ dst == c->dst)
+ return c;
+
+ return nil;
+}
+
+/*
+ * Create a new NatAddr.
+ * Return -1 if it already exist.
+ */
+int
+addnataddr(uchar *src, uchar *mask, Iplifc *dst)
+{
+ NatAddr *na; /* New address node */
+ uchar net[IPaddrlen]; /* Network address */
+
+ maskip(src, mask, net);
+
+ if(nataddrexist(src, mask, dst) != nil)
+ return -1;
+
+ na = malloc(sizeof(NatAddr));
+ ipmove(na->src, src);
+ ipmove(na->mask, mask);
+ ipmove(na->net, net);
+ na->dst = dst;
+
+ nataddrprepend(na);
+
+ return 0;
+}
+
+/*
+ * Remove a NatAddr.
+ * Return -1 if it doesn't exist.
+ */
+int
+removenataddr(uchar *src, uchar *mask, Iplifc *dst)
+{
+ NatAddr *c; /* Current node */
+ NatAddr *p; /* Precedent node */
+
+ for(p=nil, c=addrhead; c!=nil; p=c, c=c->next)
+ if(ipcmp(src, c->src) == 0 &&
+ ipcmp(mask, c->mask) == 0 &&
+ dst == c->dst)
+ break;
+
+ if(c == nil)
+ return -1;
+
+ if(p == nil)
+ addrhead = addrhead->next;
+ else
+ p->next = c->next;
+
+ return 0;
+}
+
+/*
+ * Display NatAddr list.
+ */
+void
+shownataddr(void)
+{
+ NatAddr *c; /* Current node */
+
+ for(c=addrhead; c!=nil; c=c->next)
+ print("%I %V %I\n", c->src, c->mask+IPv4off, c->dst->local);
+}
+
+/*
+ * Flush NatAddr list.
+ */
+void
+flushnataddr(void)
+{
+ NatAddr *c; /* Current node */
+
+ while((c=addrhead) != nil){
+ addrhead = addrhead->next;
+ free(c);
+ }
+}
+
+/*
+ * Return logical interface if NAT is enabled on this interface,
+ * and the source address must be translated.
+ */
+Iplifc*
+natonifco(Ipifc *ifc, Ip4hdr* h)
+{
+ NatAddr *na; /* Address list */
+ Iplifc *lifc; /* Logical interface */
+ uchar src[IPaddrlen]; /* Source address */
+ uchar net[IPaddrlen]; /* Source network address */
+
+ for(lifc=ifc->lifc; lifc!=nil; lifc=lifc->next)
+ for(na=addrhead; na; na=na->next)
+ if(lifc == na->dst){
+ /* NAT enabled on this logical interface */
+ v4tov6(src, h->src);
+ maskip(src, na->mask, net);
+ if(ipcmp(net, na->net) == 0)
+ /* Source address must be translated */
+ return lifc;
+ }
+
+ return nil;
+}
+
+/*
+ * Return logical interface if NAT is enabled on this interface.
+ */
+Iplifc*
+natonifci(Ipifc *ifc)
+{
+ NatAddr *na; /* Address list */
+ Iplifc *lifc; /* Logical interface */
+
+ for(lifc=ifc->lifc; lifc!=nil; lifc=lifc->next)
+ for(na=addrhead; na; na=na->next)
+ if(lifc == na->dst){
+ /* NAT enabled on this logical interface */
+ return lifc;
+ }
+
+ return nil;
+}
--- a/os/ip/rudp.c
+++ b/os/ip/rudp.c
@@ -701,6 +701,12 @@
upriv->orders);
}
+int
+rudpgc(Proto *rudp)
+{
+ return natgc(rudp->ipproto);
+}
+
void
rudpinit(Fs *fs)
{
@@ -719,6 +725,7 @@
rudp->rcv = rudpiput;
rudp->advise = rudpadvise;
rudp->stats = rudpstats;
+ rudp->gc = rudpgc;
rudp->ipproto = IP_UDPPROTO;
rudp->nc = 16;
rudp->ptclsize = sizeof(Rudpcb);
--- a/os/ip/tcp.c
+++ b/os/ip/tcp.c
@@ -3104,7 +3104,7 @@
Tcpctl *tcb;
- n = 0;
+ n = natgc(tcp->ipproto);
ep = &tcp->conv[tcp->nc];
for(pp = tcp->conv; pp < ep; pp++) {
c = *pp;
--- a/os/ip/udp.c
+++ b/os/ip/udp.c
@@ -624,6 +624,12 @@
upriv->ustats.udpOutDatagrams);
}
+int
+udpgc(Proto *udp)
+{
+ return natgc(udp->ipproto);
+}
+
void
udpinit(Fs *fs)
{
@@ -641,6 +647,7 @@
udp->rcv = udpiput;
udp->advise = udpadvise;
udp->stats = udpstats;
+ udp->gc = udpgc;
udp->ipproto = IP_UDPPROTO;
udp->nc = Nchans;
udp->ptclsize = sizeof(Udpcb);
--- a/os/pc64/pc64
+++ b/os/pc64/pc64
@@ -15,7 +15,7 @@
ether netif netaux ethermedium
# bridge netif log
- ip bootp ip ipv6 ipaux iproute arp netlog ptclbsum iprouter plan9 nullmedium pktmedium
+ ip bootp ip ipv6 ipaux iproute arp netlog ptclbsum iprouter plan9 nullmedium pktmedium nat
draw screen vga vgax cga
# mouse mouse