Last active
March 8, 2019 15:33
-
-
Save NeoCat/da3c141813980edaa256ad351cab3a2c to your computer and use it in GitHub Desktop.
Patch to add NAPT and port mapping functionality to esp8266
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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