system/iptables: Support filter table
Add supports for filter table, usage is same as Linux's iptables, including: - [!] -p/--protocol - [!] -s/--source -d/--destination - [!] -i/--in-interface -o/--out-interface - [!] --sport/--source-port --dport/--destination-port - [!] --icmp-type Examples: > iptables -P FORWARD DROP > iptables -I INPUT -i eth0 ! -p icmp -j DROP > iptables -t filter -A FORWARD -p tcp -s 10.0.1.2/24 -d 10.0.3.4/24 -i eth0 -o eth1 --sport 3000:3200 --dport 123:65535 -j ACCEPT > iptables -t filter -I FORWARD 2 -p icmp ! -s 123.123.123.123 ! -i eth0 -o eth1 ! --icmp-type 255 -j REJECT > iptables -L Chain INPUT (policy ACCEPT) target prot idev odev source destination DROP !icmp eth0 any anywhere anywhere Chain FORWARD (policy DROP) target prot idev odev source destination ACCEPT tcp eth0 eth1 10.0.1.2/24 10.0.3.4/24 tcp spts:3000:3200 dpts:123:65535 REJECT icmp !eth0 eth1 !123.123.123.123/32 anywhere icmp !type 255 Chain OUTPUT (policy ACCEPT) target prot idev odev source destination Note: - We're dropping dependency of argtable3, since it is difficult to support command like '! -p tcp ! -i eth0' Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
This commit is contained in:
parent
4283e57013
commit
8ae06462eb
@ -8,7 +8,6 @@ config SYSTEM_IPTABLES
|
||||
default n
|
||||
depends on NET_IPTABLES
|
||||
select NETUTILS_NETLIB
|
||||
select SYSTEM_ARGTABLE3
|
||||
---help---
|
||||
Enable support for the 'iptables' command.
|
||||
|
||||
|
@ -25,6 +25,7 @@ PRIORITY = $(CONFIG_SYSTEM_IPTABLES_PRIORITY)
|
||||
STACKSIZE = $(CONFIG_SYSTEM_IPTABLES_STACKSIZE)
|
||||
MODULE = $(CONFIG_SYSTEM_IPTABLES)
|
||||
|
||||
CSRCS += iptables_utils.c
|
||||
MAINSRC = iptables.c
|
||||
|
||||
include $(APPDIR)/Application.mk
|
||||
|
@ -25,180 +25,23 @@
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <nuttx/net/netfilter/ip_tables.h>
|
||||
#include <nuttx/net/netfilter/nf_nat.h>
|
||||
|
||||
#include "argtable3.h"
|
||||
#include "iptables.h"
|
||||
#include "netutils/netlib.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/* TODO: Our getopt(), which argtable3 depends, does not support nonoptions
|
||||
* in the middle, so commands like 'iptables -I chain rulenum -j MASQUERADE'
|
||||
* cannot be supported, because the 'rulenum' will stop getopt() logic and
|
||||
* the -j option will never be parsed. Although we write 'rulenum' option
|
||||
* here, it may not work well, but it will work when our getopt() is updated.
|
||||
*/
|
||||
|
||||
struct iptables_args_s
|
||||
{
|
||||
FAR struct arg_str *table;
|
||||
|
||||
FAR struct arg_str *append_chain;
|
||||
FAR struct arg_str *insert_chain;
|
||||
FAR struct arg_str *delete_chain;
|
||||
FAR struct arg_str *flush_chain;
|
||||
FAR struct arg_str *list_chain;
|
||||
|
||||
FAR struct arg_int *rulenum;
|
||||
|
||||
FAR struct arg_str *target;
|
||||
FAR struct arg_str *outifname;
|
||||
|
||||
FAR struct arg_end *end;
|
||||
};
|
||||
|
||||
enum iptables_command_e
|
||||
{
|
||||
COMMAND_APPEND,
|
||||
COMMAND_INSERT,
|
||||
COMMAND_DELETE,
|
||||
COMMAND_FLUSH,
|
||||
COMMAND_LIST,
|
||||
COMMAND_NUM,
|
||||
};
|
||||
|
||||
struct iptables_command_s
|
||||
{
|
||||
enum iptables_command_e cmd;
|
||||
enum nf_inet_hooks hook;
|
||||
int rulenum;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static FAR const char *g_hooknames[] =
|
||||
{
|
||||
"PREROUTING", "INPUT", "FORWARD", "OUTPUT", "POSTROUTING"
|
||||
};
|
||||
typedef CODE int
|
||||
(*iptables_command_func_t)(FAR const struct iptables_args_s *args);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_showusage
|
||||
*
|
||||
* Description:
|
||||
* Show usage of the demo program
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void iptables_showusage(FAR const char *progname, FAR void** argtable)
|
||||
{
|
||||
printf("USAGE: %s -t table -[AD] chain rule-specification\n", progname);
|
||||
printf(" %s -t table -I chain [rulenum] rule-specification\n",
|
||||
progname);
|
||||
printf(" %s -t table -D chain rulenum\n", progname);
|
||||
printf(" %s -t table -[FL] [chain]\n", progname);
|
||||
printf("iptables command:\n");
|
||||
arg_print_glossary(stdout, argtable, NULL);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_parse_hook
|
||||
*
|
||||
* Description:
|
||||
* Get hook from string
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static enum nf_inet_hooks iptables_parse_hook(FAR const char *str)
|
||||
{
|
||||
unsigned int hook;
|
||||
|
||||
if (str == NULL || strlen(str) == 0) /* Might be no input (-F/-L). */
|
||||
{
|
||||
return NF_INET_NUMHOOKS;
|
||||
}
|
||||
|
||||
for (hook = 0; hook < NF_INET_NUMHOOKS; hook++)
|
||||
{
|
||||
if (strcmp(str, g_hooknames[hook]) == 0)
|
||||
{
|
||||
return hook;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Failed to parse hook: %s, default to %d\n", str, NF_INET_NUMHOOKS);
|
||||
return NF_INET_NUMHOOKS; /* Failed to parse. */
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_command
|
||||
*
|
||||
* Description:
|
||||
* Get command from arg list
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static struct iptables_command_s
|
||||
iptables_command(FAR const struct iptables_args_s *args)
|
||||
{
|
||||
struct iptables_command_s ret =
|
||||
{
|
||||
COMMAND_NUM,
|
||||
NF_INET_NUMHOOKS,
|
||||
-1
|
||||
};
|
||||
|
||||
if (args->rulenum->count > 0)
|
||||
{
|
||||
ret.rulenum = *args->rulenum->ival;
|
||||
}
|
||||
|
||||
/* Flush & list with no chain specified will result in count > 0 and empty
|
||||
* string in sval[0], then we map the hook to NF_INET_NUMHOOKS.
|
||||
*/
|
||||
|
||||
if (args->flush_chain->count > 0)
|
||||
{
|
||||
ret.cmd = COMMAND_FLUSH;
|
||||
ret.hook = iptables_parse_hook(args->flush_chain->sval[0]);
|
||||
}
|
||||
else if (args->list_chain->count > 0)
|
||||
{
|
||||
ret.cmd = COMMAND_LIST;
|
||||
ret.hook = iptables_parse_hook(args->list_chain->sval[0]);
|
||||
}
|
||||
else if (args->append_chain->count > 0)
|
||||
{
|
||||
ret.cmd = COMMAND_APPEND;
|
||||
ret.hook = iptables_parse_hook(args->append_chain->sval[0]);
|
||||
}
|
||||
else if (args->insert_chain->count > 0)
|
||||
{
|
||||
ret.cmd = COMMAND_INSERT;
|
||||
ret.hook = iptables_parse_hook(args->insert_chain->sval[0]);
|
||||
ret.rulenum = MAX(ret.rulenum, 1);
|
||||
}
|
||||
else if (args->delete_chain->count > 0)
|
||||
{
|
||||
ret.cmd = COMMAND_DELETE;
|
||||
ret.hook = iptables_parse_hook(args->delete_chain->sval[0]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_addr2str
|
||||
*
|
||||
@ -234,22 +77,45 @@ static FAR char *iptables_addr2str(struct in_addr addr, struct in_addr msk,
|
||||
static void iptables_print_chain(FAR const struct ipt_replace *repl,
|
||||
enum nf_inet_hooks hook)
|
||||
{
|
||||
const char fmt[] = "%12s %4s %4s %16s %16s\n";
|
||||
char src[INET_ADDRSTRLEN];
|
||||
char dst[INET_ADDRSTRLEN];
|
||||
/* Format: target !prot !idev !odev !saddr !daddr match */
|
||||
|
||||
const char fmt[] = "%-12s %1s%-4s %1s%-4s %1s%-4s %1s%-18s %1s%-18s %s\n";
|
||||
char src[INET_ADDRSTRLEN + 3]; /* Format: 123.123.123.123/24 */
|
||||
char dst[INET_ADDRSTRLEN + 3];
|
||||
|
||||
FAR struct ipt_entry *entry;
|
||||
FAR struct xt_entry_match *match;
|
||||
FAR struct xt_entry_target *target;
|
||||
FAR uint8_t *head = (FAR uint8_t *)repl->entries + repl->hook_entry[hook];
|
||||
int size = repl->underflow[hook] - repl->hook_entry[hook];
|
||||
|
||||
printf("Chain %s\n", g_hooknames[hook]);
|
||||
printf(fmt, "target", "idev", "odev", "source", "destination");
|
||||
/* The underflow entry contains the default rule. */
|
||||
|
||||
entry = (FAR struct ipt_entry *)(head + size);
|
||||
target = IPT_TARGET(entry);
|
||||
|
||||
printf("Chain %s (policy %s)\n",
|
||||
iptables_hook2str(hook), iptables_target2str(target));
|
||||
printf(fmt, "target", "", "prot", "", "idev", "", "odev",
|
||||
"", "source", "", "destination", "");
|
||||
|
||||
ipt_entry_for_every(entry, head, size)
|
||||
{
|
||||
FAR struct xt_entry_target *target = IPT_TARGET(entry);
|
||||
printf(fmt, target->u.user.name, entry->ip.iniface, entry->ip.outiface,
|
||||
iptables_addr2str(entry->ip.src, entry->ip.smsk, src, sizeof(src)),
|
||||
iptables_addr2str(entry->ip.dst, entry->ip.dmsk, dst, sizeof(dst)));
|
||||
target = IPT_TARGET(entry);
|
||||
match = entry->target_offset >= sizeof(struct xt_entry_match) ?
|
||||
IPT_MATCH(entry) : NULL;
|
||||
printf(fmt, iptables_target2str(target),
|
||||
INV_FLAG_STR(entry->ip.invflags & IPT_INV_PROTO),
|
||||
iptables_proto2str(entry->ip.proto),
|
||||
INV_FLAG_STR(entry->ip.invflags & IPT_INV_VIA_IN),
|
||||
iptables_iface2str(entry->ip.iniface),
|
||||
INV_FLAG_STR(entry->ip.invflags & IPT_INV_VIA_OUT),
|
||||
iptables_iface2str(entry->ip.outiface),
|
||||
INV_FLAG_STR(entry->ip.invflags & IPT_INV_SRCIP),
|
||||
iptables_addr2str(entry->ip.src, entry->ip.smsk, src, sizeof(src)),
|
||||
INV_FLAG_STR(entry->ip.invflags & IPT_INV_DSTIP),
|
||||
iptables_addr2str(entry->ip.dst, entry->ip.dmsk, dst, sizeof(dst)),
|
||||
iptables_match2str(match));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
@ -288,49 +154,31 @@ static int iptables_list(FAR const char *table, enum nf_inet_hooks hook)
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_nat_command
|
||||
* Name: iptables_finish_command
|
||||
*
|
||||
* Description:
|
||||
* Do a NAT command
|
||||
* Do a command and commit it
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int iptables_nat_command(FAR const struct iptables_command_s *cmd,
|
||||
FAR const char *ifname)
|
||||
static int iptables_finish_command(FAR const struct iptables_args_s *args,
|
||||
FAR struct ipt_replace **repl,
|
||||
FAR struct ipt_entry *entry)
|
||||
{
|
||||
FAR struct ipt_replace *repl = netlib_ipt_prepare(TABLE_NAME_NAT);
|
||||
FAR struct ipt_entry *entry = NULL;
|
||||
int ret;
|
||||
|
||||
if (repl == NULL)
|
||||
{
|
||||
printf("Failed to read table '" TABLE_NAME_NAT "' from kernel!\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (ifname && strlen(ifname) > 0) /* No ifname if we delete with rulenum. */
|
||||
{
|
||||
entry = netlib_ipt_masquerade_entry(ifname);
|
||||
if (entry == NULL)
|
||||
{
|
||||
printf("Failed to prepare entry for dev %s!\n", ifname);
|
||||
ret = -ENOMEM;
|
||||
goto errout_with_repl;
|
||||
}
|
||||
}
|
||||
|
||||
switch (cmd->cmd)
|
||||
switch (args->cmd)
|
||||
{
|
||||
case COMMAND_APPEND:
|
||||
ret = netlib_ipt_append(&repl, entry, cmd->hook);
|
||||
ret = netlib_ipt_append(repl, entry, args->hook);
|
||||
break;
|
||||
|
||||
case COMMAND_INSERT:
|
||||
ret = netlib_ipt_insert(&repl, entry, cmd->hook, cmd->rulenum);
|
||||
ret = netlib_ipt_insert(repl, entry, args->hook, args->rulenum);
|
||||
break;
|
||||
|
||||
case COMMAND_DELETE:
|
||||
ret = netlib_ipt_delete(repl, entry, cmd->hook, cmd->rulenum);
|
||||
ret = netlib_ipt_delete(*repl, entry, args->hook, args->rulenum);
|
||||
break;
|
||||
|
||||
default: /* Other commands should not call into this function. */
|
||||
@ -340,58 +188,287 @@ static int iptables_nat_command(FAR const struct iptables_command_s *cmd,
|
||||
|
||||
if (ret == OK)
|
||||
{
|
||||
ret = netlib_ipt_commit(repl);
|
||||
ret = netlib_ipt_commit(*repl);
|
||||
}
|
||||
|
||||
if (entry)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_finish_directly
|
||||
*
|
||||
* Description:
|
||||
* Finish command directly without preparing any entry
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int iptables_finish_directly(FAR const struct iptables_args_s *args)
|
||||
{
|
||||
FAR struct ipt_replace *repl = netlib_ipt_prepare(args->table);
|
||||
int ret;
|
||||
|
||||
if (repl == NULL)
|
||||
{
|
||||
free(entry);
|
||||
printf("Failed to read table '%s' from kernel!\n", args->table);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
errout_with_repl:
|
||||
ret = iptables_finish_command(args, &repl, NULL);
|
||||
|
||||
free(repl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_nat
|
||||
* Name: iptables_nat_command
|
||||
*
|
||||
* Description:
|
||||
* Apply rules for NAT
|
||||
* Do a NAT command
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int iptables_nat(FAR const struct iptables_args_s *args)
|
||||
#ifdef CONFIG_NET_NAT
|
||||
static int iptables_nat_command(FAR const struct iptables_args_s *args)
|
||||
{
|
||||
struct iptables_command_s cmd = iptables_command(args);
|
||||
FAR struct ipt_replace *repl;
|
||||
FAR struct ipt_entry *entry = NULL;
|
||||
int ret;
|
||||
|
||||
switch (cmd.cmd)
|
||||
if (args->outifname == NULL || args->outifname[0] == '\0')
|
||||
{
|
||||
printf("Table '" TABLE_NAME_NAT "' needs an out interface!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (args->target != NULL &&
|
||||
strcmp(args->target, XT_MASQUERADE_TARGET))
|
||||
{
|
||||
printf("Only target '" XT_MASQUERADE_TARGET
|
||||
"' is supported for table '" TABLE_NAME_NAT "'!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
repl = netlib_ipt_prepare(TABLE_NAME_NAT);
|
||||
if (repl == NULL)
|
||||
{
|
||||
printf("Failed to read table '" TABLE_NAME_NAT "' from kernel!\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
entry = netlib_ipt_masquerade_entry(args->outifname);
|
||||
if (entry == NULL)
|
||||
{
|
||||
printf("Failed to prepare entry for dev %s!\n", args->outifname);
|
||||
ret = -ENOMEM;
|
||||
goto errout_with_repl;
|
||||
}
|
||||
|
||||
ret = iptables_finish_command(args, &repl, entry);
|
||||
|
||||
free(entry);
|
||||
errout_with_repl:
|
||||
free(repl);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_filter_command
|
||||
*
|
||||
* Description:
|
||||
* Do a FILTER command
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_IPFILTER
|
||||
static int iptables_filter_command(FAR const struct iptables_args_s *args)
|
||||
{
|
||||
FAR struct xt_entry_match *match;
|
||||
FAR struct ipt_replace *repl = netlib_ipt_prepare(XT_TABLE_NAME_FILTER);
|
||||
FAR struct ipt_entry *entry = NULL;
|
||||
int ret;
|
||||
|
||||
if (repl == NULL)
|
||||
{
|
||||
printf("Failed to read table '" XT_TABLE_NAME_FILTER
|
||||
"' from kernel!\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Get entry and fill in proto-specific details. */
|
||||
|
||||
if (args->sport != NULL || args->dport != NULL)
|
||||
{
|
||||
FAR struct xt_udp *tcpudp;
|
||||
|
||||
if (args->protocol != IPPROTO_TCP && args->protocol != IPPROTO_UDP)
|
||||
{
|
||||
printf("Source/destination port is only supported for TCP/UDP!\n");
|
||||
ret = -EINVAL;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
entry = netlib_ipt_filter_entry(args->target, args->verdict,
|
||||
args->protocol);
|
||||
if (entry == NULL)
|
||||
{
|
||||
goto errout_prepare_entry;
|
||||
}
|
||||
|
||||
match = IPT_MATCH(entry);
|
||||
tcpudp = (FAR struct xt_udp *)(match + 1);
|
||||
|
||||
switch (args->protocol)
|
||||
{
|
||||
case IPPROTO_TCP:
|
||||
((FAR struct xt_tcp *)tcpudp)->invflags = args->tcpudpinv;
|
||||
break;
|
||||
|
||||
case IPPROTO_UDP:
|
||||
((FAR struct xt_udp *)tcpudp)->invflags = args->tcpudpinv;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = iptables_parse_ports(args->sport, tcpudp->spts);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("Failed to parse source port!\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ret = iptables_parse_ports(args->dport, tcpudp->dpts);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("Failed to parse destination port!\n");
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
else if (args->icmp_type != NULL)
|
||||
{
|
||||
FAR struct ipt_icmp *icmp;
|
||||
|
||||
if (args->protocol != IPPROTO_ICMP)
|
||||
{
|
||||
printf("ICMP type is only supported for ICMP protocol!\n");
|
||||
ret = -EINVAL;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
entry = netlib_ipt_filter_entry(args->target, args->verdict,
|
||||
args->protocol);
|
||||
if (entry == NULL)
|
||||
{
|
||||
goto errout_prepare_entry;
|
||||
}
|
||||
|
||||
match = IPT_MATCH(entry);
|
||||
icmp = (FAR struct ipt_icmp *)(match + 1);
|
||||
|
||||
ret = iptables_parse_icmp(args->icmp_type);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("Failed to parse ICMP type!\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
icmp->type = ret;
|
||||
icmp->invflags = args->icmpinv;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry = netlib_ipt_filter_entry(args->target, args->verdict, 0);
|
||||
if (entry == NULL)
|
||||
{
|
||||
goto errout_prepare_entry;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill in common details. */
|
||||
|
||||
ret = netlib_ipt_fillifname(entry, args->inifname, args->outifname);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("Failed to fill in interface names!\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (args->saddr != NULL)
|
||||
{
|
||||
ret = iptables_parse_ip(args->saddr, &entry->ip.src, &entry->ip.smsk,
|
||||
AF_INET);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("Failed to parse source address %s!\n", args->saddr);
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
if (args->daddr != NULL)
|
||||
{
|
||||
ret = iptables_parse_ip(args->daddr, &entry->ip.dst, &entry->ip.dmsk,
|
||||
AF_INET);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("Failed to parse destination address %s!\n", args->daddr);
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
entry->ip.proto = args->protocol;
|
||||
entry->ip.invflags = args->ipinv;
|
||||
|
||||
/* Finish command. */
|
||||
|
||||
ret = iptables_finish_command(args, &repl, entry);
|
||||
|
||||
errout:
|
||||
free(entry);
|
||||
free(repl);
|
||||
return ret;
|
||||
|
||||
errout_prepare_entry:
|
||||
printf("Failed to prepare entry!\n");
|
||||
ret = -ENOMEM;
|
||||
goto errout;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_apply
|
||||
*
|
||||
* Description:
|
||||
* Apply rules for corresponding table
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int iptables_apply(FAR const struct iptables_args_s *args,
|
||||
iptables_command_func_t command_func)
|
||||
{
|
||||
switch (args->cmd)
|
||||
{
|
||||
case COMMAND_FLUSH:
|
||||
return netlib_ipt_flush(TABLE_NAME_NAT, cmd.hook);
|
||||
return netlib_ipt_flush(args->table, args->hook);
|
||||
|
||||
case COMMAND_LIST:
|
||||
return iptables_list(TABLE_NAME_NAT, cmd.hook);
|
||||
return iptables_list(args->table, args->hook);
|
||||
|
||||
case COMMAND_POLICY:
|
||||
return netlib_ipt_policy(args->table, args->hook, args->verdict);
|
||||
|
||||
case COMMAND_DELETE:
|
||||
|
||||
/* Delete rule with rulenum can be done directly. */
|
||||
|
||||
if (args->rulenum > 0)
|
||||
{
|
||||
return iptables_finish_directly(args);
|
||||
}
|
||||
|
||||
/* Fall through. */
|
||||
|
||||
case COMMAND_APPEND:
|
||||
case COMMAND_INSERT:
|
||||
case COMMAND_DELETE:
|
||||
if (args->outifname->count == 0 &&
|
||||
!(cmd.cmd == COMMAND_DELETE && cmd.rulenum > 0))
|
||||
{
|
||||
printf("Table '" TABLE_NAME_NAT "' needs an out interface!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (args->target->count > 0 &&
|
||||
strcmp(args->target->sval[0], XT_MASQUERADE_TARGET))
|
||||
{
|
||||
printf("Only target '" XT_MASQUERADE_TARGET
|
||||
"' is supported for table '" TABLE_NAME_NAT "'!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return iptables_nat_command(&cmd, args->outifname->sval[0]);
|
||||
return command_func(args);
|
||||
|
||||
default:
|
||||
printf("No supported command specified!\n");
|
||||
@ -406,55 +483,40 @@ static int iptables_nat(FAR const struct iptables_args_s *args)
|
||||
int main(int argc, FAR char *argv[])
|
||||
{
|
||||
struct iptables_args_s args;
|
||||
int nerrors;
|
||||
int ret = 0;
|
||||
int ret = iptables_parse(&args, argc, argv);
|
||||
|
||||
args.table = arg_str1("t", "table", "table", "table to manipulate");
|
||||
|
||||
args.append_chain = arg_str0("A", "append", "chain",
|
||||
"Append a rule to chain");
|
||||
args.insert_chain = arg_str0("I", "insert", "chain",
|
||||
"Insert a rule to chain at rulenum "
|
||||
"(default = 1)");
|
||||
args.delete_chain = arg_str0("D", "delete", "chain",
|
||||
"Delete matching rule from chain");
|
||||
args.flush_chain = arg_str0("F", "flush", "chain",
|
||||
"Delete all rules in chain or all chains");
|
||||
args.list_chain = arg_str0("L", "list", "chain",
|
||||
"List all rules in chain or all chains");
|
||||
|
||||
args.rulenum = arg_int0(NULL, NULL, "rulenum", "Rule num (1=first)");
|
||||
|
||||
args.target = arg_str0("j", "jump", "target", "target for rule");
|
||||
args.outifname = arg_str0("o", "out-interface", "dev",
|
||||
"output network interface name");
|
||||
|
||||
args.end = arg_end(1);
|
||||
|
||||
/* The chain of -F or -L is optional. */
|
||||
|
||||
args.flush_chain->hdr.flag |= ARG_HASOPTVALUE;
|
||||
args.list_chain->hdr.flag |= ARG_HASOPTVALUE;
|
||||
|
||||
nerrors = arg_parse(argc, argv, (FAR void**)&args);
|
||||
if (nerrors != 0)
|
||||
if (ret < 0 || args.cmd == COMMAND_INVALID)
|
||||
{
|
||||
arg_print_errors(stderr, args.end, argv[0]);
|
||||
iptables_showusage(argv[0], (FAR void**)&args);
|
||||
iptables_showusage(argv[0]);
|
||||
return ret;
|
||||
}
|
||||
else if (strcmp(args.table->sval[0], TABLE_NAME_NAT) == 0)
|
||||
|
||||
#ifdef CONFIG_NET_IPFILTER
|
||||
if (args.table == NULL || strcmp(args.table, XT_TABLE_NAME_FILTER) == 0)
|
||||
{
|
||||
ret = iptables_nat(&args);
|
||||
args.table = XT_TABLE_NAME_FILTER;
|
||||
ret = iptables_apply(&args, iptables_filter_command);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("iptables got error on filter: %d!\n", ret);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef CONFIG_NET_NAT
|
||||
if (strcmp(args.table, TABLE_NAME_NAT) == 0)
|
||||
{
|
||||
ret = iptables_apply(&args, iptables_nat_command);
|
||||
if (ret < 0)
|
||||
{
|
||||
printf("iptables got error on NAT: %d!\n", ret);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
printf("Unknown table: %s\n", args.table->sval[0]);
|
||||
printf("Unknown table: %s\n", args.table);
|
||||
}
|
||||
|
||||
arg_freetable((FAR void **)&args, 1);
|
||||
return ret;
|
||||
}
|
||||
|
204
system/iptables/iptables.h
Normal file
204
system/iptables/iptables.h
Normal file
@ -0,0 +1,204 @@
|
||||
/****************************************************************************
|
||||
* apps/system/iptables/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 __APPS_SYSTEM_IPTABLES_IPTABLES_H
|
||||
#define __APPS_SYSTEM_IPTABLES_IPTABLES_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <nuttx/compiler.h>
|
||||
#include <nuttx/net/netfilter/netfilter.h>
|
||||
#include <nuttx/net/netfilter/nf_nat.h>
|
||||
#include <nuttx/net/netfilter/x_tables.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define INV_FLAG_STR(flag) ((flag) ? "!" : "")
|
||||
|
||||
/****************************************************************************
|
||||
* Public Type Definitions
|
||||
****************************************************************************/
|
||||
|
||||
enum iptables_command_e
|
||||
{
|
||||
COMMAND_INVALID = 0,
|
||||
COMMAND_APPEND,
|
||||
COMMAND_INSERT,
|
||||
COMMAND_DELETE,
|
||||
COMMAND_FLUSH,
|
||||
COMMAND_LIST,
|
||||
COMMAND_POLICY
|
||||
};
|
||||
|
||||
struct iptables_args_s
|
||||
{
|
||||
enum iptables_command_e cmd;
|
||||
enum nf_inet_hooks hook;
|
||||
|
||||
FAR const char *table;
|
||||
|
||||
FAR const char *inifname;
|
||||
FAR const char *outifname;
|
||||
FAR const char *target;
|
||||
|
||||
FAR const char *saddr;
|
||||
FAR const char *daddr;
|
||||
FAR const char *sport;
|
||||
FAR const char *dport;
|
||||
FAR const char *icmp_type;
|
||||
|
||||
int8_t verdict;
|
||||
int8_t rulenum;
|
||||
uint8_t protocol;
|
||||
|
||||
/* invert flags */
|
||||
|
||||
uint8_t ipinv;
|
||||
uint8_t tcpudpinv;
|
||||
uint8_t icmpinv;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_parse
|
||||
*
|
||||
* Description:
|
||||
* Parse args from arg list
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 on success, or a negative error code on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int iptables_parse(FAR struct iptables_args_s *args,
|
||||
int argc, FAR char *argv[]);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_parse_ip
|
||||
*
|
||||
* Description:
|
||||
* Parse ip string into address and mask
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 on success, or a negative error code on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int iptables_parse_ip(FAR const char *str, FAR void *addr, FAR void *mask,
|
||||
uint8_t family);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_parse_ports
|
||||
*
|
||||
* Description:
|
||||
* Parse port string into min/max port, NULL for ALL
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 on success, or a negative error code on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int iptables_parse_ports(FAR const char *str, uint16_t ports[2]);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_parse_icmp
|
||||
*
|
||||
* Description:
|
||||
* Parse icmp type string into type number
|
||||
*
|
||||
* Returned Value:
|
||||
* Type code on success, or a negative error code on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int iptables_parse_icmp(FAR const char *str);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_showusage
|
||||
*
|
||||
* Description:
|
||||
* Show usage of the iptables program
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void iptables_showusage(FAR const char *progname);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_hook2str
|
||||
*
|
||||
* Description:
|
||||
* Get hook name from hook number
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR const char *iptables_hook2str(enum nf_inet_hooks hook);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_target2str
|
||||
*
|
||||
* Description:
|
||||
* Get target name from target structure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR const char *iptables_target2str(FAR const struct xt_entry_target *tgt);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_proto2str
|
||||
*
|
||||
* Description:
|
||||
* Get protocol name from protocol number
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR const char *iptables_proto2str(uint8_t proto);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_iface2str
|
||||
*
|
||||
* Description:
|
||||
* Get interface name from interface string
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#define iptables_iface2str(iface) ((iface)[0] != '\0' ? (iface) : "any")
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_match2str
|
||||
*
|
||||
* Description:
|
||||
* Get match details from match structure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR const char *iptables_match2str(FAR const struct xt_entry_match *match);
|
||||
|
||||
#endif /* __APPS_SYSTEM_IPTABLES_IPTABLES_H */
|
828
system/iptables/iptables_utils.c
Normal file
828
system/iptables/iptables_utils.c
Normal file
@ -0,0 +1,828 @@
|
||||
/****************************************************************************
|
||||
* apps/system/iptables/iptables_utils.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 <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include <nuttx/net/netfilter/ip_tables.h>
|
||||
|
||||
#include "iptables.h"
|
||||
#include "netutils/netlib.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define MATCH_BUFSIZE sizeof("tcp spts:!65535:65535 dpts:!65535:65535")
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static FAR const char *g_hooknames[] =
|
||||
{
|
||||
"PREROUTING", "INPUT", "FORWARD", "OUTPUT", "POSTROUTING"
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_parse_cmd
|
||||
*
|
||||
* Description:
|
||||
* Get command from string
|
||||
*
|
||||
* Return Value:
|
||||
* true if success, false if failed
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static bool iptables_parse_cmd(FAR const char *str,
|
||||
FAR enum iptables_command_e *command)
|
||||
{
|
||||
if (strcmp(str, "-A") == 0 || strcmp(str, "--append") == 0)
|
||||
{
|
||||
*command = COMMAND_APPEND;
|
||||
}
|
||||
else if (strcmp(str, "-D") == 0 || strcmp(str, "--delete") == 0)
|
||||
{
|
||||
*command = COMMAND_DELETE;
|
||||
}
|
||||
else if (strcmp(str, "-I") == 0 || strcmp(str, "--insert") == 0)
|
||||
{
|
||||
*command = COMMAND_INSERT;
|
||||
}
|
||||
else if (strcmp(str, "-F") == 0 || strcmp(str, "--flush") == 0)
|
||||
{
|
||||
*command = COMMAND_FLUSH;
|
||||
}
|
||||
else if (strcmp(str, "-L") == 0 || strcmp(str, "--list") == 0)
|
||||
{
|
||||
*command = COMMAND_LIST;
|
||||
}
|
||||
else if (strcmp(str, "-P") == 0 || strcmp(str, "--policy") == 0)
|
||||
{
|
||||
*command = COMMAND_POLICY;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_parse_hook
|
||||
*
|
||||
* Description:
|
||||
* Get hook from string
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static enum nf_inet_hooks iptables_parse_hook(FAR const char *str)
|
||||
{
|
||||
unsigned int hook;
|
||||
|
||||
if (str == NULL || strlen(str) == 0) /* Might be no input (-F/-L). */
|
||||
{
|
||||
return NF_INET_NUMHOOKS;
|
||||
}
|
||||
|
||||
for (hook = 0; hook < NF_INET_NUMHOOKS; hook++)
|
||||
{
|
||||
if (strcmp(str, g_hooknames[hook]) == 0)
|
||||
{
|
||||
return hook;
|
||||
}
|
||||
}
|
||||
|
||||
return NF_INET_NUMHOOKS; /* Failed to parse. */
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_parse_proto
|
||||
*
|
||||
* Description:
|
||||
* Get protocol number from protocol name
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static uint8_t iptables_parse_proto(FAR const char *proto)
|
||||
{
|
||||
if (strcmp(proto, "all") == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (strcmp(proto, "esp") == 0)
|
||||
{
|
||||
return IPPROTO_ESP;
|
||||
}
|
||||
else if (strcmp(proto, "icmp") == 0)
|
||||
{
|
||||
return IPPROTO_ICMP;
|
||||
}
|
||||
else if (strcmp(proto, "tcp") == 0)
|
||||
{
|
||||
return IPPROTO_TCP;
|
||||
}
|
||||
else if (strcmp(proto, "udp") == 0)
|
||||
{
|
||||
return IPPROTO_UDP;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Unknown protocol: %s\n", proto);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_parse_target
|
||||
*
|
||||
* Description:
|
||||
* Get target name from string
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static FAR const char *iptables_parse_target(FAR const char *str,
|
||||
FAR int8_t *verdict)
|
||||
{
|
||||
if (strcmp(str, "ACCEPT") == 0)
|
||||
{
|
||||
*verdict = -NF_ACCEPT - 1;
|
||||
return XT_STANDARD_TARGET;
|
||||
}
|
||||
else if (strcmp(str, "DROP") == 0)
|
||||
{
|
||||
*verdict = -NF_DROP - 1;
|
||||
return XT_STANDARD_TARGET;
|
||||
}
|
||||
else
|
||||
{
|
||||
*verdict = 0;
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_parse
|
||||
*
|
||||
* Description:
|
||||
* Parse args from arg list
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 on success, or a negative error code on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int iptables_parse(FAR struct iptables_args_s *args,
|
||||
int argc, FAR char *argv[])
|
||||
{
|
||||
bool inv = false;
|
||||
int i;
|
||||
|
||||
bzero(args, sizeof(struct iptables_args_s));
|
||||
args->hook = NF_INET_NUMHOOKS;
|
||||
|
||||
/* Parse arguments. */
|
||||
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
/* Table */
|
||||
|
||||
if (strcmp(argv[i], "-t") == 0 || strcmp(argv[i], "--table") == 0)
|
||||
{
|
||||
if (++i >= argc)
|
||||
{
|
||||
printf("Missing table name!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
args->table = argv[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Commands */
|
||||
|
||||
if (iptables_parse_cmd(argv[i], &args->cmd))
|
||||
{
|
||||
/* The chain name is following the command */
|
||||
|
||||
if (i + 1 < argc)
|
||||
{
|
||||
args->hook = iptables_parse_hook(argv[i + 1]);
|
||||
}
|
||||
|
||||
if (args->hook != NF_INET_NUMHOOKS)
|
||||
{
|
||||
i++; /* Success to parse as hook. */
|
||||
}
|
||||
else if (args->cmd != COMMAND_LIST && args->cmd != COMMAND_FLUSH)
|
||||
{
|
||||
printf("Wrong chain name %s!\n", argv[i + 1]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Insert or delete command may have rule number */
|
||||
|
||||
if (args->cmd == COMMAND_INSERT || args->cmd == COMMAND_DELETE)
|
||||
{
|
||||
if (i + 1 < argc)
|
||||
{
|
||||
args->rulenum = atoi(argv[i + 1]);
|
||||
}
|
||||
|
||||
if (args->rulenum >= 1)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
else if (args->cmd == COMMAND_INSERT)
|
||||
{
|
||||
/* Default insert position is 1 */
|
||||
|
||||
args->rulenum = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Policy command should have target */
|
||||
|
||||
if (args->cmd == COMMAND_POLICY)
|
||||
{
|
||||
if (++i >= argc)
|
||||
{
|
||||
printf("Missing target name!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
args->target = iptables_parse_target(argv[i], &args->verdict);
|
||||
if (args->verdict == 0)
|
||||
{
|
||||
printf("Invalid target name %s!\n", argv[i]);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Target */
|
||||
|
||||
if (strcmp(argv[i], "-j") == 0 || strcmp(argv[i], "--jump") == 0)
|
||||
{
|
||||
if (++i >= argc)
|
||||
{
|
||||
printf("Missing target name!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
args->target = iptables_parse_target(argv[i], &args->verdict);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Invert */
|
||||
|
||||
if (strcmp(argv[i], "!") == 0)
|
||||
{
|
||||
inv = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Protocol */
|
||||
|
||||
if (strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "--protocol") == 0)
|
||||
{
|
||||
if (++i >= argc)
|
||||
{
|
||||
printf("Missing protocol name!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
args->protocol = iptables_parse_proto(argv[i]);
|
||||
if (inv)
|
||||
{
|
||||
args->ipinv |= IPT_INV_PROTO;
|
||||
inv = false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Source address */
|
||||
|
||||
if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--source") == 0)
|
||||
{
|
||||
if (++i >= argc)
|
||||
{
|
||||
printf("Missing source address!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
args->saddr = argv[i];
|
||||
if (inv)
|
||||
{
|
||||
args->ipinv |= IPT_INV_SRCIP;
|
||||
inv = false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Destination address */
|
||||
|
||||
if (strcmp(argv[i], "-d") == 0 ||
|
||||
strcmp(argv[i], "--destination") == 0)
|
||||
{
|
||||
if (++i >= argc)
|
||||
{
|
||||
printf("Missing destination address!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
args->daddr = argv[i];
|
||||
if (inv)
|
||||
{
|
||||
args->ipinv |= IPT_INV_DSTIP;
|
||||
inv = false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Source port */
|
||||
|
||||
if (strcmp(argv[i], "--sport") == 0 ||
|
||||
strcmp(argv[i], "--source-port") == 0)
|
||||
{
|
||||
if (++i >= argc)
|
||||
{
|
||||
printf("Missing source port!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
args->sport = argv[i];
|
||||
if (inv)
|
||||
{
|
||||
args->tcpudpinv |= XT_TCP_INV_SRCPT;
|
||||
inv = false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Destination port */
|
||||
|
||||
if (strcmp(argv[i], "--dport") == 0 ||
|
||||
strcmp(argv[i], "--destination-port") == 0)
|
||||
{
|
||||
if (++i >= argc)
|
||||
{
|
||||
printf("Missing destination port!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
args->dport = argv[i];
|
||||
if (inv)
|
||||
{
|
||||
args->tcpudpinv |= XT_TCP_INV_DSTPT;
|
||||
inv = false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* In interface */
|
||||
|
||||
if (strcmp(argv[i], "-i") == 0 ||
|
||||
strcmp(argv[i], "--in-interface") == 0)
|
||||
{
|
||||
if (++i >= argc)
|
||||
{
|
||||
printf("Missing in-interface name!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
args->inifname = argv[i];
|
||||
if (inv)
|
||||
{
|
||||
args->ipinv |= IPT_INV_VIA_IN;
|
||||
inv = false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Out interface */
|
||||
|
||||
if (strcmp(argv[i], "-o") == 0 ||
|
||||
strcmp(argv[i], "--out-interface") == 0)
|
||||
{
|
||||
if (++i >= argc)
|
||||
{
|
||||
printf("Missing out-interface name!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
args->outifname = argv[i];
|
||||
if (inv)
|
||||
{
|
||||
args->ipinv |= IPT_INV_VIA_OUT;
|
||||
inv = false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* ICMP type */
|
||||
|
||||
if (strcmp(argv[i], "--icmp-type") == 0)
|
||||
{
|
||||
if (++i >= argc)
|
||||
{
|
||||
printf("Missing ICMP type!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
args->icmp_type = argv[i];
|
||||
if (inv)
|
||||
{
|
||||
args->icmpinv |= IPT_ICMP_INV;
|
||||
inv = false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_parse_ip
|
||||
*
|
||||
* Description:
|
||||
* Parse ip string into address and mask
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 on success, or a negative error code on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int iptables_parse_ip(FAR const char *str, FAR void *addr, FAR void *mask,
|
||||
uint8_t family)
|
||||
{
|
||||
FAR char *ch = strchr(str, '/');
|
||||
|
||||
if (family != AF_INET && family != AF_INET6)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(mask, 0xff, family == AF_INET ? 4 : 16);
|
||||
|
||||
if (ch != NULL)
|
||||
{
|
||||
FAR char *endp;
|
||||
int prefixlen;
|
||||
|
||||
*ch++ = 0;
|
||||
prefixlen = strtol(ch, &endp, 10);
|
||||
|
||||
if (*endp != '\0')
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
if (family == AF_INET)
|
||||
{
|
||||
FAR in_addr_t *mask4 = mask;
|
||||
|
||||
if (prefixlen > 32 || prefixlen < 0)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*mask4 <<= 32 - prefixlen;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
if (family == AF_INET6)
|
||||
{
|
||||
if (prefixlen > 128 || prefixlen < 0)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
netlib_prefix2ipv6netmask(atoi(ch), mask);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (inet_pton(family, str, addr) != OK)
|
||||
{
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_parse_ports
|
||||
*
|
||||
* Description:
|
||||
* Parse port string into min/max port, NULL for ALL
|
||||
*
|
||||
* Returned Value:
|
||||
* 0 on success, or a negative error code on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int iptables_parse_ports(FAR const char *str, uint16_t ports[2])
|
||||
{
|
||||
FAR char *endp;
|
||||
int port;
|
||||
|
||||
/* Maybe sports has value but dports is NULL, then we set NULL to ALL. */
|
||||
|
||||
if (str == NULL)
|
||||
{
|
||||
ports[0] = 0;
|
||||
ports[1] = 65535;
|
||||
return OK;
|
||||
}
|
||||
|
||||
port = strtol(str, &endp, 10);
|
||||
if (*endp == '\0' && port >= 0 && port <= 65535)
|
||||
{
|
||||
ports[0] = ports[1] = port;
|
||||
return OK;
|
||||
}
|
||||
|
||||
if (*endp == ':' && port >= 0 && port <= 65535)
|
||||
{
|
||||
ports[0] = port;
|
||||
port = strtol(endp + 1, &endp, 10);
|
||||
if (*endp == '\0' && port >= 0 && port <= 65535)
|
||||
{
|
||||
ports[1] = port;
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_parse_icmp
|
||||
*
|
||||
* Description:
|
||||
* Parse icmp type string into type number
|
||||
*
|
||||
* Returned Value:
|
||||
* Type code on success, or a negative error code on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int iptables_parse_icmp(FAR const char *str)
|
||||
{
|
||||
FAR char *endp;
|
||||
int type;
|
||||
|
||||
type = strtol(str, &endp, 10);
|
||||
if (*endp == '\0' && type >= 0 && type <= 255)
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
/* TODO: Support string description of icmp type, e.g. "echo-request" */
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_showusage
|
||||
*
|
||||
* Description:
|
||||
* Show usage of the iptables program
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void iptables_showusage(FAR const char *progname)
|
||||
{
|
||||
/* Format: [!] --source -s address <description> */
|
||||
|
||||
const char fmt[] = "%3s %-15s %-2s %-16s %s\n";
|
||||
|
||||
printf("USAGE: %s -t table -[AD] chain rule-specification\n", progname);
|
||||
printf(" %s -t table -I chain [rulenum] rule-specification\n",
|
||||
progname);
|
||||
printf(" %s -t table -D chain rulenum\n", progname);
|
||||
printf(" %s -t table -P chain target\n", progname);
|
||||
printf(" %s -t table -[FL] [chain]\n", progname);
|
||||
|
||||
printf("\nCommands:\n");
|
||||
printf(fmt, "", "--append", "-A", "chain", "Append a rule to chain");
|
||||
printf(fmt, "", "--insert", "-I", "chain [rulenum]",
|
||||
"Insert a rule to chain at rulenum (default = 1)");
|
||||
printf(fmt, "", "--delete", "-D", "chain [rulenum]",
|
||||
"Delete matching rule from chain");
|
||||
printf(fmt, "", "--policy", "-P", "chain target",
|
||||
"Set policy for chain to target");
|
||||
printf(fmt, "", "--flush", "-F", "[chain]",
|
||||
"Delete all rules in chain or all chains");
|
||||
printf(fmt, "", "--list", "-L", "[chain]",
|
||||
"List all rules in chain or all chains");
|
||||
|
||||
printf("\nOptions:\n");
|
||||
printf(fmt, " ", "--table", "-t", "table",
|
||||
"Table to manipulate (default: filter)");
|
||||
printf(fmt, " ", "--jump", "-j", "target", "Target for rule");
|
||||
printf(fmt, "[!]", "--in-interface", "-i", "dev",
|
||||
"Input network interface name");
|
||||
printf(fmt, "[!]", "--out-interface", "-o", "dev",
|
||||
"Output network interface name");
|
||||
printf(fmt, "[!]", "--source", "-s", "address[/mask]", "Source address");
|
||||
printf(fmt, "[!]", "--destination", "-d", "address[/mask]",
|
||||
"Destination address");
|
||||
printf(fmt, "[!]", "--protocol", "-p", "proto",
|
||||
"Protocol (tcp, udp, icmp, esp, all)");
|
||||
printf(fmt, "[!]", "--source-port,--sport", "", "", "");
|
||||
printf(fmt, " ", "", "", "port[:port]", "Source port");
|
||||
printf(fmt, "[!]", "--destination-port,--dport", "", "", "");
|
||||
printf(fmt, " ", "", "", "port[:port]", "Destination port");
|
||||
printf(fmt, "[!]", "--icmp-type", "", "type", "ICMP type");
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_hook2str
|
||||
*
|
||||
* Description:
|
||||
* Get hook name from hook number
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR const char *iptables_hook2str(enum nf_inet_hooks hook)
|
||||
{
|
||||
if (hook < NF_INET_NUMHOOKS)
|
||||
{
|
||||
return g_hooknames[hook];
|
||||
}
|
||||
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_target2str
|
||||
*
|
||||
* Description:
|
||||
* Get target name from target structure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR const char *iptables_target2str(FAR const struct xt_entry_target *tgt)
|
||||
{
|
||||
if (strcmp(tgt->u.user.name, XT_STANDARD_TARGET) == 0)
|
||||
{
|
||||
int verdict = ((FAR const struct xt_standard_target *)tgt)->verdict;
|
||||
verdict = -verdict - 1;
|
||||
|
||||
if (verdict == NF_ACCEPT)
|
||||
{
|
||||
return "ACCEPT";
|
||||
}
|
||||
else if (verdict == NF_DROP)
|
||||
{
|
||||
return "DROP";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
return tgt->u.user.name;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_proto2str
|
||||
*
|
||||
* Description:
|
||||
* Get protocol name from protocol number
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR const char *iptables_proto2str(uint8_t proto)
|
||||
{
|
||||
switch (proto)
|
||||
{
|
||||
case 0:
|
||||
return "all";
|
||||
|
||||
case IPPROTO_ICMP:
|
||||
return "icmp";
|
||||
|
||||
case IPPROTO_TCP:
|
||||
return "tcp";
|
||||
|
||||
case IPPROTO_UDP:
|
||||
return "udp";
|
||||
|
||||
case IPPROTO_ESP:
|
||||
return "esp";
|
||||
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iptables_match2str
|
||||
*
|
||||
* Description:
|
||||
* Get match details from match structure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR const char *iptables_match2str(FAR const struct xt_entry_match *match)
|
||||
{
|
||||
static char s_buf[MATCH_BUFSIZE];
|
||||
|
||||
if (match == NULL)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
if (strcmp(match->u.user.name, XT_MATCH_NAME_TCP) == 0)
|
||||
{
|
||||
FAR struct xt_tcp *tcp = (FAR struct xt_tcp *)(match + 1);
|
||||
|
||||
snprintf(s_buf, MATCH_BUFSIZE,
|
||||
"tcp spts:%s%u:%u dpts:%s%u:%u",
|
||||
INV_FLAG_STR(tcp->invflags & XT_TCP_INV_SRCPT),
|
||||
tcp->spts[0], tcp->spts[1],
|
||||
INV_FLAG_STR(tcp->invflags & XT_TCP_INV_DSTPT),
|
||||
tcp->dpts[0], tcp->dpts[1]);
|
||||
}
|
||||
else if (strcmp(match->u.user.name, XT_MATCH_NAME_UDP) == 0)
|
||||
{
|
||||
FAR struct xt_udp *udp = (FAR struct xt_udp *)(match + 1);
|
||||
|
||||
snprintf(s_buf, MATCH_BUFSIZE,
|
||||
"udp spts:%s%u:%u dpts:%s%u:%u",
|
||||
INV_FLAG_STR(udp->invflags & XT_UDP_INV_SRCPT),
|
||||
udp->spts[0], udp->spts[1],
|
||||
INV_FLAG_STR(udp->invflags & XT_UDP_INV_DSTPT),
|
||||
udp->dpts[0], udp->dpts[1]);
|
||||
}
|
||||
else if (strcmp(match->u.user.name, XT_MATCH_NAME_ICMP) == 0)
|
||||
{
|
||||
FAR struct ipt_icmp *icmp = (FAR struct ipt_icmp *)(match + 1);
|
||||
|
||||
snprintf(s_buf, MATCH_BUFSIZE,
|
||||
"icmp %stype %u",
|
||||
INV_FLAG_STR(icmp->invflags & IPT_ICMP_INV),
|
||||
icmp->type);
|
||||
}
|
||||
else
|
||||
{
|
||||
return match->u.user.name;
|
||||
}
|
||||
|
||||
return s_buf;
|
||||
}
|
Loading…
Reference in New Issue
Block a user