diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c index c66e55b6438..10bfc0695e7 100644 --- a/sbin/ipfw/ipfw2.c +++ b/sbin/ipfw/ipfw2.c @@ -296,12 +296,18 @@ static struct _s_x rule_action_params[] = { /* * The 'lookup' instruction accepts one of the following arguments. - * -1 is a terminator for the list. - * Arguments are passed as v[1] in O_DST_LOOKUP options. + * Arguments are passed as arg1 in O_DST_LOOKUP options. */ -static int lookup_key[] = { - TOK_DSTIP, TOK_SRCIP, TOK_DSTPORT, TOK_SRCPORT, - TOK_UID, TOK_JAIL, TOK_DSCP, -1 }; +static struct _s_x lookup_keys[] = { + { "dst-ip", LOOKUP_DST_IP }, + { "src-ip", LOOKUP_SRC_IP }, + { "dst-port", LOOKUP_DST_PORT }, + { "src-port", LOOKUP_SRC_PORT }, + { "uid", LOOKUP_UID }, + { "jail", LOOKUP_JAIL }, + { "dscp", LOOKUP_DSCP }, + { NULL, 0 }, +}; static struct _s_x rule_options[] = { { "tagged", TOK_TAGGED }, @@ -399,8 +405,8 @@ static int ipfw_show_config(struct cmdline_opts *co, struct format_opts *fo, static void ipfw_list_tifaces(void); struct tidx; -static uint16_t pack_object(struct tidx *tstate, char *name, int otype); -static uint16_t pack_table(struct tidx *tstate, char *name); +static uint32_t pack_object(struct tidx *tstate, char *name, int otype); +static uint32_t pack_table(struct tidx *tstate, char *name); static char *table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx); static void object_sort_ctlv(ipfw_obj_ctlv *ctlv); @@ -619,6 +625,7 @@ do_set3(int optname, ip_fw3_opheader *op3, size_t optlen) err(EX_UNAVAILABLE, "socket"); op3->opcode = optname; + op3->version = IP_FW3_OPVER; /* use last version */ return (setsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, optlen)); } @@ -648,6 +655,7 @@ do_get3(int optname, ip_fw3_opheader *op3, size_t *optlen) err(EX_UNAVAILABLE, "socket"); op3->opcode = optname; + op3->version = IP_FW3_OPVER; /* use last version */ len = *optlen; error = getsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, &len); @@ -1192,34 +1200,40 @@ print_ip(struct buf_pr *bp, const struct format_opts *fo, ipfw_insn_ip *cmd) { struct hostent *he = NULL; struct in_addr *ia; - uint32_t len = F_LEN((ipfw_insn *)cmd); + uint32_t len = F_LEN(&cmd->o); uint32_t *a = ((ipfw_insn_u32 *)cmd)->d; char *t; bprintf(bp, " "); - if (cmd->o.opcode == O_IP_DST_LOOKUP && len > F_INSN_SIZE(ipfw_insn_u32)) { - uint32_t d = a[1]; - const char *arg = ""; - - if (d < sizeof(lookup_key)/sizeof(lookup_key[0])) - arg = match_value(rule_options, lookup_key[d]); - t = table_search_ctlv(fo->tstate, ((ipfw_insn *)cmd)->arg1); - bprintf(bp, "lookup %s %s", arg, t); - return; - } - if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) { + switch (cmd->o.opcode) { + case O_IP_SRC_ME: + case O_IP_DST_ME: bprintf(bp, "me"); return; - } - if (cmd->o.opcode == O_IP_SRC_LOOKUP || - cmd->o.opcode == O_IP_DST_LOOKUP) { - t = table_search_ctlv(fo->tstate, ((ipfw_insn *)cmd)->arg1); + + case O_IP_DST_LOOKUP: + if (len == F_INSN_SIZE(ipfw_insn_kidx) && + cmd->o.arg1 != LOOKUP_NONE) { + const char *key; + + key = match_value(lookup_keys, cmd->o.arg1); + t = table_search_ctlv(fo->tstate, + insntod(&cmd->o, kidx)->kidx); + bprintf(bp, "lookup %s %s", key != NULL ? key: + "", t); + return; + } + /* FALLTHROUGH */ + case O_IP_SRC_LOOKUP: + t = table_search_ctlv(fo->tstate, + insntod(&cmd->o, kidx)->kidx); bprintf(bp, "table(%s", t); - if (len == F_INSN_SIZE(ipfw_insn_u32)) - bprintf(bp, ",%u", *a); + if (len == F_INSN_SIZE(ipfw_insn_table)) + bprintf(bp, ",%u", insntod(&cmd->o, table)->value); bprintf(bp, ")"); return; } + if (cmd->o.opcode == O_IP_SRC_SET || cmd->o.opcode == O_IP_DST_SET) { uint32_t x, *map = (uint32_t *)&(cmd->mask); int i, j; @@ -1376,10 +1390,9 @@ print_dscp(struct buf_pr *bp, ipfw_insn_u32 *cmd) } } -#define insntod(cmd, type) ((ipfw_insn_ ## type *)(cmd)) struct show_state { struct ip_fw_rule *rule; - const ipfw_insn *eaction; + const ipfw_insn_kidx *eaction; uint8_t *printed; int flags; #define HAVE_PROTO 0x0001 @@ -1581,10 +1594,11 @@ print_instruction(struct buf_pr *bp, const struct format_opts *fo, } break; case O_IP_FLOW_LOOKUP: - s = table_search_ctlv(fo->tstate, cmd->arg1); + s = table_search_ctlv(fo->tstate, + insntod(cmd, kidx)->kidx); bprintf(bp, " flow table(%s", s); - if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) - bprintf(bp, ",%u", insntod(cmd, u32)->d[0]); + if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_table)) + bprintf(bp, ",%u", insntod(cmd, table)->value); bprintf(bp, ")"); break; case O_IPID: @@ -1696,7 +1710,8 @@ print_instruction(struct buf_pr *bp, const struct format_opts *fo, if (co.named_states == 0) break; bprintf(bp, " :%s", - object_search_ctlv(fo->tstate, cmd->arg1, + object_search_ctlv(fo->tstate, + insntod(cmd, kidx)->kidx, IPFW_TLV_STATE_NAME)); break; case O_LIMIT: @@ -1708,7 +1723,8 @@ print_instruction(struct buf_pr *bp, const struct format_opts *fo, if (co.named_states == 0) break; bprintf(bp, " :%s", - object_search_ctlv(fo->tstate, cmd->arg1, + object_search_ctlv(fo->tstate, + insntod(cmd, limit)->kidx, IPFW_TLV_STATE_NAME)); break; case O_IP6: @@ -1819,8 +1835,9 @@ print_action_instruction(struct buf_pr *bp, const struct format_opts *fo, bprintf(bp, "check-state"); if (co.named_states == 0) break; - if (cmd->arg1 != 0) - s = object_search_ctlv(fo->tstate, cmd->arg1, + if (insntod(cmd, kidx)->kidx != 0) + s = object_search_ctlv(fo->tstate, + insntod(cmd, kidx)->kidx, IPFW_TLV_STATE_NAME); else s = NULL; @@ -1854,7 +1871,7 @@ print_action_instruction(struct buf_pr *bp, const struct format_opts *fo, print_unreach6_code(bp, cmd->arg1); break; case O_SKIPTO: - bprint_uint_arg(bp, "skipto ", cmd->arg1); + bprint_uint_arg(bp, "skipto ", insntod(cmd, u32)->d[0]); break; case O_PIPE: bprint_uint_arg(bp, "pipe ", cmd->arg1); @@ -1916,8 +1933,9 @@ print_action_instruction(struct buf_pr *bp, const struct format_opts *fo, * NOTE: in case when external action has no named * instances support, the second opcode isn't needed. */ - state->eaction = cmd; - s = object_search_ctlv(fo->tstate, cmd->arg1, + state->eaction = insntod(cmd, kidx); + s = object_search_ctlv(fo->tstate, + state->eaction->kidx, IPFW_TLV_EACTION); if (match_token(rule_eactions, s) != -1) bprintf(bp, "%s", s); @@ -1937,11 +1955,12 @@ print_action_instruction(struct buf_pr *bp, const struct format_opts *fo, * we calculate TLV type using IPFW_TLV_EACTION_NAME() * macro. */ - s = object_search_ctlv(fo->tstate, cmd->arg1, 0); + s = object_search_ctlv(fo->tstate, + insntod(cmd, kidx)->kidx, 0); if (s == NULL) s = object_search_ctlv(fo->tstate, - cmd->arg1, IPFW_TLV_EACTION_NAME( - state->eaction->arg1)); + insntod(cmd, kidx)->kidx, IPFW_TLV_EACTION_NAME( + state->eaction->kidx)); bprintf(bp, " %s", s); break; case O_EXTERNAL_DATA: @@ -1976,7 +1995,7 @@ print_action_instruction(struct buf_pr *bp, const struct format_opts *fo, if (cmd->len & F_NOT) bprintf(bp, "return"); else - bprint_uint_arg(bp, "call ", cmd->arg1); + bprint_uint_arg(bp, "call ", insntod(cmd, u32)->d[0]); break; default: bprintf(bp, "** unrecognized action %d len %d ", @@ -2167,7 +2186,7 @@ show_static_rule(struct cmdline_opts *co, struct format_opts *fo, warn("init_show_state() failed"); return; } - bprintf(bp, "%05u ", rule->rulenum); + bprintf(bp, "%06u ", rule->rulenum); /* Print counters if enabled */ if (fo->pcwidth > 0 || fo->bcwidth > 0) { @@ -2267,22 +2286,20 @@ show_dyn_state(struct cmdline_opts *co, struct format_opts *fo, { struct protoent *pe; struct in_addr a; - uint16_t rulenum; char buf[INET6_ADDRSTRLEN]; - if (!d->expire && !(d->dyn_type == O_LIMIT_PARENT)) + if (!d->expire && !(d->type == O_LIMIT_PARENT)) return; - bcopy(&d->rule, &rulenum, sizeof(rulenum)); - bprintf(bp, "%05d", rulenum); + bprintf(bp, "%06d", d->rulenum); if (fo->pcwidth > 0 || fo->bcwidth > 0) { bprintf(bp, " "); pr_u64(bp, &d->pcnt, fo->pcwidth); pr_u64(bp, &d->bcnt, fo->bcwidth); bprintf(bp, "(%ds)", d->expire); } - switch (d->dyn_type) { + switch (d->type) { case O_LIMIT_PARENT: - bprintf(bp, " PARENT %d", d->count); + bprintf(bp, " PARENT %u", d->count); break; case O_LIMIT: bprintf(bp, " LIMIT"); @@ -2373,9 +2390,8 @@ ipfw_sets_handler(char *av[]) ipfw_range_tlv rt; char *msg; size_t size; - uint32_t masks[2]; + uint32_t masks[2], rulenum; int i; - uint16_t rulenum; uint8_t cmd; av++; @@ -2426,7 +2442,7 @@ ipfw_sets_handler(char *av[]) if (av[0] == NULL || av[1] == NULL || av[2] == NULL || av[3] != NULL || _substrcmp(av[1], "to") != 0) errx(EX_USAGE, "syntax: set move [rule] X to Y\n"); - rulenum = atoi(av[0]); + rulenum = (uint32_t)strtoul(av[0], NULL, 10); rt.new_set = atoi(av[2]); if (cmd == IP_FW_XMOVE) { rt.start_rule = rulenum; @@ -2521,7 +2537,6 @@ prepare_format_dyn(struct cmdline_opts *co, struct format_opts *fo, { ipfw_dyn_rule *d; int width; - uint8_t set; d = (ipfw_dyn_rule *)_state; /* Count _ALL_ states */ @@ -2530,13 +2545,9 @@ prepare_format_dyn(struct cmdline_opts *co, struct format_opts *fo, if (fo->show_counters == 0) return; - if (co->use_set) { - /* skip states from another set */ - bcopy((char *)&d->rule + sizeof(uint16_t), &set, - sizeof(uint8_t)); - if (set != co->use_set - 1) - return; - } + /* skip states from another set */ + if (co->use_set != 0 && d->set != co->use_set - 1) + return; width = pr_u64(NULL, &d->pcnt, 0); if (width > fo->pcwidth) @@ -2666,24 +2677,17 @@ static void list_dyn_state(struct cmdline_opts *co, struct format_opts *fo, void *_arg, void *_state) { - uint16_t rulenum; - uint8_t set; ipfw_dyn_rule *d; struct buf_pr *bp; d = (ipfw_dyn_rule *)_state; bp = (struct buf_pr *)_arg; - bcopy(&d->rule, &rulenum, sizeof(rulenum)); - if (rulenum > fo->last) + if (d->rulenum > fo->last) return; - if (co->use_set) { - bcopy((char *)&d->rule + sizeof(uint16_t), - &set, sizeof(uint8_t)); - if (set != co->use_set - 1) - return; - } - if (rulenum >= fo->first) { + if (co->use_set != 0 && d->set != co->use_set - 1) + return; + if (d->rulenum >= fo->first) { show_dyn_state(co, fo, bp, d); printf("%s\n", bp->buf); bp_flush(bp); @@ -3009,11 +3013,11 @@ eaction_check_name(const char *name) return (0); } -static uint16_t +static uint32_t pack_object(struct tidx *tstate, char *name, int otype) { - int i; ipfw_obj_ntlv *ntlv; + int i; for (i = 0; i < tstate->count; i++) { if (strcmp(tstate->idx[i].name, name) != 0) @@ -3046,7 +3050,7 @@ pack_object(struct tidx *tstate, char *name, int otype) return (ntlv->idx); } -static uint16_t +static uint32_t pack_table(struct tidx *tstate, char *name) { @@ -3057,11 +3061,9 @@ pack_table(struct tidx *tstate, char *name) } void -fill_table(struct _ipfw_insn *cmd, char *av, uint8_t opcode, - struct tidx *tstate) +fill_table(ipfw_insn *cmd, char *av, uint8_t opcode, struct tidx *tstate) { - uint32_t *d = ((ipfw_insn_u32 *)cmd)->d; - uint16_t uidx; + ipfw_insn_kidx *c = insntod(cmd, kidx); char *p; if ((p = strchr(av + 6, ')')) == NULL) @@ -3071,16 +3073,17 @@ fill_table(struct _ipfw_insn *cmd, char *av, uint8_t opcode, if (p) *p++ = '\0'; - if ((uidx = pack_table(tstate, av + 6)) == 0) + if ((c->kidx = pack_table(tstate, av + 6)) == 0) errx(EX_DATAERR, "Invalid table name: %s", av + 6); cmd->opcode = opcode; - cmd->arg1 = uidx; if (p) { - cmd->len |= F_INSN_SIZE(ipfw_insn_u32); - d[0] = strtoul(p, NULL, 0); - } else - cmd->len |= F_INSN_SIZE(ipfw_insn); + cmd->len |= F_INSN_SIZE(ipfw_insn_table); + insntod(cmd, table)->value = strtoul(p, NULL, 0); + } else { + cmd->arg1 = LOOKUP_NONE; + cmd->len |= F_INSN_SIZE(ipfw_insn_kidx); + } } @@ -3338,13 +3341,7 @@ ipfw_delete(char *av[]) j = strtol(sep + 1, NULL, 10); av++; if (co.do_nat) { - exitval = do_cmd(IP_FW_NAT_DEL, &i, sizeof i); - if (exitval) { - exitval = EX_UNAVAILABLE; - if (co.do_quiet) - continue; - warn("nat %u not available", i); - } + exitval = ipfw_delete_nat(i); } else if (co.do_pipe) { exitval = ipfw_delete_pipe(co.do_pipe, i); } else { @@ -3403,7 +3400,7 @@ static void fill_iface(ipfw_insn_if *cmd, char *arg, int cblen, struct tidx *tstate) { char *p; - uint16_t uidx; + uint32_t uidx; cmd->name[0] = '\0'; cmd->o.len |= F_INSN_SIZE(ipfw_insn_if); @@ -3869,20 +3866,22 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate) case TOK_CHECKSTATE: have_state = action; action->opcode = O_CHECK_STATE; + action->len = F_INSN_SIZE(ipfw_insn_kidx); + CHECK_ACTLEN; if (co.named_states == 0) break; if (*av == NULL || match_token(rule_options, *av) == TOK_COMMENT) { - action->arg1 = pack_object(tstate, + insntod(have_state, kidx)->kidx = pack_object(tstate, default_state_name, IPFW_TLV_STATE_NAME); break; } if (*av[0] == ':') { if (strcmp(*av + 1, "any") == 0) - action->arg1 = 0; + insntod(have_state, kidx)->kidx = 0; else if (state_check_name(*av + 1) == 0) - action->arg1 = pack_object(tstate, *av + 1, - IPFW_TLV_STATE_NAME); + insntod(have_state, kidx)->kidx = pack_object( + tstate, *av + 1, IPFW_TLV_STATE_NAME); else errx(EX_DATAERR, "Invalid state name %s", *av); @@ -3962,6 +3961,7 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate) goto chkarg; case TOK_SKIPTO: action->opcode = O_SKIPTO; + action->len = F_INSN_SIZE(ipfw_insn_u32); goto chkarg; case TOK_NETGRAPH: action->opcode = O_NETGRAPH; @@ -3977,16 +3977,33 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate) goto chkarg; case TOK_CALL: action->opcode = O_CALLRETURN; + action->len = F_INSN_SIZE(ipfw_insn_u32); chkarg: if (!av[0]) errx(EX_USAGE, "missing argument for %s", *(av - 1)); if (isdigit(**av)) { - action->arg1 = strtoul(*av, NULL, 10); - if (action->arg1 <= 0 || action->arg1 >= IP_FW_TABLEARG) - errx(EX_DATAERR, "illegal argument for %s", - *(av - 1)); + uint32_t arg; + + arg = (uint32_t)strtoul(*av, NULL, 10); + if (arg < IPFW_ARG_MIN || arg > IPFW_ARG_MAX){ + if (arg >= IPFW_ARG_MIN && + arg <= IPFW_DEFAULT_RULE && ( + i == TOK_SKIPTO || i == TOK_CALL)) + /* FALLTHROUGH */; + else + errx(EX_DATAERR, + "illegal argument for %s", + *(av - 1)); + } + if (i == TOK_SKIPTO || i == TOK_CALL) { + insntod(action, u32)->d[0] = arg; + } else + action->arg1 = (uint16_t)arg; } else if (_substrcmp(*av, "tablearg") == 0) { - action->arg1 = IP_FW_TARG; + if (i == TOK_SKIPTO || i == TOK_CALL) + insntod(action, u32)->d[0] = IP_FW_TARG; + else + action->arg1 = IP_FW_TARG; } else if (i == TOK_DIVERT || i == TOK_TEE) { struct servent *s; setservent(1); @@ -4155,17 +4172,23 @@ chkarg: break; case TOK_RETURN: - fill_cmd(action, O_CALLRETURN, F_NOT, 0); + action->opcode = O_CALLRETURN; + action->len = F_INSN_SIZE(ipfw_insn_u32) | F_NOT; + CHECK_ACTLEN; break; case TOK_TCPSETMSS: { u_long mss; - uint16_t idx; + uint32_t idx; idx = pack_object(tstate, "tcp-setmss", IPFW_TLV_EACTION); if (idx == 0) errx(EX_DATAERR, "pack_object failed"); - fill_cmd(action, O_EXTERNAL_ACTION, 0, idx); + action->opcode = O_EXTERNAL_ACTION; + action->len = F_INSN_SIZE(ipfw_insn_kidx); + CHECK_ACTLEN; + insntod(action, kidx)->kidx = idx; + NEED1("Missing MSS value"); action = next_cmd(action, &ablen); action->len = 1; @@ -4180,12 +4203,15 @@ chkarg: case TOK_SRCPRJID: case TOK_DSTPRJID: { - uint16_t idx; + uint32_t idx; idx = pack_object(tstate, *(av - 1), IPFW_TLV_EACTION); if (idx == 0) errx(EX_DATAERR, "pack_object failed"); - fill_cmd(action, O_EXTERNAL_ACTION, 0, idx); + action->opcode = O_EXTERNAL_ACTION; + action->len = F_INSN_SIZE(ipfw_insn_kidx); + CHECK_ACTLEN; + insntod(action, kidx)->kidx = idx; break; } @@ -4202,7 +4228,7 @@ chkarg: * syntax. */ case TOK_EACTION: { - uint16_t idx; + uint32_t idx; NEED1("Missing eaction name"); if (eaction_check_name(*av) != 0) @@ -4210,12 +4236,13 @@ chkarg: idx = pack_object(tstate, *av, IPFW_TLV_EACTION); if (idx == 0) errx(EX_DATAERR, "pack_object failed"); - fill_cmd(action, O_EXTERNAL_ACTION, 0, idx); + action->opcode = O_EXTERNAL_ACTION; + action->len = F_INSN_SIZE(ipfw_insn_kidx); + CHECK_ACTLEN; + insntod(action, kidx)->kidx = idx; + av++; NEED1("Missing eaction instance name"); - action = next_cmd(action, &ablen); - action->len = 1; - CHECK_ACTLEN; if (eaction_check_name(*av) != 0) errx(EX_DATAERR, "Invalid eaction instance name %s", *av); @@ -4227,7 +4254,11 @@ chkarg: idx = pack_object(tstate, *av, 0); if (idx == 0) errx(EX_DATAERR, "pack_object failed"); - fill_cmd(action, O_EXTERNAL_INSTANCE, 0, idx); + action = next_cmd(action, &ablen); + action->opcode = O_EXTERNAL_INSTANCE; + action->len = F_INSN_SIZE(ipfw_insn_kidx); + CHECK_ACTLEN; + insntod(action, kidx)->kidx = idx; av++; } } @@ -4319,7 +4350,7 @@ chkarg: cmd = next_cmd(cmd, &cblen); } - if (have_state) { /* must be a check-state, we are done */ + if (have_state != NULL) { /* must be a check-state, we are done */ if (*av != NULL && match_token(rule_options, *av) == TOK_COMMENT) { /* check-state has a comment */ @@ -4573,7 +4604,7 @@ read_options: case TOK_VIA: NEED1("recv, xmit, via require interface name" " or address"); - fill_iface((ipfw_insn_if *)cmd, av[0], cblen, tstate); + fill_iface(insntod(cmd, if), av[0], cblen, tstate); av++; if (F_LEN(cmd) == 0) /* not a valid address */ break; @@ -4783,14 +4814,15 @@ read_options: case TOK_KEEPSTATE: case TOK_RECORDSTATE: { - uint16_t uidx; + uint32_t uidx; if (open_par) - errx(EX_USAGE, "keep-state or record-state cannot be part " - "of an or block"); - if (have_state) - errx(EX_USAGE, "only one of keep-state, record-state, " - " limit and set-limit is allowed"); + errx(EX_USAGE, "keep-state or record-state " + "cannot be part of an or block"); + if (have_state != NULL) + errx(EX_USAGE, "only one of keep-state, " + "record-state, limit and set-limit is " + "allowed"); if (co.named_states == 0) uidx = 0; else if (*av != NULL && *av[0] == ':') { @@ -4805,28 +4837,32 @@ read_options: IPFW_TLV_STATE_NAME); have_state = cmd; have_rstate = i == TOK_RECORDSTATE; - fill_cmd(cmd, O_KEEP_STATE, 0, uidx); + cmd->opcode = O_KEEP_STATE; + cmd->len = F_INSN_SIZE(ipfw_insn_kidx); + CHECK_CMDLEN; + insntod(have_state, kidx)->kidx = uidx; break; } case TOK_LIMIT: case TOK_SETLIMIT: { - ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; + ipfw_insn_limit *c = insntod(cmd, limit); int val; if (open_par) - errx(EX_USAGE, - "limit or set-limit cannot be part of an or block"); + errx(EX_USAGE, "limit or set-limit cannot " + "be part of an or block"); if (have_state) - errx(EX_USAGE, "only one of keep-state, record-state, " - " limit and set-limit is allowed"); + errx(EX_USAGE, "only one of keep-state, " + "record-state, limit and set-limit is " + "allowed"); have_state = cmd; have_rstate = i == TOK_SETLIMIT; + cmd->opcode = O_LIMIT; cmd->len = F_INSN_SIZE(ipfw_insn_limit); CHECK_CMDLEN; - cmd->opcode = O_LIMIT; - c->limit_mask = c->conn_limit = 0; + c->limit_mask = c->conn_limit = c->kidx = 0; while ( av[0] != NULL ) { if ((val = match_token(limit_masks, *av)) <= 0) @@ -4849,11 +4885,11 @@ read_options: if (state_check_name(*av + 1) != 0) errx(EX_DATAERR, "Invalid state name %s", *av); - cmd->arg1 = pack_object(tstate, *av + 1, + c->kidx = pack_object(tstate, *av + 1, IPFW_TLV_STATE_NAME); av++; } else - cmd->arg1 = pack_object(tstate, + c->kidx = pack_object(tstate, default_state_name, IPFW_TLV_STATE_NAME); break; } @@ -4994,27 +5030,25 @@ read_options: break; case TOK_LOOKUP: { - ipfw_insn_u32 *c = (ipfw_insn_u32 *)cmd; - int j; + ipfw_insn_kidx *c = insntod(cmd, kidx); if (!av[0] || !av[1]) - errx(EX_USAGE, "format: lookup argument tablenum"); + errx(EX_USAGE, + "format: lookup argument tablenum"); cmd->opcode = O_IP_DST_LOOKUP; - cmd->len |= F_INSN_SIZE(ipfw_insn) + 2; - i = match_token(rule_options, *av); - for (j = 0; lookup_key[j] >= 0 ; j++) { - if (i == lookup_key[j]) - break; - } - if (lookup_key[j] <= 0) - errx(EX_USAGE, "format: cannot lookup on %s", *av); - __PAST_END(c->d, 1) = j; // i converted to option - av++; - - if ((j = pack_table(tstate, *av)) == 0) - errx(EX_DATAERR, "Invalid table name: %s", *av); + cmd->len |= F_INSN_SIZE(ipfw_insn_kidx); + CHECK_CMDLEN; - cmd->arg1 = j; + i = match_token(lookup_keys, *av); + if (i == -1) + errx(EX_USAGE, + "format: cannot lookup on %s", *av); + cmd->arg1 = i; + av++; + c->kidx = pack_table(tstate, *av); + if (c->kidx == 0) + errx(EX_DATAERR, + "Invalid table name: %s", *av); av++; } break; @@ -5046,7 +5080,7 @@ read_options: done: - if (!have_state && have_skipcmd) + if (have_state == NULL && have_skipcmd) warnx("Rule contains \"defer-immediate-action\" " "and doesn't contain any state-related options."); @@ -5060,7 +5094,8 @@ done: dst = (ipfw_insn *)rule->cmd; /* - * First thing to write into the command stream is the match probability. + * First thing to write into the command stream is the match + * probability. */ if (match_prob != 1) { /* 1 means always match */ dst->opcode = O_PROB; @@ -5072,8 +5107,11 @@ done: /* * generate O_PROBE_STATE if necessary */ - if (have_state && have_state->opcode != O_CHECK_STATE && !have_rstate) { - fill_cmd(dst, O_PROBE_STATE, 0, have_state->arg1); + if (have_state != NULL && + have_state->opcode != O_CHECK_STATE && !have_rstate) { + dst->opcode = O_PROBE_STATE; + dst->len = F_INSN_SIZE(ipfw_insn_kidx); + insntod(dst, kidx)->kidx = insntod(have_state, kidx)->kidx; dst = next_cmd(dst, &rblen); } @@ -5102,7 +5140,8 @@ done: /* * put back the have_state command as last opcode */ - if (have_state && have_state->opcode != O_CHECK_STATE) { + if (have_state != NULL && + have_state->opcode != O_CHECK_STATE) { i = F_LEN(have_state); CHECK_RBUFLEN(i); bcopy(have_state, dst, i * sizeof(uint32_t)); @@ -5195,7 +5234,7 @@ object_sort_ctlv(ipfw_obj_ctlv *ctlv) } struct object_kt { - uint16_t uidx; + uint32_t uidx; uint16_t type; }; static int diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h index 5830e922286..43d9b1d50af 100644 --- a/sbin/ipfw/ipfw2.h +++ b/sbin/ipfw/ipfw2.h @@ -406,6 +406,7 @@ void ipfw_nat64clat_handler(int ac, char *av[]); void ipfw_nptv6_handler(int ac, char *av[]); int ipfw_check_object_name(const char *name); int ipfw_check_nat64prefix(const struct in6_addr *prefix, int length); +int ipfw_delete_nat(int i); #ifdef PF /* altq.c */ @@ -451,5 +452,5 @@ int table_check_name(const char *tablename); void ipfw_list_ta(int ac, char *av[]); void ipfw_list_values(int ac, char *av[]); void table_fill_ntlv(struct _ipfw_obj_ntlv *ntlv, const char *name, - uint8_t set, uint16_t uidx); + uint8_t set, uint32_t uidx); diff --git a/sbin/ipfw/nat.c b/sbin/ipfw/nat.c index aced8ea10ec..a60405b5df8 100644 --- a/sbin/ipfw/nat.c +++ b/sbin/ipfw/nat.c @@ -931,6 +931,32 @@ ipfw_config_nat(int ac, char **av) } } +static void +nat_fill_ntlv(ipfw_obj_ntlv *ntlv, int i) +{ + + ntlv->head.type = IPFW_TLV_EACTION_NAME(1); /* it doesn't matter */ + ntlv->head.length = sizeof(ipfw_obj_ntlv); + ntlv->idx = 1; + ntlv->set = 0; /* not yet */ + snprintf(ntlv->name, sizeof(ntlv->name), "%d", i); +} + +int +ipfw_delete_nat(int i) +{ + ipfw_obj_header oh; + + memset(&oh, 0, sizeof(oh)); + nat_fill_ntlv(&oh.ntlv, i); + if (do_set3(IP_FW_NAT44_DESTROY, &oh.opheader, sizeof(oh)) == -1) { + if (!co.do_quiet) + warn("nat %u not available", i); + return (EX_UNAVAILABLE); + } + return (EX_OK); +} + struct nat_list_arg { uint16_t cmd; int is_all; diff --git a/sbin/ipfw/tables.c b/sbin/ipfw/tables.c index 0c3f3806096..f46c4d6d5c4 100644 --- a/sbin/ipfw/tables.c +++ b/sbin/ipfw/tables.c @@ -302,7 +302,7 @@ ipfw_table_handler(int ac, char *av[]) void table_fill_ntlv(ipfw_obj_ntlv *ntlv, const char *name, uint8_t set, - uint16_t uidx) + uint32_t uidx) { ntlv->head.type = IPFW_TLV_TBL_NAME; diff --git a/sys/modules/ipfw/Makefile b/sys/modules/ipfw/Makefile index 36d5cbbc005..c0cded30a7e 100644 --- a/sys/modules/ipfw/Makefile +++ b/sys/modules/ipfw/Makefile @@ -8,7 +8,7 @@ SRCS+= ip_fw_log.c ip_fw_eaction.c SRCS+= ip_fw_sockopt.c ip_fw_table.c ip_fw_table_algo.c ip_fw_iface.c SRCS+= ip_fw_table_value.c ip_fw_yandex.c SRCS+= opt_inet.h opt_inet6.h opt_ipdivert.h opt_ipfw.h opt_ipsec.h -SRCS+= ip_fw_dynamic.c +SRCS+= ip_fw_dynamic.c ip_fw_compat.c CFLAGS+= -DIPFIREWALL -I${SRCTOP}/sys/contrib/ck/include # diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index a2fabc82893..95a56e053a6 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -36,7 +36,8 @@ * allowed for a rule. The ip_fw code relies on both meanings of this * constant. */ -#define IPFW_DEFAULT_RULE 65535 +#define IPFW_DEFAULT_RULE_COMPAT 65535 +#define IPFW_DEFAULT_RULE 131071 #define RESVD_SET 31 /*set for default and persistent rules*/ #define IPFW_MAX_SETS 32 /* Number of sets supported by ipfw*/ @@ -74,6 +75,7 @@ typedef struct _ip_fw3_opheader { uint16_t opcode; /* Operation opcode */ uint16_t version; /* Opcode version */ +#define IP_FW3_OPVER 1 uint16_t reserved[2]; /* Align to 64-bit boundary */ } ip_fw3_opheader; @@ -213,8 +215,8 @@ enum ipfw_opcodes { /* arguments (4 byte each) */ O_VERREVPATH, /* none */ O_VERSRCREACH, /* none */ - O_PROBE_STATE, /* none */ - O_KEEP_STATE, /* none */ + O_PROBE_STATE, /* v0:arg1=kidx, v1:kidx=kidx */ + O_KEEP_STATE, /* v0:arg1=kidx, v1:kidx=kidx */ O_LIMIT, /* ipfw_insn_limit */ O_LIMIT_PARENT, /* dyn_type, not an opcode. */ @@ -225,12 +227,13 @@ enum ipfw_opcodes { /* arguments (4 byte each) */ O_LOG, /* ipfw_insn_log */ O_PROB, /* u32 = match probability */ - O_CHECK_STATE, /* none */ + O_CHECK_STATE, /* v0:arg1=kidx, v1:kidx=kidx */ O_ACCEPT, /* none */ O_DENY, /* none */ O_REJECT, /* arg1=icmp arg (same as deny) */ O_COUNT, /* none */ - O_SKIPTO, /* arg1=next rule number */ + O_SKIPTO, /* v0:arg1=next rule number */ + /* v1:kidx= next rule number */ O_PIPE, /* arg1=pipe number */ O_QUEUE, /* arg1=queue number */ O_DIVERT, /* arg1=port number */ @@ -244,8 +247,10 @@ enum ipfw_opcodes { /* arguments (4 byte each) */ * More opcodes. */ O_IPSEC, /* has ipsec history */ - O_IP_SRC_LOOKUP, /* arg1=table number, u32=value */ + O_IP_SRC_LOOKUP, /* v0:arg1=table number, u32=value */ + /* v1:kidx=name, u32=value, arg1=key */ O_IP_DST_LOOKUP, /* arg1=table number, u32=value */ + /* v1:kidx=name, u32=value, arg1=key */ O_ANTISPOOF, /* none */ O_JAIL, /* u32 = id */ O_ALTQ, /* u32 = altq classif. qid */ @@ -280,16 +285,20 @@ enum ipfw_opcodes { /* arguments (4 byte each) */ O_SOCKARG, /* socket argument */ - O_CALLRETURN, /* arg1=called rule number */ + O_CALLRETURN, /* v0:arg1=called rule number */ + /* v1:kidx=called rule number */ O_FORWARD_IP6, /* fwd sockaddr_in6 */ O_DSCP, /* 2 u32 = DSCP mask */ O_SETDSCP, /* arg1=DSCP value */ - O_IP_FLOW_LOOKUP, /* arg1=table number, u32=value */ + O_IP_FLOW_LOOKUP, /* v0:arg1=table number, u32=value */ + /* v1:kidx=name, u32=value */ - O_EXTERNAL_ACTION, /* arg1=id of external action handler */ - O_EXTERNAL_INSTANCE, /* arg1=id of eaction handler instance */ + O_EXTERNAL_ACTION, /* v0:arg1=id of external action handler */ + /* v1:kidx=id of external action handler */ + O_EXTERNAL_INSTANCE, /* v0:arg1=id of eaction handler instance */ + /* v1:kidx=id of eaction handler instance */ O_EXTERNAL_DATA, /* variable length data */ O_SKIP_ACTION, /* none */ @@ -369,9 +378,14 @@ typedef struct _ipfw_insn_u16 { */ typedef struct _ipfw_insn_u32 { ipfw_insn o; - u_int32_t d[1]; /* one or more */ + u_int32_t d[1]; /* one or more */ } ipfw_insn_u32; +typedef struct _ipfw_insn_kidx { + ipfw_insn o; + uint32_t kidx; +} ipfw_insn_kidx; + /* * This is used to store IP addr-mask pairs. */ @@ -381,6 +395,23 @@ typedef struct _ipfw_insn_ip { struct in_addr mask; } ipfw_insn_ip; +typedef struct _ipfw_insn_table { + ipfw_insn o; /* arg1 is optional lookup key */ + uint32_t kidx; /* table name index */ + uint32_t value; /* table value */ +} ipfw_insn_table; + +enum ipfw_table_lookup_type { + LOOKUP_NONE = 0, + LOOKUP_DST_IP, + LOOKUP_SRC_IP, + LOOKUP_DST_PORT, + LOOKUP_SRC_PORT, + LOOKUP_UID, + LOOKUP_JAIL, + LOOKUP_DSCP +}; + /* * This is used to forward to a given address (ip). */ @@ -414,7 +445,8 @@ typedef struct _ipfw_insn_if { union { struct in_addr ip; int glob; - uint16_t kidx; + uint16_t kidx_v0; + uint32_t kidx; } p; char name[IFNAMSIZ]; } ipfw_insn_if; @@ -432,6 +464,7 @@ typedef struct _ipfw_insn_altq { */ typedef struct _ipfw_insn_limit { ipfw_insn o; + u_int32_t kidx; u_int8_t _pad; u_int8_t limit_mask; /* combination of DYN_* below */ #define DYN_SRC_ADDR 0x1 @@ -559,11 +592,12 @@ typedef struct _ipfw_insn_nat { } ipfw_insn_nat; /* Apply ipv6 mask on ipv6 addr */ -#define APPLY_MASK(addr,mask) \ +#define APPLY_MASK(addr,mask) do { \ (addr)->__u6_addr.__u6_addr32[0] &= (mask)->__u6_addr.__u6_addr32[0]; \ (addr)->__u6_addr.__u6_addr32[1] &= (mask)->__u6_addr.__u6_addr32[1]; \ (addr)->__u6_addr.__u6_addr32[2] &= (mask)->__u6_addr.__u6_addr32[2]; \ - (addr)->__u6_addr.__u6_addr32[3] &= (mask)->__u6_addr.__u6_addr32[3]; + (addr)->__u6_addr.__u6_addr32[3] &= (mask)->__u6_addr.__u6_addr32[3]; \ +} while (0) /* Structure for ipv6 */ typedef struct _ipfw_insn_ip6 { @@ -582,6 +616,9 @@ typedef struct _ipfw_insn_icmp6 { */ } ipfw_insn_icmp6; +/* Convert pointer to instruction with specified type */ +#define insntod(p, type) ((ipfw_insn_ ## type *)(p)) + /* * Here we have the structure representing an ipfw rule. * @@ -699,30 +736,29 @@ struct ipfw_flow_id { /* * Dynamic ipfw rule. */ -typedef struct _ipfw_dyn_rule ipfw_dyn_rule; - -struct _ipfw_dyn_rule { - ipfw_dyn_rule *next; /* linked list of rules. */ - struct ip_fw *rule; /* pointer to rule */ - /* 'rule' is used to pass up the rule number (from the parent) */ +#define IPFW_DYN_ORPHANED 0x40000 /* state's parent rule was deleted */ - ipfw_dyn_rule *parent; /* pointer to parent rule */ - u_int64_t pcnt; /* packet match counter */ - u_int64_t bcnt; /* byte match counter */ +typedef struct _ipfw_dyn_rule { struct ipfw_flow_id id; /* (masked) flow id */ - u_int32_t expire; /* expire time */ - u_int32_t bucket; /* which bucket in hash table */ - u_int32_t state; /* state of this rule (typically a + uint8_t set; + uint8_t type; /* rule type */ + uint16_t pad; + uint32_t expire; /* expire time */ + uint32_t rulenum; /* parent's rule number */ + uint32_t kidx; /* index of named object */ + uint64_t pcnt; /* packet match counter */ + uint64_t bcnt; /* byte match counter */ + uint32_t hashval; /* hash value */ + union { + uint32_t state; /* state of this rule (typically a * combination of TCP flags) */ -#define IPFW_DYN_ORPHANED 0x40000 /* state's parent rule was deleted */ - u_int32_t ack_fwd; /* most recent ACKs in forward */ - u_int32_t ack_rev; /* and reverse directions (used */ + uint32_t count; /* number of linked states */ + }; + uint32_t ack_fwd; /* most recent ACKs in forward */ + uint32_t ack_rev; /* and reverse directions (used */ /* to generate keepalives) */ - u_int16_t dyn_type; /* rule type */ - u_int16_t count; /* refcount */ - u_int16_t kidx; /* index of named object */ -} __packed __aligned(8); +} __packed __aligned(8) ipfw_dyn_rule; /* * Definitions for IP option names. @@ -840,10 +876,10 @@ typedef struct _ipfw_obj_data { /* Object name TLV */ typedef struct _ipfw_obj_ntlv { ipfw_obj_tlv head; /* TLV header */ - uint16_t idx; /* Name index */ + uint32_t idx; /* Name index */ uint8_t set; /* set, if applicable */ uint8_t type; /* object type, if applicable */ - uint32_t spare; /* unused */ + uint16_t spare; /* unused */ char name[64]; /* Null-terminated name */ } ipfw_obj_ntlv; @@ -891,8 +927,7 @@ typedef struct _ipfw_obj_tentry { uint8_t masklen; /* mask length */ uint8_t result; /* request result */ uint8_t spare0; - uint16_t idx; /* Table name index */ - uint16_t spare1; + uint32_t idx; /* Table name index */ union { /* Longest field needs to be aligned by 8-byte boundary */ struct in_addr addr; /* IPv4 address */ @@ -938,8 +973,8 @@ typedef struct _ipfw_obj_ctlv { typedef struct _ipfw_range_tlv { ipfw_obj_tlv head; /* TLV header */ uint32_t flags; /* Range flags */ - uint16_t start_rule; /* Range start */ - uint16_t end_rule; /* Range end */ + uint32_t start_rule; /* Range start */ + uint32_t end_rule; /* Range end */ uint32_t set; /* Range set to match */ uint32_t new_set; /* New set to move/swap to */ } ipfw_range_tlv; diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c index c219260b4da..92e2dc68324 100644 --- a/sys/netpfil/ipfw/ip_fw2.c +++ b/sys/netpfil/ipfw/ip_fw2.c @@ -131,12 +131,12 @@ VNET_DEFINE(unsigned int, fw_tables_sets) = 0; /* Don't use set-aware tables */ static unsigned int default_fw_tables = IPFW_TABLES_DEFAULT; #ifndef LINEAR_SKIPTO -static int jump_fast(struct ip_fw_chain *chain, struct ip_fw *f, int num, - int tablearg, int jump_backwards); +static int jump_fast(struct ip_fw_chain *chain, struct ip_fw *f, + uint32_t num, int tablearg, int jump_backwards); #define JUMP(ch, f, num, targ, back) jump_fast(ch, f, num, targ, back) #else -static int jump_linear(struct ip_fw_chain *chain, struct ip_fw *f, int num, - int tablearg, int jump_backwards); +static int jump_linear(struct ip_fw_chain *chain, struct ip_fw *f, + uint32_t num, int tablearg, int jump_backwards); #define JUMP(ch, f, num, targ, back) jump_linear(ch, f, num, targ, back) #endif @@ -1221,7 +1221,7 @@ set_match(struct ip_fw_args *args, int slot, * cached_id and cached_pos fields in ipfw rule. */ static int -jump_fast(struct ip_fw_chain *chain, struct ip_fw *f, int num, +jump_fast(struct ip_fw_chain *chain, struct ip_fw *f, uint32_t num, int tablearg, int jump_backwards) { int f_pos; @@ -1255,7 +1255,7 @@ jump_fast(struct ip_fw_chain *chain, struct ip_fw *f, int num, * Helper function to enable real fast rule lookups. */ static int -jump_linear(struct ip_fw_chain *chain, struct ip_fw *f, int num, +jump_linear(struct ip_fw_chain *chain, struct ip_fw *f, uint32_t num, int tablearg, int jump_backwards) { int f_pos; @@ -1947,92 +1947,89 @@ do { \ break; case O_IP_DST_LOOKUP: - { - void *pkey; - uint32_t vidx, key; - uint16_t keylen; + if (cmd->arg1 != LOOKUP_NONE) { + void *pkey; + uint32_t key, vidx; + uint16_t keylen; + + if (cmd->arg1 != LOOKUP_UID && + cmd->arg1 != LOOKUP_JAIL && + is_ipv6 == 0 && is_ipv4 == 0) + break; /* only for L3 */ + + /* Determine key length */ + if (cmd->arg1 == LOOKUP_DST_IP || + cmd->arg1 == LOOKUP_SRC_IP) { + keylen = is_ipv6 ? + sizeof(struct in6_addr): + sizeof(in_addr_t); + } else { + keylen = sizeof(key); + pkey = &key; + } - if (cmdlen > F_INSN_SIZE(ipfw_insn_u32)) { - /* Determine lookup key type */ - vidx = ((ipfw_insn_u32 *)cmd)->d[1]; - if (vidx != 4 /* uid */ && - vidx != 5 /* jail */ && - is_ipv6 == 0 && is_ipv4 == 0) - break; - /* Determine key length */ - if (vidx == 0 /* dst-ip */ || - vidx == 1 /* src-ip */) - keylen = is_ipv6 ? - sizeof(struct in6_addr): - sizeof(in_addr_t); + if (cmd->arg1 == LOOKUP_DST_IP) + pkey = is_ipv4 ? (void *)&dst_ip: + (void *)&args->f_id.dst_ip6; + else if (cmd->arg1 == LOOKUP_SRC_IP) + pkey = is_ipv4 ? (void *)&src_ip: + (void *)&args->f_id.src_ip6; + else if (cmd->arg1 == LOOKUP_DSCP) { + if (is_ipv4) + key = ip->ip_tos >> 2; else { - keylen = sizeof(key); - pkey = &key; - } - if (vidx == 0 /* dst-ip */) - pkey = is_ipv4 ? (void *)&dst_ip: - (void *)&args->f_id.dst_ip6; - else if (vidx == 1 /* src-ip */) - pkey = is_ipv4 ? (void *)&src_ip: - (void *)&args->f_id.src_ip6; - else if (vidx == 6 /* dscp */) { - if (is_ipv4) - key = ip->ip_tos >> 2; - else { - key = args->f_id.flow_id6; - key = (key & 0x0f) << 2 | - (key & 0xf000) >> 14; - } - key &= 0x3f; - } else if (vidx == 2 /* dst-port */ || - vidx == 3 /* src-port */) { - /* Skip fragments */ - if (offset != 0) - break; - /* Skip proto without ports */ - if (proto != IPPROTO_TCP && - proto != IPPROTO_UDP && - proto != IPPROTO_UDPLITE && - proto != IPPROTO_SCTP) - break; - if (vidx == 2 /* dst-port */) - key = dst_port; - else - key = src_port; + key = args->f_id.flow_id6; + key = (key & 0x0f) << 2 | + (key & 0xf000) >> 14; } + key &= 0x3f; + } else if (cmd->arg1 == LOOKUP_DST_PORT || + cmd->arg1 == LOOKUP_SRC_PORT) { + /* Skip fragments */ + if (offset != 0) + break; + /* Skip proto without ports */ + if (proto != IPPROTO_TCP && + proto != IPPROTO_UDP && + proto != IPPROTO_UDPLITE && + proto != IPPROTO_SCTP) + break; + if (cmd->arg1 == LOOKUP_DST_PORT) + key = dst_port; + else + key = src_port; + } #ifndef USERSPACE - else if (vidx == 4 /* uid */ || - vidx == 5 /* jail */) { - check_uidgid( - (ipfw_insn_u32 *)cmd, - args, &ucred_lookup, + else if (cmd->arg1 == LOOKUP_UID || + cmd->arg1 == LOOKUP_JAIL) { + check_uidgid(insntod(cmd, u32), + args, &ucred_lookup, #ifdef __FreeBSD__ - &ucred_cache); - if (vidx == 4 /* uid */) - key = ucred_cache->cr_uid; - else if (vidx == 5 /* jail */) - key = ucred_cache->cr_prison->pr_id; + &ucred_cache); + if (cmd->arg1 == LOOKUP_UID) + key = ucred_cache->cr_uid; + else if (cmd->arg1 == LOOKUP_JAIL) + key = ucred_cache->cr_prison->pr_id; #else /* !__FreeBSD__ */ - (void *)&ucred_cache); - if (vidx == 4 /* uid */) - key = ucred_cache.uid; - else if (vidx == 5 /* jail */) - key = ucred_cache.xid; + (void *)&ucred_cache); + if (cmd->arg1 == LOOKUP_UID) + key = ucred_cache.uid; + else if (cmd->arg1 == LOOKUP_JAIL) + key = ucred_cache.xid; #endif /* !__FreeBSD__ */ - } + } #endif /* !USERSPACE */ - else - break; - match = ipfw_lookup_table(chain, - cmd->arg1, keylen, pkey, &vidx); - if (!match) - break; - tablearg = vidx; + else + break; /* unknown key type */ + match = ipfw_lookup_table(chain, + insntod(cmd, kidx)->kidx, keylen, + pkey, &vidx); + + if (!match) break; - } - /* cmdlen =< F_INSN_SIZE(ipfw_insn_u32) */ - /* FALLTHROUGH */ + tablearg = vidx; } + /* FALLTHROUGH */ case O_IP_SRC_LOOKUP: { void *pkey; @@ -2053,12 +2050,15 @@ do { \ pkey = &args->f_id.src_ip6; } else break; - match = ipfw_lookup_table(chain, cmd->arg1, + + match = ipfw_lookup_table(chain, + insntod(cmd, kidx)->kidx, keylen, pkey, &vidx); if (!match) break; - if (cmdlen == F_INSN_SIZE(ipfw_insn_u32)) { - match = ((ipfw_insn_u32 *)cmd)->d[0] == + if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) { + match = + insntod(cmd, table)->value == TARG_VAL(chain, vidx, tag); if (!match) break; @@ -2068,17 +2068,20 @@ do { \ } case O_IP_FLOW_LOOKUP: - { - uint32_t v = 0; - match = ipfw_lookup_table(chain, - cmd->arg1, 0, &args->f_id, &v); - if (cmdlen == F_INSN_SIZE(ipfw_insn_u32)) - match = ((ipfw_insn_u32 *)cmd)->d[0] == - TARG_VAL(chain, v, tag); - if (match) - tablearg = v; - } + { + uint32_t v = 0; + + match = ipfw_lookup_table(chain, + insntod(cmd, kidx)->kidx, 0, + &args->f_id, &v); + if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) + match = + insntod(cmd, table)->value == + TARG_VAL(chain, v, tag); + if (match) + tablearg = v; break; + } case O_IP_SRC_MASK: case O_IP_DST_MASK: if (is_ipv4) { @@ -2788,7 +2791,8 @@ do { \ case O_SKIPTO: IPFW_INC_RULE_COUNTER(f, pktlen); - f_pos = JUMP(chain, f, cmd->arg1, tablearg, 0); + f_pos = JUMP(chain, f, + insntod(cmd, u32)->d[0], tablearg, 0); /* * Skip disabled rules, and re-enter * the inner loop with the correct @@ -2822,7 +2826,7 @@ do { \ * stack pointer. */ struct m_tag *mtag; - uint16_t jmpto, *stack; + uint32_t jmpto, *stack; #define IS_CALL ((cmd->len & F_NOT) == 0) #define IS_RETURN ((cmd->len & F_NOT) != 0) @@ -2841,7 +2845,7 @@ do { \ if (mtag == NULL && IS_CALL) { mtag = m_tag_alloc(MTAG_IPFW_CALL, 0, IPFW_CALLSTACK_SIZE * - sizeof(uint16_t), M_NOWAIT); + sizeof(uint32_t), M_NOWAIT); if (mtag != NULL) m_tag_prepend(m, mtag); } @@ -2864,25 +2868,27 @@ do { \ } IPFW_INC_RULE_COUNTER(f, pktlen); - stack = (uint16_t *)(mtag + 1); + stack = (uint32_t *)(mtag + 1); /* * The `call' action may use cached f_pos * (in f->next_rule), whose version is written * in f->next_rule. * The `return' action, however, doesn't have - * fixed jump address in cmd->arg1 and can't use + * fixed jump address in d[0] and can't use * cache. */ if (IS_CALL) { stack[mtag->m_tag_id] = f->rulenum; mtag->m_tag_id++; - f_pos = JUMP(chain, f, cmd->arg1, + f_pos = JUMP(chain, f, + insntod(cmd, u32)->d[0], tablearg, 1); } else { /* `return' action */ mtag->m_tag_id--; jmpto = stack[mtag->m_tag_id] + 1; - f_pos = ipfw_find_rule(chain, jmpto, 0); + f_pos = ipfw_find_rule(chain, + jmpto, 0); } /* diff --git a/sys/netpfil/ipfw/ip_fw_compat.c b/sys/netpfil/ipfw/ip_fw_compat.c new file mode 100644 index 00000000000..8c62f7a0720 --- /dev/null +++ b/sys/netpfil/ipfw/ip_fw_compat.c @@ -0,0 +1,615 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Yandex LLC + * Copyright (c) 2020 Andrey V. Elsukov + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * Compatibility layer for ipfw's control socket and rule management + * routines. + */ + +#include "opt_inet.h" +#include "opt_inet6.h" +#include "opt_ipfw.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include /* hooks */ +#include + +#include +#include + +#ifdef MAC +#include +#endif + +/* + * These structures were used by IP_FW3 socket option with version 0. + */ +typedef struct _ipfw_dyn_rule_v0 { + ipfw_dyn_rule *next; /* linked list of rules. */ + struct ip_fw *rule; /* pointer to rule */ + /* 'rule' is used to pass up the rule number (from the parent) */ + + ipfw_dyn_rule *parent; /* pointer to parent rule */ + u_int64_t pcnt; /* packet match counter */ + u_int64_t bcnt; /* byte match counter */ + struct ipfw_flow_id id; /* (masked) flow id */ + u_int32_t expire; /* expire time */ + u_int32_t bucket; /* which bucket in hash table */ + u_int32_t state; /* state of this rule (typically a + * combination of TCP flags) + */ + u_int32_t ack_fwd; /* most recent ACKs in forward */ + u_int32_t ack_rev; /* and reverse directions (used */ + /* to generate keepalives) */ + u_int16_t dyn_type; /* rule type */ + u_int16_t count; /* refcount */ + u_int16_t kidx; /* index of named object */ +} __packed __aligned(8) ipfw_dyn_rule_v0; + +typedef struct _ipfw_obj_dyntlv_v0 { + ipfw_obj_tlv head; + ipfw_dyn_rule_v0 state; +} ipfw_obj_dyntlv_v0; + +typedef struct _ipfw_obj_ntlv_v0 { + ipfw_obj_tlv head; /* TLV header */ + uint16_t idx; /* Name index */ + uint8_t set; /* set, if applicable */ + uint8_t type; /* object type, if applicable */ + uint32_t spare; /* unused */ + char name[64]; /* Null-terminated name */ +} ipfw_obj_ntlv_v0; + +typedef struct _ipfw_range_tlv_v0 { + ipfw_obj_tlv head; /* TLV header */ + uint32_t flags; /* Range flags */ + uint16_t start_rule; /* Range start */ + uint16_t end_rule; /* Range end */ + uint32_t set; /* Range set to match */ + uint32_t new_set; /* New set to move/swap to */ +} ipfw_range_tlv_v0; + +typedef struct _ipfw_insn_limit_v0 { + ipfw_insn o; + uint8_t _pad; + uint8_t limit_mask; + uint16_t conn_limit; +} ipfw_insn_limit_v0; + +typedef struct _ipfw_obj_tentry_v0 { + ipfw_obj_tlv head; /* TLV header */ + uint8_t subtype; /* subtype (IPv4,IPv6) */ + uint8_t masklen; /* mask length */ + uint8_t result; /* request result */ + uint8_t spare0; + uint16_t idx; /* Table name index */ + uint16_t spare1; + union { + /* Longest field needs to be aligned by 8-byte boundary */ + struct in_addr addr; /* IPv4 address */ + uint32_t key; /* uid/gid/port */ + struct in6_addr addr6; /* IPv6 address */ + char iface[IF_NAMESIZE]; /* interface name */ + struct tflow_entry flow; + } k; + union { + ipfw_table_value value; /* value data */ + uint32_t kidx; /* value kernel index */ + } v; +} ipfw_obj_tentry_v0; + +static sopt_handler_f dump_config_v0, add_rules_v0, del_rules_v0, clear_rules_v0, + move_rules_v0, manage_sets_v0, dump_soptcodes_v0, dump_srvobjects_v0; + +static struct ipfw_sopt_handler scodes[] = { + { IP_FW_XGET, 0, HDIR_GET, dump_config_v0 }, + { IP_FW_XADD, 0, HDIR_BOTH, add_rules_v0 }, + { IP_FW_XDEL, 0, HDIR_BOTH, del_rules_v0 }, + { IP_FW_XZERO, 0, HDIR_SET, clear_rules_v0 }, + { IP_FW_XRESETLOG, 0, HDIR_SET, clear_rules_v0 }, + { IP_FW_XMOVE, 0, HDIR_SET, move_rules_v0 }, + { IP_FW_SET_SWAP, 0, HDIR_SET, manage_sets_v0 }, + { IP_FW_SET_MOVE, 0, HDIR_SET, manage_sets_v0 }, + { IP_FW_SET_ENABLE, 0, HDIR_SET, manage_sets_v0 }, + { IP_FW_DUMP_SOPTCODES, 0, HDIR_GET, dump_soptcodes_v0 }, + { IP_FW_DUMP_SRVOBJECTS,0, HDIR_GET, dump_srvobjects_v0 }, +}; + +static int +dump_config_v0(struct ip_fw_chain *chain, ip_fw3_opheader *op3, + struct sockopt_data *sd) +{ + + return (EOPNOTSUPP); +} + +static int +adjust_size_v0(ipfw_insn *cmd) +{ + int cmdlen, adjust; + + cmdlen = F_LEN(cmd); + switch (cmd->opcode) { + case O_PROBE_STATE: + case O_KEEP_STATE: + adjust = F_INSN_SIZE(ipfw_insn_kidx) - cmdlen; + break; + case O_LIMIT: + adjust = F_INSN_SIZE(ipfw_insn_limit) - cmdlen; + break; + case O_IP_SRC_LOOKUP: + case O_IP_DST_LOOKUP: + case O_IP_FLOW_LOOKUP: + if (cmdlen == F_INSN_SIZE(ipfw_insn)) + adjust = F_INSN_SIZE(ipfw_insn_kidx) - cmdlen; + else + adjust = F_INSN_SIZE(ipfw_insn_table) - cmdlen; + break; + case O_CHECK_STATE: + case O_SKIPTO: + case O_CALLRETURN: + adjust = F_INSN_SIZE(ipfw_insn_u32) - cmdlen; + break; + case O_EXTERNAL_ACTION: + adjust = F_INSN_SIZE(ipfw_insn_kidx) - cmdlen; + break; + case O_EXTERNAL_DATA: + adjust = F_INSN_SIZE(ipfw_insn_kidx) - cmdlen; + break; + default: + adjust = 0; + } + return (adjust); +} + +static int +parse_rules_v0(struct ip_fw_chain *chain, ip_fw3_opheader *op3, + struct sockopt_data *sd, ipfw_obj_ctlv **prtlv, + struct rule_check_info **pci) +{ + ipfw_obj_ctlv *ctlv, *rtlv, *tstate; + ipfw_obj_ntlv_v0 *ntlv; + struct rule_check_info *ci, *cbuf; + struct ip_fw_rule *r; + size_t count, clen, read, rsize; + uint32_t rulenum; + int idx, error; + + op3 = (ip_fw3_opheader *)ipfw_get_sopt_space(sd, sd->valsize); + ctlv = (ipfw_obj_ctlv *)(op3 + 1); + read = sizeof(ip_fw3_opheader); + if (read + sizeof(*ctlv) > sd->valsize) + return (EINVAL); + + rtlv = NULL; + tstate = NULL; + cbuf = NULL; + /* Table names or other named objects. */ + if (ctlv->head.type == IPFW_TLV_TBLNAME_LIST) { + /* Check size and alignment. */ + clen = ctlv->head.length; + if (read + clen > sd->valsize || clen < sizeof(*ctlv) || + (clen % sizeof(uint64_t)) != 0) + return (EINVAL); + /* Check for validness. */ + count = (ctlv->head.length - sizeof(*ctlv)) / sizeof(*ntlv); + if (ctlv->count != count || ctlv->objsize != sizeof(*ntlv)) + return (EINVAL); + /* + * Check each TLV. + * Ensure TLVs are sorted ascending and + * there are no duplicates. + */ + idx = -1; + ntlv = (ipfw_obj_ntlv_v0 *)(ctlv + 1); + while (count > 0) { + if (ntlv->head.length != sizeof(ipfw_obj_ntlv)) + return (EINVAL); + + error = ipfw_check_object_name_generic(ntlv->name); + if (error != 0) + return (error); + + if (ntlv->idx <= idx) + return (EINVAL); + + idx = ntlv->idx; + count--; + ntlv++; + } + + tstate = ctlv; + read += ctlv->head.length; + ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length); + + if (read + sizeof(*ctlv) > sd->valsize) + return (EINVAL); + } + + /* List of rules. */ + if (ctlv->head.type == IPFW_TLV_RULE_LIST) { + clen = ctlv->head.length; + if (read + clen > sd->valsize || clen < sizeof(*ctlv) || + (clen % sizeof(uint64_t)) != 0) + return (EINVAL); + + clen -= sizeof(*ctlv); + if (ctlv->count == 0 || + ctlv->count > clen / sizeof(struct ip_fw_rule)) + return (EINVAL); + + /* Allocate state for each rule */ + cbuf = malloc(ctlv->count * sizeof(struct rule_check_info), + M_TEMP, M_WAITOK | M_ZERO); + + /* + * Check each rule for validness. + * Ensure numbered rules are sorted ascending + * and properly aligned + */ + rulenum = 0; + count = 0; + error = 0; + ci = cbuf; + r = (struct ip_fw_rule *)(ctlv + 1); + while (clen > 0) { + rsize = RULEUSIZE1(r); + if (rsize > clen || count > ctlv->count) { + error = EINVAL; + break; + } + ci->ctlv = tstate; + error = ipfw_check_rule(r, rsize, ci); + if (error != 0) + break; + + /* Check sorting */ + if (r->rulenum != 0 && r->rulenum < rulenum) { + printf("ipfw: wrong order: rulenum %u" + " vs %u\n", r->rulenum, rulenum); + error = EINVAL; + break; + } + rulenum = r->rulenum; + ci->urule = (caddr_t)r; + clen -= rsize; + r = (struct ip_fw_rule *)((caddr_t)r + rsize); + count++; + ci++; + } + + if (ctlv->count != count || error != 0) { + free(cbuf, M_TEMP); + return (EINVAL); + } + + rtlv = ctlv; + read += ctlv->head.length; + ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length); + } + + if (read != sd->valsize || rtlv == NULL) { + free(cbuf, M_TEMP); + return (EINVAL); + } + + *prtlv = rtlv; + *pci = cbuf; + return (0); +} + +/* + * Copy rule @urule from v0 userland format to kernel @krule. + */ +static void +import_rule_v0(struct ip_fw_chain *chain, struct rule_check_info *ci) +{ + struct ip_fw_rule *urule; + struct ip_fw *krule; + ipfw_insn *cmd; + int l, cmdlen, adjust, aadjust; + + urule = (struct ip_fw_rule *)ci->urule; + l = urule->cmd_len; + cmd = urule->cmd; + adjust = aadjust = 0; + while (l > 0) { + adjust += adjust_size_v0(cmd); + if (ACTION_PTR(urule) < cmd) + aadjust = adjust; + cmdlen = F_LEN(cmd); + l -= cmdlen; + cmd += cmdlen; + } + + krule = ci->krule = ipfw_alloc_rule(chain, + roundup2(sizeof(struct ip_fw) + + (urule->cmd_len + adjust) * 4 - 4, 8)); + + krule->act_ofs = urule->act_ofs + aadjust; + krule->cmd_len = urule->cmd_len + adjust; + + krule->rulenum = urule->rulenum; + krule->set = urule->set; + krule->flags = urule->flags; + + /* Save rulenum offset */ + ci->urule_numoff = offsetof(struct ip_fw_rule, rulenum); + + /* XXX: Convert and copy opcodes */ + memcpy(krule->cmd, urule->cmd, krule->cmd_len * sizeof(uint32_t)); +} + +static int +add_rules_v0(struct ip_fw_chain *chain, ip_fw3_opheader *op3, + struct sockopt_data *sd) +{ + ipfw_obj_ctlv *rtlv; + struct rule_check_info *ci, *nci; + int i, ret; + + /* + * Check rules buffer for validness. + */ + ret = parse_rules_v0(chain, op3, sd, &rtlv, &nci); + if (ret != 0) + return (ret); + /* + * Allocate storage for the kernel representation of rules. + */ + for (i = 0, ci = nci; i < rtlv->count; i++, ci++) + import_rule_v0(chain, ci); + /* + * Try to add new rules to the chain. + */ + if ((ret = ipfw_commit_rules(chain, nci, rtlv->count)) != 0) { + for (i = 0, ci = nci; i < rtlv->count; i++, ci++) + ipfw_free_rule(ci->krule); + } + /* Cleanup after ipfw_parse_rules() */ + free(nci, M_TEMP); + return (ret); +} + +static int +del_rules_v0(struct ip_fw_chain *chain, ip_fw3_opheader *op3, + struct sockopt_data *sd) +{ + + return (EOPNOTSUPP); +} + +static int +clear_rules_v0(struct ip_fw_chain *chain, ip_fw3_opheader *op3, + struct sockopt_data *sd) +{ + + return (EOPNOTSUPP); +} + +static int +move_rules_v0(struct ip_fw_chain *chain, ip_fw3_opheader *op3, + struct sockopt_data *sd) +{ + + return (EOPNOTSUPP); +} + +static int +manage_sets_v0(struct ip_fw_chain *chain, ip_fw3_opheader *op3, + struct sockopt_data *sd) +{ + + return (EOPNOTSUPP); +} + +static int +dump_soptcodes_v0(struct ip_fw_chain *chain, ip_fw3_opheader *op3, + struct sockopt_data *sd) +{ + + return (EOPNOTSUPP); +} + +static int +dump_srvobjects_v0(struct ip_fw_chain *chain, ip_fw3_opheader *op3, + struct sockopt_data *sd) +{ + + return (EOPNOTSUPP); +} + +static enum ipfw_opcheck_result +check_opcode_compat(ipfw_insn **pcmd, int *plen, struct rule_check_info *ci) +{ + ipfw_insn *cmd; + size_t cmdlen; + + if (ci->version == 0) { + cmd = *pcmd; + cmdlen = F_LEN(cmd); + switch (cmd->opcode) { + case O_PROBE_STATE: + case O_KEEP_STATE: + if (cmdlen != F_INSN_SIZE(ipfw_insn)) + return (BAD_SIZE); + ci->object_opcodes++; + break; + case O_LIMIT: + if (cmdlen != F_INSN_SIZE(ipfw_insn_limit_v0)) + return (BAD_SIZE); + ci->object_opcodes++; + break; + case O_IP_SRC_LOOKUP: + if (cmdlen > F_INSN_SIZE(ipfw_insn_u32)) + return (BAD_SIZE); + /* FALLTHROUGH */ + case O_IP_DST_LOOKUP: + if (cmdlen != F_INSN_SIZE(ipfw_insn) && + cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1 && + cmdlen != F_INSN_SIZE(ipfw_insn_u32)) + return (BAD_SIZE); + if (cmd->arg1 >= V_fw_tables_max) { + printf("ipfw: invalid table number %u\n", + cmd->arg1); + return (FAILED); + } + ci->object_opcodes++; + break; + case O_IP_FLOW_LOOKUP: + if (cmdlen != F_INSN_SIZE(ipfw_insn) && + cmdlen != F_INSN_SIZE(ipfw_insn_u32)) + return (BAD_SIZE); + if (cmd->arg1 >= V_fw_tables_max) { + printf("ipfw: invalid table number %u\n", + cmd->arg1); + return (FAILED); + } + ci->object_opcodes++; + break; + case O_CHECK_STATE: + ci->object_opcodes++; + /* FALLTHROUGH */ + case O_SKIPTO: + case O_CALLRETURN: + if (cmdlen != F_INSN_SIZE(ipfw_insn)) + return (BAD_SIZE); + return (CHECK_ACTION); + + case O_EXTERNAL_ACTION: + if (cmd->arg1 == 0 || + cmdlen != F_INSN_SIZE(ipfw_insn)) { + printf("ipfw: invalid external " + "action opcode\n"); + return (FAILED); + } + ci->object_opcodes++; + /* + * Do we have O_EXTERNAL_INSTANCE or O_EXTERNAL_DATA + * opcode? + */ + if (*plen != cmdlen) { + *plen -= cmdlen; + *pcmd = cmd += cmdlen; + cmdlen = F_LEN(cmd); + if (cmd->opcode == O_EXTERNAL_DATA) + return (CHECK_ACTION); + if (cmd->opcode != O_EXTERNAL_INSTANCE) { + printf("ipfw: invalid opcode " + "next to external action %u\n", + cmd->opcode); + return (FAILED); + } + if (cmd->arg1 == 0 || + cmdlen != F_INSN_SIZE(ipfw_insn)) { + printf("ipfw: invalid external " + "action instance opcode\n"); + return (FAILED); + } + ci->object_opcodes++; + } + return (CHECK_ACTION); + + default: + return (ipfw_check_opcode(pcmd, plen, ci)); + } + return (SUCCESS); + } + return (FAILED); +} + +/** + * {set|get}sockopt parser. + */ +int +ipfw_ctl(struct sockopt *sopt) +{ + + return (EOPNOTSUPP); +} + +static int +ipfw_compat_modevent(module_t mod, int type, void *unused) +{ + + switch (type) { + case MOD_LOAD: + IPFW_ADD_SOPT_HANDLER(1, scodes); + ipfw_register_compat(check_opcode_compat); + break; + case MOD_UNLOAD: + ipfw_unregister_compat(); + IPFW_DEL_SOPT_HANDLER(1, scodes); + break; + default: + return (EOPNOTSUPP); + } + return (0); +} + +static moduledata_t ipfw_compat_mod = { + "ipfw_compat", + ipfw_compat_modevent, + 0 +}; + +/* Define startup order. */ +#define IPFW_COMPAT_SI_SUB_FIREWALL SI_SUB_PROTO_FIREWALL +#define IPFW_COMPAT_MODEVENT_ORDER (SI_ORDER_ANY - 128) /* after ipfw */ +#define IPFW_COMPAT_MODULE_ORDER (IPFW_COMPAT_MODEVENT_ORDER + 1) + +DECLARE_MODULE(ipfw_compat, ipfw_compat_mod, IPFW_COMPAT_SI_SUB_FIREWALL, + IPFW_COMPAT_MODULE_ORDER); +MODULE_DEPEND(ipfw_compat, ipfw, 3, 3, 3); +MODULE_VERSION(ipfw_compat, 1); diff --git a/sys/netpfil/ipfw/ip_fw_dynamic.c b/sys/netpfil/ipfw/ip_fw_dynamic.c index dea8147c496..e50223c0ecc 100644 --- a/sys/netpfil/ipfw/ip_fw_dynamic.c +++ b/sys/netpfil/ipfw/ip_fw_dynamic.c @@ -135,9 +135,9 @@ struct dyn_data { uint32_t hashval; /* hash value used for hash resize */ uint16_t fibnum; /* fib used to send keepalives */ - uint8_t _pad[3]; + uint8_t _pad; uint8_t flags; /* internal flags */ - uint16_t rulenum; /* parent rule number */ + uint32_t rulenum; /* parent rule number */ uint32_t ruleid; /* parent rule id */ uint32_t state; /* TCP session state and flags */ @@ -162,8 +162,7 @@ struct dyn_data { struct dyn_parent { void *parent; /* pointer to parent rule */ uint32_t count; /* number of linked states */ - uint8_t _pad[2]; - uint16_t rulenum; /* parent rule number */ + uint32_t rulenum; /* parent rule number */ uint32_t ruleid; /* parent rule id */ uint32_t hashval; /* hash value used for hash resize */ uint32_t expire; /* expire time */ @@ -172,7 +171,8 @@ struct dyn_parent { struct dyn_ipv4_state { uint8_t type; /* State type */ uint8_t proto; /* UL Protocol */ - uint16_t kidx; /* named object index */ + uint16_t spare; + uint32_t kidx; /* named object index */ uint16_t sport, dport; /* ULP source and destination ports */ in_addr_t src, dst; /* IPv4 source and destination */ @@ -197,7 +197,8 @@ static VNET_DEFINE(struct dyn_ipv4_slist, dyn_expired_ipv4); struct dyn_ipv6_state { uint8_t type; /* State type */ uint8_t proto; /* UL Protocol */ - uint16_t kidx; /* named object index */ + uint16_t spare; + uint32_t kidx; /* named object index */ uint16_t sport, dport; /* ULP source and destination ports */ struct in6_addr src, dst; /* IPv6 source and destination */ uint32_t zoneid; /* IPv6 scope zone id */ @@ -527,12 +528,12 @@ static struct dyn_ipv6_state *dyn_lookup_ipv6_state( const struct ipfw_flow_id *, uint32_t, const void *, struct ipfw_dyn_info *, int); static int dyn_lookup_ipv6_state_locked(const struct ipfw_flow_id *, - uint32_t, const void *, int, uint32_t, uint16_t); + uint32_t, const void *, int, uint32_t, uint32_t); static struct dyn_ipv6_state *dyn_alloc_ipv6_state( - const struct ipfw_flow_id *, uint32_t, uint16_t, uint8_t); -static int dyn_add_ipv6_state(void *, uint32_t, uint16_t, + const struct ipfw_flow_id *, uint32_t, uint32_t, uint8_t); +static int dyn_add_ipv6_state(void *, uint32_t, uint32_t, const struct ipfw_flow_id *, uint32_t, const void *, int, uint32_t, - struct ipfw_dyn_info *, uint16_t, uint16_t, uint8_t); + struct ipfw_dyn_info *, uint16_t, uint32_t, uint8_t); static void dyn_export_ipv6_state(const struct dyn_ipv6_state *, ipfw_dyn_rule *); @@ -545,33 +546,33 @@ static void dyn_enqueue_keepalive_ipv6(struct mbufq *, static void dyn_send_keepalive_ipv6(struct ip_fw_chain *); static struct dyn_ipv6_state *dyn_lookup_ipv6_parent( - const struct ipfw_flow_id *, uint32_t, const void *, uint32_t, uint16_t, + const struct ipfw_flow_id *, uint32_t, const void *, uint32_t, uint32_t, uint32_t); static struct dyn_ipv6_state *dyn_lookup_ipv6_parent_locked( - const struct ipfw_flow_id *, uint32_t, const void *, uint32_t, uint16_t, + const struct ipfw_flow_id *, uint32_t, const void *, uint32_t, uint32_t, uint32_t); -static struct dyn_ipv6_state *dyn_add_ipv6_parent(void *, uint32_t, uint16_t, - const struct ipfw_flow_id *, uint32_t, uint32_t, uint32_t, uint16_t); +static struct dyn_ipv6_state *dyn_add_ipv6_parent(void *, uint32_t, uint32_t, + const struct ipfw_flow_id *, uint32_t, uint32_t, uint32_t, uint32_t); #endif /* INET6 */ /* Functions to work with limit states */ static void *dyn_get_parent_state(const struct ipfw_flow_id *, uint32_t, - struct ip_fw *, uint32_t, uint32_t, uint16_t); + struct ip_fw *, uint32_t, uint32_t, uint32_t); static struct dyn_ipv4_state *dyn_lookup_ipv4_parent( - const struct ipfw_flow_id *, const void *, uint32_t, uint16_t, uint32_t); + const struct ipfw_flow_id *, const void *, uint32_t, uint32_t, uint32_t); static struct dyn_ipv4_state *dyn_lookup_ipv4_parent_locked( - const struct ipfw_flow_id *, const void *, uint32_t, uint16_t, uint32_t); -static struct dyn_parent *dyn_alloc_parent(void *, uint32_t, uint16_t, + const struct ipfw_flow_id *, const void *, uint32_t, uint32_t, uint32_t); +static struct dyn_parent *dyn_alloc_parent(void *, uint32_t, uint32_t, uint32_t); -static struct dyn_ipv4_state *dyn_add_ipv4_parent(void *, uint32_t, uint16_t, - const struct ipfw_flow_id *, uint32_t, uint32_t, uint16_t); +static struct dyn_ipv4_state *dyn_add_ipv4_parent(void *, uint32_t, uint32_t, + const struct ipfw_flow_id *, uint32_t, uint32_t, uint32_t); static void dyn_tick(void *); static void dyn_expire_states(struct ip_fw_chain *, ipfw_range_tlv *); static void dyn_free_states(struct ip_fw_chain *); -static void dyn_export_parent(const struct dyn_parent *, uint16_t, uint8_t, +static void dyn_export_parent(const struct dyn_parent *, uint32_t, uint8_t, ipfw_dyn_rule *); -static void dyn_export_data(const struct dyn_data *, uint16_t, uint8_t, +static void dyn_export_data(const struct dyn_data *, uint32_t, uint8_t, uint8_t, ipfw_dyn_rule *); static uint32_t dyn_update_tcp_state(struct dyn_data *, const struct ipfw_flow_id *, const struct tcphdr *, int); @@ -582,12 +583,12 @@ static void dyn_update_proto_state(struct dyn_data *, struct dyn_ipv4_state *dyn_lookup_ipv4_state(const struct ipfw_flow_id *, const void *, struct ipfw_dyn_info *, int); static int dyn_lookup_ipv4_state_locked(const struct ipfw_flow_id *, - const void *, int, uint32_t, uint16_t); + const void *, int, uint32_t, uint32_t); static struct dyn_ipv4_state *dyn_alloc_ipv4_state( - const struct ipfw_flow_id *, uint16_t, uint8_t); -static int dyn_add_ipv4_state(void *, uint32_t, uint16_t, + const struct ipfw_flow_id *, uint32_t, uint8_t); +static int dyn_add_ipv4_state(void *, uint32_t, uint32_t, const struct ipfw_flow_id *, const void *, int, uint32_t, - struct ipfw_dyn_info *, uint16_t, uint16_t, uint8_t); + struct ipfw_dyn_info *, uint16_t, uint32_t, uint8_t); static void dyn_export_ipv4_state(const struct dyn_ipv4_state *, ipfw_dyn_rule *); @@ -608,26 +609,35 @@ struct dyn_state_obj { * or rewritten. */ static int -dyn_classify(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) +dyn_classify(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype) { + ipfw_insn_kidx *cmd; - DYN_DEBUG("opcode %d, arg1 %d", cmd->opcode, cmd->arg1); + if (F_LEN(cmd0) < 2) + return (EINVAL); + + /* + * NOTE: ipfw_insn_kidx and ipfw_insn_limit has overlapped kidx + * field, so we can use one type to get access to kidx field. + */ + cmd = insntod(cmd0, kidx); + DYN_DEBUG("opcode %u, kidx %u", cmd->opcode, cmd->kidx); /* Don't rewrite "check-state any" */ - if (cmd->arg1 == 0 && - cmd->opcode == O_CHECK_STATE) + if (cmd->kidx == 0 && + cmd0->opcode == O_CHECK_STATE) return (1); - *puidx = cmd->arg1; + *puidx = cmd->kidx; *ptype = 0; return (0); } static void -dyn_update(ipfw_insn *cmd, uint16_t idx) +dyn_update(ipfw_insn *cmd0, uint32_t idx) { - cmd->arg1 = idx; - DYN_DEBUG("opcode %d, arg1 %d", cmd->opcode, cmd->arg1); + insntod(cmd0, kidx)->kidx = idx; + DYN_DEBUG("opcode %u, kidx %u", cmd->opcode, idx); } static int @@ -637,7 +647,7 @@ dyn_findbyname(struct ip_fw_chain *ch, struct tid_info *ti, ipfw_obj_ntlv *ntlv; const char *name; - DYN_DEBUG("uidx %d", ti->uidx); + DYN_DEBUG("uidx %u", ti->uidx); if (ti->uidx != 0) { if (ti->tlvs == NULL) return (EINVAL); @@ -665,16 +675,16 @@ dyn_findbyname(struct ip_fw_chain *ch, struct tid_info *ti, } static struct named_object * -dyn_findbykidx(struct ip_fw_chain *ch, uint16_t idx) +dyn_findbykidx(struct ip_fw_chain *ch, uint32_t idx) { - DYN_DEBUG("kidx %d", idx); + DYN_DEBUG("kidx %u", idx); return (ipfw_objhash_lookup_kidx(CHAIN_TO_SRV(ch), idx)); } static int dyn_create(struct ip_fw_chain *ch, struct tid_info *ti, - uint16_t *pkidx) + uint32_t *pkidx) { struct namedobj_instance *ni; struct dyn_state_obj *obj; @@ -682,7 +692,7 @@ dyn_create(struct ip_fw_chain *ch, struct tid_info *ti, ipfw_obj_ntlv *ntlv; char *name; - DYN_DEBUG("uidx %d", ti->uidx); + DYN_DEBUG("uidx %u", ti->uidx); if (ti->uidx != 0) { if (ti->tlvs == NULL) return (EINVAL); @@ -712,7 +722,7 @@ dyn_create(struct ip_fw_chain *ch, struct tid_info *ti, no->refcnt++; IPFW_UH_WUNLOCK(ch); free(obj, M_IPFW); - DYN_DEBUG("\tfound kidx %d", *pkidx); + DYN_DEBUG("\tfound kidx %u", *pkidx); return (0); } if (ipfw_objhash_alloc_idx(ni, &obj->no.kidx) != 0) { @@ -726,7 +736,7 @@ dyn_create(struct ip_fw_chain *ch, struct tid_info *ti, obj->no.refcnt++; *pkidx = obj->no.kidx; IPFW_UH_WUNLOCK(ch); - DYN_DEBUG("\tcreated kidx %d", *pkidx); + DYN_DEBUG("\tcreated kidx %u", *pkidx); return (0); } @@ -742,7 +752,7 @@ dyn_destroy(struct ip_fw_chain *ch, struct named_object *no) KASSERT(no->refcnt == 1, ("Destroying object '%s' (type %u, idx %u) with refcnt %u", no->name, no->etlv, no->kidx, no->refcnt)); - DYN_DEBUG("kidx %d", no->kidx); + DYN_DEBUG("kidx %u", no->kidx); obj = SRV_OBJECT(ch, no->kidx); SRV_OBJECT(ch, no->kidx) = NULL; ipfw_objhash_del(CHAIN_TO_SRV(ch), no); @@ -1163,7 +1173,7 @@ restart: */ static int dyn_lookup_ipv4_state_locked(const struct ipfw_flow_id *pkt, - const void *ulp, int pktlen, uint32_t bucket, uint16_t kidx) + const void *ulp, int pktlen, uint32_t bucket, uint32_t kidx) { struct dyn_ipv4_state *s; int dir; @@ -1193,7 +1203,7 @@ dyn_lookup_ipv4_state_locked(const struct ipfw_flow_id *pkt, struct dyn_ipv4_state * dyn_lookup_ipv4_parent(const struct ipfw_flow_id *pkt, const void *rule, - uint32_t ruleid, uint16_t rulenum, uint32_t hashval) + uint32_t ruleid, uint32_t rulenum, uint32_t hashval) { struct dyn_ipv4_state *s; uint32_t version, bucket; @@ -1229,7 +1239,7 @@ restart: static struct dyn_ipv4_state * dyn_lookup_ipv4_parent_locked(const struct ipfw_flow_id *pkt, - const void *rule, uint32_t ruleid, uint16_t rulenum, uint32_t bucket) + const void *rule, uint32_t ruleid, uint32_t rulenum, uint32_t bucket) { struct dyn_ipv4_state *s; @@ -1333,7 +1343,7 @@ restart: */ static int dyn_lookup_ipv6_state_locked(const struct ipfw_flow_id *pkt, uint32_t zoneid, - const void *ulp, int pktlen, uint32_t bucket, uint16_t kidx) + const void *ulp, int pktlen, uint32_t bucket, uint32_t kidx) { struct dyn_ipv6_state *s; int dir; @@ -1364,7 +1374,7 @@ dyn_lookup_ipv6_state_locked(const struct ipfw_flow_id *pkt, uint32_t zoneid, static struct dyn_ipv6_state * dyn_lookup_ipv6_parent(const struct ipfw_flow_id *pkt, uint32_t zoneid, - const void *rule, uint32_t ruleid, uint16_t rulenum, uint32_t hashval) + const void *rule, uint32_t ruleid, uint32_t rulenum, uint32_t hashval) { struct dyn_ipv6_state *s; uint32_t version, bucket; @@ -1401,7 +1411,7 @@ restart: static struct dyn_ipv6_state * dyn_lookup_ipv6_parent_locked(const struct ipfw_flow_id *pkt, uint32_t zoneid, - const void *rule, uint32_t ruleid, uint16_t rulenum, uint32_t bucket) + const void *rule, uint32_t ruleid, uint32_t rulenum, uint32_t bucket) { struct dyn_ipv6_state *s; @@ -1441,10 +1451,11 @@ ipfw_dyn_lookup_state(const struct ip_fw_args *args, const void *ulp, struct ip_fw *rule; IPFW_RLOCK_ASSERT(&V_layer3_chain); + MPASS(F_LEN(cmd) >= F_INSN_SIZE(ipfw_insn_kidx)); data = NULL; rule = NULL; - info->kidx = cmd->arg1; + info->kidx = ((const ipfw_insn_kidx *)cmd)->kidx; info->direction = MATCH_NONE; info->hashval = hash_packet(&args->f_id); sync_id.addr_type = 0; /* use it as flag to invoke ipfwsync */ @@ -1573,7 +1584,7 @@ ipfw_dyn_lookup_state(const struct ip_fw_args *args, const void *ulp, } static struct dyn_parent * -dyn_alloc_parent(void *parent, uint32_t ruleid, uint16_t rulenum, +dyn_alloc_parent(void *parent, uint32_t ruleid, uint32_t rulenum, uint32_t hashval) { struct dyn_parent *limit; @@ -1599,7 +1610,7 @@ dyn_alloc_parent(void *parent, uint32_t ruleid, uint16_t rulenum, } static struct dyn_data * -dyn_alloc_dyndata(void *parent, uint32_t ruleid, uint16_t rulenum, +dyn_alloc_dyndata(void *parent, uint32_t ruleid, uint32_t rulenum, const struct ipfw_flow_id *pkt, const void *ulp, int pktlen, uint32_t hashval, uint16_t fibnum) { @@ -1627,7 +1638,7 @@ dyn_alloc_dyndata(void *parent, uint32_t ruleid, uint16_t rulenum, } static struct dyn_ipv4_state * -dyn_alloc_ipv4_state(const struct ipfw_flow_id *pkt, uint16_t kidx, +dyn_alloc_ipv4_state(const struct ipfw_flow_id *pkt, uint32_t kidx, uint8_t type) { struct dyn_ipv4_state *s; @@ -1654,9 +1665,9 @@ dyn_alloc_ipv4_state(const struct ipfw_flow_id *pkt, uint16_t kidx, * is not needed. */ static struct dyn_ipv4_state * -dyn_add_ipv4_parent(void *rule, uint32_t ruleid, uint16_t rulenum, +dyn_add_ipv4_parent(void *rule, uint32_t ruleid, uint32_t rulenum, const struct ipfw_flow_id *pkt, uint32_t hashval, uint32_t version, - uint16_t kidx) + uint32_t kidx) { struct dyn_ipv4_state *s; struct dyn_parent *limit; @@ -1707,10 +1718,10 @@ dyn_add_ipv4_parent(void *rule, uint32_t ruleid, uint16_t rulenum, } static int -dyn_add_ipv4_state(void *parent, uint32_t ruleid, uint16_t rulenum, +dyn_add_ipv4_state(void *parent, uint32_t ruleid, uint32_t rulenum, const struct ipfw_flow_id *pkt, const void *ulp, int pktlen, uint32_t hashval, struct ipfw_dyn_info *info, uint16_t fibnum, - uint16_t kidx, uint8_t type) + uint32_t kidx, uint8_t type) { struct ipfw_flow_id sync_id; struct dyn_ipv4_state *s; @@ -1763,7 +1774,7 @@ dyn_add_ipv4_state(void *parent, uint32_t ruleid, uint16_t rulenum, #ifdef INET6 static struct dyn_ipv6_state * dyn_alloc_ipv6_state(const struct ipfw_flow_id *pkt, uint32_t zoneid, - uint16_t kidx, uint8_t type) + uint32_t kidx, uint8_t type) { struct dyn_ipv6_state *s; @@ -1790,9 +1801,9 @@ dyn_alloc_ipv6_state(const struct ipfw_flow_id *pkt, uint32_t zoneid, * is not needed. */ static struct dyn_ipv6_state * -dyn_add_ipv6_parent(void *rule, uint32_t ruleid, uint16_t rulenum, +dyn_add_ipv6_parent(void *rule, uint32_t ruleid, uint32_t rulenum, const struct ipfw_flow_id *pkt, uint32_t zoneid, uint32_t hashval, - uint32_t version, uint16_t kidx) + uint32_t version, uint32_t kidx) { struct dyn_ipv6_state *s; struct dyn_parent *limit; @@ -1843,10 +1854,10 @@ dyn_add_ipv6_parent(void *rule, uint32_t ruleid, uint16_t rulenum, } static int -dyn_add_ipv6_state(void *parent, uint32_t ruleid, uint16_t rulenum, +dyn_add_ipv6_state(void *parent, uint32_t ruleid, uint32_t rulenum, const struct ipfw_flow_id *pkt, uint32_t zoneid, const void *ulp, int pktlen, uint32_t hashval, struct ipfw_dyn_info *info, - uint16_t fibnum, uint16_t kidx, uint8_t type) + uint16_t fibnum, uint32_t kidx, uint8_t type) { struct ipfw_flow_id sync_id; struct dyn_ipv6_state *s; @@ -1899,7 +1910,7 @@ dyn_add_ipv6_state(void *parent, uint32_t ruleid, uint16_t rulenum, static void * dyn_get_parent_state(const struct ipfw_flow_id *pkt, uint32_t zoneid, - struct ip_fw *rule, uint32_t hashval, uint32_t limit, uint16_t kidx) + struct ip_fw *rule, uint32_t hashval, uint32_t limit, uint32_t kidx) { char sbuf[24]; struct dyn_parent *p; @@ -1993,7 +2004,7 @@ static int dyn_install_state(const struct ipfw_flow_id *pkt, uint32_t zoneid, uint16_t fibnum, const void *ulp, int pktlen, struct ip_fw *rule, struct ipfw_dyn_info *info, uint32_t limit, uint16_t limit_mask, - uint16_t kidx, uint8_t type) + uint32_t kidx, uint8_t type) { struct ipfw_flow_id id; uint32_t hashval, parent_hashval, ruleid, rulenum; @@ -2149,7 +2160,7 @@ ipfwsyncin_one(const struct ipfw_flow_id *pkt) { struct ipfw_dyn_info info; struct named_object *no; - uint16_t kidx = 0; + uint32_t kidx = 0; info.direction = MATCH_UNKNOWN; /* force check for state existance */ no = ipfw_objhash_lookup_name_type( @@ -2277,7 +2288,7 @@ dyn_free_states(struct ip_fw_chain *chain) * dynamic states. */ static int -dyn_match_range(uint16_t rulenum, uint8_t set, const ipfw_range_tlv *rt) +dyn_match_range(uint32_t rulenum, uint8_t set, const ipfw_range_tlv *rt) { MPASS(rt != NULL); @@ -2299,7 +2310,7 @@ dyn_match_range(uint16_t rulenum, uint8_t set, const ipfw_range_tlv *rt) static void dyn_acquire_rule(struct ip_fw_chain *ch, struct dyn_data *data, - struct ip_fw *rule, uint16_t kidx) + struct ip_fw *rule, uint32_t kidx) { struct dyn_state_obj *obj; @@ -2332,7 +2343,7 @@ dyn_acquire_rule(struct ip_fw_chain *ch, struct dyn_data *data, static void dyn_release_rule(struct ip_fw_chain *ch, struct dyn_data *data, - struct ip_fw *rule, uint16_t kidx) + struct ip_fw *rule, uint32_t kidx) { struct dyn_state_obj *obj; @@ -3097,70 +3108,46 @@ ipfw_is_dyn_rule(struct ip_fw *rule) } static void -dyn_export_parent(const struct dyn_parent *p, uint16_t kidx, uint8_t set, +dyn_export_parent(const struct dyn_parent *p, uint32_t kidx, uint8_t set, ipfw_dyn_rule *dst) { - dst->dyn_type = O_LIMIT_PARENT; + dst->type = O_LIMIT_PARENT; + dst->set = set; dst->kidx = kidx; + dst->rulenum = p->rulenum; dst->count = DPARENT_COUNT(p); dst->expire = TIME_LEQ(p->expire, time_uptime) ? 0: p->expire - time_uptime; - - /* 'rule' is used to pass up the rule number and set */ - memcpy(&dst->rule, &p->rulenum, sizeof(p->rulenum)); - - /* store set number into high word of dst->rule pointer. */ - memcpy((char *)&dst->rule + sizeof(p->rulenum), &set, sizeof(set)); + dst->hashval = p->hashval; /* unused fields */ + dst->pad = 0; dst->pcnt = 0; dst->bcnt = 0; - dst->parent = NULL; - dst->state = 0; dst->ack_fwd = 0; dst->ack_rev = 0; - dst->bucket = p->hashval; - /* - * The legacy userland code will interpret a NULL here as a marker - * for the last dynamic rule. - */ - dst->next = (ipfw_dyn_rule *)1; } static void -dyn_export_data(const struct dyn_data *data, uint16_t kidx, uint8_t type, +dyn_export_data(const struct dyn_data *data, uint32_t kidx, uint8_t type, uint8_t set, ipfw_dyn_rule *dst) { - dst->dyn_type = type; + dst->type = type; + dst->set = set; dst->kidx = kidx; + dst->rulenum = data->rulenum; dst->pcnt = data->pcnt_fwd + data->pcnt_rev; dst->bcnt = data->bcnt_fwd + data->bcnt_rev; dst->expire = TIME_LEQ(data->expire, time_uptime) ? 0: data->expire - time_uptime; - - /* 'rule' is used to pass up the rule number and set */ - memcpy(&dst->rule, &data->rulenum, sizeof(data->rulenum)); - - /* store set number into high word of dst->rule pointer. */ - memcpy((char *)&dst->rule + sizeof(data->rulenum), &set, sizeof(set)); - dst->state = data->state; if (data->flags & DYN_REFERENCED) dst->state |= IPFW_DYN_ORPHANED; - - /* unused fields */ - dst->parent = NULL; dst->ack_fwd = data->ack_fwd; dst->ack_rev = data->ack_rev; - dst->count = 0; - dst->bucket = data->hashval; - /* - * The legacy userland code will interpret a NULL here as a marker - * for the last dynamic rule. - */ - dst->next = (ipfw_dyn_rule *)1; + dst->hashval = data->hashval; } static void @@ -3288,6 +3275,7 @@ ipfw_dump_states(struct ip_fw_chain *chain, struct sockopt_data *sd) #undef DYN_EXPORT_STATES } +#if 0 /* * Fill given buffer with dynamic states (legacy format). * IPFW_UH_RLOCK has to be held while calling. @@ -3333,6 +3321,7 @@ ipfw_get_dynamic(struct ip_fw_chain *chain, char **pbp, const char *ep) *pbp = bp; #undef DYN_EXPORT_STATES } +#endif static struct ip_fw * dyn_add_protected_rule(struct ip_fw_chain *chain) diff --git a/sys/netpfil/ipfw/ip_fw_eaction.c b/sys/netpfil/ipfw/ip_fw_eaction.c index 3da598b6e5c..b76166c60cf 100644 --- a/sys/netpfil/ipfw/ip_fw_eaction.c +++ b/sys/netpfil/ipfw/ip_fw_eaction.c @@ -71,7 +71,7 @@ __FBSDID("$FreeBSD$"); * It is possible to pass some additional information to external * action handler using O_EXTERNAL_INSTANCE and O_EXTERNAL_DATA opcodes. * Such opcodes should be next after the O_EXTERNAL_ACTION opcode. - * For the O_EXTERNAL_INSTANCE opcode the cmd->arg1 contains index of named + * For the O_EXTERNAL_INSTANCE opcode the cmd->kidx contains index of named * object related to an instance of external action. * For the O_EXTERNAL_DATA opcode the cmd contains the data that can be used * by external action handler without needing to create named instance. @@ -79,7 +79,7 @@ __FBSDID("$FreeBSD$"); * In case when eaction module uses named instances, it should register * opcode rewriting routines for O_EXTERNAL_INSTANCE opcode. The * classifier callback can look back into O_EXTERNAL_ACTION opcode (it - * must be in the (ipfw_insn *)(cmd - 1)). By arg1 from O_EXTERNAL_ACTION + * must be in the (ipfw_insn *)(cmd - 2)). By kidx from O_EXTERNAL_ACTION * it can deteremine eaction_id and compare it with its own. * The macro IPFW_TLV_EACTION_NAME(eaction_id) can be used to deteremine * the type of named_object related to external action instance. @@ -95,7 +95,7 @@ struct eaction_obj { }; #define EACTION_OBJ(ch, cmd) \ - ((struct eaction_obj *)SRV_OBJECT((ch), (cmd)->arg1)) + ((struct eaction_obj *)SRV_OBJECT((ch), insntod((cmd), kidx)->kidx)) #if 0 #define EACTION_DEBUG(fmt, ...) do { \ @@ -119,21 +119,28 @@ default_eaction(struct ip_fw_chain *ch, struct ip_fw_args *args, * Opcode rewriting callbacks. */ static int -eaction_classify(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) +eaction_classify(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype) { + ipfw_insn_kidx *cmd; - EACTION_DEBUG("opcode %d, arg1 %d", cmd->opcode, cmd->arg1); - *puidx = cmd->arg1; + if (F_LEN(cmd0) <= 1) + return (EINVAL); + + cmd = insntod(cmd0, kidx); + EACTION_DEBUG("opcode %u, kidx %u", cmd0->opcode, cmd->kidx); + *puidx = cmd->kidx; *ptype = 0; return (0); } static void -eaction_update(ipfw_insn *cmd, uint16_t idx) +eaction_update(ipfw_insn *cmd0, uint32_t idx) { + ipfw_insn_kidx *cmd; - cmd->arg1 = idx; - EACTION_DEBUG("opcode %d, arg1 -> %d", cmd->opcode, cmd->arg1); + cmd = insntod(cmd0, kidx); + cmd->kidx = idx; + EACTION_DEBUG("opcode %u, kidx -> %u", cmd0->opcode, cmd->kidx); } static int @@ -165,7 +172,7 @@ eaction_findbyname(struct ip_fw_chain *ch, struct tid_info *ti, } static struct named_object * -eaction_findbykidx(struct ip_fw_chain *ch, uint16_t idx) +eaction_findbykidx(struct ip_fw_chain *ch, uint32_t idx) { EACTION_DEBUG("kidx %u", idx); @@ -185,7 +192,7 @@ static struct opcode_obj_rewrite eaction_opcodes[] = { static int create_eaction_obj(struct ip_fw_chain *ch, ipfw_eaction_t handler, - const char *name, uint16_t *eaction_id) + const char *name, uint32_t *eaction_id) { struct namedobj_instance *ni; struct eaction_obj *obj; @@ -252,8 +259,8 @@ destroy_eaction_obj(struct ip_fw_chain *ch, struct named_object *no) * Resets all eaction opcodes to default handlers. */ static void -reset_eaction_rules(struct ip_fw_chain *ch, uint16_t eaction_id, - uint16_t instance_id, bool reset_rules) +reset_eaction_rules(struct ip_fw_chain *ch, uint32_t eaction_id, + uint32_t instance_id, bool reset_rules) { struct named_object *no; int i; @@ -335,11 +342,11 @@ ipfw_eaction_uninit(struct ip_fw_chain *ch, int last) * Registers external action handler to the global array. * On success it returns eaction id, otherwise - zero. */ -uint16_t +uint32_t ipfw_add_eaction(struct ip_fw_chain *ch, ipfw_eaction_t handler, const char *name) { - uint16_t eaction_id; + uint32_t eaction_id; eaction_id = 0; if (ipfw_check_object_name_generic(name) == 0) { @@ -354,7 +361,7 @@ ipfw_add_eaction(struct ip_fw_chain *ch, ipfw_eaction_t handler, * Deregisters external action handler with id eaction_id. */ int -ipfw_del_eaction(struct ip_fw_chain *ch, uint16_t eaction_id) +ipfw_del_eaction(struct ip_fw_chain *ch, uint32_t eaction_id) { struct named_object *no; @@ -374,7 +381,7 @@ ipfw_del_eaction(struct ip_fw_chain *ch, uint16_t eaction_id) int ipfw_reset_eaction(struct ip_fw_chain *ch, struct ip_fw *rule, - uint16_t eaction_id, uint16_t default_id, uint16_t instance_id) + uint32_t eaction_id, uint32_t default_id, uint32_t instance_id) { ipfw_insn *cmd, *icmd; int l; @@ -388,22 +395,23 @@ ipfw_reset_eaction(struct ip_fw_chain *ch, struct ip_fw *rule, */ cmd = ipfw_get_action(rule); if (cmd->opcode != O_EXTERNAL_ACTION || - cmd->arg1 != eaction_id) + insntod(cmd, kidx)->kidx != eaction_id) return (0); /* * Check if there is O_EXTERNAL_INSTANCE opcode, we need * to truncate the rule length. * - * NOTE: F_LEN(cmd) must be 1 for O_EXTERNAL_ACTION opcode, + * NOTE: F_LEN(cmd) must be 2 for O_EXTERNAL_ACTION opcode, * and rule length should be enough to keep O_EXTERNAL_INSTANCE - * opcode, thus we do check for l > 1. + * opcode, thus we do check for l > 2. */ l = rule->cmd + rule->cmd_len - cmd; - if (l > 1) { - MPASS(F_LEN(cmd) == 1); - icmd = cmd + 1; + if (l > 2) { + MPASS(F_LEN(cmd) == 2); + icmd = cmd + F_LEN(cmd); if (icmd->opcode == O_EXTERNAL_INSTANCE && - instance_id != 0 && icmd->arg1 != instance_id) + instance_id != 0 && + insntod(icmd, kidx)->kidx != instance_id) return (0); /* * Since named_object related to this instance will be @@ -411,7 +419,7 @@ ipfw_reset_eaction(struct ip_fw_chain *ch, struct ip_fw *rule, * the rest of cmd chain just after O_EXTERNAL_ACTION * opcode. */ - EACTION_DEBUG("truncate rule %d: len %u -> %u", + EACTION_DEBUG("truncate rule %u: len %u -> %u", rule->rulenum, rule->cmd_len, rule->cmd_len - F_LEN(icmd)); rule->cmd_len -= F_LEN(icmd); @@ -419,7 +427,7 @@ ipfw_reset_eaction(struct ip_fw_chain *ch, struct ip_fw *rule, (uint32_t *)rule->cmd) == rule->cmd_len); } - cmd->arg1 = default_id; /* Set to default id */ + insntod(cmd, kidx)->kidx = default_id; /* Set to default id */ /* * Return 1 when reset successfully happened. */ @@ -432,8 +440,8 @@ ipfw_reset_eaction(struct ip_fw_chain *ch, struct ip_fw *rule, * eaction has instance with id == kidx. */ int -ipfw_reset_eaction_instance(struct ip_fw_chain *ch, uint16_t eaction_id, - uint16_t kidx) +ipfw_reset_eaction_instance(struct ip_fw_chain *ch, uint32_t eaction_id, + uint32_t kidx) { struct named_object *no; @@ -451,5 +459,6 @@ ipfw_run_eaction(struct ip_fw_chain *ch, struct ip_fw_args *args, ipfw_insn *cmd, int *done) { + MPASS(F_LEN(cmd) == 2); return (EACTION_OBJ(ch, cmd)->handler(ch, args, cmd, done)); } diff --git a/sys/netpfil/ipfw/ip_fw_iface.c b/sys/netpfil/ipfw/ip_fw_iface.c index beb3b9115aa..6f64560ae5a 100644 --- a/sys/netpfil/ipfw/ip_fw_iface.c +++ b/sys/netpfil/ipfw/ip_fw_iface.c @@ -71,7 +71,7 @@ static int list_ifaces(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd); static struct ipfw_sopt_handler scodes[] = { - { IP_FW_XIFLIST, 0, HDIR_GET, list_ifaces }, + { IP_FW_XIFLIST, IP_FW3_OPVER, HDIR_GET, list_ifaces }, }; /* @@ -488,7 +488,7 @@ export_iface_internal(struct namedobj_instance *ii, struct named_object *no, /* * Lists all interface currently tracked by ipfw. - * Data layout (v0)(current): + * Data layout (v1)(current): * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size * Reply: [ ipfw_obj_lheader ipfw_iface_info x N ] * diff --git a/sys/netpfil/ipfw/ip_fw_nat.c b/sys/netpfil/ipfw/ip_fw_nat.c index 2889403de68..0c574e55f4a 100644 --- a/sys/netpfil/ipfw/ip_fw_nat.c +++ b/sys/netpfil/ipfw/ip_fw_nat.c @@ -874,11 +874,11 @@ nat44_get_log(struct ip_fw_chain *chain, ip_fw3_opheader *op3, } static struct ipfw_sopt_handler scodes[] = { - { IP_FW_NAT44_XCONFIG, 0, HDIR_SET, nat44_cfg }, - { IP_FW_NAT44_DESTROY, 0, HDIR_SET, nat44_destroy }, - { IP_FW_NAT44_XGETCONFIG, 0, HDIR_GET, nat44_get_cfg }, - { IP_FW_NAT44_LIST_NAT, 0, HDIR_GET, nat44_list_nat }, - { IP_FW_NAT44_XGETLOG, 0, HDIR_GET, nat44_get_log }, + { IP_FW_NAT44_XCONFIG, IP_FW3_OPVER, HDIR_SET, nat44_cfg }, + { IP_FW_NAT44_DESTROY, IP_FW3_OPVER, HDIR_SET, nat44_destroy }, + { IP_FW_NAT44_XGETCONFIG, IP_FW3_OPVER, HDIR_GET, nat44_get_cfg }, + { IP_FW_NAT44_LIST_NAT, IP_FW3_OPVER, HDIR_GET, nat44_list_nat }, + { IP_FW_NAT44_XGETLOG, IP_FW3_OPVER, HDIR_GET, nat44_get_log }, }; diff --git a/sys/netpfil/ipfw/ip_fw_private.h b/sys/netpfil/ipfw/ip_fw_private.h index 0c5986f0765..f45df8f9927 100644 --- a/sys/netpfil/ipfw/ip_fw_private.h +++ b/sys/netpfil/ipfw/ip_fw_private.h @@ -173,6 +173,7 @@ void ipfw_nat_destroy(void); /* In ip_fw_log.c */ struct ip; +struct ip_fw; struct ip_fw_chain; void ipfw_bpf_init(int); @@ -206,14 +207,14 @@ enum { /* result for matching dynamic rules */ */ #define DYN_LOOKUP_NEEDED(p, cmd) \ ((p)->direction == MATCH_UNKNOWN || \ - ((p)->kidx != 0 && (p)->kidx != (cmd)->arg1)) + ((p)->kidx != 0 && (p)->kidx != insntod((cmd), kidx)->kidx)) #define DYN_INFO_INIT(p) do { \ (p)->direction = MATCH_UNKNOWN; \ (p)->kidx = 0; \ } while (0) struct ipfw_dyn_info { - uint16_t direction; /* match direction */ - uint16_t kidx; /* state name kidx */ + uint32_t direction; /* match direction */ + uint32_t kidx; /* state name kidx */ uint32_t hashval; /* hash value */ uint32_t version; /* bucket version */ uint32_t f_pos; @@ -283,9 +284,10 @@ struct tables_config; struct ip_fw { uint16_t act_ofs; /* offset of action in 32-bit units */ uint16_t cmd_len; /* # of 32-bit words in cmd */ - uint16_t rulenum; /* rule number */ + uint32_t rulenum; /* rule number */ uint8_t set; /* rule set (0..31) */ uint8_t flags; /* currently unused */ + uint16_t _pad; counter_u64_t cntr; /* Pointer to rule counters */ uint32_t timestamp; /* tv_sec of last match */ uint32_t id; /* rule id */ @@ -307,18 +309,17 @@ struct ip_fw_chain { int n_rules; /* number of static rules */ void *tablestate; /* runtime table info */ void *valuestate; /* runtime table value info */ - int *idxmap; /* skipto array of rules */ + uint32_t *idxmap; /* skipto array of rules */ void **srvstate; /* runtime service mappings */ #if defined( __linux__ ) || defined( _WIN32 ) spinlock_t rwmtx; #endif - int static_len; /* total len of static rules (v0) */ uint32_t gencnt; /* NAT generation count */ LIST_HEAD(nat_list, cfg_nat) nat; /* list of nat entries */ struct ip_fw *default_rule; struct tables_config *tblcfg; /* tables module data */ void *ifcfg; /* interface module data */ - int *idxmap_back; /* standby skipto array of rules */ + uint32_t *idxmap_back; /* standby skipto array of rules */ struct namedobj_instance *srvmap; /* cfg name->number mappings */ #if defined( __linux__ ) || defined( _WIN32 ) spinlock_t uh_lock; @@ -355,8 +356,7 @@ struct named_object { uint16_t etlv; /* Export TLV id */ uint8_t subtype;/* object subtype within class */ uint8_t set; /* set object belongs to */ - uint16_t kidx; /* object kernel index */ - uint16_t spare; + uint32_t kidx; /* object kernel index */ uint32_t ocnt; /* object counter for internal use */ uint32_t refcnt; /* number of references */ }; @@ -482,8 +482,8 @@ struct ipfw_ifc { #define IPFW_UH_WUNLOCK(p) rw_wunlock(&(p)->uh_lock) struct obj_idx { - uint16_t uidx; /* internal index supplied by userland */ - uint16_t kidx; /* kernel object index */ + uint32_t uidx; /* internal index supplied by userland */ + uint32_t kidx; /* kernel object index */ uint16_t off; /* tlv offset from rule end in 4-byte words */ uint8_t spare; uint8_t type; /* object type within its category */ @@ -553,17 +553,17 @@ struct ip_fw_bcounter0 { */ /* Default and maximum number of ipfw tables/objects. */ -#define IPFW_TABLES_MAX 65536 +#define IPFW_TABLES_MAX 131072 #define IPFW_TABLES_DEFAULT 128 #define IPFW_OBJECTS_MAX 65536 -#define IPFW_OBJECTS_DEFAULT 2048 +#define IPFW_OBJECTS_DEFAULT 4096 #define CHAIN_TO_SRV(ch) ((ch)->srvmap) #define SRV_OBJECT(ch, idx) ((ch)->srvstate[(idx)]) struct tid_info { uint32_t set; /* table set */ - uint16_t uidx; /* table index */ + uint32_t uidx; /* table index */ uint8_t type; /* table type */ uint8_t atype; uint8_t spare; @@ -576,11 +576,11 @@ struct tid_info { * If true, returns its index and type. * Returns 0 if match is found, 1 overwise. */ -typedef int (ipfw_obj_rw_cl)(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype); +typedef int (ipfw_obj_rw_cl)(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype); /* * Updater callback. Sets kernel object reference index to @puidx */ -typedef void (ipfw_obj_rw_upd)(ipfw_insn *cmd, uint16_t puidx); +typedef void (ipfw_obj_rw_upd)(ipfw_insn *cmd0, uint32_t puidx); /* * Finder callback. Tries to find named object by name (specified via @ti). * Stores found named object pointer in @pno. @@ -596,7 +596,7 @@ typedef int (ipfw_obj_fname_cb)(struct ip_fw_chain *ch, * Returns pointer to named object or NULL. */ typedef struct named_object *(ipfw_obj_fidx_cb)(struct ip_fw_chain *ch, - uint16_t kidx); + uint32_t kidx); /* * Object creator callback. Tries to create object specified by @ti. * Stores newly-allocated object index in @pkidx. @@ -604,7 +604,7 @@ typedef struct named_object *(ipfw_obj_fidx_cb)(struct ip_fw_chain *ch, * Returns 0 on success. */ typedef int (ipfw_obj_create_cb)(struct ip_fw_chain *ch, struct tid_info *ti, - uint16_t *pkidx); + uint32_t *pkidx); /* * Object destroy callback. Intended to free resources allocated by * create_object callback. @@ -624,7 +624,7 @@ enum ipfw_sets_cmd { SWAP_ALL = 0, TEST_ALL, MOVE_ALL, COUNT_ONE, TEST_ONE, MOVE_ONE }; typedef int (ipfw_obj_sets_cb)(struct ip_fw_chain *ch, - uint16_t set, uint8_t new_set, enum ipfw_sets_cmd cmd); + uint32_t set, uint8_t new_set, enum ipfw_sets_cmd cmd); struct opcode_obj_rewrite { @@ -660,7 +660,23 @@ void ipfw_iface_unref(struct ip_fw_chain *ch, struct ipfw_ifc *ic); void ipfw_iface_add_notify(struct ip_fw_chain *ch, struct ipfw_ifc *ic); void ipfw_iface_del_notify(struct ip_fw_chain *ch, struct ipfw_ifc *ic); +enum ipfw_opcheck_result { + SUCCESS = 0, + FAILED, + BAD_SIZE, + CHECK_ACTION, +}; +typedef enum ipfw_opcheck_result (*ipfw_check_opcode_t)(ipfw_insn **, + int *, struct rule_check_info *); + +/* In ip_fw_compat.c */ +int ipfw_ctl(struct sockopt *sopt); +void ipfw_register_compat(ipfw_check_opcode_t); +void ipfw_unregister_compat(void); + /* In ip_fw_sockopt.c */ +enum ipfw_opcheck_result ipfw_check_opcode(ipfw_insn **, int *, + struct rule_check_info *); void ipfw_init_skipto_cache(struct ip_fw_chain *chain); void ipfw_destroy_skipto_cache(struct ip_fw_chain *chain); int ipfw_find_rule(struct ip_fw_chain *chain, uint32_t key, uint32_t id); @@ -672,11 +688,15 @@ void ipfw_reap_add(struct ip_fw_chain *chain, struct ip_fw **head, void ipfw_reap_rules(struct ip_fw *head); void ipfw_init_counters(void); void ipfw_destroy_counters(void); +int ipfw_commit_rules(struct ip_fw_chain *chain, struct rule_check_info *rci, + int count); struct ip_fw *ipfw_alloc_rule(struct ip_fw_chain *chain, size_t rulesize); void ipfw_free_rule(struct ip_fw *rule); int ipfw_match_range(struct ip_fw *rule, ipfw_range_tlv *rt); -int ipfw_mark_object_kidx(uint32_t *bmask, uint16_t etlv, uint16_t kidx); +int ipfw_mark_object_kidx(uint32_t *bmask, uint16_t etlv, uint32_t kidx); ipfw_insn *ipfw_get_action(struct ip_fw *); +int ipfw_check_rule(struct ip_fw_rule *rule, size_t size, + struct rule_check_info *ci); typedef int (sopt_handler_f)(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd); @@ -729,7 +749,7 @@ struct named_object *ipfw_objhash_lookup_name(struct namedobj_instance *ni, struct named_object *ipfw_objhash_lookup_name_type(struct namedobj_instance *ni, uint32_t set, uint32_t type, const char *name); struct named_object *ipfw_objhash_lookup_kidx(struct namedobj_instance *ni, - uint16_t idx); + uint32_t idx); int ipfw_objhash_same_name(struct namedobj_instance *ni, struct named_object *a, struct named_object *b); void ipfw_objhash_add(struct namedobj_instance *ni, struct named_object *no); @@ -740,14 +760,14 @@ int ipfw_objhash_foreach(struct namedobj_instance *ni, objhash_cb_t *f, void *arg); int ipfw_objhash_foreach_type(struct namedobj_instance *ni, objhash_cb_t *f, void *arg, uint16_t type); -int ipfw_objhash_free_idx(struct namedobj_instance *ni, uint16_t idx); -int ipfw_objhash_alloc_idx(void *n, uint16_t *pidx); +int ipfw_objhash_free_idx(struct namedobj_instance *ni, uint32_t idx); +int ipfw_objhash_alloc_idx(void *n, uint32_t *pidx); void ipfw_objhash_set_funcs(struct namedobj_instance *ni, objhash_hash_f *hash_f, objhash_cmp_f *cmp_f); int ipfw_objhash_find_type(struct namedobj_instance *ni, struct tid_info *ti, uint32_t etlv, struct named_object **pno); void ipfw_export_obj_ntlv(struct named_object *no, ipfw_obj_ntlv *ntlv); -ipfw_obj_ntlv *ipfw_find_name_tlv_type(void *tlvs, int len, uint16_t uidx, +ipfw_obj_ntlv *ipfw_find_name_tlv_type(void *tlvs, int len, uint32_t uidx, uint32_t etlv); void ipfw_init_obj_rewriter(void); void ipfw_destroy_obj_rewriter(void); @@ -756,13 +776,13 @@ int ipfw_del_obj_rewriter(struct opcode_obj_rewrite *rw, size_t count); int create_objects_compat(struct ip_fw_chain *ch, ipfw_insn *cmd, struct obj_idx *oib, struct obj_idx *pidx, struct tid_info *ti); -void update_opcode_kidx(ipfw_insn *cmd, uint16_t idx); -int classify_opcode_kidx(ipfw_insn *cmd, uint16_t *puidx); +void update_opcode_kidx(ipfw_insn *cmd, uint32_t idx); +int classify_opcode_kidx(ipfw_insn *cmd, uint32_t *puidx); void ipfw_init_srv(struct ip_fw_chain *ch); void ipfw_destroy_srv(struct ip_fw_chain *ch); int ipfw_check_object_name_generic(const char *name); int ipfw_obj_manage_sets(struct namedobj_instance *ni, uint16_t type, - uint16_t set, uint8_t new_set, enum ipfw_sets_cmd cmd); + uint32_t set, uint8_t new_set, enum ipfw_sets_cmd cmd); /* In ip_fw_eaction.c */ typedef int (ipfw_eaction_t)(struct ip_fw_chain *ch, struct ip_fw_args *args, @@ -770,15 +790,15 @@ typedef int (ipfw_eaction_t)(struct ip_fw_chain *ch, struct ip_fw_args *args, int ipfw_eaction_init(struct ip_fw_chain *ch, int first); void ipfw_eaction_uninit(struct ip_fw_chain *ch, int last); -uint16_t ipfw_add_eaction(struct ip_fw_chain *ch, ipfw_eaction_t handler, +uint32_t ipfw_add_eaction(struct ip_fw_chain *ch, ipfw_eaction_t handler, const char *name); -int ipfw_del_eaction(struct ip_fw_chain *ch, uint16_t eaction_id); +int ipfw_del_eaction(struct ip_fw_chain *ch, uint32_t eaction_id); int ipfw_run_eaction(struct ip_fw_chain *ch, struct ip_fw_args *args, ipfw_insn *cmd, int *done); int ipfw_reset_eaction(struct ip_fw_chain *ch, struct ip_fw *rule, - uint16_t eaction_id, uint16_t default_id, uint16_t instance_id); -int ipfw_reset_eaction_instance(struct ip_fw_chain *ch, uint16_t eaction_id, - uint16_t instance_id); + uint32_t eaction_id, uint32_t default_id, uint32_t instance_id); +int ipfw_reset_eaction_instance(struct ip_fw_chain *ch, uint32_t eaction_id, + uint32_t instance_id); /* In ip_fw_table.c */ struct table_info; @@ -786,12 +806,12 @@ struct table_info; typedef int (table_lookup_t)(struct table_info *ti, void *key, uint32_t keylen, uint32_t *val); -int ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen, +int ipfw_lookup_table(struct ip_fw_chain *ch, uint32_t tbl, uint16_t plen, void *paddr, uint32_t *val); struct named_object *ipfw_objhash_lookup_table_kidx(struct ip_fw_chain *ch, - uint16_t kidx); -int ipfw_ref_table(struct ip_fw_chain *ch, ipfw_obj_ntlv *ntlv, uint16_t *kidx); -void ipfw_unref_table(struct ip_fw_chain *ch, uint16_t kidx); + uint32_t kidx); +int ipfw_ref_table(struct ip_fw_chain *ch, ipfw_obj_ntlv *ntlv, uint32_t *kidx); +void ipfw_unref_table(struct ip_fw_chain *ch, uint32_t kidx); int ipfw_init_tables(struct ip_fw_chain *ch, int first); int ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables); int ipfw_switch_tables_namespace(struct ip_fw_chain *ch, unsigned int nsets); diff --git a/sys/netpfil/ipfw/ip_fw_sockopt.c b/sys/netpfil/ipfw/ip_fw_sockopt.c index 5facfba9de9..4b67fe2f2b1 100644 --- a/sys/netpfil/ipfw/ip_fw_sockopt.c +++ b/sys/netpfil/ipfw/ip_fw_sockopt.c @@ -86,13 +86,19 @@ SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, select_counters, CTLFLAG_RW, SYSEND #endif /* SYSCTL_NODE */ -static int ipfw_ctl(struct sockopt *sopt); +static enum ipfw_opcheck_result +check_opcode_compat_nop(ipfw_insn **pcmd, int *plen, + struct rule_check_info *ci) +{ + + /* Compatibility code is not registered */ + return (FAILED); +} + +static ipfw_check_opcode_t check_opcode_f = check_opcode_compat_nop; + static int check_ipfw_rule_body(ipfw_insn *cmd, int cmd_len, struct rule_check_info *ci); -static int check_ipfw_rule1(struct ip_fw_rule *rule, int size, - struct rule_check_info *ci); -static int check_ipfw_rule0(struct ip_fw_rule0 *rule, int size, - struct rule_check_info *ci); static int rewrite_rule_uidx(struct ip_fw_chain *chain, struct rule_check_info *ci); @@ -106,11 +112,11 @@ struct namedobj_instance { u_long *idx_mask; /* used items bitmask */ uint32_t max_blocks; /* number of "long" blocks in bitmask */ uint32_t count; /* number of items */ - uint16_t free_off[IPFW_MAX_SETS]; /* first possible free offset */ + uint16_t free_off[IPFW_MAX_SETS]; /* first possible free offset */ objhash_hash_f *hash_f; objhash_cmp_f *cmp_f; }; -#define BLOCK_ITEMS (8 * sizeof(u_long)) /* Number of items for ffsl() */ +#define BLOCK_ITEMS (8 * sizeof(u_long)) /* Number of items for ffsl() */ static uint32_t objhash_hash_name(struct namedobj_instance *ni, const void *key, uint32_t kopt); @@ -120,23 +126,6 @@ static int objhash_cmp_name(struct named_object *no, const void *name, MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's"); -static int dump_config(struct ip_fw_chain *chain, ip_fw3_opheader *op3, - struct sockopt_data *sd); -static int add_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3, - struct sockopt_data *sd); -static int del_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3, - struct sockopt_data *sd); -static int clear_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3, - struct sockopt_data *sd); -static int move_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3, - struct sockopt_data *sd); -static int manage_sets(struct ip_fw_chain *chain, ip_fw3_opheader *op3, - struct sockopt_data *sd); -static int dump_soptcodes(struct ip_fw_chain *chain, ip_fw3_opheader *op3, - struct sockopt_data *sd); -static int dump_srvobjects(struct ip_fw_chain *chain, ip_fw3_opheader *op3, - struct sockopt_data *sd); - /* ctl3 handler data */ struct mtx ctl3_lock; #define CTL3_LOCK_INIT() mtx_init(&ctl3_lock, "ctl3_lock", NULL, MTX_DEF) @@ -152,24 +141,25 @@ static uint64_t ctl3_refct, ctl3_gencnt; static int ipfw_flush_sopt_data(struct sockopt_data *sd); -static struct ipfw_sopt_handler scodes[] = { - { IP_FW_XGET, 0, HDIR_GET, dump_config }, - { IP_FW_XADD, 0, HDIR_BOTH, add_rules }, - { IP_FW_XDEL, 0, HDIR_BOTH, del_rules }, - { IP_FW_XZERO, 0, HDIR_SET, clear_rules }, - { IP_FW_XRESETLOG, 0, HDIR_SET, clear_rules }, - { IP_FW_XMOVE, 0, HDIR_SET, move_rules }, - { IP_FW_SET_SWAP, 0, HDIR_SET, manage_sets }, - { IP_FW_SET_MOVE, 0, HDIR_SET, manage_sets }, - { IP_FW_SET_ENABLE, 0, HDIR_SET, manage_sets }, - { IP_FW_DUMP_SOPTCODES, 0, HDIR_GET, dump_soptcodes }, - { IP_FW_DUMP_SRVOBJECTS,0, HDIR_GET, dump_srvobjects }, +static sopt_handler_f dump_config, add_rules, del_rules, clear_rules, + move_rules, manage_sets, dump_soptcodes, dump_srvobjects; + +static struct ipfw_sopt_handler scodes[] = { + { IP_FW_XGET, IP_FW3_OPVER, HDIR_GET, dump_config }, + { IP_FW_XADD, IP_FW3_OPVER, HDIR_BOTH, add_rules }, + { IP_FW_XDEL, IP_FW3_OPVER, HDIR_BOTH, del_rules }, + { IP_FW_XZERO, IP_FW3_OPVER, HDIR_SET, clear_rules }, + { IP_FW_XRESETLOG, IP_FW3_OPVER, HDIR_SET, clear_rules }, + { IP_FW_XMOVE, IP_FW3_OPVER, HDIR_SET, move_rules }, + { IP_FW_SET_SWAP, IP_FW3_OPVER, HDIR_SET, manage_sets }, + { IP_FW_SET_MOVE, IP_FW3_OPVER, HDIR_SET, manage_sets }, + { IP_FW_SET_ENABLE, IP_FW3_OPVER, HDIR_SET, manage_sets }, + { IP_FW_DUMP_SOPTCODES, IP_FW3_OPVER, HDIR_GET, dump_soptcodes }, + { IP_FW_DUMP_SRVOBJECTS,IP_FW3_OPVER, HDIR_GET, dump_srvobjects }, }; -static int -set_legacy_obj_kidx(struct ip_fw_chain *ch, struct ip_fw_rule0 *rule); static struct opcode_obj_rewrite *find_op_rw(ipfw_insn *cmd, - uint16_t *puidx, uint8_t *ptype); + uint32_t *puidx, uint8_t *ptype); static int ref_rule_objects(struct ip_fw_chain *ch, struct ip_fw *rule, struct rule_check_info *ci, struct obj_idx *oib, struct tid_info *ti); static int ref_opcode_object(struct ip_fw_chain *ch, ipfw_insn *cmd, @@ -205,7 +195,7 @@ ipfw_init_counters() void ipfw_destroy_counters() { - + uma_zdestroy(V_ipfw_cntr_zone); } @@ -269,7 +259,7 @@ ipfw_find_rule(struct ip_fw_chain *chain, uint32_t key, uint32_t id) static void update_skipto_cache(struct ip_fw_chain *chain, struct ip_fw **map) { - int *smap, rulenum; + uint32_t *smap, rulenum; int i, mi; IPFW_UH_WLOCK_ASSERT(chain); @@ -281,10 +271,10 @@ update_skipto_cache(struct ip_fw_chain *chain, struct ip_fw **map) if (smap == NULL) return; - for (i = 0; i < 65536; i++) { + for (i = 0; i <= IPFW_DEFAULT_RULE; i++) { smap[i] = mi; /* Use the same rule index until i < rulenum */ - if (i != rulenum || i == 65535) + if (i != rulenum || i == IPFW_DEFAULT_RULE) continue; /* Find next rule with num > i */ rulenum = map[++mi]->rulenum; @@ -299,7 +289,7 @@ update_skipto_cache(struct ip_fw_chain *chain, struct ip_fw **map) static void swap_skipto_cache(struct ip_fw_chain *chain) { - int *map; + uint32_t *map; IPFW_UH_WLOCK_ASSERT(chain); IPFW_WLOCK_ASSERT(chain); @@ -315,12 +305,12 @@ swap_skipto_cache(struct ip_fw_chain *chain) void ipfw_init_skipto_cache(struct ip_fw_chain *chain) { - int *idxmap, *idxmap_back; + uint32_t *idxmap, *idxmap_back; - idxmap = malloc(65536 * sizeof(uint32_t *), M_IPFW, - M_WAITOK | M_ZERO); - idxmap_back = malloc(65536 * sizeof(uint32_t *), M_IPFW, - M_WAITOK | M_ZERO); + idxmap = malloc((IPFW_DEFAULT_RULE + 1) * sizeof(uint32_t *), + M_IPFW, M_WAITOK | M_ZERO); + idxmap_back = malloc((IPFW_DEFAULT_RULE + 1) * sizeof(uint32_t *), + M_IPFW, M_WAITOK | M_ZERO); /* * Note we may be called at any time after initialization, @@ -430,51 +420,6 @@ export_cntr1_base(struct ip_fw *krule, struct ip_fw_bcounter *cntr) } } -static void -export_cntr0_base(struct ip_fw *krule, struct ip_fw_bcounter0 *cntr) -{ - struct timeval boottime; - - if (krule->cntr != NULL) { - cntr->pcnt = counter_u64_fetch(krule->cntr); - cntr->bcnt = counter_u64_fetch(krule->cntr + - ((select_counters == 1) ? 1: 2)); - cntr->timestamp = krule->timestamp; - } - if (cntr->timestamp > 0) { - getboottime(&boottime); - cntr->timestamp += boottime.tv_sec; - } -} - -/* - * Copies rule @urule from v1 userland format (current). - * to kernel @krule. - * Assume @krule is zeroed. - */ -static void -import_rule1(struct rule_check_info *ci) -{ - struct ip_fw_rule *urule; - struct ip_fw *krule; - - urule = (struct ip_fw_rule *)ci->urule; - krule = (struct ip_fw *)ci->krule; - - /* copy header */ - krule->act_ofs = urule->act_ofs; - krule->cmd_len = urule->cmd_len; - krule->rulenum = urule->rulenum; - krule->set = urule->set; - krule->flags = urule->flags; - - /* Save rulenum offset */ - ci->urule_numoff = offsetof(struct ip_fw_rule, rulenum); - - /* Copy opcodes */ - memcpy(krule->cmd, urule->cmd, krule->cmd_len * sizeof(uint32_t)); -} - /* * Export rule into v1 format (Current). * Layout: @@ -516,193 +461,17 @@ export_rule1(struct ip_fw *krule, caddr_t data, int len, int rcntrs) memcpy(urule->cmd, krule->cmd, krule->cmd_len * sizeof(uint32_t)); } - -/* - * Copies rule @urule from FreeBSD8 userland format (v0) - * to kernel @krule. - * Assume @krule is zeroed. - */ -static void -import_rule0(struct rule_check_info *ci) -{ - struct ip_fw_rule0 *urule; - struct ip_fw *krule; - int cmdlen, l; - ipfw_insn *cmd; - ipfw_insn_limit *lcmd; - ipfw_insn_if *cmdif; - - urule = (struct ip_fw_rule0 *)ci->urule; - krule = (struct ip_fw *)ci->krule; - - /* copy header */ - krule->act_ofs = urule->act_ofs; - krule->cmd_len = urule->cmd_len; - krule->rulenum = urule->rulenum; - krule->set = urule->set; - if ((urule->_pad & 1) != 0) - krule->flags |= IPFW_RULE_NOOPT; - - /* Save rulenum offset */ - ci->urule_numoff = offsetof(struct ip_fw_rule0, rulenum); - - /* Copy opcodes */ - memcpy(krule->cmd, urule->cmd, krule->cmd_len * sizeof(uint32_t)); - - /* - * Alter opcodes: - * 1) convert tablearg value from 65535 to 0 - * 2) Add high bit to O_SETFIB/O_SETDSCP values (to make room - * for targ). - * 3) convert table number in iface opcodes to u16 - * 4) convert old `nat global` into new 65535 - */ - l = krule->cmd_len; - cmd = krule->cmd; - cmdlen = 0; - - for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { - cmdlen = F_LEN(cmd); - - switch (cmd->opcode) { - /* Opcodes supporting tablearg */ - case O_TAG: - case O_TAGGED: - case O_PIPE: - case O_QUEUE: - case O_DIVERT: - case O_TEE: - case O_SKIPTO: - case O_CALLRETURN: - case O_NETGRAPH: - case O_NGTEE: - case O_NAT: - if (cmd->arg1 == IP_FW_TABLEARG) - cmd->arg1 = IP_FW_TARG; - else if (cmd->arg1 == 0) - cmd->arg1 = IP_FW_NAT44_GLOBAL; - break; - case O_SETFIB: - case O_SETDSCP: - if (cmd->arg1 == IP_FW_TABLEARG) - cmd->arg1 = IP_FW_TARG; - else - cmd->arg1 |= 0x8000; - break; - case O_LIMIT: - lcmd = (ipfw_insn_limit *)cmd; - if (lcmd->conn_limit == IP_FW_TABLEARG) - lcmd->conn_limit = IP_FW_TARG; - break; - /* Interface tables */ - case O_XMIT: - case O_RECV: - case O_VIA: - /* Interface table, possibly */ - cmdif = (ipfw_insn_if *)cmd; - if (cmdif->name[0] != '\1') - break; - - cmdif->p.kidx = (uint16_t)cmdif->p.glob; - break; - } - } -} - -/* - * Copies rule @krule from kernel to FreeBSD8 userland format (v0) - */ -static void -export_rule0(struct ip_fw *krule, struct ip_fw_rule0 *urule, int len) -{ - int cmdlen, l; - ipfw_insn *cmd; - ipfw_insn_limit *lcmd; - ipfw_insn_if *cmdif; - - /* copy header */ - memset(urule, 0, len); - urule->act_ofs = krule->act_ofs; - urule->cmd_len = krule->cmd_len; - urule->rulenum = krule->rulenum; - urule->set = krule->set; - if ((krule->flags & IPFW_RULE_NOOPT) != 0) - urule->_pad |= 1; - - /* Copy opcodes */ - memcpy(urule->cmd, krule->cmd, krule->cmd_len * sizeof(uint32_t)); - - /* Export counters */ - export_cntr0_base(krule, (struct ip_fw_bcounter0 *)&urule->pcnt); - - /* - * Alter opcodes: - * 1) convert tablearg value from 0 to 65535 - * 2) Remove highest bit from O_SETFIB/O_SETDSCP values. - * 3) convert table number in iface opcodes to int - */ - l = urule->cmd_len; - cmd = urule->cmd; - cmdlen = 0; - - for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { - cmdlen = F_LEN(cmd); - - switch (cmd->opcode) { - /* Opcodes supporting tablearg */ - case O_TAG: - case O_TAGGED: - case O_PIPE: - case O_QUEUE: - case O_DIVERT: - case O_TEE: - case O_SKIPTO: - case O_CALLRETURN: - case O_NETGRAPH: - case O_NGTEE: - case O_NAT: - if (cmd->arg1 == IP_FW_TARG) - cmd->arg1 = IP_FW_TABLEARG; - else if (cmd->arg1 == IP_FW_NAT44_GLOBAL) - cmd->arg1 = 0; - break; - case O_SETFIB: - case O_SETDSCP: - if (cmd->arg1 == IP_FW_TARG) - cmd->arg1 = IP_FW_TABLEARG; - else - cmd->arg1 &= ~0x8000; - break; - case O_LIMIT: - lcmd = (ipfw_insn_limit *)cmd; - if (lcmd->conn_limit == IP_FW_TARG) - lcmd->conn_limit = IP_FW_TABLEARG; - break; - /* Interface tables */ - case O_XMIT: - case O_RECV: - case O_VIA: - /* Interface table, possibly */ - cmdif = (ipfw_insn_if *)cmd; - if (cmdif->name[0] != '\1') - break; - - cmdif->p.glob = cmdif->p.kidx; - break; - } - } -} - /* * Add new rule(s) to the list possibly creating rule number for each. * Update the rule_number in the input struct so the caller knows it as well. * Must be called without IPFW_UH held */ -static int -commit_rules(struct ip_fw_chain *chain, struct rule_check_info *rci, int count) +int +ipfw_commit_rules(struct ip_fw_chain *chain, struct rule_check_info *rci, + int count) { int error, i, insert_before, tcount; - uint16_t rulenum, *pnum; + uint32_t rulenum; struct rule_check_info *ci; struct ip_fw *krule; struct ip_fw **map; /* the new array of pointers */ @@ -796,14 +565,13 @@ commit_rules(struct ip_fw_chain *chain, struct rule_check_info *rci, int count) rulenum += V_autoinc_step; krule->rulenum = rulenum; /* Save number to userland rule */ - pnum = (uint16_t *)((caddr_t)ci->urule + ci->urule_numoff); - *pnum = rulenum; + memcpy((char *)ci->urule + ci->urule_numoff, &rulenum, + sizeof(rulenum)); } krule->id = chain->id + 1; update_skipto_cache(chain, map); map = swap_map(chain, map, chain->n_rules + 1); - chain->static_len += RULEUSIZE0(krule); IPFW_UH_WUNLOCK(chain); if (map) free(map, M_IPFW); @@ -828,7 +596,6 @@ ipfw_add_protected_rule(struct ip_fw_chain *chain, struct ip_fw *rule, rule->id = chain->id + 1; /* We add rule in the end of chain, no need to update skipto cache */ map = swap_map(chain, map, chain->n_rules + 1); - chain->static_len += RULEUSIZE0(rule); IPFW_UH_WUNLOCK(chain); free(map, M_IPFW); return (0); @@ -909,7 +676,7 @@ ipfw_match_range(struct ip_fw *rule, ipfw_range_tlv *rt) } struct manage_sets_args { - uint16_t set; + uint32_t set; uint8_t new_set; }; @@ -959,7 +726,7 @@ test_sets_cb(struct namedobj_instance *ni, struct named_object *no, */ int ipfw_obj_manage_sets(struct namedobj_instance *ni, uint16_t type, - uint16_t set, uint8_t new_set, enum ipfw_sets_cmd cmd) + uint32_t set, uint8_t new_set, enum ipfw_sets_cmd cmd) { struct manage_sets_args args; struct named_object *no; @@ -1096,7 +863,6 @@ delete_range(struct ip_fw_chain *chain, ipfw_range_tlv *rt, int *ndel) rule = map[i]; if (ipfw_match_range(rule, rt) == 0) continue; - chain->static_len -= RULEUSIZE0(rule); ipfw_reap_add(chain, &reap, rule); } IPFW_UH_WUNLOCK(chain); @@ -1114,8 +880,8 @@ move_objects(struct ip_fw_chain *ch, ipfw_range_tlv *rt) struct opcode_obj_rewrite *rw; struct ip_fw *rule; ipfw_insn *cmd; + uint32_t kidx; int cmdlen, i, l, c; - uint16_t kidx; IPFW_UH_WLOCK_ASSERT(ch); @@ -1528,174 +1294,9 @@ manage_sets(struct ip_fw_chain *chain, ip_fw3_opheader *op3, return (ret); } -/** - * Remove all rules with given number, or do set manipulation. - * Assumes chain != NULL && *chain != NULL. - * - * The argument is an uint32_t. The low 16 bit are the rule or set number; - * the next 8 bits are the new set; the top 8 bits indicate the command: - * - * 0 delete rules numbered "rulenum" - * 1 delete rules in set "rulenum" - * 2 move rules "rulenum" to set "new_set" - * 3 move rules from set "rulenum" to set "new_set" - * 4 swap sets "rulenum" and "new_set" - * 5 delete rules "rulenum" and set "new_set" - */ -static int -del_entry(struct ip_fw_chain *chain, uint32_t arg) -{ - uint32_t num; /* rule number or old_set */ - uint8_t cmd, new_set; - int do_del, ndel; - int error = 0; - ipfw_range_tlv rt; - - num = arg & 0xffff; - cmd = (arg >> 24) & 0xff; - new_set = (arg >> 16) & 0xff; - - if (cmd > 5 || new_set > RESVD_SET) - return EINVAL; - if (cmd == 0 || cmd == 2 || cmd == 5) { - if (num >= IPFW_DEFAULT_RULE) - return EINVAL; - } else { - if (num > RESVD_SET) /* old_set */ - return EINVAL; - } - - /* Convert old requests into new representation */ - memset(&rt, 0, sizeof(rt)); - rt.start_rule = num; - rt.end_rule = num; - rt.set = num; - rt.new_set = new_set; - do_del = 0; - - switch (cmd) { - case 0: /* delete rules numbered "rulenum" */ - if (num == 0) - rt.flags |= IPFW_RCFLAG_ALL; - else - rt.flags |= IPFW_RCFLAG_RANGE; - do_del = 1; - break; - case 1: /* delete rules in set "rulenum" */ - rt.flags |= IPFW_RCFLAG_SET; - do_del = 1; - break; - case 5: /* delete rules "rulenum" and set "new_set" */ - rt.flags |= IPFW_RCFLAG_RANGE | IPFW_RCFLAG_SET; - rt.set = new_set; - rt.new_set = 0; - do_del = 1; - break; - case 2: /* move rules "rulenum" to set "new_set" */ - rt.flags |= IPFW_RCFLAG_RANGE; - break; - case 3: /* move rules from set "rulenum" to set "new_set" */ - IPFW_UH_WLOCK(chain); - error = swap_sets(chain, &rt, 1); - IPFW_UH_WUNLOCK(chain); - return (error); - case 4: /* swap sets "rulenum" and "new_set" */ - IPFW_UH_WLOCK(chain); - error = swap_sets(chain, &rt, 0); - IPFW_UH_WUNLOCK(chain); - return (error); - default: - return (ENOTSUP); - } - - if (do_del != 0) { - if ((error = delete_range(chain, &rt, &ndel)) != 0) - return (error); - - if (ndel == 0 && (cmd != 1 && num != 0)) - return (EINVAL); - - return (0); - } - - return (move_range(chain, &rt)); -} - -/** - * Reset some or all counters on firewall rules. - * The argument `arg' is an u_int32_t. The low 16 bit are the rule number, - * the next 8 bits are the set number, the top 8 bits are the command: - * 0 work with rules from all set's; - * 1 work with rules only from specified set. - * Specified rule number is zero if we want to clear all entries. - * log_only is 1 if we only want to reset logs, zero otherwise. - */ -static int -zero_entry(struct ip_fw_chain *chain, u_int32_t arg, int log_only) -{ - struct ip_fw *rule; - char *msg; - int i; - - uint16_t rulenum = arg & 0xffff; - uint8_t set = (arg >> 16) & 0xff; - uint8_t cmd = (arg >> 24) & 0xff; - - if (cmd > 1) - return (EINVAL); - if (cmd == 1 && set > RESVD_SET) - return (EINVAL); - - IPFW_UH_RLOCK(chain); - if (rulenum == 0) { - V_norule_counter = 0; - for (i = 0; i < chain->n_rules; i++) { - rule = chain->map[i]; - /* Skip rules not in our set. */ - if (cmd == 1 && rule->set != set) - continue; - clear_counters(rule, log_only); - } - msg = log_only ? "All logging counts reset" : - "Accounting cleared"; - } else { - int cleared = 0; - for (i = 0; i < chain->n_rules; i++) { - rule = chain->map[i]; - if (rule->rulenum == rulenum) { - if (cmd == 0 || rule->set == set) - clear_counters(rule, log_only); - cleared = 1; - } - if (rule->rulenum > rulenum) - break; - } - if (!cleared) { /* we did not find any matching rules */ - IPFW_UH_RUNLOCK(chain); - return (EINVAL); - } - msg = log_only ? "logging count reset" : "cleared"; - } - IPFW_UH_RUNLOCK(chain); - - if (V_fw_verbose) { - int lev = LOG_SECURITY | LOG_NOTICE; - - if (rulenum) - log(lev, "ipfw: Entry %d %s.\n", rulenum, msg); - else - log(lev, "ipfw: %s.\n", msg); - } - return (0); -} - - -/* - * Check rule head in FreeBSD11 format - * - */ -static int -check_ipfw_rule1(struct ip_fw_rule *rule, int size, +/* Check rule format */ +int +ipfw_check_rule(struct ip_fw_rule *rule, size_t size, struct rule_check_info *ci) { int l; @@ -1708,7 +1309,7 @@ check_ipfw_rule1(struct ip_fw_rule *rule, int size, /* Check for valid cmd_len */ l = roundup2(RULESIZE(rule), sizeof(uint64_t)); if (l != size) { - printf("ipfw: size mismatch (have %d want %d)\n", size, l); + printf("ipfw: size mismatch (have %zu want %d)\n", size, l); return (EINVAL); } if (rule->act_ofs >= rule->cmd_len) { @@ -1723,525 +1324,373 @@ check_ipfw_rule1(struct ip_fw_rule *rule, int size, return (check_ipfw_rule_body(rule->cmd, rule->cmd_len, ci)); } -/* - * Check rule head in FreeBSD8 format - * - */ -static int -check_ipfw_rule0(struct ip_fw_rule0 *rule, int size, - struct rule_check_info *ci) +enum ipfw_opcheck_result +ipfw_check_opcode(ipfw_insn **pcmd, int *plen, struct rule_check_info *ci) { - int l; - - if (size < sizeof(*rule)) { - printf("ipfw: rule too short\n"); - return (EINVAL); - } - - /* Check for valid cmd_len */ - l = sizeof(*rule) + rule->cmd_len * 4 - 4; - if (l != size) { - printf("ipfw: size mismatch (have %d want %d)\n", size, l); - return (EINVAL); - } - if (rule->act_ofs >= rule->cmd_len) { - printf("ipfw: bogus action offset (%u > %u)\n", - rule->act_ofs, rule->cmd_len - 1); - return (EINVAL); - } - - if (rule->rulenum > IPFW_DEFAULT_RULE - 1) - return (EINVAL); - - return (check_ipfw_rule_body(rule->cmd, rule->cmd_len, ci)); -} - -static int -check_ipfw_rule_body(ipfw_insn *cmd, int cmd_len, struct rule_check_info *ci) -{ - int cmdlen, l; - int have_action; + ipfw_insn *cmd; + size_t cmdlen; - have_action = 0; + cmd = *pcmd; + cmdlen = F_LEN(cmd); - /* - * Now go for the individual checks. Very simple ones, basically only - * instruction sizes. - */ - for (l = cmd_len; l > 0 ; l -= cmdlen, cmd += cmdlen) { - cmdlen = F_LEN(cmd); - if (cmdlen > l) { - printf("ipfw: opcode %d size truncated\n", - cmd->opcode); - return EINVAL; - } - switch (cmd->opcode) { - case O_PROBE_STATE: - case O_KEEP_STATE: - if (cmdlen != F_INSN_SIZE(ipfw_insn)) - goto bad_size; - ci->object_opcodes++; - break; - case O_PROTO: - case O_IP_SRC_ME: - case O_IP_DST_ME: - case O_LAYER2: - case O_IN: - case O_FRAG: - case O_DIVERTED: - case O_IPOPT: - case O_IPTOS: - case O_IPPRECEDENCE: - case O_IPVER: - case O_SOCKARG: - case O_TCPFLAGS: - case O_TCPOPTS: - case O_ESTAB: - case O_VERREVPATH: - case O_VERSRCREACH: - case O_ANTISPOOF: - case O_IPSEC: + switch (cmd->opcode) { + case O_PROBE_STATE: + case O_KEEP_STATE: + if (cmdlen != F_INSN_SIZE(ipfw_insn_kidx)) + return (BAD_SIZE); + ci->object_opcodes++; + break; + case O_PROTO: + case O_IP_SRC_ME: + case O_IP_DST_ME: + case O_LAYER2: + case O_IN: + case O_FRAG: + case O_DIVERTED: + case O_IPOPT: + case O_IPTOS: + case O_IPPRECEDENCE: + case O_IPVER: + case O_SOCKARG: + case O_TCPFLAGS: + case O_TCPOPTS: + case O_ESTAB: + case O_VERREVPATH: + case O_VERSRCREACH: + case O_ANTISPOOF: + case O_IPSEC: #ifdef INET6 - case O_IP6_SRC_ME: - case O_IP6_DST_ME: - case O_EXT_HDR: - case O_IP6: + case O_IP6_SRC_ME: + case O_IP6_DST_ME: + case O_EXT_HDR: + case O_IP6: #endif - case O_IP4: - case O_TAG: - case O_SKIP_ACTION: - if (cmdlen != F_INSN_SIZE(ipfw_insn)) - goto bad_size; - break; + case O_IP4: + case O_TAG: + case O_SKIP_ACTION: + if (cmdlen != F_INSN_SIZE(ipfw_insn)) + return (BAD_SIZE); + break; - case O_EXTERNAL_ACTION: - if (cmd->arg1 == 0 || - cmdlen != F_INSN_SIZE(ipfw_insn)) { - printf("ipfw: invalid external " - "action opcode\n"); - return (EINVAL); - } - ci->object_opcodes++; - /* - * Do we have O_EXTERNAL_INSTANCE or O_EXTERNAL_DATA - * opcode? - */ - if (l != cmdlen) { - l -= cmdlen; - cmd += cmdlen; - cmdlen = F_LEN(cmd); - if (cmd->opcode == O_EXTERNAL_DATA) - goto check_action; - if (cmd->opcode != O_EXTERNAL_INSTANCE) { - printf("ipfw: invalid opcode " - "next to external action %u\n", - cmd->opcode); - return (EINVAL); - } - if (cmd->arg1 == 0 || - cmdlen != F_INSN_SIZE(ipfw_insn)) { - printf("ipfw: invalid external " - "action instance opcode\n"); - return (EINVAL); - } - ci->object_opcodes++; - } - goto check_action; - - case O_FIB: - if (cmdlen != F_INSN_SIZE(ipfw_insn)) - goto bad_size; - if (cmd->arg1 >= rt_numfibs) { - printf("ipfw: invalid fib number %d\n", - cmd->arg1); - return EINVAL; - } - break; + case O_EXTERNAL_ACTION: + if (cmdlen != F_INSN_SIZE(ipfw_insn_kidx)) + return (BAD_SIZE); - case O_SETFIB: - if (cmdlen != F_INSN_SIZE(ipfw_insn)) - goto bad_size; - if ((cmd->arg1 != IP_FW_TARG) && - ((cmd->arg1 & 0x7FFF) >= rt_numfibs)) { - printf("ipfw: invalid fib number %d\n", - cmd->arg1 & 0x7FFF); - return EINVAL; + if (insntod(cmd, kidx)->kidx == 0) + return (FAILED); + ci->object_opcodes++; + /* + * Do we have O_EXTERNAL_INSTANCE or O_EXTERNAL_DATA + * opcode? + */ + if (*plen != cmdlen) { + *plen -= cmdlen; + *pcmd = cmd += cmdlen; + cmdlen = F_LEN(cmd); + if (cmd->opcode == O_EXTERNAL_DATA) + return (CHECK_ACTION); + if (cmd->opcode != O_EXTERNAL_INSTANCE) { + printf("ipfw: invalid opcode " + "next to external action %u\n", + cmd->opcode); + return (FAILED); } - goto check_action; - - case O_UID: - case O_GID: - case O_JAIL: - case O_IP_SRC: - case O_IP_DST: - case O_TCPSEQ: - case O_TCPACK: - case O_PROB: - case O_ICMPTYPE: - if (cmdlen != F_INSN_SIZE(ipfw_insn_u32)) - goto bad_size; - break; - - case O_LIMIT: - if (cmdlen != F_INSN_SIZE(ipfw_insn_limit)) - goto bad_size; + if (cmdlen != F_INSN_SIZE(ipfw_insn_kidx)) + return (BAD_SIZE); + if (insntod(cmd, kidx)->kidx == 0) + return (FAILED); ci->object_opcodes++; - break; + } + return (CHECK_ACTION); + + case O_FIB: + if (cmdlen != F_INSN_SIZE(ipfw_insn)) + return (BAD_SIZE); + if (cmd->arg1 >= rt_numfibs) { + printf("ipfw: invalid fib number %d\n", + cmd->arg1); + return (FAILED); + } + break; - case O_LOG: - if (cmdlen != F_INSN_SIZE(ipfw_insn_log)) - goto bad_size; + case O_SETFIB: + if (cmdlen != F_INSN_SIZE(ipfw_insn)) + return (BAD_SIZE); + if ((cmd->arg1 != IP_FW_TARG) && + ((cmd->arg1 & 0x7FFF) >= rt_numfibs)) { + printf("ipfw: invalid fib number %d\n", + cmd->arg1 & 0x7FFF); + return (FAILED); + } + return (CHECK_ACTION); + + case O_UID: + case O_GID: + case O_JAIL: + case O_IP_SRC: + case O_IP_DST: + case O_TCPSEQ: + case O_TCPACK: + case O_PROB: + case O_ICMPTYPE: + if (cmdlen != F_INSN_SIZE(ipfw_insn_u32)) + return (BAD_SIZE); + break; - ((ipfw_insn_log *)cmd)->log_left = - ((ipfw_insn_log *)cmd)->max_log; + case O_LIMIT: + if (cmdlen != F_INSN_SIZE(ipfw_insn_limit)) + return (BAD_SIZE); + ci->object_opcodes++; + break; - break; + case O_LOG: + if (cmdlen != F_INSN_SIZE(ipfw_insn_log)) + return (BAD_SIZE); + insntod(cmd, log)->log_left = insntod(cmd, log)->max_log; + break; - case O_IP_SRC_MASK: - case O_IP_DST_MASK: - /* only odd command lengths */ - if ((cmdlen & 1) == 0) - goto bad_size; - break; + case O_IP_SRC_MASK: + case O_IP_DST_MASK: + /* only odd command lengths */ + if ((cmdlen & 1) == 0) + return (BAD_SIZE); + break; - case O_IP_SRC_SET: - case O_IP_DST_SET: - if (cmd->arg1 == 0 || cmd->arg1 > 256) { - printf("ipfw: invalid set size %d\n", - cmd->arg1); - return EINVAL; - } - if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + - (cmd->arg1+31)/32 ) - goto bad_size; - break; + case O_IP_SRC_SET: + case O_IP_DST_SET: + if (cmd->arg1 == 0 || cmd->arg1 > 256) { + printf("ipfw: invalid set size %d\n", + cmd->arg1); + return (FAILED); + } + if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + + (cmd->arg1+31)/32 ) + return (BAD_SIZE); + break; - case O_IP_SRC_LOOKUP: - if (cmdlen > F_INSN_SIZE(ipfw_insn_u32)) - goto bad_size; - case O_IP_DST_LOOKUP: - if (cmd->arg1 >= V_fw_tables_max) { - printf("ipfw: invalid table number %d\n", - cmd->arg1); - return (EINVAL); - } - if (cmdlen != F_INSN_SIZE(ipfw_insn) && - cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1 && - cmdlen != F_INSN_SIZE(ipfw_insn_u32)) - goto bad_size; - ci->object_opcodes++; - break; - case O_IP_FLOW_LOOKUP: - if (cmd->arg1 >= V_fw_tables_max) { - printf("ipfw: invalid table number %d\n", - cmd->arg1); - return (EINVAL); - } - if (cmdlen != F_INSN_SIZE(ipfw_insn) && - cmdlen != F_INSN_SIZE(ipfw_insn_u32)) - goto bad_size; - ci->object_opcodes++; - break; - case O_MACADDR2: - if (cmdlen != F_INSN_SIZE(ipfw_insn_mac)) - goto bad_size; - break; + case O_IP_SRC_LOOKUP: + case O_IP_DST_LOOKUP: + case O_IP_FLOW_LOOKUP: + if (cmdlen != F_INSN_SIZE(ipfw_insn_kidx) && + cmdlen != F_INSN_SIZE(ipfw_insn_table)) + return (BAD_SIZE); + if (insntod(cmd, kidx)->kidx >= V_fw_tables_max) { + printf("ipfw: invalid table number %u\n", + insntod(cmd, kidx)->kidx); + return (FAILED); + } + ci->object_opcodes++; + break; + case O_MACADDR2: + if (cmdlen != F_INSN_SIZE(ipfw_insn_mac)) + return (BAD_SIZE); + break; - case O_NOP: - case O_IPID: - case O_IPTTL: - case O_IPLEN: - case O_TCPDATALEN: - case O_TCPMSS: - case O_TCPWIN: - case O_TAGGED: - if (cmdlen < 1 || cmdlen > 31) - goto bad_size; - break; + case O_NOP: + case O_IPID: + case O_IPTTL: + case O_IPLEN: + case O_TCPDATALEN: + case O_TCPMSS: + case O_TCPWIN: + case O_TAGGED: + if (cmdlen < 1 || cmdlen > 31) + return (BAD_SIZE); + break; - case O_DSCP: - if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1) - goto bad_size; - break; + case O_DSCP: + if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1) + return (BAD_SIZE); + break; - case O_MAC_TYPE: - case O_IP_SRCPORT: - case O_IP_DSTPORT: /* XXX artificial limit, 30 port pairs */ - if (cmdlen < 2 || cmdlen > 31) - goto bad_size; - break; + case O_MAC_TYPE: + case O_IP_SRCPORT: + case O_IP_DSTPORT: /* XXX artificial limit, 30 port pairs */ + if (cmdlen < 2 || cmdlen > 31) + return (BAD_SIZE); + break; - case O_RECV: - case O_XMIT: - case O_VIA: - if (cmdlen != F_INSN_SIZE(ipfw_insn_if)) - goto bad_size; - ci->object_opcodes++; - break; + case O_RECV: + case O_XMIT: + case O_VIA: + if (cmdlen != F_INSN_SIZE(ipfw_insn_if)) + return (BAD_SIZE); + ci->object_opcodes++; + break; - case O_ALTQ: - if (cmdlen != F_INSN_SIZE(ipfw_insn_altq)) - goto bad_size; - break; + case O_ALTQ: + if (cmdlen != F_INSN_SIZE(ipfw_insn_altq)) + return (BAD_SIZE); + break; - case O_PIPE: - case O_QUEUE: - if (cmdlen != F_INSN_SIZE(ipfw_insn)) - goto bad_size; - goto check_action; + case O_PIPE: + case O_QUEUE: + if (cmdlen != F_INSN_SIZE(ipfw_insn)) + return (BAD_SIZE); + return (CHECK_ACTION); - case O_FORWARD_IP: - if (cmdlen != F_INSN_SIZE(ipfw_insn_sa)) - goto bad_size; - goto check_action; + case O_FORWARD_IP: + if (cmdlen != F_INSN_SIZE(ipfw_insn_sa)) + return (BAD_SIZE); + return (CHECK_ACTION); #ifdef INET6 - case O_FORWARD_IP6: - if (cmdlen != F_INSN_SIZE(ipfw_insn_sa6)) - goto bad_size; - goto check_action; + case O_FORWARD_IP6: + if (cmdlen != F_INSN_SIZE(ipfw_insn_sa6)) + return (BAD_SIZE); + return (CHECK_ACTION); #endif /* INET6 */ - case O_DIVERT: - case O_TEE: - if (ip_divert_ptr == NULL) - return EINVAL; - else - goto check_size; - case O_NETGRAPH: - case O_NGTEE: - if (ng_ipfw_input_p == NULL) - return EINVAL; - else - goto check_size; - case O_NAT: - if (!IPFW_NAT_LOADED) - return EINVAL; - if (cmdlen != F_INSN_SIZE(ipfw_insn_nat)) - goto bad_size; - goto check_action; - case O_CHECK_STATE: - ci->object_opcodes++; - /* FALLTHROUGH */ - case O_FORWARD_MAC: /* XXX not implemented yet */ - case O_COUNT: - case O_ACCEPT: - case O_DENY: - case O_REJECT: - case O_SETDSCP: + case O_DIVERT: + case O_TEE: + if (ip_divert_ptr == NULL) + return (FAILED); + if (cmdlen != F_INSN_SIZE(ipfw_insn)) + return (BAD_SIZE); + break; + case O_NETGRAPH: + case O_NGTEE: + if (ng_ipfw_input_p == NULL) + return (FAILED); + if (cmdlen != F_INSN_SIZE(ipfw_insn)) + return (BAD_SIZE); + break; + case O_NAT: + if (!IPFW_NAT_LOADED) + return (FAILED); + if (cmdlen != F_INSN_SIZE(ipfw_insn_nat)) + return (BAD_SIZE); + return (CHECK_ACTION); + + case O_SKIPTO: + case O_CALLRETURN: + if (cmdlen != F_INSN_SIZE(ipfw_insn_u32)) + return (BAD_SIZE); + return (CHECK_ACTION); + + case O_CHECK_STATE: + if (cmdlen != F_INSN_SIZE(ipfw_insn_kidx)) + return (BAD_SIZE); + ci->object_opcodes++; + return (CHECK_ACTION); + + case O_FORWARD_MAC: /* XXX not implemented yet */ + case O_COUNT: + case O_ACCEPT: + case O_DENY: + case O_REJECT: + case O_SETDSCP: #ifdef INET6 - case O_UNREACH6: + case O_UNREACH6: #endif - case O_SKIPTO: - case O_REASS: - case O_CALLRETURN: -check_size: - if (cmdlen != F_INSN_SIZE(ipfw_insn)) - goto bad_size; -check_action: - if (have_action) { - printf("ipfw: opcode %d, multiple actions" - " not allowed\n", - cmd->opcode); - return (EINVAL); - } - have_action = 1; - if (l != cmdlen) { - printf("ipfw: opcode %d, action must be" - " last opcode\n", - cmd->opcode); - return (EINVAL); - } - break; + case O_REASS: + if (cmdlen != F_INSN_SIZE(ipfw_insn)) + return (BAD_SIZE); + return (CHECK_ACTION); #ifdef INET6 + case O_IP6_SRC: + case O_IP6_DST: + if (cmdlen != F_INSN_SIZE(struct in6_addr) + + F_INSN_SIZE(ipfw_insn)) + return (BAD_SIZE); + break; + + case O_FLOW6ID: + if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + + ((ipfw_insn_u32 *)cmd)->o.arg1) + return (BAD_SIZE); + break; + + case O_IP6_SRC_MASK: + case O_IP6_DST_MASK: + if ( !(cmdlen & 1) || cmdlen > 127) + return (BAD_SIZE); + break; + case O_ICMP6TYPE: + if( cmdlen != F_INSN_SIZE( ipfw_insn_icmp6 ) ) + return (BAD_SIZE); + break; +#endif + + default: + switch (cmd->opcode) { +#ifndef INET6 + case O_IP6_SRC_ME: + case O_IP6_DST_ME: + case O_EXT_HDR: + case O_IP6: + case O_UNREACH6: case O_IP6_SRC: case O_IP6_DST: - if (cmdlen != F_INSN_SIZE(struct in6_addr) + - F_INSN_SIZE(ipfw_insn)) - goto bad_size; - break; - case O_FLOW6ID: - if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + - ((ipfw_insn_u32 *)cmd)->o.arg1) - goto bad_size; - break; - case O_IP6_SRC_MASK: case O_IP6_DST_MASK: - if ( !(cmdlen & 1) || cmdlen > 127) - goto bad_size; - break; case O_ICMP6TYPE: - if( cmdlen != F_INSN_SIZE( ipfw_insn_icmp6 ) ) - goto bad_size; - break; + printf("ipfw: no IPv6 support in kernel\n"); + return (FAILED); #endif - default: - switch (cmd->opcode) { -#ifndef INET6 - case O_IP6_SRC_ME: - case O_IP6_DST_ME: - case O_EXT_HDR: - case O_IP6: - case O_UNREACH6: - case O_IP6_SRC: - case O_IP6_DST: - case O_FLOW6ID: - case O_IP6_SRC_MASK: - case O_IP6_DST_MASK: - case O_ICMP6TYPE: - printf("ipfw: no IPv6 support in kernel\n"); - return (EPROTONOSUPPORT); -#endif - default: - printf("ipfw: opcode %d, unknown opcode\n", - cmd->opcode); - return (EINVAL); - } + printf("ipfw: opcode %d, unknown opcode\n", + cmd->opcode); + return (FAILED); } } - if (have_action == 0) { - printf("ipfw: missing action\n"); - return (EINVAL); - } - return 0; - -bad_size: - printf("ipfw: opcode %d size %d wrong\n", - cmd->opcode, cmdlen); - return (EINVAL); + return (SUCCESS); } - -/* - * Translation of requests for compatibility with FreeBSD 7.2/8. - * a static variable tells us if we have an old client from userland, - * and if necessary we translate requests and responses between the - * two formats. - */ -static int is7 = 0; - -struct ip_fw7 { - struct ip_fw7 *next; /* linked list of rules */ - struct ip_fw7 *next_rule; /* ptr to next [skipto] rule */ - /* 'next_rule' is used to pass up 'set_disable' status */ - - uint16_t act_ofs; /* offset of action in 32-bit units */ - uint16_t cmd_len; /* # of 32-bit words in cmd */ - uint16_t rulenum; /* rule number */ - uint8_t set; /* rule set (0..31) */ - // #define RESVD_SET 31 /* set for default and persistent rules */ - uint8_t _pad; /* padding */ - // uint32_t id; /* rule id, only in v.8 */ - /* These fields are present in all rules. */ - uint64_t pcnt; /* Packet counter */ - uint64_t bcnt; /* Byte counter */ - uint32_t timestamp; /* tv_sec of last match */ - - ipfw_insn cmd[1]; /* storage for commands */ -}; - -static int convert_rule_to_7(struct ip_fw_rule0 *rule); -static int convert_rule_to_8(struct ip_fw_rule0 *rule); - -#ifndef RULESIZE7 -#define RULESIZE7(rule) (sizeof(struct ip_fw7) + \ - ((struct ip_fw7 *)(rule))->cmd_len * 4 - 4) -#endif - - -/* - * Copy the static and dynamic rules to the supplied buffer - * and return the amount of space actually used. - * Must be run under IPFW_UH_RLOCK - */ -static size_t -ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space) +static int +check_ipfw_rule_body(ipfw_insn *cmd, int cmd_len, struct rule_check_info *ci) { - char *bp = buf; - char *ep = bp + space; - struct ip_fw *rule; - struct ip_fw_rule0 *dst; - struct timeval boottime; - int error, i, l, warnflag; - time_t boot_seconds; - - warnflag = 0; - - getboottime(&boottime); - boot_seconds = boottime.tv_sec; - for (i = 0; i < chain->n_rules; i++) { - rule = chain->map[i]; - - if (is7) { - /* Convert rule to FreeBSd 7.2 format */ - l = RULESIZE7(rule); - if (bp + l + sizeof(uint32_t) <= ep) { - bcopy(rule, bp, l + sizeof(uint32_t)); - error = set_legacy_obj_kidx(chain, - (struct ip_fw_rule0 *)bp); - if (error != 0) - return (0); - error = convert_rule_to_7((struct ip_fw_rule0 *) bp); - if (error) - return 0; /*XXX correct? */ - /* - * XXX HACK. Store the disable mask in the "next" - * pointer in a wild attempt to keep the ABI the same. - * Why do we do this on EVERY rule? - */ - bcopy(&V_set_disable, - &(((struct ip_fw7 *)bp)->next_rule), - sizeof(V_set_disable)); - if (((struct ip_fw7 *)bp)->timestamp) - ((struct ip_fw7 *)bp)->timestamp += boot_seconds; - bp += l; - } - continue; /* go to next rule */ - } + int cmdlen, l; + int have_action, ret; - l = RULEUSIZE0(rule); - if (bp + l > ep) { /* should not happen */ - printf("overflow dumping static rules\n"); - break; + /* + * Now go for the individual checks. Very simple ones, basically only + * instruction sizes. + */ + have_action = 0; + for (l = cmd_len; l > 0 ; l -= cmdlen, cmd += cmdlen) { + cmdlen = F_LEN(cmd); + if (cmdlen > l) { + printf("ipfw: opcode %d size truncated\n", + cmd->opcode); + return EINVAL; } - dst = (struct ip_fw_rule0 *)bp; - export_rule0(rule, dst, l); - error = set_legacy_obj_kidx(chain, dst); - - /* - * XXX HACK. Store the disable mask in the "next" - * pointer in a wild attempt to keep the ABI the same. - * Why do we do this on EVERY rule? - * - * XXX: "ipfw set show" (ab)uses IP_FW_GET to read disabled mask - * so we need to fail _after_ saving at least one mask. - */ - bcopy(&V_set_disable, &dst->next_rule, sizeof(V_set_disable)); - if (dst->timestamp) - dst->timestamp += boot_seconds; - bp += l; + if (ci->version != IP_FW3_OPVER) + ret = (*check_opcode_f)(&cmd, &l, ci); + else + ret = ipfw_check_opcode(&cmd, &l, ci); - if (error != 0) { - if (error == 2) { - /* Non-fatal table rewrite error. */ - warnflag = 1; - continue; + if (ret == CHECK_ACTION) { + if (have_action != 0) { + printf("ipfw: opcode %d, multiple actions" + " not allowed\n", cmd->opcode); + ret = FAILED; + } else + have_action = 1; + if (l != cmdlen) { + printf("ipfw: opcode %d, action must be" + " last opcode\n", cmd->opcode); + ret = FAILED; } - printf("Stop on rule %d. Fail to convert table\n", - rule->rulenum); - break; + } + switch (ret) { + case SUCCESS: + continue; + case BAD_SIZE: + printf("ipfw: opcode %d size %d wrong\n", + cmd->opcode, cmdlen); + /* FALLTHROUGH */ + case FAILED: + return (EINVAL); } } - if (warnflag != 0) - printf("ipfw: process %s is using legacy interfaces," - " consider rebuilding\n", ""); - ipfw_get_dynamic(chain, &bp, ep); /* protected by the dynamic lock */ - return (bp - (char *)buf); + if (have_action == 0) { + printf("ipfw: missing action\n"); + return (EINVAL); + } + return (0); } - struct dump_args { uint32_t b; /* start rule */ uint32_t e; /* end rule */ @@ -2368,7 +1817,7 @@ dump_static_rules(struct ip_fw_chain *chain, struct dump_args *da, } int -ipfw_mark_object_kidx(uint32_t *bmask, uint16_t etlv, uint16_t kidx) +ipfw_mark_object_kidx(uint32_t *bmask, uint16_t etlv, uint32_t kidx) { uint32_t bidx; @@ -2395,8 +1844,8 @@ mark_rule_objects(struct ip_fw_chain *ch, struct ip_fw *rule, { struct opcode_obj_rewrite *rw; ipfw_insn *cmd; + uint32_t kidx; int cmdlen, l; - uint16_t kidx; uint8_t subtype; l = rule->cmd_len; @@ -2566,7 +2015,7 @@ create_objects_compat(struct ip_fw_chain *ch, ipfw_insn *cmd, { struct opcode_obj_rewrite *rw; struct obj_idx *p; - uint16_t kidx; + uint32_t kidx; int error; /* @@ -2577,96 +2026,37 @@ create_objects_compat(struct ip_fw_chain *ch, ipfw_insn *cmd, if (p->kidx != 0) continue; - ti->uidx = p->uidx; - ti->type = p->type; - ti->atype = 0; - - rw = find_op_rw(cmd + p->off, NULL, NULL); - KASSERT(rw != NULL, ("Unable to find handler for op %d", - (cmd + p->off)->opcode)); - - if (rw->create_object == NULL) - error = EOPNOTSUPP; - else - error = rw->create_object(ch, ti, &kidx); - if (error == 0) { - p->kidx = kidx; - continue; - } - - /* - * Error happened. We have to rollback everything. - * Drop all already acquired references. - */ - IPFW_UH_WLOCK(ch); - unref_oib_objects(ch, cmd, oib, pidx); - IPFW_UH_WUNLOCK(ch); - - return (error); - } - - return (0); -} - -/* - * Compatibility function for old ipfw(8) binaries. - * Rewrites table/nat kernel indices with userland ones. - * Convert tables matching '/^\d+$/' to their atoi() value. - * Use number 65535 for other tables. - * - * Returns 0 on success. - */ -static int -set_legacy_obj_kidx(struct ip_fw_chain *ch, struct ip_fw_rule0 *rule) -{ - struct opcode_obj_rewrite *rw; - struct named_object *no; - ipfw_insn *cmd; - char *end; - long val; - int cmdlen, error, l; - uint16_t kidx, uidx; - uint8_t subtype; - - error = 0; - - l = rule->cmd_len; - cmd = rule->cmd; - cmdlen = 0; - for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { - cmdlen = F_LEN(cmd); - - /* Check if is index in given opcode */ - rw = find_op_rw(cmd, &kidx, &subtype); - if (rw == NULL) - continue; - - /* Try to find referenced kernel object */ - no = rw->find_bykidx(ch, kidx); - if (no == NULL) - continue; - - val = strtol(no->name, &end, 10); - if (*end == '\0' && val < 65535) { - uidx = val; - } else { + ti->uidx = p->uidx; + ti->type = p->type; + ti->atype = 0; - /* - * We are called via legacy opcode. - * Save error and show table as fake number - * not to make ipfw(8) hang. - */ - uidx = 65535; - error = 2; + rw = find_op_rw(cmd + p->off, NULL, NULL); + KASSERT(rw != NULL, ("Unable to find handler for op %d", + (cmd + p->off)->opcode)); + + if (rw->create_object == NULL) + error = EOPNOTSUPP; + else + error = rw->create_object(ch, ti, &kidx); + if (error == 0) { + p->kidx = kidx; + continue; } - rw->update(cmd, uidx); + /* + * Error happened. We have to rollback everything. + * Drop all already acquired references. + */ + IPFW_UH_WLOCK(ch); + unref_oib_objects(ch, cmd, oib, pidx); + IPFW_UH_WUNLOCK(ch); + + return (error); } - return (error); + return (0); } - /* * Unreferences all already-referenced objects in given @cmd rule, * using information in @oib. @@ -2708,8 +2098,8 @@ unref_rule_objects(struct ip_fw_chain *ch, struct ip_fw *rule) struct opcode_obj_rewrite *rw; struct named_object *no; ipfw_insn *cmd; + uint32_t kidx; int cmdlen, l; - uint16_t kidx; uint8_t subtype; IPFW_UH_WLOCK_ASSERT(ch); @@ -2914,8 +2304,8 @@ free: } /* - * Adds one or more rules to ipfw @chain. - * Data layout (version 0)(current): + * Pareses one or more rules from userland. + * Data layout (version 1)(current): * Request: * [ * ip_fw3_opheader @@ -2939,45 +2329,38 @@ free: * Returns 0 on success. */ static int -add_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3, - struct sockopt_data *sd) +parse_rules_v1(struct ip_fw_chain *chain, ip_fw3_opheader *op3, + struct sockopt_data *sd, ipfw_obj_ctlv **prtlv, + struct rule_check_info **pci) { ipfw_obj_ctlv *ctlv, *rtlv, *tstate; ipfw_obj_ntlv *ntlv; - int clen, error, idx; - uint32_t count, read; + struct rule_check_info *ci, *cbuf; struct ip_fw_rule *r; - struct rule_check_info rci, *ci, *cbuf; - int i, rsize; + size_t count, clen, read, rsize; + uint32_t rulenum; + int idx, error; op3 = (ip_fw3_opheader *)ipfw_get_sopt_space(sd, sd->valsize); ctlv = (ipfw_obj_ctlv *)(op3 + 1); - read = sizeof(ip_fw3_opheader); - rtlv = NULL; - tstate = NULL; - cbuf = NULL; - memset(&rci, 0, sizeof(struct rule_check_info)); - if (read + sizeof(*ctlv) > sd->valsize) return (EINVAL); + rtlv = NULL; + tstate = NULL; + cbuf = NULL; + /* Table names or other named objects. */ if (ctlv->head.type == IPFW_TLV_TBLNAME_LIST) { + /* Check size and alignment. */ clen = ctlv->head.length; - /* Check size and alignment */ - if (clen > sd->valsize || clen < sizeof(*ctlv)) - return (EINVAL); - if ((clen % sizeof(uint64_t)) != 0) + if (read + clen > sd->valsize || clen < sizeof(*ctlv) || + (clen % sizeof(uint64_t)) != 0) return (EINVAL); - - /* - * Some table names or other named objects. - * Check for validness. - */ + /* Check for validness. */ count = (ctlv->head.length - sizeof(*ctlv)) / sizeof(*ntlv); if (ctlv->count != count || ctlv->objsize != sizeof(*ntlv)) return (EINVAL); - /* * Check each TLV. * Ensure TLVs are sorted ascending and @@ -3004,70 +2387,57 @@ add_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3, tstate = ctlv; read += ctlv->head.length; ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length); - } - if (read + sizeof(*ctlv) > sd->valsize) - return (EINVAL); + if (read + sizeof(*ctlv) > sd->valsize) + return (EINVAL); + } + /* List of rules. */ if (ctlv->head.type == IPFW_TLV_RULE_LIST) { clen = ctlv->head.length; - if (clen + read > sd->valsize || clen < sizeof(*ctlv)) - return (EINVAL); - if ((clen % sizeof(uint64_t)) != 0) + if (read + clen > sd->valsize || clen < sizeof(*ctlv) || + (clen % sizeof(uint64_t)) != 0) return (EINVAL); - /* - * TODO: Permit adding multiple rules at once - */ - if (ctlv->count != 1) - return (ENOTSUP); - clen -= sizeof(*ctlv); - - if (ctlv->count > clen / sizeof(struct ip_fw_rule)) + if (ctlv->count == 0 || + ctlv->count > clen / sizeof(struct ip_fw_rule)) return (EINVAL); - /* Allocate state for each rule or use stack */ - if (ctlv->count == 1) { - memset(&rci, 0, sizeof(struct rule_check_info)); - cbuf = &rci; - } else - cbuf = malloc(ctlv->count * sizeof(*ci), M_TEMP, - M_WAITOK | M_ZERO); - ci = cbuf; + /* Allocate state for each rule */ + cbuf = malloc(ctlv->count * sizeof(struct rule_check_info), + M_TEMP, M_WAITOK | M_ZERO); /* * Check each rule for validness. * Ensure numbered rules are sorted ascending * and properly aligned */ - idx = 0; - r = (struct ip_fw_rule *)(ctlv + 1); + rulenum = 0; count = 0; error = 0; + ci = cbuf; + r = (struct ip_fw_rule *)(ctlv + 1); while (clen > 0) { - rsize = roundup2(RULESIZE(r), sizeof(uint64_t)); - if (rsize > clen || ctlv->count <= count) { + rsize = RULEUSIZE1(r); + if (rsize > clen || count > ctlv->count) { error = EINVAL; break; } - ci->ctlv = tstate; - error = check_ipfw_rule1(r, rsize, ci); + error = ipfw_check_rule(r, rsize, ci); if (error != 0) break; /* Check sorting */ - if (r->rulenum != 0 && r->rulenum < idx) { - printf("rulenum %d idx %d\n", r->rulenum, idx); + if (r->rulenum != 0 && r->rulenum < rulenum) { + printf("ipfw: wrong order: rulenum %u" + " vs %u\n", r->rulenum, rulenum); error = EINVAL; break; } - idx = r->rulenum; - + rulenum = r->rulenum; ci->urule = (caddr_t)r; - - rsize = roundup2(rsize, sizeof(uint64_t)); clen -= rsize; r = (struct ip_fw_rule *)((caddr_t)r + rsize); count++; @@ -3075,8 +2445,7 @@ add_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3, } if (ctlv->count != count || error != 0) { - if (cbuf != &rci) - free(cbuf, M_TEMP); + free(cbuf, M_TEMP); return (EINVAL); } @@ -3085,32 +2454,73 @@ add_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3, ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length); } - if (read != sd->valsize || rtlv == NULL || rtlv->count == 0) { - if (cbuf != NULL && cbuf != &rci) - free(cbuf, M_TEMP); + if (read != sd->valsize || rtlv == NULL) { + free(cbuf, M_TEMP); return (EINVAL); } + *prtlv = rtlv; + *pci = cbuf; + return (0); +} + +/* + * Copy rule @urule from v1 userland format (current) to kernel @krule. + */ +static void +import_rule_v1(struct ip_fw_chain *chain, struct rule_check_info *ci) +{ + struct ip_fw_rule *urule; + struct ip_fw *krule; + + urule = (struct ip_fw_rule *)ci->urule; + krule = ci->krule = ipfw_alloc_rule(chain, RULEKSIZE1(urule)); + + krule->act_ofs = urule->act_ofs; + krule->cmd_len = urule->cmd_len; + krule->rulenum = urule->rulenum; + krule->set = urule->set; + krule->flags = urule->flags; + + /* Save rulenum offset */ + ci->urule_numoff = offsetof(struct ip_fw_rule, rulenum); + + /* Copy opcodes */ + memcpy(krule->cmd, urule->cmd, krule->cmd_len * sizeof(uint32_t)); +} + +/* + * Adds one or more rules to ipfw @chain. + */ +static int +add_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3, + struct sockopt_data *sd) +{ + ipfw_obj_ctlv *rtlv; + struct rule_check_info *ci, *nci; + int i, ret; + /* - * Passed rules seems to be valid. - * Allocate storage and try to add them to chain. + * Check rules buffer for validness. */ - for (i = 0, ci = cbuf; i < rtlv->count; i++, ci++) { - clen = RULEKSIZE1((struct ip_fw_rule *)ci->urule); - ci->krule = ipfw_alloc_rule(chain, clen); - import_rule1(ci); - } - - if ((error = commit_rules(chain, cbuf, rtlv->count)) != 0) { - /* Free allocate krules */ - for (i = 0, ci = cbuf; i < rtlv->count; i++, ci++) + ret = parse_rules_v1(chain, op3, sd, &rtlv, &nci); + if (ret != 0) + return (ret); + /* + * Allocate storage for the kernel representation of rules. + */ + for (i = 0, ci = nci; i < rtlv->count; i++, ci++) + import_rule_v1(chain, ci); + /* + * Try to add new rules to the chain. + */ + if ((ret = ipfw_commit_rules(chain, nci, rtlv->count)) != 0) { + for (i = 0, ci = nci; i < rtlv->count; i++, ci++) ipfw_free_rule(ci->krule); } - - if (cbuf != NULL && cbuf != &rci) - free(cbuf, M_TEMP); - - return (error); + /* Cleanup after ipfw_parse_rules() */ + free(nci, M_TEMP); + return (ret); } /* @@ -3226,10 +2636,10 @@ find_op_rw_range(uint16_t op, struct opcode_obj_rewrite **plo, * Returns pointer to handler or NULL. */ static struct opcode_obj_rewrite * -find_op_rw(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) +find_op_rw(ipfw_insn *cmd, uint32_t *puidx, uint8_t *ptype) { struct opcode_obj_rewrite *rw, *lo, *hi; - uint16_t uidx; + uint32_t uidx; uint8_t subtype; if (find_op_rw_range(cmd->opcode, &lo, &hi) != 0) @@ -3248,7 +2658,7 @@ find_op_rw(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) return (NULL); } int -classify_opcode_kidx(ipfw_insn *cmd, uint16_t *puidx) +classify_opcode_kidx(ipfw_insn *cmd, uint32_t *puidx) { if (find_op_rw(cmd, puidx, NULL) == NULL) @@ -3257,7 +2667,7 @@ classify_opcode_kidx(ipfw_insn *cmd, uint16_t *puidx) } void -update_opcode_kidx(ipfw_insn *cmd, uint16_t idx) +update_opcode_kidx(ipfw_insn *cmd, uint32_t idx) { struct opcode_obj_rewrite *rw; @@ -3484,7 +2894,7 @@ find_ref_sh(uint16_t opcode, uint8_t version, struct ipfw_sopt_handler *psh) sh->refcnt++; ctl3_refct++; /* Copy handler data to requested buffer */ - *psh = *sh; + *psh = *sh; CTL3_UNLOCK(); return (0); @@ -3519,6 +2929,20 @@ ipfw_destroy_sopt_handler() CTL3_LOCK_DESTROY(); } +void +ipfw_register_compat(ipfw_check_opcode_t f) +{ + + check_opcode_f = f; +} + +void +ipfw_unregister_compat(void) +{ + + check_opcode_f = check_opcode_compat_nop; +} + /* * Adds one or more sockopt handlers to the global array. * Function may sleep. @@ -3815,435 +3239,6 @@ ipfw_ctl3(struct sockopt *sopt) return (error); } -/** - * {set|get}sockopt parser. - */ -int -ipfw_ctl(struct sockopt *sopt) -{ -#define RULE_MAXSIZE (512*sizeof(u_int32_t)) - int error; - size_t size, valsize; - struct ip_fw *buf; - struct ip_fw_rule0 *rule; - struct ip_fw_chain *chain; - u_int32_t rulenum[2]; - uint32_t opt; - struct rule_check_info ci; - IPFW_RLOCK_TRACKER; - - chain = &V_layer3_chain; - error = 0; - - /* Save original valsize before it is altered via sooptcopyin() */ - valsize = sopt->sopt_valsize; - opt = sopt->sopt_name; - - /* - * Disallow modifications in really-really secure mode, but still allow - * the logging counters to be reset. - */ - if (opt == IP_FW_ADD || - (sopt->sopt_dir == SOPT_SET && opt != IP_FW_RESETLOG)) { - error = securelevel_ge(sopt->sopt_td->td_ucred, 3); - if (error != 0) - return (error); - } - - switch (opt) { - case IP_FW_GET: - /* - * pass up a copy of the current rules. Static rules - * come first (the last of which has number IPFW_DEFAULT_RULE), - * followed by a possibly empty list of dynamic rule. - * The last dynamic rule has NULL in the "next" field. - * - * Note that the calculated size is used to bound the - * amount of data returned to the user. The rule set may - * change between calculating the size and returning the - * data in which case we'll just return what fits. - */ - for (;;) { - int len = 0, want; - - size = chain->static_len; - size += ipfw_dyn_len(); - if (size >= sopt->sopt_valsize) - break; - buf = malloc(size, M_TEMP, M_WAITOK | M_ZERO); - IPFW_UH_RLOCK(chain); - /* check again how much space we need */ - want = chain->static_len + ipfw_dyn_len(); - if (size >= want) - len = ipfw_getrules(chain, buf, size); - IPFW_UH_RUNLOCK(chain); - if (size >= want) - error = sooptcopyout(sopt, buf, len); - free(buf, M_TEMP); - if (size >= want) - break; - } - break; - - case IP_FW_FLUSH: - /* locking is done within del_entry() */ - error = del_entry(chain, 0); /* special case, rule=0, cmd=0 means all */ - break; - - case IP_FW_ADD: - rule = malloc(RULE_MAXSIZE, M_TEMP, M_WAITOK); - error = sooptcopyin(sopt, rule, RULE_MAXSIZE, - sizeof(struct ip_fw7) ); - - memset(&ci, 0, sizeof(struct rule_check_info)); - - /* - * If the size of commands equals RULESIZE7 then we assume - * a FreeBSD7.2 binary is talking to us (set is7=1). - * is7 is persistent so the next 'ipfw list' command - * will use this format. - * NOTE: If wrong version is guessed (this can happen if - * the first ipfw command is 'ipfw [pipe] list') - * the ipfw binary may crash or loop infinitly... - */ - size = sopt->sopt_valsize; - if (size == RULESIZE7(rule)) { - is7 = 1; - error = convert_rule_to_8(rule); - if (error) { - free(rule, M_TEMP); - return error; - } - size = RULESIZE(rule); - } else - is7 = 0; - if (error == 0) - error = check_ipfw_rule0(rule, size, &ci); - if (error == 0) { - /* locking is done within add_rule() */ - struct ip_fw *krule; - krule = ipfw_alloc_rule(chain, RULEKSIZE0(rule)); - ci.urule = (caddr_t)rule; - ci.krule = krule; - import_rule0(&ci); - error = commit_rules(chain, &ci, 1); - if (error != 0) - ipfw_free_rule(ci.krule); - else if (sopt->sopt_dir == SOPT_GET) { - if (is7) { - error = convert_rule_to_7(rule); - size = RULESIZE7(rule); - if (error) { - free(rule, M_TEMP); - return error; - } - } - error = sooptcopyout(sopt, rule, size); - } - } - free(rule, M_TEMP); - break; - - case IP_FW_DEL: - /* - * IP_FW_DEL is used for deleting single rules or sets, - * and (ab)used to atomically manipulate sets. Argument size - * is used to distinguish between the two: - * sizeof(u_int32_t) - * delete single rule or set of rules, - * or reassign rules (or sets) to a different set. - * 2*sizeof(u_int32_t) - * atomic disable/enable sets. - * first u_int32_t contains sets to be disabled, - * second u_int32_t contains sets to be enabled. - */ - error = sooptcopyin(sopt, rulenum, - 2*sizeof(u_int32_t), sizeof(u_int32_t)); - if (error) - break; - size = sopt->sopt_valsize; - if (size == sizeof(u_int32_t) && rulenum[0] != 0) { - /* delete or reassign, locking done in del_entry() */ - error = del_entry(chain, rulenum[0]); - } else if (size == 2*sizeof(u_int32_t)) { /* set enable/disable */ - IPFW_UH_WLOCK(chain); - V_set_disable = - (V_set_disable | rulenum[0]) & ~rulenum[1] & - ~(1<sopt_val != 0) { - error = sooptcopyin(sopt, rulenum, - sizeof(u_int32_t), sizeof(u_int32_t)); - if (error) - break; - } - error = zero_entry(chain, rulenum[0], - sopt->sopt_name == IP_FW_RESETLOG); - break; - - /*--- TABLE opcodes ---*/ - case IP_FW_TABLE_ADD: - case IP_FW_TABLE_DEL: - { - ipfw_table_entry ent; - struct tentry_info tei; - struct tid_info ti; - struct table_value v; - - error = sooptcopyin(sopt, &ent, - sizeof(ent), sizeof(ent)); - if (error) - break; - - memset(&tei, 0, sizeof(tei)); - tei.paddr = &ent.addr; - tei.subtype = AF_INET; - tei.masklen = ent.masklen; - ipfw_import_table_value_legacy(ent.value, &v); - tei.pvalue = &v; - memset(&ti, 0, sizeof(ti)); - ti.uidx = ent.tbl; - ti.type = IPFW_TABLE_CIDR; - - error = (opt == IP_FW_TABLE_ADD) ? - add_table_entry(chain, &ti, &tei, 0, 1) : - del_table_entry(chain, &ti, &tei, 0, 1); - } - break; - - - case IP_FW_TABLE_FLUSH: - { - u_int16_t tbl; - struct tid_info ti; - - error = sooptcopyin(sopt, &tbl, - sizeof(tbl), sizeof(tbl)); - if (error) - break; - memset(&ti, 0, sizeof(ti)); - ti.uidx = tbl; - error = flush_table(chain, &ti); - } - break; - - case IP_FW_TABLE_GETSIZE: - { - u_int32_t tbl, cnt; - struct tid_info ti; - - if ((error = sooptcopyin(sopt, &tbl, sizeof(tbl), - sizeof(tbl)))) - break; - memset(&ti, 0, sizeof(ti)); - ti.uidx = tbl; - IPFW_RLOCK(chain); - error = ipfw_count_table(chain, &ti, &cnt); - IPFW_RUNLOCK(chain); - if (error) - break; - error = sooptcopyout(sopt, &cnt, sizeof(cnt)); - } - break; - - case IP_FW_TABLE_LIST: - { - ipfw_table *tbl; - struct tid_info ti; - - if (sopt->sopt_valsize < sizeof(*tbl)) { - error = EINVAL; - break; - } - size = sopt->sopt_valsize; - tbl = malloc(size, M_TEMP, M_WAITOK); - error = sooptcopyin(sopt, tbl, size, sizeof(*tbl)); - if (error) { - free(tbl, M_TEMP); - break; - } - tbl->size = (size - sizeof(*tbl)) / - sizeof(ipfw_table_entry); - memset(&ti, 0, sizeof(ti)); - ti.uidx = tbl->tbl; - IPFW_RLOCK(chain); - error = ipfw_dump_table_legacy(chain, &ti, tbl); - IPFW_RUNLOCK(chain); - if (error) { - free(tbl, M_TEMP); - break; - } - error = sooptcopyout(sopt, tbl, size); - free(tbl, M_TEMP); - } - break; - - /*--- NAT operations are protected by the IPFW_LOCK ---*/ - case IP_FW_NAT_CFG: - if (IPFW_NAT_LOADED) - error = ipfw_nat_cfg_ptr(sopt); - else { - printf("IP_FW_NAT_CFG: %s\n", - "ipfw_nat not present, please load it"); - error = EINVAL; - } - break; - - case IP_FW_NAT_DEL: - if (IPFW_NAT_LOADED) - error = ipfw_nat_del_ptr(sopt); - else { - printf("IP_FW_NAT_DEL: %s\n", - "ipfw_nat not present, please load it"); - error = EINVAL; - } - break; - - case IP_FW_NAT_GET_CONFIG: - if (IPFW_NAT_LOADED) - error = ipfw_nat_get_cfg_ptr(sopt); - else { - printf("IP_FW_NAT_GET_CFG: %s\n", - "ipfw_nat not present, please load it"); - error = EINVAL; - } - break; - - case IP_FW_NAT_GET_LOG: - if (IPFW_NAT_LOADED) - error = ipfw_nat_get_log_ptr(sopt); - else { - printf("IP_FW_NAT_GET_LOG: %s\n", - "ipfw_nat not present, please load it"); - error = EINVAL; - } - break; - - default: - printf("ipfw: ipfw_ctl invalid option %d\n", sopt->sopt_name); - error = EINVAL; - } - - return (error); -#undef RULE_MAXSIZE -} -#define RULE_MAXSIZE (256*sizeof(u_int32_t)) - -/* Functions to convert rules 7.2 <==> 8.0 */ -static int -convert_rule_to_7(struct ip_fw_rule0 *rule) -{ - /* Used to modify original rule */ - struct ip_fw7 *rule7 = (struct ip_fw7 *)rule; - /* copy of original rule, version 8 */ - struct ip_fw_rule0 *tmp; - - /* Used to copy commands */ - ipfw_insn *ccmd, *dst; - int ll = 0, ccmdlen = 0; - - tmp = malloc(RULE_MAXSIZE, M_TEMP, M_NOWAIT | M_ZERO); - if (tmp == NULL) { - return 1; //XXX error - } - bcopy(rule, tmp, RULE_MAXSIZE); - - /* Copy fields */ - //rule7->_pad = tmp->_pad; - rule7->set = tmp->set; - rule7->rulenum = tmp->rulenum; - rule7->cmd_len = tmp->cmd_len; - rule7->act_ofs = tmp->act_ofs; - rule7->next_rule = (struct ip_fw7 *)tmp->next_rule; - rule7->cmd_len = tmp->cmd_len; - rule7->pcnt = tmp->pcnt; - rule7->bcnt = tmp->bcnt; - rule7->timestamp = tmp->timestamp; - - /* Copy commands */ - for (ll = tmp->cmd_len, ccmd = tmp->cmd, dst = rule7->cmd ; - ll > 0 ; ll -= ccmdlen, ccmd += ccmdlen, dst += ccmdlen) { - ccmdlen = F_LEN(ccmd); - - bcopy(ccmd, dst, F_LEN(ccmd)*sizeof(uint32_t)); - - if (dst->opcode > O_NAT) - /* O_REASS doesn't exists in 7.2 version, so - * decrement opcode if it is after O_REASS - */ - dst->opcode--; - - if (ccmdlen > ll) { - printf("ipfw: opcode %d size truncated\n", - ccmd->opcode); - return EINVAL; - } - } - free(tmp, M_TEMP); - - return 0; -} - -static int -convert_rule_to_8(struct ip_fw_rule0 *rule) -{ - /* Used to modify original rule */ - struct ip_fw7 *rule7 = (struct ip_fw7 *) rule; - - /* Used to copy commands */ - ipfw_insn *ccmd, *dst; - int ll = 0, ccmdlen = 0; - - /* Copy of original rule */ - struct ip_fw7 *tmp = malloc(RULE_MAXSIZE, M_TEMP, M_NOWAIT | M_ZERO); - if (tmp == NULL) { - return 1; //XXX error - } - - bcopy(rule7, tmp, RULE_MAXSIZE); - - for (ll = tmp->cmd_len, ccmd = tmp->cmd, dst = rule->cmd ; - ll > 0 ; ll -= ccmdlen, ccmd += ccmdlen, dst += ccmdlen) { - ccmdlen = F_LEN(ccmd); - - bcopy(ccmd, dst, F_LEN(ccmd)*sizeof(uint32_t)); - - if (dst->opcode > O_NAT) - /* O_REASS doesn't exists in 7.2 version, so - * increment opcode if it is after O_REASS - */ - dst->opcode++; - - if (ccmdlen > ll) { - printf("ipfw: opcode %d size truncated\n", - ccmd->opcode); - return EINVAL; - } - } - - rule->_pad = tmp->_pad; - rule->set = tmp->set; - rule->rulenum = tmp->rulenum; - rule->cmd_len = tmp->cmd_len; - rule->act_ofs = tmp->act_ofs; - rule->next_rule = (struct ip_fw *)tmp->next_rule; - rule->cmd_len = tmp->cmd_len; - rule->id = 0; /* XXX see if is ok = 0 */ - rule->pcnt = tmp->pcnt; - rule->bcnt = tmp->bcnt; - rule->timestamp = tmp->timestamp; - - free (tmp, M_TEMP); - return 0; -} - /* * Named object api * @@ -4446,7 +3441,7 @@ ipfw_objhash_lookup_name(struct namedobj_instance *ni, uint32_t set, char *name) * Returns pointer to found TLV or NULL. */ ipfw_obj_ntlv * -ipfw_find_name_tlv_type(void *tlvs, int len, uint16_t uidx, uint32_t etlv) +ipfw_find_name_tlv_type(void *tlvs, int len, uint32_t uidx, uint32_t etlv) { ipfw_obj_ntlv *ntlv; uintptr_t pa, pe; @@ -4540,18 +3535,16 @@ ipfw_objhash_lookup_name_type(struct namedobj_instance *ni, uint32_t set, } struct named_object * -ipfw_objhash_lookup_kidx(struct namedobj_instance *ni, uint16_t kidx) +ipfw_objhash_lookup_kidx(struct namedobj_instance *ni, uint32_t kidx) { struct named_object *no; uint32_t hash; hash = objhash_hash_idx(ni, kidx); - TAILQ_FOREACH(no, &ni->values[hash], nv_next) { if (no->kidx == kidx) return (no); } - return (NULL); } @@ -4666,7 +3659,7 @@ ipfw_objhash_foreach_type(struct namedobj_instance *ni, objhash_cb_t *f, * Returns 0 on success. */ int -ipfw_objhash_free_idx(struct namedobj_instance *ni, uint16_t idx) +ipfw_objhash_free_idx(struct namedobj_instance *ni, uint32_t idx) { u_long *mask; int i, v; @@ -4688,7 +3681,7 @@ ipfw_objhash_free_idx(struct namedobj_instance *ni, uint16_t idx) /* Update free offset */ if (ni->free_off[0] > i) ni->free_off[0] = i; - + return (0); } @@ -4697,7 +3690,7 @@ ipfw_objhash_free_idx(struct namedobj_instance *ni, uint16_t idx) * Returns 0 on success. */ int -ipfw_objhash_alloc_idx(void *n, uint16_t *pidx) +ipfw_objhash_alloc_idx(void *n, uint32_t *pidx) { struct namedobj_instance *ni; u_long *mask; @@ -4714,11 +3707,8 @@ ipfw_objhash_alloc_idx(void *n, uint16_t *pidx) /* Mark as busy */ *mask &= ~ ((u_long)1 << (v - 1)); - ni->free_off[0] = i; - v = BLOCK_ITEMS * i + v - 1; - *pidx = v; return (0); } diff --git a/sys/netpfil/ipfw/ip_fw_table.c b/sys/netpfil/ipfw/ip_fw_table.c index 67593aa9e2f..8b4ae410014 100644 --- a/sys/netpfil/ipfw/ip_fw_table.c +++ b/sys/netpfil/ipfw/ip_fw_table.c @@ -101,7 +101,7 @@ static struct table_config *alloc_table_config(struct ip_fw_chain *ch, static void free_table_config(struct namedobj_instance *ni, struct table_config *tc); static int create_table_internal(struct ip_fw_chain *ch, struct tid_info *ti, - char *aname, ipfw_xtable_info *i, uint16_t *pkidx, int ref); + char *aname, ipfw_xtable_info *i, uint32_t *pkidx, int ref); static void link_table(struct ip_fw_chain *ch, struct table_config *tc); static void unlink_table(struct ip_fw_chain *ch, struct table_config *tc); static int find_ref_table(struct ip_fw_chain *ch, struct tid_info *ti, @@ -113,7 +113,6 @@ static int export_tables(struct ip_fw_chain *ch, ipfw_obj_lheader *olh, static void export_table_info(struct ip_fw_chain *ch, struct table_config *tc, ipfw_xtable_info *i); static int dump_table_tentry(void *e, void *arg); -static int dump_table_xentry(void *e, void *arg); static int swap_tables(struct ip_fw_chain *ch, struct tid_info *a, struct tid_info *b); @@ -261,7 +260,7 @@ store_tei_result(struct tentry_info *tei, int op, int error, uint32_t num) */ static int create_table_compat(struct ip_fw_chain *ch, struct tid_info *ti, - uint16_t *pkidx) + uint32_t *pkidx) { ipfw_xtable_info xi; int error; @@ -293,7 +292,7 @@ find_ref_table(struct ip_fw_chain *ch, struct tid_info *ti, { struct namedobj_instance *ni; struct table_config *tc; - uint16_t kidx; + uint32_t kidx; int error; IPFW_UH_WLOCK_ASSERT(ch); @@ -334,7 +333,7 @@ find_ref_table(struct ip_fw_chain *ch, struct tid_info *ti, return (error); tc = (struct table_config *)ipfw_objhash_lookup_kidx(ni, kidx); - KASSERT(tc != NULL, ("create_table_compat returned bad idx %d", kidx)); + KASSERT(tc != NULL, ("create_table_compat returned bad idx %u", kidx)); /* OK, now we've got referenced table. */ *ptc = tc; @@ -552,13 +551,12 @@ add_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, { struct table_config *tc; struct table_algo *ta; - uint16_t kidx; - int error, first_error, i, rollback; - uint32_t num, numadd; struct tentry_info *ptei; struct tableop_state ts; char ta_buf[TA_BUF_SZ]; caddr_t ta_buf_m, v; + uint32_t kidx, num, numadd; + int error, first_error, i, rollback; memset(&ts, 0, sizeof(ts)); ta = NULL; @@ -716,11 +714,10 @@ del_table_entry(struct ip_fw_chain *ch, struct tid_info *ti, struct table_config *tc; struct table_algo *ta; struct tentry_info *ptei; - uint16_t kidx; - int error, first_error, i; - uint32_t num, numdel; char ta_buf[TA_BUF_SZ]; caddr_t ta_buf_m, v; + uint32_t kidx, num, numdel; + int error, first_error, i; /* * Find and reference existing table. @@ -895,61 +892,6 @@ check_table_space(struct ip_fw_chain *ch, struct tableop_state *ts, return (error); } -/* - * Adds or deletes record in table. - * Data layout (v0): - * Request: [ ip_fw3_opheader ipfw_table_xentry ] - * - * Returns 0 on success - */ -static int -manage_table_ent_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3, - struct sockopt_data *sd) -{ - ipfw_table_xentry *xent; - struct tentry_info tei; - struct tid_info ti; - struct table_value v; - int error, hdrlen, read; - - hdrlen = offsetof(ipfw_table_xentry, k); - - /* Check minimum header size */ - if (sd->valsize < (sizeof(*op3) + hdrlen)) - return (EINVAL); - - read = sizeof(ip_fw3_opheader); - - /* Check if xentry len field is valid */ - xent = (ipfw_table_xentry *)(op3 + 1); - if (xent->len < hdrlen || xent->len + read > sd->valsize) - return (EINVAL); - - memset(&tei, 0, sizeof(tei)); - tei.paddr = &xent->k; - tei.masklen = xent->masklen; - ipfw_import_table_value_legacy(xent->value, &v); - tei.pvalue = &v; - /* Old requests compatibility */ - tei.flags = TEI_FLAGS_COMPAT; - if (xent->type == IPFW_TABLE_ADDR) { - if (xent->len - hdrlen == sizeof(in_addr_t)) - tei.subtype = AF_INET; - else - tei.subtype = AF_INET6; - } - - memset(&ti, 0, sizeof(ti)); - ti.uidx = xent->tbl; - ti.type = xent->type; - - error = (op3->opcode == IP_FW_TABLE_XADD) ? - add_table_entry(ch, &ti, &tei, 0, 1) : - del_table_entry(ch, &ti, &tei, 0, 1); - - return (error); -} - /* * Adds or deletes record in table. * Data layout (v1)(current): @@ -968,7 +910,8 @@ manage_table_ent_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3, ipfw_obj_header *oh; struct tentry_info *ptei, tei, *tei_buf; struct tid_info ti; - int error, i, kidx, read; + uint32_t kidx; + int error, i, read; /* Check minimum header size */ if (sd->valsize < (sizeof(*oh) + sizeof(*ctlv))) @@ -1210,7 +1153,7 @@ flush_table(struct ip_fw_chain *ch, struct tid_info *ti) char algostate[64], *pstate; struct tableop_state ts; int error, need_gc; - uint16_t kidx; + uint32_t kidx; uint8_t tflags; /* @@ -1500,7 +1443,7 @@ destroy_table(struct ip_fw_chain *ch, struct tid_info *ti) /* Free obj index */ if (ipfw_objhash_free_idx(ni, tc->no.kidx) != 0) - printf("Error unlinking kidx %d from table %s\n", + printf("Error unlinking kidx %u from table %s\n", tc->no.kidx, tc->tablename); /* Unref values used in tables while holding UH lock */ @@ -1612,7 +1555,7 @@ ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables) * Lookup table's named object by its @kidx. */ struct named_object * -ipfw_objhash_lookup_table_kidx(struct ip_fw_chain *ch, uint16_t kidx) +ipfw_objhash_lookup_table_kidx(struct ip_fw_chain *ch, uint32_t kidx) { return (ipfw_objhash_lookup_kidx(CHAIN_TO_NI(ch), kidx)); @@ -1623,7 +1566,7 @@ ipfw_objhash_lookup_table_kidx(struct ip_fw_chain *ch, uint16_t kidx) * On success return its @kidx. */ int -ipfw_ref_table(struct ip_fw_chain *ch, ipfw_obj_ntlv *ntlv, uint16_t *kidx) +ipfw_ref_table(struct ip_fw_chain *ch, ipfw_obj_ntlv *ntlv, uint32_t *kidx) { struct tid_info ti; struct table_config *tc; @@ -1646,7 +1589,7 @@ ipfw_ref_table(struct ip_fw_chain *ch, ipfw_obj_ntlv *ntlv, uint16_t *kidx) } void -ipfw_unref_table(struct ip_fw_chain *ch, uint16_t kidx) +ipfw_unref_table(struct ip_fw_chain *ch, uint32_t kidx) { struct namedobj_instance *ni; @@ -1655,7 +1598,7 @@ ipfw_unref_table(struct ip_fw_chain *ch, uint16_t kidx) IPFW_UH_WLOCK_ASSERT(ch); ni = CHAIN_TO_NI(ch); no = ipfw_objhash_lookup_kidx(ni, kidx); - KASSERT(no != NULL, ("Table with index %d not found", kidx)); + KASSERT(no != NULL, ("Table with index %u not found", kidx)); no->refcnt--; } @@ -1666,7 +1609,7 @@ ipfw_unref_table(struct ip_fw_chain *ch, uint16_t kidx) * Returns 1 if key was found. */ int -ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, uint16_t plen, +ipfw_lookup_table(struct ip_fw_chain *ch, uint32_t tbl, uint16_t plen, void *paddr, uint32_t *val) { struct table_info *ti; @@ -1870,12 +1813,12 @@ create_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, */ static int create_table_internal(struct ip_fw_chain *ch, struct tid_info *ti, - char *aname, ipfw_xtable_info *i, uint16_t *pkidx, int compat) + char *aname, ipfw_xtable_info *i, uint32_t *pkidx, int compat) { struct namedobj_instance *ni; struct table_config *tc, *tc_new, *tmp; struct table_algo *ta; - uint16_t kidx; + uint32_t kidx; ni = CHAIN_TO_NI(ch); @@ -1976,7 +1919,7 @@ ipfw_get_table_objhash(struct ip_fw_chain *ch) * Returns 0 on success. */ int -ipfw_export_table_ntlv(struct ip_fw_chain *ch, uint16_t kidx, +ipfw_export_table_ntlv(struct ip_fw_chain *ch, uint32_t kidx, struct sockopt_data *sd) { struct namedobj_instance *ni; @@ -2218,72 +2161,6 @@ dump_table_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3, return (da.error); } -/* - * Dumps all table data - * Data layout (version 0)(legacy): - * Request: [ ipfw_xtable ], size = IP_FW_TABLE_XGETSIZE() - * Reply: [ ipfw_xtable ipfw_table_xentry x N ] - * - * Returns 0 on success - */ -static int -dump_table_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3, - struct sockopt_data *sd) -{ - ipfw_xtable *xtbl; - struct tid_info ti; - struct table_config *tc; - struct table_algo *ta; - struct dump_args da; - size_t sz, count; - - xtbl = (ipfw_xtable *)ipfw_get_sopt_header(sd, sizeof(ipfw_xtable)); - if (xtbl == NULL) - return (EINVAL); - - memset(&ti, 0, sizeof(ti)); - ti.uidx = xtbl->tbl; - - IPFW_UH_RLOCK(ch); - if ((tc = find_table(CHAIN_TO_NI(ch), &ti)) == NULL) { - IPFW_UH_RUNLOCK(ch); - return (0); - } - count = table_get_count(ch, tc); - sz = count * sizeof(ipfw_table_xentry) + sizeof(ipfw_xtable); - - xtbl->cnt = count; - xtbl->size = sz; - xtbl->type = tc->no.subtype; - xtbl->tbl = ti.uidx; - - if (sd->valsize < sz) { - - /* - * Submitted buffer size is not enough. - * WE've already filled in @i structure with - * relevant table info including size, so we - * can return. Buffer will be flushed automatically. - */ - IPFW_UH_RUNLOCK(ch); - return (ENOMEM); - } - - /* Do the actual dump in eXtended format */ - memset(&da, 0, sizeof(da)); - da.ch = ch; - da.ti = KIDX_TO_TI(ch, tc->no.kidx); - da.tc = tc; - da.sd = sd; - - ta = tc->ta; - - ta->foreach(tc->astate, da.ti, dump_table_xentry, &da); - IPFW_UH_RUNLOCK(ch); - - return (0); -} - /* * Legacy function to retrieve number of items in table. */ @@ -2452,52 +2329,6 @@ dump_table_tentry(void *e, void *arg) return (0); } -/* - * Dumps table entry in eXtended format (v0). - */ -static int -dump_table_xentry(void *e, void *arg) -{ - struct dump_args *da; - struct table_config *tc; - struct table_algo *ta; - ipfw_table_xentry *xent; - ipfw_obj_tentry *tent; - struct table_value *pval; - int error; - - da = (struct dump_args *)arg; - - tc = da->tc; - ta = tc->ta; - - xent = (ipfw_table_xentry *)ipfw_get_sopt_space(da->sd, sizeof(*xent)); - /* Out of memory, returning */ - if (xent == NULL) - return (1); - xent->len = sizeof(ipfw_table_xentry); - xent->tbl = da->uidx; - - memset(&da->tent, 0, sizeof(da->tent)); - tent = &da->tent; - error = ta->dump_tentry(tc->astate, da->ti, e, tent); - if (error != 0) - return (error); - - /* Convert current format to previous one */ - xent->masklen = tent->masklen; - pval = get_table_value(da->ch, da->tc, da->tent.v.kidx); - xent->value = ipfw_export_table_value_legacy(pval); - /* Apply some hacks */ - if (tc->no.subtype == IPFW_TABLE_ADDR && tent->subtype == AF_INET) { - xent->k.addr6.s6_addr32[3] = tent->k.addr.s_addr; - xent->flags = IPFW_TCF_INET; - } else - memcpy(&xent->k, &tent->k, sizeof(xent->k)); - - return (0); -} - /* * Helper function to export table algo data * to tentry format before calling user function. @@ -2530,7 +2361,7 @@ prepare_table_tentry(void *e, void *arg) * Allow external consumers to read table entries in standard format. */ int -ipfw_foreach_table_tentry(struct ip_fw_chain *ch, uint16_t kidx, +ipfw_foreach_table_tentry(struct ip_fw_chain *ch, uint32_t kidx, ta_foreach_f *f, void *arg) { struct namedobj_instance *ni; @@ -2740,88 +2571,67 @@ list_table_algo(struct ip_fw_chain *ch, ip_fw3_opheader *op3, } static int -classify_srcdst(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) +classify_srcdst(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype) { + ipfw_insn_table *cmd; + /* Basic IPv4/IPv6 or u32 lookups */ - *puidx = cmd->arg1; - /* Assume ADDR by default */ - *ptype = IPFW_TABLE_ADDR; - int v; - - if (F_LEN(cmd) > F_INSN_SIZE(ipfw_insn_u32)) { - /* - * generic lookup. The key must be - * in 32bit big-endian format. - */ - v = ((ipfw_insn_u32 *)cmd)->d[1]; - switch (v) { - case 0: - case 1: - /* IPv4 src/dst */ - break; - case 2: - case 3: - /* src/dst port */ - *ptype = IPFW_TABLE_NUMBER; - break; - case 4: - /* uid/gid */ - *ptype = IPFW_TABLE_NUMBER; - break; - case 5: - /* jid */ - *ptype = IPFW_TABLE_NUMBER; - break; - case 6: - /* dscp */ - *ptype = IPFW_TABLE_NUMBER; - break; - } + cmd = insntod(cmd0, table); + *puidx = cmd->kidx; + switch(cmd0->arg1) { + case LOOKUP_DST_IP: + case LOOKUP_SRC_IP: + default: + /* IPv4 src/dst */ + *ptype = IPFW_TABLE_ADDR; + break; + case LOOKUP_DST_PORT: + case LOOKUP_SRC_PORT: + case LOOKUP_UID: + case LOOKUP_JAIL: + case LOOKUP_DSCP: + *ptype = IPFW_TABLE_NUMBER; + break; } - return (0); } static int -classify_via(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) +classify_via(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype) { ipfw_insn_if *cmdif; /* Interface table, possibly */ - cmdif = (ipfw_insn_if *)cmd; + cmdif = insntod(cmd0, if); if (cmdif->name[0] != '\1') return (1); *ptype = IPFW_TABLE_INTERFACE; - *puidx = cmdif->p.kidx; - + *puidx = cmdif->p.kidx; /* XXXAE */ return (0); } static int -classify_flow(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) +classify_flow(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype) { - *puidx = cmd->arg1; + *puidx = insntod(cmd0, table)->kidx; *ptype = IPFW_TABLE_FLOW; - return (0); } static void -update_arg1(ipfw_insn *cmd, uint16_t idx) +update_kidx(ipfw_insn *cmd0, uint32_t idx) { - cmd->arg1 = idx; + insntod(cmd0, table)->kidx = idx; } static void -update_via(ipfw_insn *cmd, uint16_t idx) +update_via(ipfw_insn *cmd0, uint32_t idx) { - ipfw_insn_if *cmdif; - cmdif = (ipfw_insn_if *)cmd; - cmdif->p.kidx = idx; + insntod(cmd0, if)->p.kidx= idx; } static int @@ -2843,7 +2653,7 @@ table_findbyname(struct ip_fw_chain *ch, struct tid_info *ti, /* XXX: sets-sets! */ static struct named_object * -table_findbykidx(struct ip_fw_chain *ch, uint16_t idx) +table_findbykidx(struct ip_fw_chain *ch, uint32_t idx) { struct namedobj_instance *ni; struct table_config *tc; @@ -2851,13 +2661,13 @@ table_findbykidx(struct ip_fw_chain *ch, uint16_t idx) IPFW_UH_WLOCK_ASSERT(ch); ni = CHAIN_TO_NI(ch); tc = (struct table_config *)ipfw_objhash_lookup_kidx(ni, idx); - KASSERT(tc != NULL, ("Table with index %d not found", idx)); + KASSERT(tc != NULL, ("Table with index %u not found", idx)); return (&tc->no); } static int -table_manage_sets(struct ip_fw_chain *ch, uint16_t set, uint8_t new_set, +table_manage_sets(struct ip_fw_chain *ch, uint32_t set, uint8_t new_set, enum ipfw_sets_cmd cmd) { @@ -2902,7 +2712,7 @@ table_manage_sets(struct ip_fw_chain *ch, uint16_t set, uint8_t new_set, * so it should be called first. */ static int -table_manage_sets_all(struct ip_fw_chain *ch, uint16_t set, uint8_t new_set, +table_manage_sets_all(struct ip_fw_chain *ch, uint32_t set, uint8_t new_set, enum ipfw_sets_cmd cmd) { @@ -2932,7 +2742,7 @@ static struct opcode_obj_rewrite opcodes[] = { .opcode = O_IP_SRC_LOOKUP, .etlv = IPFW_TLV_TBL_NAME, .classifier = classify_srcdst, - .update = update_arg1, + .update = update_kidx, .find_byname = table_findbyname, .find_bykidx = table_findbykidx, .create_object = create_table_compat, @@ -2942,7 +2752,7 @@ static struct opcode_obj_rewrite opcodes[] = { .opcode = O_IP_DST_LOOKUP, .etlv = IPFW_TLV_TBL_NAME, .classifier = classify_srcdst, - .update = update_arg1, + .update = update_kidx, .find_byname = table_findbyname, .find_bykidx = table_findbykidx, .create_object = create_table_compat, @@ -2952,7 +2762,7 @@ static struct opcode_obj_rewrite opcodes[] = { .opcode = O_IP_FLOW_LOOKUP, .etlv = IPFW_TLV_TBL_NAME, .classifier = classify_flow, - .update = update_arg1, + .update = update_kidx, .find_byname = table_findbyname, .find_bykidx = table_findbykidx, .create_object = create_table_compat, @@ -3017,7 +2827,7 @@ ipfw_switch_tables_namespace(struct ip_fw_chain *ch, unsigned int sets) struct ip_fw *rule; ipfw_insn *cmd; int cmdlen, i, l; - uint16_t kidx; + uint32_t kidx; uint8_t subtype; IPFW_UH_WLOCK(ch); @@ -3276,22 +3086,19 @@ unlink_table(struct ip_fw_chain *ch, struct table_config *tc) } static struct ipfw_sopt_handler scodes[] = { - { IP_FW_TABLE_XCREATE, 0, HDIR_SET, create_table }, - { IP_FW_TABLE_XDESTROY, 0, HDIR_SET, flush_table_v0 }, - { IP_FW_TABLE_XFLUSH, 0, HDIR_SET, flush_table_v0 }, - { IP_FW_TABLE_XMODIFY, 0, HDIR_BOTH, modify_table }, - { IP_FW_TABLE_XINFO, 0, HDIR_GET, describe_table }, - { IP_FW_TABLES_XLIST, 0, HDIR_GET, list_tables }, - { IP_FW_TABLE_XLIST, 0, HDIR_GET, dump_table_v0 }, - { IP_FW_TABLE_XLIST, 1, HDIR_GET, dump_table_v1 }, - { IP_FW_TABLE_XADD, 0, HDIR_BOTH, manage_table_ent_v0 }, - { IP_FW_TABLE_XADD, 1, HDIR_BOTH, manage_table_ent_v1 }, - { IP_FW_TABLE_XDEL, 0, HDIR_BOTH, manage_table_ent_v0 }, - { IP_FW_TABLE_XDEL, 1, HDIR_BOTH, manage_table_ent_v1 }, - { IP_FW_TABLE_XFIND, 0, HDIR_GET, find_table_entry }, - { IP_FW_TABLE_XSWAP, 0, HDIR_SET, swap_table }, - { IP_FW_TABLES_ALIST, 0, HDIR_GET, list_table_algo }, - { IP_FW_TABLE_XGETSIZE, 0, HDIR_GET, get_table_size }, + { IP_FW_TABLE_XCREATE, IP_FW3_OPVER, HDIR_SET, create_table }, + { IP_FW_TABLE_XDESTROY, IP_FW3_OPVER, HDIR_SET, flush_table_v0 }, + { IP_FW_TABLE_XFLUSH, IP_FW3_OPVER, HDIR_SET, flush_table_v0 }, + { IP_FW_TABLE_XMODIFY, IP_FW3_OPVER, HDIR_BOTH, modify_table }, + { IP_FW_TABLE_XINFO, IP_FW3_OPVER, HDIR_GET, describe_table }, + { IP_FW_TABLES_XLIST, IP_FW3_OPVER, HDIR_GET, list_tables }, + { IP_FW_TABLE_XLIST, IP_FW3_OPVER, HDIR_GET, dump_table_v1 }, + { IP_FW_TABLE_XADD, IP_FW3_OPVER, HDIR_BOTH, manage_table_ent_v1 }, + { IP_FW_TABLE_XDEL, IP_FW3_OPVER, HDIR_BOTH, manage_table_ent_v1 }, + { IP_FW_TABLE_XFIND, IP_FW3_OPVER, HDIR_GET, find_table_entry }, + { IP_FW_TABLE_XSWAP, IP_FW3_OPVER, HDIR_SET, swap_table }, + { IP_FW_TABLES_ALIST, IP_FW3_OPVER, HDIR_GET, list_table_algo }, + { IP_FW_TABLE_XGETSIZE, IP_FW3_OPVER, HDIR_GET, get_table_size }, }; static int diff --git a/sys/netpfil/ipfw/ip_fw_table.h b/sys/netpfil/ipfw/ip_fw_table.h index d6578482fb3..8435f3ab219 100644 --- a/sys/netpfil/ipfw/ip_fw_table.h +++ b/sys/netpfil/ipfw/ip_fw_table.h @@ -181,7 +181,7 @@ int ipfw_rewrite_table_uidx(struct ip_fw_chain *chain, struct rule_check_info *ci); int ipfw_mark_table_kidx(struct ip_fw_chain *chain, struct ip_fw *rule, uint32_t *bmask); -int ipfw_export_table_ntlv(struct ip_fw_chain *ch, uint16_t kidx, +int ipfw_export_table_ntlv(struct ip_fw_chain *ch, uint32_t kidx, struct sockopt_data *sd); void ipfw_unref_rule_tables(struct ip_fw_chain *chain, struct ip_fw *rule); struct namedobj_instance *ipfw_get_table_objhash(struct ip_fw_chain *ch); @@ -191,7 +191,7 @@ int ipfw_move_tables_sets(struct ip_fw_chain *ch, ipfw_range_tlv *rt, uint32_t new_set); void ipfw_swap_tables_sets(struct ip_fw_chain *ch, uint32_t old_set, uint32_t new_set, int mv); -int ipfw_foreach_table_tentry(struct ip_fw_chain *ch, uint16_t kidx, +int ipfw_foreach_table_tentry(struct ip_fw_chain *ch, uint32_t kidx, ta_foreach_f f, void *arg); /* internal functions */ diff --git a/sys/netpfil/ipfw/ip_fw_table_value.c b/sys/netpfil/ipfw/ip_fw_table_value.c index d60fc34f39e..830732ab3dd 100644 --- a/sys/netpfil/ipfw/ip_fw_table_value.c +++ b/sys/netpfil/ipfw/ip_fw_table_value.c @@ -68,7 +68,7 @@ static int list_table_values(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd); static struct ipfw_sopt_handler scodes[] = { - { IP_FW_TABLE_VLIST, 0, HDIR_GET, list_table_values }, + { IP_FW_TABLE_VLIST, IP_FW3_OPVER, HDIR_GET, list_table_values }, }; #define CHAIN_TO_VI(chain) (CHAIN_TO_TCFG(chain)->valhash) @@ -364,10 +364,10 @@ rollback_table_values(struct tableop_state *ts) */ static int alloc_table_vidx(struct ip_fw_chain *ch, struct tableop_state *ts, - struct namedobj_instance *vi, uint16_t *pvidx) + struct namedobj_instance *vi, uint32_t *pvidx) { int error, vlimit; - uint16_t vidx; + uint32_t vidx; IPFW_UH_WLOCK_ASSERT(ch); @@ -480,8 +480,7 @@ ipfw_link_table_values(struct ip_fw_chain *ch, struct tableop_state *ts) struct namedobj_instance *vi; struct table_config *tc; struct tentry_info *tei, *ptei; - uint32_t count, vlimit; - uint16_t vidx; + uint32_t count, vidx, vlimit; struct table_val_link *ptv; struct table_value tval, *pval; diff --git a/sys/netpfil/ipfw/ip_fw_yandex.c b/sys/netpfil/ipfw/ip_fw_yandex.c index e25820e3938..7d219dc5212 100644 --- a/sys/netpfil/ipfw/ip_fw_yandex.c +++ b/sys/netpfil/ipfw/ip_fw_yandex.c @@ -48,8 +48,8 @@ __FBSDID("$FreeBSD$"); #include -static VNET_DEFINE(uint16_t, srcprjid_eid) = 0; -static VNET_DEFINE(uint16_t, dstprjid_eid) = 0; +static VNET_DEFINE(uint32_t, srcprjid_eid) = 0; +static VNET_DEFINE(uint32_t, dstprjid_eid) = 0; #define V_srcprjid_eid VNET(srcprjid_eid) #define V_dstprjid_eid VNET(dstprjid_eid) @@ -80,11 +80,11 @@ ipfw_prjid(struct ip_fw_chain *chain, struct ip_fw_args *args, *done = 0; /* try next rule */ if (cmd->opcode != O_EXTERNAL_ACTION || ( - cmd->arg1 != V_srcprjid_eid && - cmd->arg1 != V_dstprjid_eid)) + insntod(cmd, kidx)->kidx != V_srcprjid_eid && + insntod(cmd, kidx)->kidx != V_dstprjid_eid)) return (IP_FW_DENY); - if (cmd->arg1 == V_srcprjid_eid) + if (insntod(cmd, kidx)->kidx == V_srcprjid_eid) paddr = &args->f_id.src_ip6; else paddr = &args->f_id.dst_ip6; diff --git a/sys/netpfil/ipfw/nat64/ip_fw_nat64.h b/sys/netpfil/ipfw/nat64/ip_fw_nat64.h index bfcf57ab9b3..4d5039a364f 100644 --- a/sys/netpfil/ipfw/nat64/ip_fw_nat64.h +++ b/sys/netpfil/ipfw/nat64/ip_fw_nat64.h @@ -56,4 +56,52 @@ void nat64lsn_uninit(struct ip_fw_chain *ch, int last); int nat64clat_init(struct ip_fw_chain *ch, int first); void nat64clat_uninit(struct ip_fw_chain *ch, int last); +#define NAT64_DEFINE_OPCODE_REWRITER(mod, name, ops) \ +static int \ +mod ## _classify(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype) \ +{ \ + ipfw_insn *icmd; \ + icmd = cmd0 - F_LEN(cmd0); \ + if (icmd->opcode != O_EXTERNAL_ACTION || \ + insntod(icmd, kidx)->kidx != V_ ## mod ## _eid) \ + return (1); \ + *puidx = insntod(cmd0, kidx)->kidx; \ + *ptype = 0; \ + return (0); \ +} \ +static void \ +mod ## _update_kidx(ipfw_insn *cmd0, uint32_t idx) \ +{ \ + insntod(cmd0, kidx)->kidx = idx; \ +} \ +static int \ +mod ## _findbyname(struct ip_fw_chain *ch, struct tid_info *ti, \ + struct named_object **pno) \ +{ \ + return (ipfw_objhash_find_type(CHAIN_TO_SRV(ch), ti, \ + IPFW_TLV_## name ## _NAME, pno)); \ +} \ +static struct named_object * \ +mod ## _findbykidx(struct ip_fw_chain *ch, uint32_t idx) \ +{ \ + struct namedobj_instance *ni; \ + struct named_object *no; \ + IPFW_UH_WLOCK_ASSERT(ch); \ + ni = CHAIN_TO_SRV(ch); \ + no = ipfw_objhash_lookup_kidx(ni, idx); \ + KASSERT(no != NULL, ("NAT with index %u not found", idx)); \ + return (no); \ +} \ +static struct opcode_obj_rewrite ops[] = { \ + { \ + .opcode = O_EXTERNAL_INSTANCE, \ + .etlv = IPFW_TLV_EACTION /* just show it isn't table */,\ + .classifier = mod ## _classify, \ + .update = mod ## _update_kidx, \ + .find_byname = mod ## _findbyname, \ + .find_bykidx = mod ## _findbykidx, \ + .manage_sets = mod ## _manage_sets, \ + }, \ +} + #endif /* _IP_FW_NAT64_H_ */ diff --git a/sys/netpfil/ipfw/nat64/nat64clat.c b/sys/netpfil/ipfw/nat64/nat64clat.c index e9c962874b1..25f5d4b6a39 100644 --- a/sys/netpfil/ipfw/nat64/nat64clat.c +++ b/sys/netpfil/ipfw/nat64/nat64clat.c @@ -1,8 +1,9 @@ /*- - * Copyright (c) 2015-2016 Yandex LLC - * Copyright (c) 2015-2016 Andrey V. Elsukov + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2015-2020 Yandex LLC + * Copyright (c) 2015-2020 Andrey V. Elsukov * Copyright (c) 2019 Boris N. Lytochkin - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -61,7 +62,7 @@ __FBSDID("$FreeBSD$"); #include "nat64clat.h" #define NAT64_LOOKUP(chain, cmd) \ - (struct nat64clat_cfg *)SRV_OBJECT((chain), (cmd)->arg1) + (struct nat64clat_cfg *)SRV_OBJECT((chain), insntod(cmd, kidx)->kidx) static void nat64clat_log(struct pfloghdr *plog, struct mbuf *m, sa_family_t family, @@ -205,16 +206,16 @@ int ipfw_nat64clat(struct ip_fw_chain *chain, struct ip_fw_args *args, ipfw_insn *cmd, int *done) { - ipfw_insn *icmd; struct nat64clat_cfg *cfg; + ipfw_insn *icmd; int ret; IPFW_RLOCK_ASSERT(chain); *done = 0; /* try next rule if not matched */ - icmd = cmd + 1; + icmd = cmd + F_LEN(cmd); if (cmd->opcode != O_EXTERNAL_ACTION || - cmd->arg1 != V_nat64clat_eid || + insntod(cmd, kidx)->kidx != V_nat64clat_eid || icmd->opcode != O_EXTERNAL_INSTANCE || (cfg = NAT64_LOOKUP(chain, icmd)) == NULL) return (0); diff --git a/sys/netpfil/ipfw/nat64/nat64clat.h b/sys/netpfil/ipfw/nat64/nat64clat.h index bd0464684b8..6ac554cd263 100644 --- a/sys/netpfil/ipfw/nat64/nat64clat.h +++ b/sys/netpfil/ipfw/nat64/nat64clat.h @@ -1,8 +1,9 @@ /*- - * Copyright (c) 2015-2016 Yandex LLC - * Copyright (c) 2015-2016 Andrey V. Elsukov + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2015-2020 Yandex LLC + * Copyright (c) 2015-2020 Andrey V. Elsukov * Copyright (c) 2019 Boris N. Lytochkin - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -42,7 +43,7 @@ struct nat64clat_cfg { char name[64]; }; -VNET_DECLARE(uint16_t, nat64clat_eid); +VNET_DECLARE(uint32_t, nat64clat_eid); #define V_nat64clat_eid VNET(nat64clat_eid) #define IPFW_TLV_NAT64CLAT_NAME IPFW_TLV_EACTION_NAME(V_nat64clat_eid) diff --git a/sys/netpfil/ipfw/nat64/nat64clat_control.c b/sys/netpfil/ipfw/nat64/nat64clat_control.c index 2baa96f4ca2..eb114b5f5bb 100644 --- a/sys/netpfil/ipfw/nat64/nat64clat_control.c +++ b/sys/netpfil/ipfw/nat64/nat64clat_control.c @@ -1,9 +1,10 @@ /*- - * Copyright (c) 2015-2016 Yandex LLC - * Copyright (c) 2015-2016 Andrey V. Elsukov + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2015-2020 Yandex LLC + * Copyright (c) 2015-2020 Andrey V. Elsukov * Copyright (c) 2015 Alexander V. Chernikov * Copyright (c) 2019 Boris N. Lytochkin - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -64,7 +65,7 @@ __FBSDID("$FreeBSD$"); #include "nat64clat.h" -VNET_DEFINE(uint16_t, nat64clat_eid) = 0; +VNET_DEFINE(uint32_t, nat64clat_eid) = 0; static struct nat64clat_cfg *nat64clat_alloc_config(const char *name, uint8_t set); @@ -489,82 +490,23 @@ nat64clat_reset_stats(struct ip_fw_chain *ch, ip_fw3_opheader *op, } static struct ipfw_sopt_handler scodes[] = { - - { IP_FW_NAT64CLAT_CREATE, 0, HDIR_SET, nat64clat_create }, - { IP_FW_NAT64CLAT_DESTROY,0, HDIR_SET, nat64clat_destroy }, - { IP_FW_NAT64CLAT_CONFIG, 0, HDIR_BOTH, nat64clat_config }, - { IP_FW_NAT64CLAT_LIST, 0, HDIR_GET, nat64clat_list }, - { IP_FW_NAT64CLAT_STATS, 0, HDIR_GET, nat64clat_stats }, - { IP_FW_NAT64CLAT_RESET_STATS,0, HDIR_SET, nat64clat_reset_stats }, + { IP_FW_NAT64CLAT_CREATE, IP_FW3_OPVER, HDIR_SET, nat64clat_create }, + { IP_FW_NAT64CLAT_DESTROY, IP_FW3_OPVER, HDIR_SET, nat64clat_destroy }, + { IP_FW_NAT64CLAT_CONFIG, IP_FW3_OPVER, HDIR_BOTH, nat64clat_config }, + { IP_FW_NAT64CLAT_LIST, IP_FW3_OPVER, HDIR_GET, nat64clat_list }, + { IP_FW_NAT64CLAT_STATS, IP_FW3_OPVER, HDIR_GET, nat64clat_stats }, + { IP_FW_NAT64CLAT_RESET_STATS, IP_FW3_OPVER, HDIR_SET, nat64clat_reset_stats }, }; static int -nat64clat_classify(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) +nat64clat_manage_sets(struct ip_fw_chain *ch, uint32_t set, + uint8_t new_set, enum ipfw_sets_cmd cmd) { - ipfw_insn *icmd; - icmd = cmd - 1; - if (icmd->opcode != O_EXTERNAL_ACTION || - icmd->arg1 != V_nat64clat_eid) - return (1); - - *puidx = cmd->arg1; - *ptype = 0; - return (0); + return (ipfw_obj_manage_sets(CHAIN_TO_SRV(ch), + IPFW_TLV_NAT64CLAT_NAME, set, new_set, cmd)); } - -static void -nat64clat_update_arg1(ipfw_insn *cmd, uint16_t idx) -{ - - cmd->arg1 = idx; -} - -static int -nat64clat_findbyname(struct ip_fw_chain *ch, struct tid_info *ti, - struct named_object **pno) -{ - int err; - - err = ipfw_objhash_find_type(CHAIN_TO_SRV(ch), ti, - IPFW_TLV_NAT64CLAT_NAME, pno); - return (err); -} - -static struct named_object * -nat64clat_findbykidx(struct ip_fw_chain *ch, uint16_t idx) -{ - struct namedobj_instance *ni; - struct named_object *no; - - IPFW_UH_WLOCK_ASSERT(ch); - ni = CHAIN_TO_SRV(ch); - no = ipfw_objhash_lookup_kidx(ni, idx); - KASSERT(no != NULL, ("NAT with index %d not found", idx)); - - return (no); -} - -static int -nat64clat_manage_sets(struct ip_fw_chain *ch, uint16_t set, uint8_t new_set, - enum ipfw_sets_cmd cmd) -{ - - return (ipfw_obj_manage_sets(CHAIN_TO_SRV(ch), IPFW_TLV_NAT64CLAT_NAME, - set, new_set, cmd)); -} - -static struct opcode_obj_rewrite opcodes[] = { - { - .opcode = O_EXTERNAL_INSTANCE, - .etlv = IPFW_TLV_EACTION /* just show it isn't table */, - .classifier = nat64clat_classify, - .update = nat64clat_update_arg1, - .find_byname = nat64clat_findbyname, - .find_bykidx = nat64clat_findbykidx, - .manage_sets = nat64clat_manage_sets, - }, -}; +NAT64_DEFINE_OPCODE_REWRITER(nat64clat, NAT64CLAT, opcodes); static int destroy_config_cb(struct namedobj_instance *ni, struct named_object *no, diff --git a/sys/netpfil/ipfw/nat64/nat64lsn.c b/sys/netpfil/ipfw/nat64/nat64lsn.c index a77a690d8d2..4cd9caaa56d 100644 --- a/sys/netpfil/ipfw/nat64/nat64lsn.c +++ b/sys/netpfil/ipfw/nat64/nat64lsn.c @@ -1,9 +1,9 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2015-2019 Yandex LLC + * Copyright (c) 2015-2020 Yandex LLC * Copyright (c) 2015 Alexander V. Chernikov - * Copyright (c) 2016-2019 Andrey V. Elsukov + * Copyright (c) 2016-2020 Andrey V. Elsukov * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -88,7 +88,7 @@ static uma_zone_t nat64lsn_job_zone; static void nat64lsn_periodic(void *data); #define PERIODIC_DELAY 4 #define NAT64_LOOKUP(chain, cmd) \ - (struct nat64lsn_instance *)SRV_OBJECT((chain), (cmd)->arg1) + (struct nat64lsn_instance *)SRV_OBJECT((chain), insntod(cmd, kidx)->kidx) /* * Delayed job queue, used to create new hosts * and new portgroups @@ -1733,9 +1733,9 @@ ipfw_nat64lsn(struct ip_fw_chain *ch, struct ip_fw_args *args, IPFW_RLOCK_ASSERT(ch); *done = 0; /* continue the search in case of failure */ - icmd = cmd + 1; + icmd = cmd + F_LEN(cmd); if (cmd->opcode != O_EXTERNAL_ACTION || - cmd->arg1 != V_nat64lsn_eid || + insntod(cmd, kidx)->kidx != V_nat64lsn_eid || icmd->opcode != O_EXTERNAL_INSTANCE || (i = NAT64_LOOKUP(ch, icmd)) == NULL) return (IP_FW_DENY); diff --git a/sys/netpfil/ipfw/nat64/nat64lsn.h b/sys/netpfil/ipfw/nat64/nat64lsn.h index 68c449da6d9..6b7d9e02a91 100644 --- a/sys/netpfil/ipfw/nat64/nat64lsn.h +++ b/sys/netpfil/ipfw/nat64/nat64lsn.h @@ -1,9 +1,9 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2015-2019 Yandex LLC + * Copyright (c) 2015-2020 Yandex LLC * Copyright (c) 2015 Alexander V. Chernikov - * Copyright (c) 2016-2019 Andrey V. Elsukov + * Copyright (c) 2016-2020 Andrey V. Elsukov * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -198,7 +198,7 @@ struct nat64lsn_host { * NOTE: lock order - ALIAS_LOCK() first, then HOST_LOCK(). */ -VNET_DECLARE(uint16_t, nat64lsn_eid); +VNET_DECLARE(uint32_t, nat64lsn_eid); #define V_nat64lsn_eid VNET(nat64lsn_eid) #define IPFW_TLV_NAT64LSN_NAME IPFW_TLV_EACTION_NAME(V_nat64lsn_eid) diff --git a/sys/netpfil/ipfw/nat64/nat64lsn_control.c b/sys/netpfil/ipfw/nat64/nat64lsn_control.c index ecdcb5165d1..6cf42c5c7e0 100644 --- a/sys/netpfil/ipfw/nat64/nat64lsn_control.c +++ b/sys/netpfil/ipfw/nat64/nat64lsn_control.c @@ -1,10 +1,9 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2015-2019 Yandex LLC + * Copyright (c) 2015-2020 Yandex LLC * Copyright (c) 2015 Alexander V. Chernikov - * Copyright (c) 2016-2019 Andrey V. Elsukov - * All rights reserved. + * Copyright (c) 2016-2020 Andrey V. Elsukov * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -60,7 +59,7 @@ __FBSDID("$FreeBSD$"); #include "nat64lsn.h" -VNET_DEFINE(uint16_t, nat64lsn_eid) = 0; +VNET_DEFINE(uint32_t, nat64lsn_eid) = 0; static struct nat64lsn_instance * nat64lsn_find(struct namedobj_instance *ni, const char *name, uint8_t set) @@ -566,7 +565,7 @@ nat64lsn_reset_stats(struct ip_fw_chain *ch, ip_fw3_opheader *op, * ipfw_nat64lsn_state x count, ... ] ] */ static int -nat64lsn_export_states_v1(struct nat64lsn_cfg *cfg, union nat64lsn_pgidx *idx, +nat64lsn_export_states(struct nat64lsn_cfg *cfg, union nat64lsn_pgidx *idx, struct nat64lsn_pg *pg, struct sockopt_data *sd, uint32_t *ret_count) { ipfw_nat64lsn_state_v1 *s; @@ -678,24 +677,6 @@ nat64lsn_get_pg_byidx(struct nat64lsn_cfg *cfg, union nat64lsn_pgidx *idx) return (NULL); } -/* - * Lists nat64lsn states. - * Data layout (v0): - * Request: [ ipfw_obj_header ipfw_obj_data [ uint64_t ]] - * Reply: [ ipfw_obj_header ipfw_obj_data [ - * ipfw_nat64lsn_stg ipfw_nat64lsn_state x N] ] - * - * Returns 0 on success - */ -static int -nat64lsn_states_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3, - struct sockopt_data *sd) -{ - - /* TODO: implement states listing for old ipfw(8) binaries */ - return (EOPNOTSUPP); -} - /* * Lists nat64lsn states. * Data layout (v1)(current): @@ -706,7 +687,7 @@ nat64lsn_states_v0(struct ip_fw_chain *ch, ip_fw3_opheader *op3, * Returns 0 on success */ static int -nat64lsn_states_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3, +nat64lsn_states(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd) { ipfw_obj_header *oh; @@ -779,7 +760,7 @@ nat64lsn_states_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3, pg = nat64lsn_get_pg_byidx(cfg, &idx); if (pg != NULL) { count = 0; - ret = nat64lsn_export_states_v1(cfg, &idx, pg, + ret = nat64lsn_export_states(cfg, &idx, pg, sd, &count); if (ret != 0) break; @@ -826,63 +807,15 @@ nat64lsn_states_v1(struct ip_fw_chain *ch, ip_fw3_opheader *op3, } static struct ipfw_sopt_handler scodes[] = { - { IP_FW_NAT64LSN_CREATE, 0, HDIR_BOTH, nat64lsn_create }, - { IP_FW_NAT64LSN_DESTROY,0, HDIR_SET, nat64lsn_destroy }, - { IP_FW_NAT64LSN_CONFIG, 0, HDIR_BOTH, nat64lsn_config }, - { IP_FW_NAT64LSN_LIST, 0, HDIR_GET, nat64lsn_list }, - { IP_FW_NAT64LSN_STATS, 0, HDIR_GET, nat64lsn_stats }, - { IP_FW_NAT64LSN_RESET_STATS,0, HDIR_SET, nat64lsn_reset_stats }, - { IP_FW_NAT64LSN_LIST_STATES,0, HDIR_GET, nat64lsn_states_v0 }, - { IP_FW_NAT64LSN_LIST_STATES,1, HDIR_GET, nat64lsn_states_v1 }, + { IP_FW_NAT64LSN_CREATE, IP_FW3_OPVER, HDIR_BOTH, nat64lsn_create }, + { IP_FW_NAT64LSN_DESTROY, IP_FW3_OPVER, HDIR_SET, nat64lsn_destroy }, + { IP_FW_NAT64LSN_CONFIG, IP_FW3_OPVER, HDIR_BOTH, nat64lsn_config }, + { IP_FW_NAT64LSN_LIST, IP_FW3_OPVER, HDIR_GET, nat64lsn_list }, + { IP_FW_NAT64LSN_STATS, IP_FW3_OPVER, HDIR_GET, nat64lsn_stats }, + { IP_FW_NAT64LSN_RESET_STATS, IP_FW3_OPVER, HDIR_SET, nat64lsn_reset_stats }, + { IP_FW_NAT64LSN_LIST_STATES, IP_FW3_OPVER, HDIR_GET, nat64lsn_states }, }; -static int -nat64lsn_classify(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) -{ - ipfw_insn *icmd; - - icmd = cmd - 1; - if (icmd->opcode != O_EXTERNAL_ACTION || - icmd->arg1 != V_nat64lsn_eid) - return (1); - - *puidx = cmd->arg1; - *ptype = 0; - return (0); -} - -static void -nat64lsn_update_arg1(ipfw_insn *cmd, uint16_t idx) -{ - - cmd->arg1 = idx; -} - -static int -nat64lsn_findbyname(struct ip_fw_chain *ch, struct tid_info *ti, - struct named_object **pno) -{ - int err; - - err = ipfw_objhash_find_type(CHAIN_TO_SRV(ch), ti, - IPFW_TLV_NAT64LSN_NAME, pno); - return (err); -} - -static struct named_object * -nat64lsn_findbykidx(struct ip_fw_chain *ch, uint16_t idx) -{ - struct namedobj_instance *ni; - struct named_object *no; - - IPFW_UH_WLOCK_ASSERT(ch); - ni = CHAIN_TO_SRV(ch); - no = ipfw_objhash_lookup_kidx(ni, idx); - KASSERT(no != NULL, ("NAT64LSN with index %d not found", idx)); - - return (no); -} - #define NAT64LSN_ARE_EQUAL(v) (cfg0->v == cfg1->v) static int nat64lsn_cmp_configs(struct nat64lsn_cfg *cfg0, struct nat64lsn_cfg *cfg1) @@ -953,7 +886,7 @@ nat64lsn_swap_sets_cb(struct namedobj_instance *ni, struct named_object *no, } static int -nat64lsn_manage_sets(struct ip_fw_chain *ch, uint16_t set, uint8_t new_set, +nat64lsn_manage_sets(struct ip_fw_chain *ch, uint32_t set, uint8_t new_set, enum ipfw_sets_cmd cmd) { uint8_t sets[2]; @@ -967,18 +900,7 @@ nat64lsn_manage_sets(struct ip_fw_chain *ch, uint16_t set, uint8_t new_set, return (ipfw_obj_manage_sets(CHAIN_TO_SRV(ch), IPFW_TLV_NAT64LSN_NAME, set, new_set, cmd)); } - -static struct opcode_obj_rewrite opcodes[] = { - { - .opcode = O_EXTERNAL_INSTANCE, - .etlv = IPFW_TLV_EACTION /* just show it isn't table */, - .classifier = nat64lsn_classify, - .update = nat64lsn_update_arg1, - .find_byname = nat64lsn_findbyname, - .find_bykidx = nat64lsn_findbykidx, - .manage_sets = nat64lsn_manage_sets, - }, -}; +NAT64_DEFINE_OPCODE_REWRITER(nat64lsn, NAT64LSN, opcodes); static int destroy_config_cb(struct namedobj_instance *ni, struct named_object *no, diff --git a/sys/netpfil/ipfw/nat64/nat64stl.c b/sys/netpfil/ipfw/nat64/nat64stl.c index 0f0228dc7a1..0781ebd45db 100644 --- a/sys/netpfil/ipfw/nat64/nat64stl.c +++ b/sys/netpfil/ipfw/nat64/nat64stl.c @@ -1,7 +1,8 @@ /*- - * Copyright (c) 2015-2016 Yandex LLC - * Copyright (c) 2015-2016 Andrey V. Elsukov - * All rights reserved. + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2015-2020 Yandex LLC + * Copyright (c) 2015-2020 Andrey V. Elsukov * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -60,7 +61,7 @@ __FBSDID("$FreeBSD$"); #include "nat64stl.h" #define NAT64_LOOKUP(chain, cmd) \ - (struct nat64stl_cfg *)SRV_OBJECT((chain), (cmd)->arg1) + (struct nat64stl_cfg *)SRV_OBJECT((chain), insntod(cmd, kidx)->kidx) static void nat64stl_log(struct pfloghdr *plog, struct mbuf *m, sa_family_t family, @@ -206,8 +207,8 @@ int ipfw_nat64stl(struct ip_fw_chain *chain, struct ip_fw_args *args, ipfw_insn *cmd, int *done) { - ipfw_insn *icmd; struct nat64stl_cfg *cfg; + ipfw_insn *icmd; in_addr_t dst4; uint32_t tablearg; int ret; @@ -215,9 +216,9 @@ ipfw_nat64stl(struct ip_fw_chain *chain, struct ip_fw_args *args, IPFW_RLOCK_ASSERT(chain); *done = 0; /* try next rule if not matched */ - icmd = cmd + 1; + icmd = cmd + F_LEN(cmd); if (cmd->opcode != O_EXTERNAL_ACTION || - cmd->arg1 != V_nat64stl_eid || + insntod(cmd, kidx)->kidx != V_nat64stl_eid || icmd->opcode != O_EXTERNAL_INSTANCE || (cfg = NAT64_LOOKUP(chain, icmd)) == NULL) return (0); diff --git a/sys/netpfil/ipfw/nat64/nat64stl.h b/sys/netpfil/ipfw/nat64/nat64stl.h index 99bdc5218dc..20390cfe239 100644 --- a/sys/netpfil/ipfw/nat64/nat64stl.h +++ b/sys/netpfil/ipfw/nat64/nat64stl.h @@ -1,7 +1,8 @@ /*- - * Copyright (c) 2015-2016 Yandex LLC - * Copyright (c) 2015-2016 Andrey V. Elsukov - * All rights reserved. + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2015-2020 Yandex LLC + * Copyright (c) 2015-2020 Andrey V. Elsukov * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -36,8 +37,8 @@ struct nat64stl_cfg { struct named_object no; - uint16_t map64; /* table with 6to4 mapping */ - uint16_t map46; /* table with 4to6 mapping */ + uint32_t map64; /* table with 6to4 mapping */ + uint32_t map46; /* table with 4to6 mapping */ struct nat64_config base; #define NAT64STL_KIDX 0x0100 @@ -47,7 +48,7 @@ struct nat64stl_cfg { char name[64]; }; -VNET_DECLARE(uint16_t, nat64stl_eid); +VNET_DECLARE(uint32_t, nat64stl_eid); #define V_nat64stl_eid VNET(nat64stl_eid) #define IPFW_TLV_NAT64STL_NAME IPFW_TLV_EACTION_NAME(V_nat64stl_eid) diff --git a/sys/netpfil/ipfw/nat64/nat64stl_control.c b/sys/netpfil/ipfw/nat64/nat64stl_control.c index ab211c795d7..15129e1b0d6 100644 --- a/sys/netpfil/ipfw/nat64/nat64stl_control.c +++ b/sys/netpfil/ipfw/nat64/nat64stl_control.c @@ -1,8 +1,9 @@ /*- - * Copyright (c) 2015-2016 Yandex LLC - * Copyright (c) 2015-2016 Andrey V. Elsukov + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2015-2020 Yandex LLC + * Copyright (c) 2015-2020 Andrey V. Elsukov * Copyright (c) 2015 Alexander V. Chernikov - * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -63,7 +64,7 @@ __FBSDID("$FreeBSD$"); #include "nat64stl.h" -VNET_DEFINE(uint16_t, nat64stl_eid) = 0; +VNET_DEFINE(uint32_t, nat64stl_eid) = 0; static struct nat64stl_cfg *nat64stl_alloc_config(const char *name, uint8_t set); @@ -492,82 +493,23 @@ nat64stl_reset_stats(struct ip_fw_chain *ch, ip_fw3_opheader *op, } static struct ipfw_sopt_handler scodes[] = { - - { IP_FW_NAT64STL_CREATE, 0, HDIR_SET, nat64stl_create }, - { IP_FW_NAT64STL_DESTROY,0, HDIR_SET, nat64stl_destroy }, - { IP_FW_NAT64STL_CONFIG, 0, HDIR_BOTH, nat64stl_config }, - { IP_FW_NAT64STL_LIST, 0, HDIR_GET, nat64stl_list }, - { IP_FW_NAT64STL_STATS, 0, HDIR_GET, nat64stl_stats }, - { IP_FW_NAT64STL_RESET_STATS,0, HDIR_SET, nat64stl_reset_stats }, + { IP_FW_NAT64STL_CREATE, IP_FW3_OPVER, HDIR_SET, nat64stl_create }, + { IP_FW_NAT64STL_DESTROY, IP_FW3_OPVER, HDIR_SET, nat64stl_destroy }, + { IP_FW_NAT64STL_CONFIG, IP_FW3_OPVER, HDIR_BOTH,nat64stl_config }, + { IP_FW_NAT64STL_LIST, IP_FW3_OPVER, HDIR_GET, nat64stl_list }, + { IP_FW_NAT64STL_STATS, IP_FW3_OPVER, HDIR_GET, nat64stl_stats }, + { IP_FW_NAT64STL_RESET_STATS, IP_FW3_OPVER, HDIR_SET, nat64stl_reset_stats }, }; static int -nat64stl_classify(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) -{ - ipfw_insn *icmd; - - icmd = cmd - 1; - if (icmd->opcode != O_EXTERNAL_ACTION || - icmd->arg1 != V_nat64stl_eid) - return (1); - - *puidx = cmd->arg1; - *ptype = 0; - return (0); -} - -static void -nat64stl_update_arg1(ipfw_insn *cmd, uint16_t idx) -{ - - cmd->arg1 = idx; -} - -static int -nat64stl_findbyname(struct ip_fw_chain *ch, struct tid_info *ti, - struct named_object **pno) -{ - int err; - - err = ipfw_objhash_find_type(CHAIN_TO_SRV(ch), ti, - IPFW_TLV_NAT64STL_NAME, pno); - return (err); -} - -static struct named_object * -nat64stl_findbykidx(struct ip_fw_chain *ch, uint16_t idx) -{ - struct namedobj_instance *ni; - struct named_object *no; - - IPFW_UH_WLOCK_ASSERT(ch); - ni = CHAIN_TO_SRV(ch); - no = ipfw_objhash_lookup_kidx(ni, idx); - KASSERT(no != NULL, ("NAT with index %d not found", idx)); - - return (no); -} - -static int -nat64stl_manage_sets(struct ip_fw_chain *ch, uint16_t set, uint8_t new_set, - enum ipfw_sets_cmd cmd) +nat64stl_manage_sets(struct ip_fw_chain *ch, uint32_t set, + uint8_t new_set, enum ipfw_sets_cmd cmd) { - return (ipfw_obj_manage_sets(CHAIN_TO_SRV(ch), IPFW_TLV_NAT64STL_NAME, - set, new_set, cmd)); + return (ipfw_obj_manage_sets(CHAIN_TO_SRV(ch), + IPFW_TLV_NAT64STL_NAME, set, new_set, cmd)); } - -static struct opcode_obj_rewrite opcodes[] = { - { - .opcode = O_EXTERNAL_INSTANCE, - .etlv = IPFW_TLV_EACTION /* just show it isn't table */, - .classifier = nat64stl_classify, - .update = nat64stl_update_arg1, - .find_byname = nat64stl_findbyname, - .find_bykidx = nat64stl_findbykidx, - .manage_sets = nat64stl_manage_sets, - }, -}; +NAT64_DEFINE_OPCODE_REWRITER(nat64stl, NAT64STL, opcodes); static int destroy_config_cb(struct namedobj_instance *ni, struct named_object *no, diff --git a/sys/netpfil/ipfw/nptv6/ip_fw_nptv6.c b/sys/netpfil/ipfw/nptv6/ip_fw_nptv6.c index ec63ad00c16..caf35fa8693 100644 --- a/sys/netpfil/ipfw/nptv6/ip_fw_nptv6.c +++ b/sys/netpfil/ipfw/nptv6/ip_fw_nptv6.c @@ -1,7 +1,8 @@ /*- - * Copyright (c) 2016 Yandex LLC - * Copyright (c) 2016 Andrey V. Elsukov - * All rights reserved. + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2016-2020 Yandex LLC + * Copyright (c) 2016-2020 Andrey V. Elsukov * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sys/netpfil/ipfw/nptv6/nptv6.c b/sys/netpfil/ipfw/nptv6/nptv6.c index 3e5943e7612..5cfff028556 100644 --- a/sys/netpfil/ipfw/nptv6/nptv6.c +++ b/sys/netpfil/ipfw/nptv6/nptv6.c @@ -1,7 +1,8 @@ /*- - * Copyright (c) 2016 Yandex LLC - * Copyright (c) 2016 Andrey V. Elsukov - * All rights reserved. + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2016-2020 Yandex LLC + * Copyright (c) 2016-2020 Andrey V. Elsukov * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -62,7 +63,7 @@ __FBSDID("$FreeBSD$"); #include #include -VNET_DEFINE_STATIC(uint16_t, nptv6_eid) = 0; +VNET_DEFINE_STATIC(uint32_t, nptv6_eid) = 0; #define V_nptv6_eid VNET(nptv6_eid) #define IPFW_TLV_NPTV6_NAME IPFW_TLV_EACTION_NAME(V_nptv6_eid) @@ -78,7 +79,7 @@ static int nptv6_rewrite_external(struct nptv6_cfg *cfg, struct mbuf **mp, int offset); #define NPTV6_LOOKUP(chain, cmd) \ - (struct nptv6_cfg *)SRV_OBJECT((chain), (cmd)->arg1) + (struct nptv6_cfg *)SRV_OBJECT((chain), insntod(cmd, kidx)->kidx) #ifndef IN6_MASK_ADDR #define IN6_MASK_ADDR(a, m) do { \ @@ -356,9 +357,9 @@ ipfw_nptv6(struct ip_fw_chain *chain, struct ip_fw_args *args, *done = 0; /* try next rule if not matched */ ret = IP_FW_DENY; - icmd = cmd + 1; + icmd = cmd + F_LEN(cmd); if (cmd->opcode != O_EXTERNAL_ACTION || - cmd->arg1 != V_nptv6_eid || + insntod(cmd, kidx)->kidx != V_nptv6_eid || icmd->opcode != O_EXTERNAL_INSTANCE || (cfg = NPTV6_LOOKUP(chain, icmd)) == NULL || (cfg->flags & NPTV6_READY) == 0) @@ -376,7 +377,7 @@ ipfw_nptv6(struct ip_fw_chain *chain, struct ip_fw_args *args, */ ip6 = mtod(args->m, struct ip6_hdr *); NPTV6_IPDEBUG("eid %u, oid %u, %s -> %s %d", - cmd->arg1, icmd->arg1, + insntod(cmd, kidx)->kidx, insntod(icmd, kidx)->kidx, inet_ntop(AF_INET6, &ip6->ip6_src, _s, sizeof(_s)), inet_ntop(AF_INET6, &ip6->ip6_dst, _d, sizeof(_d)), ip6->ip6_nxt); @@ -905,37 +906,38 @@ nptv6_reset_stats(struct ip_fw_chain *ch, ip_fw3_opheader *op, } static struct ipfw_sopt_handler scodes[] = { - { IP_FW_NPTV6_CREATE, 0, HDIR_SET, nptv6_create }, - { IP_FW_NPTV6_DESTROY,0, HDIR_SET, nptv6_destroy }, - { IP_FW_NPTV6_CONFIG, 0, HDIR_BOTH, nptv6_config }, - { IP_FW_NPTV6_LIST, 0, HDIR_GET, nptv6_list }, - { IP_FW_NPTV6_STATS, 0, HDIR_GET, nptv6_stats }, - { IP_FW_NPTV6_RESET_STATS,0, HDIR_SET, nptv6_reset_stats }, + { IP_FW_NPTV6_CREATE, IP_FW3_OPVER, HDIR_SET, nptv6_create }, + { IP_FW_NPTV6_DESTROY, IP_FW3_OPVER, HDIR_SET, nptv6_destroy }, + { IP_FW_NPTV6_CONFIG, IP_FW3_OPVER, HDIR_BOTH,nptv6_config }, + { IP_FW_NPTV6_LIST, IP_FW3_OPVER, HDIR_GET, nptv6_list }, + { IP_FW_NPTV6_STATS, IP_FW3_OPVER, HDIR_GET, nptv6_stats }, + { IP_FW_NPTV6_RESET_STATS, IP_FW3_OPVER, HDIR_SET, nptv6_reset_stats }, }; static int -nptv6_classify(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) +nptv6_classify(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype) { ipfw_insn *icmd; - icmd = cmd - 1; - NPTV6_DEBUG("opcode %d, arg1 %d, opcode0 %d, arg1 %d", - cmd->opcode, cmd->arg1, icmd->opcode, icmd->arg1); + icmd = cmd0 - F_LEN(cmd0); + NPTV6_DEBUG("opcode %u, kidx %u, opcode0 %u, kidx %u", + cmd->opcode, insntod(cmd, kidx)->kidx, + icmd->opcode, insntod(icmd, kidx)->kidx); if (icmd->opcode != O_EXTERNAL_ACTION || - icmd->arg1 != V_nptv6_eid) + insntod(icmd, kidx)->kidx != V_nptv6_eid) return (1); - *puidx = cmd->arg1; + *puidx = insntod(cmd0, kidx)->kidx; *ptype = 0; return (0); } static void -nptv6_update_arg1(ipfw_insn *cmd, uint16_t idx) +nptv6_update_kidx(ipfw_insn *cmd0, uint32_t idx) { - cmd->arg1 = idx; - NPTV6_DEBUG("opcode %d, arg1 -> %d", cmd->opcode, cmd->arg1); + insntod(cmd0, kidx)->kidx = idx; + NPTV6_DEBUG("opcode %u, kidx -> %u", cmd->opcode, idx); } static int @@ -951,7 +953,7 @@ nptv6_findbyname(struct ip_fw_chain *ch, struct tid_info *ti, } static struct named_object * -nptv6_findbykidx(struct ip_fw_chain *ch, uint16_t idx) +nptv6_findbykidx(struct ip_fw_chain *ch, uint32_t idx) { struct namedobj_instance *ni; struct named_object *no; @@ -959,14 +961,14 @@ nptv6_findbykidx(struct ip_fw_chain *ch, uint16_t idx) IPFW_UH_WLOCK_ASSERT(ch); ni = CHAIN_TO_SRV(ch); no = ipfw_objhash_lookup_kidx(ni, idx); - KASSERT(no != NULL, ("NPT with index %d not found", idx)); + KASSERT(no != NULL, ("NPT with index %u not found", idx)); NPTV6_DEBUG("kidx %u -> %s", idx, no->name); return (no); } static int -nptv6_manage_sets(struct ip_fw_chain *ch, uint16_t set, uint8_t new_set, +nptv6_manage_sets(struct ip_fw_chain *ch, uint32_t set, uint8_t new_set, enum ipfw_sets_cmd cmd) { @@ -979,7 +981,7 @@ static struct opcode_obj_rewrite opcodes[] = { .opcode = O_EXTERNAL_INSTANCE, .etlv = IPFW_TLV_EACTION /* just show it isn't table */, .classifier = nptv6_classify, - .update = nptv6_update_arg1, + .update = nptv6_update_kidx, .find_byname = nptv6_findbyname, .find_bykidx = nptv6_findbykidx, .manage_sets = nptv6_manage_sets, diff --git a/sys/netpfil/ipfw/nptv6/nptv6.h b/sys/netpfil/ipfw/nptv6/nptv6.h index df5a4e8bf0e..59bed70eba8 100644 --- a/sys/netpfil/ipfw/nptv6/nptv6.h +++ b/sys/netpfil/ipfw/nptv6/nptv6.h @@ -1,7 +1,8 @@ /*- - * Copyright (c) 2016 Yandex LLC - * Copyright (c) 2016 Andrey V. Elsukov - * All rights reserved. + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2016-2020 Yandex LLC + * Copyright (c) 2016-2020 Andrey V. Elsukov * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sys/netpfil/ipfw/pmod/ip_fw_pmod.c b/sys/netpfil/ipfw/pmod/ip_fw_pmod.c index b731c12229e..755cb39fac1 100644 --- a/sys/netpfil/ipfw/pmod/ip_fw_pmod.c +++ b/sys/netpfil/ipfw/pmod/ip_fw_pmod.c @@ -1,7 +1,8 @@ /*- - * Copyright (c) 2017 Yandex LLC - * Copyright (c) 2017 Andrey V. Elsukov - * All rights reserved. + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2017-2020 Yandex LLC + * Copyright (c) 2017-2020 Andrey V. Elsukov * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sys/netpfil/ipfw/pmod/pmod.h b/sys/netpfil/ipfw/pmod/pmod.h index 1e9f6ec00f7..2ae16712255 100644 --- a/sys/netpfil/ipfw/pmod/pmod.h +++ b/sys/netpfil/ipfw/pmod/pmod.h @@ -1,7 +1,8 @@ /*- - * Copyright (c) 2017 Yandex LLC - * Copyright (c) 2017 Andrey V. Elsukov - * All rights reserved. + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2017-2020 Yandex LLC + * Copyright (c) 2017-2020 Andrey V. Elsukov * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/sys/netpfil/ipfw/pmod/tcpmod.c b/sys/netpfil/ipfw/pmod/tcpmod.c index 4780e7c007f..550502a1b68 100644 --- a/sys/netpfil/ipfw/pmod/tcpmod.c +++ b/sys/netpfil/ipfw/pmod/tcpmod.c @@ -1,7 +1,8 @@ /*- - * Copyright (c) 2017 Yandex LLC - * Copyright (c) 2017 Andrey V. Elsukov - * All rights reserved. + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2017-2020 Yandex LLC + * Copyright (c) 2017-2020 Andrey V. Elsukov * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -56,7 +57,7 @@ __FBSDID("$FreeBSD$"); #include -static VNET_DEFINE(uint16_t, tcpmod_setmss_eid) = 0; +static VNET_DEFINE(uint32_t, tcpmod_setmss_eid) = 0; #define V_tcpmod_setmss_eid VNET(tcpmod_setmss_eid) static int @@ -181,9 +182,9 @@ ipfw_tcpmod(struct ip_fw_chain *chain, struct ip_fw_args *args, *done = 0; /* try next rule if not matched */ ret = IP_FW_DENY; - icmd = cmd + 1; + icmd = cmd + F_LEN(cmd); if (cmd->opcode != O_EXTERNAL_ACTION || - cmd->arg1 != V_tcpmod_setmss_eid || + insntod(cmd, kidx)->kidx != V_tcpmod_setmss_eid || icmd->opcode != O_EXTERNAL_DATA || icmd->len != F_INSN_SIZE(ipfw_insn)) return (ret);