You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2022/11/11 06:37:02 UTC
[incubator-nuttx] 01/07: net: add basic NAT workflow
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/incubator-nuttx.git
commit b595430578e252a5f7950c319cae32293f57d102
Author: Zhe Weng <we...@xiaomi.com>
AuthorDate: Mon Oct 17 15:13:34 2022 +0800
net: add basic NAT workflow
Add basic functions for NAT (NAPT), remaining some logic unimplemented (UDP, ICMP, port assignment, etc). NAT for TCP can work now (unless port conflicts).
Outbound: LAN -> Forward -> NAT(only if targeting at WAN) -> WAN
Inbound: WAN -> NAT(only from WAN, change dest) -> Forward -> LAN
Signed-off-by: Zhe Weng <we...@xiaomi.com>
---
include/net/if.h | 4 +
net/Kconfig | 1 +
net/Makefile | 1 +
net/devif/ipv4_input.c | 11 ++
net/ipforward/ipv4_forward.c | 13 ++
net/nat/Kconfig | 11 ++
net/nat/Make.defs | 34 +++++
net/nat/ipv4_nat.c | 324 +++++++++++++++++++++++++++++++++++++++++++
net/nat/ipv4_nat_entry.c | 203 +++++++++++++++++++++++++++
net/nat/nat.h | 199 ++++++++++++++++++++++++++
10 files changed, 801 insertions(+)
diff --git a/include/net/if.h b/include/net/if.h
index aa6adcf3a6..299bfdc763 100644
--- a/include/net/if.h
+++ b/include/net/if.h
@@ -53,6 +53,7 @@
#define IFF_LOOPBACK (1 << 5) /* Is a loopback net */
#define IFF_POINTOPOINT (1 << 6) /* Is point-to-point link */
#define IFF_NOARP (1 << 7) /* ARP is not required for this packet */
+#define IFF_NAT (1 << 8) /* NAT is enabled for this interface */
#define IFF_MULTICAST (1 << 12) /* Supports multicast. */
#define IFF_BROADCAST (1 << 13) /* Broadcast address valid. */
@@ -61,6 +62,7 @@
#define IFF_SET_UP(f) do { (f) |= IFF_UP; } while (0)
#define IFF_SET_RUNNING(f) do { (f) |= IFF_RUNNING; } while (0)
#define IFF_SET_NOARP(f) do { (f) |= IFF_NOARP; } while (0)
+#define IFF_SET_NAT(f) do { (f) |= IFF_NAT; } while (0)
#define IFF_SET_LOOPBACK(f) do { (f) |= IFF_LOOPBACK; } while (0)
#define IFF_SET_POINTOPOINT(f) do { (f) |= IFF_POINTOPOINT; } while (0)
#define IFF_SET_MULTICAST(f) do { (f) |= IFF_MULTICAST; } while (0)
@@ -69,6 +71,7 @@
#define IFF_CLR_UP(f) do { (f) &= ~IFF_UP; } while (0)
#define IFF_CLR_RUNNING(f) do { (f) &= ~IFF_RUNNING; } while (0)
#define IFF_CLR_NOARP(f) do { (f) &= ~IFF_NOARP; } while (0)
+#define IFF_CLR_NAT(f) do { (f) &= ~IFF_NAT; } while (0)
#define IFF_CLR_LOOPBACK(f) do { (f) &= ~IFF_LOOPBACK; } while (0)
#define IFF_CLR_POINTOPOINT(f) do { (f) &= ~IFF_POINTOPOINT; } while (0)
#define IFF_CLR_MULTICAST(f) do { (f) &= ~IFF_MULTICAST; } while (0)
@@ -77,6 +80,7 @@
#define IFF_IS_UP(f) (((f) & IFF_UP) != 0)
#define IFF_IS_RUNNING(f) (((f) & IFF_RUNNING) != 0)
#define IFF_IS_NOARP(f) (((f) & IFF_NOARP) != 0)
+#define IFF_IS_NAT(f) (((f) & IFF_NAT) != 0)
#define IFF_IS_LOOPBACK(f) (((f) & IFF_LOOPBACK) != 0)
#define IFF_IS_POINTOPOINT(f) (((f) & IFF_POINTOPOINT) != 0)
#define IFF_IS_MULTICAST(f) (((f) & IFF_MULTICAST) != 0)
diff --git a/net/Kconfig b/net/Kconfig
index 8dcd20d18a..c38539fcbf 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -320,6 +320,7 @@ menuconfig NET_6LOWPAN
source "net/sixlowpan/Kconfig"
source "net/ipforward/Kconfig"
+source "net/nat/Kconfig"
endmenu # Internet Protocol Selection
diff --git a/net/Makefile b/net/Makefile
index b9b596a80a..e9e80904db 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -47,6 +47,7 @@ include bluetooth/Make.defs
include ieee802154/Make.defs
include devif/Make.defs
include ipforward/Make.defs
+include nat/Make.defs
include route/Make.defs
include procfs/Make.defs
include usrsock/Make.defs
diff --git a/net/devif/ipv4_input.c b/net/devif/ipv4_input.c
index 338d18f365..d492fff50d 100644
--- a/net/devif/ipv4_input.c
+++ b/net/devif/ipv4_input.c
@@ -103,6 +103,7 @@
#include "ipforward/ipforward.h"
#include "devif/devif.h"
+#include "nat/nat.h"
/****************************************************************************
* Private Data
@@ -206,6 +207,16 @@ int ipv4_input(FAR struct net_driver_s *dev)
goto drop;
}
+#ifdef CONFIG_NET_NAT
+ /* Try NAT inbound, rule matching will be performed in NAT module. */
+
+ if (ipv4_nat_inbound(dev, ipv4) < 0)
+ {
+ nwarn("WARNING: Performing NAT inbound failed!\n");
+ goto drop;
+ }
+#endif
+
/* Get the destination IP address in a friendlier form */
destipaddr = net_ip4addr_conv32(ipv4->destipaddr);
diff --git a/net/ipforward/ipv4_forward.c b/net/ipforward/ipv4_forward.c
index c0c549dc83..8da46a528c 100644
--- a/net/ipforward/ipv4_forward.c
+++ b/net/ipforward/ipv4_forward.c
@@ -38,6 +38,7 @@
#include "utils/utils.h"
#include "sixlowpan/sixlowpan.h"
#include "ipforward/ipforward.h"
+#include "nat/nat.h"
#include "devif/devif.h"
#if defined(CONFIG_NET_IPFORWARD) && defined(CONFIG_NET_IPv4)
@@ -312,6 +313,18 @@ static int ipv4_dev_forward(FAR struct net_driver_s *dev,
goto errout_with_iobchain;
}
+#ifdef CONFIG_NET_NAT
+ /* Try NAT outbound, rule matching will be performed in NAT module. */
+
+ ret = ipv4_nat_outbound(fwd->f_dev,
+ (FAR struct ipv4_hdr_s *)fwd->f_iob->io_data);
+ if (ret < 0)
+ {
+ nwarn("WARNING: Performing NAT outbound failed, dropping!\n");
+ goto errout_with_iobchain;
+ }
+#endif
+
/* Then set up to forward the packet according to the protocol. */
ret = ipfwd_forward(fwd);
diff --git a/net/nat/Kconfig b/net/nat/Kconfig
new file mode 100644
index 0000000000..f50d237695
--- /dev/null
+++ b/net/nat/Kconfig
@@ -0,0 +1,11 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+config NET_NAT
+ bool "Network Address Translation (NAT)"
+ default n
+ depends on NET_IPFORWARD
+ ---help---
+ Enable or disable Network Address Translation (NAT) function.
diff --git a/net/nat/Make.defs b/net/nat/Make.defs
new file mode 100644
index 0000000000..43d185837e
--- /dev/null
+++ b/net/nat/Make.defs
@@ -0,0 +1,34 @@
+############################################################################
+# net/nat/Make.defs
+#
+# 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.
+#
+############################################################################
+
+# NAT source files
+
+ifeq ($(CONFIG_NET_NAT),y)
+
+ifeq ($(CONFIG_NET_IPv4),y)
+NET_CSRCS += ipv4_nat.c ipv4_nat_entry.c
+endif
+
+# Include NAT build support
+
+DEPPATH += --dep-path nat
+VPATH += :nat
+
+endif
diff --git a/net/nat/ipv4_nat.c b/net/nat/ipv4_nat.c
new file mode 100644
index 0000000000..f1d44155fc
--- /dev/null
+++ b/net/nat/ipv4_nat.c
@@ -0,0 +1,324 @@
+/****************************************************************************
+ * net/nat/ipv4_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 <errno.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <nuttx/net/tcp.h>
+
+#include "nat/nat.h"
+#include "utils/utils.h"
+
+#if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Adjust checksums in headers. */
+
+#define chksum_adjust(chksum,old_data,new_data) \
+ net_chksum_adjust((FAR uint16_t *)&(chksum), \
+ (FAR uint16_t *)&(old_data), sizeof(old_data), \
+ (FAR uint16_t *)&(new_data), sizeof(new_data))
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipv4_nat_inbound_tcp
+ *
+ * Description:
+ * Check if a received TCP packet belongs to a NAT entry. If so, translate
+ * it.
+ *
+ * Input Parameters:
+ * ipv4 - Points to the IPv4 header with dev->d_buf.
+ *
+ * Returned Value:
+ * Zero is returned if NAT is successfully applied, or is not enabled for
+ * this packet;
+ * A negated errno value is returned if error occured.
+ *
+ * Assumptions:
+ * Packet is received on NAT device and is targeting at the address
+ * assigned to the device.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_TCP
+static int ipv4_nat_inbound_tcp(FAR struct ipv4_hdr_s *ipv4)
+{
+ uint16_t iphdrlen = (ipv4->vhl & IPv4_HLMASK) << 2;
+ FAR struct tcp_hdr_s *tcp =
+ (FAR struct tcp_hdr_s *)((FAR uint8_t *)ipv4 + iphdrlen);
+ FAR struct ipv4_nat_entry *entry =
+ ipv4_nat_inbound_entry_find(IP_PROTO_TCP, tcp->destport);
+ if (!entry)
+ {
+ /* Inbound without entry is OK (e.g. towards NuttX itself), skip NAT. */
+
+ return OK;
+ }
+
+ /* Modify port and checksum. */
+
+ chksum_adjust(tcp->tcpchksum, tcp->destport, entry->local_port);
+ tcp->destport = entry->local_port;
+
+ /* Modify address and checksum. */
+
+ chksum_adjust(tcp->tcpchksum, ipv4->destipaddr, entry->local_ip);
+ chksum_adjust(ipv4->ipchksum, ipv4->destipaddr, entry->local_ip);
+ net_ipv4addr_hdrcopy(ipv4->destipaddr, &entry->local_ip);
+
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: ipv4_nat_outbound_tcp
+ *
+ * Description:
+ * Check if we want to perform NAT with this outbound TCP packet before
+ * sending it. If so, translate it.
+ *
+ * Input Parameters:
+ * dev - The device to sent the packet.
+ * ipv4 - Points to the IPv4 header to be filled into dev->d_buf later.
+ *
+ * Returned Value:
+ * Zero is returned if NAT is successfully applied, or is not enabled for
+ * this packet;
+ * A negated errno value is returned if error occured.
+ *
+ * Assumptions:
+ * Packet will be sent on NAT device.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_TCP
+static int ipv4_nat_outbound_tcp(FAR struct net_driver_s *dev,
+ FAR struct ipv4_hdr_s *ipv4)
+{
+ uint16_t iphdrlen = (ipv4->vhl & IPv4_HLMASK) << 2;
+ FAR struct tcp_hdr_s *tcp =
+ (FAR struct tcp_hdr_s *)((FAR uint8_t *)ipv4 + iphdrlen);
+ FAR struct ipv4_nat_entry *entry = ipv4_nat_outbound_entry_find(
+ IP_PROTO_TCP, net_ip4addr_conv32(ipv4->srcipaddr), tcp->srcport);
+ if (!entry)
+ {
+ /* Outbound entry creation failed, should have corresponding entry. */
+
+ return -ENOMEM;
+ }
+
+ /* Modify port and checksum. */
+
+ chksum_adjust(tcp->tcpchksum, tcp->srcport, entry->external_port);
+ tcp->srcport = entry->external_port;
+
+ /* Modify address and checksum. */
+
+ chksum_adjust(tcp->tcpchksum, ipv4->srcipaddr, dev->d_ipaddr);
+ chksum_adjust(ipv4->ipchksum, ipv4->srcipaddr, dev->d_ipaddr);
+ net_ipv4addr_hdrcopy(ipv4->srcipaddr, &dev->d_ipaddr);
+
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * 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.
+ *
+ * Assumptions:
+ * NAT will only be enabled on at most one device.
+ *
+ * Limitations:
+ * External ports are not isolated between devices yet, so if NAT is
+ * enabled on more than one device, an external port used on one device
+ * will also be used by same local ip:port on another device.
+ *
+ * TODO:
+ * Support multiple NAT devices with isolated external port mapping.
+ ****************************************************************************/
+
+int ipv4_nat_enable(FAR struct net_driver_s *dev)
+{
+ if (IFF_IS_NAT(dev->d_flags))
+ {
+ nwarn("WARNING: NAT was already enabled for %s!\n", dev->d_ifname);
+ return -EEXIST;
+ }
+
+ IFF_SET_NAT(dev->d_flags);
+ 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)
+{
+ if (!IFF_IS_NAT(dev->d_flags))
+ {
+ nwarn("WARNING: NAT was not enabled for %s!\n", dev->d_ifname);
+ return -ENODEV;
+ }
+
+ /* TODO: Clear entries related to dev. */
+
+ IFF_CLR_NAT(dev->d_flags);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: ipv4_nat_inbound
+ *
+ * Description:
+ * Check if a received packet belongs to a NAT entry. If so, translate it.
+ *
+ * Input Parameters:
+ * dev - The device on which the packet is received.
+ * ipv4 - Points to the IPv4 header with dev->d_buf.
+ *
+ * Returned Value:
+ * Zero is returned if NAT is successfully applied, or is not enabled for
+ * this packet;
+ * A negated errno value is returned if error occured.
+ *
+ ****************************************************************************/
+
+int ipv4_nat_inbound(FAR struct net_driver_s *dev,
+ FAR struct ipv4_hdr_s *ipv4)
+{
+ /* We only process packets from NAT device and targeting at the address
+ * assigned to the device.
+ */
+
+ if (IFF_IS_NAT(dev->d_flags) &&
+ net_ipv4addr_hdrcmp(ipv4->destipaddr, &dev->d_ipaddr))
+ {
+ switch (ipv4->proto)
+ {
+#ifdef CONFIG_NET_TCP
+ case IP_PROTO_TCP:
+ return ipv4_nat_inbound_tcp(ipv4);
+#endif
+
+#ifdef CONFIG_NET_UDP
+# warning Missing logic
+#endif
+
+#ifdef CONFIG_NET_ICMP
+# warning Missing logic
+#endif
+ }
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: ipv4_nat_outbound
+ *
+ * Description:
+ * Check if we want to perform NAT with this outbound packet before sending
+ * it. If so, translate it.
+ *
+ * Input Parameters:
+ * dev - The device on which the packet will be sent.
+ * ipv4 - Points to the IPv4 header to be filled into dev->d_buf later.
+ *
+ * Returned Value:
+ * Zero is returned if NAT is successfully applied, or is not enabled for
+ * this packet;
+ * A negated errno value is returned if error occured.
+ *
+ ****************************************************************************/
+
+int ipv4_nat_outbound(FAR struct net_driver_s *dev,
+ FAR struct ipv4_hdr_s *ipv4)
+{
+ /* We only process packets targeting at NAT device but not targeting at the
+ * address assigned to the device.
+ */
+
+ if (IFF_IS_NAT(dev->d_flags) &&
+ !net_ipv4addr_hdrcmp(ipv4->destipaddr, &dev->d_ipaddr))
+ {
+ /* TODO: Skip broadcast? */
+
+ switch (ipv4->proto)
+ {
+#ifdef CONFIG_NET_TCP
+ case IP_PROTO_TCP:
+ return ipv4_nat_outbound_tcp(dev, ipv4);
+#endif
+
+#ifdef CONFIG_NET_UDP
+# warning Missing logic
+#endif
+
+#ifdef CONFIG_NET_ICMP
+# warning Missing logic
+#endif
+ }
+ }
+
+ return OK;
+}
+
+#endif /* CONFIG_NET_NAT && CONFIG_NET_IPv4 */
diff --git a/net/nat/ipv4_nat_entry.c b/net/nat/ipv4_nat_entry.c
new file mode 100644
index 0000000000..e0f7e92513
--- /dev/null
+++ b/net/nat/ipv4_nat_entry.c
@@ -0,0 +1,203 @@
+/****************************************************************************
+ * net/nat/ipv4_nat_entry.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 <nuttx/kmalloc.h>
+#include <nuttx/queue.h>
+
+#include "nat/nat.h"
+
+#if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4)
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static sq_queue_t g_entries;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipv4_nat_select_port
+ *
+ * Description:
+ * Select an available port number for TCP/UDP protocol, or id for ICMP.
+ *
+ * Input Parameters:
+ * 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(uint8_t protocol, uint16_t local_port)
+{
+ /* TODO: Implement this, need to consider local ports and nat ports.
+ * TODO: Shall we let the chosen port same as local_port if possible?
+ * TODO: Also need to modify local port number assignment.
+ */
+
+# warning Missing logic
+
+ return local_port;
+}
+
+/****************************************************************************
+ * Name: ipv4_nat_entry_create
+ *
+ * Description:
+ * Create a NAT entry and insert into entry list.
+ *
+ * Input Parameters:
+ * protocol - The L4 protocol of the packet.
+ * external_port - The external port of the packet.
+ * local_ip - The local ip of the packet.
+ * local_port - The local port of the packet.
+ *
+ * Returned Value:
+ * Pointer to entry on success; null on failure
+ *
+ ****************************************************************************/
+
+static FAR struct ipv4_nat_entry *
+ipv4_nat_entry_create(uint8_t protocol, uint16_t external_port,
+ in_addr_t local_ip, uint16_t local_port)
+{
+ FAR struct ipv4_nat_entry *entry =
+ (FAR struct ipv4_nat_entry *)kmm_malloc(sizeof(struct ipv4_nat_entry));
+ if (entry == NULL)
+ {
+ nwarn("WARNING: Failed to allocate IPv4 NAT entry\n");
+ return NULL;
+ }
+
+ entry->protocol = protocol;
+ entry->external_port = external_port;
+ entry->local_ip = local_ip;
+ entry->local_port = local_port;
+
+ sq_addfirst((FAR sq_entry_t *)entry, &g_entries);
+ return entry;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipv4_nat_inbound_entry_find
+ *
+ * Description:
+ * Find the inbound entry in NAT entry list.
+ *
+ * Input Parameters:
+ * protocol - The L4 protocol of the packet.
+ * external_port - The external port of the packet.
+ *
+ * Returned Value:
+ * Pointer to entry on success; null on failure
+ *
+ ****************************************************************************/
+
+FAR struct ipv4_nat_entry *
+ipv4_nat_inbound_entry_find(uint8_t protocol, uint16_t external_port)
+{
+ FAR sq_entry_t *p;
+ sq_for_every(&g_entries, p)
+ {
+ FAR struct ipv4_nat_entry *entry = (FAR struct ipv4_nat_entry *)p;
+ if (entry->protocol == protocol &&
+ entry->external_port == external_port)
+ {
+ /* TODO: Use hash table, or move recent node to head. */
+
+ return entry;
+ }
+ }
+
+ nwarn("WARNING: Failed to find IPv4 inbound NAT entry for "
+ "proto=%d, external_port=%d\n", protocol, external_port);
+ return NULL;
+}
+
+/****************************************************************************
+ * Name: ipv4_nat_outbound_entry_find
+ *
+ * Description:
+ * Find the outbound entry in NAT entry list. Create one if corresponding
+ * entry does not exist.
+ *
+ * Input Parameters:
+ * protocol - The L4 protocol of the packet.
+ * local_ip - The local ip of the packet.
+ * local_port - The local port of the packet.
+ *
+ * Returned Value:
+ * Pointer to entry on success; null on failure
+ *
+ ****************************************************************************/
+
+FAR struct ipv4_nat_entry *
+ipv4_nat_outbound_entry_find(uint8_t protocol, in_addr_t local_ip,
+ uint16_t local_port)
+{
+ FAR sq_entry_t *p;
+ sq_for_every(&g_entries, p)
+ {
+ FAR struct ipv4_nat_entry *entry = (FAR struct ipv4_nat_entry *)p;
+ if (entry->protocol == protocol &&
+ net_ipv4addr_cmp(entry->local_ip, local_ip) &&
+ entry->local_port == local_port)
+ {
+ /* TODO: Use hash table, or move recent node to head. */
+
+ return entry;
+ }
+ }
+
+ /* Failed to find the entry, create one. */
+
+ ninfo("INFO: Failed to find IPv4 outbound NAT entry for "
+ "proto=%d, local=%x:%d, try creating one.\n",
+ protocol, local_ip, local_port);
+
+ uint16_t external_port = ipv4_nat_select_port(protocol, local_port);
+ if (!external_port)
+ {
+ nwarn("WARNING: Failed to find an available port!\n");
+ return NULL;
+ }
+
+ return ipv4_nat_entry_create(protocol, external_port, local_ip,
+ local_port);
+}
+
+#endif /* CONFIG_NET_NAT && CONFIG_NET_IPv4 */
diff --git a/net/nat/nat.h b/net/nat/nat.h
new file mode 100644
index 0000000000..c5b13e5a3e
--- /dev/null
+++ b/net/nat/nat.h
@@ -0,0 +1,199 @@
+/****************************************************************************
+ * net/nat/nat.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __NET_NAT_NAT_H
+#define __NET_NAT_NAT_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+
+#include <netinet/in.h>
+
+#include <nuttx/net/ip.h>
+#include <nuttx/net/netdev.h>
+
+#if defined(CONFIG_NET_NAT) && defined(CONFIG_NET_IPv4)
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+struct ipv4_nat_entry
+{
+ /* Support for single-linked lists.
+ *
+ * TODO: Implement a general hash table, and use it to optimize performance
+ * here.
+ */
+
+ FAR struct ipv4_nat_entry *flink;
+
+ /* Local Network External Network
+ * |----------------|
+ * <local IP, | | <external IP, <peer IP,
+ * -----------| |-----------------------------
+ * local port> | | external port> peer port>
+ * |----------------|
+ *
+ * Full cone NAT on single WAN only need to save local ip:port and external
+ * port. For ICMP, save id in port field.
+ */
+
+ in_addr_t local_ip; /* IP address of the local (private) host. */
+ uint16_t local_port; /* Port of the local (private) host. */
+ uint16_t external_port; /* The external port of local (private) host. */
+ uint8_t protocol; /* L4 protocol (TCP, UDP etc). */
+
+ /* TODO: Timeout check and remove outdated entry. */
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * 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.
+ *
+ * Assumptions:
+ * NAT will only be enabled on at most one device.
+ *
+ * Limitations:
+ * External ports are not isolated between devices yet, so if NAT is
+ * enabled on more than one device, an external port used on one device
+ * will also be used by same local ip:port on another device.
+ *
+ ****************************************************************************/
+
+int ipv4_nat_enable(FAR struct net_driver_s *dev);
+
+/****************************************************************************
+ * 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);
+
+/****************************************************************************
+ * Name: ipv4_nat_inbound
+ *
+ * Description:
+ * Check if a received packet belongs to a NAT entry. If so, translate it.
+ *
+ * Input Parameters:
+ * dev - The device on which the packet is received.
+ * ipv4 - Points to the IPv4 header with dev->d_buf.
+ *
+ * Returned Value:
+ * Zero is returned if NAT is successfully applied, or is not enabled for
+ * this packet;
+ * A negated errno value is returned if error occured.
+ *
+ ****************************************************************************/
+
+int ipv4_nat_inbound(FAR struct net_driver_s *dev,
+ FAR struct ipv4_hdr_s *ipv4);
+
+/****************************************************************************
+ * Name: ipv4_nat_outbound
+ *
+ * Description:
+ * Check if we want to perform NAT with this outbound packet before sending
+ * it. If so, translate it.
+ *
+ * Input Parameters:
+ * dev - The device on which the packet will be sent.
+ * ipv4 - Points to the IPv4 header to be filled into dev->d_buf later.
+ *
+ * Returned Value:
+ * Zero is returned if NAT is successfully applied, or is not enabled for
+ * this packet;
+ * A negated errno value is returned if error occured.
+ *
+ ****************************************************************************/
+
+int ipv4_nat_outbound(FAR struct net_driver_s *dev,
+ FAR struct ipv4_hdr_s *ipv4);
+
+/****************************************************************************
+ * Name: ipv4_nat_inbound_entry_find
+ *
+ * Description:
+ * Find the inbound entry in NAT entry list.
+ *
+ * Input Parameters:
+ * protocol - The L4 protocol of the packet.
+ * external_port - The external port of the packet.
+ *
+ * Returned Value:
+ * Pointer to entry on success; null on failure
+ *
+ ****************************************************************************/
+
+FAR struct ipv4_nat_entry *
+ipv4_nat_inbound_entry_find(uint8_t protocol, uint16_t external_port);
+
+/****************************************************************************
+ * Name: ipv4_nat_outbound_entry_find
+ *
+ * Description:
+ * Find the outbound entry in NAT entry list. Create one if corresponding
+ * entry does not exist.
+ *
+ * Input Parameters:
+ * protocol - The L4 protocol of the packet.
+ * local_ip - The local ip of the packet.
+ * local_port - The local port of the packet.
+ *
+ * Returned Value:
+ * Pointer to entry on success; null on failure
+ *
+ ****************************************************************************/
+
+FAR struct ipv4_nat_entry *
+ipv4_nat_outbound_entry_find(uint8_t protocol, in_addr_t local_ip,
+ uint16_t local_port);
+
+#endif /* CONFIG_NET_NAT && CONFIG_NET_IPv4 */
+#endif /* __NET_NAT_NAT_H */