svn commit: r332400 - stable/11/sbin/ipfw
Andrey V. Elsukov
ae at FreeBSD.org
Wed Apr 11 10:24:48 UTC 2018
Author: ae
Date: Wed Apr 11 10:24:47 2018
New Revision: 332400
URL: https://svnweb.freebsd.org/changeset/base/332400
Log:
MFC r331668:
Rework ipfw rules parsing and printing code.
Introduce show_state structure to keep information about printed opcodes.
Split show_static_rule() function into several smaller functions. Make
parsing and printing opcodes into several passes. Each printed opcode
is marked in show_state structure and will be skipped in next passes.
Now show_static_rule() function is simple, it just prints each part
of rule separately: action, modifiers, proto, src and dst addresses,
options. The main goal of this change is avoiding occurrence of wrong
result of `ifpw show` command, that can not be parsed by ipfw(8).
Also now it is possible to make some simple static optimizations
by reordering of opcodes in the rule.
PR: 222705
Modified:
stable/11/sbin/ipfw/ipfw2.c
stable/11/sbin/ipfw/ipfw2.h
stable/11/sbin/ipfw/main.c
Directory Properties:
stable/11/ (props changed)
Modified: stable/11/sbin/ipfw/ipfw2.c
==============================================================================
--- stable/11/sbin/ipfw/ipfw2.c Wed Apr 11 07:15:30 2018 (r332399)
+++ stable/11/sbin/ipfw/ipfw2.c Wed Apr 11 10:24:47 2018 (r332400)
@@ -1176,7 +1176,7 @@ print_flags(struct buf_pr *bp, char const *name, ipfw_
* Print the ip address contained in a command.
*/
static void
-print_ip(struct buf_pr *bp, struct format_opts *fo, ipfw_insn_ip *cmd,
+print_ip(struct buf_pr *bp, const struct format_opts *fo, ipfw_insn_ip *cmd,
char const *s)
{
struct hostent *he = NULL;
@@ -1277,7 +1277,7 @@ print_ip(struct buf_pr *bp, struct format_opts *fo, ip
* prints a MAC address/mask pair
*/
static void
-print_mac(struct buf_pr *bp, uint8_t *addr, uint8_t *mask)
+format_mac(struct buf_pr *bp, uint8_t *addr, uint8_t *mask)
{
int l = contigmask(mask, 48);
@@ -1296,6 +1296,15 @@ print_mac(struct buf_pr *bp, uint8_t *addr, uint8_t *m
}
static void
+print_mac(struct buf_pr *bp, ipfw_insn_mac *mac)
+{
+
+ bprintf(bp, " MAC");
+ format_mac(bp, mac->addr, mac->mask);
+ format_mac(bp, mac->addr + 6, mac->mask + 6);
+}
+
+static void
fill_icmptypes(ipfw_insn_u32 *cmd, char *av)
{
uint8_t type;
@@ -1358,817 +1367,843 @@ print_dscp(struct buf_pr *bp, ipfw_insn_u32 *cmd)
}
}
-/*
- * show_ipfw() prints the body of an ipfw rule.
- * Because the standard rule has at least proto src_ip dst_ip, we use
- * a helper function to produce these entries if not provided explicitly.
- * The first argument is the list of fields we have, the second is
- * the list of fields we want to be printed.
- *
- * Special cases if we have provided a MAC header:
- * + if the rule does not contain IP addresses/ports, do not print them;
- * + if the rule does not contain an IP proto, print "all" instead of "ip";
- *
- * Once we have 'have_options', IP header fields are printed as options.
- */
+#define insntod(cmd, type) ((ipfw_insn_ ## type *)(cmd))
+struct show_state {
+ struct ip_fw_rule *rule;
+ const ipfw_insn *eaction;
+ uint8_t *printed;
+ int flags;
#define HAVE_PROTO 0x0001
#define HAVE_SRCIP 0x0002
#define HAVE_DSTIP 0x0004
-#define HAVE_PROTO4 0x0008
-#define HAVE_PROTO6 0x0010
-#define HAVE_IP 0x0100
-#define HAVE_OPTIONS 0x8000
+ int proto;
+ int or_block;
+};
-static void
-show_prerequisites(struct buf_pr *bp, int *flags, int want, int cmd)
+static int
+init_show_state(struct show_state *state, struct ip_fw_rule *rule)
{
- (void)cmd; /* UNUSED */
- if (co.comment_only)
- return;
- if ( (*flags & HAVE_IP) == HAVE_IP)
- *flags |= HAVE_OPTIONS;
- if ( !(*flags & HAVE_OPTIONS)) {
- if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO)) {
- if ( (*flags & HAVE_PROTO4))
- bprintf(bp, " ip4");
- else if ( (*flags & HAVE_PROTO6))
- bprintf(bp, " ip6");
- else
- bprintf(bp, " ip");
- }
- if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP))
- bprintf(bp, " from any");
- if ( !(*flags & HAVE_DSTIP) && (want & HAVE_DSTIP))
- bprintf(bp, " to any");
- }
- *flags |= want;
+ state->printed = calloc(rule->cmd_len, sizeof(uint8_t));
+ if (state->printed == NULL)
+ return (ENOMEM);
+ state->rule = rule;
+ state->eaction = NULL;
+ state->flags = 0;
+ state->proto = 0;
+ state->or_block = 0;
+ return (0);
}
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)
+free_show_state(struct show_state *state)
{
- static int twidth = 0;
- int l;
- ipfw_insn *cmd, *has_eaction = NULL, *tagptr = NULL;
- const char *comment = NULL; /* ptr to comment if we have one */
- const char *ename;
- int proto = 0; /* default */
- int flags = 0; /* prerequisites */
- 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 */
- if (!co->show_sets)
- return;
- else
- bprintf(bp, "# DISABLED ");
- }
- bprintf(bp, "%05u ", rule->rulenum);
+ free(state->printed);
+}
- /* Print counters if enabled */
- if (fo->pcwidth > 0 || fo->bcwidth > 0) {
- pr_u64(bp, &cntr->pcnt, fo->pcwidth);
- pr_u64(bp, &cntr->bcnt, fo->bcwidth);
- }
+static uint8_t
+is_printed_opcode(struct show_state *state, const ipfw_insn *cmd)
+{
- if (co->do_time == 2)
- bprintf(bp, "%10u ", cntr->timestamp);
- else if (co->do_time == 1) {
- char timestr[30];
- time_t t = (time_t)0;
+ return (state->printed[cmd - state->rule->cmd]);
+}
- if (twidth == 0) {
- strcpy(timestr, ctime(&t));
- *strchr(timestr, '\n') = '\0';
- twidth = strlen(timestr);
- }
- if (cntr->timestamp > 0) {
- t = _long_to_time(cntr->timestamp);
+static void
+mark_printed(struct show_state *state, const ipfw_insn *cmd)
+{
- strcpy(timestr, ctime(&t));
- *strchr(timestr, '\n') = '\0';
- bprintf(bp, "%s ", timestr);
- } else {
- bprintf(bp, "%*s", twidth, " ");
- }
- }
+ state->printed[cmd - state->rule->cmd] = 1;
+}
- if (co->show_sets)
- bprintf(bp, "set %d ", rule->set);
+static void
+print_limit(struct buf_pr *bp, const ipfw_insn_limit *limit)
+{
+ struct _s_x *p = limit_masks;
+ char const *comma = " ";
+ uint8_t x;
- /*
- * print the optional "match probability"
- */
- if (rule->cmd_len > 0) {
- cmd = rule->cmd ;
- if (cmd->opcode == O_PROB) {
- ipfw_insn_u32 *p = (ipfw_insn_u32 *)cmd;
- double d = 1.0 * p->d[0];
-
- d = (d / 0x7fffffff);
- bprintf(bp, "prob %f ", d);
+ bprintf(bp, " limit");
+ for (x = limit->limit_mask; p->x != 0; p++) {
+ if ((x & p->x) == p->x) {
+ x &= ~p->x;
+ bprintf(bp, "%s%s", comma, p->s);
+ comma = ",";
}
}
+ bprint_uint_arg(bp, " ", limit->conn_limit);
+}
- /*
- * first print actions
- */
- for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule);
- l > 0 ; l -= F_LEN(cmd), cmd += F_LEN(cmd)) {
- switch(cmd->opcode) {
- case O_CHECK_STATE:
- bprintf(bp, "check-state");
- if (cmd->arg1 != 0)
- ename = object_search_ctlv(fo->tstate,
- cmd->arg1, IPFW_TLV_STATE_NAME);
- else
- ename = NULL;
- bprintf(bp, " :%s", ename ? ename: "any");
- /* avoid printing anything else */
- flags = HAVE_PROTO | HAVE_SRCIP |
- HAVE_DSTIP | HAVE_IP;
- break;
+static int
+print_instruction(struct buf_pr *bp, const struct format_opts *fo,
+ struct show_state *state, ipfw_insn *cmd)
+{
+ struct protoent *pe;
+ struct passwd *pwd;
+ struct group *grp;
+ const char *s;
+ double d;
- case O_ACCEPT:
- bprintf(bp, "allow");
- break;
+ if (is_printed_opcode(state, cmd))
+ return (0);
+ if ((cmd->len & F_OR) != 0 && state->or_block == 0)
+ bprintf(bp, " {");
+ if (cmd->opcode != O_IN && (cmd->len & F_NOT) != 0)
+ bprintf(bp, " not");
- case O_COUNT:
- bprintf(bp, "count");
+ switch (cmd->opcode) {
+ case O_PROB:
+ d = 1.0 * insntod(cmd, u32)->d[0] / 0x7fffffff;
+ bprintf(bp, "prob %f ", d);
+ break;
+ case O_PROBE_STATE: /* no need to print anything here */
+ break;
+ case O_IP_SRC:
+ case O_IP_SRC_LOOKUP:
+ case O_IP_SRC_MASK:
+ case O_IP_SRC_ME:
+ case O_IP_SRC_SET:
+ case O_IP_DST:
+ case O_IP_DST_LOOKUP:
+ case O_IP_DST_MASK:
+ case O_IP_DST_ME:
+ case O_IP_DST_SET:
+ print_ip(bp, fo, insntod(cmd, ip), "");
+ break;
+ case O_IP6_SRC:
+ case O_IP6_SRC_MASK:
+ case O_IP6_SRC_ME:
+ case O_IP6_DST:
+ case O_IP6_DST_MASK:
+ case O_IP6_DST_ME:
+ print_ip6(bp, insntod(cmd, ip6), "");
+ break;
+ case O_FLOW6ID:
+ print_flow6id(bp, insntod(cmd, u32));
+ break;
+ case O_IP_DSTPORT:
+ case O_IP_SRCPORT:
+ print_newports(bp, insntod(cmd, u16), state->proto,
+ (state->flags & (HAVE_SRCIP | HAVE_DSTIP)) ==
+ (HAVE_SRCIP | HAVE_DSTIP) ? cmd->opcode: 0);
+ break;
+ case O_PROTO:
+ pe = getprotobynumber(cmd->arg1);
+ if (state->flags & HAVE_PROTO)
+ bprintf(bp, " proto");
+ if (pe != NULL)
+ bprintf(bp, " %s", pe->p_name);
+ else
+ bprintf(bp, " %u", cmd->arg1);
+ break;
+ case O_MACADDR2:
+ print_mac(bp, insntod(cmd, mac));
+ break;
+ case O_MAC_TYPE:
+ print_newports(bp, insntod(cmd, u16),
+ IPPROTO_ETHERTYPE, cmd->opcode);
+ break;
+ case O_FRAG:
+ bprintf(bp, " frag");
+ break;
+ case O_FIB:
+ bprintf(bp, " fib %u", cmd->arg1);
+ break;
+ case O_SOCKARG:
+ bprintf(bp, " sockarg");
+ break;
+ case O_IN:
+ bprintf(bp, cmd->len & F_NOT ? " out" : " in");
+ break;
+ case O_DIVERTED:
+ switch (cmd->arg1) {
+ case 3:
+ bprintf(bp, " diverted");
break;
-
- case O_DENY:
- bprintf(bp, "deny");
+ case 2:
+ bprintf(bp, " diverted-output");
break;
-
- case O_REJECT:
- if (cmd->arg1 == ICMP_REJECT_RST)
- bprintf(bp, "reset");
- else if (cmd->arg1 == ICMP_REJECT_ABORT)
- bprintf(bp, "abort");
- else if (cmd->arg1 == ICMP_UNREACH_HOST)
- bprintf(bp, "reject");
- else
- print_reject_code(bp, cmd->arg1);
+ case 1:
+ bprintf(bp, " diverted-loopback");
break;
-
- case O_UNREACH6:
- if (cmd->arg1 == ICMP6_UNREACH_RST)
- bprintf(bp, "reset6");
- else if (cmd->arg1 == ICMP6_UNREACH_ABORT)
- bprintf(bp, "abort6");
- else
- print_unreach6_code(bp, cmd->arg1);
+ default:
+ bprintf(bp, " diverted-?<%u>", cmd->arg1);
break;
-
- case O_SKIPTO:
- bprint_uint_arg(bp, "skipto ", cmd->arg1);
+ }
+ break;
+ case O_LAYER2:
+ bprintf(bp, " layer2");
+ break;
+ case O_XMIT:
+ case O_RECV:
+ case O_VIA:
+ if (cmd->opcode == O_XMIT)
+ s = "xmit";
+ else if (cmd->opcode == O_RECV)
+ s = "recv";
+ else /* if (cmd->opcode == O_VIA) */
+ s = "via";
+ switch (insntod(cmd, if)->name[0]) {
+ case '\0':
+ bprintf(bp, " %s %s", s,
+ inet_ntoa(insntod(cmd, if)->p.ip));
break;
-
- case O_PIPE:
- bprint_uint_arg(bp, "pipe ", cmd->arg1);
+ case '\1':
+ bprintf(bp, " %s table(%s)", s,
+ table_search_ctlv(fo->tstate,
+ insntod(cmd, if)->p.kidx));
break;
-
- case O_QUEUE:
- bprint_uint_arg(bp, "queue ", cmd->arg1);
- break;
-
- case O_DIVERT:
- bprint_uint_arg(bp, "divert ", cmd->arg1);
- break;
-
- case O_TEE:
- bprint_uint_arg(bp, "tee ", cmd->arg1);
- break;
-
- case O_NETGRAPH:
- bprint_uint_arg(bp, "netgraph ", cmd->arg1);
- break;
-
- case O_NGTEE:
- bprint_uint_arg(bp, "ngtee ", cmd->arg1);
- break;
-
- case O_FORWARD_IP:
- {
- ipfw_insn_sa *s = (ipfw_insn_sa *)cmd;
-
- if (s->sa.sin_addr.s_addr == INADDR_ANY) {
- bprintf(bp, "fwd tablearg");
- } else {
- bprintf(bp, "fwd %s",inet_ntoa(s->sa.sin_addr));
- }
- if (s->sa.sin_port)
- bprintf(bp, ",%d", s->sa.sin_port);
- }
- break;
-
- case O_FORWARD_IP6:
- {
- char buf[INET6_ADDRSTRLEN + IF_NAMESIZE + 2];
- ipfw_insn_sa6 *s = (ipfw_insn_sa6 *)cmd;
-
- bprintf(bp, "fwd ");
- if (getnameinfo((const struct sockaddr *)&s->sa,
- sizeof(struct sockaddr_in6), buf, sizeof(buf),
- NULL, 0, NI_NUMERICHOST) == 0)
- bprintf(bp, "%s", buf);
- if (s->sa.sin6_port)
- bprintf(bp, ",%d", s->sa.sin6_port);
- }
- break;
-
- case O_LOG: /* O_LOG is printed last */
- logptr = (ipfw_insn_log *)cmd;
- break;
-
- case O_ALTQ: /* O_ALTQ is printed after O_LOG */
- altqptr = (ipfw_insn_altq *)cmd;
- break;
-
- case O_TAG:
- tagptr = cmd;
- break;
-
- case O_NAT:
- if (cmd->arg1 != IP_FW_NAT44_GLOBAL)
- bprint_uint_arg(bp, "nat ", cmd->arg1);
- else
- bprintf(bp, "nat global");
- break;
-
- case O_SETFIB:
- if (cmd->arg1 == IP_FW_TARG)
- bprint_uint_arg(bp, "setfib ", cmd->arg1);
- else
- bprintf(bp, "setfib %u", cmd->arg1 & 0x7FFF);
- break;
-
- case O_EXTERNAL_ACTION: {
- /*
- * The external action can consists of two following
- * each other opcodes - O_EXTERNAL_ACTION and
- * O_EXTERNAL_INSTANCE. The first contains the ID of
- * name of external action. The second contains the ID
- * of name of external action instance.
- * NOTE: in case when external action has no named
- * instances support, the second opcode isn't needed.
- */
- has_eaction = cmd;
- ename = object_search_ctlv(fo->tstate, cmd->arg1,
- IPFW_TLV_EACTION);
- if (match_token(rule_eactions, ename) != -1)
- bprintf(bp, "%s", ename);
- else
- bprintf(bp, "eaction %s", ename);
- break;
+ default:
+ bprintf(bp, " %s %s", s,
+ insntod(cmd, if)->name);
}
-
- case O_EXTERNAL_INSTANCE: {
- if (has_eaction == NULL)
+ break;
+ case O_IP_FLOW_LOOKUP:
+ s = table_search_ctlv(fo->tstate, cmd->arg1);
+ bprintf(bp, " flow table(%s", s);
+ if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32))
+ bprintf(bp, ",%u", insntod(cmd, u32)->d[0]);
+ bprintf(bp, ")");
+ break;
+ case O_IPID:
+ case O_IPTTL:
+ case O_IPLEN:
+ case O_TCPDATALEN:
+ case O_TCPWIN:
+ if (F_LEN(cmd) == 1) {
+ switch (cmd->opcode) {
+ case O_IPID:
+ s = "ipid";
break;
- /*
- * XXX: we need to teach ipfw(9) to rewrite opcodes
- * in the user buffer on rule addition. When we add
- * the rule, we specify zero TLV type for
- * O_EXTERNAL_INSTANCE object. To show correct
- * rule after `ipfw add` we need to search instance
- * name with zero type. But when we do `ipfw show`
- * we calculate TLV type using IPFW_TLV_EACTION_NAME()
- * macro.
- */
- ename = object_search_ctlv(fo->tstate, cmd->arg1, 0);
- if (ename == NULL)
- ename = object_search_ctlv(fo->tstate,
- cmd->arg1,
- IPFW_TLV_EACTION_NAME(has_eaction->arg1));
- bprintf(bp, " %s", ename);
- break;
- }
-
- case O_EXTERNAL_DATA: {
- if (has_eaction == NULL)
+ case O_IPTTL:
+ s = "ipttl";
break;
- /*
- * Currently we support data formatting only for
- * external data with datalen u16. For unknown data
- * print its size in bytes.
- */
- if (cmd->len == F_INSN_SIZE(ipfw_insn))
- bprintf(bp, " %u", cmd->arg1);
- else
- bprintf(bp, " %ubytes",
- cmd->len * sizeof(uint32_t));
- break;
- }
-
- case O_SETDSCP:
- {
- const char *code;
-
- if (cmd->arg1 == IP_FW_TARG) {
- bprint_uint_arg(bp, "setdscp ", cmd->arg1);
+ case O_IPLEN:
+ s = "iplen";
break;
+ case O_TCPDATALEN:
+ s = "tcpdatalen";
+ break;
+ case O_TCPWIN:
+ s = "tcpwin";
+ break;
}
- uval = cmd->arg1 & 0x3F;
- if ((code = match_value(f_ipdscp, uval)) != NULL)
- bprintf(bp, "setdscp %s", code);
- else
- bprint_uint_arg(bp, "setdscp ", uval);
- }
- break;
+ bprintf(bp, " %s %u", s, cmd->arg1);
+ } else
+ print_newports(bp, insntod(cmd, u16), 0,
+ cmd->opcode);
+ break;
+ case O_IPVER:
+ bprintf(bp, " ipver %u", cmd->arg1);
+ break;
+ case O_IPPRECEDENCE:
+ bprintf(bp, " ipprecedence %u", cmd->arg1 >> 5);
+ break;
+ case O_DSCP:
+ print_dscp(bp, insntod(cmd, u32));
+ break;
+ case O_IPOPT:
+ print_flags(bp, "ipoptions", cmd, f_ipopts);
+ break;
+ case O_IPTOS:
+ print_flags(bp, "iptos", cmd, f_iptos);
+ break;
+ case O_ICMPTYPE:
+ print_icmptypes(bp, insntod(cmd, u32));
+ break;
+ case O_ESTAB:
+ bprintf(bp, " established");
+ break;
+ case O_TCPFLAGS:
+ print_flags(bp, "tcpflags", cmd, f_tcpflags);
+ break;
+ case O_TCPOPTS:
+ print_flags(bp, "tcpoptions", cmd, f_tcpopts);
+ break;
+ case O_TCPACK:
+ bprintf(bp, " tcpack %d",
+ ntohl(insntod(cmd, u32)->d[0]));
+ break;
+ case O_TCPSEQ:
+ bprintf(bp, " tcpseq %d",
+ ntohl(insntod(cmd, u32)->d[0]));
+ break;
+ case O_UID:
+ pwd = getpwuid(insntod(cmd, u32)->d[0]);
+ if (pwd != NULL)
+ bprintf(bp, " uid %s", pwd->pw_name);
+ else
+ bprintf(bp, " uid %u",
+ insntod(cmd, u32)->d[0]);
+ break;
+ case O_GID:
+ grp = getgrgid(insntod(cmd, u32)->d[0]);
+ if (grp != NULL)
+ bprintf(bp, " gid %s", grp->gr_name);
+ else
+ bprintf(bp, " gid %u",
+ insntod(cmd, u32)->d[0]);
+ break;
+ case O_JAIL:
+ bprintf(bp, " jail %d", insntod(cmd, u32)->d[0]);
+ break;
+ case O_VERREVPATH:
+ bprintf(bp, " verrevpath");
+ break;
+ case O_VERSRCREACH:
+ bprintf(bp, " versrcreach");
+ break;
+ case O_ANTISPOOF:
+ bprintf(bp, " antispoof");
+ break;
+ case O_IPSEC:
+ bprintf(bp, " ipsec");
+ break;
+ case O_NOP:
+ bprintf(bp, " // %s", (char *)(cmd + 1));
+ break;
+ case O_KEEP_STATE:
+ bprintf(bp, " keep-state");
+ bprintf(bp, " :%s",
+ object_search_ctlv(fo->tstate, cmd->arg1,
+ IPFW_TLV_STATE_NAME));
+ break;
+ case O_LIMIT:
+ print_limit(bp, insntod(cmd, limit));
+ bprintf(bp, " :%s",
+ object_search_ctlv(fo->tstate, cmd->arg1,
+ IPFW_TLV_STATE_NAME));
+ break;
+ case O_IP6:
+ bprintf(bp, " ip6");
+ break;
+ case O_IP4:
+ bprintf(bp, " ip4");
+ break;
+ case O_ICMP6TYPE:
+ print_icmp6types(bp, insntod(cmd, u32));
+ break;
+ case O_EXT_HDR:
+ print_ext6hdr(bp, cmd);
+ break;
+ case O_TAGGED:
+ if (F_LEN(cmd) == 1)
+ bprint_uint_arg(bp, " tagged ", cmd->arg1);
+ else
+ print_newports(bp, insntod(cmd, u16),
+ 0, O_TAGGED);
+ break;
+ default:
+ bprintf(bp, " [opcode %d len %d]", cmd->opcode,
+ cmd->len);
+ }
+ if (cmd->len & F_OR) {
+ bprintf(bp, " or");
+ state->or_block = 1;
+ } else if (state->or_block != 0) {
+ bprintf(bp, " }");
+ state->or_block = 0;
+ }
+ mark_printed(state, cmd);
- case O_REASS:
- bprintf(bp, "reass");
- break;
+ return (1);
+}
- case O_CALLRETURN:
- if (cmd->len & F_NOT)
- bprintf(bp, "return");
- else
- bprint_uint_arg(bp, "call ", cmd->arg1);
- break;
+static ipfw_insn *
+print_opcode(struct buf_pr *bp, struct format_opts *fo,
+ struct show_state *state, uint8_t opcode)
+{
+ ipfw_insn *cmd;
+ int l;
- default:
- bprintf(bp, "** unrecognized action %d len %d ",
- cmd->opcode, cmd->len);
- }
+ for (l = state->rule->act_ofs, cmd = state->rule->cmd;
+ l > 0; l -= F_LEN(cmd), cmd += F_LEN(cmd)) {
+ /* We use zero opcode to print the rest of options */
+ if (opcode != 0 && cmd->opcode != opcode)
+ continue;
+ /*
+ * Skip O_NOP, when we printing the rest
+ * of options, it will be handled separately.
+ */
+ if (cmd->opcode == O_NOP && opcode != O_NOP)
+ continue;
+ if (!print_instruction(bp, fo, state, cmd))
+ continue;
+ return (cmd);
}
- if (logptr) {
- if (logptr->max_log > 0)
- bprintf(bp, " log logamount %d", logptr->max_log);
+ return (NULL);
+}
+
+static void
+print_fwd(struct buf_pr *bp, const ipfw_insn *cmd)
+{
+ char buf[INET6_ADDRSTRLEN + IF_NAMESIZE + 2];
+ ipfw_insn_sa6 *sa6;
+ ipfw_insn_sa *sa;
+ uint16_t port;
+
+ if (cmd->opcode == O_FORWARD_IP) {
+ sa = insntod(cmd, sa);
+ port = sa->sa.sin_port;
+ if (sa->sa.sin_addr.s_addr == INADDR_ANY)
+ bprintf(bp, "fwd tablearg");
else
- bprintf(bp, " log");
+ bprintf(bp, "fwd %s", inet_ntoa(sa->sa.sin_addr));
+ } else {
+ sa6 = insntod(cmd, sa6);
+ port = sa6->sa.sin6_port;
+ bprintf(bp, "fwd ");
+ if (getnameinfo((const struct sockaddr *)&sa6->sa,
+ sizeof(struct sockaddr_in6), buf, sizeof(buf), NULL, 0,
+ NI_NUMERICHOST) == 0)
+ bprintf(bp, "%s", buf);
}
+ if (port != 0)
+ bprintf(bp, ",%u", port);
+}
+
+static int
+print_action_instruction(struct buf_pr *bp, const struct format_opts *fo,
+ struct show_state *state, const ipfw_insn *cmd)
+{
+ const char *s;
+
+ if (is_printed_opcode(state, cmd))
+ return (0);
+ switch (cmd->opcode) {
+ case O_CHECK_STATE:
+ bprintf(bp, "check-state");
+ if (cmd->arg1 != 0)
+ s = object_search_ctlv(fo->tstate, cmd->arg1,
+ IPFW_TLV_STATE_NAME);
+ else
+ s = NULL;
+ bprintf(bp, " :%s", s ? s: "any");
+ break;
+ case O_ACCEPT:
+ bprintf(bp, "allow");
+ break;
+ case O_COUNT:
+ bprintf(bp, "count");
+ break;
+ case O_DENY:
+ bprintf(bp, "deny");
+ break;
+ case O_REJECT:
+ if (cmd->arg1 == ICMP_REJECT_RST)
+ bprintf(bp, "reset");
+ else if (cmd->arg1 == ICMP_REJECT_ABORT)
+ bprintf(bp, "abort");
+ else if (cmd->arg1 == ICMP_UNREACH_HOST)
+ bprintf(bp, "reject");
+ else
+ print_reject_code(bp, cmd->arg1);
+ break;
+ case O_UNREACH6:
+ if (cmd->arg1 == ICMP6_UNREACH_RST)
+ bprintf(bp, "reset6");
+ else if (cmd->arg1 == ICMP6_UNREACH_ABORT)
+ bprintf(bp, "abort6");
+ else
+ print_unreach6_code(bp, cmd->arg1);
+ break;
+ case O_SKIPTO:
+ bprint_uint_arg(bp, "skipto ", cmd->arg1);
+ break;
+ case O_PIPE:
+ bprint_uint_arg(bp, "pipe ", cmd->arg1);
+ break;
+ case O_QUEUE:
+ bprint_uint_arg(bp, "queue ", cmd->arg1);
+ break;
+ case O_DIVERT:
+ bprint_uint_arg(bp, "divert ", cmd->arg1);
+ break;
+ case O_TEE:
+ bprint_uint_arg(bp, "tee ", cmd->arg1);
+ break;
+ case O_NETGRAPH:
+ bprint_uint_arg(bp, "netgraph ", cmd->arg1);
+ break;
+ case O_NGTEE:
+ bprint_uint_arg(bp, "ngtee ", cmd->arg1);
+ break;
+ case O_FORWARD_IP:
+ case O_FORWARD_IP6:
+ 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");
+ break;
+ case O_ALTQ:
#ifndef NO_ALTQ
- if (altqptr) {
- print_altq_cmd(bp, altqptr);
- }
+ print_altq_cmd(bp, insntod(cmd, altq));
#endif
- if (tagptr) {
- if (tagptr->len & F_NOT)
- bprint_uint_arg(bp, " untag ", tagptr->arg1);
+ break;
+ case O_TAG:
+ bprint_uint_arg(bp, cmd->len & F_NOT ? " untag ":
+ " tag ", cmd->arg1);
+ break;
+ case O_NAT:
+ if (cmd->arg1 != IP_FW_NAT44_GLOBAL)
+ bprint_uint_arg(bp, "nat ", cmd->arg1);
else
- bprint_uint_arg(bp, " tag ", tagptr->arg1);
- }
-
- /*
- * then print the body.
- */
- for (l = rule->act_ofs, cmd = rule->cmd;
- l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) {
- if ((cmd->len & F_OR) || (cmd->len & F_NOT))
- continue;
- if (cmd->opcode == O_IP4) {
- flags |= HAVE_PROTO4;
+ bprintf(bp, "nat global");
+ break;
+ case O_SETFIB:
+ if (cmd->arg1 == IP_FW_TARG)
+ bprint_uint_arg(bp, "setfib ", cmd->arg1);
+ else
+ bprintf(bp, "setfib %u", cmd->arg1 & 0x7FFF);
+ break;
+ case O_EXTERNAL_ACTION:
+ /*
+ * The external action can consists of two following
+ * each other opcodes - O_EXTERNAL_ACTION and
+ * O_EXTERNAL_INSTANCE. The first contains the ID of
+ * name of external action. The second contains the ID
+ * of name of external action instance.
+ * 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,
+ IPFW_TLV_EACTION);
+ if (match_token(rule_eactions, s) != -1)
+ bprintf(bp, "%s", s);
+ else
+ bprintf(bp, "eaction %s", s);
+ break;
+ case O_EXTERNAL_INSTANCE:
+ if (state->eaction == NULL)
break;
- } else if (cmd->opcode == O_IP6) {
- flags |= HAVE_PROTO6;
+ /*
+ * XXX: we need to teach ipfw(9) to rewrite opcodes
+ * in the user buffer on rule addition. When we add
+ * the rule, we specify zero TLV type for
+ * O_EXTERNAL_INSTANCE object. To show correct
+ * rule after `ipfw add` we need to search instance
+ * name with zero type. But when we do `ipfw show`
+ * we calculate TLV type using IPFW_TLV_EACTION_NAME()
+ * macro.
+ */
+ s = object_search_ctlv(fo->tstate, cmd->arg1, 0);
+ if (s == NULL)
+ s = object_search_ctlv(fo->tstate,
+ cmd->arg1, IPFW_TLV_EACTION_NAME(
+ state->eaction->arg1));
+ bprintf(bp, " %s", s);
+ break;
+ case O_EXTERNAL_DATA:
+ if (state->eaction == NULL)
break;
+ /*
+ * Currently we support data formatting only for
+ * external data with datalen u16. For unknown data
+ * print its size in bytes.
+ */
+ if (cmd->len == F_INSN_SIZE(ipfw_insn))
+ bprintf(bp, " %u", cmd->arg1);
+ else
+ bprintf(bp, " %ubytes",
+ cmd->len * sizeof(uint32_t));
+ break;
+ case O_SETDSCP:
+ if (cmd->arg1 == IP_FW_TARG) {
+ bprintf(bp, "setdscp tablearg");
+ break;
}
+ s = match_value(f_ipdscp, cmd->arg1 & 0x3F);
+ if (s != NULL)
+ bprintf(bp, "setdscp %s", s);
+ else
+ bprintf(bp, "setdscp %s", cmd->arg1 & 0x3F);
+ break;
+ case O_REASS:
+ bprintf(bp, "reass");
+ break;
+ case O_CALLRETURN:
+ if (cmd->len & F_NOT)
+ bprintf(bp, "return");
+ else
+ bprint_uint_arg(bp, "call ", cmd->arg1);
+ break;
+ default:
+ bprintf(bp, "** unrecognized action %d len %d ",
+ cmd->opcode, cmd->len);
}
- if (rule->flags & IPFW_RULE_NOOPT) { /* empty rules before options */
- if (!co->do_compact) {
- show_prerequisites(bp, &flags, HAVE_PROTO, 0);
- bprintf(bp, " from any to any");
- }
- flags |= HAVE_IP | HAVE_OPTIONS | HAVE_PROTO |
- HAVE_SRCIP | HAVE_DSTIP;
- }
+ mark_printed(state, cmd);
- if (co->comment_only)
- comment = "...";
+ return (1);
+}
- for (l = rule->act_ofs, cmd = rule->cmd;
- l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) {
- /* useful alias */
- ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;
- if (co->comment_only) {
- if (cmd->opcode != O_NOP)
- continue;
- bprintf(bp, " // %s\n", (char *)(cmd + 1));
- return;
- }
+static ipfw_insn *
+print_action(struct buf_pr *bp, struct format_opts *fo,
+ struct show_state *state, uint8_t opcode)
+{
+ ipfw_insn *cmd;
+ int l;
- show_prerequisites(bp, &flags, 0, cmd->opcode);
+ for (l = state->rule->cmd_len - state->rule->act_ofs,
+ cmd = ACTION_PTR(state->rule); l > 0;
+ l -= F_LEN(cmd), cmd += F_LEN(cmd)) {
+ if (cmd->opcode != opcode)
+ continue;
+ if (!print_action_instruction(bp, fo, state, cmd))
+ continue;
+ return (cmd);
+ }
+ return (NULL);
+}
- switch(cmd->opcode) {
- case O_PROB:
- break; /* done already */
+static void
+print_proto(struct buf_pr *bp, struct format_opts *fo,
+ struct show_state *state)
+{
+ ipfw_insn *cmd;
+ int l, proto, ip4, ip6, tmp;
- case O_PROBE_STATE:
- break; /* no need to print anything here */
-
- case O_IP_SRC:
- case O_IP_SRC_LOOKUP:
- case O_IP_SRC_MASK:
- case O_IP_SRC_ME:
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-stable
mailing list