/* We use exec_style instead of #ifdef's because ebtables.so is a shared object. */ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table) { char *buffer; int c, i; int zerochain = -1; /* Needed for the -Z option (we can have -Z <this> -L <that>) */ 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; const char *policy = NULL; int exec_style = EXEC_STYLE_PRG; int selected_chain = -1; struct xtables_rule_match *xtrm_i; struct ebt_match *match; 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; /* 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 */ goto handle_P; } if (OPT_COMMANDS) xtables_error(PARAMETER_PROBLEM, "Multiple commands are not allowed"); command = c; chain = optarg; selected_chain = get_current_chain(chain); flags |= OPT_COMMAND; /*if (!(replace->flags & OPT_KERNELDATA)) ebt_get_kernel_table(replace, 0);*/ /*if (optarg && (optarg[0] == '-' || !strcmp(optarg, "!"))) ebt_print_error2("No chain name specified");*/ if (c == 'N') { ret = nft_chain_user_add(h, chain, *table); break; } else if (c == 'X') { ret = nft_chain_user_del(h, chain, *table); break; } if (c == 'E') { if (optind >= argc) xtables_error(PARAMETER_PROBLEM, "No new chain name specified"); else if (optind < argc - 1) xtables_error(PARAMETER_PROBLEM, "No extra options allowed with -E"); else if (strlen(argv[optind]) >= NFT_CHAIN_MAXNAMELEN) xtables_error(PARAMETER_PROBLEM, "Chain name length can't exceed %d"" characters", NFT_CHAIN_MAXNAMELEN - 1); else if (strchr(argv[optind], ' ') != NULL) xtables_error(PARAMETER_PROBLEM, "Use of ' ' not allowed in chain names"); ret = nft_chain_user_rename(h, chain, *table, argv[optind]); if (ret != 0 && errno == ENOENT) xtables_error(PARAMETER_PROBLEM, "Chain '%s' doesn't exists", chain); optind++; 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++; } } else if (c == 'P') { handle_P: if (optind >= argc) xtables_error(PARAMETER_PROBLEM, "No policy specified"); for (i = 0; i < NUM_STANDARD_TARGETS; i++) if (!strcmp(argv[optind], nft_ebt_standard_target(i))) { policy = argv[optind]; if (-i-1 == EBT_CONTINUE) xtables_error(PARAMETER_PROBLEM, "Wrong policy '%s'", argv[optind]); break; } if (i == NUM_STANDARD_TARGETS) xtables_error(PARAMETER_PROBLEM, "Unknown policy '%s'", argv[optind]); optind++; } break; case 'L': /* List */ 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; } #ifdef SILENT_DAEMON if (c== 'L' && exec_style == EXEC_STYLE_DAEMON) xtables_error(PARAMETER_PROBLEM, "-L not supported in daemon mode"); #endif /*if (!(replace->flags & OPT_KERNELDATA)) ebt_get_kernel_table(replace, 0); i = -1; if (optind < argc && argv[optind][0] != '-') { if ((i = ebt_get_chainnr(replace, argv[optind])) == -1) ebt_print_error2("Chain '%s' doesn't exist", argv[optind]); optind++; } if (i != -1) { if (c == 'Z') zerochain = i; else replace->selected_chain = i; }*/ 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': /* Help */ #ifdef SILENT_DAEMON if (exec_style == EXEC_STYLE_DAEMON) xtables_error(PARAMETER_PROBLEM, "-h not supported in daemon mode"); #endif if (OPT_COMMANDS) xtables_error(PARAMETER_PROBLEM, "Multiple commands are not allowed"); command = 'h'; /* All other arguments should be extension names */ while (optind < argc) { /*struct ebt_u_match *m; struct ebt_u_watcher *w;*/ if (!strcasecmp("list_extensions", argv[optind])) { ebt_list_extensions(xtables_targets, cs.matches); exit(0); } /*if ((m = ebt_find_match(argv[optind]))) ebt_add_match(new_entry, m); else if ((w = ebt_find_watcher(argv[optind]))) ebt_add_watcher(new_entry, w); else {*/ if (!(t = xtables_find_target(argv[optind], XTF_TRY_LOAD))) xtables_error(PARAMETER_PROBLEM,"Extension '%s' not found", argv[optind]); if (flags & OPT_JUMP) xtables_error(PARAMETER_PROBLEM,"Sorry, you can only see help for one target extension at a time"); flags |= OPT_JUMP; cs.target = t; //} optind++; } 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 */ #ifdef SILENT_DAEMON if (exec_style == EXEC_STYLE_DAEMON) xtables_error(PARAMETER_PROBLEM, "--Lc is not supported in daemon mode"); #endif ebt_check_option2(&flags, LIST_C); if (command != 'L') xtables_error(PARAMETER_PROBLEM, "Use --Lc with -L"); flags |= LIST_C; break; case 5 : /* Ln */ #ifdef SILENT_DAEMON if (exec_style == EXEC_STYLE_DAEMON) xtables_error(PARAMETER_PROBLEM, "--Ln is not supported in daemon mode"); #endif 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 */ #ifdef SILENT_DAEMON if (exec_style == EXEC_STYLE_DAEMON) xtables_error(PARAMETER_PROBLEM, "--Lx is not supported in daemon mode"); #endif 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 */ #ifdef SILENT_DAEMON if (exec_style == EXEC_STYLE_DAEMON) xtables_error(PARAMETER_PROBLEM, "--Lmac2 is not supported in daemon mode"); #endif ebt_check_option2(&flags, LIST_MAC2); if (command != 'L') xtables_error(PARAMETER_PROBLEM, "Use --Lmac2 with -L"); flags |= LIST_MAC2; break; case 8 : /* atomic-commit */ /* if (exec_style == EXEC_STYLE_DAEMON) ebt_print_error2("--atomic-commit is not supported in daemon mode"); replace->command = c; if (OPT_COMMANDS) ebt_print_error2("Multiple commands are not allowed"); replace->flags |= OPT_COMMAND; if (!replace->filename) ebt_print_error2("No atomic file specified");*/ /* Get the information from the file */ /*ebt_get_table(replace, 0);*/ /* We don't want the kernel giving us its counters, * they would overwrite the counters extracted from * the file */ /*replace->num_counters = 0;*/ /* Make sure the table will be written to the kernel */ /*free(replace->filename); replace->filename = NULL; break;*/ /*case 7 :*/ /* atomic-init */ /*case 10:*/ /* atomic-save */ /*case 11:*/ /* init-table */ /* if (exec_style == EXEC_STYLE_DAEMON) { if (c == 7) { ebt_print_error2("--atomic-init is not supported in daemon mode"); } else if (c == 10) ebt_print_error2("--atomic-save is not supported in daemon mode"); ebt_print_error2("--init-table is not supported in daemon mode"); } replace->command = c; if (OPT_COMMANDS) ebt_print_error2("Multiple commands are not allowed"); if (c != 11 && !replace->filename) ebt_print_error2("No atomic file specified"); replace->flags |= OPT_COMMAND; { char *tmp = replace->filename;*/ /* Get the kernel table */ /*replace->filename = NULL; ebt_get_kernel_table(replace, c == 10 ? 0 : 1); replace->filename = tmp; } break; case 9 :*/ /* atomic */ /*if (exec_style == EXEC_STYLE_DAEMON) ebt_print_error2("--atomic is not supported in daemon mode"); if (OPT_COMMANDS) ebt_print_error2("--atomic has to come before the command");*/ /* A possible memory leak here, but this is not * executed in daemon mode */ /*replace->filename = (char *)malloc(strlen(optarg) + 1); strcpy(replace->filename, optarg); break; case 13 : *//* concurrent */ /*signal(SIGINT, sighandler); signal(SIGTERM, sighandler); use_lockfd = 1; 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_invert, &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; } } /* if (w == NULL && c == '?') ebt_print_error2("Unknown argument: '%s'", argv[optind - 1], (char)optopt, (char)c); else if (w == NULL) { if (!strcmp(t->name, "standard")) ebt_print_error2("Unknown argument: don't forget the -t option"); else ebt_print_error2("Target-specific option does not correspond with specified target"); } if (ebt_errormsg[0] != '\0') return -1; if (w->used == 0) { ebt_add_watcher(new_entry, w); w->used = 1; }*/ 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; } /* Just in case we didn't catch an error */ /*if (ebt_errormsg[0] != '\0') return -1; if (!(table = ebt_find_table(replace->name))) ebt_print_error2("Bad table name");*/ if (command == 'h' && !(flags & OPT_ZERO)) { print_help(cs.target, cs.matches, *table); if (exec_style == EXEC_STYLE_PRG) exit(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); } /* So, the extensions can work with the host endian. * The kernel does not have to do this of course */ cs.fw.ethproto = htons(cs.fw.ethproto); if (command == 'P') { if (selected_chain < 0) { xtables_error(PARAMETER_PROBLEM, "Policy %s not allowed for user defined chains", policy); } if (strcmp(policy, "RETURN") == 0) { xtables_error(PARAMETER_PROBLEM, "Policy RETURN only allowed for user defined chains"); } ret = nft_chain_set(h, *table, chain, policy, NULL); if (ret < 0) xtables_error(PARAMETER_PROBLEM, "Wrong policy"); } else if (command == 'L') { ret = list_rules(h, chain, *table, rule_nr, flags&OPT_VERBOSE, flags&OPT_NUMERIC, /*flags&OPT_EXPANDED*/0, flags&LIST_N, flags&LIST_C); if (!(flags & OPT_ZERO) && exec_style == EXEC_STYLE_PRG) exit(0); } if (flags & OPT_ZERO) { selected_chain = zerochain; ret = nft_chain_zero_counters(h, chain, *table); } else if (command == 'F') { ret = nft_rule_flush(h, chain, *table); } else if (command == 'A') { ret = append_entry(h, chain, *table, &cs, 0, flags&OPT_VERBOSE, true); } else if (command == 'I') { ret = append_entry(h, chain, *table, &cs, rule_nr - 1, flags&OPT_VERBOSE, false); } else if (command == 'D') { ret = delete_entry(h, chain, *table, &cs, rule_nr - 1, rule_nr_end, flags&OPT_VERBOSE); } /*else if (replace->command == 'C') { ebt_change_counters(replace, new_entry, rule_nr, rule_nr_end, &(new_entry->cnt_surplus), chcounter); if (ebt_errormsg[0] != '\0') return -1; }*/ /* Commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save, * --init-table fall through */ /*if (ebt_errormsg[0] != '\0') return -1; if (table->check) table->check(replace); if (exec_style == EXEC_STYLE_PRG) {*//* Implies ebt_errormsg[0] == '\0' */ /*ebt_deliver_table(replace); if (replace->nentries) ebt_deliver_counters(replace);*/ ebt_cs_clean(&cs); 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 rule_nr = 0; int rule_nr_end = 0; int ret = 0; unsigned int flags = 0; struct iptables_command_state cs = { .argv = argv, .eb.bitmask = EBT_NOPROTO, }; 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, }; /* 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; cs.invert = ebt_invert; 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 = 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 */ 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"); 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; p.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') 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.eb.invflags |= EBT_IIN; ebtables_parse_interface(optarg, cs.eb.in); 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.eb.invflags |= EBT_ILOGICALIN; ebtables_parse_interface(optarg, cs.eb.logical_in); 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.eb.invflags |= EBT_IOUT; ebtables_parse_interface(optarg, cs.eb.out); 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.eb.invflags |= EBT_ILOGICALOUT; ebtables_parse_interface(optarg, cs.eb.logical_out); break; } else if (c == 'j') { ebt_check_option2(&flags, OPT_JUMP); 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 (ebt_get_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_DEST); if (ebt_check_inverse2(optarg, argc, argv)) cs.eb.invflags |= EBT_IDEST; if (ebt_get_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_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.eb.invflags |= EBT_IPROTO; 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; 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; if (cs.eb.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: ebt_check_inverse2(optarg, argc, argv); if (ebt_command_default(&cs)) xtables_error(PARAMETER_PROBLEM, "Unknown argument: '%s'", argv[optind - 1]); if (command != 'A' && command != 'I' && command != 'D') xtables_error(PARAMETER_PROBLEM, "Extensions only for -A, -I, -D"); } ebt_invert = 0; } /* 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; xtables_option_tfcall(match->u.watcher); } if (cs.target != NULL) xtables_option_tfcall(cs.target); } cs.eb.ethproto = htons(cs.eb.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; } static int dummy_compat_rev(const char *name, uint8_t rev, int opt) { return 1; } int xtables_eb_xlate_main(int argc, char *argv[]) { int ret; char *table = "filter"; struct nft_handle h; nft_init_eb(&h, argv[0]); ebtables_globals.compat_rev = dummy_compat_rev; ret = do_commandeb_xlate(&h, argc, argv, &table); if (!ret) fprintf(stderr, "Translation not implemented\n"); exit(!ret); }