mirror of
https://github.com/espressif/esp-lwip.git
synced 2026-06-05 21:04:45 +00:00
napt: Add basic support for NAT by martin-ger
319d4d3cnapt: Add basic support for NAT by martin-ger Co-Authored-By: David Cermak <cermak@espressif.com> (4b4d6b28,754b8d5d) Co-Authored-By: leo chung <gewalalb@gmail.com> (bb63eed1) Co-Authored-By: yuanjm <yuanjianmin@espressif.com> (74cf7f9f)
This commit is contained in:
@@ -323,4 +323,7 @@ void lwip_example_app_platform_assert(const char *msg, int line, const char *fil
|
||||
#define LWIP_PLATFORM_ASSERT(x) lwip_example_app_platform_assert(x, __LINE__, __FILE__)
|
||||
#endif
|
||||
|
||||
/* ESP options */
|
||||
#define ESP_LWIP LWIP_NETCONN_FULLDUPLEX
|
||||
|
||||
#endif /* LWIP_LWIPOPTS_H */
|
||||
|
||||
@@ -66,6 +66,7 @@ set(lwipcore4_SRCS
|
||||
${LWIP_DIR}/src/core/ipv4/igmp.c
|
||||
${LWIP_DIR}/src/core/ipv4/ip4_frag.c
|
||||
${LWIP_DIR}/src/core/ipv4/ip4.c
|
||||
${LWIP_DIR}/src/core/ipv4/ip4_napt.c
|
||||
${LWIP_DIR}/src/core/ipv4/ip4_addr.c
|
||||
)
|
||||
set(lwipcore6_SRCS
|
||||
|
||||
@@ -59,6 +59,7 @@ CORE4FILES=$(LWIPDIR)/core/ipv4/acd.c \
|
||||
$(LWIPDIR)/core/ipv4/igmp.c \
|
||||
$(LWIPDIR)/core/ipv4/ip4_frag.c \
|
||||
$(LWIPDIR)/core/ipv4/ip4.c \
|
||||
$(LWIPDIR)/core/ipv4/ip4_napt.c \
|
||||
$(LWIPDIR)/core/ipv4/ip4_addr.c
|
||||
|
||||
CORE6FILES=$(LWIPDIR)/core/ipv6/dhcp6.c \
|
||||
|
||||
@@ -244,6 +244,8 @@ PACK_STRUCT_END
|
||||
#error "For LWIP_NETCONN_FULLDUPLEX to work, LWIP_NETCONN_SEM_PER_THREAD is required"
|
||||
#endif
|
||||
|
||||
#if LWIP_SOCKET
|
||||
#endif /* LWIP_SOCKET */
|
||||
|
||||
/* Compile-time checks for deprecated options.
|
||||
*/
|
||||
|
||||
+30
-1
@@ -56,6 +56,7 @@
|
||||
#include "lwip/autoip.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/prot/iana.h"
|
||||
#include "lwip/ip4_napt.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -329,6 +330,13 @@ ip4_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
|
||||
return;
|
||||
}
|
||||
|
||||
#if ESP_LWIP
|
||||
#if IP_NAPT
|
||||
if (ip_napt_forward(p, iphdr, inp, netif) != ERR_OK)
|
||||
return;
|
||||
#endif
|
||||
#endif /* ESP_LWIP */
|
||||
|
||||
/* Incrementally update the IP checksum. */
|
||||
if (IPH_CHKSUM(iphdr) >= PP_HTONS(0xffffU - 0x100)) {
|
||||
IPH_CHKSUM_SET(iphdr, (u16_t)(IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1));
|
||||
@@ -459,7 +467,11 @@ ip4_input_accept(struct netif *netif)
|
||||
err_t
|
||||
ip4_input(struct pbuf *p, struct netif *inp)
|
||||
{
|
||||
#if ESP_LWIP && IP_NAPT
|
||||
struct ip_hdr *iphdr;
|
||||
#else
|
||||
const struct ip_hdr *iphdr;
|
||||
#endif /* IP_NAPT && ESP_LWIP */
|
||||
struct netif *netif;
|
||||
u16_t iphdr_hlen;
|
||||
u16_t iphdr_len;
|
||||
@@ -545,6 +557,14 @@ ip4_input(struct pbuf *p, struct netif *inp)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ESP_LWIP
|
||||
#if IP_NAPT
|
||||
/* for unicast packet, check NAPT table and modify dest if needed */
|
||||
if (!inp->napt && ip4_addr_cmp(&iphdr->dest, netif_ip4_addr(inp)))
|
||||
ip_napt_recv(p, iphdr);
|
||||
#endif
|
||||
#endif /* ESP_LWIP */
|
||||
|
||||
/* copy IP addresses to aligned ip_addr_t */
|
||||
ip_addr_copy_from_ip4(ip_data.current_iphdr_dest, iphdr->dest);
|
||||
ip_addr_copy_from_ip4(ip_data.current_iphdr_src, iphdr->src);
|
||||
@@ -678,7 +698,11 @@ ip4_input(struct pbuf *p, struct netif *inp)
|
||||
if (p == NULL) {
|
||||
return ERR_OK;
|
||||
}
|
||||
#if ESP_LWIP && IP_NAPT
|
||||
iphdr = (struct ip_hdr *)p->payload;
|
||||
#else
|
||||
iphdr = (const struct ip_hdr *)p->payload;
|
||||
#endif
|
||||
#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */
|
||||
pbuf_free(p);
|
||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",
|
||||
@@ -1015,7 +1039,11 @@ ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *d
|
||||
ip4_debug_print(p);
|
||||
|
||||
#if ENABLE_LOOPBACK
|
||||
if (ip4_addr_eq(dest, netif_ip4_addr(netif))
|
||||
#if ESP_LWIP && IP_NAPT
|
||||
/* doesn't work for external wifi interfaces */
|
||||
#else
|
||||
|
||||
if (ip4_addr_cmp(dest, netif_ip4_addr(netif))
|
||||
#if !LWIP_HAVE_LOOPIF
|
||||
|| ip4_addr_isloopback(dest)
|
||||
#endif /* !LWIP_HAVE_LOOPIF */
|
||||
@@ -1029,6 +1057,7 @@ ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *d
|
||||
netif_loop_output(netif, p);
|
||||
}
|
||||
#endif /* LWIP_MULTICAST_TX_OPTIONS */
|
||||
#endif /* ESP_LWIP && IP_NAPT */
|
||||
#endif /* ENABLE_LOOPBACK */
|
||||
#if IP_FRAG
|
||||
/* don't fragment if interface has mtu set to 0 [loopif] */
|
||||
|
||||
@@ -0,0 +1,800 @@
|
||||
/**
|
||||
* @file
|
||||
* This is the NAPT implementation on IPv4 layer
|
||||
*
|
||||
* @see ip4.c
|
||||
*
|
||||
*/
|
||||
#include "lwip/opt.h"
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* original reassembly code by Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
#if ESP_LWIP
|
||||
#if LWIP_IPV4
|
||||
#if IP_NAPT
|
||||
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/inet_chksum.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/icmp.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/priv/tcp_priv.h"
|
||||
#include "lwip/lwip_napt.h"
|
||||
#include "lwip/ip4_napt.h"
|
||||
#include "string.h"
|
||||
#include "assert.h"
|
||||
|
||||
#define NO_IDX ((u16_t)-1)
|
||||
#define NT(x) ((x) == NO_IDX ? NULL : &ip_napt_table[x])
|
||||
|
||||
struct napt_table {
|
||||
u32_t last;
|
||||
u32_t src;
|
||||
u32_t dest;
|
||||
u16_t sport;
|
||||
u16_t dport;
|
||||
u16_t mport;
|
||||
u8_t proto;
|
||||
unsigned int fin1 : 1;
|
||||
unsigned int fin2 : 1;
|
||||
unsigned int finack1 : 1;
|
||||
unsigned int finack2 : 1;
|
||||
unsigned int synack : 1;
|
||||
unsigned int rst : 1;
|
||||
u16_t next, prev;
|
||||
};
|
||||
|
||||
struct portmap_table {
|
||||
u32_t maddr;
|
||||
u32_t daddr;
|
||||
u16_t mport;
|
||||
u16_t dport;
|
||||
u8_t proto;
|
||||
u8_t valid;
|
||||
};
|
||||
|
||||
static u16_t napt_list = NO_IDX, napt_list_last = NO_IDX, napt_free = 0;
|
||||
|
||||
static struct napt_table *ip_napt_table = NULL;
|
||||
static struct portmap_table *ip_portmap_table = NULL;
|
||||
|
||||
static int nr_active_napt_tcp = 0, nr_active_napt_udp = 0, nr_active_napt_icmp = 0;
|
||||
static uint16_t ip_napt_max = 0;
|
||||
static uint8_t ip_portmap_max = 0;
|
||||
|
||||
#if NAPT_DEBUG
|
||||
/* Print NAPT table using LWIP_DEBUGF
|
||||
*/
|
||||
static void
|
||||
napt_debug_print(void)
|
||||
{
|
||||
int i, next;
|
||||
LWIP_DEBUGF(NAPT_DEBUG, ("NAPT table:\n"));
|
||||
LWIP_DEBUGF(NAPT_DEBUG, (" src dest sport dport mport \n"));
|
||||
LWIP_DEBUGF(NAPT_DEBUG, ("+-----------------------+-----------------------+-------+-------+-------+\n"));
|
||||
|
||||
for (i = napt_list; i != NO_IDX; i = next) {
|
||||
struct napt_table *t = &ip_napt_table[i];
|
||||
next = t->next;
|
||||
|
||||
LWIP_DEBUGF(NAPT_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" |",
|
||||
((const u8_t*) (&t->src))[0],
|
||||
((const u8_t*) (&t->src))[1],
|
||||
((const u8_t*) (&t->src))[2],
|
||||
((const u8_t*) (&t->src))[3]));
|
||||
|
||||
LWIP_DEBUGF(NAPT_DEBUG, (" %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" |",
|
||||
((const u8_t*) (&t->dest))[0],
|
||||
((const u8_t*) (&t->dest))[1],
|
||||
((const u8_t*) (&t->dest))[2],
|
||||
((const u8_t*) (&t->dest))[3]));
|
||||
|
||||
LWIP_DEBUGF(NAPT_DEBUG, (" %5"U16_F" | %5"U16_F" | %5"U16_F" |\n",
|
||||
lwip_htons(t->sport),
|
||||
lwip_htons(t->dport),
|
||||
lwip_htons(t->mport)));
|
||||
|
||||
}
|
||||
}
|
||||
#endif /* NAPT_DEBUG */
|
||||
|
||||
/**
|
||||
* Deallocates the NAPT tables.
|
||||
*
|
||||
*/
|
||||
static void
|
||||
ip_napt_deinit(void)
|
||||
{
|
||||
mem_free(ip_napt_table);
|
||||
mem_free(ip_portmap_table);
|
||||
ip_portmap_table = NULL;
|
||||
ip_napt_table = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates and initializes the NAPT tables.
|
||||
*
|
||||
* @param max_nat max number of enties in the NAPT table (use IP_NAPT_MAX if in doubt)
|
||||
* @param max_portmap max number of enties in the NAPT table (use IP_PORTMAP_MAX if in doubt)
|
||||
*/
|
||||
static void
|
||||
ip_napt_init(uint16_t max_nat, uint8_t max_portmap)
|
||||
{
|
||||
u16_t i;
|
||||
|
||||
if (ip_portmap_table == NULL && ip_napt_table == NULL) {
|
||||
ip_napt_max = max_nat;
|
||||
ip_portmap_max = max_portmap;
|
||||
|
||||
ip_napt_table = (struct napt_table*)mem_calloc(ip_napt_max, sizeof(struct napt_table[1]));
|
||||
ip_portmap_table = (struct portmap_table*)mem_calloc(ip_portmap_max, sizeof(struct portmap_table[1]));
|
||||
assert(ip_portmap_table != NULL && ip_napt_table != NULL);
|
||||
|
||||
for (i = 0; i < ip_napt_max - 1; i++)
|
||||
ip_napt_table[i].next = i + 1;
|
||||
ip_napt_table[i].next = NO_IDX;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ip_napt_enable(u32_t addr, int enable)
|
||||
{
|
||||
struct netif *netif;
|
||||
int napt_in_any_netif = 0;
|
||||
for (netif = netif_list; netif; netif = netif->next) {
|
||||
if (netif->napt)
|
||||
napt_in_any_netif = 1;
|
||||
if (netif_is_up(netif) && !ip_addr_isany(&netif->ip_addr) && (ip_2_ip4(&netif->ip_addr)->addr) == addr && enable) {
|
||||
netif->napt = 1;
|
||||
ip_napt_init(IP_NAPT_MAX, IP_PORTMAP_MAX);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!enable && !napt_in_any_netif) {
|
||||
for (netif = netif_list; netif; netif = netif->next)
|
||||
netif->napt = 0;
|
||||
ip_napt_deinit();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ip_napt_enable_no(u8_t number, int enable)
|
||||
{
|
||||
struct netif *netif;
|
||||
for (netif = netif_list; netif; netif = netif->next) {
|
||||
if (netif->num == number) {
|
||||
netif->napt = !!enable;
|
||||
if (enable)
|
||||
ip_napt_init(IP_NAPT_MAX, IP_PORTMAP_MAX);
|
||||
else
|
||||
ip_napt_deinit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* adjusts checksum in a packet
|
||||
- chksum points to the chksum in the packet
|
||||
- optr points to the old data in the packet (before)
|
||||
- nptr points to the new data in the packet (after)
|
||||
*/
|
||||
static void
|
||||
checksumadjust(u8_t *chksum, u8_t *optr, int olen, u8_t *nptr, int nlen)
|
||||
{
|
||||
s32_t x, before, after;
|
||||
x=chksum[0]*256+chksum[1];
|
||||
x=~x & 0xFFFFU;
|
||||
while (olen)
|
||||
{
|
||||
before=optr[0]*256+optr[1]; optr+=2;
|
||||
x-=before & 0xFFFFU;
|
||||
if (x<=0) { x--; x&=0xFFFFU; }
|
||||
olen-=2;
|
||||
}
|
||||
while (nlen)
|
||||
{
|
||||
after=nptr[0]*256+nptr[1]; nptr+=2;
|
||||
x+=after & 0xFFFFU;
|
||||
if (x & 0x10000U) { x++; x&=0xFFFFU; }
|
||||
nlen-=2;
|
||||
}
|
||||
x=~x & 0xFFFFU;
|
||||
chksum[0]=x/256; chksum[1]=x & 0xFFU;
|
||||
}
|
||||
|
||||
/* t must be indexed by napt_free */
|
||||
static void
|
||||
ip_napt_insert(struct napt_table *t)
|
||||
{
|
||||
u16_t ti = t - ip_napt_table;
|
||||
assert(ti == napt_free);
|
||||
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
|
||||
LWIP_DEBUGF(NAPT_DEBUG, ("ip_napt_insert(): TCP=%d, UDP=%d, ICMP=%d\n", nr_active_napt_tcp, nr_active_napt_udp, nr_active_napt_icmp));
|
||||
}
|
||||
|
||||
static void
|
||||
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
|
||||
LWIP_DEBUGF(NAPT_DEBUG, ("ip_napt_free\n"));
|
||||
#if NAPT_DEBUG
|
||||
napt_debug_print();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if LWIP_TCP
|
||||
static u8_t
|
||||
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 *
|
||||
ip_portmap_find(u8_t proto, u16_t mport);
|
||||
|
||||
static u8_t
|
||||
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
|
||||
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
|
||||
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 +
|
||||
LWIP_RAND() % (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*
|
||||
ip_napt_find(u8_t proto, u32_t addr, u16_t port, u16_t mport, u8_t dest)
|
||||
{
|
||||
u16_t i, next;
|
||||
u32_t now;
|
||||
struct napt_table *t;
|
||||
|
||||
LWIP_DEBUGF(NAPT_DEBUG, ("ip_napt_find\n"));
|
||||
LWIP_DEBUGF(NAPT_DEBUG, ("looking up in table %s: %"U16_F".%"U16_F".%"U16_F".%"U16_F", port: %u, mport: %u\n",
|
||||
(dest ? "dest" : "src"),
|
||||
((const u8_t*) (&addr))[0], ((const u8_t*) (&addr))[1],
|
||||
((const u8_t*) (&addr))[2], ((const u8_t*) (&addr))[3],
|
||||
PP_HTONS(port),
|
||||
PP_HTONS(mport)));
|
||||
#if NAPT_DEBUG
|
||||
napt_debug_print();
|
||||
#endif
|
||||
|
||||
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) {
|
||||
t->last = now;
|
||||
LWIP_DEBUGF(NAPT_DEBUG, ("found\n"));
|
||||
return t;
|
||||
}
|
||||
if (dest == 1 && t->proto == proto && t->dest == addr && t->dport == port
|
||||
&& t->mport == mport) {
|
||||
t->last = now;
|
||||
LWIP_DEBUGF(NAPT_DEBUG, ("found\n"));
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(NAPT_DEBUG, ("not found\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static u16_t
|
||||
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->last = sys_now();
|
||||
t->dest = dest;
|
||||
t->dport = dport;
|
||||
/* move this entry to the top of napt_list */
|
||||
ip_napt_free(t);
|
||||
ip_napt_insert(t);
|
||||
|
||||
LWIP_DEBUGF(NAPT_DEBUG, ("ip_napt_add\n"));
|
||||
#if NAPT_DEBUG
|
||||
napt_debug_print();
|
||||
#endif
|
||||
|
||||
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);
|
||||
|
||||
LWIP_DEBUGF(NAPT_DEBUG, ("ip_napt_add\n"));
|
||||
#if NAPT_DEBUG
|
||||
napt_debug_print();
|
||||
#endif
|
||||
|
||||
return mport;
|
||||
}
|
||||
LWIP_DEBUGF(NAPT_DEBUG, ("ip_napt_add() failed to insert\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8_t
|
||||
ip_portmap_add(u8_t proto, u32_t maddr, u16_t mport, u32_t daddr, u16_t dport)
|
||||
{
|
||||
int i;
|
||||
mport = PP_HTONS(mport);
|
||||
dport = PP_HTONS(dport);
|
||||
|
||||
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 *
|
||||
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 *
|
||||
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;
|
||||
}
|
||||
|
||||
u8_t
|
||||
ip_portmap_remove(u8_t proto, u16_t mport)
|
||||
{
|
||||
struct portmap_table *last = &ip_portmap_table[ip_portmap_max - 1];
|
||||
struct portmap_table *m = ip_portmap_find(proto, PP_HTONS(mport));
|
||||
if (!m)
|
||||
return 0;
|
||||
for (; m != last; m++)
|
||||
memcpy(m, m + 1, sizeof(*m));
|
||||
last->valid = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if LWIP_TCP
|
||||
static void
|
||||
ip_napt_modify_port_tcp(struct tcp_hdr *tcphdr, u8_t dest, u16_t newval)
|
||||
{
|
||||
if (dest) {
|
||||
checksumadjust((u8_t *)&tcphdr->chksum, (u8_t *)&tcphdr->dest, 2, (u8_t *)&newval, 2);
|
||||
tcphdr->dest = newval;
|
||||
} else {
|
||||
checksumadjust((u8_t *)&tcphdr->chksum, (u8_t *)&tcphdr->src, 2, (u8_t *)&newval, 2);
|
||||
tcphdr->src = newval;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ip_napt_modify_addr_tcp(struct tcp_hdr *tcphdr, ip4_addr_p_t *oldval, u32_t newval)
|
||||
{
|
||||
checksumadjust((u8_t *)&tcphdr->chksum, (u8_t *)&oldval->addr, 4, (u8_t *)&newval, 4);
|
||||
}
|
||||
#endif /* LWIP_TCP */
|
||||
|
||||
#if LWIP_UDP
|
||||
static void
|
||||
ip_napt_modify_port_udp(struct udp_hdr *udphdr, u8_t dest, u16_t newval)
|
||||
{
|
||||
if (dest) {
|
||||
if (udphdr->chksum != 0)
|
||||
checksumadjust((u8_t *)&udphdr->chksum, (u8_t *)&udphdr->dest, 2, (u8_t *)&newval, 2);
|
||||
udphdr->dest = newval;
|
||||
} else {
|
||||
if (udphdr->chksum != 0)
|
||||
checksumadjust((u8_t *)&udphdr->chksum, (u8_t *)&udphdr->src, 2, (u8_t *)&newval, 2);
|
||||
udphdr->src = newval;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ip_napt_modify_addr_udp(struct udp_hdr *udphdr, ip4_addr_p_t *oldval, u32_t newval)
|
||||
{
|
||||
if (udphdr->chksum != 0)
|
||||
checksumadjust( (u8_t *)&udphdr->chksum, (u8_t *)&oldval->addr, 4, (u8_t *)&newval, 4);
|
||||
}
|
||||
#endif /* LWIP_UDP */
|
||||
|
||||
static void
|
||||
ip_napt_modify_addr(struct ip_hdr *iphdr, ip4_addr_p_t *field, u32_t newval)
|
||||
{
|
||||
checksumadjust((u8_t *)&IPH_CHKSUM(iphdr), (u8_t *)&field->addr, 4, (u8_t *)&newval, 4);
|
||||
field->addr = newval;
|
||||
}
|
||||
|
||||
void
|
||||
ip_napt_recv(struct pbuf *p, struct ip_hdr *iphdr)
|
||||
{
|
||||
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);
|
||||
|
||||
|
||||
LWIP_DEBUGF(NAPT_DEBUG, ("ip_napt_recv\n"));
|
||||
LWIP_DEBUGF(NAPT_DEBUG, ("src: %"U16_F".%"U16_F".%"U16_F".%"U16_F", dest: %"U16_F".%"U16_F".%"U16_F".%"U16_F", \n",
|
||||
ip4_addr1_16(&iphdr->src), ip4_addr2_16(&iphdr->src),
|
||||
ip4_addr3_16(&iphdr->src), ip4_addr4_16(&iphdr->src),
|
||||
ip4_addr1_16(&iphdr->dest), ip4_addr2_16(&iphdr->dest),
|
||||
ip4_addr3_16(&iphdr->dest), ip4_addr4_16(&iphdr->dest)));
|
||||
|
||||
LWIP_DEBUGF(NAPT_DEBUG, ("sport %u, dport: %u\n",
|
||||
lwip_htons(tcphdr->src),
|
||||
lwip_htons(tcphdr->dest)));
|
||||
|
||||
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 */
|
||||
|
||||
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 */
|
||||
|
||||
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 */
|
||||
}
|
||||
|
||||
err_t
|
||||
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, ip_2_ip4(&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);
|
||||
if (mport == 0)
|
||||
return ERR_RTE; /* routing err if add entry failed */
|
||||
} 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 */
|
||||
}
|
||||
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, ip_2_ip4(&outp->ip_addr)->addr);
|
||||
ip_napt_modify_addr(iphdr, &iphdr->src, ip_2_ip4(&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);
|
||||
LWIP_DEBUGF(NAPT_DEBUG, ("Modify UDP addr %x %x", iphdr->src.addr, 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);
|
||||
if (mport == 0)
|
||||
return ERR_RTE; /* routing err if add entry failed */
|
||||
} 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, ip_2_ip4(&outp->ip_addr)->addr);
|
||||
ip_napt_modify_addr(iphdr, &iphdr->src, ip_2_ip4(&outp->ip_addr)->addr);
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
#endif /* IP_NAPT */
|
||||
#endif /* LWIP_IPV4 */
|
||||
#endif /* ESP_LWIP */
|
||||
@@ -380,6 +380,12 @@ netif_add(struct netif *netif,
|
||||
#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
|
||||
#endif /* ENABLE_LOOPBACK */
|
||||
|
||||
#if ESP_LWIP
|
||||
#if IP_NAPT
|
||||
netif->napt = 0;
|
||||
#endif /* IP_NAPT */
|
||||
#endif /* ESP_LWIP */
|
||||
|
||||
#if LWIP_IPV4
|
||||
netif_set_addr(netif, ipaddr, netmask, gw);
|
||||
#endif /* LWIP_IPV4 */
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* @file ip4_napt.h
|
||||
* This is a private interface of ip4_napt used from ip4.c
|
||||
*
|
||||
* @see ip4_napt.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* original reassembly code by Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LWIP_HDR_IP4_NAPT_H
|
||||
#define LWIP_HDR_IP4_NAPT_H
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if ESP_LWIP
|
||||
#if IP_FORWARD
|
||||
#if IP_NAPT
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/ip4_addr.h"
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/prot/ip4.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/ip4.h"
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
err_t
|
||||
ip_napt_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp, struct netif *outp);
|
||||
|
||||
/**
|
||||
* NAPT for an input packet. It checks weather the destination is on NAPT
|
||||
* table and modify the 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
|
||||
*/
|
||||
void
|
||||
ip_napt_recv(struct pbuf *p, struct ip_hdr *iphdr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* IP_NAPT */
|
||||
#endif /* IP_FORWARD */
|
||||
#endif /* ESP_LWIP */
|
||||
|
||||
#endif /* LWIP_HDR_IP4_NAPT_H */
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* @file lwip_napt.h
|
||||
* public API of ip4_napt
|
||||
*
|
||||
* @see ip4_napt.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* original reassembly code by Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __LWIP_NAPT_H__
|
||||
#define __LWIP_NAPT_H__
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if ESP_LWIP
|
||||
#if IP_FORWARD
|
||||
#if IP_NAPT
|
||||
|
||||
/* Default size of the tables used for NAPT */
|
||||
#ifndef IP_NAPT_MAX
|
||||
#define IP_NAPT_MAX 512
|
||||
#endif
|
||||
#ifndef IP_PORTMAP_MAX
|
||||
#define IP_PORTMAP_MAX 32
|
||||
#endif
|
||||
|
||||
/* Timeouts in sec for the various protocol types */
|
||||
#define IP_NAPT_TIMEOUT_MS_TCP (30*60*1000)
|
||||
#define IP_NAPT_TIMEOUT_MS_TCP_DISCON (20*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
|
||||
|
||||
/**
|
||||
* 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
|
||||
ip_napt_enable(u32_t addr, int enable);
|
||||
|
||||
|
||||
/**
|
||||
* Enable/Disable NAPT for a specified interface.
|
||||
*
|
||||
* @param number netif number of the interface
|
||||
* @param enable non-zero to enable NAPT, or 0 to disable.
|
||||
*/
|
||||
void
|
||||
ip_napt_enable_no(u8_t number, int enable);
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
ip_portmap_add(u8_t proto, u32_t maddr, u16_t mport, u32_t daddr, u16_t dport);
|
||||
|
||||
|
||||
/**
|
||||
* Unregister port mapping on the external interface to internal interface.
|
||||
*
|
||||
* @param proto target protocol
|
||||
* @param mport mapped port
|
||||
*/
|
||||
u8_t
|
||||
ip_portmap_remove(u8_t proto, u16_t mport);
|
||||
|
||||
#endif /* IP_NAPT */
|
||||
#endif /* IP_FORWARD */
|
||||
#endif /* ESP_LWIP */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LWIP_NAPT_H__ */
|
||||
@@ -403,6 +403,9 @@ struct netif {
|
||||
u8_t reschedule_poll;
|
||||
#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
|
||||
#endif /* ENABLE_LOOPBACK */
|
||||
#if LWIP_IPV4 && IP_NAPT
|
||||
u8_t napt;
|
||||
#endif /*LWIP_IPV4 && IP_NAPT */
|
||||
};
|
||||
|
||||
#if LWIP_CHECKSUM_CTRL_PER_NETIF
|
||||
|
||||
@@ -771,6 +771,14 @@
|
||||
#define IP_FRAG 0
|
||||
#endif /* !LWIP_IPV4 */
|
||||
|
||||
/**
|
||||
* IP_NAPT==1: Enables IPv4 Network Address and Port Translation
|
||||
* Note that IP_FORWARD needs to be enabled for NAPT to work
|
||||
*/
|
||||
#if !defined IP_NAPT || defined __DOXYGEN__
|
||||
#define IP_NAPT 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* IP_OPTIONS_ALLOWED: Defines the behavior for IP options.
|
||||
* IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped.
|
||||
@@ -3571,6 +3579,13 @@
|
||||
#define LWIP_TESTMODE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* NAPT_DEBUG: Enable debugging for NAPT.
|
||||
*/
|
||||
#ifndef NAPT_DEBUG
|
||||
#define NAPT_DEBUG LWIP_DBG_OFF
|
||||
#endif
|
||||
|
||||
/*
|
||||
--------------------------------------------------
|
||||
---------- Performance tracking options ----------
|
||||
|
||||
@@ -24,7 +24,7 @@ make -j 4 check
|
||||
make clean
|
||||
export EXTRA_CFLAGS="-DESP_LWIP=1 -DIP_FORWARD=1 -DIP_NAPT=1" && export CC="${ORIG_CC} ${EXTRA_CFLAGS}"
|
||||
make -j 4 check
|
||||
# Please uncomment the below to test IP_FORWARD/IP_NAPT tests with debug output (only ip4_route test suite will be executed)
|
||||
# test only ip4_route with debug options enabled
|
||||
make clean
|
||||
export EXTRA_CFLAGS="-DESP_LWIP=1 -DIP_FORWARD=1 -DESP_TEST_DEBUG=1 -DIP_NAPT=1" && export CC="${ORIG_CC} ${EXTRA_CFLAGS}"
|
||||
make -j 4 check
|
||||
|
||||
@@ -23,6 +23,7 @@ set(LWIP_TESTFILES
|
||||
${LWIP_TESTDIR}/core/test_netif.c
|
||||
${LWIP_TESTDIR}/core/test_pbuf.c
|
||||
${LWIP_TESTDIR}/core/test_timers.c
|
||||
${LWIP_TESTDIR}/core/test_ip4_route.c
|
||||
${LWIP_TESTDIR}/dhcp/test_dhcp.c
|
||||
${LWIP_TESTDIR}/etharp/test_etharp.c
|
||||
${LWIP_TESTDIR}/ip4/test_ip4.c
|
||||
|
||||
@@ -37,6 +37,7 @@ TESTFILES=$(TESTDIR)/lwip_unittests.c \
|
||||
$(TESTDIR)/core/test_dns.c \
|
||||
$(TESTDIR)/core/test_mem.c \
|
||||
$(TESTDIR)/core/test_netif.c \
|
||||
$(TESTDIR)/core/test_ip4_route.c \
|
||||
$(TESTDIR)/core/test_pbuf.c \
|
||||
$(TESTDIR)/core/test_timers.c \
|
||||
$(TESTDIR)/dhcp/test_dhcp.c \
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
#ifndef LWIP_ARCH_CC_ESP_H
|
||||
#define LWIP_ARCH_CC_ESP_H
|
||||
|
||||
/* see https://sourceforge.net/p/predef/wiki/OperatingSystems/ */
|
||||
#if defined __ANDROID__
|
||||
#define LWIP_UNIX_ANDROID
|
||||
#elif defined __linux__
|
||||
#define LWIP_UNIX_LINUX
|
||||
#elif defined __APPLE__
|
||||
#define LWIP_UNIX_MACH
|
||||
#elif defined __OpenBSD__
|
||||
#define LWIP_UNIX_OPENBSD
|
||||
#elif defined __CYGWIN__
|
||||
#define LWIP_UNIX_CYGWIN
|
||||
#elif defined __GNU__
|
||||
#define LWIP_UNIX_HURD
|
||||
#endif
|
||||
|
||||
#define LWIP_TIMEVAL_PRIVATE 0
|
||||
#include <sys/time.h>
|
||||
|
||||
#define LWIP_ERRNO_INCLUDE <errno.h>
|
||||
|
||||
#if defined(LWIP_UNIX_LINUX) || defined(LWIP_UNIX_HURD)
|
||||
#define LWIP_ERRNO_STDINCLUDE 1
|
||||
#endif
|
||||
|
||||
#ifdef LWIP_RAND
|
||||
#define LWIP_RAND() ((u32_t)rand())
|
||||
#endif
|
||||
|
||||
/* different handling for unit test, normally not needed */
|
||||
#ifdef LWIP_NOASSERT_ON_ERROR
|
||||
#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \
|
||||
handler;}} while(0)
|
||||
#endif
|
||||
|
||||
#if defined(LWIP_UNIX_ANDROID) && defined(FD_SET)
|
||||
typedef __kernel_fd_set fd_set;
|
||||
#endif
|
||||
|
||||
#if defined(LWIP_UNIX_MACH)
|
||||
/* sys/types.h and signal.h bring in Darwin byte order macros. pull the
|
||||
header here and disable LwIP's version so that apps still can get
|
||||
the macros via LwIP headers and use system headers */
|
||||
#include <sys/types.h>
|
||||
#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS
|
||||
#endif
|
||||
|
||||
struct sio_status_s;
|
||||
typedef struct sio_status_s sio_status_t;
|
||||
#define sio_fd_t sio_status_t*
|
||||
#define __sio_fd_t_defined
|
||||
|
||||
typedef unsigned int sys_prot_t;
|
||||
|
||||
#endif /* LWIP_ARCH_CC_ESP_H */
|
||||
@@ -0,0 +1,561 @@
|
||||
#include "test_ip4_route.h"
|
||||
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/etharp.h"
|
||||
#include "netif/ethernet.h"
|
||||
#include "lwip/ip4.h"
|
||||
#include "lwip/udp.h"
|
||||
#include "lwip/inet_chksum.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/prot/ip.h"
|
||||
#include "lwip/prot/ip4.h"
|
||||
#include "lwip/lwip_napt.h"
|
||||
#include "lwip/priv/tcp_priv.h"
|
||||
|
||||
#include "lwip/tcpip.h"
|
||||
|
||||
#if !LWIP_IPV4 || !IP_REASSEMBLY || !MIB2_STATS || !IPFRAG_STATS
|
||||
#error "This tests needs LWIP_IPV4, IP_REASSEMBLY; MIB2- and IPFRAG-statistics enabled"
|
||||
#endif
|
||||
|
||||
#if !LWIP_NETIF_EXT_STATUS_CALLBACK
|
||||
#error "This tests needs LWIP_NETIF_EXT_STATUS_CALLBACK enabled"
|
||||
#endif
|
||||
|
||||
static struct netif sta;
|
||||
static struct netif ap;
|
||||
|
||||
static int ap_cnt = 0;
|
||||
static int sta_cnt = 0;
|
||||
static u32_t last_src_addr = 0;
|
||||
static u32_t last_dst_addr = 0;
|
||||
static u16_t last_src_port = 0;
|
||||
|
||||
#if IP_NAPT
|
||||
static int random_mock = -1;
|
||||
/* Mock the esp-random to return 0 for easier result checking */
|
||||
uint32_t esp_random(void)
|
||||
{
|
||||
if (random_mock == -1) {
|
||||
/* fall back to default "port/unix" rand (if other tests are launched with IP_NAPT ON) */
|
||||
return rand();
|
||||
}
|
||||
return random_mock;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Setups/teardown functions */
|
||||
static void
|
||||
ip4route_setup(void)
|
||||
{
|
||||
lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
|
||||
}
|
||||
|
||||
static void
|
||||
ip4route_teardown(void)
|
||||
{
|
||||
lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
|
||||
}
|
||||
|
||||
/* test helper functions */
|
||||
static void debug_print_packet(struct pbuf *q)
|
||||
{
|
||||
struct ip_hdr *iphdr = (struct ip_hdr *)q->payload;
|
||||
u16_t iphdr_hlen;
|
||||
|
||||
iphdr_hlen = IPH_HL_BYTES(iphdr);
|
||||
fail_unless(0 == inet_chksum((struct ip_hdr *)q->payload, iphdr_hlen));
|
||||
|
||||
ip4_debug_print(q);
|
||||
|
||||
last_src_addr = iphdr->src.addr;
|
||||
last_dst_addr = iphdr->dest.addr;
|
||||
|
||||
if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
|
||||
struct udp_hdr *udphdr = (struct udp_hdr *)(( u8_t *)iphdr + iphdr_hlen);
|
||||
udp_debug_print(udphdr);
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp ("));
|
||||
ip_addr_debug_print_val(UDP_DEBUG, *ip_current_dest_addr());
|
||||
LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", lwip_ntohs(udphdr->dest)));
|
||||
ip_addr_debug_print_val(UDP_DEBUG, *ip_current_src_addr());
|
||||
LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", lwip_ntohs(udphdr->src)));
|
||||
last_src_port = udphdr->src;
|
||||
|
||||
} else if (IPH_PROTO(iphdr) == IP_PROTO_TCP) {
|
||||
struct tcp_hdr* tcphdr;
|
||||
pbuf_header(q, -(s16_t)sizeof(struct ip_hdr));
|
||||
tcphdr = (struct tcp_hdr*)q->payload;
|
||||
tcp_debug_print(tcphdr);
|
||||
last_src_port = tcphdr->src;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static err_t
|
||||
ap_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr)
|
||||
{
|
||||
ap_cnt++;
|
||||
debug_print_packet(q);
|
||||
LWIP_UNUSED_ARG(netif);
|
||||
LWIP_UNUSED_ARG(q);
|
||||
LWIP_UNUSED_ARG(ipaddr);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static err_t
|
||||
sta_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr)
|
||||
{
|
||||
sta_cnt++;
|
||||
debug_print_packet(q);
|
||||
LWIP_UNUSED_ARG(netif);
|
||||
LWIP_UNUSED_ARG(q);
|
||||
LWIP_UNUSED_ARG(ipaddr);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static err_t
|
||||
sta_tx_func(struct netif *netif, struct pbuf *p)
|
||||
{
|
||||
LWIP_UNUSED_ARG(netif);
|
||||
LWIP_UNUSED_ARG(p);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static err_t
|
||||
ap_tx_func(struct netif *netif, struct pbuf *p)
|
||||
{
|
||||
LWIP_UNUSED_ARG(netif);
|
||||
LWIP_UNUSED_ARG(p);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
#if IP_NAPT
|
||||
static struct pbuf*
|
||||
test_create_tcp_packet(u32_t src_ip4, u32_t dst_ip4,
|
||||
u16_t src_port, u16_t dst_port,
|
||||
u32_t seqno, u32_t ackno, u8_t headerflags, u16_t wnd)
|
||||
{
|
||||
struct pbuf *p, *q;
|
||||
ip_addr_t src_ip;
|
||||
ip_addr_t dst_ip;
|
||||
struct ip_hdr* iphdr;
|
||||
struct tcp_hdr* tcphdr;
|
||||
u16_t pbuf_len = (u16_t)(sizeof(struct ip_hdr) + sizeof(struct tcp_hdr));
|
||||
|
||||
src_ip.u_addr.ip4.addr = src_ip4;
|
||||
dst_ip.u_addr.ip4.addr = dst_ip4;
|
||||
|
||||
p = pbuf_alloc(PBUF_RAW, pbuf_len, PBUF_POOL);
|
||||
EXPECT_RETNULL(p != NULL);
|
||||
/* first pbuf must be big enough to hold the headers */
|
||||
EXPECT_RETNULL(p->len >= (sizeof(struct ip_hdr) + sizeof(struct tcp_hdr)));
|
||||
|
||||
for(q = p; q != NULL; q = q->next) {
|
||||
memset(q->payload, 0, q->len);
|
||||
}
|
||||
|
||||
iphdr = (struct ip_hdr*)p->payload;
|
||||
/* fill IP header */
|
||||
iphdr->dest.addr = ip_2_ip4(&dst_ip)->addr;
|
||||
iphdr->src.addr = ip_2_ip4(&src_ip)->addr;
|
||||
IPH_VHL_SET(iphdr, 4, IP_HLEN / 4);
|
||||
IPH_TOS_SET(iphdr, 0);
|
||||
IPH_LEN_SET(iphdr, htons(p->tot_len));
|
||||
iphdr->_ttl = 32;
|
||||
iphdr->_proto = IP_PROTO_TCP;
|
||||
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
|
||||
|
||||
/* let p point to TCP header */
|
||||
pbuf_header(p, -(s16_t)sizeof(struct ip_hdr));
|
||||
|
||||
tcphdr = (struct tcp_hdr*)p->payload;
|
||||
tcphdr->src = htons(src_port);
|
||||
tcphdr->dest = htons(dst_port);
|
||||
tcphdr->seqno = htonl(seqno);
|
||||
tcphdr->ackno = htonl(ackno);
|
||||
TCPH_HDRLEN_SET(tcphdr, sizeof(struct tcp_hdr)/4);
|
||||
TCPH_FLAGS_SET(tcphdr, headerflags);
|
||||
tcphdr->wnd = htons(wnd);
|
||||
|
||||
/* calculate checksum */
|
||||
tcphdr->chksum = ip_chksum_pseudo(p,
|
||||
IP_PROTO_TCP, p->tot_len, &src_ip, &dst_ip);
|
||||
|
||||
pbuf_header(p, sizeof(struct ip_hdr));
|
||||
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct pbuf *
|
||||
test_udp_create_test_packet(u16_t length, u16_t dst_port, u16_t src_port, u32_t dst_addr, u32_t src_addr)
|
||||
{
|
||||
err_t err;
|
||||
u8_t ret;
|
||||
struct udp_hdr *uh;
|
||||
struct ip_hdr *ih;
|
||||
struct pbuf *p;
|
||||
const u8_t test_data[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
|
||||
|
||||
p = pbuf_alloc(PBUF_TRANSPORT, length, PBUF_POOL);
|
||||
fail_unless(p != NULL);
|
||||
if (p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
fail_unless(p->next == NULL);
|
||||
err = pbuf_take(p, test_data, length);
|
||||
fail_unless(err == ERR_OK);
|
||||
|
||||
/* add UDP header */
|
||||
ret = pbuf_add_header(p, sizeof(struct udp_hdr));
|
||||
fail_unless(!ret);
|
||||
uh = (struct udp_hdr *)p->payload;
|
||||
uh->chksum = 0;
|
||||
uh->dest = lwip_htons(dst_port);
|
||||
uh->src = lwip_htons(src_port);
|
||||
uh->len = lwip_htons(p->tot_len);
|
||||
/* add IPv4 header */
|
||||
ret = pbuf_add_header(p, sizeof(struct ip_hdr));
|
||||
fail_unless(!ret);
|
||||
ih = (struct ip_hdr *)p->payload;
|
||||
memset(ih, 0, sizeof(*ih));
|
||||
ih->dest.addr = dst_addr;
|
||||
ih->src.addr = src_addr;
|
||||
ih->_len = lwip_htons(p->tot_len);
|
||||
ih->_ttl = 32;
|
||||
ih->_proto = IP_PROTO_UDP;
|
||||
IPH_VHL_SET(ih, 4, sizeof(struct ip_hdr) / 4);
|
||||
IPH_CHKSUM_SET(ih, inet_chksum(ih, sizeof(struct ip_hdr)));
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
send_to_netif(struct netif *input_netif, struct pbuf *p)
|
||||
{
|
||||
err_t err;
|
||||
|
||||
if (p != NULL) {
|
||||
err = ip4_input(p, input_netif);
|
||||
fail_unless(err == ERR_OK);
|
||||
}
|
||||
}
|
||||
|
||||
static err_t
|
||||
testif_init_sta(struct netif *netif)
|
||||
{
|
||||
netif->name[0] = 's';
|
||||
netif->name[1] = 't';
|
||||
netif->output = sta_output;
|
||||
netif->linkoutput = sta_tx_func;
|
||||
netif->mtu = 1500;
|
||||
netif->hwaddr_len = 6;
|
||||
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP | NETIF_FLAG_MLD6 | NETIF_FLAG_LINK_UP;
|
||||
|
||||
netif->hwaddr[0] = 0x02;
|
||||
netif->hwaddr[1] = 0x03;
|
||||
netif->hwaddr[2] = 0x04;
|
||||
netif->hwaddr[3] = 0x05;
|
||||
netif->hwaddr[4] = 0x06;
|
||||
netif->hwaddr[5] = 0x08;
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static err_t
|
||||
testif_init_ap(struct netif *netif)
|
||||
{
|
||||
netif->name[0] = 'a';
|
||||
netif->name[1] = 'p';
|
||||
netif->output = ap_output;
|
||||
netif->linkoutput = ap_tx_func;
|
||||
netif->mtu = 1500;
|
||||
netif->hwaddr_len = 6;
|
||||
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP | NETIF_FLAG_MLD6 | NETIF_FLAG_LINK_UP;
|
||||
|
||||
netif->hwaddr[0] = 0x02;
|
||||
netif->hwaddr[1] = 0x03;
|
||||
netif->hwaddr[2] = 0x04;
|
||||
netif->hwaddr[3] = 0x05;
|
||||
netif->hwaddr[4] = 0x06;
|
||||
netif->hwaddr[5] = 0x07;
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
/* Test functions */
|
||||
START_TEST(test_ip4_route_netif_forward)
|
||||
{
|
||||
#define UDP_PORT 1234
|
||||
ip4_addr_t addr, src_addr;
|
||||
ip4_addr_t netmask;
|
||||
ip4_addr_t gw;
|
||||
struct pbuf *p;
|
||||
LWIP_UNUSED_ARG(_i);
|
||||
|
||||
/* setup station */
|
||||
IP4_ADDR(&addr, 1, 2, 4, 4);
|
||||
IP4_ADDR(&netmask, 255, 255, 255, 0);
|
||||
IP4_ADDR(&gw, 1, 2, 4, 10);
|
||||
netif_add(&sta, &addr, &netmask, &gw, &sta, testif_init_sta, ethernet_input);
|
||||
netif_set_up(&sta);
|
||||
|
||||
/* setup access point */
|
||||
IP4_ADDR(&addr, 1, 2, 3, 5);
|
||||
IP4_ADDR(&netmask, 255, 255, 255, 0);
|
||||
IP4_ADDR(&gw, 1, 2, 3, 4);
|
||||
netif_add(&ap, &addr, &netmask, &gw, &ap, testif_init_ap, ethernet_input);
|
||||
netif_set_up(&ap);
|
||||
|
||||
/* create packet and send it to the AP */
|
||||
IP4_ADDR(&addr, 1, 2, 4, 100);
|
||||
IP4_ADDR(&src_addr, 1, 2, 3, 5);
|
||||
p = test_udp_create_test_packet(16, UDP_PORT, UDP_PORT, addr.addr, src_addr.addr);
|
||||
send_to_netif(&ap, p);
|
||||
|
||||
/* cleanup */
|
||||
netif_set_down(&ap);
|
||||
netif_remove(&ap);
|
||||
netif_set_down(&sta);
|
||||
netif_remove(&sta);
|
||||
|
||||
fail_unless(ap_cnt == 0);
|
||||
#if IP_FORWARD
|
||||
fail_unless(sta_cnt == 1);
|
||||
fail_unless(last_src_port == lwip_ntohs(UDP_PORT));
|
||||
fail_unless(last_src_addr == src_addr.addr);
|
||||
#else
|
||||
/* if IP FORWARD disabled, no packet to be found on the other interface */
|
||||
fail_unless(sta_cnt == 0);
|
||||
#endif
|
||||
#undef UDP_PORT
|
||||
}
|
||||
END_TEST
|
||||
|
||||
#if IP_NAPT
|
||||
START_TEST(test_ip4_route_netif_napt_udp)
|
||||
{
|
||||
#define UDP_PORT 1234
|
||||
ip4_addr_t addr, src_addr, sta_addr;
|
||||
ip4_addr_t netmask;
|
||||
ip4_addr_t gw;
|
||||
struct pbuf *p;
|
||||
LWIP_UNUSED_ARG(_i);
|
||||
|
||||
/* setup station */
|
||||
IP4_ADDR(&sta_addr, 1, 2, 4, 4);
|
||||
IP4_ADDR(&netmask, 255, 255, 255, 0);
|
||||
IP4_ADDR(&gw, 1, 2, 4, 10);
|
||||
netif_add(&sta, &sta_addr, &netmask, &gw, &sta, testif_init_sta, ethernet_input);
|
||||
netif_set_up(&sta);
|
||||
|
||||
/* setup access point */
|
||||
IP4_ADDR(&addr, 10, 0, 0, 1);
|
||||
IP4_ADDR(&netmask, 255, 255, 0, 0);
|
||||
IP4_ADDR(&gw, 10, 0, 0, 1);
|
||||
netif_add(&ap, &addr, &netmask, &gw, &ap, testif_init_ap, ethernet_input);
|
||||
netif_set_up(&ap);
|
||||
ip_napt_enable(addr.addr, 1);
|
||||
|
||||
/* create packet and send it to the AP */
|
||||
IP4_ADDR(&addr, 1, 2, 4, 100);
|
||||
IP4_ADDR(&src_addr, 10, 0, 0, 2);
|
||||
p = test_udp_create_test_packet(16, UDP_PORT, UDP_PORT, addr.addr, src_addr.addr);
|
||||
|
||||
random_mock = 1;
|
||||
send_to_netif(&ap, p);
|
||||
|
||||
/* expect to see a random port and translated source address to be station address */
|
||||
fail_unless(last_src_port == lwip_ntohs(IP_NAPT_PORT_RANGE_START+random_mock));
|
||||
fail_unless(last_src_addr == sta_addr.addr);
|
||||
fail_unless(ap_cnt == 0);
|
||||
fail_unless(sta_cnt == 1);
|
||||
|
||||
p = test_udp_create_test_packet(16, IP_NAPT_PORT_RANGE_START+random_mock, UDP_PORT, sta_addr.addr, addr.addr);
|
||||
send_to_netif(&sta, p);
|
||||
fail_unless(ap_cnt == 1);
|
||||
fail_unless(sta_cnt == 1);
|
||||
/* expect to see a random port and translated source address to be station address */
|
||||
fail_unless(last_src_port == lwip_ntohs(UDP_PORT));
|
||||
fail_unless(last_dst_addr == src_addr.addr);
|
||||
|
||||
/* cleanup */
|
||||
netif_set_down(&ap);
|
||||
netif_remove(&ap);
|
||||
netif_set_down(&sta);
|
||||
netif_remove(&sta);
|
||||
|
||||
IP4_ADDR(&addr, 10, 0, 0, 1);
|
||||
ip_napt_enable(addr.addr, 0);
|
||||
|
||||
#undef UDP_PORT
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_ip4_route_netif_napt_tcp)
|
||||
{
|
||||
#define TCP_PORT 2222
|
||||
ip4_addr_t addr, src_addr, sta_addr;
|
||||
ip4_addr_t netmask;
|
||||
ip4_addr_t gw;
|
||||
struct pbuf *p;
|
||||
LWIP_UNUSED_ARG(_i);
|
||||
|
||||
/* setup station */
|
||||
IP4_ADDR(&sta_addr, 1, 2, 4, 4);
|
||||
IP4_ADDR(&netmask, 255, 255, 255, 0);
|
||||
IP4_ADDR(&gw, 1, 2, 4, 10);
|
||||
netif_add(&sta, &sta_addr, &netmask, &gw, &sta, testif_init_sta, ethernet_input);
|
||||
netif_set_up(&sta);
|
||||
|
||||
/* setup access point */
|
||||
IP4_ADDR(&addr, 10, 0, 0, 1);
|
||||
IP4_ADDR(&netmask, 255, 255, 0, 0);
|
||||
IP4_ADDR(&gw, 10, 0, 0, 1);
|
||||
netif_add(&ap, &addr, &netmask, &gw, &ap, testif_init_ap, ethernet_input);
|
||||
netif_set_up(&ap);
|
||||
ip_napt_enable_no(ap.num, 1);
|
||||
|
||||
/* create packet and send it to the AP */
|
||||
IP4_ADDR(&addr, 1, 2, 4, 100);
|
||||
IP4_ADDR(&src_addr, 10, 0, 0, 2);
|
||||
p = test_create_tcp_packet(src_addr.addr, addr.addr, TCP_PORT, TCP_PORT, 0, 0, TCP_SYN, 0);
|
||||
|
||||
random_mock = 2;
|
||||
send_to_netif(&ap, p);
|
||||
|
||||
/* expect to see a random port and translated source address to be station address */
|
||||
fail_unless(last_src_port == lwip_ntohs(IP_NAPT_PORT_RANGE_START+random_mock));
|
||||
fail_unless(last_src_addr == sta_addr.addr);
|
||||
fail_unless(ap_cnt == 0);
|
||||
fail_unless(sta_cnt == 1);
|
||||
|
||||
p = test_create_tcp_packet(addr.addr, sta_addr.addr, TCP_PORT, IP_NAPT_PORT_RANGE_START+random_mock, 0, 0, TCP_SYN|TCP_ACK, 0);
|
||||
send_to_netif(&sta, p);
|
||||
fail_unless(ap_cnt == 1);
|
||||
fail_unless(sta_cnt == 1);
|
||||
/* expect to see a random port and translated source address to be station address */
|
||||
fail_unless(last_src_port == lwip_ntohs(TCP_PORT));
|
||||
fail_unless(last_dst_addr == src_addr.addr);
|
||||
|
||||
/* cleanup */
|
||||
ip_napt_enable_no(ap.num, 0);
|
||||
netif_set_down(&ap);
|
||||
netif_remove(&ap);
|
||||
netif_set_down(&sta);
|
||||
netif_remove(&sta);
|
||||
|
||||
#undef TCP_PORT
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_ip4_route_netif_max_napt)
|
||||
{
|
||||
#define TCP_PORT 2222
|
||||
ip4_addr_t addr, src_addr, sta_addr;
|
||||
ip4_addr_t netmask;
|
||||
ip4_addr_t gw;
|
||||
struct pbuf *p;
|
||||
int i;
|
||||
LWIP_UNUSED_ARG(_i);
|
||||
|
||||
/* setup station */
|
||||
IP4_ADDR(&sta_addr, 1, 2, 4, 4);
|
||||
IP4_ADDR(&netmask, 255, 255, 255, 0);
|
||||
IP4_ADDR(&gw, 1, 2, 4, 10);
|
||||
netif_add(&sta, &sta_addr, &netmask, &gw, &sta, testif_init_sta, ethernet_input);
|
||||
netif_set_up(&sta);
|
||||
|
||||
/* setup access point */
|
||||
IP4_ADDR(&addr, 10, 0, 0, 1);
|
||||
IP4_ADDR(&netmask, 255, 255, 0, 0);
|
||||
IP4_ADDR(&gw, 10, 0, 0, 1);
|
||||
netif_add(&ap, &addr, &netmask, &gw, &ap, testif_init_ap, ethernet_input);
|
||||
netif_set_up(&ap);
|
||||
ip_napt_enable_no(ap.num, 1);
|
||||
|
||||
/* create packet and send it to the AP */
|
||||
IP4_ADDR(&addr, 1, 2, 4, 100);
|
||||
IP4_ADDR(&src_addr, 10, 0, 0, 2);
|
||||
for (i=0; i<IP_NAPT_MAX*2; ++i) {
|
||||
random_mock = i;
|
||||
p = test_create_tcp_packet(src_addr.addr, addr.addr, TCP_PORT + i, TCP_PORT + i, 0, 0, TCP_SYN, 0);
|
||||
send_to_netif(&ap, p);
|
||||
|
||||
if (i<IP_NAPT_MAX) {
|
||||
/* if translated pairs of addr/port still below IP_NAT_MAX -> expect to see an outgoing packet */
|
||||
fail_unless(last_src_port == lwip_ntohs(IP_NAPT_PORT_RANGE_START+random_mock));
|
||||
fail_unless(last_src_addr == sta_addr.addr);
|
||||
fail_unless(sta_cnt == 1+i);
|
||||
p = test_create_tcp_packet(addr.addr, sta_addr.addr, TCP_PORT+i, IP_NAPT_PORT_RANGE_START+random_mock, 0, 0, TCP_SYN | TCP_ACK, 0);
|
||||
send_to_netif(&sta, p);
|
||||
|
||||
} else {
|
||||
/* if more than NAPT_MAX, no more packet to be forwarded */
|
||||
fail_unless(sta_cnt == IP_NAPT_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
/* moves time forward to test releasing: */
|
||||
lwip_sys_now += IP_NAPT_TIMEOUT_MS_TCP_DISCON + 1;
|
||||
p = test_create_tcp_packet(addr.addr, sta_addr.addr, TCP_PORT, IP_NAPT_PORT_RANGE_START+0, 0, 0, TCP_PSH, 0);
|
||||
send_to_netif(&sta, p);
|
||||
p = test_create_tcp_packet(src_addr.addr, addr.addr, TCP_PORT + IP_NAPT_MAX*2, TCP_PORT + IP_NAPT_MAX*2, 0, 0, TCP_PSH | TCP_ACK, 0);
|
||||
sta_cnt = 0;
|
||||
send_to_netif(&ap, p);
|
||||
/* should not be released yet, since all the TCP connections are active */
|
||||
fail_unless(sta_cnt == 0); /* expect no packet forwarded */
|
||||
|
||||
/* FIN the first connection so it could be released */
|
||||
p = test_create_tcp_packet(addr.addr, sta_addr.addr, TCP_PORT+0, IP_NAPT_PORT_RANGE_START+0, 0, 0, TCP_FIN, 0);
|
||||
send_to_netif(&sta, p);
|
||||
p = test_create_tcp_packet(src_addr.addr, addr.addr, TCP_PORT+0, TCP_PORT + 0, 0, 0, TCP_FIN | TCP_ACK, 0);
|
||||
send_to_netif(&ap, p);
|
||||
p = test_create_tcp_packet(addr.addr, sta_addr.addr, TCP_PORT+0, IP_NAPT_PORT_RANGE_START+0, 0, 0, TCP_ACK, 0);
|
||||
send_to_netif(&sta, p);
|
||||
/* moves time forward to test releasing: */
|
||||
lwip_sys_now += IP_NAPT_TIMEOUT_MS_TCP_DISCON + 1;
|
||||
|
||||
/* now sending a new packet with max port, that should be forwarded */
|
||||
p = test_create_tcp_packet(src_addr.addr, addr.addr, TCP_PORT + IP_NAPT_MAX*2, TCP_PORT + IP_NAPT_MAX*2, 0, 0, TCP_SYN, 0);
|
||||
random_mock = 0;
|
||||
sta_cnt = 0;
|
||||
send_to_netif(&ap, p);
|
||||
|
||||
fail_unless(last_src_port == lwip_ntohs(IP_NAPT_PORT_RANGE_START+0));
|
||||
fail_unless(last_src_addr == sta_addr.addr);
|
||||
fail_unless(sta_cnt == 1); /* expect this packet gets forwarded */
|
||||
|
||||
/* cleanup */
|
||||
netif_set_down(&ap);
|
||||
ip_napt_enable_no(ap.num, 0);
|
||||
netif_remove(&ap);
|
||||
netif_set_down(&sta);
|
||||
netif_remove(&sta);
|
||||
|
||||
#undef TCP_PORT
|
||||
}
|
||||
END_TEST
|
||||
#endif
|
||||
|
||||
/** Create the suite including all tests for this module */
|
||||
Suite *
|
||||
ip4route_suite(void)
|
||||
{
|
||||
testfunc tests[] = {
|
||||
TESTFUNC(test_ip4_route_netif_forward),
|
||||
#if IP_NAPT
|
||||
TESTFUNC(test_ip4_route_netif_napt_udp),
|
||||
TESTFUNC(test_ip4_route_netif_napt_tcp),
|
||||
TESTFUNC(test_ip4_route_netif_max_napt),
|
||||
|
||||
#endif
|
||||
};
|
||||
return create_suite("IP4_ROUTE", tests, sizeof(tests)/sizeof(testfunc), ip4route_setup, ip4route_teardown);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef LWIP_HDR_TEST_IP4ROUTE_H
|
||||
#define LWIP_HDR_TEST_IP4ROUTE_H
|
||||
|
||||
#include "../lwip_check.h"
|
||||
|
||||
Suite *ip4route_suite(void);
|
||||
|
||||
#endif
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "core/test_dns.h"
|
||||
#include "core/test_mem.h"
|
||||
#include "core/test_netif.h"
|
||||
#include "core/test_ip4_route.h"
|
||||
#include "core/test_pbuf.h"
|
||||
#include "core/test_timers.h"
|
||||
#include "etharp/test_etharp.h"
|
||||
@@ -75,6 +76,7 @@ int main(void)
|
||||
SRunner *sr;
|
||||
size_t i;
|
||||
suite_getter_fn* suites[] = {
|
||||
#ifndef ESP_TEST_DEBUG
|
||||
ip4_suite,
|
||||
ip6_suite,
|
||||
udp_suite,
|
||||
@@ -91,10 +93,12 @@ int main(void)
|
||||
dhcp_suite,
|
||||
mdns_suite,
|
||||
mqtt_suite,
|
||||
sockets_suite
|
||||
sockets_suite,
|
||||
#if PPP_SUPPORT && PPPOS_SUPPORT
|
||||
, pppos_suite
|
||||
pppos_suite,
|
||||
#endif /* PPP_SUPPORT && PPPOS_SUPPORT */
|
||||
#endif /* ESP_TEST_DEBUG */
|
||||
ip4route_suite
|
||||
};
|
||||
size_t num = sizeof(suites)/sizeof(void*);
|
||||
LWIP_ASSERT("No suites defined", num > 0);
|
||||
|
||||
@@ -94,4 +94,19 @@
|
||||
/* Enable Espressif specific options */
|
||||
#define ESP_LWIP 1
|
||||
|
||||
#ifdef IP_NAPT
|
||||
#define IP_NAPT_MAX 16
|
||||
#include "lwip/arch.h"
|
||||
#undef LWIP_RAND
|
||||
#define LWIP_RAND() (esp_random())
|
||||
u32_t esp_random(void);
|
||||
#endif /* IP_NAPT */
|
||||
/* ESP debug options */
|
||||
#ifdef ESP_TEST_DEBUG
|
||||
#define NAPT_DEBUG LWIP_DBG_ON
|
||||
#define IP_DEBUG LWIP_DBG_ON
|
||||
#define UDP_DEBUG LWIP_DBG_ON
|
||||
#define TCP_DEBUG LWIP_DBG_ON
|
||||
#endif /* ESP_TEST_DEBUG */
|
||||
|
||||
#endif /* LWIP_HDR_LWIPOPTS_H */
|
||||
|
||||
Reference in New Issue
Block a user