diff --git a/src/core/init.c b/src/core/init.c index b3737a35..f35344d5 100644 --- a/src/core/init.c +++ b/src/core/init.c @@ -57,6 +57,7 @@ #include "lwip/nd6.h" #include "lwip/mld6.h" #include "lwip/api.h" +#include "lwip/lwip_napt.h" #include "netif/ppp/ppp_opts.h" #include "netif/ppp/ppp_impl.h" @@ -67,7 +68,8 @@ # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN -struct packed_struct_test { +struct packed_struct_test +{ PACK_STRUCT_FLD_8(u8_t dummy1); PACK_STRUCT_FIELD(u32_t dummy2); } PACK_STRUCT_STRUCT; @@ -83,183 +85,187 @@ PACK_STRUCT_END * These can be done independently of LWIP_DEBUG, without penalty. */ #ifndef BYTE_ORDER -#error "BYTE_ORDER is not defined, you have to define it in your cc.h" + #error "BYTE_ORDER is not defined, you have to define it in your cc.h" #endif #if (!IP_SOF_BROADCAST && IP_SOF_BROADCAST_RECV) -#error "If you want to use broadcast filter per pcb on recv operations, you have to define IP_SOF_BROADCAST=1 in your lwipopts.h" + #error "If you want to use broadcast filter per pcb on recv operations, you have to define IP_SOF_BROADCAST=1 in your lwipopts.h" #endif #if (!LWIP_UDP && LWIP_UDPLITE) -#error "If you want to use UDP Lite, you have to define LWIP_UDP=1 in your lwipopts.h" + #error "If you want to use UDP Lite, you have to define LWIP_UDP=1 in your lwipopts.h" #endif #if (!LWIP_UDP && LWIP_DHCP) -#error "If you want to use DHCP, you have to define LWIP_UDP=1 in your lwipopts.h" + #error "If you want to use DHCP, you have to define LWIP_UDP=1 in your lwipopts.h" #endif -#if (!LWIP_UDP && !LWIP_RAW && LWIP_MULTICAST_TX_OPTIONS) -#error "If you want to use LWIP_MULTICAST_TX_OPTIONS, you have to define LWIP_UDP=1 and/or LWIP_RAW=1 in your lwipopts.h" +#if (!LWIP_UDP && LWIP_MULTICAST_TX_OPTIONS) + #error "If you want to use IGMP/LWIP_MULTICAST_TX_OPTIONS, you have to define LWIP_UDP=1 in your lwipopts.h" #endif #if (!LWIP_UDP && LWIP_DNS) -#error "If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h" + #error "If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h" #endif #if !MEMP_MEM_MALLOC /* MEMP_NUM_* checks are disabled when not using the pool allocator */ #if (LWIP_ARP && ARP_QUEUEING && (MEMP_NUM_ARP_QUEUE<=0)) -#error "If you want to use ARP Queueing, you have to define MEMP_NUM_ARP_QUEUE>=1 in your lwipopts.h" + #error "If you want to use ARP Queueing, you have to define MEMP_NUM_ARP_QUEUE>=1 in your lwipopts.h" #endif #if (LWIP_RAW && (MEMP_NUM_RAW_PCB<=0)) -#error "If you want to use RAW, you have to define MEMP_NUM_RAW_PCB>=1 in your lwipopts.h" + #error "If you want to use RAW, you have to define MEMP_NUM_RAW_PCB>=1 in your lwipopts.h" #endif #if (LWIP_UDP && (MEMP_NUM_UDP_PCB<=0)) -#error "If you want to use UDP, you have to define MEMP_NUM_UDP_PCB>=1 in your lwipopts.h" + #error "If you want to use UDP, you have to define MEMP_NUM_UDP_PCB>=1 in your lwipopts.h" #endif #if (LWIP_TCP && (MEMP_NUM_TCP_PCB<=0)) -#error "If you want to use TCP, you have to define MEMP_NUM_TCP_PCB>=1 in your lwipopts.h" + #error "If you want to use TCP, you have to define MEMP_NUM_TCP_PCB>=1 in your lwipopts.h" #endif #if (LWIP_IGMP && (MEMP_NUM_IGMP_GROUP<=1)) -#error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h" + #error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h" #endif #if (LWIP_IGMP && !LWIP_MULTICAST_TX_OPTIONS) -#error "If you want to use IGMP, you have to define LWIP_MULTICAST_TX_OPTIONS==1 in your lwipopts.h" + #error "If you want to use IGMP, you have to define LWIP_MULTICAST_TX_OPTIONS==1 in your lwipopts.h" #endif #if (LWIP_IGMP && !LWIP_IPV4) -#error "IGMP needs LWIP_IPV4 enabled in your lwipopts.h" + #error "IGMP needs LWIP_IPV4 enabled in your lwipopts.h" +#endif +#if (LWIP_MULTICAST_TX_OPTIONS && !LWIP_IPV4) + #error "LWIP_MULTICAST_TX_OPTIONS needs LWIP_IPV4 enabled in your lwipopts.h" #endif #if ((LWIP_NETCONN || LWIP_SOCKET) && (MEMP_NUM_TCPIP_MSG_API<=0)) -#error "If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h" + #error "If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h" #endif /* There must be sufficient timeouts, taking into account requirements of the subsystems. */ -#if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < LWIP_NUM_SYS_TIMEOUT_INTERNAL) -#error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts" +#if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT + (LWIP_IPV6 ? (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD) : 0))) + #error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts" #endif #if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS)) -#error "MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS doesn't make sense since each struct ip_reassdata must hold 2 pbufs at least!" + #error "MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS doesn't make sense since each struct ip_reassdata must hold 2 pbufs at least!" #endif #endif /* !MEMP_MEM_MALLOC */ #if LWIP_WND_SCALE #if (LWIP_TCP && (TCP_WND > 0xffffffff)) -#error "If you want to use TCP, TCP_WND must fit in an u32_t, so, you have to reduce it in your lwipopts.h" + #error "If you want to use TCP, TCP_WND must fit in an u32_t, so, you have to reduce it in your lwipopts.h" #endif #if (LWIP_TCP && (TCP_RCV_SCALE > 14)) -#error "The maximum valid window scale value is 14!" + #error "The maximum valid window scale value is 14!" #endif #if (LWIP_TCP && (TCP_WND > (0xFFFFU << TCP_RCV_SCALE))) -#error "TCP_WND is bigger than the configured LWIP_WND_SCALE allows!" + #error "TCP_WND is bigger than the configured LWIP_WND_SCALE allows!" #endif #if (LWIP_TCP && ((TCP_WND >> TCP_RCV_SCALE) == 0)) -#error "TCP_WND is too small for the configured LWIP_WND_SCALE (results in zero window)!" + #error "TCP_WND is too small for the configured LWIP_WND_SCALE (results in zero window)!" #endif #else /* LWIP_WND_SCALE */ #if (LWIP_TCP && (TCP_WND > 0xffff)) -#error "If you want to use TCP, TCP_WND must fit in an u16_t, so, you have to reduce it in your lwipopts.h (or enable window scaling)" + #error "If you want to use TCP, TCP_WND must fit in an u16_t, so, you have to reduce it in your lwipopts.h (or enable window scaling)" #endif #endif /* LWIP_WND_SCALE */ #if (LWIP_TCP && (TCP_SND_QUEUELEN > 0xffff)) -#error "If you want to use TCP, TCP_SND_QUEUELEN must fit in an u16_t, so, you have to reduce it in your lwipopts.h" + #error "If you want to use TCP, TCP_SND_QUEUELEN must fit in an u16_t, so, you have to reduce it in your lwipopts.h" #endif #if (LWIP_TCP && (TCP_SND_QUEUELEN < 2)) -#error "TCP_SND_QUEUELEN must be at least 2 for no-copy TCP writes to work" + #error "TCP_SND_QUEUELEN must be at least 2 for no-copy TCP writes to work" #endif #if (LWIP_TCP && ((TCP_MAXRTX > 12) || (TCP_SYNMAXRTX > 12))) -#error "If you want to use TCP, TCP_MAXRTX and TCP_SYNMAXRTX must less or equal to 12 (due to tcp_backoff table), so, you have to reduce them in your lwipopts.h" + #error "If you want to use TCP, TCP_MAXRTX and TCP_SYNMAXRTX must less or equal to 12 (due to tcp_backoff table), so, you have to reduce them in your lwipopts.h" #endif #if (LWIP_TCP && TCP_LISTEN_BACKLOG && ((TCP_DEFAULT_LISTEN_BACKLOG < 0) || (TCP_DEFAULT_LISTEN_BACKLOG > 0xff))) -#error "If you want to use TCP backlog, TCP_DEFAULT_LISTEN_BACKLOG must fit into an u8_t" -#endif -#if (LWIP_TCP && LWIP_TCP_SACK_OUT && !TCP_QUEUE_OOSEQ) -#error "To use LWIP_TCP_SACK_OUT, TCP_QUEUE_OOSEQ needs to be enabled" -#endif -#if (LWIP_TCP && LWIP_TCP_SACK_OUT && (LWIP_TCP_MAX_SACK_NUM < 1)) -#error "LWIP_TCP_MAX_SACK_NUM must be greater than 0" + #error "If you want to use TCP backlog, TCP_DEFAULT_LISTEN_BACKLOG must fit into an u8_t" #endif #if (LWIP_NETIF_API && (NO_SYS==1)) -#error "If you want to use NETIF API, you have to define NO_SYS=0 in your lwipopts.h" + #error "If you want to use NETIF API, you have to define NO_SYS=0 in your lwipopts.h" #endif #if ((LWIP_SOCKET || LWIP_NETCONN) && (NO_SYS==1)) -#error "If you want to use Sequential API, you have to define NO_SYS=0 in your lwipopts.h" + #error "If you want to use Sequential API, you have to define NO_SYS=0 in your lwipopts.h" #endif #if (LWIP_PPP_API && (NO_SYS==1)) -#error "If you want to use PPP API, you have to define NO_SYS=0 in your lwipopts.h" + #error "If you want to use PPP API, you have to define NO_SYS=0 in your lwipopts.h" #endif #if (LWIP_PPP_API && (PPP_SUPPORT==0)) -#error "If you want to use PPP API, you have to enable PPP_SUPPORT in your lwipopts.h" + #error "If you want to use PPP API, you have to enable PPP_SUPPORT in your lwipopts.h" #endif #if (((!LWIP_DHCP) || (!LWIP_AUTOIP)) && LWIP_DHCP_AUTOIP_COOP) -#error "If you want to use DHCP/AUTOIP cooperation mode, you have to define LWIP_DHCP=1 and LWIP_AUTOIP=1 in your lwipopts.h" + #error "If you want to use DHCP/AUTOIP cooperation mode, you have to define LWIP_DHCP=1 and LWIP_AUTOIP=1 in your lwipopts.h" #endif #if (((!LWIP_DHCP) || (!LWIP_ARP)) && DHCP_DOES_ARP_CHECK) -#error "If you want to use DHCP ARP checking, you have to define LWIP_DHCP=1 and LWIP_ARP=1 in your lwipopts.h" + #error "If you want to use DHCP ARP checking, you have to define LWIP_DHCP=1 and LWIP_ARP=1 in your lwipopts.h" #endif #if (!LWIP_ARP && LWIP_AUTOIP) -#error "If you want to use AUTOIP, you have to define LWIP_ARP=1 in your lwipopts.h" + #error "If you want to use AUTOIP, you have to define LWIP_ARP=1 in your lwipopts.h" #endif #if (LWIP_TCP && ((LWIP_EVENT_API && LWIP_CALLBACK_API) || (!LWIP_EVENT_API && !LWIP_CALLBACK_API))) -#error "One and exactly one of LWIP_EVENT_API and LWIP_CALLBACK_API has to be enabled in your lwipopts.h" -#endif -#if (LWIP_ALTCP && LWIP_EVENT_API) -#error "The application layered tcp API does not work with LWIP_EVENT_API" + #error "One and exactly one of LWIP_EVENT_API and LWIP_CALLBACK_API has to be enabled in your lwipopts.h" #endif #if (MEM_LIBC_MALLOC && MEM_USE_POOLS) -#error "MEM_LIBC_MALLOC and MEM_USE_POOLS may not both be simultaneously enabled in your lwipopts.h" + #error "MEM_LIBC_MALLOC and MEM_USE_POOLS may not both be simultaneously enabled in your lwipopts.h" #endif #if (MEM_USE_POOLS && !MEMP_USE_CUSTOM_POOLS) -#error "MEM_USE_POOLS requires custom pools (MEMP_USE_CUSTOM_POOLS) to be enabled in your lwipopts.h" + #error "MEM_USE_POOLS requires custom pools (MEMP_USE_CUSTOM_POOLS) to be enabled in your lwipopts.h" #endif #if (PBUF_POOL_BUFSIZE <= MEM_ALIGNMENT) -#error "PBUF_POOL_BUFSIZE must be greater than MEM_ALIGNMENT or the offset may take the full first pbuf" + #error "PBUF_POOL_BUFSIZE must be greater than MEM_ALIGNMENT or the offset may take the full first pbuf" #endif #if (DNS_LOCAL_HOSTLIST && !DNS_LOCAL_HOSTLIST_IS_DYNAMIC && !(defined(DNS_LOCAL_HOSTLIST_INIT))) -#error "you have to define define DNS_LOCAL_HOSTLIST_INIT {{'host1', 0x123}, {'host2', 0x234}} to initialize DNS_LOCAL_HOSTLIST" + #error "you have to define define DNS_LOCAL_HOSTLIST_INIT {{'host1', 0x123}, {'host2', 0x234}} to initialize DNS_LOCAL_HOSTLIST" #endif #if PPP_SUPPORT && !PPPOS_SUPPORT && !PPPOE_SUPPORT && !PPPOL2TP_SUPPORT -#error "PPP_SUPPORT needs at least one of PPPOS_SUPPORT, PPPOE_SUPPORT or PPPOL2TP_SUPPORT turned on" + #error "PPP_SUPPORT needs at least one of PPPOS_SUPPORT, PPPOE_SUPPORT or PPPOL2TP_SUPPORT turned on" #endif #if PPP_SUPPORT && !PPP_IPV4_SUPPORT && !PPP_IPV6_SUPPORT -#error "PPP_SUPPORT needs PPP_IPV4_SUPPORT and/or PPP_IPV6_SUPPORT turned on" + #error "PPP_SUPPORT needs PPP_IPV4_SUPPORT and/or PPP_IPV6_SUPPORT turned on" #endif #if PPP_SUPPORT && PPP_IPV4_SUPPORT && !LWIP_IPV4 -#error "PPP_IPV4_SUPPORT needs LWIP_IPV4 turned on" + #error "PPP_IPV4_SUPPORT needs LWIP_IPV4 turned on" #endif #if PPP_SUPPORT && PPP_IPV6_SUPPORT && !LWIP_IPV6 -#error "PPP_IPV6_SUPPORT needs LWIP_IPV6 turned on" + #error "PPP_IPV6_SUPPORT needs LWIP_IPV6 turned on" #endif #if !LWIP_ETHERNET && (LWIP_ARP || PPPOE_SUPPORT) -#error "LWIP_ETHERNET needs to be turned on for LWIP_ARP or PPPOE_SUPPORT" + #error "LWIP_ETHERNET needs to be turned on for LWIP_ARP or PPPOE_SUPPORT" #endif #if LWIP_TCPIP_CORE_LOCKING_INPUT && !LWIP_TCPIP_CORE_LOCKING -#error "When using LWIP_TCPIP_CORE_LOCKING_INPUT, LWIP_TCPIP_CORE_LOCKING must be enabled, too" + #error "When using LWIP_TCPIP_CORE_LOCKING_INPUT, LWIP_TCPIP_CORE_LOCKING must be enabled, too" #endif #if LWIP_TCP && LWIP_NETIF_TX_SINGLE_PBUF && !TCP_OVERSIZE -#error "LWIP_NETIF_TX_SINGLE_PBUF needs TCP_OVERSIZE enabled to create single-pbuf TCP packets" + #error "LWIP_NETIF_TX_SINGLE_PBUF needs TCP_OVERSIZE enabled to create single-pbuf TCP packets" #endif #if LWIP_NETCONN && LWIP_TCP #if NETCONN_COPY != TCP_WRITE_FLAG_COPY -#error "NETCONN_COPY != TCP_WRITE_FLAG_COPY" + #error "NETCONN_COPY != TCP_WRITE_FLAG_COPY" #endif #if NETCONN_MORE != TCP_WRITE_FLAG_MORE -#error "NETCONN_MORE != TCP_WRITE_FLAG_MORE" + #error "NETCONN_MORE != TCP_WRITE_FLAG_MORE" #endif #endif /* LWIP_NETCONN && LWIP_TCP */ #if LWIP_SOCKET +/* Check that the SO_* socket options and SOF_* lwIP-internal flags match */ +#if SO_REUSEADDR != SOF_REUSEADDR + #error "WARNING: SO_REUSEADDR != SOF_REUSEADDR" +#endif +#if SO_KEEPALIVE != SOF_KEEPALIVE + #error "WARNING: SO_KEEPALIVE != SOF_KEEPALIVE" +#endif +#if SO_BROADCAST != SOF_BROADCAST + #error "WARNING: SO_BROADCAST != SOF_BROADCAST" +#endif #endif /* LWIP_SOCKET */ /* Compile-time checks for deprecated options. */ #ifdef MEMP_NUM_TCPIP_MSG -#error "MEMP_NUM_TCPIP_MSG option is deprecated. Remove it from your lwipopts.h." + #error "MEMP_NUM_TCPIP_MSG option is deprecated. Remove it from your lwipopts.h." #endif #ifdef TCP_REXMIT_DEBUG -#error "TCP_REXMIT_DEBUG option is deprecated. Remove it from your lwipopts.h." + #error "TCP_REXMIT_DEBUG option is deprecated. Remove it from your lwipopts.h." #endif #ifdef RAW_STATS -#error "RAW_STATS option is deprecated. Remove it from your lwipopts.h." + #error "RAW_STATS option is deprecated. Remove it from your lwipopts.h." #endif #ifdef ETHARP_QUEUE_FIRST -#error "ETHARP_QUEUE_FIRST option is deprecated. Remove it from your lwipopts.h." + #error "ETHARP_QUEUE_FIRST option is deprecated. Remove it from your lwipopts.h." #endif #ifdef ETHARP_ALWAYS_INSERT -#error "ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h." + #error "ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h." #endif #if !NO_SYS && LWIP_TCPIP_CORE_LOCKING && LWIP_COMPAT_MUTEX && !defined(LWIP_COMPAT_MUTEX_ALLOWED) -#error "LWIP_COMPAT_MUTEX cannot prevent priority inversion. It is recommended to implement priority-aware mutexes. (Define LWIP_COMPAT_MUTEX_ALLOWED to disable this error.)" + #error "LWIP_COMPAT_MUTEX cannot prevent priority inversion. It is recommended to implement priority-aware mutexes. (Define LWIP_COMPAT_MUTEX_ALLOWED to disable this error.)" #endif #ifndef LWIP_DISABLE_TCP_SANITY_CHECKS @@ -294,31 +300,31 @@ PACK_STRUCT_END #if !LWIP_DISABLE_TCP_SANITY_CHECKS #if LWIP_TCP #if !MEMP_MEM_MALLOC && (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN) -#error "lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." + #error "lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." #endif #if TCP_SND_BUF < (2 * TCP_MSS) -#error "lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." + #error "lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." #endif #if TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF / TCP_MSS)) -#error "lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." + #error "lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." #endif #if TCP_SNDLOWAT >= TCP_SND_BUF -#error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." + #error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." #endif #if TCP_SNDLOWAT >= (0xFFFF - (4 * TCP_MSS)) -#error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must at least be 4*MSS below u16_t overflow!" + #error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must at least be 4*MSS below u16_t overflow!" #endif #if TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN -#error "lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." + #error "lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." #endif #if !MEMP_MEM_MALLOC && PBUF_POOL_SIZE && (PBUF_POOL_BUFSIZE <= (PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) -#error "lwip_sanity_check: WARNING: PBUF_POOL_BUFSIZE does not provide enough space for protocol headers. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." + #error "lwip_sanity_check: WARNING: PBUF_POOL_BUFSIZE does not provide enough space for protocol headers. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." #endif #if !MEMP_MEM_MALLOC && PBUF_POOL_SIZE && (TCP_WND > (PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - (PBUF_LINK_ENCAPSULATION_HLEN + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)))) -#error "lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - protocol headers). If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." + #error "lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - protocol headers). If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." #endif #if TCP_WND < TCP_MSS -#error "lwip_sanity_check: WARNING: TCP_WND is smaller than MSS. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." + #error "lwip_sanity_check: WARNING: TCP_WND is smaller than MSS. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." #endif #endif /* LWIP_TCP */ #endif /* !LWIP_DISABLE_TCP_SANITY_CHECKS */ @@ -334,7 +340,7 @@ lwip_init(void) #ifndef LWIP_SKIP_CONST_CHECK int a = 0; LWIP_UNUSED_ARG(a); - LWIP_ASSERT("LWIP_CONST_CAST not implemented correctly. Check your lwIP port.", LWIP_CONST_CAST(void *, &a) == &a); + LWIP_ASSERT("LWIP_CONST_CAST not implemented correctly. Check your lwIP port.", LWIP_CONST_CAST(void*, &a) == &a); #endif #ifndef LWIP_SKIP_PACKING_CHECK LWIP_ASSERT("Struct packing not implemented correctly. Check your lwIP port.", sizeof(struct packed_struct_test) == PACKED_STRUCT_TEST_EXPECTED_SIZE); @@ -373,8 +379,12 @@ lwip_init(void) #if PPP_SUPPORT ppp_init(); #endif - + #if LWIP_TIMERS sys_timeouts_init(); #endif /* LWIP_TIMERS */ + +#if IP_NAPT && !IP_NAPT_DYNAMIC + ip_napt_init(IP_NAPT_MAX, IP_PORTMAP_MAX); +#endif /* IP_NAPT */ } diff --git a/src/core/ipv4/ip4.c b/src/core/ipv4/ip4.c index 886f42cc..04930aca 100644 --- a/src/core/ipv4/ip4.c +++ b/src/core/ipv4/ip4.c @@ -42,6 +42,7 @@ #if LWIP_IPV4 +#include "lwip/sys.h" #include "lwip/ip.h" #include "lwip/def.h" #include "lwip/mem.h" @@ -56,6 +57,7 @@ #include "lwip/autoip.h" #include "lwip/stats.h" #include "lwip/prot/iana.h" +#include "lwip/lwip_napt.h" #include @@ -279,6 +281,699 @@ ip4_route(const ip4_addr_t *dest) } #if IP_FORWARD +#if IP_NAPT + +#define NO_IDX ((u16_t)-1) +#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 napt_table *ip_napt_table; +struct portmap_table *ip_portmap_table; + +int nr_active_napt_tcp = 0, nr_active_napt_udp = 0, nr_active_napt_icmp = 0; +uint16_t ip_napt_max = 0; +uint8_t ip_portmap_max = 0; + +#if NAPT_DEBUG +/* Print NAPT table using LWIP_DEBUGF +*/ +void +napt_debug_print() +{ + 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 */ + +void +ip_napt_init(uint16_t max_nat, uint8_t max_portmap) +{ + u16_t i; + + ip_napt_max = max_nat; + ip_portmap_max = max_portmap; + + ip_napt_table = (struct napt_table*)calloc(1, sizeof(struct napt_table[ip_napt_max])); + ip_portmap_table = (struct portmap_table*)calloc(1, sizeof(struct portmap_table[ip_portmap_max])); + + 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; + for (netif = netif_list; netif; netif = netif->next) { + if (netif_is_up(netif) && !ip_addr_isany(&netif->ip_addr) && netif->ip_addr.u_addr.ip4.addr == addr) { + netif->napt = !!enable; + break; + } + } +} + +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; + break; + } + } +} + +void checksumadjust(unsigned char *chksum, unsigned char *optr, + int olen, unsigned char *nptr, int nlen) + /* assuming: unsigned char is 8 bits, long is 32 bits. + - chksum points to the chksum in the packet + - optr points to the old data in the packet + - nptr points to the new data in the packet + */ + { + long x, old, new; + x=chksum[0]*256+chksum[1]; + x=~x & 0xFFFF; + while (olen) + { + old=optr[0]*256+optr[1]; optr+=2; + x-=old & 0xffff; + if (x<=0) { x--; x&=0xffff; } + olen-=2; + } + while (nlen) + { + new=nptr[0]*256+nptr[1]; nptr+=2; + x+=new & 0xffff; + if (x & 0x10000) { x++; x&=0xffff; } + nlen-=2; + } + x=~x & 0xFFFF; + chksum[0]=x/256; chksum[1]=x & 0xff; + } + + +/* t must be indexed by napt_free */ +static void +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 +//os_printf("T: %d, U: %d, I: %d\r\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 + + esp_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* +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; + + 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 + + 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) { + 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; + } + return 0; +} + +u8_t +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 * +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) +{ + 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 +ip_napt_modify_port_tcp(struct tcp_hdr *tcphdr, u8_t dest, u16_t newval) +{ + if (dest) { + checksumadjust((unsigned char *)&tcphdr->chksum, (unsigned char *)&tcphdr->dest, 2, (unsigned char *)&newval, 2); + tcphdr->dest = newval; + } else { + checksumadjust((unsigned char *)&tcphdr->chksum, (unsigned char *)&tcphdr->src, 2, (unsigned char *)&newval, 2); + tcphdr->src = newval; + } +} + +void +ip_napt_modify_addr_tcp(struct tcp_hdr *tcphdr, ip4_addr_p_t *oldval, u32_t newval) +{ + checksumadjust((unsigned char *)&tcphdr->chksum, (unsigned char *)&oldval->addr, 4, (unsigned char *)&newval, 4); +} +#endif // LWIP_TCP + +#if LWIP_UDP +void +ip_napt_modify_port_udp(struct udp_hdr *udphdr, u8_t dest, u16_t newval) +{ + if (dest) { + checksumadjust((unsigned char *)&udphdr->chksum, (unsigned char *)&udphdr->dest, 2, (unsigned char *)&newval, 2); + udphdr->dest = newval; + } else { + checksumadjust((unsigned char *)&udphdr->chksum, (unsigned char *)&udphdr->src, 2, (unsigned char *)&newval, 2); + udphdr->src = newval; + } +} + +void +ip_napt_modify_addr_udp(struct udp_hdr *udphdr, ip4_addr_p_t *oldval, u32_t newval) +{ + checksumadjust( (unsigned char *)&udphdr->chksum, (unsigned char *)&oldval->addr, 4, (unsigned char *)&newval, 4); +} +#endif // LWIP_UDP + +void +ip_napt_modify_addr(struct ip_hdr *iphdr, ip4_addr_p_t *field, u32_t newval) +{ + checksumadjust((unsigned char *)&IPH_CHKSUM(iphdr), (unsigned char *)&field->addr, 4, (unsigned char *)&newval, 4); + 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 +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 +} + +/** + * 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 +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.u_addr.ip4.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 */ + } + 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.u_addr.ip4.addr); + ip_napt_modify_addr(iphdr, &iphdr->src, outp->ip_addr.u_addr.ip4.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.u_addr.ip4.addr); + ip_napt_modify_addr(iphdr, &iphdr->src, outp->ip_addr.u_addr.ip4.addr); + return ERR_OK; + } +#endif + + return ERR_OK; +} +#endif // IP_NAPT + /** * Determine whether an IP address is in a reserved set of addresses * that may not be forwarded, or whether datagrams to that destination @@ -380,6 +1075,11 @@ ip4_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(0xffffU - 0x100)) { IPH_CHKSUM_SET(iphdr, (u16_t)(IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1)); @@ -476,7 +1176,7 @@ ip4_input_accept(struct netif *netif) err_t ip4_input(struct pbuf *p, struct netif *inp) { - const struct ip_hdr *iphdr; + struct ip_hdr *iphdr; struct netif *netif; u16_t iphdr_hlen; u16_t iphdr_len; @@ -562,6 +1262,12 @@ ip4_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 && ip4_addr_cmp(&iphdr->dest, netif_ip4_addr(inp))) + ip_napt_recv(p, iphdr); +#endif + /* 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); @@ -1031,7 +1737,9 @@ ip4_output_if_opt_src(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *d LWIP_DEBUGF(IP_DEBUG, ("ip4_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], (u16_t)netif->num)); ip4_debug_print(p); -#if ENABLE_LOOPBACK +#if 0 && ENABLE_LOOPBACK + /* doesn't work for external wifi interfaces */ + if (ip4_addr_cmp(dest, netif_ip4_addr(netif)) #if !LWIP_HAVE_LOOPIF || ip4_addr_isloopback(dest) diff --git a/src/core/netif.c b/src/core/netif.c index ac9f2821..7df65e40 100644 --- a/src/core/netif.c +++ b/src/core/netif.c @@ -367,6 +367,10 @@ netif_add(struct netif *netif, netif->loop_cnt_current = 0; #endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */ +#if IP_NAPT + netif->napt = 0; +#endif /* IP_NAPT */ + #if LWIP_IPV4 netif_set_addr(netif, ipaddr, netmask, gw); #endif /* LWIP_IPV4 */ diff --git a/src/include/lwip/ip.h b/src/include/lwip/ip.h index 653c3b2f..5cf4d8a4 100644 --- a/src/include/lwip/ip.h +++ b/src/include/lwip/ip.h @@ -172,6 +172,12 @@ extern struct ip_globals ip_data; /** Destination IP4 address of current_header */ #define ip4_current_dest_addr() (ip_2_ip4(&ip_data.current_iphdr_dest)) +#if NAPT_DEBUG +void napt_debug_print()ICACHE_FLASH_ATTR; +#else +#define napt_debug_print(p) +#endif /* NAPT_DEBUG */ + #elif LWIP_IPV4 /* LWIP_IPV4 && LWIP_IPV6 */ /** Get the IPv4 header of the current packet. diff --git a/src/include/lwip/lwip_napt.h b/src/include/lwip/lwip_napt.h new file mode 100644 index 00000000..0cde2949 --- /dev/null +++ b/src/include/lwip/lwip_napt.h @@ -0,0 +1,114 @@ +#ifndef __LWIP_NAPT_H__ +#define __LWIP_NAPT_H__ + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if IP_FORWARD +#if IP_NAPT + +/* Default size of the tables used for NAPT */ +#define IP_NAPT_MAX 512 +#define IP_PORTMAP_MAX 32 + +/* 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 + +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; + 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; +}; + +extern struct portmap_table *ip_portmap_table; + +/** + * 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) + */ +void ip_napt_init(uint16_t max_nat, uint8_t max_portmap); + + +/** + * 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 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 maddr ip address of the external interface + */ +u8_t +ip_portmap_remove(u8_t proto, u16_t mport); + +#endif /* IP_NAPT */ +#endif /* IP_FORWARD */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_NAPT_H__ */ diff --git a/src/include/lwip/netif.h b/src/include/lwip/netif.h index f72f082e..89747829 100644 --- a/src/include/lwip/netif.h +++ b/src/include/lwip/netif.h @@ -410,6 +410,9 @@ struct netif { void (*l2_buffer_free_notify)(struct netif *lwip_netif, void *user_buf); /* Allows LWIP to notify driver when a L2-supplied pbuf can be freed */ ip_addr_t last_ip_addr; /* Store last non-zero ip address */ #endif +#if LWIP_IPV4 && IP_NAPT + u8_t napt; +#endif }; #if LWIP_CHECKSUM_CTRL_PER_NETIF #define NETIF_SET_CHECKSUM_CTRL(netif, chksumflags) do { \ diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 09562a45..cb0e5890 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -736,7 +736,7 @@ * interface, define this to 0. */ #if !defined IP_FORWARD || defined __DOXYGEN__ -#define IP_FORWARD 0 +#define IP_FORWARD 1 #endif /** @@ -767,6 +767,10 @@ #define IP_FRAG 0 #endif /* !LWIP_IPV4 */ +#ifndef IP_NAPT +#define IP_NAPT 1 +#endif + /** * IP_OPTIONS_ALLOWED: Defines the behavior for IP options. * IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. @@ -1114,7 +1118,7 @@ * transport. */ #if !defined LWIP_DNS || defined __DOXYGEN__ -#define LWIP_DNS 0 +#define LWIP_DNS 1 #endif /** DNS maximum number of entries to maintain locally. */ @@ -3525,6 +3529,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 ----------