static void ebt_add_match(struct xtables_match *m, struct ebtables_command_state *cs) { struct xtables_rule_match *i, **rule_matches = &cs->matches; struct xtables_match *newm; struct ebt_match *newnode; /* match already in rule_matches, skip inclusion */ for (i = *rule_matches; i; i = i->next) { if (strcmp(m->name, i->match->name) == 0) { i->match->mflags |= m->mflags; return; } } newm = xtables_find_match(m->name, XTF_LOAD_MUST_SUCCEED, rule_matches); if (newm == NULL) xtables_error(OTHER_PROBLEM, "Unable to add match %s", m->name); newm->mflags = m->mflags; /* glue code for watchers */ newnode = calloc(1, sizeof(struct ebt_match)); if (newnode == NULL) xtables_error(OTHER_PROBLEM, "Unable to alloc memory"); newnode->ismatch = true; newnode->u.match = newm; if (cs->match_list == NULL) cs->match_list = newnode; else cs->match_list->next = newnode; }
static struct xtables_match * find_proto(const char *pname, enum xtables_tryload tryload, int nolookup, struct xtables_rule_match **matches) { unsigned int proto; if (xtables_strtoui(pname, NULL, &proto, 0, UINT8_MAX)) { const char *protoname = proto_to_name(proto, nolookup); if (protoname) return xtables_find_match(protoname, tryload, matches); } else return xtables_find_match(pname, tryload, matches); return NULL; }
static void command_match(struct iptables_command_state *cs) { struct xtables_match *m; size_t size; if (cs->invert) xtables_error(PARAMETER_PROBLEM, "unexpected ! flag before --match"); m = xtables_find_match(optarg, XTF_LOAD_MUST_SUCCEED, &cs->matches); size = XT_ALIGN(sizeof(struct xt_entry_match)) + m->size; m->m = xtables_calloc(1, size); m->m->u.match_size = size; if (m->real_name == NULL) { strcpy(m->m->u.user.name, m->name); } else { strcpy(m->m->u.user.name, m->real_name); if (!(m->ext_flags & XTABLES_EXT_ALIAS)) fprintf(stderr, "Notice: the %s match is converted into %s match " "in rule listing and saving.\n", m->name, m->real_name); } m->m->u.user.revision = m->revision; xs_init_match(m); if (m == m->next) return; /* Merge options for non-cloned matches */ if (m->x6_options != NULL) opts = xtables_options_xfrm(xtables_globals.orig_opts, opts, m->x6_options, &m->option_offset); else if (m->extra_opts != NULL) opts = xtables_merge_options(xtables_globals.orig_opts, opts, m->extra_opts, &m->option_offset); if (opts == NULL) xtables_error(OTHER_PROBLEM, "can't alloc memory!"); }
static void *load_extension(const char *search_path, const char *af_prefix, const char *name, bool is_target) { const char *all_prefixes[] = {"libxt_", af_prefix, NULL}; const char **prefix; const char *dir = search_path, *next; void *ptr = NULL; struct stat sb; char path[256]; do { next = strchr(dir, ':'); if (next == NULL) next = dir + strlen(dir); for (prefix = all_prefixes; *prefix != NULL; ++prefix) { snprintf(path, sizeof(path), "%.*s/%s%s.so", (unsigned int)(next - dir), dir, *prefix, name); if (stat(path, &sb) != 0) { if (errno == ENOENT) continue; fprintf(stderr, "%s: %s\n", path, strerror(errno)); return NULL; } if (dlopen(path, RTLD_NOW) == NULL) { fprintf(stderr, "%s: %s\n", path, dlerror()); break; } if (is_target) ptr = xtables_find_target(name, XTF_DONT_LOAD); else ptr = xtables_find_match(name, XTF_DONT_LOAD, NULL); if (ptr != NULL) return ptr; fprintf(stderr, "%s: no \"%s\" extension found for " "this protocol\n", path, name); errno = ENOENT; return NULL; } dir = next + 1; } while (*next != '\0'); return NULL; }
static void xtables_fully_register_pending_match(struct xtables_match *me) { struct xtables_match **i, *old; const char *rn; int compare; old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL); if (old) { compare = xtables_match_prefer(old, me); if (compare == 0) { fprintf(stderr, "%s: match `%s' already registered.\n", xt_params->program_name, me->name); exit(1); } /* Now we have two (or more) options, check compatibility. */ rn = (old->real_name != NULL) ? old->real_name : old->name; if (compare > 0 && compatible_match_revision(rn, old->revision)) return; /* See if new match can be used. */ rn = (me->real_name != NULL) ? me->real_name : me->name; if (!compatible_match_revision(rn, me->revision)) return; /* Delete old one. */ for (i = &xtables_matches; *i!=old; i = &(*i)->next); *i = old->next; } if (me->size != XT_ALIGN(me->size)) { fprintf(stderr, "%s: match `%s' has invalid size %u.\n", xt_params->program_name, me->name, (unsigned int)me->size); exit(1); } /* Append to list. */ for (i = &xtables_matches; *i; i = &(*i)->next); me->next = NULL; *i = me; me->m = NULL; me->mflags = 0; }
static void xtables_fully_register_pending_match(struct xtables_match *me) { struct xtables_match **i, *old; old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL); if (old) { if (old->revision == me->revision && old->family == me->family) { fprintf(stderr, "%s: match `%s' already registered.\n", xt_params->program_name, me->name); exit(1); } /* Now we have two (or more) options, check compatibility. */ if (compatible_match_revision(old->name, old->revision) && old->revision > me->revision) return; /* See if new match can be used. */ if (!compatible_match_revision(me->name, me->revision)) return; /* Prefer !AF_UNSPEC over AF_UNSPEC for same revision. */ if (old->revision == me->revision && me->family == AF_UNSPEC) return; /* Delete old one. */ for (i = &xtables_matches; *i!=old; i = &(*i)->next); *i = old->next; } if (me->size != XT_ALIGN(me->size)) { fprintf(stderr, "%s: match `%s' has invalid size %u.\n", xt_params->program_name, me->name, (unsigned int)me->size); exit(1); } /* Append to list. */ for (i = &xtables_matches; *i; i = &(*i)->next); me->next = NULL; *i = me; me->m = NULL; me->mflags = 0; }
void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e) { uint32_t mt_len; const char *mt_name = nftnl_expr_get_str(e, NFTNL_EXPR_MT_NAME); const void *mt_info = nftnl_expr_get(e, NFTNL_EXPR_MT_INFO, &mt_len); struct xtables_match *match; struct xtables_rule_match **matches; struct xt_entry_match *m; struct nft_family_ops *ops; switch (ctx->family) { case NFPROTO_IPV4: case NFPROTO_IPV6: matches = &ctx->state.cs->matches; break; case NFPROTO_BRIDGE: matches = &ctx->state.cs_eb->matches; break; default: fprintf(stderr, "BUG: nft_parse_match() unknown family %d\n", ctx->family); exit(EXIT_FAILURE); } match = xtables_find_match(mt_name, XTF_TRY_LOAD, matches); if (match == NULL) return; m = calloc(1, sizeof(struct xt_entry_match) + mt_len); if (m == NULL) { fprintf(stderr, "OOM"); exit(EXIT_FAILURE); } memcpy(&m->data, mt_info, mt_len); m->u.match_size = mt_len + XT_ALIGN(sizeof(struct xt_entry_match)); m->u.user.revision = nftnl_expr_get_u32(e, NFTNL_EXPR_TG_REV); strcpy(m->u.user.name, match->name); match->m = m; ops = nft_family_ops_lookup(ctx->family); if (ops->parse_match != NULL) ops->parse_match(match, nft_get_data(ctx)); }
/* This code is very similar to iptables/xtables.c:command_match() */ static void ebt_load_match(const char *name) { struct xtables_match *m; size_t size; m = xtables_find_match(name, XTF_LOAD_MUST_SUCCEED, NULL); if (m == NULL) xtables_error(OTHER_PROBLEM, "Unable to load %s match", name); size = XT_ALIGN(sizeof(struct xt_entry_match)) + m->size; m->m = xtables_calloc(1, size); m->m->u.match_size = size; strcpy(m->m->u.user.name, m->name); m->m->u.user.revision = m->revision; xs_init_match(m); opts = merge_options(opts, m->extra_opts, &m->option_offset); if (opts == NULL) xtables_error(OTHER_PROBLEM, "Can't alloc memory"); }
static int print_match(const struct xt_entry_match *m, const struct ipt_ip *ip, int numeric) { const struct xtables_match *match = xtables_find_match(m->u.user.name, XTF_TRY_LOAD, NULL); if (match) { if (match->print) match->print(ip, m, numeric); else ptr += sprintf(ptr,"%s ", match->name); } else { if (m->u.user.name[0]) ptr += sprintf(ptr,"UNKNOWN match `%s' ", m->u.user.name); } /* Don't stop iterating. */ return 0; }
static int print_match_save(const struct xt_entry_match *e, const struct ipt_ip *ip) { char buf[BUFSIZ]; const struct xtables_match *match = xtables_find_match(e->u.user.name, XTF_TRY_LOAD, NULL); if (match) { #ifdef OLD_IPTABLES ptr += sprintf(ptr," -m %s", e->u.user.name); #else ptr += sprintf(ptr, " -m %s", match->alias ? match->alias(e) : e->u.user.name); #endif /* some matches don't provide a save function */ if (match->save){ memset(buf, 0, sizeof(buf)); switchStdout("/dev/null"); setvbuf(stdout, buf, _IOLBF, BUFSIZ); match->save(ip, e); fflush(stdout); setbuf(stdout, NULL); revertStdout(); ptr += sprintf(ptr, "%s", buf); } } else { if (e->u.match_size) { fprintf(stderr, "Can't find library for match `%s'\n", e->u.user.name); exit(1); } } return 0; }
void nft_rule_to_iptables_command_state(struct nftnl_rule *r, struct iptables_command_state *cs) { struct nftnl_expr_iter *iter; struct nftnl_expr *expr; int family = nftnl_rule_get_u32(r, NFTNL_RULE_FAMILY); struct nft_xt_ctx ctx = { .state.cs = cs, .family = family, }; iter = nftnl_expr_iter_create(r); if (iter == NULL) return; ctx.iter = iter; expr = nftnl_expr_iter_next(iter); while (expr != NULL) { const char *name = nftnl_expr_get_str(expr, NFTNL_EXPR_NAME); if (strcmp(name, "counter") == 0) nft_parse_counter(expr, &ctx.state.cs->counters); else if (strcmp(name, "payload") == 0) nft_parse_payload(&ctx, expr); else if (strcmp(name, "meta") == 0) nft_parse_meta(&ctx, expr); else if (strcmp(name, "bitwise") == 0) nft_parse_bitwise(&ctx, expr); else if (strcmp(name, "cmp") == 0) nft_parse_cmp(&ctx, expr); else if (strcmp(name, "immediate") == 0) nft_parse_immediate(&ctx, expr); else if (strcmp(name, "match") == 0) nft_parse_match(&ctx, expr); else if (strcmp(name, "target") == 0) nft_parse_target(&ctx, expr); expr = nftnl_expr_iter_next(iter); } nftnl_expr_iter_destroy(iter); if (nftnl_rule_is_set(r, NFTNL_RULE_USERDATA)) { const void *data; uint32_t len; struct xtables_match *match; struct xt_entry_match *m; data = nftnl_rule_get_data(r, NFTNL_RULE_USERDATA, &len); match = xtables_find_match("comment", XTF_TRY_LOAD, &cs->matches); if (match == NULL) return; m = calloc(1, sizeof(struct xt_entry_match) + len); if (m == NULL) { fprintf(stderr, "OOM"); exit(EXIT_FAILURE); } memcpy(&m->data, get_comment(data, len), len); m->u.match_size = len + XT_ALIGN(sizeof(struct xt_entry_match)); m->u.user.revision = 0; strcpy(m->u.user.name, match->name); match->m = m; } if (cs->target != NULL) cs->jumpto = cs->target->name; else if (cs->jumpto != NULL) cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD); else cs->jumpto = ""; } void print_header(unsigned int format, const char *chain, const char *pol, const struct xt_counters *counters, bool basechain, uint32_t refs) { printf("Chain %s", chain); if (basechain) { printf(" (policy %s", pol); if (!(format & FMT_NOCOUNTS)) { fputc(' ', stdout); xtables_print_num(counters->pcnt, (format|FMT_NOTABLE)); fputs("packets, ", stdout); xtables_print_num(counters->bcnt, (format|FMT_NOTABLE)); fputs("bytes", stdout); } printf(")\n"); } else { printf(" (%u references)\n", refs); } if (format & FMT_LINENUMBERS) printf(FMT("%-4s ", "%s "), "num"); if (!(format & FMT_NOCOUNTS)) { if (format & FMT_KILOMEGAGIGA) { printf(FMT("%5s ","%s "), "pkts"); printf(FMT("%5s ","%s "), "bytes"); } else { printf(FMT("%8s ","%s "), "pkts"); printf(FMT("%10s ","%s "), "bytes"); } } if (!(format & FMT_NOTARGET)) printf(FMT("%-9s ","%s "), "target"); fputs(" prot ", stdout); if (format & FMT_OPTIONS) fputs("opt", stdout); if (format & FMT_VIA) { printf(FMT(" %-6s ","%s "), "in"); printf(FMT("%-6s ","%s "), "out"); } printf(FMT(" %-19s ","%s "), "source"); printf(FMT(" %-19s "," %s "), "destination"); printf("\n"); }
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; }