diff --git a/include/netutils/netlib.h b/include/netutils/netlib.h index ba6bb618b..4975bd7f2 100644 --- a/include/netutils/netlib.h +++ b/include/netutils/netlib.h @@ -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 diff --git a/netutils/netlib/netlib_iptables.c b/netutils/netlib/netlib_iptables.c index 21331c9ad..adfb442d8 100644 --- a/netutils/netlib/netlib_iptables.c +++ b/netutils/netlib/netlib_iptables.c @@ -24,23 +24,27 @@ #include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include #include -#include #include #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