aboutsummaryrefslogtreecommitdiff
path: root/sbin/ipfw/ipfw2.c
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/ipfw/ipfw2.c')
-rw-r--r--sbin/ipfw/ipfw2.c743
1 files changed, 555 insertions, 188 deletions
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
index 7a8601aad46a..2addc0295f0f 100644
--- a/sbin/ipfw/ipfw2.c
+++ b/sbin/ipfw/ipfw2.c
@@ -47,6 +47,8 @@
#include <net/ethernet.h>
#include <net/if.h> /* only IFNAMSIZ */
+#include <net/if_dl.h>
+#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h> /* only n_short, n_long */
#include <netinet/ip.h>
@@ -290,6 +292,12 @@ static struct _s_x rule_actions[] = {
{ NULL, 0 } /* terminator */
};
+static struct _s_x return_types[] = {
+ { "next-rulenum", RETURN_NEXT_RULENUM },
+ { "next-rule", RETURN_NEXT_RULE },
+ { NULL, 0 } /* terminator */
+};
+
static struct _s_x rule_action_params[] = {
{ "altq", TOK_ALTQ },
{ "log", TOK_LOG },
@@ -300,7 +308,7 @@ static struct _s_x rule_action_params[] = {
/*
* The 'lookup' instruction accepts one of the following arguments.
- * Arguments are passed as v[1] in O_DST_LOOKUP options.
+ * Arguments are passed as o.arg1 and o->value in O_DST_LOOKUP option.
*/
static struct _s_x lookup_keys[] = {
{ "dst-ip", LOOKUP_DST_IP },
@@ -313,9 +321,29 @@ static struct _s_x lookup_keys[] = {
{ "jail", LOOKUP_JAIL },
{ "dscp", LOOKUP_DSCP },
{ "mark", LOOKUP_MARK },
+ { "rulenum", LOOKUP_RULENUM },
{ NULL, 0 },
};
+/*
+ * table(name,valuename=value) instruction accepts one of the
+ * following arguments as valuename.
+ */
+static struct _s_x tvalue_names[] = {
+ { "tag", TVALUE_TAG },
+ { "pipe", TVALUE_PIPE },
+ { "divert", TVALUE_DIVERT },
+ { "skipto", TVALUE_SKIPTO },
+ { "netgraph", TVALUE_NETGRAPH },
+ { "fib", TVALUE_FIB },
+ { "nat", TVALUE_NAT },
+ { "nh4", TVALUE_NH4 },
+ { "dscp", TVALUE_DSCP },
+ { "limit", TVALUE_LIMIT },
+ { "mark", TVALUE_MARK },
+ { NULL, 0 }
+};
+
static struct _s_x rule_options[] = {
{ "tagged", TOK_TAGGED },
{ "uid", TOK_UID },
@@ -415,12 +443,12 @@ 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, const char *name, int otype);
-static uint16_t pack_table(struct tidx *tstate, const char *name);
+static uint32_t pack_object(struct tidx *tstate, const char *name, int otype);
+static uint32_t pack_table(struct tidx *tstate, const char *name);
-static char *table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx);
+static char *table_search_ctlv(ipfw_obj_ctlv *ctlv, uint32_t idx);
static void object_sort_ctlv(ipfw_obj_ctlv *ctlv);
-static char *object_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx,
+static char *object_search_ctlv(ipfw_obj_ctlv *ctlv, uint32_t idx,
uint16_t type);
int
@@ -650,6 +678,7 @@ do_set3(int optname, ip_fw3_opheader *op3, size_t optlen)
{
op3->opcode = optname;
+ op3->version = IP_FW3_OPVER; /* use last version */
if (g_co.debug_only) {
struct debug_header dbg = {
@@ -690,6 +719,7 @@ do_get3(int optname, ip_fw3_opheader *op3, size_t *optlen)
socklen_t len;
op3->opcode = optname;
+ op3->version = IP_FW3_OPVER; /* use last version */
if (g_co.debug_only) {
struct debug_header dbg = {
@@ -1284,6 +1314,15 @@ print_flags(struct buf_pr *bp, char const *name, const ipfw_insn *cmd,
}
}
+static void
+print_tvalue(struct buf_pr *bp, const ipfw_insn_table *cmd)
+{
+ const char *name;
+
+ name = match_value(tvalue_names, IPFW_TVALUE_TYPE(&cmd->o));
+ bprintf(bp, ",%s=%u", name != NULL ? name: "<invalid>", cmd->value);
+}
+
/*
* Print the ip address contained in a command.
@@ -1295,33 +1334,46 @@ print_ip(struct buf_pr *bp, const struct format_opts *fo,
struct hostent *he = NULL;
const struct in_addr *ia;
const uint32_t *a = ((const ipfw_insn_u32 *)cmd)->d;
- uint32_t len = F_LEN((const ipfw_insn *)cmd);
+ uint32_t len = F_LEN(&cmd->o);
char *t;
bprintf(bp, " ");
- if (cmd->o.opcode == O_IP_DST_LOOKUP && len > F_INSN_SIZE(ipfw_insn_u32)) {
- const char *arg;
-
- arg = match_value(lookup_keys, a[1]);
- t = table_search_ctlv(fo->tstate,
- ((const 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) {
+
+ case O_IP_DST_LOOKUP:
+ if ((len == F_INSN_SIZE(ipfw_insn_kidx) ||
+ len == F_INSN_SIZE(ipfw_insn_table)) &&
+ IPFW_LOOKUP_TYPE(&cmd->o) != LOOKUP_NONE) {
+ const char *key;
+
+ key = match_value(lookup_keys,
+ IPFW_LOOKUP_TYPE(&cmd->o));
+ t = table_search_ctlv(fo->tstate,
+ insntoc(&cmd->o, kidx)->kidx);
+ if (len == F_INSN_SIZE(ipfw_insn_table)) {
+ bprintf(bp, "lookup %s:%#x %s",
+ (key != NULL ? key : "<invalid>"),
+ insntoc(&cmd->o, table)->value, t);
+ } else
+ bprintf(bp, "lookup %s %s", key != NULL ? key:
+ "<invalid>", t);
+ return;
+ }
+ /* FALLTHROUGH */
+ case O_IP_SRC_LOOKUP:
t = table_search_ctlv(fo->tstate,
- ((const ipfw_insn *)cmd)->arg1);
+ insntoc(&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))
+ print_tvalue(bp, insntoc(&cmd->o, table));
bprintf(bp, ")");
return;
}
+
if (cmd->o.opcode == O_IP_SRC_SET || cmd->o.opcode == O_IP_DST_SET) {
const uint32_t *map = (const uint32_t *)&cmd->mask;
struct in_addr addr;
@@ -1427,10 +1479,10 @@ print_mac_lookup(struct buf_pr *bp, const struct format_opts *fo,
bprintf(bp, " ");
- t = table_search_ctlv(fo->tstate, cmd->arg1);
+ t = table_search_ctlv(fo->tstate, insntoc(cmd, kidx)->kidx);
bprintf(bp, "table(%s", t);
- if (len == F_INSN_SIZE(ipfw_insn_u32))
- bprintf(bp, ",%u", ((const ipfw_insn_u32 *)cmd)->d[0]);
+ if (len == F_INSN_SIZE(ipfw_insn_table))
+ print_tvalue(bp, insntoc(cmd, table));
bprintf(bp, ")");
}
@@ -1497,10 +1549,9 @@ print_dscp(struct buf_pr *bp, const ipfw_insn_u32 *cmd)
}
}
-#define insntod(cmd, type) ((const 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
@@ -1583,7 +1634,7 @@ print_instruction(struct buf_pr *bp, const struct format_opts *fo,
switch (cmd->opcode) {
case O_PROB:
- d = 1.0 * insntod(cmd, u32)->d[0] / 0x7fffffff;
+ d = 1.0 * insntoc(cmd, u32)->d[0] / 0x7fffffff;
bprintf(bp, "prob %f ", d);
break;
case O_PROBE_STATE: /* no need to print anything here */
@@ -1596,30 +1647,36 @@ print_instruction(struct buf_pr *bp, const struct format_opts *fo,
case O_IP_SRC_SET:
if (state->flags & HAVE_SRCIP)
bprintf(bp, " src-ip");
- print_ip(bp, fo, insntod(cmd, ip));
+ print_ip(bp, fo, insntoc(cmd, ip));
break;
case O_IP_DST:
- case O_IP_DST_LOOKUP:
case O_IP_DST_MASK:
case O_IP_DST_ME:
case O_IP_DST_SET:
- if (state->flags & HAVE_DSTIP)
+ case O_IP_DST_LOOKUP:
+ /*
+ * Special handling for O_IP_DST_LOOKUP when
+ * lookup type is not LOOKUP_NONE.
+ */
+ if ((state->flags & HAVE_DSTIP) != 0 && (
+ cmd->opcode != O_IP_DST_LOOKUP ||
+ IPFW_LOOKUP_TYPE(cmd) == LOOKUP_NONE))
bprintf(bp, " dst-ip");
- print_ip(bp, fo, insntod(cmd, ip));
+ print_ip(bp, fo, insntoc(cmd, ip));
break;
case O_IP6_SRC:
case O_IP6_SRC_MASK:
case O_IP6_SRC_ME:
if (state->flags & HAVE_SRCIP)
bprintf(bp, " src-ip6");
- print_ip6(bp, insntod(cmd, ip6));
+ print_ip6(bp, insntoc(cmd, ip6));
break;
case O_IP6_DST:
case O_IP6_DST_MASK:
case O_IP6_DST_ME:
if (state->flags & HAVE_DSTIP)
bprintf(bp, " dst-ip6");
- print_ip6(bp, insntod(cmd, ip6));
+ print_ip6(bp, insntoc(cmd, ip6));
break;
case O_MAC_SRC_LOOKUP:
bprintf(bp, " src-mac");
@@ -1630,11 +1687,11 @@ print_instruction(struct buf_pr *bp, const struct format_opts *fo,
print_mac_lookup(bp, fo, cmd);
break;
case O_FLOW6ID:
- print_flow6id(bp, insntod(cmd, u32));
+ print_flow6id(bp, insntoc(cmd, u32));
break;
case O_IP_DSTPORT:
case O_IP_SRCPORT:
- print_newports(bp, insntod(cmd, u16), state->proto,
+ print_newports(bp, insntoc(cmd, u16), state->proto,
(state->flags & (HAVE_SRCIP | HAVE_DSTIP)) ==
(HAVE_SRCIP | HAVE_DSTIP) ? cmd->opcode: 0);
break;
@@ -1649,10 +1706,10 @@ print_instruction(struct buf_pr *bp, const struct format_opts *fo,
state->proto = cmd->arg1;
break;
case O_MACADDR2:
- print_mac(bp, insntod(cmd, mac));
+ print_mac(bp, insntoc(cmd, mac));
break;
case O_MAC_TYPE:
- print_newports(bp, insntod(cmd, u16),
+ print_newports(bp, insntoc(cmd, u16),
IPPROTO_ETHERTYPE, cmd->opcode);
break;
case O_FRAG:
@@ -1695,26 +1752,27 @@ print_instruction(struct buf_pr *bp, const struct format_opts *fo,
s = "recv";
else /* if (cmd->opcode == O_VIA) */
s = "via";
- switch (insntod(cmd, if)->name[0]) {
+ switch (insntoc(cmd, if)->name[0]) {
case '\0':
bprintf(bp, " %s %s", s,
- inet_ntoa(insntod(cmd, if)->p.ip));
+ inet_ntoa(insntoc(cmd, if)->p.ip));
break;
case '\1':
bprintf(bp, " %s table(%s)", s,
table_search_ctlv(fo->tstate,
- insntod(cmd, if)->p.kidx));
+ insntoc(cmd, if)->p.kidx));
break;
default:
bprintf(bp, " %s %s", s,
- insntod(cmd, if)->name);
+ insntoc(cmd, if)->name);
}
break;
case O_IP_FLOW_LOOKUP:
- s = table_search_ctlv(fo->tstate, cmd->arg1);
+ s = table_search_ctlv(fo->tstate,
+ insntoc(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))
+ print_tvalue(bp, insntoc(cmd, table));
bprintf(bp, ")");
break;
case O_IPID:
@@ -1749,7 +1807,7 @@ print_instruction(struct buf_pr *bp, const struct format_opts *fo,
}
bprintf(bp, " %s %u", s, cmd->arg1);
} else
- print_newports(bp, insntod(cmd, u16), 0,
+ print_newports(bp, insntoc(cmd, u16), 0,
cmd->opcode);
break;
case O_IPVER:
@@ -1759,7 +1817,7 @@ print_instruction(struct buf_pr *bp, const struct format_opts *fo,
bprintf(bp, " ipprecedence %u", cmd->arg1 >> 5);
break;
case O_DSCP:
- print_dscp(bp, insntod(cmd, u32));
+ print_dscp(bp, insntoc(cmd, u32));
break;
case O_IPOPT:
print_flags(bp, "ipoptions", cmd, f_ipopts);
@@ -1768,7 +1826,7 @@ print_instruction(struct buf_pr *bp, const struct format_opts *fo,
print_flags(bp, "iptos", cmd, f_iptos);
break;
case O_ICMPTYPE:
- print_icmptypes(bp, insntod(cmd, u32));
+ print_icmptypes(bp, insntoc(cmd, u32));
break;
case O_ESTAB:
bprintf(bp, " established");
@@ -1781,30 +1839,30 @@ print_instruction(struct buf_pr *bp, const struct format_opts *fo,
break;
case O_TCPACK:
bprintf(bp, " tcpack %d",
- ntohl(insntod(cmd, u32)->d[0]));
+ ntohl(insntoc(cmd, u32)->d[0]));
break;
case O_TCPSEQ:
bprintf(bp, " tcpseq %d",
- ntohl(insntod(cmd, u32)->d[0]));
+ ntohl(insntoc(cmd, u32)->d[0]));
break;
case O_UID:
- pwd = getpwuid(insntod(cmd, u32)->d[0]);
+ pwd = getpwuid(insntoc(cmd, u32)->d[0]);
if (pwd != NULL)
bprintf(bp, " uid %s", pwd->pw_name);
else
bprintf(bp, " uid %u",
- insntod(cmd, u32)->d[0]);
+ insntoc(cmd, u32)->d[0]);
break;
case O_GID:
- grp = getgrgid(insntod(cmd, u32)->d[0]);
+ grp = getgrgid(insntoc(cmd, u32)->d[0]);
if (grp != NULL)
bprintf(bp, " gid %s", grp->gr_name);
else
bprintf(bp, " gid %u",
- insntod(cmd, u32)->d[0]);
+ insntoc(cmd, u32)->d[0]);
break;
case O_JAIL:
- bprintf(bp, " jail %d", insntod(cmd, u32)->d[0]);
+ bprintf(bp, " jail %d", insntoc(cmd, u32)->d[0]);
break;
case O_VERREVPATH:
bprintf(bp, " verrevpath");
@@ -1827,7 +1885,8 @@ print_instruction(struct buf_pr *bp, const struct format_opts *fo,
else
bprintf(bp, " record-state");
bprintf(bp, " :%s",
- object_search_ctlv(fo->tstate, cmd->arg1,
+ object_search_ctlv(fo->tstate,
+ insntoc(cmd, kidx)->kidx,
IPFW_TLV_STATE_NAME));
break;
case O_LIMIT:
@@ -1835,9 +1894,10 @@ print_instruction(struct buf_pr *bp, const struct format_opts *fo,
bprintf(bp, " limit");
else
bprintf(bp, " set-limit");
- print_limit_mask(bp, insntod(cmd, limit));
+ print_limit_mask(bp, insntoc(cmd, limit));
bprintf(bp, " :%s",
- object_search_ctlv(fo->tstate, cmd->arg1,
+ object_search_ctlv(fo->tstate,
+ insntoc(cmd, kidx)->kidx,
IPFW_TLV_STATE_NAME));
break;
case O_IP6:
@@ -1851,7 +1911,7 @@ print_instruction(struct buf_pr *bp, const struct format_opts *fo,
bprintf(bp, " ip4");
break;
case O_ICMP6TYPE:
- print_icmp6types(bp, insntod(cmd, u32));
+ print_icmp6types(bp, insntoc(cmd, u32));
break;
case O_EXT_HDR:
print_ext6hdr(bp, cmd);
@@ -1860,7 +1920,7 @@ print_instruction(struct buf_pr *bp, const struct format_opts *fo,
if (F_LEN(cmd) == 1)
bprint_uint_arg(bp, " tagged ", cmd->arg1);
else
- print_newports(bp, insntod(cmd, u16),
+ print_newports(bp, insntoc(cmd, u16),
0, O_TAGGED);
break;
case O_SKIP_ACTION:
@@ -1871,12 +1931,10 @@ print_instruction(struct buf_pr *bp, const struct format_opts *fo,
if (cmd->arg1 == IP_FW_TARG)
bprintf(bp, " tablearg");
else
- bprintf(bp, " %#x",
- ((const ipfw_insn_u32 *)cmd)->d[0]);
+ bprintf(bp, " %#x", insntoc(cmd, u32)->d[0]);
- if (((const ipfw_insn_u32 *)cmd)->d[1] != 0xFFFFFFFF)
- bprintf(bp, ":%#x",
- ((const ipfw_insn_u32 *)cmd)->d[1]);
+ if (insntoc(cmd, u32)->d[1] != 0xFFFFFFFF)
+ bprintf(bp, ":%#x", insntoc(cmd, u32)->d[1]);
break;
default:
@@ -1929,14 +1987,14 @@ print_fwd(struct buf_pr *bp, const ipfw_insn *cmd)
uint16_t port;
if (cmd->opcode == O_FORWARD_IP) {
- sa = insntod(cmd, sa);
+ sa = insntoc(cmd, sa);
port = sa->sa.sin_port;
if (sa->sa.sin_addr.s_addr == INADDR_ANY)
bprintf(bp, "fwd tablearg");
else
bprintf(bp, "fwd %s", inet_ntoa(sa->sa.sin_addr));
} else {
- sa6 = insntod(cmd, sa6);
+ sa6 = insntoc(cmd, sa6);
port = sa6->sa.sin6_port;
bprintf(bp, "fwd ");
if (getnameinfo((const struct sockaddr *)&sa6->sa,
@@ -1948,6 +2006,26 @@ print_fwd(struct buf_pr *bp, const ipfw_insn *cmd)
bprintf(bp, ",%u", port);
}
+static void
+print_logdst(struct buf_pr *bp, uint16_t arg1)
+{
+ char const *comma = "";
+
+ bprintf(bp, " logdst ");
+ if (arg1 & IPFW_LOG_SYSLOG) {
+ bprintf(bp, "%ssyslog", comma);
+ comma = ",";
+ }
+ if (arg1 & IPFW_LOG_IPFW0) {
+ bprintf(bp, "%sipfw0", comma);
+ comma = ",";
+ }
+ if (arg1 & IPFW_LOG_RTSOCK) {
+ bprintf(bp, "%srtsock", comma);
+ comma = ",";
+ }
+}
+
static int
print_action_instruction(struct buf_pr *bp, const struct format_opts *fo,
struct show_state *state, const ipfw_insn *cmd)
@@ -1959,8 +2037,9 @@ print_action_instruction(struct buf_pr *bp, const struct format_opts *fo,
switch (cmd->opcode) {
case O_CHECK_STATE:
bprintf(bp, "check-state");
- if (cmd->arg1 != 0)
- s = object_search_ctlv(fo->tstate, cmd->arg1,
+ if (insntoc(cmd, kidx)->kidx != 0)
+ s = object_search_ctlv(fo->tstate,
+ insntoc(cmd, kidx)->kidx,
IPFW_TLV_STATE_NAME);
else
s = NULL;
@@ -1985,7 +2064,7 @@ print_action_instruction(struct buf_pr *bp, const struct format_opts *fo,
else if (cmd->arg1 == ICMP_UNREACH_NEEDFRAG &&
cmd->len == F_INSN_SIZE(ipfw_insn_u16))
bprintf(bp, "needfrag %u",
- ((const ipfw_insn_u16 *)cmd)->ports[0]);
+ insntoc(cmd, u16)->ports[0]);
else
print_reject_code(bp, cmd->arg1);
break;
@@ -1998,7 +2077,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 ", insntoc(cmd, u32)->d[0]);
break;
case O_PIPE:
bprint_uint_arg(bp, "pipe ", cmd->arg1);
@@ -2023,15 +2102,16 @@ print_action_instruction(struct buf_pr *bp, const struct format_opts *fo,
print_fwd(bp, cmd);
break;
case O_LOG:
- if (insntod(cmd, log)->max_log > 0)
- bprintf(bp, " log logamount %d",
- insntod(cmd, log)->max_log);
- else
- bprintf(bp, " log");
+ bprintf(bp, " log");
+ if (insntoc(cmd, log)->max_log > 0)
+ bprintf(bp, " logamount %d",
+ insntoc(cmd, log)->max_log);
+ if (cmd->arg1 != IPFW_LOG_DEFAULT)
+ print_logdst(bp, cmd->arg1);
break;
case O_ALTQ:
#ifndef NO_ALTQ
- print_altq_cmd(bp, insntod(cmd, altq));
+ print_altq_cmd(bp, insntoc(cmd, altq));
#endif
break;
case O_TAG:
@@ -2060,8 +2140,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 = insntoc(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);
@@ -2081,11 +2162,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,
+ insntoc(cmd, kidx)->kidx, 0);
if (s == NULL)
s = object_search_ctlv(fo->tstate,
- cmd->arg1, IPFW_TLV_EACTION_NAME(
- state->eaction->arg1));
+ insntoc(cmd, kidx)->kidx, IPFW_TLV_EACTION_NAME(
+ state->eaction->kidx));
bprintf(bp, " %s", s);
break;
case O_EXTERNAL_DATA:
@@ -2100,7 +2182,7 @@ print_action_instruction(struct buf_pr *bp, const struct format_opts *fo,
bprintf(bp, " %u", cmd->arg1);
else
bprintf(bp, " %ubytes",
- cmd->len * sizeof(uint32_t));
+ (unsigned)(cmd->len * sizeof(uint32_t)));
break;
case O_SETDSCP:
if (cmd->arg1 == IP_FW_TARG) {
@@ -2117,17 +2199,18 @@ print_action_instruction(struct buf_pr *bp, const struct format_opts *fo,
bprintf(bp, "reass");
break;
case O_CALLRETURN:
- if (cmd->len & F_NOT)
- bprintf(bp, "return");
- else
- bprint_uint_arg(bp, "call ", cmd->arg1);
+ if (cmd->len & F_NOT) {
+ s = match_value(return_types, cmd->arg1);
+ bprintf(bp, "return %s", s ? s: "<invalid>");
+ } else
+ bprint_uint_arg(bp, "call ", insntoc(cmd, u32)->d[0]);
break;
case O_SETMARK:
if (cmd->arg1 == IP_FW_TARG) {
bprintf(bp, "setmark tablearg");
break;
}
- bprintf(bp, "setmark %#x", ((const ipfw_insn_u32 *)cmd)->d[0]);
+ bprintf(bp, "setmark %#x", insntoc(cmd, u32)->d[0]);
break;
default:
bprintf(bp, "** unrecognized action %d len %d ",
@@ -2233,9 +2316,16 @@ print_address(struct buf_pr *bp, struct format_opts *fo,
count = portcnt = 0;
for (l = state->rule->act_ofs, cmd = state->rule->cmd;
l > 0; l -= F_LEN(cmd), cmd += F_LEN(cmd)) {
- if (match_opcode(cmd->opcode, opcodes, nops))
+ if (match_opcode(cmd->opcode, opcodes, nops)) {
+ /*
+ * Special handling for O_IP_DST_LOOKUP when
+ * lookup type is not LOOKUP_NONE.
+ */
+ if (cmd->opcode == O_IP_DST_LOOKUP &&
+ IPFW_LOOKUP_TYPE(cmd) != LOOKUP_NONE)
+ continue;
count++;
- else if (cmd->opcode == portop)
+ } else if (cmd->opcode == portop)
portcnt++;
}
if (count == 0)
@@ -2292,6 +2382,12 @@ static const int dst_opcodes[] = {
O_IP_DST_SET, O_IP6_DST, O_IP6_DST_MASK, O_IP6_DST_ME
};
+#if IPFW_DEFAULT_RULE > 65535
+#define RULENUM_FORMAT "%06d"
+#else
+#define RULENUM_FORMAT "%05d"
+#endif
+
static void
show_static_rule(struct cmdline_opts *co, struct format_opts *fo,
struct buf_pr *bp, struct ip_fw_rule *rule, struct ip_fw_bcounter *cntr)
@@ -2313,7 +2409,8 @@ show_static_rule(struct cmdline_opts *co, struct format_opts *fo,
warn("init_show_state() failed");
return;
}
- bprintf(bp, "%05u ", rule->rulenum);
+
+ bprintf(bp, RULENUM_FORMAT " ", rule->rulenum);
/* only if counters are available */
if (cntr != NULL) {
@@ -2380,6 +2477,13 @@ show_static_rule(struct cmdline_opts *co, struct format_opts *fo,
if (rule->flags & IPFW_RULE_JUSTOPTS) {
state.flags |= HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP;
+ /*
+ * Print `proto ip` if all opcodes has been already printed.
+ */
+ if (memchr(state.printed, 0, rule->act_ofs) == NULL) {
+ bprintf(bp, " proto ip");
+ goto end;
+ }
goto justopts;
}
@@ -2416,23 +2520,21 @@ 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 == 0 && 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, RULENUM_FORMAT, 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");
@@ -2524,9 +2626,8 @@ ipfw_sets_handler(char *av[])
ipfw_range_tlv rt;
const char *msg;
size_t size;
- uint32_t masks[2];
+ uint32_t masks[2], rulenum;
int i;
- uint16_t rulenum;
uint8_t cmd;
av++;
@@ -2577,7 +2678,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;
@@ -2630,6 +2731,18 @@ ipfw_sets_handler(char *av[])
errx(EX_USAGE, "invalid set command %s\n", *av);
}
+static void
+manage_skipto_cache(int op)
+{
+ ipfw_cmd_header req;
+
+ memset(&req, 0, sizeof(req));
+ req.size = sizeof(req);
+ req.cmd = op ? SKIPTO_CACHE_ENABLE : SKIPTO_CACHE_DISABLE;
+
+ do_set3(IP_FW_SKIPTO_CACHE, &req.opheader, sizeof(req));
+}
+
void
ipfw_sysctl_handler(char *av[], int which)
{
@@ -2654,6 +2767,8 @@ ipfw_sysctl_handler(char *av[], int which)
} else if (_substrcmp(*av, "dyn_keepalive") == 0) {
sysctlbyname("net.inet.ip.fw.dyn_keepalive", NULL, 0,
&which, sizeof(which));
+ } else if (_substrcmp(*av, "skipto_cache") == 0) {
+ manage_skipto_cache(which);
#ifndef NO_ALTQ
} else if (_substrcmp(*av, "altq") == 0) {
altq_set_enabled(which);
@@ -2672,7 +2787,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 */
@@ -2681,13 +2795,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)
@@ -2815,24 +2925,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);
@@ -3158,7 +3261,7 @@ eaction_check_name(const char *name)
return (0);
}
-static uint16_t
+static uint32_t
pack_object(struct tidx *tstate, const char *name, int otype)
{
ipfw_obj_ntlv *ntlv;
@@ -3195,7 +3298,7 @@ pack_object(struct tidx *tstate, const char *name, int otype)
return (ntlv->idx);
}
-static uint16_t
+static uint32_t
pack_table(struct tidx *tstate, const char *name)
{
@@ -3205,12 +3308,32 @@ pack_table(struct tidx *tstate, const char *name)
return (pack_object(tstate, name, IPFW_TLV_TBL_NAME));
}
+static void
+fill_table_value(ipfw_insn *cmd, char *s)
+{
+ char *p;
+ int i;
+
+ p = strchr(s, '=');
+ if (p != NULL) {
+ *p++ = '\0';
+ i = match_token(tvalue_names, s);
+ if (i == -1)
+ errx(EX_USAGE,
+ "format: unknown table value name %s", s);
+ } else {
+ i = TVALUE_TAG;
+ p = s;
+ }
+
+ IPFW_SET_TVALUE_TYPE(cmd, i);
+ insntod(cmd, table)->value = strtoul(p, NULL, 0);
+}
+
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)
@@ -3220,19 +3343,19 @@ 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);
+ fill_table_value(cmd, p);
+ } else {
+ IPFW_SET_LOOKUP_TYPE(cmd, LOOKUP_NONE);
+ cmd->len |= F_INSN_SIZE(ipfw_insn_kidx);
+ }
}
-
/*
* fills the addr and mask fields in the instruction as appropriate from av.
* Update length as appropriate.
@@ -3463,7 +3586,7 @@ ipfw_delete(char *av[])
{
ipfw_range_tlv rt;
char *sep;
- int i, j;
+ uint32_t i, j;
int exitval = EX_OK;
int do_set = 0;
@@ -3496,8 +3619,8 @@ ipfw_delete(char *av[])
rt.set = i & 31;
rt.flags = IPFW_RCFLAG_SET;
} else {
- rt.start_rule = i & 0xffff;
- rt.end_rule = j & 0xffff;
+ rt.start_rule = i;
+ rt.end_rule = j;
if (rt.start_rule == 0 && rt.end_rule == 0)
rt.flags |= IPFW_RCFLAG_ALL;
else
@@ -3522,7 +3645,7 @@ ipfw_delete(char *av[])
if (g_co.do_quiet)
continue;
if (rt.start_rule != rt.end_rule)
- warnx("no rules rules in %u-%u range",
+ warnx("no rules in %u-%u range",
rt.start_rule, rt.end_rule);
else
warnx("rule %u not found",
@@ -3534,7 +3657,6 @@ ipfw_delete(char *av[])
exit(exitval);
}
-
/*
* fill the interface structure. We do not check the name as we can
* create interfaces dynamically, so checking them at insert time
@@ -3546,7 +3668,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);
@@ -3854,6 +3976,8 @@ static struct _s_x f_reserved_keywords[] = {
{ "to", TOK_OR },
{ "via", TOK_OR },
{ "{", TOK_OR },
+ { "lookup", TOK_OR },
+ { "tagged", TOK_OR },
{ NULL, 0 } /* terminator */
};
@@ -3934,8 +4058,35 @@ add_dst(ipfw_insn *cmd, char *av, u_char proto, int cblen, struct tidx *tstate)
return ret;
}
-static inline int
-arg_or_targ_relaxed(const char *arg, const char *action)
+static uint16_t
+parse_logdst(char *logdst_iter)
+{
+ char *token;
+ uint16_t ret;
+
+ ret = IPFW_LOG_DEFAULT;
+ while ((token = strsep(&logdst_iter, ",")) != NULL) {
+ if (_substrcmp(token, "syslog") == 0) {
+ ret |= IPFW_LOG_SYSLOG;
+ continue;
+ }
+ if (_substrcmp(token, "ipfw0") == 0) {
+ /* XXX add multiple ipfw* */
+ ret |= IPFW_LOG_IPFW0;
+ continue;
+ }
+ if (_substrcmp(token, "rtsock") == 0) {
+ ret |= IPFW_LOG_RTSOCK;
+ continue;
+ }
+ errx(EX_DATAERR,
+ "unsupported logdst token");
+ }
+ return (ret);
+}
+
+static inline uint32_t
+arg_or_targ_relaxed(const char *arg, const char *action, uint32_t maxarg)
{
uint32_t arg1 = (uint32_t)(-1);
@@ -3943,7 +4094,7 @@ arg_or_targ_relaxed(const char *arg, const char *action)
errx(EX_USAGE, "missing argument for %s", action);
if (isdigit(arg[0])) {
arg1 = strtoul(arg, NULL, 10);
- if (arg1 <= 0 || arg1 >= IP_FW_TABLEARG)
+ if (arg1 < IPFW_ARG_MIN || arg1 > maxarg)
errx(EX_DATAERR, "illegal argument %s(%u) for %s",
arg, arg1, action);
} else if (_substrcmp(arg, "tablearg") == 0)
@@ -3951,10 +4102,10 @@ arg_or_targ_relaxed(const char *arg, const char *action)
return (arg1);
}
-static inline uint16_t
+static inline uint32_t
arg_or_targ(const char *arg, const char *action)
{
- uint32_t arg1 = arg_or_targ_relaxed(arg, action);
+ uint32_t arg1 = arg_or_targ_relaxed(arg, action, IPFW_ARG_MAX);
if (arg1 == (uint32_t)(-1))
errx(EX_DATAERR, "illegal argument %s(%u) for %s",
@@ -3965,7 +4116,7 @@ arg_or_targ(const char *arg, const char *action)
static uint16_t
get_divert_port(const char *arg, const char *action)
{
- uint32_t arg1 = arg_or_targ_relaxed(arg, action);
+ uint32_t arg1 = arg_or_targ_relaxed(arg, action, IPFW_ARG_MAX);
if (arg1 != (uint32_t)(-1))
return (arg1);
@@ -4035,8 +4186,8 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate)
rblen = *rbufsize / sizeof(uint32_t);
rblen -= sizeof(struct ip_fw_rule) / sizeof(uint32_t);
- ablen = sizeof(actbuf) / sizeof(actbuf[0]);
- cblen = sizeof(cmdbuf) / sizeof(cmdbuf[0]);
+ ablen = nitems(actbuf);
+ cblen = nitems(cmdbuf);
cblen -= F_INSN_SIZE(ipfw_insn_u32) + 1;
#define CHECK_RBUFLEN(len) { CHECK_LENGTH(rblen, len); rblen -= len; }
@@ -4079,18 +4230,20 @@ 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 (*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);
@@ -4147,7 +4300,7 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate)
errx(EX_DATAERR, "illegal argument for %s",
*(av - 1));
action->len = F_INSN_SIZE(ipfw_insn_u16);
- ((ipfw_insn_u16 *)action)->ports[0] = mtu;
+ insntod(action, u16)->ports[0] = mtu;
av++;
}
break;
@@ -4185,7 +4338,10 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate)
break;
case TOK_SKIPTO:
action->opcode = O_SKIPTO;
- action->arg1 = arg_or_targ(av[0], *(av - 1));
+ action->len = F_INSN_SIZE(ipfw_insn_u32);
+ CHECK_ACTLEN;
+ insntod(action, u32)->d[0] =
+ arg_or_targ_relaxed(av[0], *(av - 1), IPFW_DEFAULT_RULE);
av++;
break;
case TOK_NETGRAPH:
@@ -4210,7 +4366,10 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate)
break;
case TOK_CALL:
action->opcode = O_CALLRETURN;
- action->arg1 = arg_or_targ(av[0], *(av - 1));
+ action->len = F_INSN_SIZE(ipfw_insn_u32);
+ CHECK_ACTLEN;
+ insntod(action, u32)->d[0] =
+ arg_or_targ_relaxed(av[0], *(av - 1), IPFW_DEFAULT_RULE);
av++;
break;
@@ -4378,7 +4537,21 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate)
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;
+ if (*av != NULL) {
+ /*
+ * Return type is optional.
+ * By default we use RETURN_NEXT_RULENUM.
+ */
+ i = match_token(return_types, *av);
+ if (i >= 0) {
+ action->arg1 = i;
+ av++;
+ } else
+ action->arg1 = RETURN_NEXT_RULENUM;
+ }
break;
case TOK_SETMARK: {
@@ -4388,8 +4561,7 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate)
if (strcmp(*av, "tablearg") == 0) {
action->arg1 = IP_FW_TARG;
} else {
- ((ipfw_insn_u32 *)action)->d[0] =
- strtoul(*av, NULL, 0);
+ insntod(action, u32)->d[0] = strtoul(*av, NULL, 0);
/* This is not a tablearg */
action->arg1 |= 0x8000;
}
@@ -4400,12 +4572,16 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate)
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;
@@ -4431,7 +4607,7 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate)
* syntax.
*/
case TOK_EACTION: {
- uint16_t idx;
+ uint32_t idx;
NEED1("Missing eaction name");
if (eaction_check_name(*av) != 0)
@@ -4439,12 +4615,13 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate)
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);
@@ -4456,7 +4633,11 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate)
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++;
}
}
@@ -4484,6 +4665,15 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate)
cmd->len = F_INSN_SIZE(ipfw_insn_log);
CHECK_CMDLEN;
cmd->opcode = O_LOG;
+ cmd->arg1 = IPFW_LOG_DEFAULT;
+ /* logdst before logamount */
+ if (av[0] && _substrcmp(*av, "logdst") == 0) {
+ av++;
+ NEED1("logdst requires argument");
+ cmd->arg1 = parse_logdst(*av);
+ av++;
+ }
+
if (av[0] && _substrcmp(*av, "logamount") == 0) {
av++;
NEED1("logamount requires argument");
@@ -4505,6 +4695,14 @@ compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate)
"net.inet.ip.fw.verbose_limit");
}
}
+
+ /* logdst after logamount */
+ if (av[0] && _substrcmp(*av, "logdst") == 0) {
+ av++;
+ NEED1("logdst requires argument");
+ cmd->arg1 = parse_logdst(*av);
+ av++;
+ }
}
break;
@@ -4817,7 +5015,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;
@@ -5027,7 +5225,7 @@ 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 "
@@ -5047,13 +5245,16 @@ 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)
@@ -5065,10 +5266,10 @@ read_options:
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)
@@ -5088,11 +5289,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;
}
@@ -5249,24 +5450,55 @@ read_options:
break;
case TOK_LOOKUP: {
- ipfw_insn_u32 *c = (ipfw_insn_u32 *)cmd;
+ /* optional mask for some LOOKUP types */
+ ipfw_insn_table *c = insntod(cmd, table);
+ char *lkey;
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(lookup_keys, *av);
- if (i == -1)
- errx(EX_USAGE, "format: cannot lookup on %s", *av);
- __PAST_END(c->d, 1) = i;
- av++;
- if ((i = pack_table(tstate, *av)) == 0)
- errx(EX_DATAERR, "Invalid table name: %s", *av);
+ lkey = strsep(av, ":");
+ i = match_token(lookup_keys, lkey);
+ if (i == -1)
+ errx(EX_USAGE,
+ "format: cannot lookup on %s", lkey);
+ /* masked lookup key */
+ if (*av != NULL) {
+ switch (i) {
+ case LOOKUP_DST_PORT:
+ case LOOKUP_SRC_PORT:
+ case LOOKUP_UID:
+ case LOOKUP_JAIL:
+ case LOOKUP_DSCP:
+ case LOOKUP_MARK:
+ case LOOKUP_RULENUM:
+ break;
+ default:
+ errx(EX_USAGE,
+ "masked lookup is not supported "
+ "for %s", lkey);
+ }
+ cmd->len |= F_INSN_SIZE(ipfw_insn_table);
+ c->value = strtoul(*av, NULL, 0);
+ if (c->value == 0)
+ errx(EX_USAGE,
+ "all-zeroes bitmask for lookup "
+ "is meaningless");
+ } else {
+ cmd->len |= F_INSN_SIZE(ipfw_insn_kidx);
+ }
+ CHECK_CMDLEN;
- cmd->arg1 = i;
+ IPFW_SET_LOOKUP_TYPE(cmd, i);
av++;
- }
+ c->kidx = pack_table(tstate, *av);
+ if (c->kidx == 0)
+ errx(EX_DATAERR,
+ "Invalid table name: %s", *av);
+ av++;
+ }
break;
case TOK_FLOW:
NEED1("missing table name");
@@ -5329,7 +5561,9 @@ 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);
+ 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);
}
@@ -5451,7 +5685,7 @@ object_sort_ctlv(ipfw_obj_ctlv *ctlv)
}
struct object_kt {
- uint16_t uidx;
+ uint32_t uidx;
uint16_t type;
};
static int
@@ -5485,7 +5719,7 @@ compare_object_kntlv(const void *k, const void *v)
* Returns table name or NULL.
*/
static char *
-object_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx, uint16_t type)
+object_search_ctlv(ipfw_obj_ctlv *ctlv, uint32_t idx, uint16_t type)
{
ipfw_obj_ntlv *ntlv;
struct object_kt key;
@@ -5503,7 +5737,7 @@ object_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx, uint16_t type)
}
static char *
-table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx)
+table_search_ctlv(ipfw_obj_ctlv *ctlv, uint32_t idx)
{
return (object_search_ctlv(ctlv, idx, IPFW_TLV_TBL_NAME));
@@ -5724,6 +5958,7 @@ static struct _s_x intcmds[] = {
{ "iflist", TOK_IFLIST },
{ "olist", TOK_OLIST },
{ "vlist", TOK_VLIST },
+ { "monitor", TOK_MONITOR },
{ NULL, 0 }
};
@@ -5798,6 +6033,134 @@ ipfw_list_objects(int ac __unused, char *av[] __unused)
free(olh);
}
+static void
+bprint_sa(struct buf_pr *bp, const struct sockaddr *sa)
+{
+ struct sockaddr_storage ss;
+ char buf[INET6_ADDRSTRLEN];
+
+ memset(&ss, 0, sizeof(ss));
+ if (sa->sa_len == 0)
+ ss.ss_family = sa->sa_family;
+ else
+ memcpy(&ss, sa, sa->sa_len);
+
+ /* set ss_len in case it was shortened */
+ switch (sa->sa_family) {
+ case AF_INET:
+ ss.ss_len = sizeof(struct sockaddr_in);
+ break;
+ default:
+ ss.ss_len = sizeof(struct sockaddr_in6);
+ }
+ if (getnameinfo((const struct sockaddr *)&ss, ss.ss_len,
+ buf, sizeof(buf), NULL, 0, NI_NUMERICHOST) != 0) {
+ bprintf(bp, "bad-addr");
+ return;
+ }
+ bprintf(bp, "%s", buf);
+}
+
+static void
+ipfw_rtsock_monitor(const char *filter)
+{
+ char msg[2048], buf[32];
+ struct timespec tp;
+ struct tm tm;
+ struct buf_pr bp;
+ struct rt_msghdr *hdr;
+ struct sockaddr *sa;
+ struct sockaddr_dl *sdl;
+ ipfwlog_rtsock_hdr_v2 *loghdr;
+ ssize_t nread;
+ size_t msglen;
+ int rtsock;
+
+ rtsock = socket(PF_ROUTE, SOCK_RAW, AF_IPFWLOG);
+ if (rtsock < 0)
+ err(EX_UNAVAILABLE, "socket(AF_IPFWLOG)");
+ bp_alloc(&bp, 4096);
+ for (;;) {
+ nread = read(rtsock, msg, sizeof(msg));
+ if (nread < 0) {
+ warn("read()");
+ continue;
+ }
+ msglen = nread;
+ if (msglen < sizeof(*hdr))
+ continue;
+
+ hdr = (struct rt_msghdr *)msg;
+ if (hdr->rtm_version != RTM_VERSION ||
+ hdr->rtm_type != RTM_IPFWLOG ||
+ (hdr->rtm_addrs & (1 << RTAX_DST)) == 0 ||
+ (hdr->rtm_addrs & (1 << RTAX_GATEWAY)) == 0 ||
+ (hdr->rtm_addrs & (1 << RTAX_NETMASK)) == 0)
+ continue;
+
+ msglen -= sizeof(*hdr);
+ sdl = (struct sockaddr_dl *)(hdr + 1);
+ if (msglen < sizeof(*sdl) || msglen < SA_SIZE(sdl) ||
+ sdl->sdl_family != AF_IPFWLOG ||
+ sdl->sdl_type != 2 /* version */ ||
+ sdl->sdl_alen != sizeof(*loghdr))
+ continue;
+
+ msglen -= SA_SIZE(sdl);
+ loghdr = (ipfwlog_rtsock_hdr_v2 *)sdl->sdl_data;
+ /* filter by rule comment. MAX_COMMENT_LEN = 80 */
+ if (filter != NULL &&
+ strncmp(filter, loghdr->comment, 80) != 0)
+ continue;
+
+ sa = (struct sockaddr *)((char *)sdl + SA_SIZE(sdl));
+ if (msglen < SA_SIZE(sa))
+ continue;
+
+ msglen -= SA_SIZE(sa);
+ bp_flush(&bp);
+
+ clock_gettime(CLOCK_REALTIME, &tp);
+ localtime_r(&tp.tv_sec, &tm);
+ strftime(buf, sizeof(buf), "%T", &tm);
+ bprintf(&bp, "%s.%03ld AF %s", buf, tp.tv_nsec / 1000000,
+ sa->sa_family == AF_INET ? "IPv4" : "IPv6");
+
+ bprintf(&bp, " %s >",
+ ether_ntoa((const struct ether_addr *)loghdr->ether_shost));
+ bprintf(&bp, " %s, ",
+ ether_ntoa((const struct ether_addr *)loghdr->ether_dhost));
+ bprint_sa(&bp, sa);
+
+ sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa));
+ if (msglen < SA_SIZE(sa))
+ continue;
+
+ msglen -= SA_SIZE(sa);
+ bprintf(&bp, " > ");
+ bprint_sa(&bp, sa);
+ bprintf(&bp, ", set %u, rulenum %u, targ 0x%08x, "
+ "%scmd[op %d, len %d, arg1 0x%04x], mark 0x%08x",
+ sdl->sdl_index, loghdr->rulenum, loghdr->tablearg,
+ (loghdr->cmd.len & F_NOT) ? "!": "",
+ loghdr->cmd.opcode, F_LEN(&loghdr->cmd),
+ loghdr->cmd.arg1, loghdr->mark);
+
+ sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa));
+ if ((hdr->rtm_addrs & (1 << RTAX_GENMASK)) != 0 &&
+ msglen >= SA_SIZE(sa)) {
+ msglen -= SA_SIZE(sa);
+ bprintf(&bp, ", nh ");
+ bprint_sa(&bp, sa);
+ }
+ if (sdl->sdl_nlen > 0)
+ bprintf(&bp, " // %s", loghdr->comment);
+ printf("%s\n", bp.buf);
+ }
+ bp_free(&bp);
+ close(rtsock);
+}
+
void
ipfw_internal_handler(int ac, char *av[])
{
@@ -5822,6 +6185,10 @@ ipfw_internal_handler(int ac, char *av[])
case TOK_VLIST:
ipfw_list_values(ac, av);
break;
+ case TOK_MONITOR:
+ av++;
+ ipfw_rtsock_monitor(*av);
+ break;
}
}