This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit f2ff5cee03353acb4acf817a2c1709722c1b4391 Author: Zhe Weng <[email protected]> AuthorDate: Mon Mar 18 18:41:38 2024 +0800 net/nat: Make some IPv4 NAT functions as common To prepare for future IPv6 NAT functions. - Rename common ipv4_nat_xxx to nat_xxx - Move some common definitions into header Signed-off-by: Zhe Weng <[email protected]> --- Documentation/components/net/nat.rst | 12 +- net/nat/CMakeLists.txt | 6 +- net/nat/Make.defs | 2 + net/nat/ipv4_nat.c | 129 +------------ net/nat/ipv4_nat_entry.c | 189 +------------------ net/nat/nat.c | 341 +++++++++++++++++++++++++++++++++++ net/nat/nat.h | 93 +++++++++- net/netfilter/ipt_nat.c | 4 +- net/tcp/tcp_conn.c | 10 +- net/udp/udp_conn.c | 14 +- 10 files changed, 462 insertions(+), 338 deletions(-) diff --git a/Documentation/components/net/nat.rst b/Documentation/components/net/nat.rst index 773bb5bf1a..621e7b738b 100644 --- a/Documentation/components/net/nat.rst +++ b/Documentation/components/net/nat.rst @@ -75,10 +75,10 @@ Configuration Options Usage ===== - - :c:func:`ipv4_nat_enable()` - - :c:func:`ipv4_nat_disable()` + - :c:func:`nat_enable()` + - :c:func:`nat_disable()` -.. c:function:: int ipv4_nat_enable(FAR struct net_driver_s *dev); +.. c:function:: int nat_enable(FAR struct net_driver_s *dev); Enable NAT function on a network device, on which the outbound packets will be masqueraded. @@ -86,7 +86,7 @@ Usage :return: Zero is returned if NAT function is successfully enabled on the device; A negated errno value is returned if failed. -.. c:function:: int ipv4_nat_disable(FAR struct net_driver_s *dev); +.. c:function:: int nat_disable(FAR struct net_driver_s *dev); Disable NAT function on a network device. @@ -107,7 +107,7 @@ Validated on Ubuntu 22.04 x86_64 with NuttX SIM by following steps: # CONFIG_SIM_NET_BRIDGE is not set CONFIG_SIM_NETDEV_NUMBER=2 -2. Call ``ipv4_nat_enable`` on one dev on startup, or manually enable NAT +2. Call ``nat_enable`` on one dev on startup, or manually enable NAT with ``iptables`` command (either may work). .. code-block:: c @@ -116,7 +116,7 @@ Validated on Ubuntu 22.04 x86_64 with NuttX SIM by following steps: int netdriver_init(void) { ... - ipv4_nat_enable(&g_sim_dev[0]); + nat_enable(&g_sim_dev[0]); ... } diff --git a/net/nat/CMakeLists.txt b/net/nat/CMakeLists.txt index 0e8dd83f5c..ebf100a46a 100644 --- a/net/nat/CMakeLists.txt +++ b/net/nat/CMakeLists.txt @@ -22,8 +22,12 @@ if(CONFIG_NET_NAT) + list(APPEND SRCS nat.c) + if(CONFIG_NET_IPv4) - target_sources(net PRIVATE ipv4_nat.c ipv4_nat_entry.c) + list(APPEND SRCS ipv4_nat.c ipv4_nat_entry.c) endif() + target_sources(net PRIVATE ${SRCS}) + endif() diff --git a/net/nat/Make.defs b/net/nat/Make.defs index 43d185837e..ee4fe9cbe2 100644 --- a/net/nat/Make.defs +++ b/net/nat/Make.defs @@ -22,6 +22,8 @@ ifeq ($(CONFIG_NET_NAT),y) +NET_CSRCS += nat.c + ifeq ($(CONFIG_NET_IPv4),y) NET_CSRCS += ipv4_nat.c ipv4_nat_entry.c endif diff --git a/net/nat/ipv4_nat.c b/net/nat/ipv4_nat.c index c3a81b064a..06c627bd4e 100644 --- a/net/nat/ipv4_nat.c +++ b/net/nat/ipv4_nat.c @@ -26,7 +26,6 @@ #include <assert.h> #include <debug.h> -#include <errno.h> #include <stdint.h> #include <string.h> #include <sys/types.h> @@ -44,28 +43,6 @@ * Pre-processor Definitions ****************************************************************************/ -/* Adjust checksums in headers. */ - -#define chksum_adjust(chksum,optr,nptr,len) \ - net_chksum_adjust((FAR uint16_t *)(chksum), (FAR uint16_t *)(optr), len, \ - (FAR uint16_t *)(nptr), len) - -/* Getting IP & Port to manipulate from L3/L4 header. */ - -#define MANIP_IPADDR(iphdr,manip_type) \ - ((manip_type) == NAT_MANIP_SRC ? (iphdr)->srcipaddr : (iphdr)->destipaddr) - -#define MANIP_PORT(l4hdr,manip_type) \ - ((manip_type) == NAT_MANIP_SRC ? &(l4hdr)->srcport : &(l4hdr)->destport) - -/* Getting peer IP & Port (just other than MANIP) */ - -#define PEER_IPADDR(iphdr,manip_type) \ - ((manip_type) != NAT_MANIP_SRC ? (iphdr)->srcipaddr : (iphdr)->destipaddr) - -#define PEER_PORT(l4hdr,manip_type) \ - ((manip_type) != NAT_MANIP_SRC ? &(l4hdr)->srcport : &(l4hdr)->destport) - /* Getting L4 header from IPv4 header. */ #define L4_HDR(ipv4) \ @@ -151,10 +128,10 @@ static void ipv4_nat_ip_adjust(FAR struct ipv4_hdr_s *ipv4, { if (l4chksum != NULL) { - chksum_adjust(l4chksum, old_ip, &new_ip, sizeof(new_ip)); + nat_chksum_adjust(l4chksum, old_ip, &new_ip, sizeof(new_ip)); } - chksum_adjust(&ipv4->ipchksum, old_ip, &new_ip, sizeof(new_ip)); + nat_chksum_adjust(&ipv4->ipchksum, old_ip, &new_ip, sizeof(new_ip)); net_ipv4addr_hdrcopy(old_ip, &new_ip); } @@ -176,7 +153,7 @@ static void ipv4_nat_port_adjust(FAR uint16_t *l4chksum, { if (l4chksum != NULL) { - chksum_adjust(l4chksum, old_port, &new_port, sizeof(new_port)); + nat_chksum_adjust(l4chksum, old_port, &new_port, sizeof(new_port)); } *old_port = new_port; @@ -400,8 +377,8 @@ ipv4_nat_inbound_icmp(FAR struct ipv4_hdr_s *ipv4, * and the overall checksum of IPv4 header will not change. */ - chksum_adjust(&icmp->icmpchksum, inner_l4hdrbak, inner_l4, - inner_l4hdrlen); + nat_chksum_adjust(&icmp->icmpchksum, inner_l4hdrbak, inner_l4, + inner_l4hdrlen); return entry; } @@ -639,8 +616,8 @@ ipv4_nat_outbound_icmp(FAR struct net_driver_s *dev, * and the overall checksum of IPv4 header will not change. */ - chksum_adjust(&icmp->icmpchksum, inner_l4hdrbak, inner_l4, - inner_l4hdrlen); + nat_chksum_adjust(&icmp->icmpchksum, inner_l4hdrbak, inner_l4, + inner_l4hdrlen); return entry; } @@ -745,74 +722,6 @@ ipv4_nat_outbound_internal(FAR struct net_driver_s *dev, * Public Functions ****************************************************************************/ -/**************************************************************************** - * Name: ipv4_nat_enable - * - * Description: - * Enable NAT function on a network device. - * - * Input Parameters: - * dev - The device on which the outbound packets will be masqueraded. - * - * Returned Value: - * Zero is returned if NAT function is successfully enabled on the device; - * A negated errno value is returned if failed. - * - ****************************************************************************/ - -int ipv4_nat_enable(FAR struct net_driver_s *dev) -{ - net_lock(); - - if (IFF_IS_NAT(dev->d_flags)) - { - nwarn("WARNING: NAT was already enabled for %s!\n", dev->d_ifname); - net_unlock(); - return -EEXIST; - } - - IFF_SET_NAT(dev->d_flags); - - net_unlock(); - return OK; -} - -/**************************************************************************** - * Name: ipv4_nat_disable - * - * Description: - * Disable NAT function on a network device. - * - * Input Parameters: - * dev - The device on which the NAT function will be disabled. - * - * Returned Value: - * Zero is returned if NAT function is successfully disabled on the device; - * A negated errno value is returned if failed. - * - ****************************************************************************/ - -int ipv4_nat_disable(FAR struct net_driver_s *dev) -{ - net_lock(); - - if (!IFF_IS_NAT(dev->d_flags)) - { - nwarn("WARNING: NAT was not enabled for %s!\n", dev->d_ifname); - net_unlock(); - return -ENODEV; - } - - /* Clear entries related to dev. */ - - ipv4_nat_entry_clear(dev); - - IFF_CLR_NAT(dev->d_flags); - - net_unlock(); - return OK; -} - /**************************************************************************** * Name: ipv4_nat_inbound * @@ -899,28 +808,4 @@ int ipv4_nat_outbound(FAR struct net_driver_s *dev, return OK; } -/**************************************************************************** - * Name: ipv4_nat_port_inuse - * - * Description: - * Check whether a port is currently used by NAT. - * - * Input Parameters: - * protocol - The L4 protocol of the packet. - * ip - The IP bind with the port (in network byte order). - * port - The port number to check (in network byte order). - * - * Returned Value: - * True if the port is already used by NAT, otherwise false. - * - ****************************************************************************/ - -bool ipv4_nat_port_inuse(uint8_t protocol, in_addr_t ip, uint16_t port) -{ - FAR struct ipv4_nat_entry *entry = - ipv4_nat_inbound_entry_find(protocol, ip, port, INADDR_ANY, 0, false); - - return entry != NULL; -} - #endif /* CONFIG_NET_NAT && CONFIG_NET_IPv4 */ diff --git a/net/nat/ipv4_nat_entry.c b/net/nat/ipv4_nat_entry.c index 8f2624a5f9..7b033a5d0f 100644 --- a/net/nat/ipv4_nat_entry.c +++ b/net/nat/ipv4_nat_entry.c @@ -31,12 +31,8 @@ #include <nuttx/hashtable.h> #include <nuttx/kmalloc.h> #include <nuttx/nuttx.h> -#include <nuttx/queue.h> -#include "icmp/icmp.h" #include "nat/nat.h" -#include "tcp/tcp.h" -#include "udp/udp.h" #if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4) @@ -83,152 +79,6 @@ static inline uint32_t ipv4_nat_outbound_key(in_addr_t local_ip, ((uint32_t)protocol << 8) ^ ((uint32_t)local_port << 16); } -/**************************************************************************** - * Name: ipv4_nat_select_port_without_stack - * - * Description: - * Select an available port number for TCP/UDP protocol, or id for ICMP. - * Used when corresponding stack is disabled. - * - * Input Parameters: - * protocol - The L4 protocol of the packet. - * ip - The IP bind with the port (in network byte order). - * portno - The local port (in network byte order), as reference. - * - * Returned Value: - * port number on success; 0 on failure - * - ****************************************************************************/ - -#if (defined(CONFIG_NET_TCP) && defined(CONFIG_NET_TCP_NO_STACK)) || \ - (defined(CONFIG_NET_UDP) && defined(CONFIG_NET_UDP_NO_STACK)) || \ - (defined(CONFIG_NET_ICMP) && !defined(CONFIG_NET_ICMP_SOCKET)) - -static uint16_t ipv4_nat_select_port_without_stack( - uint8_t protocol, in_addr_t ip, uint16_t portno) -{ - uint16_t hport = NTOHS(portno); - while (ipv4_nat_port_inuse(protocol, ip, portno)) - { - ++hport; - if (hport >= CONFIG_NET_DEFAULT_MAX_PORT || - hport < CONFIG_NET_DEFAULT_MIN_PORT) - { - hport = CONFIG_NET_DEFAULT_MIN_PORT; - } - - portno = HTONS(hport); - } - - return portno; -} - -#endif - -/**************************************************************************** - * Name: ipv4_nat_select_port - * - * Description: - * Select an available port number for TCP/UDP protocol, or id for ICMP. - * - * Input Parameters: - * dev - The device on which the packet will be sent. - * protocol - The L4 protocol of the packet. - * local_port - The local port of the packet, as reference. - * - * Returned Value: - * port number on success; 0 on failure - * - ****************************************************************************/ - -static uint16_t ipv4_nat_select_port(FAR struct net_driver_s *dev, - uint8_t protocol, - uint16_t local_port) -{ - switch (protocol) - { -#ifdef CONFIG_NET_TCP - case IP_PROTO_TCP: - { -#ifndef CONFIG_NET_TCP_NO_STACK - /* Try to select local_port first. */ - - int ret = tcp_selectport(PF_INET, - (FAR const union ip_addr_u *)&dev->d_ipaddr, - local_port); - - /* If failed, try select another unused port. */ - - if (ret < 0) - { - ret = tcp_selectport(PF_INET, - (FAR const union ip_addr_u *)&dev->d_ipaddr, 0); - } - - return ret > 0 ? ret : 0; -#else - return ipv4_nat_select_port_without_stack(IP_PROTO_TCP, - dev->d_ipaddr, - local_port); -#endif - } -#endif - -#ifdef CONFIG_NET_UDP - case IP_PROTO_UDP: - { -#ifndef CONFIG_NET_UDP_NO_STACK - union ip_binding_u u; - u.ipv4.laddr = dev->d_ipaddr; - u.ipv4.raddr = INADDR_ANY; - - /* TODO: Try keep origin port as possible. */ - - return HTONS(udp_select_port(PF_INET, &u)); -#else - return ipv4_nat_select_port_without_stack(IP_PROTO_UDP, - dev->d_ipaddr, - local_port); -#endif - } -#endif - -#ifdef CONFIG_NET_ICMP - case IP_PROTO_ICMP: - { -#ifdef CONFIG_NET_ICMP_SOCKET - uint16_t id = local_port; - uint16_t hid = NTOHS(id); - while (icmp_findconn(dev, id) || - ipv4_nat_port_inuse(IP_PROTO_ICMP, dev->d_ipaddr, id)) - { - ++hid; - if (hid >= CONFIG_NET_DEFAULT_MAX_PORT || - hid < CONFIG_NET_DEFAULT_MIN_PORT) - { - hid = CONFIG_NET_DEFAULT_MIN_PORT; - } - - id = HTONS(hid); - } - - return id; -#else - return ipv4_nat_select_port_without_stack(IP_PROTO_ICMP, - dev->d_ipaddr, - local_port); -#endif - } -#endif - } - - /* TODO: Currently select original port for unsupported protocol, maybe - * return zero to indicate failure. - */ - - return local_port; -} - /**************************************************************************** * Name: ipv4_nat_entry_refresh * @@ -242,40 +92,7 @@ static uint16_t ipv4_nat_select_port(FAR struct net_driver_s *dev, static void ipv4_nat_entry_refresh(FAR struct ipv4_nat_entry *entry) { - /* Note: May add logic here to move recent node to head side if each chain - * in hashtable is still too long (with long expire time). - */ - - switch (entry->protocol) - { -#ifdef CONFIG_NET_TCP - case IP_PROTO_TCP: - /* NOTE: According to RFC2663, Section 2.6, Page 5, we can reduce the - * time to 4min if we have received FINs from both side of one - * connection, and keep 24h for other TCP connections. However, full - * cone NAT may have multiple connections on one entry, so this - * optimization may not work and we only use one expiration time. - */ - - entry->expire_time = TICK2SEC(clock_systime_ticks()) + - CONFIG_NET_NAT_TCP_EXPIRE_SEC; - break; -#endif - -#ifdef CONFIG_NET_UDP - case IP_PROTO_UDP: - entry->expire_time = TICK2SEC(clock_systime_ticks()) + - CONFIG_NET_NAT_UDP_EXPIRE_SEC; - break; -#endif - -#ifdef CONFIG_NET_ICMP - case IP_PROTO_ICMP: - entry->expire_time = TICK2SEC(clock_systime_ticks()) + - CONFIG_NET_NAT_ICMP_EXPIRE_SEC; - break; -#endif - } + entry->expire_time = nat_expire_time(entry->protocol); } /**************************************************************************** @@ -556,6 +373,7 @@ ipv4_nat_outbound_entry_find(FAR struct net_driver_s *dev, uint8_t protocol, { FAR hash_node_t *p; FAR hash_node_t *tmp; + uint16_t external_port; int32_t current_time = TICK2SEC(clock_systime_ticks()); #if CONFIG_NET_NAT_ENTRY_RECLAIM_SEC > 0 @@ -602,7 +420,8 @@ ipv4_nat_outbound_entry_find(FAR struct net_driver_s *dev, uint8_t protocol, "proto=%" PRIu8 ", local=%" PRIx32 ":%" PRIu16 ", try create one.\n", protocol, local_ip, local_port); - uint16_t external_port = ipv4_nat_select_port(dev, protocol, local_port); + external_port = nat_port_select(dev, PF_INET, protocol, + (FAR union ip_addr_u *)&dev->d_ipaddr, local_port); if (!external_port) { nwarn("WARNING: Failed to find an available port!\n"); diff --git a/net/nat/nat.c b/net/nat/nat.c new file mode 100644 index 0000000000..0c3dc02907 --- /dev/null +++ b/net/nat/nat.c @@ -0,0 +1,341 @@ +/**************************************************************************** + * net/nat/nat.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <debug.h> + +#include "icmp/icmp.h" +#include "nat/nat.h" +#include "tcp/tcp.h" +#include "udp/udp.h" + +#ifdef CONFIG_NET_NAT + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nat_port_select_without_stack + * + * Description: + * Select an available port number for TCP/UDP protocol, or id for ICMP. + * Used when corresponding stack is disabled. + * + * Input Parameters: + * domain - The domain of the packet. + * protocol - The L4 protocol of the packet. + * ip - The IP bind with the port (in network byte order). + * portno - The local port (in network byte order), as reference. + * + * Returned Value: + * port number on success; 0 on failure + * + ****************************************************************************/ + +#if (defined(CONFIG_NET_TCP) && defined(CONFIG_NET_TCP_NO_STACK)) || \ + (defined(CONFIG_NET_UDP) && defined(CONFIG_NET_UDP_NO_STACK)) || \ + (defined(CONFIG_NET_ICMP) && !defined(CONFIG_NET_ICMP_SOCKET)) + +static uint16_t nat_port_select_without_stack( + uint8_t domain, uint8_t protocol, FAR const union ip_addr_u *ip, + uint16_t portno) +{ + uint16_t hport = NTOHS(portno); + while (nat_port_inuse(domain, protocol, ip, portno)) + { + ++hport; + if (hport >= CONFIG_NET_DEFAULT_MAX_PORT || + hport < CONFIG_NET_DEFAULT_MIN_PORT) + { + hport = CONFIG_NET_DEFAULT_MIN_PORT; + } + + portno = HTONS(hport); + } + + return portno; +} + +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nat_enable + * + * Description: + * Enable NAT function on a network device. + * + * Input Parameters: + * dev - The device on which the outbound packets will be masqueraded. + * + * Returned Value: + * Zero is returned if NAT function is successfully enabled on the device; + * A negated errno value is returned if failed. + * + ****************************************************************************/ + +int nat_enable(FAR struct net_driver_s *dev) +{ + net_lock(); + + if (IFF_IS_NAT(dev->d_flags)) + { + nwarn("WARNING: NAT was already enabled for %s!\n", dev->d_ifname); + net_unlock(); + return -EEXIST; + } + + IFF_SET_NAT(dev->d_flags); + + net_unlock(); + return OK; +} + +/**************************************************************************** + * Name: nat_disable + * + * Description: + * Disable NAT function on a network device. + * + * Input Parameters: + * dev - The device on which the NAT function will be disabled. + * + * Returned Value: + * Zero is returned if NAT function is successfully disabled on the device; + * A negated errno value is returned if failed. + * + ****************************************************************************/ + +int nat_disable(FAR struct net_driver_s *dev) +{ + net_lock(); + + if (!IFF_IS_NAT(dev->d_flags)) + { + nwarn("WARNING: NAT was not enabled for %s!\n", dev->d_ifname); + net_unlock(); + return -ENODEV; + } + + /* Clear entries related to dev. */ + +#ifdef CONFIG_NET_IPv4 + ipv4_nat_entry_clear(dev); +#endif + + IFF_CLR_NAT(dev->d_flags); + + net_unlock(); + return OK; +} + +/**************************************************************************** + * Name: nat_port_inuse + * + * Description: + * Check whether a port is currently used by NAT. + * + * Input Parameters: + * domain - The domain of the packet. + * protocol - The L4 protocol of the packet. + * ip - The IP bind with the port (in network byte order). + * port - The port number to check (in network byte order). + * + * Returned Value: + * True if the port is already used by NAT, otherwise false. + * + ****************************************************************************/ + +bool nat_port_inuse(uint8_t domain, uint8_t protocol, + FAR const union ip_addr_u *ip, uint16_t port) +{ +#ifdef CONFIG_NET_IPv4 + if (domain == PF_INET) + { + return !!ipv4_nat_inbound_entry_find(protocol, ip->ipv4, port, + INADDR_ANY, 0, false); + } +#endif + + return false; +} + +/**************************************************************************** + * Name: nat_port_select + * + * Description: + * Select an available port number for TCP/UDP protocol, or id for ICMP. + * + * Input Parameters: + * dev - The device on which the packet will be sent. + * domain - The domain of the packet. + * protocol - The L4 protocol of the packet. + * external_ip - The external IP bind with the port. + * local_port - The local port of the packet, as reference. + * + * Returned Value: + * External port number on success; 0 on failure + * + ****************************************************************************/ + +uint16_t nat_port_select(FAR struct net_driver_s *dev, + uint8_t domain, uint8_t protocol, + FAR const union ip_addr_u *external_ip, + uint16_t local_port) +{ + switch (protocol) + { +#ifdef CONFIG_NET_TCP + case IP_PROTO_TCP: + { +#ifndef CONFIG_NET_TCP_NO_STACK + /* Try to select local_port first. */ + + int ret = tcp_selectport(domain, external_ip, local_port); + + /* If failed, try select another unused port. */ + + if (ret < 0) + { + ret = tcp_selectport(domain, external_ip, 0); + } + + return ret > 0 ? ret : 0; +#else + return nat_port_select_without_stack(domain, IP_PROTO_TCP, + external_ip, local_port); +#endif + } +#endif + +#ifdef CONFIG_NET_UDP + case IP_PROTO_UDP: + { +#ifndef CONFIG_NET_UDP_NO_STACK + union ip_binding_u u; + u.ipv4.laddr = external_ip->ipv4; + u.ipv4.raddr = INADDR_ANY; + + /* TODO: Try keep origin port as possible. */ + + return HTONS(udp_select_port(domain, &u)); +#else + return nat_port_select_without_stack(domain, IP_PROTO_UDP, + external_ip, local_port); +#endif + } +#endif + +#ifdef CONFIG_NET_ICMP + case IP_PROTO_ICMP: + { +#ifdef CONFIG_NET_ICMP_SOCKET + uint16_t id = local_port; + uint16_t hid = NTOHS(id); + while (icmp_findconn(dev, id) || + nat_port_inuse(domain, IP_PROTO_ICMP, external_ip, id)) + { + ++hid; + if (hid >= CONFIG_NET_DEFAULT_MAX_PORT || + hid < CONFIG_NET_DEFAULT_MIN_PORT) + { + hid = CONFIG_NET_DEFAULT_MIN_PORT; + } + + id = HTONS(hid); + } + + return id; +#else + return nat_port_select_without_stack(domain, IP_PROTO_ICMP, + external_ip, local_port); +#endif + } +#endif + } + + /* Select original port for unsupported protocol. */ + + return local_port; +} + +/**************************************************************************** + * Name: nat_expire_time + * + * Description: + * Get the expiration time of a specific protocol. + * + * Input Parameters: + * protocol - The L4 protocol of the packet. + * + * Returned Value: + * The expiration time of the protocol. + * + ****************************************************************************/ + +uint32_t nat_expire_time(uint8_t protocol) +{ + /* Note: May add logic here to move recent node to head side if each chain + * in hashtable is still too long (with long expire time). + */ + + switch (protocol) + { +#ifdef CONFIG_NET_TCP + case IP_PROTO_TCP: + /* NOTE: According to RFC2663, Section 2.6, Page 5, we can reduce the + * time to 4min if we have received FINs from both side of one + * connection, and keep 24h for other TCP connections. However, full + * cone NAT may have multiple connections on one entry, so this + * optimization may not work and we only use one expiration time. + */ + + return TICK2SEC(clock_systime_ticks()) + + CONFIG_NET_NAT_TCP_EXPIRE_SEC; +#endif + +#ifdef CONFIG_NET_UDP + case IP_PROTO_UDP: + return TICK2SEC(clock_systime_ticks()) + + CONFIG_NET_NAT_UDP_EXPIRE_SEC; +#endif + +#ifdef CONFIG_NET_ICMP + case IP_PROTO_ICMP: + return TICK2SEC(clock_systime_ticks()) + + CONFIG_NET_NAT_ICMP_EXPIRE_SEC; +#endif + + default: + nwarn("WARNING: Unsupported protocol %" PRIu8 "\n", protocol); + return 0; + } +} + +#endif /* CONFIG_NET_NAT */ diff --git a/net/nat/nat.h b/net/nat/nat.h index 6273ecc131..c5921c77db 100644 --- a/net/nat/nat.h +++ b/net/nat/nat.h @@ -36,7 +36,33 @@ #include <nuttx/net/ip.h> #include <nuttx/net/netdev.h> -#if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4) +#ifdef CONFIG_NET_NAT + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Adjust checksums in headers. */ + +#define nat_chksum_adjust(chksum,optr,nptr,len) \ + net_chksum_adjust((FAR uint16_t *)(chksum), (FAR uint16_t *)(optr), len, \ + (FAR uint16_t *)(nptr), len) + +/* Getting IP & Port to manipulate from L3/L4 header. */ + +#define MANIP_IPADDR(iphdr,manip_type) \ + ((manip_type) == NAT_MANIP_SRC ? (iphdr)->srcipaddr : (iphdr)->destipaddr) + +#define MANIP_PORT(l4hdr,manip_type) \ + ((manip_type) == NAT_MANIP_SRC ? &(l4hdr)->srcport : &(l4hdr)->destport) + +/* Getting peer IP & Port (just other than MANIP) */ + +#define PEER_IPADDR(iphdr,manip_type) \ + ((manip_type) != NAT_MANIP_SRC ? (iphdr)->srcipaddr : (iphdr)->destipaddr) + +#define PEER_PORT(l4hdr,manip_type) \ + ((manip_type) != NAT_MANIP_SRC ? &(l4hdr)->srcport : &(l4hdr)->destport) /**************************************************************************** * Public Types @@ -89,7 +115,7 @@ enum nat_manip_type_e ****************************************************************************/ /**************************************************************************** - * Name: ipv4_nat_enable + * Name: nat_enable * * Description: * Enable NAT function on a network device. @@ -103,10 +129,10 @@ enum nat_manip_type_e * ****************************************************************************/ -int ipv4_nat_enable(FAR struct net_driver_s *dev); +int nat_enable(FAR struct net_driver_s *dev); /**************************************************************************** - * Name: ipv4_nat_disable + * Name: nat_disable * * Description: * Disable NAT function on a network device. @@ -120,7 +146,7 @@ int ipv4_nat_enable(FAR struct net_driver_s *dev); * ****************************************************************************/ -int ipv4_nat_disable(FAR struct net_driver_s *dev); +int nat_disable(FAR struct net_driver_s *dev); /**************************************************************************** * Name: ipv4_nat_inbound @@ -139,8 +165,10 @@ int ipv4_nat_disable(FAR struct net_driver_s *dev); * ****************************************************************************/ +#ifdef CONFIG_NET_IPv4 int ipv4_nat_inbound(FAR struct net_driver_s *dev, FAR struct ipv4_hdr_s *ipv4); +#endif /**************************************************************************** * Name: ipv4_nat_outbound @@ -161,17 +189,20 @@ int ipv4_nat_inbound(FAR struct net_driver_s *dev, * ****************************************************************************/ +#ifdef CONFIG_NET_IPv4 int ipv4_nat_outbound(FAR struct net_driver_s *dev, FAR struct ipv4_hdr_s *ipv4, enum nat_manip_type_e manip_type); +#endif /**************************************************************************** - * Name: ipv4_nat_port_inuse + * Name: nat_port_inuse * * Description: * Check whether a port is currently used by NAT. * * Input Parameters: + * domain - The domain of the packet. * protocol - The L4 protocol of the packet. * ip - The IP bind with the port (in network byte order). * port - The port number to check (in network byte order). @@ -181,7 +212,47 @@ int ipv4_nat_outbound(FAR struct net_driver_s *dev, * ****************************************************************************/ -bool ipv4_nat_port_inuse(uint8_t protocol, in_addr_t ip, uint16_t port); +bool nat_port_inuse(uint8_t domain, uint8_t protocol, + FAR const union ip_addr_u *ip, uint16_t port); + +/**************************************************************************** + * Name: nat_port_select + * + * Description: + * Select an available port number for TCP/UDP protocol, or id for ICMP. + * + * Input Parameters: + * dev - The device on which the packet will be sent. + * domain - The domain of the packet. + * protocol - The L4 protocol of the packet. + * external_ip - The external IP bind with the port. + * local_port - The local port of the packet, as reference. + * + * Returned Value: + * External port number on success; 0 on failure + * + ****************************************************************************/ + +uint16_t nat_port_select(FAR struct net_driver_s *dev, + uint8_t domain, uint8_t protocol, + FAR const union ip_addr_u *external_ip, + uint16_t local_port); + +/**************************************************************************** + * Name: nat_expire_time + * + * Description: + * Get the expiration time of a specific protocol. + * + * Input Parameters: + * protocol - The L4 protocol of the packet. + * + * Returned Value: + * The expiration time of the protocol. + * + ****************************************************************************/ + +uint32_t nat_expire_time(uint8_t protocol); /**************************************************************************** * Name: ipv4_nat_entry_clear @@ -198,7 +269,9 @@ bool ipv4_nat_port_inuse(uint8_t protocol, in_addr_t ip, uint16_t port); * ****************************************************************************/ +#ifdef CONFIG_NET_IPv4 void ipv4_nat_entry_clear(FAR struct net_driver_s *dev); +#endif /**************************************************************************** * Name: ipv4_nat_inbound_entry_find @@ -219,10 +292,12 @@ void ipv4_nat_entry_clear(FAR struct net_driver_s *dev); * ****************************************************************************/ +#ifdef CONFIG_NET_IPv4 FAR struct ipv4_nat_entry * ipv4_nat_inbound_entry_find(uint8_t protocol, in_addr_t external_ip, uint16_t external_port, in_addr_t peer_ip, uint16_t peer_port, bool refresh); +#endif /**************************************************************************** * Name: ipv4_nat_outbound_entry_find @@ -245,11 +320,13 @@ ipv4_nat_inbound_entry_find(uint8_t protocol, in_addr_t external_ip, * ****************************************************************************/ +#ifdef CONFIG_NET_IPv4 FAR struct ipv4_nat_entry * ipv4_nat_outbound_entry_find(FAR struct net_driver_s *dev, uint8_t protocol, in_addr_t local_ip, uint16_t local_port, in_addr_t peer_ip, uint16_t peer_port, bool try_create); +#endif -#endif /* CONFIG_NET_NAT && CONFIG_NET_IPv4 */ +#endif /* CONFIG_NET_NAT */ #endif /* __NET_NAT_NAT_H */ diff --git a/net/netfilter/ipt_nat.c b/net/netfilter/ipt_nat.c index 914845fff4..682f3018ce 100644 --- a/net/netfilter/ipt_nat.c +++ b/net/netfilter/ipt_nat.c @@ -60,12 +60,12 @@ static int adjust_nat(FAR struct net_driver_s *dev, FAR void *arg) if (strcmp(target->u.user.name, XT_MASQUERADE_TARGET) == 0 && strcmp(dev->d_ifname, entry->ip.outiface) == 0) { - ipv4_nat_enable(dev); + nat_enable(dev); return 0; } } - ipv4_nat_disable(dev); + nat_disable(dev); return 0; } diff --git a/net/tcp/tcp_conn.c b/net/tcp/tcp_conn.c index 4d7fbf98a3..1deac8d001 100644 --- a/net/tcp/tcp_conn.c +++ b/net/tcp/tcp_conn.c @@ -617,9 +617,8 @@ int tcp_selectport(uint8_t domain, portno = HTONS(g_last_tcp_port); } while (tcp_listener(domain, ipaddr, portno) -#if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4) - || (domain == PF_INET && - ipv4_nat_port_inuse(IP_PROTO_TCP, ipaddr->ipv4, portno)) +#ifdef CONFIG_NET_NAT + || nat_port_inuse(domain, IP_PROTO_TCP, ipaddr, portno) #endif ); } @@ -630,9 +629,8 @@ int tcp_selectport(uint8_t domain, */ if (tcp_listener(domain, ipaddr, portno) -#if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4) - || (domain == PF_INET && - ipv4_nat_port_inuse(IP_PROTO_TCP, ipaddr->ipv4, portno)) +#ifdef CONFIG_NET_NAT + || nat_port_inuse(domain, IP_PROTO_TCP, ipaddr, portno) #endif ) { diff --git a/net/udp/udp_conn.c b/net/udp/udp_conn.c index 1e9b09ab8d..31da06e12b 100644 --- a/net/udp/udp_conn.c +++ b/net/udp/udp_conn.c @@ -567,10 +567,9 @@ uint16_t udp_select_port(uint8_t domain, FAR union ip_binding_u *u) } } while (udp_find_conn(domain, u, HTONS(g_last_udp_port), 0) != NULL -#if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4) - || (domain == PF_INET && - ipv4_nat_port_inuse(IP_PROTO_UDP, u->ipv4.laddr, - HTONS(g_last_udp_port))) +#ifdef CONFIG_NET_NAT + || nat_port_inuse(domain, IP_PROTO_UDP, (FAR union ip_addr_u *)u, + HTONS(g_last_udp_port)) #endif ); @@ -939,10 +938,9 @@ int udp_bind(FAR struct udp_conn_s *conn, FAR const struct sockaddr *addr) 0 #endif ) == NULL -#if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4) - && !(conn->domain == PF_INET && - ipv4_nat_port_inuse(IP_PROTO_UDP, conn->u.ipv4.laddr, - portno)) +#ifdef CONFIG_NET_NAT + && !nat_port_inuse(conn->domain, IP_PROTO_UDP, + (FAR union ip_addr_u *)&conn->u, portno) #endif ) {
