netlib/iptables: Add functions for filter table

Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
This commit is contained in:
Zhe Weng 2024-04-16 16:06:22 +08:00 committed by Xiang Xiao
parent 9fcde632a7
commit 4283e57013
2 changed files with 264 additions and 21 deletions

View File

@ -395,6 +395,8 @@ enum nf_inet_hooks; /* Forward reference */
FAR struct ipt_replace *netlib_ipt_prepare(FAR const char *table);
int netlib_ipt_commit(FAR const struct ipt_replace *repl);
int netlib_ipt_flush(FAR const char *table, enum nf_inet_hooks hook);
int netlib_ipt_policy(FAR const char *table, enum nf_inet_hooks hook,
int verdict);
int netlib_ipt_append(FAR struct ipt_replace **repl,
FAR const struct ipt_entry *entry,
enum nf_inet_hooks hook);
@ -404,9 +406,17 @@ int netlib_ipt_insert(FAR struct ipt_replace **repl,
int netlib_ipt_delete(FAR struct ipt_replace *repl,
FAR const struct ipt_entry *entry,
enum nf_inet_hooks hook, int rulenum);
int netlib_ipt_fillifname(FAR struct ipt_entry *entry,
FAR const char *inifname,
FAR const char *outifname);
# ifdef CONFIG_NET_NAT
FAR struct ipt_entry *netlib_ipt_masquerade_entry(FAR const char *ifname);
# endif
# ifdef CONFIG_NET_IPFILTER
FAR struct ipt_entry *netlib_ipt_filter_entry(FAR const char *target,
int verdict,
uint8_t match_proto);
# endif
#endif
#ifdef CONFIG_NETLINK_NETFILTER

View File

@ -24,23 +24,27 @@
#include <nuttx/config.h>
#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <nuttx/net/netconfig.h>
#include <nuttx/net/netfilter/ip_tables.h>
#include <nuttx/net/netfilter/netfilter.h>
#include <nuttx/net/netfilter/nf_nat.h>
#include "netutils/netlib.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define IPT_FILL_MATCH(e, match_name) \
do \
{ \
strlcpy((e)->match.u.user.name, (match_name), \
sizeof((e)->match.u.user.name)); \
(e)->match.u.match_size = offsetof(typeof(*(e)), target) - \
offsetof(typeof(*(e)), match); \
} \
while(0)
/****************************************************************************
* Private Types
****************************************************************************/
@ -59,6 +63,39 @@ struct ipt_masquerade_entry_s
} target;
};
struct ipt_filter_entry_s
{
struct ipt_entry entry;
/* Compatible with ACCEPT/DROP/REJECT target. */
struct xt_standard_target target;
};
struct ipt_filter_tcp_entry_s
{
struct ipt_entry entry;
struct xt_entry_match match;
struct xt_tcp tcp;
struct xt_standard_target target;
};
struct ipt_filter_udp_entry_s
{
struct ipt_entry entry;
struct xt_entry_match match;
struct xt_udp udp;
struct xt_standard_target target;
};
struct ipt_filter_icmp_entry_s
{
struct ipt_entry entry;
struct xt_entry_match match;
struct ipt_icmp icmp;
struct xt_standard_target target;
};
/****************************************************************************
* Private Functions
****************************************************************************/
@ -355,7 +392,8 @@ int netlib_ipt_flush(FAR const char *table, enum nf_inet_hooks hook)
if (hook != NF_INET_NUMHOOKS && (repl->valid_hooks & (1 << hook)) == 0)
{
fprintf(stderr, "Invalid hook number %d for table %s!\n", hook, table);
return -EINVAL;
ret = -EINVAL;
goto errout;
}
for (cur_hook = 0; cur_hook < NF_INET_NUMHOOKS; cur_hook++)
@ -383,6 +421,62 @@ errout:
return ret;
}
/****************************************************************************
* Name: netlib_ipt_policy
*
* Description:
* Set policy for the table. It's a common operation, but may only take
* effect on filter-related tables.
*
* Input Parameters:
* table - The table name to set policy.
* hook - The hook to set policy.
* verdict - The verdict to set.
*
****************************************************************************/
int netlib_ipt_policy(FAR const char *table, enum nf_inet_hooks hook,
int verdict)
{
FAR struct ipt_replace *repl = netlib_ipt_prepare(table);
FAR struct ipt_entry *entry;
FAR struct xt_standard_target *target;
int ret;
if (repl == NULL)
{
fprintf(stderr, "Failed to read table %s from kernel!\n", table);
return -EIO;
}
if ((repl->valid_hooks & (1 << hook)) == 0)
{
fprintf(stderr, "Invalid hook number %d for table %s!\n", hook, table);
ret = -EINVAL;
goto errout;
}
/* The underflow entry is the default policy of the chain. */
entry = (FAR struct ipt_entry *)((uintptr_t)repl->entries +
repl->underflow[hook]);
target = (FAR struct xt_standard_target *)IPT_TARGET(entry);
if (strcmp(target->target.u.user.name, XT_STANDARD_TARGET) != 0)
{
fprintf(stderr, "Wrong target %s!\n", target->target.u.user.name);
ret = -EINVAL;
goto errout;
}
target->verdict = verdict;
ret = netlib_ipt_commit(repl);
errout:
free(repl);
return ret;
}
/****************************************************************************
* Name: netlib_ipt_append
*
@ -527,6 +621,59 @@ int netlib_ipt_delete(FAR struct ipt_replace *repl,
return -ENOENT;
}
/****************************************************************************
* Name: netlib_ipt_fillifname
*
* Description:
* Fill inifname and outifname into entry.
*
* Input Parameters:
* entry - The entry to fill.
* inifname - The input device name, NULL for no change.
* outifname - The output device name, NULL for no change.
*
****************************************************************************/
int netlib_ipt_fillifname(FAR struct ipt_entry *entry,
FAR const char *inifname,
FAR const char *outifname)
{
size_t len;
if (entry == NULL)
{
return -EINVAL;
}
if (inifname != NULL)
{
len = strlen(inifname);
if (len + 1 > IFNAMSIZ)
{
fprintf(stderr, "Too long inifname %s!\n", inifname);
return -EINVAL;
}
strlcpy(entry->ip.iniface, inifname, sizeof(entry->ip.iniface));
memset(entry->ip.iniface_mask, 0xff, len + 1);
}
if (outifname != NULL)
{
len = strlen(outifname);
if (len + 1 > IFNAMSIZ)
{
fprintf(stderr, "Too long outifname %s!\n", outifname);
return -EINVAL;
}
strlcpy(entry->ip.outiface, outifname, sizeof(entry->ip.outiface));
memset(entry->ip.outiface_mask, 0xff, len + 1);
}
return OK;
}
/****************************************************************************
* Name: netlib_ipt_masquerade_entry
*
@ -545,15 +692,8 @@ int netlib_ipt_delete(FAR struct ipt_replace *repl,
#ifdef CONFIG_NET_NAT
FAR struct ipt_entry *netlib_ipt_masquerade_entry(FAR const char *ifname)
{
size_t len;
FAR struct ipt_masquerade_entry_s *entry;
len = strlen(ifname);
if (len + 1 > IFNAMSIZ)
{
return NULL;
}
entry = zalloc(sizeof(*entry));
if (entry == NULL)
{
@ -562,10 +702,103 @@ FAR struct ipt_entry *netlib_ipt_masquerade_entry(FAR const char *ifname)
IPT_FILL_ENTRY(entry, XT_MASQUERADE_TARGET);
strlcpy(entry->entry.ip.outiface, ifname,
sizeof(entry->entry.ip.outiface));
memset(entry->entry.ip.outiface_mask, 0xff, len + 1);
if (netlib_ipt_fillifname(&entry->entry, NULL, ifname) < 0)
{
free(entry);
return NULL;
}
return &entry->entry;
}
#endif
/****************************************************************************
* Name: netlib_ipt_filter_entry
*
* Description:
* Alloc an entry with filter target.
*
* Input Parameters:
* target - The target name to apply.
* verdict - The verdict to set, compatible with reject target's code
* match_proto - The protocol match type in the entry, 0 for no match.
*
* Returned Value:
* The pointer to the entry, or NULL if failed.
* Caller must free it after use.
*
****************************************************************************/
#ifdef CONFIG_NET_IPFILTER
FAR struct ipt_entry *netlib_ipt_filter_entry(FAR const char *target,
int verdict,
uint8_t match_proto)
{
if (target == NULL)
{
fprintf(stderr, "Empty target!\n");
return NULL;
}
switch (match_proto)
{
case 0:
{
FAR struct ipt_filter_entry_s *entry = zalloc(sizeof(*entry));
if (entry == NULL)
{
return NULL;
}
IPT_FILL_ENTRY(entry, target);
entry->target.verdict = verdict;
return &entry->entry;
}
case IPPROTO_TCP:
{
FAR struct ipt_filter_tcp_entry_s *entry = zalloc(sizeof(*entry));
if (entry == NULL)
{
return NULL;
}
IPT_FILL_ENTRY(entry, target);
IPT_FILL_MATCH(entry, XT_MATCH_NAME_TCP);
entry->target.verdict = verdict;
return &entry->entry;
}
case IPPROTO_UDP:
{
FAR struct ipt_filter_udp_entry_s *entry = zalloc(sizeof(*entry));
if (entry == NULL)
{
return NULL;
}
IPT_FILL_ENTRY(entry, target);
IPT_FILL_MATCH(entry, XT_MATCH_NAME_UDP);
entry->target.verdict = verdict;
return &entry->entry;
}
case IPPROTO_ICMP:
{
FAR struct ipt_filter_icmp_entry_s *entry = zalloc(sizeof(*entry));
if (entry == NULL)
{
return NULL;
}
IPT_FILL_ENTRY(entry, target);
IPT_FILL_MATCH(entry, XT_MATCH_NAME_ICMP);
entry->target.verdict = verdict;
return &entry->entry;
}
default:
return NULL;
}
}
#endif