static int brip_parse(int c, char **argv, int invert, unsigned int *flags, const void *entry, struct xt_entry_match **match) { struct ebt_ip_info *info = (struct ebt_ip_info *)(*match)->data; switch (c) { case IP_SOURCE: if (invert) info->invflags |= EBT_IP_SOURCE; ebt_parse_ip_address(optarg, &info->saddr, &info->smsk); info->bitmask |= EBT_IP_SOURCE; break; case IP_DEST: if (invert) info->invflags |= EBT_IP_DEST; ebt_parse_ip_address(optarg, &info->daddr, &info->dmsk); info->bitmask |= EBT_IP_DEST; break; case IP_SPORT: if (invert) info->invflags |= EBT_IP_SPORT; parse_port_range(NULL, optarg, info->sport); info->bitmask |= EBT_IP_SPORT; break; case IP_DPORT: if (invert) info->invflags |= EBT_IP_DPORT; parse_port_range(NULL, optarg, info->dport); info->bitmask |= EBT_IP_DPORT; break; case IP_EBT_TOS: if (invert) info->invflags |= EBT_IP_TOS; if (!xtables_strtoul(optarg, NULL, (uintmax_t *)&info->tos, 0, 255)) xtables_error(PARAMETER_PROBLEM, "Problem with specified IP tos"); info->bitmask |= EBT_IP_TOS; break; case IP_PROTO: if (invert) info->invflags |= EBT_IP_PROTO; info->protocol = xtables_parse_protocol(optarg); if (info->protocol == -1) xtables_error(PARAMETER_PROBLEM, "Unknown specified IP protocol - %s", optarg); info->bitmask |= EBT_IP_PROTO; break; default: return 0; } *flags |= info->bitmask; return 1; }
/* Function which parses command options; returns true if it ate an option */ static int ipvs_mt_parse(int c, char **argv, int invert, unsigned int *flags, const void *entry, struct xt_entry_match **match, unsigned int family) { struct xt_ipvs_mtinfo *data = (void *)(*match)->data; char *p = NULL; u_int8_t op = 0; if ('0' <= c && c <= '6') { static const int ops[] = { XT_IPVS_IPVS_PROPERTY, XT_IPVS_PROTO, XT_IPVS_VADDR, XT_IPVS_VPORT, XT_IPVS_DIR, XT_IPVS_METHOD, XT_IPVS_VPORTCTL }; op = ops[c - '0']; } else return 0; if (*flags & op & XT_IPVS_ONCE_MASK) goto multiple_use; switch (c) { case '0': /* --ipvs */ /* Nothing to do here. */ break; case '1': /* --vproto */ /* Canonicalize into lower case */ for (p = optarg; *p != '\0'; ++p) *p = tolower(*p); data->l4proto = xtables_parse_protocol(optarg); break; case '2': /* --vaddr */ ipvs_mt_parse_addr_and_mask(optarg, &data->vaddr, &data->vmask, family); break; case '3': /* --vport */ data->vport = htons(xtables_parse_port(optarg, "tcp")); break; case '4': /* --vdir */ xtables_param_act(XTF_NO_INVERT, "ipvs", "--vdir", invert); if (strcasecmp(optarg, "ORIGINAL") == 0) { data->bitmask |= XT_IPVS_DIR; data->invert &= ~XT_IPVS_DIR; } else if (strcasecmp(optarg, "REPLY") == 0) { data->bitmask |= XT_IPVS_DIR; data->invert |= XT_IPVS_DIR; } else { xtables_param_act(XTF_BAD_VALUE, "ipvs", "--vdir", optarg); } break; case '5': /* --vmethod */ if (strcasecmp(optarg, "GATE") == 0) data->fwd_method = IP_VS_CONN_F_DROUTE; else if (strcasecmp(optarg, "IPIP") == 0) data->fwd_method = IP_VS_CONN_F_TUNNEL; else if (strcasecmp(optarg, "MASQ") == 0) data->fwd_method = IP_VS_CONN_F_MASQ; else xtables_param_act(XTF_BAD_VALUE, "ipvs", "--vmethod", optarg); break; case '6': /* --vportctl */ data->vportctl = htons(xtables_parse_port(optarg, "tcp")); break; default: /* Hu? How did we come here? */ assert(false); return 0; } if (op & XT_IPVS_ONCE_MASK) { if (data->invert & XT_IPVS_IPVS_PROPERTY) xtables_error(PARAMETER_PROBLEM, "! --ipvs cannot be together with" " other options"); data->bitmask |= XT_IPVS_IPVS_PROPERTY; } data->bitmask |= op; if (invert) data->invert |= op; *flags |= op; return 1; multiple_use: xtables_error(PARAMETER_PROBLEM, "multiple use of the same IPVS option is not allowed"); }
static int policy_parse(int c, int invert, unsigned int *flags, struct xt_policy_info *info, uint8_t family) { struct xt_policy_elem *e = &info->pol[info->len]; struct in_addr *addr = NULL, mask; struct in6_addr *addr6 = NULL, mask6; unsigned int naddr = 0, num; int mode; xtables_check_inverse(optarg, &invert, &optind, 0); switch (c) { case '1': if (info->flags & (XT_POLICY_MATCH_IN | XT_POLICY_MATCH_OUT)) xtables_error(PARAMETER_PROBLEM, "policy match: double --dir option"); if (invert) xtables_error(PARAMETER_PROBLEM, "policy match: can't invert --dir option"); info->flags |= parse_direction(optarg); break; case '2': if (invert) xtables_error(PARAMETER_PROBLEM, "policy match: can't invert --policy option"); info->flags |= parse_policy(optarg); break; case '3': if (info->flags & XT_POLICY_MATCH_STRICT) xtables_error(PARAMETER_PROBLEM, "policy match: double --strict option"); if (invert) xtables_error(PARAMETER_PROBLEM, "policy match: can't invert --strict option"); info->flags |= XT_POLICY_MATCH_STRICT; break; case '4': if (e->match.reqid) xtables_error(PARAMETER_PROBLEM, "policy match: double --reqid option"); e->match.reqid = 1; e->invert.reqid = invert; if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) xtables_param_act(XTF_BAD_VALUE, "policy", "--spi", optarg); e->reqid = num; break; case '5': if (e->match.spi) xtables_error(PARAMETER_PROBLEM, "policy match: double --spi option"); e->match.spi = 1; e->invert.spi = invert; if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) xtables_param_act(XTF_BAD_VALUE, "policy", "--spi", optarg); e->spi = num; break; case '6': if (e->match.saddr) xtables_error(PARAMETER_PROBLEM, "policy match: double --tunnel-src option"); if (family == NFPROTO_IPV6) xtables_ip6parse_any(optarg, &addr6, &mask6, &naddr); else xtables_ipparse_any(optarg, &addr, &mask, &naddr); if (naddr > 1) xtables_error(PARAMETER_PROBLEM, "policy match: name resolves to multiple IPs"); e->match.saddr = 1; e->invert.saddr = invert; if (family == NFPROTO_IPV6) { memcpy(&e->saddr.a6, addr6, sizeof(*addr6)); memcpy(&e->smask.a6, &mask6, sizeof(mask6)); } else { e->saddr.a4 = addr[0]; e->smask.a4 = mask; } break; case '7': if (e->match.daddr) xtables_error(PARAMETER_PROBLEM, "policy match: double --tunnel-dst option"); if (family == NFPROTO_IPV6) xtables_ip6parse_any(optarg, &addr6, &mask6, &naddr); else xtables_ipparse_any(optarg, &addr, &mask, &naddr); if (naddr > 1) xtables_error(PARAMETER_PROBLEM, "policy match: name resolves to multiple IPs"); e->match.daddr = 1; e->invert.daddr = invert; if (family == NFPROTO_IPV6) { memcpy(&e->daddr.a6, addr6, sizeof(*addr6)); memcpy(&e->dmask.a6, &mask6, sizeof(mask6)); } else { e->daddr.a4 = addr[0]; e->dmask.a4 = mask; } break; case '8': if (e->match.proto) xtables_error(PARAMETER_PROBLEM, "policy match: double --proto option"); e->proto = xtables_parse_protocol(optarg); if (e->proto != IPPROTO_AH && e->proto != IPPROTO_ESP && e->proto != IPPROTO_COMP) xtables_error(PARAMETER_PROBLEM, "policy match: protocol must ah/esp/ipcomp"); e->match.proto = 1; e->invert.proto = invert; break; case '9': if (e->match.mode) xtables_error(PARAMETER_PROBLEM, "policy match: double --mode option"); mode = parse_mode(optarg); e->match.mode = 1; e->invert.mode = invert; e->mode = mode; break; case 'a': if (invert) xtables_error(PARAMETER_PROBLEM, "policy match: can't invert --next option"); if (++info->len == XT_POLICY_MAX_ELEM) xtables_error(PARAMETER_PROBLEM, "policy match: maximum policy depth reached"); break; default: return 0; } return 1; }
static int conntrack_mt_parse(int c, bool invert, unsigned int *flags, struct xt_conntrack_mtinfo2 *info) { unsigned int port; char *p; switch (c) { case '1': /* --ctstate */ conntrack_ps_states(info, optarg); info->match_flags |= XT_CONNTRACK_STATE; if (invert) info->invert_flags |= XT_CONNTRACK_STATE; break; case '2': /* --ctproto */ /* Canonicalize into lower case */ for (p = optarg; *p != '\0'; ++p) *p = tolower(*p); info->l4proto = xtables_parse_protocol(optarg); if (info->l4proto == 0 && (info->invert_flags & XT_INV_PROTO)) xtables_error(PARAMETER_PROBLEM, "conntrack: rule would " "never match protocol"); info->match_flags |= XT_CONNTRACK_PROTO; if (invert) info->invert_flags |= XT_CONNTRACK_PROTO; break; case '7': /* --ctstatus */ conntrack_ps_statuses(info, optarg); info->match_flags |= XT_CONNTRACK_STATUS; if (invert) info->invert_flags |= XT_CONNTRACK_STATUS; break; case '8': /* --ctexpire */ conntrack_ps_expires(info, optarg); info->match_flags |= XT_CONNTRACK_EXPIRES; if (invert) info->invert_flags |= XT_CONNTRACK_EXPIRES; break; case 'a': /* --ctorigsrcport */ if (!xtables_strtoui(optarg, NULL, &port, 0, UINT16_MAX)) xtables_param_act(XTF_BAD_VALUE, "conntrack", "--ctorigsrcport", optarg); info->match_flags |= XT_CONNTRACK_ORIGSRC_PORT; info->origsrc_port = htons(port); if (invert) info->invert_flags |= XT_CONNTRACK_ORIGSRC_PORT; break; case 'b': /* --ctorigdstport */ if (!xtables_strtoui(optarg, NULL, &port, 0, UINT16_MAX)) xtables_param_act(XTF_BAD_VALUE, "conntrack", "--ctorigdstport", optarg); info->match_flags |= XT_CONNTRACK_ORIGDST_PORT; info->origdst_port = htons(port); if (invert) info->invert_flags |= XT_CONNTRACK_ORIGDST_PORT; break; case 'c': /* --ctreplsrcport */ if (!xtables_strtoui(optarg, NULL, &port, 0, UINT16_MAX)) xtables_param_act(XTF_BAD_VALUE, "conntrack", "--ctreplsrcport", optarg); info->match_flags |= XT_CONNTRACK_REPLSRC_PORT; info->replsrc_port = htons(port); if (invert) info->invert_flags |= XT_CONNTRACK_REPLSRC_PORT; break; case 'd': /* --ctrepldstport */ if (!xtables_strtoui(optarg, NULL, &port, 0, UINT16_MAX)) xtables_param_act(XTF_BAD_VALUE, "conntrack", "--ctrepldstport", optarg); info->match_flags |= XT_CONNTRACK_REPLDST_PORT; info->repldst_port = htons(port); if (invert) info->invert_flags |= XT_CONNTRACK_REPLDST_PORT; break; case 'e': /* --ctdir */ xtables_param_act(XTF_NO_INVERT, "conntrack", "--ctdir", invert); if (strcasecmp(optarg, "ORIGINAL") == 0) { info->match_flags |= XT_CONNTRACK_DIRECTION; info->invert_flags &= ~XT_CONNTRACK_DIRECTION; } else if (strcasecmp(optarg, "REPLY") == 0) { info->match_flags |= XT_CONNTRACK_DIRECTION; info->invert_flags |= XT_CONNTRACK_DIRECTION; } else { xtables_param_act(XTF_BAD_VALUE, "conntrack", "--ctdir", optarg); } break; default: return false; } *flags = info->match_flags; return true; }
static int conntrack_parse(int c, char **argv, int invert, unsigned int *flags, const void *entry, struct xt_entry_match **match) { struct xt_conntrack_info *sinfo = (void *)(*match)->data; char *protocol = NULL; unsigned int naddrs = 0; struct in_addr *addrs = NULL; switch (c) { case '1': xtables_check_inverse(optarg, &invert, &optind, 0); parse_states(argv[optind-1], sinfo); if (invert) { sinfo->invflags |= XT_CONNTRACK_STATE; } sinfo->flags |= XT_CONNTRACK_STATE; break; case '2': xtables_check_inverse(optarg, &invert, &optind, 0); if(invert) sinfo->invflags |= XT_CONNTRACK_PROTO; /* Canonicalize into lower case */ for (protocol = argv[optind-1]; *protocol; protocol++) *protocol = tolower(*protocol); protocol = argv[optind-1]; sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum = xtables_parse_protocol(protocol); if (sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum == 0 && (sinfo->invflags & XT_INV_PROTO)) xtables_error(PARAMETER_PROBLEM, "rule would never match protocol"); sinfo->flags |= XT_CONNTRACK_PROTO; break; case '3': xtables_check_inverse(optarg, &invert, &optind, 0); if (invert) sinfo->invflags |= XT_CONNTRACK_ORIGSRC; xtables_ipparse_any(argv[optind-1], &addrs, &sinfo->sipmsk[IP_CT_DIR_ORIGINAL], &naddrs); if(naddrs > 1) xtables_error(PARAMETER_PROBLEM, "multiple IP addresses not allowed"); if(naddrs == 1) { sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip = addrs[0].s_addr; } sinfo->flags |= XT_CONNTRACK_ORIGSRC; break; case '4': xtables_check_inverse(optarg, &invert, &optind, 0); if (invert) sinfo->invflags |= XT_CONNTRACK_ORIGDST; xtables_ipparse_any(argv[optind-1], &addrs, &sinfo->dipmsk[IP_CT_DIR_ORIGINAL], &naddrs); if(naddrs > 1) xtables_error(PARAMETER_PROBLEM, "multiple IP addresses not allowed"); if(naddrs == 1) { sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip = addrs[0].s_addr; } sinfo->flags |= XT_CONNTRACK_ORIGDST; break; case '5': xtables_check_inverse(optarg, &invert, &optind, 0); if (invert) sinfo->invflags |= XT_CONNTRACK_REPLSRC; xtables_ipparse_any(argv[optind-1], &addrs, &sinfo->sipmsk[IP_CT_DIR_REPLY], &naddrs); if(naddrs > 1) xtables_error(PARAMETER_PROBLEM, "multiple IP addresses not allowed"); if(naddrs == 1) { sinfo->tuple[IP_CT_DIR_REPLY].src.ip = addrs[0].s_addr; } sinfo->flags |= XT_CONNTRACK_REPLSRC; break; case '6': xtables_check_inverse(optarg, &invert, &optind, 0); if (invert) sinfo->invflags |= XT_CONNTRACK_REPLDST; xtables_ipparse_any(argv[optind-1], &addrs, &sinfo->dipmsk[IP_CT_DIR_REPLY], &naddrs); if(naddrs > 1) xtables_error(PARAMETER_PROBLEM, "multiple IP addresses not allowed"); if(naddrs == 1) { sinfo->tuple[IP_CT_DIR_REPLY].dst.ip = addrs[0].s_addr; } sinfo->flags |= XT_CONNTRACK_REPLDST; break; case '7': xtables_check_inverse(optarg, &invert, &optind, 0); parse_statuses(argv[optind-1], sinfo); if (invert) { sinfo->invflags |= XT_CONNTRACK_STATUS; } sinfo->flags |= XT_CONNTRACK_STATUS; break; case '8': xtables_check_inverse(optarg, &invert, &optind, 0); parse_expires(argv[optind-1], sinfo); if (invert) { sinfo->invflags |= XT_CONNTRACK_EXPIRES; } sinfo->flags |= XT_CONNTRACK_EXPIRES; break; default: return 0; } *flags = sinfo->flags; return 1; }
int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table, bool restore) { struct iptables_command_state cs; int verbose = 0; const char *chain = NULL; const char *policy = NULL, *newname = NULL; unsigned int rulenum = 0, command = 0; int ret = 1; struct xtables_match *m; struct xtables_rule_match *matchp; struct xtables_target *t; struct xtables_args args = { .family = h->family, }; memset(&cs, 0, sizeof(cs)); cs.jumpto = ""; cs.argv = argv; /* re-set optind to 0 in case do_command4 gets called * a second time */ optind = 0; /* clear mflags in case do_command4 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; } /* Suppress error messages: we may add new options if we demand-load a protocol. */ opterr = 0; h->ops = nft_family_ops_lookup(h->family); if (h->ops == NULL) xtables_error(PARAMETER_PROBLEM, "Unknown family"); opts = xt_params->orig_opts; while ((cs.c = getopt_long(argc, argv, "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:g:46", opts, NULL)) != -1) { switch (cs.c) { /* * Command selection */ case 'A': add_command(&command, CMD_APPEND, CMD_NONE, cs.invert); chain = optarg; break; case 'C': add_command(&command, CMD_CHECK, CMD_NONE, cs.invert); chain = optarg; break; case 'D': add_command(&command, CMD_DELETE, CMD_NONE, cs.invert); chain = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') { rulenum = parse_rulenumber(argv[optind++]); command = CMD_DELETE_NUM; } break; case 'R': add_command(&command, CMD_REPLACE, CMD_NONE, cs.invert); chain = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') rulenum = parse_rulenumber(argv[optind++]); else xtables_error(PARAMETER_PROBLEM, "-%c requires a rule number", cmd2char(CMD_REPLACE)); break; case 'I': add_command(&command, CMD_INSERT, CMD_NONE, cs.invert); chain = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') rulenum = parse_rulenumber(argv[optind++]); else rulenum = 1; break; case 'L': add_command(&command, CMD_LIST, CMD_ZERO | CMD_ZERO_NUM, cs.invert); if (optarg) chain = optarg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') chain = argv[optind++]; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') rulenum = parse_rulenumber(argv[optind++]); break; case 'S': add_command(&command, CMD_LIST_RULES, CMD_ZERO|CMD_ZERO_NUM, cs.invert); if (optarg) chain = optarg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') chain = argv[optind++]; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') rulenum = parse_rulenumber(argv[optind++]); break; case 'F': add_command(&command, CMD_FLUSH, CMD_NONE, cs.invert); if (optarg) chain = optarg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') chain = argv[optind++]; break; case 'Z': add_command(&command, CMD_ZERO, CMD_LIST|CMD_LIST_RULES, cs.invert); if (optarg) chain = optarg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') chain = argv[optind++]; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') { rulenum = parse_rulenumber(argv[optind++]); command = CMD_ZERO_NUM; } break; case 'N': if (optarg && (*optarg == '-' || *optarg == '!')) xtables_error(PARAMETER_PROBLEM, "chain name not allowed to start " "with `%c'\n", *optarg); if (xtables_find_target(optarg, XTF_TRY_LOAD)) xtables_error(PARAMETER_PROBLEM, "chain name may not clash " "with target name\n"); add_command(&command, CMD_NEW_CHAIN, CMD_NONE, cs.invert); chain = optarg; break; case 'X': add_command(&command, CMD_DELETE_CHAIN, CMD_NONE, cs.invert); if (optarg) chain = optarg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') chain = argv[optind++]; break; case 'E': add_command(&command, CMD_RENAME_CHAIN, CMD_NONE, cs.invert); chain = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') newname = argv[optind++]; else xtables_error(PARAMETER_PROBLEM, "-%c requires old-chain-name and " "new-chain-name", cmd2char(CMD_RENAME_CHAIN)); break; case 'P': add_command(&command, CMD_SET_POLICY, CMD_NONE, cs.invert); chain = optarg; if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') policy = argv[optind++]; else xtables_error(PARAMETER_PROBLEM, "-%c requires a chain and a policy", cmd2char(CMD_SET_POLICY)); break; case 'h': if (!optarg) optarg = argv[optind]; /* iptables -p icmp -h */ if (!cs.matches && cs.protocol) xtables_find_match(cs.protocol, XTF_TRY_LOAD, &cs.matches); exit_printhelp(cs.matches); /* * Option selection */ case 'p': set_option(&cs.options, OPT_PROTOCOL, &args.invflags, cs.invert); /* Canonicalize into lower case */ for (cs.protocol = optarg; *cs.protocol; cs.protocol++) *cs.protocol = tolower(*cs.protocol); cs.protocol = optarg; args.proto = xtables_parse_protocol(cs.protocol); if (args.proto == 0 && (args.invflags & XT_INV_PROTO)) xtables_error(PARAMETER_PROBLEM, "rule would never match protocol"); /* This needs to happen here to parse extensions */ h->ops->proto_parse(&cs, &args); break; case 's': set_option(&cs.options, OPT_SOURCE, &args.invflags, cs.invert); args.shostnetworkmask = optarg; break; case 'd': set_option(&cs.options, OPT_DESTINATION, &args.invflags, cs.invert); args.dhostnetworkmask = optarg; break; #ifdef IPT_F_GOTO case 'g': set_option(&cs.options, OPT_JUMP, &args.invflags, cs.invert); args.goto_set = true; cs.jumpto = parse_target(optarg); break; #endif case 'j': command_jump(&cs); break; case 'i': if (*optarg == '\0') xtables_error(PARAMETER_PROBLEM, "Empty interface is likely to be " "undesired"); set_option(&cs.options, OPT_VIANAMEIN, &args.invflags, cs.invert); xtables_parse_interface(optarg, args.iniface, args.iniface_mask); break; case 'o': if (*optarg == '\0') xtables_error(PARAMETER_PROBLEM, "Empty interface is likely to be " "undesired"); set_option(&cs.options, OPT_VIANAMEOUT, &args.invflags, cs.invert); xtables_parse_interface(optarg, args.outiface, args.outiface_mask); break; case 'f': if (args.family == AF_INET6) { xtables_error(PARAMETER_PROBLEM, "`-f' is not supported in IPv6, " "use -m frag instead"); } set_option(&cs.options, OPT_FRAGMENT, &args.invflags, cs.invert); args.flags |= IPT_F_FRAG; break; case 'v': if (!verbose) set_option(&cs.options, OPT_VERBOSE, &args.invflags, cs.invert); verbose++; break; case 'm': command_match(&cs); break; case 'n': set_option(&cs.options, OPT_NUMERIC, &args.invflags, cs.invert); break; case 't': if (cs.invert) xtables_error(PARAMETER_PROBLEM, "unexpected ! flag before --table"); *table = optarg; break; case 'x': set_option(&cs.options, OPT_EXPANDED, &args.invflags, cs.invert); break; case 'V': if (cs.invert) printf("Not %s ;-)\n", prog_vers); else printf("%s v%s\n", prog_name, prog_vers); exit(0); case 'w': if (restore) { xtables_error(PARAMETER_PROBLEM, "You cannot use `-w' from " "iptables-restore"); } break; case '0': set_option(&cs.options, OPT_LINENUMBERS, &args.invflags, cs.invert); break; case 'M': xtables_modprobe_program = optarg; break; case 'c': set_option(&cs.options, OPT_COUNTERS, &args.invflags, cs.invert); args.pcnt = optarg; args.bcnt = strchr(args.pcnt + 1, ','); if (args.bcnt) args.bcnt++; if (!args.bcnt && optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') args.bcnt = argv[optind++]; if (!args.bcnt) xtables_error(PARAMETER_PROBLEM, "-%c requires packet and byte counter", opt2char(OPT_COUNTERS)); if (sscanf(args.pcnt, "%llu", &args.pcnt_cnt) != 1) xtables_error(PARAMETER_PROBLEM, "-%c packet counter not numeric", opt2char(OPT_COUNTERS)); if (sscanf(args.bcnt, "%llu", &args.bcnt_cnt) != 1) xtables_error(PARAMETER_PROBLEM, "-%c byte counter not numeric", opt2char(OPT_COUNTERS)); break; case '4': if (args.family != AF_INET) exit_tryhelp(2); h->ops = nft_family_ops_lookup(args.family); break; case '6': args.family = AF_INET6; xtables_set_nfproto(AF_INET6); h->ops = nft_family_ops_lookup(args.family); if (h->ops == NULL) xtables_error(PARAMETER_PROBLEM, "Unknown family"); break; case 1: /* non option */ if (optarg[0] == '!' && optarg[1] == '\0') { if (cs.invert) xtables_error(PARAMETER_PROBLEM, "multiple consecutive ! not" " allowed"); cs.invert = TRUE; optarg[0] = '\0'; continue; } fprintf(stderr, "Bad argument `%s'\n", optarg); exit_tryhelp(2); default: if (command_default(&cs, &xtables_globals) == 1) /* cf. ip6tables.c */ continue; break; } cs.invert = FALSE; } if (strcmp(*table, "nat") == 0 && ((policy != NULL && strcmp(policy, "DROP") == 0) || (cs.jumpto != NULL && strcmp(cs.jumpto, "DROP") == 0))) xtables_error(PARAMETER_PROBLEM, "\nThe \"nat\" table is not intended for filtering, " "the use of DROP is therefore inhibited.\n\n"); for (matchp = cs.matches; matchp; matchp = matchp->next) xtables_option_mfcall(matchp->match); if (cs.target != NULL) xtables_option_tfcall(cs.target); /* Fix me: must put inverse options checking here --MN */ if (optind < argc) xtables_error(PARAMETER_PROBLEM, "unknown arguments found on commandline"); if (!command) xtables_error(PARAMETER_PROBLEM, "no command specified"); if (cs.invert) xtables_error(PARAMETER_PROBLEM, "nothing appropriate following !"); /* Set only if required, needed by xtables-restore */ if (h->family == AF_UNSPEC) h->family = args.family; h->ops->post_parse(command, &cs, &args); if (command == CMD_REPLACE && (args.s.naddrs != 1 || args.d.naddrs != 1)) xtables_error(PARAMETER_PROBLEM, "Replacement rule does not " "specify a unique address"); generic_opt_check(command, cs.options); if (chain != NULL && strlen(chain) >= XT_EXTENSION_MAXNAMELEN) xtables_error(PARAMETER_PROBLEM, "chain name `%s' too long (must be under %u chars)", chain, XT_EXTENSION_MAXNAMELEN); if (command == CMD_APPEND || command == CMD_DELETE || command == CMD_CHECK || command == CMD_INSERT || command == CMD_REPLACE) { if (strcmp(chain, "PREROUTING") == 0 || strcmp(chain, "INPUT") == 0) { /* -o not valid with incoming packets. */ if (cs.options & OPT_VIANAMEOUT) xtables_error(PARAMETER_PROBLEM, "Can't use -%c with %s\n", opt2char(OPT_VIANAMEOUT), chain); } if (strcmp(chain, "POSTROUTING") == 0 || strcmp(chain, "OUTPUT") == 0) { /* -i not valid with outgoing packets */ if (cs.options & OPT_VIANAMEIN) xtables_error(PARAMETER_PROBLEM, "Can't use -%c with %s\n", opt2char(OPT_VIANAMEIN), chain); } /* * Contrary to what iptables does, we assume that any jumpto * is a custom chain jumps (if no target is found). Later on, * nf_table will spot the error if the chain does not exists. */ } switch (command) { case CMD_APPEND: ret = add_entry(chain, *table, &cs, 0, h->family, args.s, args.d, cs.options&OPT_VERBOSE, h, true); break; case CMD_DELETE: ret = delete_entry(chain, *table, &cs, h->family, args.s, args.d, cs.options&OPT_VERBOSE, h); break; case CMD_DELETE_NUM: ret = nft_rule_delete_num(h, chain, *table, rulenum - 1, verbose); break; case CMD_CHECK: ret = check_entry(chain, *table, &cs, h->family, args.s, args.d, cs.options&OPT_VERBOSE, h); break; case CMD_REPLACE: ret = replace_entry(chain, *table, &cs, rulenum - 1, h->family, args.s, args.d, cs.options&OPT_VERBOSE, h); break; case CMD_INSERT: ret = add_entry(chain, *table, &cs, rulenum - 1, h->family, args.s, args.d, cs.options&OPT_VERBOSE, h, false); break; case CMD_FLUSH: ret = nft_rule_flush(h, chain, *table); break; case CMD_ZERO: ret = nft_chain_zero_counters(h, chain, *table); break; case CMD_ZERO_NUM: ret = nft_rule_zero_counters(h, chain, *table, rulenum - 1); break; case CMD_LIST: case CMD_LIST|CMD_ZERO: case CMD_LIST|CMD_ZERO_NUM: ret = list_entries(h, chain, *table, rulenum, cs.options&OPT_VERBOSE, cs.options&OPT_NUMERIC, cs.options&OPT_EXPANDED, cs.options&OPT_LINENUMBERS); if (ret && (command & CMD_ZERO)) ret = nft_chain_zero_counters(h, chain, *table); if (ret && (command & CMD_ZERO_NUM)) ret = nft_rule_zero_counters(h, chain, *table, rulenum - 1); break; case CMD_LIST_RULES: case CMD_LIST_RULES|CMD_ZERO: case CMD_LIST_RULES|CMD_ZERO_NUM: ret = list_rules(h, chain, *table, rulenum, cs.options&OPT_VERBOSE); if (ret && (command & CMD_ZERO)) ret = nft_chain_zero_counters(h, chain, *table); if (ret && (command & CMD_ZERO_NUM)) ret = nft_rule_zero_counters(h, chain, *table, rulenum - 1); break; case CMD_NEW_CHAIN: ret = nft_chain_user_add(h, chain, *table); break; case CMD_DELETE_CHAIN: ret = nft_chain_user_del(h, chain, *table); break; case CMD_RENAME_CHAIN: ret = nft_chain_user_rename(h, chain, *table, newname); break; case CMD_SET_POLICY: ret = nft_chain_set(h, *table, chain, policy, NULL); if (ret < 0) xtables_error(PARAMETER_PROBLEM, "Wrong policy `%s'\n", policy); break; default: /* We should never reach this... */ exit_tryhelp(2); } /* if (verbose > 1) dump_entries(*handle); */ xtables_rule_matches_free(&cs.matches); if (h->family == AF_INET) { free(args.s.addr.v4); free(args.s.mask.v4); free(args.d.addr.v4); free(args.d.mask.v4); } else if (h->family == AF_INET6) { free(args.s.addr.v6); free(args.s.mask.v6); free(args.d.addr.v6); free(args.d.mask.v6); } xtables_free_opts(1); return ret; }