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/12/28 14:41:00 UTC

[nuttx] branch master updated: net: Add set/getsockopt options compatible with iptables.

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new cbe4cb2056 net: Add set/getsockopt options compatible with iptables.
cbe4cb2056 is described below

commit cbe4cb2056db5a34bdbc13fe756aaca9c60254c6
Author: Zhe Weng <we...@xiaomi.com>
AuthorDate: Tue Dec 13 16:08:24 2022 +0800

    net: Add set/getsockopt options compatible with iptables.
    
    Signed-off-by: Zhe Weng <we...@xiaomi.com>
---
 include/nuttx/net/netfilter/ip_tables.h |  12 +
 include/nuttx/net/netfilter/nf_nat.h    |   6 +
 net/Kconfig                             |   1 +
 net/Makefile                            |   1 +
 net/inet/Make.defs                      |   2 +-
 net/inet/inet.h                         |  32 +++
 net/inet/inet_sockif.c                  |  24 +-
 net/inet/ipv4_getsockopt.c              |  97 +++++++
 net/inet/ipv4_setsockopt.c              |   7 +
 net/netfilter/Kconfig                   |  13 +
 net/{inet => netfilter}/Make.defs       |  28 +-
 net/netfilter/ipt_nat.c                 | 126 +++++++++
 net/netfilter/ipt_sockopt.c             | 440 ++++++++++++++++++++++++++++++++
 net/netfilter/iptables.h                | 109 ++++++++
 14 files changed, 869 insertions(+), 29 deletions(-)

diff --git a/include/nuttx/net/netfilter/ip_tables.h b/include/nuttx/net/netfilter/ip_tables.h
index 4b7bb610e6..0ac092fce0 100644
--- a/include/nuttx/net/netfilter/ip_tables.h
+++ b/include/nuttx/net/netfilter/ip_tables.h
@@ -60,6 +60,18 @@
 #define IPT_TARGET(e) \
   ((FAR struct xt_entry_target *)((FAR uint8_t *)(e) + (e)->target_offset))
 
+/* Auto fill common fields of entry and target. */
+
+#define IPT_FILL_ENTRY(e, target_name) \
+  do \
+    { \
+      (e)->entry.target_offset = sizeof((e)->entry); \
+      (e)->entry.next_offset = sizeof(*(e)); \
+      (e)->target.target.u.target_size = sizeof(*(e)) - sizeof((e)->entry); \
+      strcpy((e)->target.target.u.user.name, (target_name)); \
+    } \
+  while(0)
+
 /****************************************************************************
  * Public Types
  ****************************************************************************/
diff --git a/include/nuttx/net/netfilter/nf_nat.h b/include/nuttx/net/netfilter/nf_nat.h
index 9d59d273bb..8844885d76 100644
--- a/include/nuttx/net/netfilter/nf_nat.h
+++ b/include/nuttx/net/netfilter/nf_nat.h
@@ -27,6 +27,12 @@
 
 #include <sys/types.h>
 
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define TABLE_NAME_NAT "nat"
+
 /****************************************************************************
  * Public Types
  ****************************************************************************/
diff --git a/net/Kconfig b/net/Kconfig
index 5a8f0c0e2d..53134fd980 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -330,6 +330,7 @@ menuconfig NET_6LOWPAN
 source "net/sixlowpan/Kconfig"
 source "net/ipforward/Kconfig"
 source "net/nat/Kconfig"
+source "net/netfilter/Kconfig"
 
 endmenu # Internet Protocol Selection
 
diff --git a/net/Makefile b/net/Makefile
index e9e80904db..7d81a4db4a 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -48,6 +48,7 @@ include ieee802154/Make.defs
 include devif/Make.defs
 include ipforward/Make.defs
 include nat/Make.defs
+include netfilter/Make.defs
 include route/Make.defs
 include procfs/Make.defs
 include usrsock/Make.defs
diff --git a/net/inet/Make.defs b/net/inet/Make.defs
index 0fcbf4f2bc..498d15e679 100644
--- a/net/inet/Make.defs
+++ b/net/inet/Make.defs
@@ -31,7 +31,7 @@ SOCK_CSRCS += inet_globals.c
 endif
 
 ifeq ($(CONFIG_NET_IPv4),y)
-SOCK_CSRCS += ipv4_setsockopt.c ipv4_getsockname.c ipv4_getpeername.c ipv4_build_header.c
+SOCK_CSRCS += ipv4_setsockopt.c ipv4_getsockopt.c ipv4_getsockname.c ipv4_getpeername.c ipv4_build_header.c
 endif
 
 ifeq ($(CONFIG_NET_IPv6),y)
diff --git a/net/inet/inet.h b/net/inet/inet.h
index 2eaf1d8a07..6dc2fdf4a6 100644
--- a/net/inet/inet.h
+++ b/net/inet/inet.h
@@ -161,6 +161,38 @@ int ipv6_setsockopt(FAR struct socket *psock, int option,
                     FAR const void *value, socklen_t value_len);
 #endif
 
+/****************************************************************************
+ * Name: ipv4_getsockopt
+ *
+ * Description:
+ *   ipv4_getsockopt() retrieve the value for the option specified by the
+ *   'option' argument for the socket specified by the 'psock' argument.  If
+ *   the size of the option value is greater than 'value_len', the value
+ *   stored in the object pointed to by the 'value' argument will be silently
+ *   truncated. Otherwise, the length pointed to by the 'value_len' argument
+ *   will be modified to indicate the actual length of the 'value'.
+ *
+ *   See <netinet/in.h> for the a complete list of values of IPv4 protocol
+ *   socket options.
+ *
+ * Input Parameters:
+ *   psock     Socket structure of the socket to query
+ *   option    identifies the option to get
+ *   value     Points to the argument value
+ *   value_len The length of the argument value
+ *
+ * Returned Value:
+ *   Returns zero (OK) on success.  On failure, it returns a negated errno
+ *   value to indicate the nature of the error.  See psock_getsockopt() for
+ *   the list of possible error values.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IPv4
+int ipv4_getsockopt(FAR struct socket *psock, int option,
+                    FAR void *value, FAR socklen_t *value_len);
+#endif
+
 /****************************************************************************
  * Name: ipv4_getsockname and ipv6_sockname
  *
diff --git a/net/inet/inet_sockif.c b/net/inet/inet_sockif.c
index a7b1030a80..85f12a0521 100644
--- a/net/inet/inet_sockif.c
+++ b/net/inet/inet_sockif.c
@@ -739,19 +739,23 @@ static int inet_get_socketlevel_option(FAR struct socket *psock, int option,
 static int inet_getsockopt(FAR struct socket *psock, int level, int option,
                            FAR void *value, FAR socklen_t *value_len)
 {
-  if (level == SOL_SOCKET)
+  switch (level)
     {
-      return inet_get_socketlevel_option(psock, option, value, value_len);
-    }
+      case SOL_SOCKET:
+        return inet_get_socketlevel_option(psock, option, value, value_len);
+
 #ifdef CONFIG_NET_TCPPROTO_OPTIONS
-  else if (level == IPPROTO_TCP)
-    {
-      return tcp_getsockopt(psock, option, value, value_len);
-    }
+      case IPPROTO_TCP:
+        return tcp_getsockopt(psock, option, value, value_len);
 #endif
-  else
-    {
-      return -ENOPROTOOPT;
+
+#ifdef CONFIG_NET_IPv4
+      case IPPROTO_IP:
+        return ipv4_getsockopt(psock, option, value, value_len);
+#endif
+
+      default:
+        return -ENOPROTOOPT;
     }
 }
 
diff --git a/net/inet/ipv4_getsockopt.c b/net/inet/ipv4_getsockopt.c
new file mode 100644
index 0000000000..36ef1f0708
--- /dev/null
+++ b/net/inet/ipv4_getsockopt.c
@@ -0,0 +1,97 @@
+/****************************************************************************
+ * net/inet/ipv4_getsockopt.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 <sys/types.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/net/net.h>
+
+#include <netinet/in.h>
+
+#include "netfilter/iptables.h"
+
+#ifdef CONFIG_NET_IPv4
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipv4_getsockopt
+ *
+ * Description:
+ *   ipv4_getsockopt() retrieve the value for the option specified by the
+ *   'option' argument for the socket specified by the 'psock' argument.  If
+ *   the size of the option value is greater than 'value_len', the value
+ *   stored in the object pointed to by the 'value' argument will be silently
+ *   truncated. Otherwise, the length pointed to by the 'value_len' argument
+ *   will be modified to indicate the actual length of the 'value'.
+ *
+ *   See <netinet/in.h> for the a complete list of values of IPv4 protocol
+ *   socket options.
+ *
+ * Input Parameters:
+ *   psock     Socket structure of the socket to query
+ *   option    identifies the option to get
+ *   value     Points to the argument value
+ *   value_len The length of the argument value
+ *
+ * Returned Value:
+ *   Returns zero (OK) on success.  On failure, it returns a negated errno
+ *   value to indicate the nature of the error.  See psock_getsockopt() for
+ *   the list of possible error values.
+ *
+ ****************************************************************************/
+
+int ipv4_getsockopt(FAR struct socket *psock, int option,
+                    FAR void *value, FAR socklen_t *value_len)
+{
+  int ret;
+
+  ninfo("option: %d\n", option);
+
+  net_lock();
+  switch (option)
+    {
+#ifdef CONFIG_NET_IPTABLES
+      case IPT_SO_GET_INFO:
+      case IPT_SO_GET_ENTRIES:
+        ret = ipt_getsockopt(psock, option, value, value_len);
+        break;
+#endif
+
+      default:
+        nerr("ERROR: Unrecognized IPv4 option: %d\n", option);
+        ret = -ENOPROTOOPT;
+        break;
+    }
+
+  net_unlock();
+  return ret;
+}
+
+#endif /* CONFIG_NET_IPv4 */
diff --git a/net/inet/ipv4_setsockopt.c b/net/inet/ipv4_setsockopt.c
index 9cf43b508b..2e97fbec5a 100644
--- a/net/inet/ipv4_setsockopt.c
+++ b/net/inet/ipv4_setsockopt.c
@@ -34,6 +34,7 @@
 #include <netinet/in.h>
 
 #include "netdev/netdev.h"
+#include "netfilter/iptables.h"
 #include "igmp/igmp.h"
 #include "inet/inet.h"
 #include "udp/udp.h"
@@ -261,6 +262,12 @@ int ipv4_setsockopt(FAR struct socket *psock, int option,
         break;
 #endif
 
+#ifdef CONFIG_NET_IPTABLES
+      case IPT_SO_SET_REPLACE:
+        ret = ipt_setsockopt(psock, option, value, value_len);
+        break;
+#endif
+
       default:
         nerr("ERROR: Unrecognized IPv4 option: %d\n", option);
         ret = -ENOPROTOOPT;
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
new file mode 100644
index 0000000000..c0a907f77a
--- /dev/null
+++ b/net/netfilter/Kconfig
@@ -0,0 +1,13 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+config NET_IPTABLES
+	bool "Iptables Interface"
+	default y
+	depends on NET_IPv4
+	depends on NET_SOCKOPTS
+	depends on NET_NAT  # May change dependency if we have firewall later.
+	---help---
+		Enable or disable iptables compatible interface (for NAT).
diff --git a/net/inet/Make.defs b/net/netfilter/Make.defs
similarity index 62%
copy from net/inet/Make.defs
copy to net/netfilter/Make.defs
index 0fcbf4f2bc..02d250a4b8 100644
--- a/net/inet/Make.defs
+++ b/net/netfilter/Make.defs
@@ -1,5 +1,5 @@
 ############################################################################
-# net/inet/Make.defs
+# net/netfilter/Make.defs
 #
 # Licensed to the Apache Software Foundation (ASF) under one or more
 # contributor license agreements.  See the NOTICE file distributed with
@@ -18,27 +18,19 @@
 #
 ############################################################################
 
-# PF_INET/PF_INET6 socket address families
+# Netfilter source files
 
-SOCK_CSRCS += inet_txdrain.c
+ifeq ($(CONFIG_NET_IPTABLES),y)
 
-ifeq ($(CONFIG_NET_IPv4),y)
-SOCK_CSRCS += inet_sockif.c
-SOCK_CSRCS += inet_globals.c
-else ifeq ($(CONFIG_NET_IPv6),y)
-SOCK_CSRCS += inet_sockif.c
-SOCK_CSRCS += inet_globals.c
-endif
+NET_CSRCS += ipt_sockopt.c
 
-ifeq ($(CONFIG_NET_IPv4),y)
-SOCK_CSRCS += ipv4_setsockopt.c ipv4_getsockname.c ipv4_getpeername.c ipv4_build_header.c
+ifeq ($(CONFIG_NET_NAT),y)
+NET_CSRCS += ipt_nat.c
 endif
 
-ifeq ($(CONFIG_NET_IPv6),y)
-SOCK_CSRCS += ipv6_setsockopt.c ipv6_getsockname.c ipv6_getpeername.c ipv6_build_header.c
-endif
+# Include Netfilter build support
 
-# Include inet build support
+DEPPATH += --dep-path netfilter
+VPATH += :netfilter
 
-DEPPATH += --dep-path inet
-VPATH += :inet
+endif
diff --git a/net/netfilter/ipt_nat.c b/net/netfilter/ipt_nat.c
new file mode 100644
index 0000000000..914845fff4
--- /dev/null
+++ b/net/netfilter/ipt_nat.c
@@ -0,0 +1,126 @@
+/****************************************************************************
+ * net/netfilter/ipt_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 <debug.h>
+#include <errno.h>
+#include <string.h>
+
+#include <nuttx/net/netfilter/nf_nat.h>
+
+#include "nat/nat.h"
+#include "netdev/netdev.h"
+#include "netfilter/iptables.h"
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: adjust_nat
+ *
+ * Description:
+ *   Callback for netdev_foreach, enable/disable NAT on dev.
+ *
+ * Input Parameters:
+ *   dev       - Device to adjust NAT.
+ *   arg       - The input ipt_replace config of NAT.
+ *
+ ****************************************************************************/
+
+static int adjust_nat(FAR struct net_driver_s *dev, FAR void *arg)
+{
+  FAR const struct ipt_replace *repl = arg;
+  FAR struct ipt_entry *entry;
+  FAR struct xt_entry_target *target;
+
+  ipt_entry_for_every(entry, repl->entries, repl->size)
+    {
+      target = IPT_TARGET(entry);
+      if (strcmp(target->u.user.name, XT_MASQUERADE_TARGET) == 0 &&
+          strcmp(dev->d_ifname, entry->ip.outiface) == 0)
+        {
+          ipv4_nat_enable(dev);
+          return 0;
+        }
+    }
+
+  ipv4_nat_disable(dev);
+  return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipt_nat_init
+ *
+ * Description:
+ *   Init NAT table data.
+ *
+ ****************************************************************************/
+
+FAR struct ipt_replace *ipt_nat_init(void)
+{
+  return ipt_alloc_table(TABLE_NAME_NAT, 1 << NF_INET_POST_ROUTING);
+}
+
+/****************************************************************************
+ * Name: ipt_nat_apply
+ *
+ * Description:
+ *   Try to apply NAT rules, will do nothing if failed.
+ *
+ * Input Parameters:
+ *   repl   - The config got from user space to control NAT table.
+ *
+ ****************************************************************************/
+
+int ipt_nat_apply(FAR const struct ipt_replace *repl)
+{
+  FAR struct ipt_entry *entry;
+  FAR struct xt_entry_target *target;
+
+  /* Check config first. */
+
+  ipt_entry_for_every(entry, repl->entries, repl->size)
+    {
+      target = IPT_TARGET(entry);
+      if (strcmp(target->u.user.name, XT_MASQUERADE_TARGET) == 0 &&
+          netdev_findbyname(entry->ip.outiface) == NULL)
+        {
+          /* MASQUERADE specified but no WAN device, don't apply. */
+
+          nwarn("WARNING: Trying to apply nat on nonexistent dev: %s",
+                entry->ip.outiface);
+          return -EINVAL;
+        }
+    }
+
+  /* Do actual work. */
+
+  netdev_foreach(adjust_nat, (FAR void *)repl);
+
+  return OK;
+}
diff --git a/net/netfilter/ipt_sockopt.c b/net/netfilter/ipt_sockopt.c
new file mode 100644
index 0000000000..3f9dc3612f
--- /dev/null
+++ b/net/netfilter/ipt_sockopt.c
@@ -0,0 +1,440 @@
+/****************************************************************************
+ * net/netfilter/ipt_sockopt.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 <errno.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <nuttx/kmalloc.h>
+
+#include "netfilter/iptables.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define SWAP(a,b,t)    do { t = a; a = b; b = t; } while (0)
+
+#ifndef ARRAY_SIZE
+#  define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* Structure to store all info we need, including table data and
+ * init/apply functions.
+ */
+
+struct ipt_table_s
+{
+  FAR struct ipt_replace *repl;
+  FAR struct ipt_replace *(*init_func)(void);
+  FAR int (*apply_func)(FAR const struct ipt_replace *);
+};
+
+/* Following structs represent the layout of an entry with standard/error
+ * target (without matches). Mainly used to simplify initialization (entry
+ * creation), not suggested to use under other situations, because there
+ * might be matches between entry and target in data from user space.
+ */
+
+struct ipt_standard_entry_s
+{
+  struct ipt_entry entry;
+  struct xt_standard_target target;
+};
+
+struct ipt_error_entry_s
+{
+  struct ipt_entry entry;
+  struct xt_error_target target;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct ipt_table_s g_tables[] =
+{
+#ifdef CONFIG_NET_NAT
+  {NULL, ipt_nat_init, ipt_nat_apply},
+#endif
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipt_table_init
+ *
+ * Description:
+ *   Try initialize the table data if not initialized.
+ *
+ ****************************************************************************/
+
+static void ipt_table_init(FAR struct ipt_table_s *table)
+{
+  if (table->repl == NULL && table->init_func != NULL)
+    {
+      table->repl = table->init_func();
+    }
+}
+
+/****************************************************************************
+ * Name: ipt_table
+ *
+ * Description:
+ *   Find table data by table name.
+ *
+ ****************************************************************************/
+
+static FAR struct ipt_table_s *ipt_table(FAR const char *name)
+{
+  int i;
+  for (i = 0; i < ARRAY_SIZE(g_tables); i++)
+    {
+      ipt_table_init(&g_tables[i]);
+      if (g_tables[i].repl != NULL &&
+          strcmp(g_tables[i].repl->name, name) == 0)
+        {
+          return &g_tables[i];
+        }
+    }
+
+  return NULL;
+}
+
+/****************************************************************************
+ * Name: ipt_table_repl
+ *
+ * Description:
+ *   Find table data by table name.
+ *
+ ****************************************************************************/
+
+static FAR struct ipt_replace *ipt_table_repl(FAR const char *name)
+{
+  FAR struct ipt_table_s *table = ipt_table(name);
+  if (table)
+    {
+      return table->repl;
+    }
+
+  return NULL;
+}
+
+/****************************************************************************
+ * Name: get_info
+ *
+ * Description:
+ *   Fill table info into ipt_getinfo structure.
+ *
+ * Input Parameters:
+ *   get, len - The parameters from getsockopt.
+ *
+ ****************************************************************************/
+
+static int get_info(FAR struct ipt_getinfo *get, FAR socklen_t *len)
+{
+  FAR struct ipt_replace *repl;
+
+  if (*len != sizeof(*get))
+    {
+      return -EINVAL;
+    }
+
+  repl = ipt_table_repl(get->name);
+  if (repl == NULL)
+    {
+      return -ENOENT;
+    }
+
+  get->valid_hooks = repl->valid_hooks;
+  memcpy(get->hook_entry, repl->hook_entry, sizeof(get->hook_entry));
+  memcpy(get->underflow, repl->underflow, sizeof(get->underflow));
+  get->num_entries = repl->num_entries;
+  get->size = repl->size;
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: get_entries
+ *
+ * Description:
+ *   Fill entry info into ipt_get_entries structure.
+ *
+ * Input Parameters:
+ *   get, len - The parameters from getsockopt.
+ *
+ ****************************************************************************/
+
+static int get_entries(FAR struct ipt_get_entries *get, FAR socklen_t *len)
+{
+  FAR struct ipt_replace *repl;
+
+  if (*len < sizeof(*get) || *len != sizeof(*get) + get->size)
+    {
+      return -EINVAL;
+    }
+
+  repl = ipt_table_repl(get->name);
+  if (repl == NULL)
+    {
+      return -ENOENT;
+    }
+
+  if (get->size != repl->size)
+    {
+      return -EAGAIN;
+    }
+
+  memcpy(get->entrytable, repl->entries, get->size);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: check_replace
+ *
+ * Description:
+ *   Check whether an ipt_replace structure from user space is valid.
+ *
+ * Input Parameters:
+ *   repl - The ipt_replace structure to check.
+ *
+ * Returned Value:
+ *   OK if repl is valid, otherwise -EINVAL.
+ *
+ ****************************************************************************/
+
+static int check_replace(FAR const struct ipt_replace *repl)
+{
+  FAR struct ipt_entry *entry;
+  unsigned int entry_count = 0;
+
+  ipt_entry_for_every(entry, repl->entries, repl->size)
+    {
+      entry_count++;
+    }
+
+  if (entry_count != repl->num_entries)
+    {
+      return -EINVAL;
+    }
+
+  /* May add more checks later. */
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: replace_entries
+ *
+ * Description:
+ *   Apply replace data to kernel tables.
+ *
+ * Input Parameters:
+ *   repl, len - The parameters from setsockopt.
+ *
+ ****************************************************************************/
+
+static int replace_entries(FAR const struct ipt_replace *repl, socklen_t len)
+{
+  int ret;
+  FAR struct ipt_replace *new_repl;
+  FAR struct ipt_table_s *table = ipt_table(repl->name);
+
+  if (table == NULL || table->repl == NULL)
+    {
+      return -ENOENT;
+    }
+
+  if (len < sizeof(*repl) || len != sizeof(*repl) + repl->size ||
+      repl->valid_hooks != table->repl->valid_hooks)
+    {
+      return -EINVAL;
+    }
+
+  /* Check replace struct before applying it. */
+
+  ret = check_replace(repl);
+  if (ret != OK)
+    {
+      return ret;
+    }
+
+  new_repl = kmm_malloc(sizeof(*new_repl) + repl->size);
+  if (new_repl == NULL)
+    {
+      return -ENOMEM;
+    }
+
+  /* Try to apply the config in replace data. */
+
+  ret = table->apply_func(repl);
+
+  /* If successfully applied, save data into kernel space. */
+
+  if (ret == OK)
+    {
+      FAR struct ipt_replace *tmp;
+      memcpy(new_repl, repl, sizeof(*repl) + repl->size);
+      SWAP(table->repl, new_repl, tmp);
+    }
+
+  kmm_free(new_repl);
+  return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipt_alloc_table
+ *
+ * Description:
+ *   Allocate an initial table info with valid_hooks specified.
+ *   Will generate a default entry with standard target for each valid hook,
+ *   and an entry with error target at the end of entry table.
+ *
+ * Input Parameters:
+ *   table       - The name of the table.
+ *   valid_hooks - The valid_hooks of the table, it's a bitmask.
+ *
+ * Returned Value:
+ *   Newly generated ipt_replace structure.
+ *
+ ****************************************************************************/
+
+FAR struct ipt_replace *ipt_alloc_table(FAR const char *table,
+                                        unsigned int valid_hooks)
+{
+  FAR struct ipt_replace *repl;
+  FAR struct ipt_standard_entry_s *entry;
+  FAR struct ipt_error_entry_s *error_entry;
+  size_t entry_size;
+  unsigned int hook;
+  unsigned int num_hooks;
+
+  if (valid_hooks == 0 || valid_hooks > (1 << NF_INET_NUMHOOKS))
+    {
+      return NULL;
+    }
+
+  num_hooks = popcount(valid_hooks);
+
+  /* There will be num_hooks entries with standard target (ACCEPT). */
+
+  entry_size = num_hooks * sizeof(struct ipt_standard_entry_s);
+
+  /* An error target as final entry. */
+
+  entry_size += sizeof(struct ipt_error_entry_s);
+
+  repl = kmm_zalloc(sizeof(*repl) + entry_size);
+  if (repl == NULL)
+    {
+      return NULL;
+    }
+
+  strcpy(repl->name, table);
+  repl->valid_hooks = valid_hooks;
+  repl->num_entries = num_hooks + 1;
+  repl->size = entry_size;
+
+  entry = (FAR struct ipt_standard_entry_s *)(repl + 1);
+
+  for (hook = 0; hook < NF_INET_NUMHOOKS; hook++)
+    {
+      if ((valid_hooks >> hook & 0x01) == 0)
+        {
+          continue;
+        }
+
+      repl->hook_entry[hook] = (uintptr_t)entry - (uintptr_t)(repl + 1);
+      repl->underflow[hook] = repl->hook_entry[hook];
+
+      entry->target.verdict = -NF_ACCEPT - 1;
+      IPT_FILL_ENTRY(entry, XT_STANDARD_TARGET);
+
+      entry++;
+    }
+
+  error_entry = (FAR struct ipt_error_entry_s *)entry;
+  strcpy(error_entry->target.errorname, XT_ERROR_TARGET);
+  IPT_FILL_ENTRY(error_entry, XT_ERROR_TARGET);
+
+  return repl;
+}
+
+/****************************************************************************
+ * Name: ipt_setsockopt
+ *
+ * Description:
+ *   setsockopt function of iptables.
+ *
+ ****************************************************************************/
+
+int ipt_setsockopt(FAR struct socket *psock, int option,
+                   FAR const void *value, socklen_t value_len)
+{
+  switch (option)
+    {
+      case IPT_SO_SET_REPLACE:
+        return replace_entries(value, value_len);
+
+      default:
+        return -ENOPROTOOPT;
+    }
+}
+
+/****************************************************************************
+ * Name: ipt_getsockopt
+ *
+ * Description:
+ *   getsockopt function of iptables.
+ *
+ ****************************************************************************/
+
+int ipt_getsockopt(FAR struct socket *psock, int option,
+                   FAR void *value, FAR socklen_t *value_len)
+{
+  switch (option)
+    {
+      case IPT_SO_GET_INFO:
+        return get_info(value, value_len);
+
+      case IPT_SO_GET_ENTRIES:
+        return get_entries(value, value_len);
+
+      default:
+        return -ENOPROTOOPT;
+    }
+}
diff --git a/net/netfilter/iptables.h b/net/netfilter/iptables.h
new file mode 100644
index 0000000000..de6d945f62
--- /dev/null
+++ b/net/netfilter/iptables.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+ * net/netfilter/iptables.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_NETFILTER_IPTABLES_H
+#define __NET_NETFILTER_IPTABLES_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <nuttx/net/net.h>
+#include <nuttx/net/netfilter/ip_tables.h>
+
+#ifdef CONFIG_NET_IPTABLES
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ipt_setsockopt
+ *
+ * Description:
+ *   setsockopt function of iptables.
+ *
+ ****************************************************************************/
+
+int ipt_setsockopt(FAR struct socket *psock, int option,
+                   FAR const void *value, socklen_t value_len);
+
+/****************************************************************************
+ * Name: ipt_getsockopt
+ *
+ * Description:
+ *   getsockopt function of iptables.
+ *
+ ****************************************************************************/
+
+int ipt_getsockopt(FAR struct socket *psock, int option,
+                   FAR void *value, FAR socklen_t *value_len);
+
+/****************************************************************************
+ * Name: ipt_alloc_table
+ *
+ * Description:
+ *   Allocate an initial table info with valid_hooks specified.
+ *   Will generate a default entry with standard target for each valid hook,
+ *   and an entry with error target at the end of entry table.
+ *
+ * Input Parameters:
+ *   table       - The name of the table.
+ *   valid_hooks - The valid_hooks of the table, it's a bitmap of hooks.
+ *
+ * Returned Value:
+ *   Newly generated ipt_replace structure.
+ *
+ ****************************************************************************/
+
+FAR struct ipt_replace *ipt_alloc_table(FAR const char *table,
+                                        unsigned int valid_hooks);
+
+/****************************************************************************
+ * Name: ipt_nat_init
+ *
+ * Description:
+ *   Init NAT table data.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_NAT
+FAR struct ipt_replace *ipt_nat_init(void);
+#endif
+
+/****************************************************************************
+ * Name: ipt_nat_apply
+ *
+ * Description:
+ *   Try to apply NAT rules, will do nothing if failed.
+ *
+ * Input Parameters:
+ *   repl   - The config got from user space to control NAT table.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_NAT
+int ipt_nat_apply(FAR const struct ipt_replace *repl);
+#endif
+
+#endif /* CONFIG_NET_IPTABLES */
+#endif /* __NET_NETFILTER_IPTABLES_H */