Signed-off-by: Florian Westphal <fw@xxxxxxxxx> --- iptables/Makefile.am | 1 + iptables/xtables-compat-multi.c | 1 + iptables/xtables-eb-translate.c | 801 ++++++++++++++++++++++++++++++++++++++++ iptables/xtables-eb.c | 2 +- iptables/xtables-multi.h | 1 + 5 files changed, 805 insertions(+), 1 deletion(-) create mode 100644 iptables/xtables-eb-translate.c diff --git a/iptables/Makefile.am b/iptables/Makefile.am index 60a14bf2ba1a..2de142083c81 100644 --- a/iptables/Makefile.am +++ b/iptables/Makefile.am @@ -44,6 +44,7 @@ xtables_compat_multi_SOURCES += xtables-save.c xtables-restore.c \ xtables-arp-standalone.c xtables-arp.c \ getethertype.c nft-bridge.c \ xtables-eb-standalone.c xtables-eb.c \ + xtables-eb-translate.c \ xtables-translate.c xtables_compat_multi_LDADD += ${libmnl_LIBS} ${libnftnl_LIBS} ${libnetfilter_conntrack_LIBS} ../extensions/libext4.a ../extensions/libext6.a ../extensions/libext_ebt.a ../extensions/libext_arpt.a # yacc and lex generate dirty code diff --git a/iptables/xtables-compat-multi.c b/iptables/xtables-compat-multi.c index 032911e170e4..0b05eaded617 100644 --- a/iptables/xtables-compat-multi.c +++ b/iptables/xtables-compat-multi.c @@ -33,6 +33,7 @@ static const struct subcommand multi_subcommands[] = { {"arptables", xtables_arp_main}, {"arptables-compat", xtables_arp_main}, {"ebtables-compat", xtables_eb_main}, + {"ebtables-translate", xtables_eb_xlate_main}, {"ebtables", xtables_eb_main}, {NULL}, }; diff --git a/iptables/xtables-eb-translate.c b/iptables/xtables-eb-translate.c new file mode 100644 index 000000000000..0ecd0f3f003a --- /dev/null +++ b/iptables/xtables-eb-translate.c @@ -0,0 +1,801 @@ +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <stdarg.h> +#include <string.h> +#include <fcntl.h> +#include <getopt.h> +#include <iptables.h> +#include <xtables.h> + +#include <netinet/ether.h> + +#include <linux/netfilter_bridge.h> +#include <linux/netfilter/nf_tables.h> +#include <ebtables/ethernetdb.h> +#include <libiptc/libxtc.h> + +#include "xshared.h" +#include "xtables-multi.h" +#include "nft-bridge.h" +#include "nft.h" +#include "nft-shared.h" +/* + * From include/ebtables_u.h + */ +#define EXEC_STYLE_PRG 0 +#define EXEC_STYLE_DAEMON 1 + +#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; +} + +static const char * +parse_target(const char *targetname) +{ + const char *ptr; + + if (strlen(targetname) < 1) + xtables_error(PARAMETER_PROBLEM, + "Invalid target name (too short)"); + + if (strlen(targetname)+1 > EBT_CHAIN_MAXNAMELEN) + xtables_error(PARAMETER_PROBLEM, + "Invalid target '%s' (%d chars max)", + targetname, EBT_CHAIN_MAXNAMELEN); + + for (ptr = targetname; *ptr; ptr++) + if (isspace(*ptr)) + xtables_error(PARAMETER_PROBLEM, + "Invalid target name `%s'", targetname); + return targetname; +} + +static int get_current_chain(const char *chain) +{ + if (strcmp(chain, "PREROUTING") == 0) + return NF_BR_PRE_ROUTING; + else if (strcmp(chain, "INPUT") == 0) + return NF_BR_LOCAL_IN; + else if (strcmp(chain, "FORWARD") == 0) + return NF_BR_FORWARD; + else if (strcmp(chain, "OUTPUT") == 0) + return NF_BR_LOCAL_OUT; + else if (strcmp(chain, "POSTROUTING") == 0) + return NF_BR_POST_ROUTING; + + return -1; +} + +/* + * The original ebtables parser + */ + +/* Checks whether a command has already been specified */ +#define OPT_COMMANDS (flags & OPT_COMMAND || flags & OPT_ZERO) + +#define OPT_COMMAND 0x01 +#define OPT_TABLE 0x02 +#define OPT_IN 0x04 +#define OPT_OUT 0x08 +#define OPT_JUMP 0x10 +#define OPT_PROTOCOL 0x20 +#define OPT_SOURCE 0x40 +#define OPT_DEST 0x80 +#define OPT_ZERO 0x100 +#define OPT_LOGICALIN 0x200 +#define OPT_LOGICALOUT 0x400 +#define OPT_KERNELDATA 0x800 /* This value is also defined in ebtablesd.c */ +#define OPT_COUNT 0x1000 /* This value is also defined in libebtc.c */ + +/* 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[]; +extern struct xtables_globals ebtables_globals; +#define opts ebtables_globals.opts +#define prog_name ebtables_globals.program_name +#define prog_vers ebtables_globals.program_version + +#define OPTION_OFFSET 256 +static struct option *merge_options(struct option *oldopts, + const struct option *newopts, + unsigned int *options_offset) +{ + unsigned int num_old, num_new, i; + struct option *merge; + + if (!newopts || !oldopts || !options_offset) + return oldopts; + for (num_old = 0; oldopts[num_old].name; num_old++); + for (num_new = 0; newopts[num_new].name; num_new++); + + ebtables_globals.option_offset += OPTION_OFFSET; + *options_offset = ebtables_globals.option_offset; + + merge = malloc(sizeof(struct option) * (num_new + num_old + 1)); + if (!merge) + return NULL; + memcpy(merge, oldopts, num_old * sizeof(struct option)); + for (i = 0; i < num_new; i++) { + merge[num_old + i] = newopts[i]; + merge[num_old + i].val += *options_offset; + } + memset(merge + num_old + num_new, 0, sizeof(struct option)); + /* Only free dynamically allocated stuff */ + if (oldopts != ebt_original_options) + free(oldopts); + + return merge; +} + +/* + * More glue code. + */ +static struct xtables_target *command_jump(struct ebtables_command_state *cs, + const char *jumpto) +{ + struct xtables_target *target; + size_t size; + + /* XTF_TRY_LOAD (may be chain name) */ + target = xtables_find_target(jumpto, XTF_TRY_LOAD); + + if (!target) + return NULL; + + size = XT_ALIGN(sizeof(struct xt_entry_target)) + + target->size; + + target->t = xtables_calloc(1, size); + target->t->u.target_size = size; + strncpy(target->t->u.user.name, jumpto, sizeof(target->t->u.user.name)); + target->t->u.user.name[sizeof(target->t->u.user.name)-1] = '\0'; + target->t->u.user.revision = target->revision; + + xs_init_target(target); + + opts = merge_options(opts, target->extra_opts, &target->option_offset); + if (opts == NULL) + xtables_error(OTHER_PROBLEM, "Can't alloc memory"); + + return target; +} + +static void print_help(void) +{ + fprintf(stderr, "%s: Translate ebtables command to nft syntax\n" + "no side effects occur, the translated command is written " + "to standard output.\n" + "A '#' followed by input means no translation " + "is available.\n", prog_name); + 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; +} + +/* Incrementing or decrementing rules in daemon mode is not supported as the + * involved code overload is not worth it (too annoying to take the increased + * counters in the kernel into account). */ +static int parse_change_counters_rule(int argc, char **argv, int *rule_nr, int *rule_nr_end, int exec_style, struct ebtables_command_state *cs) +{ + char *buffer; + int ret = 0; + + if (optind + 1 >= argc || (argv[optind][0] == '-' && (argv[optind][1] < '0' || argv[optind][1] > '9')) || + (argv[optind + 1][0] == '-' && (argv[optind + 1][1] < '0' && argv[optind + 1][1] > '9'))) + xtables_error(PARAMETER_PROBLEM, + "The command -C needs at least 2 arguments"); + if (optind + 2 < argc && (argv[optind + 2][0] != '-' || (argv[optind + 2][1] >= '0' && argv[optind + 2][1] <= '9'))) { + if (optind + 3 != argc) + xtables_error(PARAMETER_PROBLEM, + "No extra options allowed with -C start_nr[:end_nr] pcnt bcnt"); + if (parse_rule_range(argv[optind], rule_nr, rule_nr_end)) + xtables_error(PARAMETER_PROBLEM, + "Something is wrong with the rule number specification '%s'", argv[optind]); + optind++; + } + + if (argv[optind][0] == '+') { + if (exec_style == EXEC_STYLE_DAEMON) +daemon_incr: + xtables_error(PARAMETER_PROBLEM, + "Incrementing rule counters (%s) not allowed in daemon mode", argv[optind]); + ret += 1; + cs->counters.pcnt = strtoull(argv[optind] + 1, &buffer, 10); + } else if (argv[optind][0] == '-') { + if (exec_style == EXEC_STYLE_DAEMON) +daemon_decr: + xtables_error(PARAMETER_PROBLEM, + "Decrementing rule counters (%s) not allowed in daemon mode", argv[optind]); + ret += 2; + cs->counters.pcnt = strtoull(argv[optind] + 1, &buffer, 10); + } else + cs->counters.pcnt = strtoull(argv[optind], &buffer, 10); + + if (*buffer != '\0') + goto invalid; + optind++; + if (argv[optind][0] == '+') { + if (exec_style == EXEC_STYLE_DAEMON) + goto daemon_incr; + ret += 3; + cs->counters.bcnt = strtoull(argv[optind] + 1, &buffer, 10); + } else if (argv[optind][0] == '-') { + if (exec_style == EXEC_STYLE_DAEMON) + goto daemon_decr; + ret += 6; + cs->counters.bcnt = strtoull(argv[optind] + 1, &buffer, 10); + } else + cs->counters.bcnt = strtoull(argv[optind], &buffer, 10); + + if (*buffer != '\0') + goto invalid; + optind++; + return ret; +invalid: + xtables_error(PARAMETER_PROBLEM,"Packet counter '%s' invalid", argv[optind]); +} + +static int parse_iface(char *iface, char *option) +{ + char *c; + + if ((c = strchr(iface, '+'))) { + if (*(c + 1) != '\0') { + xtables_error(PARAMETER_PROBLEM, + "Spurious characters after '+' wildcard for '%s'", option); + return -1; + } else + *c = IF_WILDCARD; + } + return 0; +} + +static void print_ebt_cmd(int argc, char *argv[]) +{ + int i; + + printf("# "); + for (i = 1; i < argc; i++) + printf("%s ", argv[i]); + + printf("\n"); +} + +static int nft_rule_eb_xlate_add(struct nft_handle *h, const struct nft_xt_cmd_parse *p, + const struct ebtables_command_state *cs, bool append) +{ + struct xt_xlate *xl = xt_xlate_alloc(10240); + int ret; + + if (append) { + xt_xlate_add(xl, "add rule bridge %s %s ", p->table, p->chain); + } else { + xt_xlate_add(xl, "insert rule bridge %s %s ", p->table, p->chain); + } + + ret = h->ops->xlate(cs, xl); + if (ret) + printf("%s\n", xt_xlate_get(xl)); + + xt_xlate_free(xl); + return ret; +} + +/* We use exec_style instead of #ifdef's because ebtables.so is a shared object. */ +static int do_commandeb_xlate(struct nft_handle *h, int argc, char *argv[], char **table) +{ + char *buffer; + int c, i; + int chcounter = 0; /* Needed for -C */ + int rule_nr = 0; + int rule_nr_end = 0; + int ret = 0; + unsigned int flags = 0; + struct xtables_target *t, *w; + struct xtables_match *m; + struct ebtables_command_state cs; + char command = 'h'; + const char *chain = NULL; + int exec_style = EXEC_STYLE_PRG; + int selected_chain = -1; + struct xtables_rule_match *xtrm_i; + struct ebt_match *match; + struct nft_xt_cmd_parse p = { + .table = *table, + }; + + memset(&cs, 0, sizeof(cs)); + cs.argv = argv; + + if (nft_init(h, xtables_bridge) < 0) + xtables_error(OTHER_PROBLEM, + "Could not initialize nftables layer."); + + h->ops = nft_family_ops_lookup(h->family); + if (h->ops == NULL) + xtables_error(PARAMETER_PROBLEM, "Unknown family"); + + /* manually registering ebt matches, given the original ebtables parser + * don't use '-m matchname' and the match can't loaded dinamically when + * the user calls it. + */ + ebt_load_match_extensions(); + + /* clear mflags in case do_commandeb gets called a second time + * (we clear the global list of all matches for security)*/ + for (m = xtables_matches; m; m = m->next) + m->mflags = 0; + + for (t = xtables_targets; t; t = t->next) { + t->tflags = 0; + t->used = 0; + } + + /* prevent getopt to spoil our error reporting */ + opterr = false; + + printf("nft "); + /* Getopt saves the day */ + while ((c = getopt_long(argc, argv, + "-A:D:C:I:N:E:X::L::Z::F::P:Vhi:o:j:c:p:s:d:t:M:", opts, NULL)) != -1) { + cs.c = c; + cs.invert = ebt_invert; + switch (c) { + case 'A': /* Add a rule */ + case 'D': /* Delete a rule */ + case 'C': /* Change counters */ + 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 = 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 == 'C') { + if ((chcounter = parse_change_counters_rule(argc, argv, &rule_nr, &rule_nr_end, exec_style, &cs)) == -1) + return -1; + } 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 */ + if (p.chain) { + printf("flush chain bridge %s %s\n", p.table, p.chain); + } else { + printf("flush table bridge %s\n", p.table); + } + ret = 1; + break; + 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"); + command = 'V'; + if (exec_style == EXEC_STYLE_DAEMON) + xtables_error(PARAMETER_PROBLEM, + "%s %s\n", prog_name, prog_vers); + 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"); + ebt_check_option2(&flags, OPT_TABLE); + if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1) + xtables_error(PARAMETER_PROBLEM, + "Table name length cannot exceed %d characters", + EBT_TABLE_MAXNAMELEN - 1); + *table = optarg; + break; + case 'i': /* Input interface */ + case 2 : /* Logical input interface */ + case 'o': /* Output interface */ + case 3 : /* 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' && command != 'C') + xtables_error(PARAMETER_PROBLEM, + "Command and option do not match"); + if (c == 'i') { + ebt_check_option2(&flags, OPT_IN); + 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.fw.invflags |= EBT_IIN; + + if (strlen(optarg) >= IFNAMSIZ) +big_iface_length: + xtables_error(PARAMETER_PROBLEM, + "Interface name length cannot exceed %d characters", + IFNAMSIZ - 1); + xtables_parse_interface(optarg, cs.fw.in, cs.fw.in_mask); + break; + } else if (c == 2) { + 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.fw.invflags |= EBT_ILOGICALIN; + + if (strlen(optarg) >= IFNAMSIZ) + goto big_iface_length; + strcpy(cs.fw.logical_in, optarg); + if (parse_iface(cs.fw.logical_in, "--logical-in")) + return -1; + break; + } else if (c == 'o') { + ebt_check_option2(&flags, OPT_OUT); + 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.fw.invflags |= EBT_IOUT; + + if (strlen(optarg) >= IFNAMSIZ) + goto big_iface_length; + + xtables_parse_interface(optarg, cs.fw.out, cs.fw.out_mask); + break; + } else if (c == 3) { + 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.fw.invflags |= EBT_ILOGICALOUT; + + if (strlen(optarg) >= IFNAMSIZ) + goto big_iface_length; + strcpy(cs.fw.logical_out, optarg); + if (parse_iface(cs.fw.logical_out, "--logical-out")) + return -1; + break; + } else if (c == 'j') { + ebt_check_option2(&flags, OPT_JUMP); + cs.jumpto = parse_target(optarg); + cs.target = command_jump(&cs, cs.jumpto); + break; + } else if (c == 's') { + ebt_check_option2(&flags, OPT_SOURCE); + if (ebt_check_inverse2(optarg, argc, argv)) + cs.fw.invflags |= EBT_ISOURCE; + + if (ebt_get_mac_and_mask(optarg, cs.fw.sourcemac, cs.fw.sourcemsk)) + xtables_error(PARAMETER_PROBLEM, "Problem with specified source mac '%s'", optarg); + cs.fw.bitmask |= EBT_SOURCEMAC; + break; + } else if (c == 'd') { + ebt_check_option2(&flags, OPT_DEST); + if (ebt_check_inverse2(optarg, argc, argv)) + cs.fw.invflags |= EBT_IDEST; + + if (ebt_get_mac_and_mask(optarg, cs.fw.destmac, cs.fw.destmsk)) + xtables_error(PARAMETER_PROBLEM, "Problem with specified destination mac '%s'", optarg); + cs.fw.bitmask |= EBT_DESTMAC; + break; + } else if (c == 'c') { + ebt_check_option2(&flags, OPT_COUNT); + 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.fw.invflags |= EBT_IPROTO; + + cs.fw.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 ethertypeent *ent; + + if (!strcasecmp(optarg, "LENGTH")) { + cs.fw.bitmask |= EBT_802_3; + break; + } + ent = getethertypebyname(optarg); + if (!ent) + xtables_error(PARAMETER_PROBLEM, + "Problem with the specified Ethernet protocol '%s', perhaps "_PATH_ETHERTYPES " is missing", optarg); + cs.fw.ethproto = ent->e_ethertype; + } else + cs.fw.ethproto = i; + + if (cs.fw.ethproto < 0x0600) + xtables_error(PARAMETER_PROBLEM, + "Sorry, protocols have values above or equal to 0x0600"); + break; + case 4 : /* Lc */ + ebt_check_option2(&flags, LIST_C); + if (command != 'L') + xtables_error(PARAMETER_PROBLEM, + "Use --Lc with -L"); + flags |= LIST_C; + break; + case 5 : /* 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 6 : /* 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: + /* Is it a target option? */ + if (cs.target != NULL && cs.target->parse != NULL) { + int opt_offset = cs.target->option_offset; + if (cs.target->parse(c - opt_offset, + argv, ebt_invert, + &cs.target->tflags, + NULL, &cs.target->t)) + goto check_extension; + } + + /* Is it a match_option? */ + for (m = xtables_matches; m; m = m->next) { + if (m->parse(c - m->option_offset, argv, ebt_check_inverse2(optarg, argc, argv), &m->mflags, NULL, &m->m)) { + ebt_add_match(m, &cs); + goto check_extension; + } + } + + /* Is it a watcher option? */ + for (w = xtables_targets; w; w = w->next) { + if (w->parse(c - w->option_offset, argv, + ebt_invert, &w->tflags, + NULL, &w->t)) { + ebt_add_watcher(w, &cs); + goto check_extension; + } + } +check_extension: + if (command != 'A' && command != 'I' && + command != 'D' && command != 'C') + xtables_error(PARAMETER_PROBLEM, + "Extensions only for -A, -I, -D and -C"); + } + ebt_invert = 0; + } + + /* Do the final checks */ + if (command == 'A' || command == 'I' || + command == 'D' || command == 'C') { + 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; + + xtables_option_tfcall(match->u.watcher); + } + + if (cs.target != NULL) + xtables_option_tfcall(cs.target); + } + + cs.fw.ethproto = htons(cs.fw.ethproto); + + if (command == 'P') { + return 0; + } else if (command == 'A') { + ret = nft_rule_eb_xlate_add(h, &p, &cs, true); + if (!ret) + print_ebt_cmd(argc, argv); + } else if (command == 'I') { + ret = nft_rule_eb_xlate_add(h, &p, &cs, false); + if (!ret) + print_ebt_cmd(argc, argv); + } + + ebt_cs_clean(&cs); + return ret; +} + +int xtables_eb_xlate_main(int argc, char *argv[]) +{ + int ret; + char *table = "filter"; + struct nft_handle h = { + .family = NFPROTO_BRIDGE, + }; + + ebtables_globals.program_name = argv[0]; + ret = xtables_init_all(&ebtables_globals, NFPROTO_BRIDGE); + if (ret < 0) { + fprintf(stderr, "%s/%s Failed to initialize xtables\n", + ebtables_globals.program_name, + ebtables_globals.program_version); + exit(EXIT_FAILURE); + } + + ret = do_commandeb_xlate(&h, argc, argv, &table); + if (!ret) + fprintf(stderr, "Translation not implemented\n"); + + exit(!ret); +} + diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c index 75ce109047b3..c99033a74936 100644 --- a/iptables/xtables-eb.c +++ b/iptables/xtables-eb.c @@ -247,7 +247,7 @@ static int get_current_chain(const char *chain) /* Default command line options. Do not mess around with the already * assigned numbers unless you know what you are doing */ -static struct option ebt_original_options[] = +struct option ebt_original_options[] = { { "append" , required_argument, 0, 'A' }, { "insert" , required_argument, 0, 'I' }, diff --git a/iptables/xtables-multi.h b/iptables/xtables-multi.h index 7b4195c17960..f0c14ea42ed4 100644 --- a/iptables/xtables-multi.h +++ b/iptables/xtables-multi.h @@ -11,6 +11,7 @@ extern int xtables_ip6_save_main(int, char **); extern int xtables_ip6_restore_main(int, char **); extern int xtables_ip4_xlate_main(int, char **); extern int xtables_ip6_xlate_main(int, char **); +extern int xtables_eb_xlate_main(int, char **); extern int xtables_ip4_xlate_restore_main(int, char **); extern int xtables_ip6_xlate_restore_main(int, char **); extern int xtables_arp_main(int, char **); -- 2.16.1 -- To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html