Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save NeoCat/da3c141813980edaa256ad351cab3a2c to your computer and use it in GitHub Desktop.
Save NeoCat/da3c141813980edaa256ad351cab3a2c to your computer and use it in GitHub Desktop.
Patch to add NAPT and port mapping functionality to esp8266
From 1dfbeab6f4ca7287e27c31a9f90ddec3343a18d5 Mon Sep 17 00:00:00 2001
From: NeoCat <neocat@neocat.jp>
Date: Thu, 13 Oct 2016 22:19:22 +0900
Subject: [PATCH] Adds NAPT and port mapping functionality to esp8266 lwip
esp8266 can handle 2 network interfaces (Wifi client and softAP)
simultaneously in the WIFI_AP_STA mode.
Currently IP_FORWARD is implemented in lwip to forward packets
between 2 interfaces, but static routing must be setup manually.
This patch adds IP_NAPT config option to enable esp8266 to use
NAPT technique on forwarding packets from softAP clients to the
parent WiFi AP.
To enable NAPT on the interface, ip_napt_enable() must be called
with esp8266's softAP interface address. For example:
extern "C" void ip_napt_enable(unsigned long addr, int enable);
ip_napt_enable(IPAddress(192,168,4,1), 1);
This patch also provides port mappings to forward packets from
the parent WiFi network to softAP network. To register and
unregister port mappings, following functions can be used:
void ip_portmap_add(byte proto, unsigned long maddr, unsigned short mport,
unsigned long daddr, unsigned short dport);
bool ip_portmap_remove(byte proto, unsigned short mport);
For exmaple:
#define IP_PROTO_TCP 6
#define IP_PROTO_UDP 17
...
ip_portmap_add(IP_PROTO_TCP, WiFi.localIP(), 8080,
IPAddress(192,168,4,3), 80);
ip_portmap_add(IP_PROTO_UDP, WiFi.localIP(), 12345,
IPAddress(192,168,4,2), 12345);
These map TCP port 8080 on WiFi client address to 192.168.4.3:80, and
UDP port 12345 to 192.168.4.2:12345. To remove the first mapping:
ip_portmap_remove(IP_PROTO_TCP, 8080);
To apply this change, SDK needs to be recompiled with this patch:
$ cd tools/sdk/lwip/src
$ make && make release #=> intalled to ../../lib/liblwip_gcc.a
Note that this patch is experimental and is provided as is.
---
.../2.3.0/tools/sdk/lwip/include/lwip/netif.h | 3 +
.../2.3.0/tools/sdk/lwip/include/lwip/opt.h | 6 +-
.../2.3.0/tools/sdk/lwip/include/lwipopts.h | 6 +-
.../esp8266/2.3.0/tools/sdk/lwip/src/core/init.c | 4 +
.../2.3.0/tools/sdk/lwip/src/core/ipv4/ip.c | 651 +++++++++++++++++++++
.../esp8266/2.3.0/tools/sdk/lwip/src/core/netif.c | 3 +
6 files changed, 671 insertions(+), 2 deletions(-)
diff --git a/hardware/esp8266/2.3.0/tools/sdk/lwip/include/lwip/netif.h b/hardware/esp8266/2.3.0/tools/sdk/lwip/include/lwip/netif.h
index 04e4f7a..c6b85e5 100644
--- a/hardware/esp8266/2.3.0/tools/sdk/lwip/include/lwip/netif.h
+++ b/hardware/esp8266/2.3.0/tools/sdk/lwip/include/lwip/netif.h
@@ -228,6 +228,9 @@ struct netif {
u16_t loop_cnt_current;
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
#endif /* ENABLE_LOOPBACK */
+#if IP_NAPT
+ u8_t napt;
+#endif
};
#if LWIP_SNMP
diff --git a/hardware/esp8266/2.3.0/tools/sdk/lwip/include/lwip/opt.h b/hardware/esp8266/2.3.0/tools/sdk/lwip/include/lwip/opt.h
index 0d2b3fc..12e70ae 100644
--- a/hardware/esp8266/2.3.0/tools/sdk/lwip/include/lwip/opt.h
+++ b/hardware/esp8266/2.3.0/tools/sdk/lwip/include/lwip/opt.h
@@ -501,7 +501,11 @@
* interface, define this to 0.
*/
#ifndef IP_FORWARD
-#define IP_FORWARD 0
+#define IP_FORWARD 1
+#endif
+
+#ifndef IP_NAPT
+#define IP_NAPT 1
#endif
/**
diff --git a/hardware/esp8266/2.3.0/tools/sdk/lwip/include/lwipopts.h b/hardware/esp8266/2.3.0/tools/sdk/lwip/include/lwipopts.h
index 2081b3a..ab56d98 100644
--- a/hardware/esp8266/2.3.0/tools/sdk/lwip/include/lwipopts.h
+++ b/hardware/esp8266/2.3.0/tools/sdk/lwip/include/lwipopts.h
@@ -505,7 +505,11 @@
* interface, define this to 0.
*/
#ifndef IP_FORWARD
-#define IP_FORWARD 0
+#define IP_FORWARD 1
+#endif
+
+#ifndef IP_NAPT
+#define IP_NAPT 1
#endif
/**
diff --git a/hardware/esp8266/2.3.0/tools/sdk/lwip/src/core/init.c b/hardware/esp8266/2.3.0/tools/sdk/lwip/src/core/init.c
index aa403f4..dea0425 100644
--- a/hardware/esp8266/2.3.0/tools/sdk/lwip/src/core/init.c
+++ b/hardware/esp8266/2.3.0/tools/sdk/lwip/src/core/init.c
@@ -322,4 +322,8 @@ lwip_init(void)
#if LWIP_TIMERS
sys_timeouts_init();
#endif /* LWIP_TIMERS */
+
+#if IP_NAPT
+ ip_napt_init();
+#endif /* IP_NAPT */
}
diff --git a/hardware/esp8266/2.3.0/tools/sdk/lwip/src/core/ipv4/ip.c b/hardware/esp8266/2.3.0/tools/sdk/lwip/src/core/ipv4/ip.c
index 89d3f11..bad0d61 100644
--- a/hardware/esp8266/2.3.0/tools/sdk/lwip/src/core/ipv4/ip.c
+++ b/hardware/esp8266/2.3.0/tools/sdk/lwip/src/core/ipv4/ip.c
@@ -199,7 +199,647 @@ ip_router(ip_addr_t *dest, ip_addr_t *source){
return netif_default;
}
+
#if IP_FORWARD
+#if IP_NAPT
+#define IP_NAPT_MAX 512
+#define IP_PORTMAP_MAX 32
+#define IP_NAPT_TIMEOUT_MS_TCP (10*60*1000)
+#define IP_NAPT_TIMEOUT_MS_TCP_DISCON (3*1000)
+#define IP_NAPT_TIMEOUT_MS_UDP (2*1000)
+#define IP_NAPT_TIMEOUT_MS_ICMP (2*1000)
+#define IP_NAPT_PORT_RANGE_START 49152
+#define IP_NAPT_PORT_RANGE_END 61439
+
+int nr_active_napt_tcp = 0, nr_active_napt_udp = 0, nr_active_napt_icmp = 0;
+
+/**
+ * Enable/Disable NAPT for a specified interface.
+ *
+ * @param addr ip address of the interface
+ * @param enable non-zero to enable NAPT, or 0 to disable.
+ */
+void ICACHE_FLASH_ATTR
+ip_napt_enable(u32_t addr, int enable)
+{
+ struct netif *netif;
+ for (netif = netif_list; netif; netif = netif->next) {
+ if (netif_is_up(netif) && !ip_addr_isany(&netif->ip_addr) && netif->ip_addr.addr == addr) {
+ netif->napt = !!enable;
+ break;
+ }
+ }
+}
+
+
+static struct napt_table {
+ u32_t last;
+ u32_t src;
+ u32_t dest;
+ u16_t sport;
+ u16_t dport;
+ u16_t mport;
+ u8_t proto;
+ u8_t fin1 : 1;
+ u8_t fin2 : 1;
+ u8_t finack1 : 1;
+ u8_t finack2 : 1;
+ u8_t synack : 1;
+ u8_t rst : 1;
+#if IP_NAPT_MAX<255
+ u8_t next, prev;
+#else
+ u16_t next, prev;
+#endif
+} ip_napt_table[IP_NAPT_MAX] = {};
+#if IP_NAPT_MAX<255
+#define NO_IDX ((u8_t)-1)
+#else
+#define NO_IDX ((u16_t)-1)
+#endif
+#define NT(x) ((x) == NO_IDX ? NULL : &ip_napt_table[x])
+u16_t napt_list = NO_IDX, napt_list_last = NO_IDX, napt_free = 0;
+
+static struct portmap_table {
+ u32_t maddr;
+ u32_t daddr;
+ u16_t mport;
+ u16_t dport;
+ u8_t proto;
+ u8 valid;
+} ip_portmap_table[IP_PORTMAP_MAX] = {};
+
+void ICACHE_FLASH_ATTR
+ip_napt_init()
+{
+ u16_t i;
+ for (i = 0; i < IP_NAPT_MAX - 1; i++)
+ ip_napt_table[i].next = i + 1;
+ ip_napt_table[i].next = NO_IDX;
+}
+
+/* t must be indexed by napt_free */
+static void ICACHE_FLASH_ATTR
+ip_napt_insert(struct napt_table *t)
+{
+ u16_t ti = t - ip_napt_table;
+ if (ti != napt_free) *((int*)1)=1; //DEBUG
+ napt_free = t->next;
+ t->prev = NO_IDX;
+ t->next = napt_list;
+ if (napt_list != NO_IDX)
+ NT(napt_list)->prev = ti;
+ napt_list = ti;
+ if (napt_list_last == NO_IDX)
+ napt_list_last = ti;
+
+#if LWIP_TCP
+ if (t->proto == IP_PROTO_TCP)
+ nr_active_napt_tcp++;
+#endif
+#if LWIP_UDP
+ if (t->proto == IP_PROTO_UDP)
+ nr_active_napt_udp++;
+#endif
+#if LWIP_ICMP
+ if (t->proto == IP_PROTO_ICMP)
+ nr_active_napt_icmp++;
+#endif
+}
+
+static void ICACHE_FLASH_ATTR
+ip_napt_free(struct napt_table *t)
+{
+ u16_t ti = t - ip_napt_table;
+ if (ti == napt_list)
+ napt_list = t->next;
+ if (ti == napt_list_last)
+ napt_list_last = t->prev;
+ if (t->next != NO_IDX)
+ NT(t->next)->prev = t->prev;
+ if (t->prev != NO_IDX)
+ NT(t->prev)->next = t->next;
+ t->prev = NO_IDX;
+ t->next = napt_free;
+ napt_free = ti;
+
+#if LWIP_TCP
+ if (t->proto == IP_PROTO_TCP)
+ nr_active_napt_tcp--;
+#endif
+#if LWIP_UDP
+ if (t->proto == IP_PROTO_UDP)
+ nr_active_napt_udp--;
+#endif
+#if LWIP_ICMP
+ if (t->proto == IP_PROTO_ICMP)
+ nr_active_napt_icmp--;
+#endif
+}
+
+#if LWIP_TCP
+static u8_t ICACHE_FLASH_ATTR
+ip_napt_find_port(u8_t proto, u16_t port)
+{
+ int i, next;
+ for (i = napt_list; i != NO_IDX; i = next) {
+ struct napt_table *t = &ip_napt_table[i];
+ next = t->next;
+ if (t->proto == proto && t->mport == port)
+ return 1;
+ }
+ return 0;
+}
+
+static struct portmap_table * ICACHE_FLASH_ATTR
+ip_portmap_find(u8_t proto, u16_t mport);
+
+static u8_t ICACHE_FLASH_ATTR
+tcp_listening(u16_t port)
+{
+ struct tcp_pcb_listen *t;
+ for (t = tcp_listen_pcbs.listen_pcbs; t; t = t->next)
+ if (t->local_port == port)
+ return 1;
+ if (ip_portmap_find(IP_PROTO_TCP, port))
+ return 1;
+ return 0;
+}
+#endif // LWIP_TCP
+
+#if LWIP_UDP
+static u8_t ICACHE_FLASH_ATTR
+udp_listening(u16_t port)
+{
+ struct udp_pcb *pcb;
+ for (pcb = udp_pcbs; pcb; pcb = pcb->next)
+ if (pcb->local_port == port)
+ return 1;
+ if (ip_portmap_find(IP_PROTO_UDP, port))
+ return 1;
+ return 0;
+}
+#endif // LWIP_UDP
+
+static u16_t ICACHE_FLASH_ATTR
+ip_napt_new_port(u8_t proto, u16_t port)
+{
+ if (PP_NTOHS(port) >= IP_NAPT_PORT_RANGE_START && PP_NTOHS(port) <= IP_NAPT_PORT_RANGE_END)
+ if (!ip_napt_find_port(proto, port) && !tcp_listening(port))
+ return port;
+ for (;;) {
+ port = PP_HTONS(IP_NAPT_PORT_RANGE_START +
+ os_random() % (IP_NAPT_PORT_RANGE_END - IP_NAPT_PORT_RANGE_START + 1));
+ if (ip_napt_find_port(proto, port))
+ continue;
+#if LWIP_TCP
+ if (proto == IP_PROTO_TCP && tcp_listening(port))
+ continue;
+#endif // LWIP_TCP
+#if LWIP_UDP
+ if (proto == IP_PROTO_UDP && udp_listening(port))
+ continue;
+#endif // LWIP_UDP
+
+ return port;
+ }
+}
+
+static struct napt_table* ICACHE_FLASH_ATTR
+ip_napt_find(u8_t proto, u32_t addr, u16_t port, u16_t mport, u8_t dest)
+{
+ u16_t i, next;
+ struct napt_table *t;
+ u32_t now = sys_now();
+ for (i = napt_list; i != NO_IDX; i = next) {
+ t = NT(i);
+ next = t->next;
+#if LWIP_TCP
+ if (t->proto == IP_PROTO_TCP &&
+ (((t->finack1 && t->finack2 || !t->synack) &&
+ now - t->last > IP_NAPT_TIMEOUT_MS_TCP_DISCON) ||
+ now - t->last > IP_NAPT_TIMEOUT_MS_TCP)) {
+ ip_napt_free(t);
+ continue;
+ }
+#endif
+#if LWIP_UDP
+ if (t->proto == IP_PROTO_UDP && now - t->last > IP_NAPT_TIMEOUT_MS_UDP) {
+ ip_napt_free(t);
+ continue;
+ }
+#endif
+#if LWIP_ICMP
+ if (t->proto == IP_PROTO_ICMP && now - t->last > IP_NAPT_TIMEOUT_MS_ICMP) {
+ ip_napt_free(t);
+ continue;
+ }
+#endif
+ if (dest == 0 && t->proto == proto && t->src == addr && t->sport == port)
+ return t;
+ if (dest == 1 && t->proto == proto && t->dest == addr && t->dport == port
+ && t->mport == mport)
+ return t;
+ }
+ return NULL;
+}
+
+static void ICACHE_FLASH_ATTR
+ip_napt_update(struct napt_table *t)
+{
+ t->last = sys_now();
+ /* move this entry to the top of napt_list */
+ ip_napt_free(t);
+ ip_napt_insert(t);
+}
+
+static u16_t ICACHE_FLASH_ATTR
+ip_napt_add(u8_t proto, u32_t src, u16_t sport, u32_t dest, u16_t dport)
+{
+ struct napt_table *t = ip_napt_find(proto, src, sport, 0, 0);
+ if (t) {
+ t->dest = dest;
+ t->dport = dport;
+ ip_napt_update(t);
+ return t->mport;
+ }
+ t = NT(napt_free);
+ if (t) {
+ u16_t mport = sport;
+#if LWIP_TCP
+ if (proto == IP_PROTO_TCP)
+ mport = ip_napt_new_port(IP_PROTO_TCP, sport);
+#endif
+#if LWIP_TCP
+ if (proto == IP_PROTO_UDP)
+ mport = ip_napt_new_port(IP_PROTO_UDP, sport);
+#endif
+ t->last = sys_now();
+ t->src = src;
+ t->dest = dest;
+ t->sport = sport;
+ t->dport = dport;
+ t->mport = mport;
+ t->proto = proto;
+ t->fin1 = t->fin2 = t->finack1 = t->finack2 = t->synack = t->rst = 0;
+ ip_napt_insert(t);
+ return mport;
+ }
+ return 0;
+}
+
+/**
+ * Register port mapping on the external interface to internal interface.
+ * When the same port mapping is registered again, the old mapping is overwritten.
+ * In this implementation, only 1 unique port mapping can be defined for each target address/port.
+ *
+ * @param proto target protocol
+ * @param maddr ip address of the external interface
+ * @param mport mapped port on the external interface, in host byte order.
+ * @param daddr destination ip address
+ * @param dport destination port, in host byte order.
+ */
+u8_t ICACHE_FLASH_ATTR
+ip_portmap_add(u8_t proto, u32_t maddr, u16_t mport, u32_t daddr, u16_t dport)
+{
+ mport = PP_HTONS(mport);
+ dport = PP_HTONS(dport);
+ int i;
+ for (i = 0; i < IP_PORTMAP_MAX; i++) {
+ struct portmap_table *p = &ip_portmap_table[i];
+ if (p->valid && p->proto == proto && p->mport == mport) {
+ p->dport = dport;
+ p->daddr = daddr;
+ } else if (!p->valid) {
+ p->maddr = maddr;
+ p->daddr = daddr;
+ p->mport = mport;
+ p->dport = dport;
+ p->proto = proto;
+ p->valid = 1;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static struct portmap_table * ICACHE_FLASH_ATTR
+ip_portmap_find(u8_t proto, u16_t mport)
+{
+ int i;
+ for (i = 0; i < IP_PORTMAP_MAX; i++) {
+ struct portmap_table *p = &ip_portmap_table[i];
+ if (!p->valid)
+ return 0;
+ if (p->proto == proto && p->mport == mport)
+ return p;
+ }
+ return NULL;
+}
+
+static struct portmap_table * ICACHE_FLASH_ATTR
+ip_portmap_find_dest(u8_t proto, u16_t dport, u32_t daddr)
+{
+ int i;
+ for (i = 0; i < IP_PORTMAP_MAX; i++) {
+ struct portmap_table *p = &ip_portmap_table[i];
+ if (!p->valid)
+ return 0;
+ if (p->proto == proto && p->dport == dport && p->daddr == daddr)
+ return p;
+ }
+ return NULL;
+}
+
+/**
+ * Unregister port mapping on the external interface to internal interface.
+ *
+ * @param proto target protocol
+ * @param maddr ip address of the external interface
+ */
+u8_t ICACHE_FLASH_ATTR
+ip_portmap_remove(u8_t proto, u16_t mport)
+{
+ mport = PP_HTONS(mport);
+ struct portmap_table *last = &ip_portmap_table[IP_PORTMAP_MAX - 1];
+ struct portmap_table *m = ip_portmap_find(proto, mport);
+ if (!m)
+ return 0;
+ for (; m != last; m++)
+ memcpy(m, m + 1, sizeof(*m));
+ last->valid = 0;
+ return 1;
+}
+
+#if LWIP_TCP
+void ICACHE_FLASH_ATTR
+ip_napt_modify_port_tcp(struct tcp_hdr *tcphdr, u8_t dest, u16_t newval)
+{
+ u16_t s1 = PP_NTOHS(dest ? tcphdr->dest : tcphdr->src), s2 = PP_NTOHS(newval);
+ u32_t chksum = PP_NTOHS(tcphdr->chksum), chksum2 = chksum;
+ chksum += s1 - s2;
+ chksum = (chksum >> 16) + (chksum & 0xffff);
+ tcphdr->chksum = PP_HTONS(chksum);
+ if (dest)
+ tcphdr->dest = newval;
+ else
+ tcphdr->src = newval;
+}
+
+void ICACHE_FLASH_ATTR
+ip_napt_modify_addr_tcp(struct tcp_hdr *tcphdr, ip_addr_p_t *oldval, u32_t newval)
+{
+ u32_t s1 = PP_NTOHL(oldval->addr), s2 = PP_NTOHL(newval);
+ u32_t chksum = PP_NTOHS(tcphdr->chksum);
+ chksum += (s1 >> 16) + (s1 & 0xfff) - (s2 >> 16) - (s2 & 0xffff);
+ chksum = (chksum >> 16) + (chksum & 0xffff);
+ tcphdr->chksum = PP_HTONS(chksum);
+}
+#endif // LWIP_TCP
+
+#if LWIP_UDP
+void ICACHE_FLASH_ATTR
+ip_napt_modify_port_udp(struct udp_hdr *udphdr, u8_t dest, u16_t newval)
+{
+ u16_t s1 = PP_NTOHS(dest ? udphdr->dest : udphdr->src), s2 = PP_NTOHS(newval);
+ u32_t chksum = PP_NTOHS(udphdr->chksum), chksum2 = chksum;
+ chksum += s1 - s2;
+ chksum = (chksum >> 16) + (chksum & 0xffff);
+ udphdr->chksum = PP_HTONS(chksum);
+ if (dest)
+ udphdr->dest = newval;
+ else
+ udphdr->src = newval;
+}
+
+void ICACHE_FLASH_ATTR
+ip_napt_modify_addr_udp(struct udp_hdr *udphdr, ip_addr_p_t *oldval, u32_t newval)
+{
+ u32_t s1 = PP_NTOHL(oldval->addr), s2 = PP_NTOHL(newval);
+ u32_t chksum = PP_NTOHS(udphdr->chksum);
+ chksum += (s1 >> 16) + (s1 & 0xfff) - (s2 >> 16) - (s2 & 0xffff);
+ chksum = (chksum >> 16) + (chksum & 0xffff);
+ udphdr->chksum = PP_HTONS(chksum);
+}
+#endif // LWIP_UDP
+
+void ICACHE_FLASH_ATTR
+ip_napt_modify_addr(struct ip_hdr *iphdr, ip_addr_p_t *field, u32_t newval)
+{
+ u32_t s1 = PP_NTOHL(field->addr), s2 = PP_NTOHL(newval);
+ u32_t chksum = PP_NTOHS(IPH_CHKSUM(iphdr));
+ chksum += (s1 >> 16) + (s1 & 0xfff) - (s2 >> 16) - (s2 & 0xffff);
+ chksum = (chksum >> 16) + (chksum & 0xffff);
+ IPH_CHKSUM_SET(iphdr, PP_HTONS(chksum));
+ field->addr = newval;
+}
+
+/**
+ * NAPT for an input packet. It checks weather the destination is on NAPT
+ * table and modifythe packet destination address and port if needed.
+ *
+ * @param p the packet to forward (p->payload points to IP header)
+ * @param iphdr the IP header of the input packet
+ * @param inp the netif on which this packet was received
+ */
+static void ICACHE_FLASH_ATTR
+ip_napt_recv(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
+{
+ struct portmap_table *m;
+ struct napt_table *t;
+
+#if LWIP_ICMP
+ /* NAPT for ICMP Echo Request using identifier */
+ if (IPH_PROTO(iphdr) == IP_PROTO_ICMP) {
+ struct icmp_echo_hdr *iecho = (struct icmp_echo_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4);
+ if (iecho->type == ICMP_ER) {
+ t = ip_napt_find(IP_PROTO_ICMP, iphdr->src.addr, iecho->id, iecho->id, 1);
+ if (!t)
+ return;
+ ip_napt_modify_addr(iphdr, &iphdr->dest, t->src);
+ return;
+ }
+
+ return;
+ }
+#endif // LWIP_ICMP
+
+#if LWIP_TCP
+ if (IPH_PROTO(iphdr) == IP_PROTO_TCP) {
+ struct tcp_hdr *tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4);
+ m = ip_portmap_find(IP_PROTO_TCP, tcphdr->dest);
+ if (m) {
+ /* packet to mapped port: rewrite destination */
+ if (m->dport != tcphdr->dest)
+ ip_napt_modify_port_tcp(tcphdr, 1, m->dport);
+ ip_napt_modify_addr_tcp(tcphdr, &iphdr->dest, m->daddr);
+ ip_napt_modify_addr(iphdr, &iphdr->dest, m->daddr);
+ return;
+ }
+ t = ip_napt_find(IP_PROTO_TCP, iphdr->src.addr, tcphdr->src, tcphdr->dest, 1);
+ if (!t)
+ return; /* Unknown TCP session; do nothing */
+ ip_napt_update(t);
+
+ if (t->sport != tcphdr->dest)
+ ip_napt_modify_port_tcp(tcphdr, 1, t->sport);
+ ip_napt_modify_addr_tcp(tcphdr, &iphdr->dest, t->src);
+ ip_napt_modify_addr(iphdr, &iphdr->dest, t->src);
+
+ if ((TCPH_FLAGS(tcphdr) & (TCP_SYN|TCP_ACK)) == (TCP_SYN|TCP_ACK))
+ t->synack = 1;
+ if ((TCPH_FLAGS(tcphdr) & TCP_FIN))
+ t->fin1 = 1;
+ if (t->fin2 && (TCPH_FLAGS(tcphdr) & TCP_ACK))
+ t->finack2 = 1; /* FIXME: Currently ignoring ACK seq... */
+ if (TCPH_FLAGS(tcphdr) & TCP_RST)
+ t->rst = 1;
+ return;
+ }
+#endif // LWIP_TCP
+
+#if LWIP_UDP
+ if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
+ struct udp_hdr *udphdr = (struct udp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4);
+ m = ip_portmap_find(IP_PROTO_UDP, udphdr->dest);
+ if (m) {
+ /* packet to mapped port: rewrite destination */
+ if (m->dport != udphdr->dest)
+ ip_napt_modify_port_udp(udphdr, 1, m->dport);
+ ip_napt_modify_addr_udp(udphdr, &iphdr->dest, m->daddr);
+ ip_napt_modify_addr(iphdr, &iphdr->dest, m->daddr);
+ return;
+ }
+ t = ip_napt_find(IP_PROTO_UDP, iphdr->src.addr, udphdr->src, udphdr->dest, 1);
+ if (!t)
+ return; /* Unknown session; do nothing */
+ ip_napt_update(t);
+
+ if (t->sport != udphdr->dest)
+ ip_napt_modify_port_udp(udphdr, 1, t->sport);
+ ip_napt_modify_addr_udp(udphdr, &iphdr->dest, t->src);
+ ip_napt_modify_addr(iphdr, &iphdr->dest, t->src);
+ return;
+ }
+#endif // LWIP_UDP
+}
+
+/**
+ * NAPT for a forwarded packet. It checks weather we need NAPT and modify
+ * the packet source address and port if needed.
+ *
+ * @param p the packet to forward (p->payload points to IP header)
+ * @param iphdr the IP header of the input packet
+ * @param inp the netif on which this packet was received
+ * @param outp the netif on which this packet will be sent
+ * @return ERR_OK if packet should be sent, or ERR_RTE if it should be dropped
+ */
+static err_t ICACHE_FLASH_ATTR
+ip_napt_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp, struct netif *outp)
+{
+ if (!inp->napt)
+ return ERR_OK;
+
+#if LWIP_ICMP
+ /* NAPT for ICMP Echo Request using identifier */
+ if (IPH_PROTO(iphdr) == IP_PROTO_ICMP) {
+ struct icmp_echo_hdr *iecho = (struct icmp_echo_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4);
+ if (iecho->type == ICMP_ECHO) {
+ /* register src addr and iecho->id and dest info */
+ ip_napt_add(IP_PROTO_ICMP, iphdr->src.addr, iecho->id, iphdr->dest.addr, iecho->id);
+
+ ip_napt_modify_addr(iphdr, &iphdr->src, outp->ip_addr.addr);
+ }
+ return ERR_OK;
+ }
+#endif
+
+#if LWIP_TCP
+ if (IPH_PROTO(iphdr) == IP_PROTO_TCP) {
+ struct tcp_hdr *tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4);
+ u16_t mport;
+
+ struct portmap_table *m = ip_portmap_find_dest(IP_PROTO_TCP, tcphdr->src, iphdr->src.addr);
+ if (m) {
+ /* packet from port-mapped dest addr/port: rewrite source to this node */
+ if (m->mport != tcphdr->src)
+ ip_napt_modify_port_tcp(tcphdr, 0, m->mport);
+ ip_napt_modify_addr_tcp(tcphdr, &iphdr->src, m->maddr);
+ ip_napt_modify_addr(iphdr, &iphdr->src, m->maddr);
+ return ERR_OK;
+ }
+ if ((TCPH_FLAGS(tcphdr) & (TCP_SYN|TCP_ACK)) == TCP_SYN &&
+ PP_NTOHS(tcphdr->src) >= 1024) {
+ /* Register new TCP session to NAPT */
+ mport = ip_napt_add(IP_PROTO_TCP, iphdr->src.addr, tcphdr->src,
+ iphdr->dest.addr, tcphdr->dest);
+ } else {
+ struct napt_table *t = ip_napt_find(IP_PROTO_TCP, iphdr->src.addr, tcphdr->src, 0, 0);
+ if (!t || t->dest != iphdr->dest.addr || t->dport != tcphdr->dest) {
+#if LWIP_ICMP
+ icmp_dest_unreach(p, ICMP_DUR_PORT);
+#endif
+ return ERR_RTE; /* Drop unknown TCP session */
+ }
+ ip_napt_update(t);
+ mport = t->mport;
+ if ((TCPH_FLAGS(tcphdr) & TCP_FIN))
+ t->fin2 = 1;
+ if (t->fin1 && (TCPH_FLAGS(tcphdr) & TCP_ACK))
+ t->finack1 = 1; /* FIXME: Currently ignoring ACK seq... */
+ if (TCPH_FLAGS(tcphdr) & TCP_RST)
+ t->rst = 1;
+ }
+
+ if (mport != tcphdr->src)
+ ip_napt_modify_port_tcp(tcphdr, 0, mport);
+ ip_napt_modify_addr_tcp(tcphdr, &iphdr->src, outp->ip_addr.addr);
+ ip_napt_modify_addr(iphdr, &iphdr->src, outp->ip_addr.addr);
+ return ERR_OK;
+ }
+#endif
+
+#if LWIP_UDP
+ if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
+ struct udp_hdr *udphdr = (struct udp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4);
+ u16_t mport;
+
+ struct portmap_table *m = ip_portmap_find_dest(IP_PROTO_UDP, udphdr->src, iphdr->src.addr);
+ if (m) {
+ /* packet from port-mapped dest addr/port: rewrite source to this node */
+ if (m->mport != udphdr->src)
+ ip_napt_modify_port_udp(udphdr, 0, m->mport);
+ ip_napt_modify_addr_udp(udphdr, &iphdr->src, m->maddr);
+ ip_napt_modify_addr(iphdr, &iphdr->src, m->maddr);
+ return ERR_OK;
+ }
+ if (PP_NTOHS(udphdr->src) >= 1024) {
+ /* Register new UDP session */
+ mport = ip_napt_add(IP_PROTO_UDP, iphdr->src.addr, udphdr->src,
+ iphdr->dest.addr, udphdr->dest);
+ } else {
+ struct napt_table *t = ip_napt_find(IP_PROTO_UDP, iphdr->src.addr, udphdr->src, 0, 0);
+ if (!t || t->dest != iphdr->dest.addr || t->dport != udphdr->dest) {
+#if LWIP_ICMP
+ icmp_dest_unreach(p, ICMP_DUR_PORT);
+#endif
+ return ERR_RTE; /* Drop unknown UDP session */
+ }
+ mport = t->mport;
+ }
+
+ if (mport != udphdr->src)
+ ip_napt_modify_port_udp(udphdr, 0, mport);
+ ip_napt_modify_addr_udp(udphdr, &iphdr->src, outp->ip_addr.addr);
+ ip_napt_modify_addr(iphdr, &iphdr->src, outp->ip_addr.addr);
+ return ERR_OK;
+ }
+#endif
+
+ return ERR_OK;
+}
+#endif // IP_NAPT
+
/**
* Forwards an IP packet. It finds an appropriate route for the
* packet, decrements the TTL value of the packet, adjusts the
@@ -253,6 +893,11 @@ ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
return;
}
+#if IP_NAPT
+ if (ip_napt_forward(p, iphdr, inp, netif) != ERR_OK)
+ return;
+#endif
+
/* Incrementally update the IP checksum. */
if (IPH_CHKSUM(iphdr) >= PP_HTONS(0xffff - 0x100)) {
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1);
@@ -359,6 +1004,12 @@ ip_input(struct pbuf *p, struct netif *inp)
}
#endif
+#if IP_NAPT
+ /* for unicast packet, check NAPT table and modify dest if needed */
+ if (!inp->napt && ip_addr_cmp(&iphdr->dest, &(inp->ip_addr)))
+ ip_napt_recv(p, iphdr, netif);
+#endif
+
/* Trim pbuf. This should have been done at the netif layer,
* but we'll do it anyway just to be sure that its done. */
pbuf_realloc(p, iphdr_len);
diff --git a/hardware/esp8266/2.3.0/tools/sdk/lwip/src/core/netif.c b/hardware/esp8266/2.3.0/tools/sdk/lwip/src/core/netif.c
index 6913b40..32f7a1a 100644
--- a/hardware/esp8266/2.3.0/tools/sdk/lwip/src/core/netif.c
+++ b/hardware/esp8266/2.3.0/tools/sdk/lwip/src/core/netif.c
@@ -179,6 +179,9 @@ netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
#if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS
netif->loop_cnt_current = 0;
#endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */
+#if IP_NAPT
+ netif->napt = 0;
+#endif /* IP_NAPT */
netif_set_addr(netif, ipaddr, netmask, gw);
--
2.8.4 (Apple Git-73)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment