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 <wengzhe@xiaomi.com>
This commit is contained in:
Zhe Weng 2024-03-18 18:41:38 +08:00 committed by Xiang Xiao
parent 412d2ce113
commit f2ff5cee03
10 changed files with 462 additions and 338 deletions

View file

@ -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]);
...
}

View file

@ -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()

View file

@ -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

View file

@ -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 */

View file

@ -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");

341
net/nat/nat.c Normal file
View file

@ -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 */

View file

@ -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 */

View file

@ -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;
}

View file

@ -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
)
{

View file

@ -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
)
{