summaryrefslogtreecommitdiffstats
path: root/iptables/xtables-eb-translate.c
diff options
context:
space:
mode:
authorPhil Sutter <phil@nwl.cc>2023-11-09 16:59:51 +0100
committerPhil Sutter <phil@nwl.cc>2023-12-05 16:35:37 +0100
commit58d364c7120b515d80482c99586dd815653be59c (patch)
tree47bf49aa4942bfd1f0716ef60cc54ef1142f3a6c /iptables/xtables-eb-translate.c
parent12d780775b5e34bcc2e0c34c550a6d5d96028628 (diff)
ebtables: Use do_parse() from xshared
Drop the custom commandline parsers from ebtables and ebtables-translate, extend and use the shared one instead. ebtables gains a few new features from doing this: - Rule counters may be specified in the '-c N,M' syntax - Support for --replace command - Support for --list-rules command - Zero individual rules There is one known regression in this patch, namely maximum chain name length shrinks to 28 characters (from 32). Since this limit changed for iptables in the past as well (e.g. with commit 5429b41c2bb4a), assume nobody really relies upon it anyway. Signed-off-by: Phil Sutter <phil@nwl.cc>
Diffstat (limited to 'iptables/xtables-eb-translate.c')
-rw-r--r--iptables/xtables-eb-translate.c477
1 files changed, 55 insertions, 422 deletions
diff --git a/iptables/xtables-eb-translate.c b/iptables/xtables-eb-translate.c
index a2ab318c..fbeff74f 100644
--- a/iptables/xtables-eb-translate.c
+++ b/iptables/xtables-eb-translate.c
@@ -21,61 +21,10 @@
#include "nft-bridge.h"
#include "nft.h"
#include "nft-shared.h"
-/*
- * From include/ebtables_u.h
- */
-#define ebt_check_option2(flags, mask) EBT_CHECK_OPTION(flags, mask)
-extern int ebt_invert;
-
-static int ebt_check_inverse2(const char option[], int argc, char **argv)
-{
- if (!option)
- return ebt_invert;
- if (strcmp(option, "!") == 0) {
- if (ebt_invert == 1)
- xtables_error(PARAMETER_PROBLEM,
- "Double use of '!' not allowed");
- if (optind >= argc)
- optarg = NULL;
- else
- optarg = argv[optind];
- optind++;
- ebt_invert = 1;
- return 1;
- }
- return ebt_invert;
-}
-
-/*
- * Glue code to use libxtables
- */
-static int parse_rule_number(const char *rule)
-{
- unsigned int rule_nr;
-
- if (!xtables_strtoui(rule, NULL, &rule_nr, 1, INT_MAX))
- xtables_error(PARAMETER_PROBLEM,
- "Invalid rule number `%s'", rule);
-
- return rule_nr;
-}
-
-/*
- * The original ebtables parser
- */
-
-/* Checks whether a command has already been specified */
-#define OPT_COMMANDS (flags & OPT_COMMAND || flags & OPT_ZERO)
-
-/* Default command line options. Do not mess around with the already
- * assigned numbers unless you know what you are doing */
-extern struct option ebt_original_options[];
-#define opts ebtables_globals.opts
#define prog_name ebtables_globals.program_name
-#define prog_vers ebtables_globals.program_version
-static void print_help(void)
+static void print_help(struct iptables_command_state *cs)
{
fprintf(stderr, "%s: Translate ebtables command to nft syntax\n"
"no side effects occur, the translated command is written "
@@ -85,46 +34,6 @@ static void print_help(void)
exit(0);
}
-static int parse_rule_range(const char *argv, int *rule_nr, int *rule_nr_end)
-{
- char *colon = strchr(argv, ':'), *buffer;
-
- if (colon) {
- *colon = '\0';
- if (*(colon + 1) == '\0')
- *rule_nr_end = -1; /* Until the last rule */
- else {
- *rule_nr_end = strtol(colon + 1, &buffer, 10);
- if (*buffer != '\0' || *rule_nr_end == 0)
- return -1;
- }
- }
- if (colon == argv)
- *rule_nr = 1; /* Beginning with the first rule */
- else {
- *rule_nr = strtol(argv, &buffer, 10);
- if (*buffer != '\0' || *rule_nr == 0)
- return -1;
- }
- if (!colon)
- *rule_nr_end = *rule_nr;
- return 0;
-}
-
-static void ebtables_parse_interface(const char *arg, char *vianame)
-{
- unsigned char mask[IFNAMSIZ];
- char *c;
-
- xtables_parse_interface(arg, vianame, mask);
-
- if ((c = strchr(vianame, '+'))) {
- if (*(c + 1) != '\0')
- xtables_error(PARAMETER_PROBLEM,
- "Spurious characters after '+' wildcard");
- }
-}
-
static void print_ebt_cmd(int argc, char *argv[])
{
int i;
@@ -158,347 +67,35 @@ static int nft_rule_eb_xlate_add(struct nft_handle *h, const struct xt_cmd_parse
static int do_commandeb_xlate(struct nft_handle *h, int argc, char *argv[], char **table)
{
- char *buffer;
- int c, i;
- int rule_nr = 0;
- int rule_nr_end = 0;
- int ret = 0;
- unsigned int flags = 0;
struct iptables_command_state cs = {
.argv = argv,
+ .jumpto = "",
.eb.bitmask = EBT_NOPROTO,
};
- char command = 'h';
- const char *chain = NULL;
- int selected_chain = -1;
- struct xtables_rule_match *xtrm_i;
- struct ebt_match *match;
struct xt_cmd_parse p = {
.table = *table,
+ .rule_ranges = true,
+ .ops = &h->ops->cmd_parse,
};
- bool table_set = false;
-
- /* prevent getopt to spoil our error reporting */
- opterr = false;
-
- printf("nft ");
- /* Getopt saves the day */
- while ((c = getopt_long(argc, argv,
- "-:A:D:I:N:E:X::L::Z::F::P:Vhi:o:j:c:p:s:d:t:M:", opts, NULL)) != -1) {
- cs.c = c;
- switch (c) {
- case 'A': /* Add a rule */
- case 'D': /* Delete a rule */
- case 'P': /* Define policy */
- case 'I': /* Insert a rule */
- case 'N': /* Make a user defined chain */
- case 'E': /* Rename chain */
- case 'X': /* Delete chain */
- /* We allow -N chainname -P policy */
- /* XXX: Not in ebtables-compat */
- if (command == 'N' && c == 'P') {
- command = c;
- optind--; /* No table specified */
- break;
- }
- if (OPT_COMMANDS)
- xtables_error(PARAMETER_PROBLEM,
- "Multiple commands are not allowed");
- command = c;
- chain = optarg;
- selected_chain = ebt_get_current_chain(chain);
- p.chain = chain;
- flags |= OPT_COMMAND;
-
- if (c == 'N') {
- printf("add chain bridge %s %s\n", p.table, p.chain);
- ret = 1;
- break;
- } else if (c == 'X') {
- printf("delete chain bridge %s %s\n", p.table, p.chain);
- ret = 1;
- break;
- }
-
- if (c == 'E') {
- break;
- } else if (c == 'D' && optind < argc && (argv[optind][0] != '-' || (argv[optind][1] >= '0' && argv[optind][1] <= '9'))) {
- if (optind != argc - 1)
- xtables_error(PARAMETER_PROBLEM,
- "No extra options allowed with -D start_nr[:end_nr]");
- if (parse_rule_range(argv[optind], &rule_nr, &rule_nr_end))
- xtables_error(PARAMETER_PROBLEM,
- "Problem with the specified rule number(s) '%s'", argv[optind]);
- optind++;
- } else if (c == 'I') {
- if (optind >= argc || (argv[optind][0] == '-' && (argv[optind][1] < '0' || argv[optind][1] > '9')))
- rule_nr = 1;
- else {
- rule_nr = parse_rule_number(argv[optind]);
- optind++;
- }
- p.rulenum = rule_nr;
- } else if (c == 'P') {
- break;
- }
- break;
- case 'L': /* List */
- printf("list table bridge %s\n", p.table);
- ret = 1;
- break;
- case 'F': /* Flush */
- case 'Z': /* Zero counters */
- if (c == 'Z') {
- if ((flags & OPT_ZERO) || (flags & OPT_COMMAND && command != 'L'))
-print_zero:
- xtables_error(PARAMETER_PROBLEM,
- "Command -Z only allowed together with command -L");
- flags |= OPT_ZERO;
- } else {
- if (flags & OPT_COMMAND)
- xtables_error(PARAMETER_PROBLEM,
- "Multiple commands are not allowed");
- command = c;
- flags |= OPT_COMMAND;
- if (flags & OPT_ZERO && c != 'L')
- goto print_zero;
- }
- break;
- case 'V': /* Version */
- if (OPT_COMMANDS)
- xtables_error(PARAMETER_PROBLEM,
- "Multiple commands are not allowed");
- printf("%s %s\n", prog_name, prog_vers);
- exit(0);
- case 'h':
- if (OPT_COMMANDS)
- xtables_error(PARAMETER_PROBLEM,
- "Multiple commands are not allowed");
- print_help();
- break;
- case 't': /* Table */
- if (OPT_COMMANDS)
- xtables_error(PARAMETER_PROBLEM,
- "Please put the -t option first");
- if (table_set)
- xtables_error(PARAMETER_PROBLEM,
- "Multiple use of same option not allowed");
- if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
- xtables_error(PARAMETER_PROBLEM,
- "Table name length cannot exceed %d characters",
- EBT_TABLE_MAXNAMELEN - 1);
- *table = optarg;
- p.table = optarg;
- table_set = true;
- break;
- case 'i': /* Input interface */
- case 15 : /* Logical input interface */
- case 'o': /* Output interface */
- case 16 : /* Logical output interface */
- case 'j': /* Target */
- case 'p': /* Net family protocol */
- case 's': /* Source mac */
- case 'd': /* Destination mac */
- case 'c': /* Set counters */
- if (!OPT_COMMANDS)
- xtables_error(PARAMETER_PROBLEM,
- "No command specified");
- if (command != 'A' && command != 'D' && command != 'I')
- xtables_error(PARAMETER_PROBLEM,
- "Command and option do not match");
- if (c == 'i') {
- ebt_check_option2(&flags, OPT_VIANAMEIN);
- if (selected_chain > 2 && selected_chain < NF_BR_BROUTING)
- xtables_error(PARAMETER_PROBLEM,
- "Use -i only in INPUT, FORWARD, PREROUTING and BROUTING chains");
- if (ebt_check_inverse2(optarg, argc, argv))
- cs.eb.invflags |= EBT_IIN;
-
- ebtables_parse_interface(optarg, cs.eb.in);
- break;
- } else if (c == 15) {
- ebt_check_option2(&flags, OPT_LOGICALIN);
- if (selected_chain > 2 && selected_chain < NF_BR_BROUTING)
- xtables_error(PARAMETER_PROBLEM,
- "Use --logical-in only in INPUT, FORWARD, PREROUTING and BROUTING chains");
- if (ebt_check_inverse2(optarg, argc, argv))
- cs.eb.invflags |= EBT_ILOGICALIN;
-
- ebtables_parse_interface(optarg, cs.eb.logical_in);
- break;
- } else if (c == 'o') {
- ebt_check_option2(&flags, OPT_VIANAMEOUT);
- if (selected_chain < 2 || selected_chain == NF_BR_BROUTING)
- xtables_error(PARAMETER_PROBLEM,
- "Use -o only in OUTPUT, FORWARD and POSTROUTING chains");
- if (ebt_check_inverse2(optarg, argc, argv))
- cs.eb.invflags |= EBT_IOUT;
-
- ebtables_parse_interface(optarg, cs.eb.out);
- break;
- } else if (c == 16) {
- ebt_check_option2(&flags, OPT_LOGICALOUT);
- if (selected_chain < 2 || selected_chain == NF_BR_BROUTING)
- xtables_error(PARAMETER_PROBLEM,
- "Use --logical-out only in OUTPUT, FORWARD and POSTROUTING chains");
- if (ebt_check_inverse2(optarg, argc, argv))
- cs.eb.invflags |= EBT_ILOGICALOUT;
-
- ebtables_parse_interface(optarg, cs.eb.logical_out);
- break;
- } else if (c == 'j') {
- ebt_check_option2(&flags, OPT_JUMP);
- if (strcmp(optarg, "CONTINUE") != 0) {
- command_jump(&cs, optarg);
- }
- break;
- } else if (c == 's') {
- ebt_check_option2(&flags, OPT_SOURCE);
- if (ebt_check_inverse2(optarg, argc, argv))
- cs.eb.invflags |= EBT_ISOURCE;
-
- if (xtables_parse_mac_and_mask(optarg,
- cs.eb.sourcemac,
- cs.eb.sourcemsk))
- xtables_error(PARAMETER_PROBLEM, "Problem with specified source mac '%s'", optarg);
- cs.eb.bitmask |= EBT_SOURCEMAC;
- break;
- } else if (c == 'd') {
- ebt_check_option2(&flags, OPT_DESTINATION);
- if (ebt_check_inverse2(optarg, argc, argv))
- cs.eb.invflags |= EBT_IDEST;
-
- if (xtables_parse_mac_and_mask(optarg,
- cs.eb.destmac,
- cs.eb.destmsk))
- xtables_error(PARAMETER_PROBLEM, "Problem with specified destination mac '%s'", optarg);
- cs.eb.bitmask |= EBT_DESTMAC;
- break;
- } else if (c == 'c') {
- ebt_check_option2(&flags, OPT_COUNTERS);
- if (ebt_check_inverse2(optarg, argc, argv))
- xtables_error(PARAMETER_PROBLEM,
- "Unexpected '!' after -c");
- if (optind >= argc || optarg[0] == '-' || argv[optind][0] == '-')
- xtables_error(PARAMETER_PROBLEM,
- "Option -c needs 2 arguments");
-
- cs.counters.pcnt = strtoull(optarg, &buffer, 10);
- if (*buffer != '\0')
- xtables_error(PARAMETER_PROBLEM,
- "Packet counter '%s' invalid",
- optarg);
- cs.counters.bcnt = strtoull(argv[optind], &buffer, 10);
- if (*buffer != '\0')
- xtables_error(PARAMETER_PROBLEM,
- "Packet counter '%s' invalid",
- argv[optind]);
- optind++;
- break;
- }
- ebt_check_option2(&flags, OPT_PROTOCOL);
- if (ebt_check_inverse2(optarg, argc, argv))
- cs.eb.invflags |= EBT_IPROTO;
+ struct xtables_args args = {
+ .family = h->family,
+ };
+ int ret = 0;
- cs.eb.bitmask &= ~((unsigned int)EBT_NOPROTO);
- i = strtol(optarg, &buffer, 16);
- if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
- xtables_error(PARAMETER_PROBLEM,
- "Problem with the specified protocol");
- if (*buffer != '\0') {
- struct xt_ethertypeent *ent;
+ p.ops->print_help = print_help;
- if (!strcasecmp(optarg, "LENGTH")) {
- cs.eb.bitmask |= EBT_802_3;
- break;
- }
- ent = xtables_getethertypebyname(optarg);
- if (!ent)
- xtables_error(PARAMETER_PROBLEM,
- "Problem with the specified Ethernet protocol '%s', perhaps "XT_PATH_ETHERTYPES " is missing", optarg);
- cs.eb.ethproto = ent->e_ethertype;
- } else
- cs.eb.ethproto = i;
+ do_parse(argc, argv, &p, &cs, &args);
- if (cs.eb.ethproto < 0x0600)
- xtables_error(PARAMETER_PROBLEM,
- "Sorry, protocols have values above or equal to 0x0600");
- break;
- case 17 : /* Lc */
- ebt_check_option2(&flags, LIST_C);
- if (command != 'L')
- xtables_error(PARAMETER_PROBLEM,
- "Use --Lc with -L");
- flags |= LIST_C;
- break;
- case 18 : /* Ln */
- ebt_check_option2(&flags, LIST_N);
- if (command != 'L')
- xtables_error(PARAMETER_PROBLEM,
- "Use --Ln with -L");
- if (flags & LIST_X)
- xtables_error(PARAMETER_PROBLEM,
- "--Lx is not compatible with --Ln");
- flags |= LIST_N;
- break;
- case 19 : /* Lx */
- ebt_check_option2(&flags, LIST_X);
- if (command != 'L')
- xtables_error(PARAMETER_PROBLEM,
- "Use --Lx with -L");
- if (flags & LIST_N)
- xtables_error(PARAMETER_PROBLEM,
- "--Lx is not compatible with --Ln");
- flags |= LIST_X;
- break;
- case 12 : /* Lmac2 */
- ebt_check_option2(&flags, LIST_MAC2);
- if (command != 'L')
- xtables_error(PARAMETER_PROBLEM,
- "Use --Lmac2 with -L");
- flags |= LIST_MAC2;
- break;
- case 1 :
- if (!strcmp(optarg, "!"))
- ebt_check_inverse2(optarg, argc, argv);
- else
- xtables_error(PARAMETER_PROBLEM,
- "Bad argument : '%s'", optarg);
- /* ebt_ebt_check_inverse2() did optind++ */
- optind--;
- continue;
- default:
- ebt_check_inverse2(optarg, argc, argv);
- ebt_command_default(&cs);
-
- if (command != 'A' && command != 'I' &&
- command != 'D')
- xtables_error(PARAMETER_PROBLEM,
- "Extensions only for -A, -I, -D");
- }
- ebt_invert = 0;
- }
+ h->verbose = p.verbose;
/* Do the final checks */
- if (command == 'A' || command == 'I' || command == 'D') {
- for (xtrm_i = cs.matches; xtrm_i; xtrm_i = xtrm_i->next)
- xtables_option_mfcall(xtrm_i->match);
-
- for (match = cs.match_list; match; match = match->next) {
- if (match->ismatch)
- continue;
+ if (!nft_table_builtin_find(h, p.table))
+ xtables_error(VERSION_PROBLEM,
+ "table '%s' does not exist", p.table);
- xtables_option_tfcall(match->u.watcher);
- }
-
- if (cs.target != NULL)
- xtables_option_tfcall(cs.target);
- }
-
- cs.eb.ethproto = htons(cs.eb.ethproto);
-
- switch (command) {
- case 'F':
+ printf("nft ");
+ switch (p.command) {
+ case CMD_FLUSH:
if (p.chain) {
printf("flush chain bridge %s %s\n", p.table, p.chain);
} else {
@@ -506,16 +103,52 @@ print_zero:
}
ret = 1;
break;
- case 'A':
+ case CMD_APPEND:
ret = nft_rule_eb_xlate_add(h, &p, &cs, true);
if (!ret)
print_ebt_cmd(argc, argv);
break;
- case 'I':
+ case CMD_INSERT:
ret = nft_rule_eb_xlate_add(h, &p, &cs, false);
if (!ret)
print_ebt_cmd(argc, argv);
break;
+ case CMD_LIST:
+ printf("list table bridge %s\n", p.table);
+ ret = 1;
+ break;
+ case CMD_NEW_CHAIN:
+ printf("add chain bridge %s %s\n", p.table, p.chain);
+ ret = 1;
+ break;
+ case CMD_DELETE_CHAIN:
+ printf("delete chain bridge %s %s\n", p.table, p.chain);
+ ret = 1;
+ break;
+ case CMD_INIT_TABLE:
+ printf("flush table bridge %s\n", p.table);
+ ret = 1;
+ break;
+ case CMD_DELETE:
+ case CMD_DELETE_NUM:
+ case CMD_CHECK:
+ case CMD_REPLACE:
+ case CMD_ZERO:
+ case CMD_ZERO_NUM:
+ case CMD_LIST|CMD_ZERO:
+ case CMD_LIST|CMD_ZERO_NUM:
+ case CMD_LIST_RULES:
+ case CMD_LIST_RULES|CMD_ZERO:
+ case CMD_LIST_RULES|CMD_ZERO_NUM:
+ case CMD_NEW_CHAIN|CMD_SET_POLICY:
+ case CMD_SET_POLICY:
+ case CMD_RENAME_CHAIN:
+ case CMD_CHANGE_COUNTERS:
+ break;
+ default:
+ /* We should never reach this... */
+ printf("Unsupported command?\n");
+ exit(1);
}
ebt_cs_clean(&cs);