diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c index 3ba52f4bfaf9..1309bafaa2fb 100644 --- a/sbin/ipfw/ipfw2.c +++ b/sbin/ipfw/ipfw2.c @@ -93,7 +93,7 @@ int ipfw_socket = -1; if (!av[0]) \ errx(EX_USAGE, "%s: missing argument", match_value(s_x, tok)); \ if (_substrcmp(*av, "tablearg") == 0) { \ - arg = IP_FW_TABLEARG; \ + arg = IP_FW_TARG; \ break; \ } \ \ @@ -111,7 +111,7 @@ int ipfw_socket = -1; errx(EX_DATAERR, "%s: argument is out of range (%u..%u): %s", \ match_value(s_x, tok), min, max, *av); \ \ - if (_xval == IP_FW_TABLEARG) \ + if (_xval == IP_FW_TARG) \ errx(EX_DATAERR, "%s: illegal argument value: %s", \ match_value(s_x, tok), *av); \ arg = _xval; \ @@ -123,7 +123,7 @@ PRINT_UINT_ARG(const char *str, uint32_t arg) { if (str != NULL) printf("%s",str); - if (arg == IP_FW_TABLEARG) + if (arg == IP_FW_TARG) printf("tablearg"); else printf("%u", arg); @@ -469,7 +469,7 @@ bprint_uint_arg(struct buf_pr *bp, const char *str, uint32_t arg) if (str != NULL) bprintf(bp, "%s", str); - if (arg == IP_FW_TABLEARG) + if (arg == IP_FW_TARG) bprintf(bp, "tablearg"); else bprintf(bp, "%u", arg); @@ -1843,7 +1843,7 @@ show_static_rule(struct cmdline_opts *co, struct format_opts *fo, else if (cmdif->name[0] == '\1') { /* interface table */ t = table_search_ctlv(fo->tstate, - cmdif->p.glob); + cmdif->p.kidx); printf(" %s table(%s)", s, t); } else printf(" %s %s", s, cmdif->name); @@ -3092,7 +3092,7 @@ fill_iface(ipfw_insn_if *cmd, char *arg, int cblen, struct tidx *tstate) errx(EX_DATAERR, "Invalid table name: %s", arg + 6); cmd->name[0] = '\1'; /* Special value indicating table */ - cmd->p.glob = uidx; + cmd->p.kidx = uidx; } else if (!isdigit(*arg)) { strlcpy(cmd->name, arg, sizeof(cmd->name)); cmd->p.glob = strpbrk(arg, "*?[") != NULL ? 1 : 0; @@ -3596,11 +3596,11 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate) 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) + if (action->arg1 <= 0 || action->arg1 >= IP_FW_TARG) errx(EX_DATAERR, "illegal argument for %s", *(av - 1)); } else if (_substrcmp(*av, "tablearg") == 0) { - action->arg1 = IP_FW_TABLEARG; + action->arg1 = IP_FW_TARG; } else if (i == TOK_DIVERT || i == TOK_TEE) { struct servent *s; setservent(1); @@ -3724,7 +3724,7 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate) action->opcode = O_SETFIB; NEED1("missing fib number"); if (_substrcmp(*av, "tablearg") == 0) { - action->arg1 = IP_FW_TABLEARG; + action->arg1 = IP_FW_TARG; } else { action->arg1 = strtoul(*av, NULL, 10); if (sysctlbyname("net.fibs", &numfibs, &intsize, @@ -3744,7 +3744,7 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate) action->opcode = O_SETDSCP; NEED1("missing DSCP code"); if (_substrcmp(*av, "tablearg") == 0) { - action->arg1 = IP_FW_TABLEARG; + action->arg1 = IP_FW_TARG; } else if (isalpha(*av[0])) { if ((code = match_token(f_ipdscp, *av)) == -1) errx(EX_DATAERR, "Unknown DSCP code"); diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index aa210c7b5634..0326d03a9c4e 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -49,7 +49,7 @@ * Most commands (queue, pipe, tag, untag, limit...) can have a 16-bit * argument between 1 and 65534. The value 0 is unused, the value * 65535 (IP_FW_TABLEARG) is used to represent 'tablearg', i.e. the - * can be 1..65534, or 65535 to indicate the use of a 'tablearg' + * can be 1..65534, or 0 to indicate the use of a 'tablearg' * result of the most recent table() lookup. * Note that 16bit is only a historical limit, resulting from * the use of a 16-bit fields for that value. In reality, we can have @@ -57,7 +57,8 @@ */ #define IPFW_ARG_MIN 1 #define IPFW_ARG_MAX 65534 -#define IP_FW_TABLEARG 65535 /* XXX should use 0 */ +#define IP_FW_TABLEARG 65535 /* Compat value for old clients */ +#define IP_FW_TARG 0 /* Current tablearg value */ /* * Number of entries in the call stack of the call/return commands. @@ -391,6 +392,7 @@ typedef struct _ipfw_insn_if { union { struct in_addr ip; int glob; + uint16_t kidx; } p; char name[IFNAMSIZ]; } ipfw_insn_if; diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c index 0570fdbd1dc6..98f15ce18b9f 100644 --- a/sys/netpfil/ipfw/ip_fw2.c +++ b/sys/netpfil/ipfw/ip_fw2.c @@ -368,7 +368,7 @@ iface_match(struct ifnet *ifp, ipfw_insn_if *cmd, struct ip_fw_chain *chain, /* Check by name or by IP address */ if (cmd->name[0] != '\0') { /* match by name */ if (cmd->name[0] == '\1') /* use tablearg to match */ - return ipfw_lookup_table_extended(chain, cmd->p.glob, 0, + return ipfw_lookup_table_extended(chain, cmd->p.kidx, 0, &ifp->if_index, tablearg); /* Check name */ if (cmd->p.glob) { @@ -810,7 +810,7 @@ jump_fast(struct ip_fw_chain *chain, struct ip_fw *f, int num, * whose version is written in f->next_rule * (horrible hacks to avoid changing the ABI). */ - if (num != IP_FW_TABLEARG && (uintptr_t)f->x_next == chain->id) + if (num != IP_FW_TARG && (uintptr_t)f->x_next == chain->id) f_pos = (uintptr_t)f->next_rule; else { int i = IP_FW_ARG_TABLEARG(num); @@ -822,7 +822,7 @@ jump_fast(struct ip_fw_chain *chain, struct ip_fw *f, int num, else f_pos = ipfw_find_rule(chain, i, 0); /* update the cache */ - if (num != IP_FW_TABLEARG) { + if (num != IP_FW_TARG) { f->next_rule = (void *)(uintptr_t)f_pos; f->x_next = (void *)(uintptr_t)chain->id; } @@ -2461,7 +2461,7 @@ do { \ retval = IP_FW_DENY; break; } - if (cmd->arg1 != IP_FW_TABLEARG) + if (cmd->arg1 != IP_FW_TARG) ((ipfw_insn_nat *)cmd)->nat = t; } retval = ipfw_nat_ptr(args, t, m); diff --git a/sys/netpfil/ipfw/ip_fw_dynamic.c b/sys/netpfil/ipfw/ip_fw_dynamic.c index 475ad8e705f9..ba166344a2c9 100644 --- a/sys/netpfil/ipfw/ip_fw_dynamic.c +++ b/sys/netpfil/ipfw/ip_fw_dynamic.c @@ -719,7 +719,7 @@ ipfw_install_state(struct ip_fw *rule, ipfw_insn_limit *cmd, conn_limit = IP_FW_ARG_TABLEARG(cmd->conn_limit); DEB( - if (cmd->conn_limit == IP_FW_TABLEARG) + if (cmd->conn_limit == IP_FW_TARG) printf("ipfw: %s: O_LIMIT rule, conn_limit: %u " "(tablearg)\n", __func__, conn_limit); else diff --git a/sys/netpfil/ipfw/ip_fw_private.h b/sys/netpfil/ipfw/ip_fw_private.h index 246bb3a001f1..2b953084ceb1 100644 --- a/sys/netpfil/ipfw/ip_fw_private.h +++ b/sys/netpfil/ipfw/ip_fw_private.h @@ -384,7 +384,7 @@ struct ipfw_ifc { #endif -#define IP_FW_ARG_TABLEARG(a) (((a) == IP_FW_TABLEARG) ? tablearg : (a)) +#define IP_FW_ARG_TABLEARG(a) (((a) == IP_FW_TARG) ? tablearg : (a)) /* * The lock is heavily used by ip_fw2.c (the main file) and ip_fw_nat.c * so the variable and the macros must be here. diff --git a/sys/netpfil/ipfw/ip_fw_sockopt.c b/sys/netpfil/ipfw/ip_fw_sockopt.c index 485815c78bd5..55030c6ef291 100644 --- a/sys/netpfil/ipfw/ip_fw_sockopt.c +++ b/sys/netpfil/ipfw/ip_fw_sockopt.c @@ -375,7 +375,7 @@ export_cntr0_base(struct ip_fw *krule, struct ip_fw_bcounter0 *cntr) } /* - * Copies rule @urule from v1 userland format + * Copies rule @urule from v1 userland format (current). * to kernel @krule. * Assume @krule is zeroed. */ @@ -454,6 +454,10 @@ 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; @@ -471,11 +475,68 @@ import_rule0(struct rule_check_info *ci) /* Copy opcodes */ memcpy(krule->cmd, urule->cmd, krule->cmd_len * sizeof(uint32_t)); + + /* + * Alter opcodes: + * 1) convert tablearg value from 65335 to 0 + * 2) convert table number in iface opcodes to u16 + */ + 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_SETFIB: + case O_SETDSCP: + case O_NAT: + if (cmd->arg1 == 65535) + cmd->arg1 = IP_FW_TARG; + break; + case O_LIMIT: + lcmd = (ipfw_insn_limit *)cmd; + if (lcmd->conn_limit == 65535) + 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; @@ -490,6 +551,55 @@ export_rule0(struct ip_fw *krule, struct ip_fw_rule0 *urule, int len) /* Export counters */ export_cntr0_base(krule, (struct ip_fw_bcounter0 *)&urule->pcnt); + + /* + * Alter opcodes: + * 1) convert tablearg value from 0 to 65335 + * 2) 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_SETFIB: + case O_SETDSCP: + case O_NAT: + if (cmd->arg1 == IP_FW_TARG) + cmd->arg1 = 65535; + break; + case O_LIMIT: + lcmd = (ipfw_insn_limit *)cmd; + if (lcmd->conn_limit == IP_FW_TARG) + lcmd->conn_limit = 65535; + 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; + } + } } /* diff --git a/sys/netpfil/ipfw/ip_fw_table.c b/sys/netpfil/ipfw/ip_fw_table.c index f6a8855d0ae1..08029c8d8f1a 100644 --- a/sys/netpfil/ipfw/ip_fw_table.c +++ b/sys/netpfil/ipfw/ip_fw_table.c @@ -2047,7 +2047,7 @@ classify_table_opcode(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) break; *ptype = IPFW_TABLE_INTERFACE; - *puidx = cmdif->p.glob; + *puidx = cmdif->p.kidx; skip = 0; break; case O_IP_FLOW_LOOKUP: @@ -2080,7 +2080,7 @@ update_table_opcode(ipfw_insn *cmd, uint16_t idx) case O_VIA: /* Interface table, possibly */ cmdif = (ipfw_insn_if *)cmd; - cmdif->p.glob = idx; + cmdif->p.kidx = idx; break; case O_IP_FLOW_LOOKUP: cmd->arg1 = idx;