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:
parent
412d2ce113
commit
f2ff5cee03
10 changed files with 462 additions and 338 deletions
|
|
@ -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]);
|
||||
...
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
341
net/nat/nat.c
Normal 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 */
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue