net: Add set/getsockopt options compatible with ip6tables

Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
This commit is contained in:
Zhe Weng 2024-05-07 11:25:29 +08:00 committed by Xiang Xiao
parent 9637c10696
commit c72edb0637
9 changed files with 505 additions and 8 deletions

View file

@ -71,6 +71,14 @@
#define ip6t_entry_target xt_entry_target
#define ip6t_entry_match xt_entry_match
/* Foreach macro for entries. */
#define ip6t_entry_for_every(entry, head, size) \
for ((entry) = (FAR struct ip6t_entry *)(head); \
(entry) < (FAR struct ip6t_entry *)((FAR uint8_t *)(head) + (size)); \
(entry) = (FAR struct ip6t_entry *) \
((FAR uint8_t *)(entry) + (entry)->next_offset))
/****************************************************************************
* Public Types
****************************************************************************/

View file

@ -33,6 +33,7 @@
#include <nuttx/net/net.h>
#include "mld/mld.h"
#include "netfilter/iptables.h"
#include "inet/inet.h"
#include "udp/udp.h"
@ -75,6 +76,13 @@ int ipv6_getsockopt(FAR struct socket *psock, int option,
net_lock();
switch (option)
{
#ifdef CONFIG_NET_IPTABLES
case IP6T_SO_GET_INFO:
case IP6T_SO_GET_ENTRIES:
ret = ip6t_getsockopt(psock, option, value, value_len);
break;
#endif
case IPV6_TCLASS:
{
FAR struct socket_conn_s *conn = psock->s_conn;

View file

@ -33,6 +33,7 @@
#include <nuttx/net/net.h>
#include "netdev/netdev.h"
#include "netfilter/iptables.h"
#include "mld/mld.h"
#include "inet/inet.h"
#include "socket/socket.h"
@ -216,6 +217,12 @@ int ipv6_setsockopt(FAR struct socket *psock, int option,
}
break;
#ifdef CONFIG_NET_IPTABLES
case IP6T_SO_SET_REPLACE:
ret = ip6t_setsockopt(psock, option, value, value_len);
break;
#endif
default:
nerr("ERROR: Unrecognized IPv6 option: %d\n", option);
ret = -ENOPROTOOPT;

View file

@ -22,7 +22,13 @@
if(CONFIG_NET_IPTABLES)
set(SRCS ipt_sockopt.c)
if(CONFIG_NET_IPv4)
list(APPEND SRCS ipt_sockopt.c)
endif()
if(CONFIG_NET_IPv6)
list(APPEND SRCS ip6t_sockopt.c)
endif()
if(CONFIG_NET_NAT)
list(APPEND SRCS ipt_nat.c)

View file

@ -4,9 +4,9 @@
#
config NET_IPTABLES
bool "Iptables Interface"
bool "Iptables & Ip6tables Interface"
default y
depends on NET_IPv4
depends on NET_IPv4 || NET_IPv6
depends on NET_SOCKOPTS
depends on NET_NAT || NET_IPFILTER
---help---

View file

@ -22,7 +22,13 @@
ifeq ($(CONFIG_NET_IPTABLES),y)
ifeq ($(CONFIG_NET_IPv4),y)
NET_CSRCS += ipt_sockopt.c
endif
ifeq ($(CONFIG_NET_IPv6),y)
NET_CSRCS += ip6t_sockopt.c
endif
ifeq ($(CONFIG_NET_NAT),y)
NET_CSRCS += ipt_nat.c

View file

@ -0,0 +1,440 @@
/****************************************************************************
* net/netfilter/ip6t_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 <sys/param.h>
#include <nuttx/kmalloc.h>
#include "netfilter/iptables.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define SWAP_PTR(a,b) do { FAR void *t = (a); (a) = (b); (b) = t; } while (0)
/****************************************************************************
* Private Types
****************************************************************************/
/* Structure to store all info we need, including table data and
* init/apply functions.
*/
struct ip6t_table_s
{
FAR struct ip6t_replace *repl;
FAR struct ip6t_replace *(*init_func)(void);
FAR int (*apply_func)(FAR const struct ip6t_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 ip6t_standard_entry_s
{
struct ip6t_entry entry;
struct xt_standard_target target;
};
struct ip6t_error_entry_s
{
struct ip6t_entry entry;
struct xt_error_target target;
};
/****************************************************************************
* Private Data
****************************************************************************/
static struct ip6t_table_s g_tables[] =
{
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: ip6t_table_init
*
* Description:
* Try initialize the table data if not initialized.
*
****************************************************************************/
static void ip6t_table_init(FAR struct ip6t_table_s *table)
{
if (table->repl == NULL && table->init_func != NULL)
{
table->repl = table->init_func();
}
}
/****************************************************************************
* Name: ip6t_table
*
* Description:
* Find table data by table name.
*
****************************************************************************/
static FAR struct ip6t_table_s *ip6t_table(FAR const char *name)
{
int i;
for (i = 0; i < nitems(g_tables); i++)
{
ip6t_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: ip6t_table_repl
*
* Description:
* Find table data by table name.
*
****************************************************************************/
static FAR struct ip6t_replace *ip6t_table_repl(FAR const char *name)
{
FAR struct ip6t_table_s *table = ip6t_table(name);
if (table)
{
return table->repl;
}
return NULL;
}
/****************************************************************************
* Name: get_info
*
* Description:
* Fill table info into ip6t_getinfo structure.
*
* Input Parameters:
* get, len - The parameters from getsockopt.
*
****************************************************************************/
static int get_info(FAR struct ip6t_getinfo *get, FAR socklen_t *len)
{
FAR struct ip6t_replace *repl;
if (*len != sizeof(*get))
{
return -EINVAL;
}
repl = ip6t_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 ip6t_get_entries structure.
*
* Input Parameters:
* get, len - The parameters from getsockopt.
*
****************************************************************************/
static int get_entries(FAR struct ip6t_get_entries *get, FAR socklen_t *len)
{
FAR struct ip6t_replace *repl;
if (*len < sizeof(*get) || *len != sizeof(*get) + get->size)
{
return -EINVAL;
}
repl = ip6t_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 ip6t_replace structure from user space is valid.
*
* Input Parameters:
* repl - The ip6t_replace structure to check.
*
* Returned Value:
* OK if repl is valid, otherwise -EINVAL.
*
****************************************************************************/
static int check_replace(FAR const struct ip6t_replace *repl)
{
FAR struct ip6t_entry *entry;
unsigned int entry_count = 0;
ip6t_entry_for_every(entry, repl->entries, repl->size)
{
entry_count++;
if (entry->next_offset == 0)
{
return -EINVAL;
}
}
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 ip6t_replace *repl,
socklen_t len)
{
int ret;
FAR struct ip6t_replace *new_repl;
FAR struct ip6t_table_s *table = ip6t_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)
{
memcpy(new_repl, repl, sizeof(*repl) + repl->size);
SWAP_PTR(table->repl, new_repl);
}
kmm_free(new_repl);
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ip6t_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 ip6t_replace structure.
*
****************************************************************************/
FAR struct ip6t_replace *ip6t_alloc_table(FAR const char *table,
unsigned int valid_hooks)
{
FAR struct ip6t_replace *repl;
FAR struct ip6t_standard_entry_s *entry;
FAR struct ip6t_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 ip6t_standard_entry_s);
/* An error target as final entry. */
entry_size += sizeof(struct ip6t_error_entry_s);
repl = kmm_zalloc(sizeof(*repl) + entry_size);
if (repl == NULL)
{
return NULL;
}
strlcpy(repl->name, table, sizeof(repl->name));
repl->valid_hooks = valid_hooks;
repl->num_entries = num_hooks + 1;
repl->size = entry_size;
entry = (FAR struct ip6t_standard_entry_s *)(repl->entries);
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->entries);
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 ip6t_error_entry_s *)entry;
strlcpy(error_entry->target.errorname, XT_ERROR_TARGET,
sizeof(error_entry->target.errorname));
IPT_FILL_ENTRY(error_entry, XT_ERROR_TARGET);
return repl;
}
/****************************************************************************
* Name: ip6t_setsockopt
*
* Description:
* setsockopt function of iptables.
*
****************************************************************************/
int ip6t_setsockopt(FAR struct socket *psock, int option,
FAR const void *value, socklen_t value_len)
{
switch (option)
{
case IP6T_SO_SET_REPLACE:
return replace_entries(value, value_len);
default:
return -ENOPROTOOPT;
}
}
/****************************************************************************
* Name: ip6t_getsockopt
*
* Description:
* getsockopt function of iptables.
*
****************************************************************************/
int ip6t_getsockopt(FAR struct socket *psock, int option,
FAR void *value, FAR socklen_t *value_len)
{
switch (option)
{
case IP6T_SO_GET_INFO:
return get_info(value, value_len);
case IP6T_SO_GET_ENTRIES:
return get_entries(value, value_len);
default:
return -ENOPROTOOPT;
}
}

View file

@ -37,7 +37,7 @@
* Pre-processor Definitions
****************************************************************************/
#define SWAP(a,b,t) do { t = a; a = b; b = t; } while (0)
#define SWAP_PTR(a,b) do { FAR void *t = (a); (a) = (b); (b) = t; } while (0)
/****************************************************************************
* Private Types
@ -242,6 +242,10 @@ static int check_replace(FAR const struct ipt_replace *repl)
ipt_entry_for_every(entry, repl->entries, repl->size)
{
entry_count++;
if (entry->next_offset == 0)
{
return -EINVAL;
}
}
if (entry_count != repl->num_entries)
@ -304,9 +308,8 @@ static int replace_entries(FAR const struct ipt_replace *repl, socklen_t len)
if (ret == OK)
{
FAR struct ipt_replace *tmp;
memcpy(new_repl, repl, sizeof(*repl) + repl->size);
SWAP(table->repl, new_repl, tmp);
SWAP_PTR(table->repl, new_repl);
}
kmm_free(new_repl);
@ -370,7 +373,7 @@ FAR struct ipt_replace *ipt_alloc_table(FAR const char *table,
repl->num_entries = num_hooks + 1;
repl->size = entry_size;
entry = (FAR struct ipt_standard_entry_s *)(repl + 1);
entry = (FAR struct ipt_standard_entry_s *)(repl->entries);
for (hook = 0; hook < NF_INET_NUMHOOKS; hook++)
{
@ -379,7 +382,7 @@ FAR struct ipt_replace *ipt_alloc_table(FAR const char *table,
continue;
}
repl->hook_entry[hook] = (uintptr_t)entry - (uintptr_t)(repl + 1);
repl->hook_entry[hook] = (uintptr_t)entry - (uintptr_t)(repl->entries);
repl->underflow[hook] = repl->hook_entry[hook];
entry->target.verdict = -NF_ACCEPT - 1;

View file

@ -29,6 +29,7 @@
#include <nuttx/net/net.h>
#include <nuttx/net/netfilter/ip_tables.h>
#include <nuttx/net/netfilter/ip6_tables.h>
#ifdef CONFIG_NET_IPTABLES
@ -44,8 +45,14 @@
*
****************************************************************************/
#ifdef CONFIG_NET_IPv4
int ipt_setsockopt(FAR struct socket *psock, int option,
FAR const void *value, socklen_t value_len);
#endif
#ifdef CONFIG_NET_IPv6
int ip6t_setsockopt(FAR struct socket *psock, int option,
FAR const void *value, socklen_t value_len);
#endif
/****************************************************************************
* Name: ipt_getsockopt
@ -55,8 +62,14 @@ int ipt_setsockopt(FAR struct socket *psock, int option,
*
****************************************************************************/
#ifdef CONFIG_NET_IPv4
int ipt_getsockopt(FAR struct socket *psock, int option,
FAR void *value, FAR socklen_t *value_len);
#endif
#ifdef CONFIG_NET_IPv6
int ip6t_getsockopt(FAR struct socket *psock, int option,
FAR void *value, FAR socklen_t *value_len);
#endif
/****************************************************************************
* Name: ipt_alloc_table
@ -75,8 +88,14 @@ int ipt_getsockopt(FAR struct socket *psock, int option,
*
****************************************************************************/
#ifdef CONFIG_NET_IPv4
FAR struct ipt_replace *ipt_alloc_table(FAR const char *table,
unsigned int valid_hooks);
#endif
#ifdef CONFIG_NET_IPv6
FAR struct ip6t_replace *ip6t_alloc_table(FAR const char *table,
unsigned int valid_hooks);
#endif
/****************************************************************************
* Name: ipt_nat_init