aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander V. Chernikov <melifaro@FreeBSD.org>2014-08-12 15:51:48 +0000
committerAlexander V. Chernikov <melifaro@FreeBSD.org>2014-08-12 15:51:48 +0000
commit1940fa77278f0ec2ff1d3a8a174dbf5785d8e70e (patch)
treea8fa20927c28cd192b16b34d205f195ff47c0df4
parent56f43a5e98695a187837094740286c60fdcc0de0 (diff)
downloadsrc-1940fa77278f0ec2ff1d3a8a174dbf5785d8e70e.tar.gz
src-1940fa77278f0ec2ff1d3a8a174dbf5785d8e70e.zip
Notes
-rw-r--r--sbin/ipfw/ipfw2.c33
-rw-r--r--sbin/ipfw/ipfw2.h1
-rw-r--r--sys/netinet/ip_fw.h11
-rw-r--r--sys/netpfil/ipfw/ip_fw2.c8
-rw-r--r--sys/netpfil/ipfw/ip_fw_dynamic.c2
-rw-r--r--sys/netpfil/ipfw/ip_fw_private.h2
-rw-r--r--sys/netpfil/ipfw/ip_fw_sockopt.c135
-rw-r--r--sys/netpfil/ipfw/ip_fw_table.c4
8 files changed, 135 insertions, 61 deletions
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
index d90ac1a63113..54065831a39b 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);
@@ -1386,6 +1386,7 @@ show_static_rule(struct cmdline_opts *co, struct format_opts *fo,
ipfw_insn_log *logptr = NULL; /* set if we find an O_LOG */
ipfw_insn_altq *altqptr = NULL; /* set if we find an O_ALTQ */
int or_block = 0; /* we are in an or block */
+ uint32_t uval;
if ((fo->set_mask & (1 << rule->set)) == 0) {
/* disabled mask */
@@ -1556,17 +1557,22 @@ show_static_rule(struct cmdline_opts *co, struct format_opts *fo,
break;
case O_SETFIB:
- bprint_uint_arg(bp, "setfib ", cmd->arg1);
+ bprint_uint_arg(bp, "setfib ", cmd->arg1 & 0x7FFF);
break;
case O_SETDSCP:
{
const char *code;
- if ((code = match_value(f_ipdscp, cmd->arg1)) != NULL)
+ if (cmd->arg1 == IP_FW_TARG) {
+ bprint_uint_arg(bp, "setdscp ", cmd->arg1);
+ break;
+ }
+ uval = cmd->arg1 & 0x3F;
+ if ((code = match_value(f_ipdscp, uval)) != NULL)
bprintf(bp, "setdscp %s", code);
else
- bprint_uint_arg(bp, "setdscp ", cmd->arg1);
+ bprint_uint_arg(bp, "setdscp ", uval);
}
break;
@@ -3597,11 +3603,11 @@ chkarg:
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);
@@ -3725,7 +3731,7 @@ chkarg:
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,
@@ -3733,6 +3739,8 @@ chkarg:
errx(EX_DATAERR, "fibs not suported.\n");
if (action->arg1 >= numfibs) /* Temporary */
errx(EX_DATAERR, "fib too large.\n");
+ /* Add high-order bit to fib to make room for tablearg*/
+ action->arg1 |= 0x8000;
}
av++;
break;
@@ -3745,13 +3753,16 @@ chkarg:
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");
action->arg1 = code;
} else
action->arg1 = strtoul(*av, NULL, 10);
+ /* Add high-order bit to DSCP to make room for tablearg */
+ if (action->arg1 != IP_FW_TARG)
+ action->arg1 |= 0x8000;
av++;
break;
}
diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h
index d15df7e8f0fe..05e234dbdf11 100644
--- a/sbin/ipfw/ipfw2.h
+++ b/sbin/ipfw/ipfw2.h
@@ -228,6 +228,7 @@ enum tokens {
TOK_LOCK,
TOK_UNLOCK,
};
+
/*
* the following macro returns an error message if we run out of
* arguments.
diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h
index 4d6c3baf5f85..e5e1179cfdc8 100644
--- a/sys/netinet/ip_fw.h
+++ b/sys/netinet/ip_fw.h
@@ -47,18 +47,17 @@
/*
* 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'
+ * argument between 1 and 65534. The value 0 (IP_FW_TARG) is used
+ * to represent 'tablearg' value, e.g. 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
- * 2^32 pipes, queues, tag values and so on, and use 0 as a tablearg.
- * Note there are some opcodes where value 0 is perfectly valid (fib, dscp).
+ * 2^32 pipes, queues, tag values and so on.
*/
#define IPFW_ARG_MIN 1
#define IPFW_ARG_MAX 65534
-#define IP_FW_TABLEARG 65535
+#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.
diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c
index 52c83ef82901..55130c5763f4 100644
--- a/sys/netpfil/ipfw/ip_fw2.c
+++ b/sys/netpfil/ipfw/ip_fw2.c
@@ -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 && f->cached_id == chain->id)
+ if (num != IP_FW_TARG && f->cached_id == chain->id)
f_pos = f->cached_pos;
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->cached_id = chain->id;
f->cached_pos = f_pos;
}
@@ -2400,7 +2400,7 @@ do { \
uint32_t fib;
IPFW_INC_RULE_COUNTER(f, pktlen);
- fib = IP_FW_ARG_TABLEARG(cmd->arg1);
+ fib = IP_FW_ARG_TABLEARG(cmd->arg1) & 0x7FFFF;
if (fib >= rt_numfibs)
fib = 0;
M_SETFIB(m, fib);
@@ -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 52c9ae158d1e..8eb1785a59c4 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 5dda99959764..7f05ed1c57eb 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.
*/
@@ -456,6 +456,7 @@ import_rule0(struct rule_check_info *ci)
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;
@@ -477,36 +478,69 @@ import_rule0(struct rule_check_info *ci)
/*
* Alter opcodes:
- * 1) convert table number in iface opcodes to u16
+ * 1) convert tablearg value from 65335 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
*/
- l = urule->cmd_len;
- cmd = urule->cmd;
+ l = krule->cmd_len;
+ cmd = krule->cmd;
cmdlen = 0;
- for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
- cmdlen = F_LEN(cmd);
+ for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
+ cmdlen = F_LEN(cmd);
- switch (cmd->opcode) {
- /* 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;
+ 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 == 65535)
+ cmd->arg1 = IP_FW_TARG;
+ break;
+ case O_SETFIB:
+ case O_SETDSCP:
+ if (cmd->arg1 == 65535)
+ cmd->arg1 = IP_FW_TARG;
+ else
+ cmd->arg1 |= 0x8000;
+ 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 = cmdif->p.glob;
- 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 */
@@ -526,28 +560,57 @@ export_rule0(struct ip_fw *krule, struct ip_fw_rule0 *urule, int len)
/*
* Alter opcodes:
- * 1) convert table number in iface opcodes to int
+ * 1) convert tablearg value from 0 to 65335
+ * 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);
+ for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
+ cmdlen = F_LEN(cmd);
- switch (cmd->opcode) {
- /* 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;
+ 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 = 65535;
+ break;
+ case O_SETFIB:
+ case O_SETDSCP:
+ if (cmd->arg1 == IP_FW_TARG)
+ cmd->arg1 = 65535;
+ else
+ cmd->arg1 &= ~0x8000;
+ 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;
- }
+ cmdif->p.glob = cmdif->p.kidx;
+ break;
+ }
}
}
@@ -1391,10 +1454,10 @@ check_ipfw_rule_body(ipfw_insn *cmd, int cmd_len, struct rule_check_info *ci)
case O_SETFIB:
if (cmdlen != F_INSN_SIZE(ipfw_insn))
goto bad_size;
- if ((cmd->arg1 != IP_FW_TABLEARG) &&
- (cmd->arg1 >= rt_numfibs)) {
+ if ((cmd->arg1 != IP_FW_TARG) &&
+ ((cmd->arg1 & 0x7FFFF) >= rt_numfibs)) {
printf("ipfw: invalid fib number %d\n",
- cmd->arg1);
+ cmd->arg1 & 0x7FFFF);
return EINVAL;
}
goto check_action;
diff --git a/sys/netpfil/ipfw/ip_fw_table.c b/sys/netpfil/ipfw/ip_fw_table.c
index 232a0a8ad1be..c67073598a97 100644
--- a/sys/netpfil/ipfw/ip_fw_table.c
+++ b/sys/netpfil/ipfw/ip_fw_table.c
@@ -2482,7 +2482,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:
@@ -2515,7 +2515,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;