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.c2232
1 files changed, 1388 insertions, 844 deletions
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
index 25d6afd5febe..2c9846628977 100644
--- a/sbin/ipfw/ipfw2.c
+++ b/sbin/ipfw/ipfw2.c
@@ -35,6 +35,7 @@
#include <netdb.h>
#include <pwd.h>
#include <stdio.h>
+#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
@@ -56,16 +57,22 @@
struct cmdline_opts co; /* global options */
+struct format_opts {
+ int bcwidth;
+ int pcwidth;
+ int show_counters;
+ uint32_t set_mask; /* enabled sets mask */
+ uint32_t flags; /* request flags */
+ uint32_t first; /* first rule to request */
+ uint32_t last; /* last rule to request */
+ uint32_t dcnt; /* number of dynamic states */
+ ipfw_obj_ctlv *tstate; /* table state data */
+};
+
int resvd_set_number = RESVD_SET;
int ipfw_socket = -1;
-uint32_t ipfw_tables_max = 0; /* Number of tables supported by kernel */
-
-#ifndef s6_addr32
-#define s6_addr32 __u6_addr.__u6_addr32
-#endif
-
#define CHECK_LENGTH(v, len) do { \
if ((v) < (len)) \
errx(EX_DATAERR, "Rule too long"); \
@@ -86,7 +93,7 @@ uint32_t ipfw_tables_max = 0; /* Number of tables supported by kernel */
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; \
} \
\
@@ -104,24 +111,13 @@ uint32_t ipfw_tables_max = 0; /* Number of tables supported by kernel */
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; \
} \
} while (0)
-static void
-PRINT_UINT_ARG(const char *str, uint32_t arg)
-{
- if (str != NULL)
- printf("%s",str);
- if (arg == IP_FW_TABLEARG)
- printf("tablearg");
- else
- printf("%u", arg);
-}
-
static struct _s_x f_tcpflags[] = {
{ "syn", TH_SYN },
{ "fin", TH_FIN },
@@ -169,7 +165,7 @@ static struct _s_x f_iptos[] = {
{ NULL, 0 }
};
-static struct _s_x f_ipdscp[] = {
+struct _s_x f_ipdscp[] = {
{ "af11", IPTOS_DSCP_AF11 >> 2 }, /* 001010 */
{ "af12", IPTOS_DSCP_AF12 >> 2 }, /* 001100 */
{ "af13", IPTOS_DSCP_AF13 >> 2 }, /* 001110 */
@@ -357,6 +353,7 @@ static struct _s_x rule_options[] = {
{ "src-ipv6", TOK_SRCIP6},
{ "src-ip6", TOK_SRCIP6},
{ "lookup", TOK_LOOKUP},
+ { "flow", TOK_FLOW},
{ "//", TOK_COMMENT },
{ "not", TOK_NOT }, /* pseudo option */
@@ -370,6 +367,103 @@ static struct _s_x rule_options[] = {
{ NULL, 0 } /* terminator */
};
+void bprint_uint_arg(struct buf_pr *bp, const char *str, uint32_t arg);
+static int ipfw_get_config(struct cmdline_opts *co, struct format_opts *fo,
+ ipfw_cfg_lheader **pcfg, size_t *psize);
+static int ipfw_show_config(struct cmdline_opts *co, struct format_opts *fo,
+ ipfw_cfg_lheader *cfg, size_t sz, int ac, char **av);
+static void ipfw_list_tifaces(void);
+
+/*
+ * Simple string buffer API.
+ * Used to simplify buffer passing between function and for
+ * transparent overrun handling.
+ */
+
+/*
+ * Allocates new buffer of given size @sz.
+ *
+ * Returns 0 on success.
+ */
+int
+bp_alloc(struct buf_pr *b, size_t size)
+{
+ memset(b, 0, sizeof(struct buf_pr));
+
+ if ((b->buf = calloc(1, size)) == NULL)
+ return (ENOMEM);
+
+ b->ptr = b->buf;
+ b->size = size;
+ b->avail = b->size;
+
+ return (0);
+}
+
+void
+bp_free(struct buf_pr *b)
+{
+
+ free(b->buf);
+}
+
+/*
+ * Flushes buffer so new writer start from beginning.
+ */
+void
+bp_flush(struct buf_pr *b)
+{
+
+ b->ptr = b->buf;
+ b->avail = b->size;
+}
+
+/*
+ * Print message specified by @format and args.
+ * Automatically manage buffer space and transparently handle
+ * buffer overruns.
+ *
+ * Returns number of bytes that should have been printed.
+ */
+int
+bprintf(struct buf_pr *b, char *format, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, format);
+
+ i = vsnprintf(b->ptr, b->avail, format, args);
+ va_end(args);
+
+ if (i > b->avail || i < 0) {
+ /* Overflow or print error */
+ b->avail = 0;
+ } else {
+ b->ptr += i;
+ b->avail -= i;
+ }
+
+ b->needed += i;
+
+ return (i);
+}
+
+/*
+ * Special values printer for tablearg-aware opcodes.
+ */
+void
+bprint_uint_arg(struct buf_pr *bp, const char *str, uint32_t arg)
+{
+
+ if (str != NULL)
+ bprintf(bp, "%s", str);
+ if (arg == IP_FW_TARG)
+ bprintf(bp, "tablearg");
+ else
+ bprintf(bp, "%u", arg);
+}
+
/*
* Helper routine to print a possibly unaligned uint64_t on
* various platform. If width > 0, print the value with
@@ -377,7 +471,7 @@ static struct _s_x rule_options[] = {
* otherwise, return the required width.
*/
int
-pr_u64(uint64_t *pd, int width)
+pr_u64(struct buf_pr *b, uint64_t *pd, int width)
{
#ifdef TCC
#define U64_FMT "I64"
@@ -390,11 +484,12 @@ pr_u64(uint64_t *pd, int width)
bcopy (pd, &u, sizeof(u));
d = u;
return (width > 0) ?
- printf("%*" U64_FMT " ", width, d) :
+ bprintf(b, "%*" U64_FMT " ", width, d) :
snprintf(NULL, 0, "%" U64_FMT, d) ;
#undef U64_FMT
}
+
void *
safe_calloc(size_t number, size_t size)
{
@@ -416,6 +511,26 @@ safe_realloc(void *ptr, size_t size)
}
/*
+ * Compare things like interface or table names.
+ */
+int
+stringnum_cmp(const char *a, const char *b)
+{
+ int la, lb;
+
+ la = strlen(a);
+ lb = strlen(b);
+
+ if (la > lb)
+ return (1);
+ else if (la < lb)
+ return (-01);
+
+ return (strcmp(a, b));
+}
+
+
+/*
* conditionally runs the command.
* Selected options or negative -> getsockopt
*/
@@ -448,20 +563,18 @@ do_cmd(int optname, void *optval, uintptr_t optlen)
}
/*
- * do_setcmd3 - pass ipfw control cmd to kernel
+ * do_set3 - pass ipfw control cmd to kernel
* @optname: option name
* @optval: pointer to option data
* @optlen: option length
*
- * Function encapsulates option value in IP_FW3 socket option
- * and calls setsockopt().
- * Function returns 0 on success or -1 otherwise.
+ * Assumes op3 header is already embedded.
+ * Calls setsockopt() with IP_FW3 as kernel-visible opcode.
+ * Returns 0 on success or errno otherwise.
*/
-static int
-do_setcmd3(int optname, void *optval, socklen_t optlen)
+int
+do_set3(int optname, ip_fw3_opheader *op3, uintptr_t optlen)
{
- socklen_t len;
- ip_fw3_opheader *op3;
if (co.test_only)
return (0);
@@ -471,14 +584,40 @@ do_setcmd3(int optname, void *optval, socklen_t optlen)
if (ipfw_socket < 0)
err(EX_UNAVAILABLE, "socket");
- len = sizeof(ip_fw3_opheader) + optlen;
- op3 = alloca(len);
- /* Zero reserved fields */
- memset(op3, 0, sizeof(ip_fw3_opheader));
- memcpy(op3 + 1, optval, optlen);
op3->opcode = optname;
- return setsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, len);
+ return (setsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, optlen));
+}
+
+/*
+ * do_get3 - pass ipfw control cmd to kernel
+ * @optname: option name
+ * @optval: pointer to option data
+ * @optlen: pointer to option length
+ *
+ * Assumes op3 header is already embedded.
+ * Calls getsockopt() with IP_FW3 as kernel-visible opcode.
+ * Returns 0 on success or errno otherwise.
+ */
+int
+do_get3(int optname, ip_fw3_opheader *op3, size_t *optlen)
+{
+ int error;
+
+ if (co.test_only)
+ return (0);
+
+ if (ipfw_socket == -1)
+ ipfw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+ if (ipfw_socket < 0)
+ err(EX_UNAVAILABLE, "socket");
+
+ op3->opcode = optname;
+
+ error = getsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3,
+ (socklen_t *)optlen);
+
+ return (error);
}
/**
@@ -494,7 +633,38 @@ match_token(struct _s_x *table, char *string)
for (pt = table ; i && pt->s != NULL ; pt++)
if (strlen(pt->s) == i && !bcmp(string, pt->s, i))
return pt->x;
- return -1;
+ return (-1);
+}
+
+/**
+ * match_token takes a table and a string, returns the value associated
+ * with the string for the best match.
+ *
+ * Returns:
+ * value from @table for matched records
+ * -1 for non-matched records
+ * -2 if more than one records match @string.
+ */
+int
+match_token_relaxed(struct _s_x *table, char *string)
+{
+ struct _s_x *pt, *m;
+ int i, c;
+
+ i = strlen(string);
+ c = 0;
+
+ for (pt = table ; i != 0 && pt->s != NULL ; pt++) {
+ if (strncmp(pt->s, string, i) != 0)
+ continue;
+ m = pt;
+ c++;
+ }
+
+ if (c == 1)
+ return (m->x);
+
+ return (c > 0 ? -2: -1);
}
/**
@@ -510,6 +680,78 @@ match_value(struct _s_x *p, int value)
return NULL;
}
+size_t
+concat_tokens(char *buf, size_t bufsize, struct _s_x *table, char *delimiter)
+{
+ struct _s_x *pt;
+ int l;
+ size_t sz;
+
+ for (sz = 0, pt = table ; pt->s != NULL; pt++) {
+ l = snprintf(buf + sz, bufsize - sz, "%s%s",
+ (sz == 0) ? "" : delimiter, pt->s);
+ sz += l;
+ bufsize += l;
+ if (sz > bufsize)
+ return (bufsize);
+ }
+
+ return (sz);
+}
+
+/*
+ * helper function to process a set of flags and set bits in the
+ * appropriate masks.
+ */
+int
+fill_flags(struct _s_x *flags, char *p, char **e, uint32_t *set,
+ uint32_t *clear)
+{
+ char *q; /* points to the separator */
+ int val;
+ uint32_t *which; /* mask we are working on */
+
+ while (p && *p) {
+ if (*p == '!') {
+ p++;
+ which = clear;
+ } else
+ which = set;
+ q = strchr(p, ',');
+ if (q)
+ *q++ = '\0';
+ val = match_token(flags, p);
+ if (val <= 0) {
+ if (e != NULL)
+ *e = p;
+ return (-1);
+ }
+ *which |= (uint32_t)val;
+ p = q;
+ }
+ return (0);
+}
+
+void
+print_flags_buffer(char *buf, size_t sz, struct _s_x *list, uint32_t set)
+{
+ char const *comma = "";
+ int i, l;
+
+ for (i = 0; list[i].x != 0; i++) {
+ if ((set & list[i].x) == 0)
+ continue;
+
+ set &= ~list[i].x;
+ l = snprintf(buf, sz, "%s%s", comma, list[i].s);
+ if (l >= sz)
+ return;
+ comma = ",";
+ buf += l;
+ sz -=l;
+ }
+}
+
/*
* _substrcmp takes two strings and returns 1 if they do not match,
* and 0 if they match exactly or the first string is a sub-string
@@ -564,16 +806,16 @@ _substrcmp2(const char *str1, const char* str2, const char* str3)
* prints one port, symbolic or numeric
*/
static void
-print_port(int proto, uint16_t port)
+print_port(struct buf_pr *bp, int proto, uint16_t port)
{
if (proto == IPPROTO_ETHERTYPE) {
char const *s;
if (co.do_resolv && (s = match_value(ether_types, port)) )
- printf("%s", s);
+ bprintf(bp, "%s", s);
else
- printf("0x%04x", port);
+ bprintf(bp, "0x%04x", port);
} else {
struct servent *se = NULL;
if (co.do_resolv) {
@@ -582,9 +824,9 @@ print_port(int proto, uint16_t port)
se = getservbyport(htons(port), pe ? pe->p_name : NULL);
}
if (se)
- printf("%s", se->s_name);
+ bprintf(bp, "%s", se->s_name);
else
- printf("%d", port);
+ bprintf(bp, "%d", port);
}
}
@@ -606,7 +848,7 @@ static struct _s_x _port_name[] = {
* XXX todo: add support for mask.
*/
static void
-print_newports(ipfw_insn_u16 *cmd, int proto, int opcode)
+print_newports(struct buf_pr *bp, ipfw_insn_u16 *cmd, int proto, int opcode)
{
uint16_t *p = cmd->ports;
int i;
@@ -616,15 +858,15 @@ print_newports(ipfw_insn_u16 *cmd, int proto, int opcode)
sep = match_value(_port_name, opcode);
if (sep == NULL)
sep = "???";
- printf (" %s", sep);
+ bprintf(bp, " %s", sep);
}
sep = " ";
for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) {
- printf("%s", sep);
- print_port(proto, p[0]);
+ bprintf(bp, "%s", sep);
+ print_port(bp, proto, p[0]);
if (p[0] != p[1]) {
- printf("-");
- print_port(proto, p[1]);
+ bprintf(bp, "-");
+ print_port(bp, proto, p[1]);
}
sep = ",";
}
@@ -824,14 +1066,14 @@ fill_reject_code(u_short *codep, char *str)
}
static void
-print_reject_code(uint16_t code)
+print_reject_code(struct buf_pr *bp, uint16_t code)
{
- char const *s = match_value(icmpcodes, code);
+ char const *s;
- if (s != NULL)
- printf("unreach %s", s);
+ if ((s = match_value(icmpcodes, code)) != NULL)
+ bprintf(bp, "unreach %s", s);
else
- printf("unreach %u", code);
+ bprintf(bp, "unreach %u", code);
}
/*
@@ -864,7 +1106,8 @@ contigmask(uint8_t *p, int len)
* There is a specialized check for f_tcpflags.
*/
static void
-print_flags(char const *name, ipfw_insn *cmd, struct _s_x *list)
+print_flags(struct buf_pr *bp, char const *name, ipfw_insn *cmd,
+ struct _s_x *list)
{
char const *comma = "";
int i;
@@ -872,34 +1115,38 @@ print_flags(char const *name, ipfw_insn *cmd, struct _s_x *list)
uint8_t clear = (cmd->arg1 >> 8) & 0xff;
if (list == f_tcpflags && set == TH_SYN && clear == TH_ACK) {
- printf(" setup");
+ bprintf(bp, " setup");
return;
}
- printf(" %s ", name);
+ bprintf(bp, " %s ", name);
for (i=0; list[i].x != 0; i++) {
if (set & list[i].x) {
set &= ~list[i].x;
- printf("%s%s", comma, list[i].s);
+ bprintf(bp, "%s%s", comma, list[i].s);
comma = ",";
}
if (clear & list[i].x) {
clear &= ~list[i].x;
- printf("%s!%s", comma, list[i].s);
+ bprintf(bp, "%s!%s", comma, list[i].s);
comma = ",";
}
}
}
+
/*
* Print the ip address contained in a command.
*/
static void
-print_ip(ipfw_insn_ip *cmd, char const *s)
+print_ip(struct buf_pr *bp, struct format_opts *fo, ipfw_insn_ip *cmd,
+ char const *s)
{
struct hostent *he = NULL;
+ struct in_addr *ia;
uint32_t len = F_LEN((ipfw_insn *)cmd);
uint32_t *a = ((ipfw_insn_u32 *)cmd)->d;
+ char *t;
if (cmd->o.opcode == O_IP_DST_LOOKUP && len > F_INSN_SIZE(ipfw_insn_u32)) {
uint32_t d = a[1];
@@ -907,22 +1154,24 @@ print_ip(ipfw_insn_ip *cmd, char const *s)
if (d < sizeof(lookup_key)/sizeof(lookup_key[0]))
arg = match_value(rule_options, lookup_key[d]);
- printf("%s lookup %s %d", cmd->o.len & F_NOT ? " not": "",
- arg, cmd->o.arg1);
+ t = table_search_ctlv(fo->tstate, ((ipfw_insn *)cmd)->arg1);
+ bprintf(bp, "%s lookup %s %s", cmd->o.len & F_NOT ? " not": "",
+ arg, t);
return;
}
- printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s);
+ bprintf(bp, "%s%s ", cmd->o.len & F_NOT ? " not": "", s);
if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) {
- printf("me");
+ bprintf(bp, "me");
return;
}
if (cmd->o.opcode == O_IP_SRC_LOOKUP ||
cmd->o.opcode == O_IP_DST_LOOKUP) {
- printf("table(%u", ((ipfw_insn *)cmd)->arg1);
+ t = table_search_ctlv(fo->tstate, ((ipfw_insn *)cmd)->arg1);
+ bprintf(bp, "table(%s", t);
if (len == F_INSN_SIZE(ipfw_insn_u32))
- printf(",%u", *a);
- printf(")");
+ bprintf(bp, ",%u", *a);
+ bprintf(bp, ")");
return;
}
if (cmd->o.opcode == O_IP_SRC_SET || cmd->o.opcode == O_IP_DST_SET) {
@@ -933,7 +1182,7 @@ print_ip(ipfw_insn_ip *cmd, char const *s)
x = cmd->o.arg1 - 1;
x = htonl( ~x );
cmd->addr.s_addr = htonl(cmd->addr.s_addr);
- printf("%s/%d", inet_ntoa(cmd->addr),
+ bprintf(bp, "%s/%d", inet_ntoa(cmd->addr),
contigmask((uint8_t *)&x, 32));
x = cmd->addr.s_addr = htonl(cmd->addr.s_addr);
x &= 0xff; /* base */
@@ -948,14 +1197,14 @@ print_ip(ipfw_insn_ip *cmd, char const *s)
for (j=i+1; j < cmd->o.arg1; j++)
if (!(map[ j/32] & (1<<(j & 31))))
break;
- printf("%c%d", comma, i+x);
+ bprintf(bp, "%c%d", comma, i+x);
if (j>i+2) { /* range has at least 3 elements */
- printf("-%d", j-1+x);
+ bprintf(bp, "-%d", j-1+x);
i = j-1;
}
comma = ',';
}
- printf("}");
+ bprintf(bp, "}");
return;
}
/*
@@ -970,18 +1219,20 @@ print_ip(ipfw_insn_ip *cmd, char const *s)
if (mb == 32 && co.do_resolv)
he = gethostbyaddr((char *)&(a[0]), sizeof(u_long), AF_INET);
if (he != NULL) /* resolved to name */
- printf("%s", he->h_name);
+ bprintf(bp, "%s", he->h_name);
else if (mb == 0) /* any */
- printf("any");
+ bprintf(bp, "any");
else { /* numeric IP followed by some kind of mask */
- printf("%s", inet_ntoa( *((struct in_addr *)&a[0]) ) );
- if (mb < 0)
- printf(":%s", inet_ntoa( *((struct in_addr *)&a[1]) ) );
- else if (mb < 32)
- printf("/%d", mb);
+ ia = (struct in_addr *)&a[0];
+ bprintf(bp, "%s", inet_ntoa(*ia));
+ if (mb < 0) {
+ ia = (struct in_addr *)&a[1];
+ bprintf(bp, ":%s", inet_ntoa(*ia));
+ } else if (mb < 32)
+ bprintf(bp, "/%d", mb);
}
if (len > 1)
- printf(",");
+ bprintf(bp, ",");
}
}
@@ -989,21 +1240,21 @@ print_ip(ipfw_insn_ip *cmd, char const *s)
* prints a MAC address/mask pair
*/
static void
-print_mac(uint8_t *addr, uint8_t *mask)
+print_mac(struct buf_pr *bp, uint8_t *addr, uint8_t *mask)
{
int l = contigmask(mask, 48);
if (l == 0)
- printf(" any");
+ bprintf(bp, " any");
else {
- printf(" %02x:%02x:%02x:%02x:%02x:%02x",
+ bprintf(bp, " %02x:%02x:%02x:%02x:%02x:%02x",
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
if (l == -1)
- printf("&%02x:%02x:%02x:%02x:%02x:%02x",
+ bprintf(bp, "&%02x:%02x:%02x:%02x:%02x:%02x",
mask[0], mask[1], mask[2],
mask[3], mask[4], mask[5]);
else if (l < 48)
- printf("/%d", l);
+ bprintf(bp, "/%d", l);
}
}
@@ -1032,38 +1283,38 @@ fill_icmptypes(ipfw_insn_u32 *cmd, char *av)
}
static void
-print_icmptypes(ipfw_insn_u32 *cmd)
+print_icmptypes(struct buf_pr *bp, ipfw_insn_u32 *cmd)
{
int i;
char sep= ' ';
- printf(" icmptypes");
+ bprintf(bp, " icmptypes");
for (i = 0; i < 32; i++) {
if ( (cmd->d[0] & (1 << (i))) == 0)
continue;
- printf("%c%d", sep, i);
+ bprintf(bp, "%c%d", sep, i);
sep = ',';
}
}
static void
-print_dscp(ipfw_insn_u32 *cmd)
+print_dscp(struct buf_pr *bp, ipfw_insn_u32 *cmd)
{
int i, c;
uint32_t *v;
char sep= ' ';
const char *code;
- printf(" dscp");
+ bprintf(bp, " dscp");
i = 0;
c = 0;
v = cmd->d;
while (i < 64) {
if (*v & (1 << i)) {
if ((code = match_value(f_ipdscp, i)) != NULL)
- printf("%c%s", sep, code);
+ bprintf(bp, "%c%s", sep, code);
else
- printf("%c%d", sep, i);
+ bprintf(bp, "%c%d", sep, i);
sep = ',';
}
@@ -1094,7 +1345,7 @@ print_dscp(ipfw_insn_u32 *cmd)
#define HAVE_OPTIONS 0x8000
static void
-show_prerequisites(int *flags, int want, int cmd)
+show_prerequisites(struct buf_pr *bp, int *flags, int want, int cmd)
{
(void)cmd; /* UNUSED */
if (co.comment_only)
@@ -1105,22 +1356,23 @@ show_prerequisites(int *flags, int want, int cmd)
if ( !(*flags & HAVE_OPTIONS)) {
if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO)) {
if ( (*flags & HAVE_PROTO4))
- printf(" ip4");
+ bprintf(bp, " ip4");
else if ( (*flags & HAVE_PROTO6))
- printf(" ip6");
+ bprintf(bp, " ip6");
else
- printf(" ip");
+ bprintf(bp, " ip");
}
if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP))
- printf(" from any");
+ bprintf(bp, " from any");
if ( !(*flags & HAVE_DSTIP) && (want & HAVE_DSTIP))
- printf(" to any");
+ bprintf(bp, " to any");
}
*flags |= want;
}
static void
-show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
+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)
{
static int twidth = 0;
int l;
@@ -1131,26 +1383,26 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
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 set_disable;
+ uint32_t uval;
- bcopy(&rule->next_rule, &set_disable, sizeof(set_disable));
-
- if (set_disable & (1 << rule->set)) { /* disabled */
- if (!co.show_sets)
+ if ((fo->set_mask & (1 << rule->set)) == 0) {
+ /* disabled mask */
+ if (!co->show_sets)
return;
else
- printf("# DISABLED ");
+ bprintf(bp, "# DISABLED ");
}
- printf("%05u ", rule->rulenum);
+ bprintf(bp, "%05u ", rule->rulenum);
- if (pcwidth > 0 || bcwidth > 0) {
- pr_u64(&rule->pcnt, pcwidth);
- pr_u64(&rule->bcnt, bcwidth);
+ /* 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);
}
- if (co.do_time == 2)
- printf("%10u ", rule->timestamp);
- else if (co.do_time == 1) {
+ 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;
@@ -1159,19 +1411,19 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
*strchr(timestr, '\n') = '\0';
twidth = strlen(timestr);
}
- if (rule->timestamp) {
- t = _long_to_time(rule->timestamp);
+ if (cntr->timestamp > 0) {
+ t = _long_to_time(cntr->timestamp);
strcpy(timestr, ctime(&t));
*strchr(timestr, '\n') = '\0';
- printf("%s ", timestr);
+ bprintf(bp, "%s ", timestr);
} else {
- printf("%*s", twidth, " ");
+ bprintf(bp, "%*s", twidth, " ");
}
}
- if (co.show_sets)
- printf("set %d ", rule->set);
+ if (co->show_sets)
+ bprintf(bp, "set %d ", rule->set);
/*
* print the optional "match probability"
@@ -1183,7 +1435,7 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
double d = 1.0 * p->d[0];
d = (d / 0x7fffffff);
- printf("prob %f ", d);
+ bprintf(bp, "prob %f ", d);
}
}
@@ -1194,66 +1446,66 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
l > 0 ; l -= F_LEN(cmd), cmd += F_LEN(cmd)) {
switch(cmd->opcode) {
case O_CHECK_STATE:
- printf("check-state");
+ bprintf(bp, "check-state");
/* avoid printing anything else */
flags = HAVE_PROTO | HAVE_SRCIP |
HAVE_DSTIP | HAVE_IP;
break;
case O_ACCEPT:
- printf("allow");
+ bprintf(bp, "allow");
break;
case O_COUNT:
- printf("count");
+ bprintf(bp, "count");
break;
case O_DENY:
- printf("deny");
+ bprintf(bp, "deny");
break;
case O_REJECT:
if (cmd->arg1 == ICMP_REJECT_RST)
- printf("reset");
+ bprintf(bp, "reset");
else if (cmd->arg1 == ICMP_UNREACH_HOST)
- printf("reject");
+ bprintf(bp, "reject");
else
- print_reject_code(cmd->arg1);
+ print_reject_code(bp, cmd->arg1);
break;
case O_UNREACH6:
if (cmd->arg1 == ICMP6_UNREACH_RST)
- printf("reset6");
+ bprintf(bp, "reset6");
else
print_unreach6_code(cmd->arg1);
break;
case O_SKIPTO:
- PRINT_UINT_ARG("skipto ", cmd->arg1);
+ bprint_uint_arg(bp, "skipto ", cmd->arg1);
break;
case O_PIPE:
- PRINT_UINT_ARG("pipe ", cmd->arg1);
+ bprint_uint_arg(bp, "pipe ", cmd->arg1);
break;
case O_QUEUE:
- PRINT_UINT_ARG("queue ", cmd->arg1);
+ bprint_uint_arg(bp, "queue ", cmd->arg1);
break;
case O_DIVERT:
- PRINT_UINT_ARG("divert ", cmd->arg1);
+ bprint_uint_arg(bp, "divert ", cmd->arg1);
break;
case O_TEE:
- PRINT_UINT_ARG("tee ", cmd->arg1);
+ bprint_uint_arg(bp, "tee ", cmd->arg1);
break;
case O_NETGRAPH:
- PRINT_UINT_ARG("netgraph ", cmd->arg1);
+ bprint_uint_arg(bp, "netgraph ", cmd->arg1);
break;
case O_NGTEE:
- PRINT_UINT_ARG("ngtee ", cmd->arg1);
+ bprint_uint_arg(bp, "ngtee ", cmd->arg1);
break;
case O_FORWARD_IP:
@@ -1261,12 +1513,12 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
ipfw_insn_sa *s = (ipfw_insn_sa *)cmd;
if (s->sa.sin_addr.s_addr == INADDR_ANY) {
- printf("fwd tablearg");
+ bprintf(bp, "fwd tablearg");
} else {
- printf("fwd %s", inet_ntoa(s->sa.sin_addr));
+ bprintf(bp, "fwd %s",inet_ntoa(s->sa.sin_addr));
}
if (s->sa.sin_port)
- printf(",%d", s->sa.sin_port);
+ bprintf(bp, ",%d", s->sa.sin_port);
}
break;
@@ -1275,10 +1527,10 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
char buf[4 + INET6_ADDRSTRLEN + 1];
ipfw_insn_sa6 *s = (ipfw_insn_sa6 *)cmd;
- printf("fwd %s", inet_ntop(AF_INET6, &s->sa.sin6_addr,
- buf, sizeof(buf)));
+ bprintf(bp, "fwd %s", inet_ntop(AF_INET6,
+ &s->sa.sin6_addr, buf, sizeof(buf)));
if (s->sa.sin6_port)
- printf(",%d", s->sa.sin6_port);
+ bprintf(bp, ",%d", s->sa.sin6_port);
}
break;
@@ -1296,64 +1548,69 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
case O_NAT:
if (cmd->arg1 != 0)
- PRINT_UINT_ARG("nat ", cmd->arg1);
+ bprint_uint_arg(bp, "nat ", cmd->arg1);
else
- printf("nat global");
+ bprintf(bp, "nat global");
break;
case O_SETFIB:
- PRINT_UINT_ARG("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)
- printf("setdscp %s", code);
+ 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
- PRINT_UINT_ARG("setdscp ", cmd->arg1);
+ bprint_uint_arg(bp, "setdscp ", uval);
}
break;
case O_REASS:
- printf("reass");
+ bprintf(bp, "reass");
break;
case O_CALLRETURN:
if (cmd->len & F_NOT)
- printf("return");
+ bprintf(bp, "return");
else
- PRINT_UINT_ARG("call ", cmd->arg1);
+ bprint_uint_arg(bp, "call ", cmd->arg1);
break;
default:
- printf("** unrecognized action %d len %d ",
+ bprintf(bp, "** unrecognized action %d len %d ",
cmd->opcode, cmd->len);
}
}
if (logptr) {
if (logptr->max_log > 0)
- printf(" log logamount %d", logptr->max_log);
+ bprintf(bp, " log logamount %d", logptr->max_log);
else
- printf(" log");
+ bprintf(bp, " log");
}
#ifndef NO_ALTQ
if (altqptr) {
- print_altq_cmd(altqptr);
+ print_altq_cmd(bp, altqptr);
}
#endif
if (tagptr) {
if (tagptr->len & F_NOT)
- PRINT_UINT_ARG(" untag ", tagptr->arg1);
+ bprint_uint_arg(bp, " untag ", tagptr->arg1);
else
- PRINT_UINT_ARG(" tag ", tagptr->arg1);
+ bprint_uint_arg(bp, " tag ", tagptr->arg1);
}
/*
* then print the body.
*/
- for (l = rule->act_ofs, cmd = rule->cmd ;
+ 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;
@@ -1365,31 +1622,31 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
break;
}
}
- if (rule->_pad & 1) { /* empty rules before options */
- if (!co.do_compact) {
- show_prerequisites(&flags, HAVE_PROTO, 0);
- printf(" from any to any");
+ 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;
}
- if (co.comment_only)
+ if (co->comment_only)
comment = "...";
- for (l = rule->act_ofs, cmd = rule->cmd ;
+ 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 (co->comment_only) {
if (cmd->opcode != O_NOP)
continue;
- printf(" // %s\n", (char *)(cmd + 1));
+ bprintf(bp, " // %s\n", (char *)(cmd + 1));
return;
}
- show_prerequisites(&flags, 0, cmd->opcode);
+ show_prerequisites(bp, &flags, 0, cmd->opcode);
switch(cmd->opcode) {
case O_PROB:
@@ -1403,12 +1660,12 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
case O_IP_SRC_MASK:
case O_IP_SRC_ME:
case O_IP_SRC_SET:
- show_prerequisites(&flags, HAVE_PROTO, 0);
+ show_prerequisites(bp, &flags, HAVE_PROTO, 0);
if (!(flags & HAVE_SRCIP))
- printf(" from");
+ bprintf(bp, " from");
if ((cmd->len & F_OR) && !or_block)
- printf(" {");
- print_ip((ipfw_insn_ip *)cmd,
+ bprintf(bp, " {");
+ print_ip(bp, fo, (ipfw_insn_ip *)cmd,
(flags & HAVE_OPTIONS) ? " src-ip" : "");
flags |= HAVE_SRCIP;
break;
@@ -1418,12 +1675,12 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
case O_IP_DST_MASK:
case O_IP_DST_ME:
case O_IP_DST_SET:
- show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0);
+ show_prerequisites(bp, &flags, HAVE_PROTO|HAVE_SRCIP, 0);
if (!(flags & HAVE_DSTIP))
- printf(" to");
+ bprintf(bp, " to");
if ((cmd->len & F_OR) && !or_block)
- printf(" {");
- print_ip((ipfw_insn_ip *)cmd,
+ bprintf(bp, " {");
+ print_ip(bp, fo, (ipfw_insn_ip *)cmd,
(flags & HAVE_OPTIONS) ? " dst-ip" : "");
flags |= HAVE_DSTIP;
break;
@@ -1431,12 +1688,12 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
case O_IP6_SRC:
case O_IP6_SRC_MASK:
case O_IP6_SRC_ME:
- show_prerequisites(&flags, HAVE_PROTO, 0);
+ show_prerequisites(bp, &flags, HAVE_PROTO, 0);
if (!(flags & HAVE_SRCIP))
- printf(" from");
+ bprintf(bp, " from");
if ((cmd->len & F_OR) && !or_block)
- printf(" {");
- print_ip6((ipfw_insn_ip6 *)cmd,
+ bprintf(bp, " {");
+ print_ip6(bp, (ipfw_insn_ip6 *)cmd,
(flags & HAVE_OPTIONS) ? " src-ip6" : "");
flags |= HAVE_SRCIP | HAVE_PROTO;
break;
@@ -1444,35 +1701,35 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
case O_IP6_DST:
case O_IP6_DST_MASK:
case O_IP6_DST_ME:
- show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0);
+ show_prerequisites(bp, &flags, HAVE_PROTO|HAVE_SRCIP, 0);
if (!(flags & HAVE_DSTIP))
- printf(" to");
+ bprintf(bp, " to");
if ((cmd->len & F_OR) && !or_block)
- printf(" {");
- print_ip6((ipfw_insn_ip6 *)cmd,
+ bprintf(bp, " {");
+ print_ip6(bp, (ipfw_insn_ip6 *)cmd,
(flags & HAVE_OPTIONS) ? " dst-ip6" : "");
flags |= HAVE_DSTIP;
break;
case O_FLOW6ID:
- print_flow6id( (ipfw_insn_u32 *) cmd );
- flags |= HAVE_OPTIONS;
- break;
+ print_flow6id(bp, (ipfw_insn_u32 *) cmd );
+ flags |= HAVE_OPTIONS;
+ break;
case O_IP_DSTPORT:
- show_prerequisites(&flags,
+ show_prerequisites(bp, &flags,
HAVE_PROTO | HAVE_SRCIP |
HAVE_DSTIP | HAVE_IP, 0);
case O_IP_SRCPORT:
if (flags & HAVE_DSTIP)
flags |= HAVE_IP;
- show_prerequisites(&flags,
+ show_prerequisites(bp, &flags,
HAVE_PROTO | HAVE_SRCIP, 0);
if ((cmd->len & F_OR) && !or_block)
- printf(" {");
+ bprintf(bp, " {");
if (cmd->len & F_NOT)
- printf(" not");
- print_newports((ipfw_insn_u16 *)cmd, proto,
+ bprintf(bp, " not");
+ print_newports(bp, (ipfw_insn_u16 *)cmd, proto,
(flags & HAVE_OPTIONS) ? cmd->opcode : 0);
break;
@@ -1480,22 +1737,22 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
struct protoent *pe = NULL;
if ((cmd->len & F_OR) && !or_block)
- printf(" {");
+ bprintf(bp, " {");
if (cmd->len & F_NOT)
- printf(" not");
+ bprintf(bp, " not");
proto = cmd->arg1;
pe = getprotobynumber(cmd->arg1);
if ((flags & (HAVE_PROTO4 | HAVE_PROTO6)) &&
!(flags & HAVE_PROTO))
- show_prerequisites(&flags,
+ show_prerequisites(bp, &flags,
HAVE_PROTO | HAVE_IP | HAVE_SRCIP |
HAVE_DSTIP | HAVE_OPTIONS, 0);
if (flags & HAVE_OPTIONS)
- printf(" proto");
+ bprintf(bp, " proto");
if (pe)
- printf(" %s", pe->p_name);
+ bprintf(bp, " %s", pe->p_name);
else
- printf(" %u", cmd->arg1);
+ bprintf(bp, " %u", cmd->arg1);
}
flags |= HAVE_PROTO;
break;
@@ -1507,68 +1764,68 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
((cmd->opcode == O_IP4) &&
(flags & HAVE_PROTO4)))
break;
- show_prerequisites(&flags, HAVE_PROTO | HAVE_SRCIP |
+ show_prerequisites(bp, &flags, HAVE_PROTO | HAVE_SRCIP |
HAVE_DSTIP | HAVE_IP | HAVE_OPTIONS, 0);
if ((cmd->len & F_OR) && !or_block)
- printf(" {");
+ bprintf(bp, " {");
if (cmd->len & F_NOT && cmd->opcode != O_IN)
- printf(" not");
+ bprintf(bp, " not");
switch(cmd->opcode) {
case O_MACADDR2: {
ipfw_insn_mac *m = (ipfw_insn_mac *)cmd;
- printf(" MAC");
- print_mac(m->addr, m->mask);
- print_mac(m->addr + 6, m->mask + 6);
+ bprintf(bp, " MAC");
+ print_mac(bp, m->addr, m->mask);
+ print_mac(bp, m->addr + 6, m->mask + 6);
}
break;
case O_MAC_TYPE:
- print_newports((ipfw_insn_u16 *)cmd,
+ print_newports(bp, (ipfw_insn_u16 *)cmd,
IPPROTO_ETHERTYPE, cmd->opcode);
break;
case O_FRAG:
- printf(" frag");
+ bprintf(bp, " frag");
break;
case O_FIB:
- printf(" fib %u", cmd->arg1 );
+ bprintf(bp, " fib %u", cmd->arg1 );
break;
case O_SOCKARG:
- printf(" sockarg");
+ bprintf(bp, " sockarg");
break;
case O_IN:
- printf(cmd->len & F_NOT ? " out" : " in");
+ bprintf(bp, cmd->len & F_NOT ? " out" : " in");
break;
case O_DIVERTED:
switch (cmd->arg1) {
case 3:
- printf(" diverted");
+ bprintf(bp, " diverted");
break;
case 1:
- printf(" diverted-loopback");
+ bprintf(bp, " diverted-loopback");
break;
case 2:
- printf(" diverted-output");
+ bprintf(bp, " diverted-output");
break;
default:
- printf(" diverted-?<%u>", cmd->arg1);
+ bprintf(bp, " diverted-?<%u>", cmd->arg1);
break;
}
break;
case O_LAYER2:
- printf(" layer2");
+ bprintf(bp, " layer2");
break;
case O_XMIT:
case O_RECV:
case O_VIA:
{
- char const *s;
+ char const *s, *t;
ipfw_insn_if *cmdif = (ipfw_insn_if *)cmd;
if (cmd->opcode == O_XMIT)
@@ -1578,97 +1835,112 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
else /* if (cmd->opcode == O_VIA) */
s = "via";
if (cmdif->name[0] == '\0')
- printf(" %s %s", s,
+ bprintf(bp, " %s %s", s,
inet_ntoa(cmdif->p.ip));
- else if (cmdif->name[0] == '\1') /* interface table */
- printf(" %s table(%d)", s, cmdif->p.glob);
- else
- printf(" %s %s", s, cmdif->name);
+ else if (cmdif->name[0] == '\1') {
+ /* interface table */
+ t = table_search_ctlv(fo->tstate,
+ cmdif->p.kidx);
+ bprintf(bp, " %s table(%s)", s, t);
+ } else
+ bprintf(bp, " %s %s", s, cmdif->name);
break;
}
+ case O_IP_FLOW_LOOKUP:
+ {
+ char *t;
+
+ t = table_search_ctlv(fo->tstate, cmd->arg1);
+ bprintf(bp, " flow table(%s", t);
+ if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32))
+ bprintf(bp, ",%u",
+ ((ipfw_insn_u32 *)cmd)->d[0]);
+ bprintf(bp, ")");
+ break;
+ }
case O_IPID:
if (F_LEN(cmd) == 1)
- printf(" ipid %u", cmd->arg1 );
+ bprintf(bp, " ipid %u", cmd->arg1 );
else
- print_newports((ipfw_insn_u16 *)cmd, 0,
+ print_newports(bp, (ipfw_insn_u16 *)cmd, 0,
O_IPID);
break;
case O_IPTTL:
if (F_LEN(cmd) == 1)
- printf(" ipttl %u", cmd->arg1 );
+ bprintf(bp, " ipttl %u", cmd->arg1 );
else
- print_newports((ipfw_insn_u16 *)cmd, 0,
+ print_newports(bp, (ipfw_insn_u16 *)cmd, 0,
O_IPTTL);
break;
case O_IPVER:
- printf(" ipver %u", cmd->arg1 );
+ bprintf(bp, " ipver %u", cmd->arg1 );
break;
case O_IPPRECEDENCE:
- printf(" ipprecedence %u", (cmd->arg1) >> 5 );
+ bprintf(bp, " ipprecedence %u", cmd->arg1 >> 5);
break;
case O_DSCP:
- print_dscp((ipfw_insn_u32 *)cmd);
+ print_dscp(bp, (ipfw_insn_u32 *)cmd);
break;
case O_IPLEN:
if (F_LEN(cmd) == 1)
- printf(" iplen %u", cmd->arg1 );
+ bprintf(bp, " iplen %u", cmd->arg1 );
else
- print_newports((ipfw_insn_u16 *)cmd, 0,
+ print_newports(bp, (ipfw_insn_u16 *)cmd, 0,
O_IPLEN);
break;
case O_IPOPT:
- print_flags("ipoptions", cmd, f_ipopts);
+ print_flags(bp, "ipoptions", cmd, f_ipopts);
break;
case O_IPTOS:
- print_flags("iptos", cmd, f_iptos);
+ print_flags(bp, "iptos", cmd, f_iptos);
break;
case O_ICMPTYPE:
- print_icmptypes((ipfw_insn_u32 *)cmd);
+ print_icmptypes(bp, (ipfw_insn_u32 *)cmd);
break;
case O_ESTAB:
- printf(" established");
+ bprintf(bp, " established");
break;
case O_TCPDATALEN:
if (F_LEN(cmd) == 1)
- printf(" tcpdatalen %u", cmd->arg1 );
+ bprintf(bp, " tcpdatalen %u", cmd->arg1 );
else
- print_newports((ipfw_insn_u16 *)cmd, 0,
+ print_newports(bp, (ipfw_insn_u16 *)cmd, 0,
O_TCPDATALEN);
break;
case O_TCPFLAGS:
- print_flags("tcpflags", cmd, f_tcpflags);
+ print_flags(bp, "tcpflags", cmd, f_tcpflags);
break;
case O_TCPOPTS:
- print_flags("tcpoptions", cmd, f_tcpopts);
+ print_flags(bp, "tcpoptions", cmd, f_tcpopts);
break;
case O_TCPWIN:
if (F_LEN(cmd) == 1)
- printf(" tcpwin %u", cmd->arg1);
+ bprintf(bp, " tcpwin %u", cmd->arg1);
else
- print_newports((ipfw_insn_u16 *)cmd, 0,
+ print_newports(bp, (ipfw_insn_u16 *)cmd, 0,
O_TCPWIN);
break;
case O_TCPACK:
- printf(" tcpack %d", ntohl(cmd32->d[0]));
+ bprintf(bp, " tcpack %d", ntohl(cmd32->d[0]));
break;
case O_TCPSEQ:
- printf(" tcpseq %d", ntohl(cmd32->d[0]));
+ bprintf(bp, " tcpseq %d", ntohl(cmd32->d[0]));
break;
case O_UID:
@@ -1676,9 +1948,9 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
struct passwd *pwd = getpwuid(cmd32->d[0]);
if (pwd)
- printf(" uid %s", pwd->pw_name);
+ bprintf(bp, " uid %s", pwd->pw_name);
else
- printf(" uid %u", cmd32->d[0]);
+ bprintf(bp, " uid %u", cmd32->d[0]);
}
break;
@@ -1687,30 +1959,30 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
struct group *grp = getgrgid(cmd32->d[0]);
if (grp)
- printf(" gid %s", grp->gr_name);
+ bprintf(bp, " gid %s", grp->gr_name);
else
- printf(" gid %u", cmd32->d[0]);
+ bprintf(bp, " gid %u", cmd32->d[0]);
}
break;
case O_JAIL:
- printf(" jail %d", cmd32->d[0]);
+ bprintf(bp, " jail %d", cmd32->d[0]);
break;
case O_VERREVPATH:
- printf(" verrevpath");
+ bprintf(bp, " verrevpath");
break;
case O_VERSRCREACH:
- printf(" versrcreach");
+ bprintf(bp, " versrcreach");
break;
case O_ANTISPOOF:
- printf(" antispoof");
+ bprintf(bp, " antispoof");
break;
case O_IPSEC:
- printf(" ipsec");
+ bprintf(bp, " ipsec");
break;
case O_NOP:
@@ -1718,7 +1990,7 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
break;
case O_KEEP_STATE:
- printf(" keep-state");
+ bprintf(bp, " keep-state");
break;
case O_LIMIT: {
@@ -1727,113 +1999,132 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
uint8_t x = c->limit_mask;
char const *comma = " ";
- printf(" limit");
+ bprintf(bp, " limit");
for (; p->x != 0 ; p++)
if ((x & p->x) == p->x) {
x &= ~p->x;
- printf("%s%s", comma, p->s);
+ bprintf(bp, "%s%s", comma,p->s);
comma = ",";
}
- PRINT_UINT_ARG(" ", c->conn_limit);
+ bprint_uint_arg(bp, " ", c->conn_limit);
break;
}
case O_IP6:
- printf(" ip6");
+ bprintf(bp, " ip6");
break;
case O_IP4:
- printf(" ip4");
+ bprintf(bp, " ip4");
break;
case O_ICMP6TYPE:
- print_icmp6types((ipfw_insn_u32 *)cmd);
+ print_icmp6types(bp, (ipfw_insn_u32 *)cmd);
break;
case O_EXT_HDR:
- print_ext6hdr( (ipfw_insn *) cmd );
+ print_ext6hdr(bp, (ipfw_insn *)cmd);
break;
case O_TAGGED:
if (F_LEN(cmd) == 1)
- PRINT_UINT_ARG(" tagged ", cmd->arg1);
+ bprint_uint_arg(bp, " tagged ",
+ cmd->arg1);
else
- print_newports((ipfw_insn_u16 *)cmd, 0,
- O_TAGGED);
+ print_newports(bp, (ipfw_insn_u16 *)cmd,
+ 0, O_TAGGED);
break;
default:
- printf(" [opcode %d len %d]",
+ bprintf(bp, " [opcode %d len %d]",
cmd->opcode, cmd->len);
}
}
if (cmd->len & F_OR) {
- printf(" or");
+ bprintf(bp, " or");
or_block = 1;
} else if (or_block) {
- printf(" }");
+ bprintf(bp, " }");
or_block = 0;
}
}
- show_prerequisites(&flags, HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP
+ show_prerequisites(bp, &flags, HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP
| HAVE_IP, 0);
if (comment)
- printf(" // %s", comment);
- printf("\n");
+ bprintf(bp, " // %s", comment);
+ bprintf(bp, "\n");
}
static void
-show_dyn_ipfw(ipfw_dyn_rule *d, int pcwidth, int bcwidth)
+show_dyn_state(struct cmdline_opts *co, struct format_opts *fo,
+ struct buf_pr *bp, ipfw_dyn_rule *d)
{
struct protoent *pe;
struct in_addr a;
uint16_t rulenum;
char buf[INET6_ADDRSTRLEN];
- if (!co.do_expired) {
+ if (!co->do_expired) {
if (!d->expire && !(d->dyn_type == O_LIMIT_PARENT))
return;
}
bcopy(&d->rule, &rulenum, sizeof(rulenum));
- printf("%05d", rulenum);
- if (pcwidth > 0 || bcwidth > 0) {
- printf(" ");
- pr_u64(&d->pcnt, pcwidth);
- pr_u64(&d->bcnt, bcwidth);
- printf("(%ds)", d->expire);
+ bprintf(bp, "%05d", 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) {
case O_LIMIT_PARENT:
- printf(" PARENT %d", d->count);
+ bprintf(bp, " PARENT %d", d->count);
break;
case O_LIMIT:
- printf(" LIMIT");
+ bprintf(bp, " LIMIT");
break;
case O_KEEP_STATE: /* bidir, no mask */
- printf(" STATE");
+ bprintf(bp, " STATE");
break;
}
if ((pe = getprotobynumber(d->id.proto)) != NULL)
- printf(" %s", pe->p_name);
+ bprintf(bp, " %s", pe->p_name);
else
- printf(" proto %u", d->id.proto);
+ bprintf(bp, " proto %u", d->id.proto);
if (d->id.addr_type == 4) {
a.s_addr = htonl(d->id.src_ip);
- printf(" %s %d", inet_ntoa(a), d->id.src_port);
+ bprintf(bp, " %s %d", inet_ntoa(a), d->id.src_port);
a.s_addr = htonl(d->id.dst_ip);
- printf(" <-> %s %d", inet_ntoa(a), d->id.dst_port);
+ bprintf(bp, " <-> %s %d", inet_ntoa(a), d->id.dst_port);
} else if (d->id.addr_type == 6) {
- printf(" %s %d", inet_ntop(AF_INET6, &d->id.src_ip6, buf,
+ bprintf(bp, " %s %d", inet_ntop(AF_INET6, &d->id.src_ip6, buf,
sizeof(buf)), d->id.src_port);
- printf(" <-> %s %d", inet_ntop(AF_INET6, &d->id.dst_ip6, buf,
- sizeof(buf)), d->id.dst_port);
+ bprintf(bp, " <-> %s %d", inet_ntop(AF_INET6, &d->id.dst_ip6,
+ buf, sizeof(buf)), d->id.dst_port);
} else
- printf(" UNKNOWN <-> UNKNOWN\n");
+ bprintf(bp, " UNKNOWN <-> UNKNOWN\n");
+}
- printf("\n");
+static int
+do_range_cmd(int cmd, ipfw_range_tlv *rt)
+{
+ ipfw_range_header rh;
+ size_t sz;
+
+ memset(&rh, 0, sizeof(rh));
+ memcpy(&rh.range, rt, sizeof(*rt));
+ rh.range.head.length = sizeof(*rt);
+ rh.range.head.type = IPFW_TLV_RANGE;
+ sz = sizeof(rh);
+
+ if (do_get3(cmd, &rh.opheader, &sz) != 0)
+ return (-1);
+ /* Save number of matched objects */
+ rt->new_set = rh.range.new_set;
+ return (0);
}
/*
@@ -1846,77 +2137,75 @@ show_dyn_ipfw(ipfw_dyn_rule *d, int pcwidth, int bcwidth)
void
ipfw_sets_handler(char *av[])
{
- uint32_t set_disable, masks[2];
- int i, nbytes;
- uint16_t rulenum;
- uint8_t cmd, new_set;
+ uint32_t masks[2];
+ int i;
+ uint8_t cmd, rulenum;
+ ipfw_range_tlv rt;
+ char *msg;
+ size_t size;
av++;
+ memset(&rt, 0, sizeof(rt));
if (av[0] == NULL)
errx(EX_USAGE, "set needs command");
if (_substrcmp(*av, "show") == 0) {
- void *data = NULL;
- char const *msg;
- int nalloc;
-
- nalloc = nbytes = sizeof(struct ip_fw);
- while (nbytes >= nalloc) {
- if (data)
- free(data);
- nalloc = nalloc * 2 + 200;
- nbytes = nalloc;
- data = safe_calloc(1, nbytes);
- if (do_cmd(IP_FW_GET, data, (uintptr_t)&nbytes) < 0)
- err(EX_OSERR, "getsockopt(IP_FW_GET)");
- }
+ struct format_opts fo;
+ ipfw_cfg_lheader *cfg;
- bcopy(&((struct ip_fw *)data)->next_rule,
- &set_disable, sizeof(set_disable));
+ memset(&fo, 0, sizeof(fo));
+ if (ipfw_get_config(&co, &fo, &cfg, &size) != 0)
+ err(EX_OSERR, "requesting config failed");
- for (i = 0, msg = "disable" ; i < RESVD_SET; i++)
- if ((set_disable & (1<<i))) {
+ for (i = 0, msg = "disable"; i < RESVD_SET; i++)
+ if ((cfg->set_mask & (1<<i)) == 0) {
printf("%s %d", msg, i);
msg = "";
}
- msg = (set_disable) ? " enable" : "enable";
+ msg = (cfg->set_mask != (uint32_t)-1) ? " enable" : "enable";
for (i = 0; i < RESVD_SET; i++)
- if (!(set_disable & (1<<i))) {
+ if ((cfg->set_mask & (1<<i)) != 0) {
printf("%s %d", msg, i);
msg = "";
}
printf("\n");
+ free(cfg);
} else if (_substrcmp(*av, "swap") == 0) {
av++;
if ( av[0] == NULL || av[1] == NULL )
errx(EX_USAGE, "set swap needs 2 set numbers\n");
- rulenum = atoi(av[0]);
- new_set = atoi(av[1]);
- if (!isdigit(*(av[0])) || rulenum > RESVD_SET)
+ rt.set = atoi(av[0]);
+ rt.new_set = atoi(av[1]);
+ if (!isdigit(*(av[0])) || rt.set > RESVD_SET)
errx(EX_DATAERR, "invalid set number %s\n", av[0]);
- if (!isdigit(*(av[1])) || new_set > RESVD_SET)
+ if (!isdigit(*(av[1])) || rt.new_set > RESVD_SET)
errx(EX_DATAERR, "invalid set number %s\n", av[1]);
- masks[0] = (4 << 24) | (new_set << 16) | (rulenum);
- i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t));
+ i = do_range_cmd(IP_FW_SET_SWAP, &rt);
} else if (_substrcmp(*av, "move") == 0) {
av++;
if (av[0] && _substrcmp(*av, "rule") == 0) {
- cmd = 2;
+ rt.flags = IPFW_RCFLAG_RANGE; /* move rules to new set */
+ cmd = IP_FW_XMOVE;
av++;
} else
- cmd = 3;
+ cmd = IP_FW_SET_MOVE; /* Move set to new one */
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]);
- new_set = atoi(av[2]);
- if (!isdigit(*(av[0])) || (cmd == 3 && rulenum > RESVD_SET) ||
- (cmd == 2 && rulenum == IPFW_DEFAULT_RULE) )
+ rt.new_set = atoi(av[2]);
+ if (cmd == IP_FW_XMOVE) {
+ rt.start_rule = rulenum;
+ rt.end_rule = rulenum;
+ } else
+ rt.set = rulenum;
+ rt.new_set = atoi(av[2]);
+ if (!isdigit(*(av[0])) || (cmd == 3 && rt.set > RESVD_SET) ||
+ (cmd == 2 && rt.start_rule == IPFW_DEFAULT_RULE) )
errx(EX_DATAERR, "invalid source number %s\n", av[0]);
- if (!isdigit(*(av[2])) || new_set > RESVD_SET)
+ if (!isdigit(*(av[2])) || rt.new_set > RESVD_SET)
errx(EX_DATAERR, "invalid dest. set %s\n", av[1]);
- masks[0] = (cmd << 24) | (new_set << 16) | (rulenum);
- i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t));
+ i = do_range_cmd(cmd, &rt);
} else if (_substrcmp(*av, "disable") == 0 ||
_substrcmp(*av, "enable") == 0 ) {
int which = _substrcmp(*av, "enable") == 0 ? 1 : 0;
@@ -1944,9 +2233,11 @@ ipfw_sets_handler(char *av[])
errx(EX_DATAERR,
"cannot enable and disable the same set\n");
- i = do_cmd(IP_FW_DEL, masks, sizeof(masks));
+ rt.set = masks[0];
+ rt.new_set = masks[1];
+ i = do_range_cmd(IP_FW_SET_ENABLE, &rt);
if (i)
- warn("set enable/disable: setsockopt(IP_FW_DEL)");
+ warn("set enable/disable: setsockopt(IP_FW_SET_ENABLE)");
} else
errx(EX_USAGE, "invalid set command %s\n", *av);
}
@@ -1984,28 +2275,204 @@ ipfw_sysctl_handler(char *av[], int which)
}
}
+typedef void state_cb(struct cmdline_opts *co, struct format_opts *fo,
+ void *arg, void *state);
+
+static void
+prepare_format_dyn(struct cmdline_opts *co, struct format_opts *fo,
+ void *arg, void *_state)
+{
+ ipfw_dyn_rule *d;
+ int width;
+ uint8_t set;
+
+ d = (ipfw_dyn_rule *)_state;
+ /* Count _ALL_ states */
+ fo->dcnt++;
+
+ 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;
+ }
+
+ width = pr_u64(NULL, &d->pcnt, 0);
+ if (width > fo->pcwidth)
+ fo->pcwidth = width;
+
+ width = pr_u64(NULL, &d->bcnt, 0);
+ if (width > fo->bcwidth)
+ fo->bcwidth = width;
+}
+
+static int
+foreach_state(struct cmdline_opts *co, struct format_opts *fo,
+ caddr_t base, size_t sz, state_cb dyn_bc, void *dyn_arg)
+{
+ int ttype;
+ state_cb *fptr;
+ void *farg;
+ ipfw_obj_tlv *tlv;
+ ipfw_obj_ctlv *ctlv;
+
+ fptr = NULL;
+ ttype = 0;
+
+ while (sz > 0) {
+ ctlv = (ipfw_obj_ctlv *)base;
+ switch (ctlv->head.type) {
+ case IPFW_TLV_DYNSTATE_LIST:
+ base += sizeof(*ctlv);
+ sz -= sizeof(*ctlv);
+ ttype = IPFW_TLV_DYN_ENT;
+ fptr = dyn_bc;
+ farg = dyn_arg;
+ break;
+ default:
+ return (sz);
+ }
+
+ while (sz > 0) {
+ tlv = (ipfw_obj_tlv *)base;
+ if (tlv->type != ttype)
+ break;
+
+ fptr(co, fo, farg, tlv + 1);
+ sz -= tlv->length;
+ base += tlv->length;
+ }
+ }
+
+ return (sz);
+}
+
+static void
+prepare_format_opts(struct cmdline_opts *co, struct format_opts *fo,
+ ipfw_obj_tlv *rtlv, int rcnt, caddr_t dynbase, size_t dynsz)
+{
+ int bcwidth, pcwidth, width;
+ int n;
+ struct ip_fw_bcounter *cntr;
+ struct ip_fw_rule *r;
+
+ bcwidth = 0;
+ pcwidth = 0;
+ if (fo->show_counters != 0) {
+ for (n = 0; n < rcnt; n++,
+ rtlv = (ipfw_obj_tlv *)((caddr_t)rtlv + rtlv->length)) {
+ cntr = (struct ip_fw_bcounter *)(rtlv + 1);
+ r = (struct ip_fw_rule *)((caddr_t)cntr + cntr->size);
+ /* skip rules from another set */
+ if (co->use_set && r->set != co->use_set - 1)
+ continue;
+
+ /* packet counter */
+ width = pr_u64(NULL, &cntr->pcnt, 0);
+ if (width > pcwidth)
+ pcwidth = width;
+
+ /* byte counter */
+ width = pr_u64(NULL, &cntr->bcnt, 0);
+ if (width > bcwidth)
+ bcwidth = width;
+ }
+ }
+ fo->bcwidth = bcwidth;
+ fo->pcwidth = pcwidth;
+
+ fo->dcnt = 0;
+ if (co->do_dynamic && dynsz > 0)
+ foreach_state(co, fo, dynbase, dynsz, prepare_format_dyn, NULL);
+}
+
+static int
+list_static_range(struct cmdline_opts *co, struct format_opts *fo,
+ struct buf_pr *bp, ipfw_obj_tlv *rtlv, int rcnt)
+{
+ int n, seen;
+ struct ip_fw_rule *r;
+ struct ip_fw_bcounter *cntr;
+ int c = 0;
+
+ for (n = seen = 0; n < rcnt; n++,
+ rtlv = (ipfw_obj_tlv *)((caddr_t)rtlv + rtlv->length)) {
+
+ if (fo->show_counters != 0) {
+ cntr = (struct ip_fw_bcounter *)(rtlv + 1);
+ r = (struct ip_fw_rule *)((caddr_t)cntr + cntr->size);
+ } else {
+ cntr = NULL;
+ r = (struct ip_fw_rule *)(rtlv + 1);
+ }
+ if (r->rulenum > fo->last)
+ break;
+ if (co->use_set && r->set != co->use_set - 1)
+ continue;
+ if (r->rulenum >= fo->first && r->rulenum <= fo->last) {
+ show_static_rule(co, fo, bp, r, cntr);
+ printf("%s", bp->buf);
+ c += rtlv->length;
+ bp_flush(bp);
+ seen++;
+ }
+ }
+
+ return (seen);
+}
+
+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)
+ 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) {
+ show_dyn_state(co, fo, bp, d);
+ printf("%s\n", bp->buf);
+ bp_flush(bp);
+ }
+}
+
+static int
+list_dyn_range(struct cmdline_opts *co, struct format_opts *fo,
+ struct buf_pr *bp, caddr_t base, size_t sz)
+{
+
+ sz = foreach_state(co, fo, base, sz, list_dyn_state, bp);
+ return (sz);
+}
+
void
ipfw_list(int ac, char *av[], int show_counters)
{
- struct ip_fw *r;
- ipfw_dyn_rule *dynrules, *d;
-
-#define NEXT(r) ((struct ip_fw *)((char *)r + RULESIZE(r)))
- char *lim;
- void *data = NULL;
- int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width;
- int exitval = EX_OK;
+ ipfw_cfg_lheader *cfg;
+ struct format_opts sfo;
+ size_t sz;
+ int error;
int lac;
char **lav;
- u_long rnum, last;
+ uint32_t rnum;
char *endptr;
- int seen = 0;
- uint8_t set;
-
- const int ocmd = co.do_pipe ? IP_DUMMYNET_GET : IP_FW_GET;
- int nalloc = 1024; /* start somewhere... */
-
- last = 0;
if (co.test_only) {
fprintf(stderr, "Testing only, list disabled\n");
@@ -2018,162 +2485,216 @@ ipfw_list(int ac, char *av[], int show_counters)
ac--;
av++;
+ memset(&sfo, 0, sizeof(sfo));
- /* get rules or pipes from kernel, resizing array as necessary */
- nbytes = nalloc;
+ /* Determine rule range to request */
+ if (ac > 0) {
+ for (lac = ac, lav = av; lac != 0; lac--) {
+ rnum = strtoul(*lav++, &endptr, 10);
+ if (sfo.first == 0 || rnum < sfo.first)
+ sfo.first = rnum;
- while (nbytes >= nalloc) {
- nalloc = nalloc * 2 + 200;
- nbytes = nalloc;
- data = safe_realloc(data, nbytes);
- if (do_cmd(ocmd, data, (uintptr_t)&nbytes) < 0)
- err(EX_OSERR, "getsockopt(IP_%s_GET)",
- co.do_pipe ? "DUMMYNET" : "FW");
+ if (*endptr == '-')
+ rnum = strtoul(endptr + 1, &endptr, 10);
+ if (sfo.last == 0 || rnum > sfo.last)
+ sfo.last = rnum;
+ }
}
- /*
- * Count static rules. They have variable size so we
- * need to scan the list to count them.
- */
- for (nstat = 1, r = data, lim = (char *)data + nbytes;
- r->rulenum < IPFW_DEFAULT_RULE && (char *)r < lim;
- ++nstat, r = NEXT(r) )
- ; /* nothing */
+ /* get configuraion from kernel */
+ cfg = NULL;
+ sfo.show_counters = show_counters;
+ sfo.flags = IPFW_CFG_GET_STATIC;
+ if (co.do_dynamic != 0)
+ sfo.flags |= IPFW_CFG_GET_STATES;
+ if (sfo.show_counters != 0)
+ sfo.flags |= IPFW_CFG_GET_COUNTERS;
+ if (ipfw_get_config(&co, &sfo, &cfg, &sz) != 0)
+ err(EX_OSERR, "retrieving config failed");
+
+ error = ipfw_show_config(&co, &sfo, cfg, sz, ac, av);
+
+ free(cfg);
+
+ if (error != EX_OK)
+ exit(error);
+}
+
+static int
+ipfw_show_config(struct cmdline_opts *co, struct format_opts *fo,
+ ipfw_cfg_lheader *cfg, size_t sz, int ac, char *av[])
+{
+ caddr_t dynbase;
+ size_t dynsz;
+ int rcnt;
+ int exitval = EX_OK;
+ int lac;
+ char **lav;
+ char *endptr;
+ size_t readsz;
+ struct buf_pr bp;
+ ipfw_obj_ctlv *ctlv, *tstate;
+ ipfw_obj_tlv *rbase;
/*
- * Count dynamic rules. This is easier as they have
- * fixed size.
+ * Handle tablenames TLV first, if any
*/
- r = NEXT(r);
- dynrules = (ipfw_dyn_rule *)r ;
- n = (char *)r - (char *)data;
- ndyn = (nbytes - n) / sizeof *dynrules;
-
- /* if showing stats, figure out column widths ahead of time */
- bcwidth = pcwidth = 0;
- if (show_counters) {
- for (n = 0, r = data; n < nstat; n++, r = NEXT(r)) {
- /* skip rules from another set */
- if (co.use_set && r->set != co.use_set - 1)
- continue;
-
- /* packet counter */
- width = pr_u64(&r->pcnt, 0);
- if (width > pcwidth)
- pcwidth = width;
+ tstate = NULL;
+ rbase = NULL;
+ dynbase = NULL;
+ dynsz = 0;
+ readsz = sizeof(*cfg);
+ rcnt = 0;
+
+ fo->set_mask = cfg->set_mask;
+
+ ctlv = (ipfw_obj_ctlv *)(cfg + 1);
+
+ if (cfg->flags & IPFW_CFG_GET_STATIC) {
+ /* We've requested static rules */
+ if (ctlv->head.type == IPFW_TLV_TBLNAME_LIST) {
+ fo->tstate = ctlv;
+ readsz += ctlv->head.length;
+ ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv +
+ ctlv->head.length);
+ }
- /* byte counter */
- width = pr_u64(&r->bcnt, 0);
- if (width > bcwidth)
- bcwidth = width;
+ if (ctlv->head.type == IPFW_TLV_RULE_LIST) {
+ rbase = (ipfw_obj_tlv *)(ctlv + 1);
+ rcnt = ctlv->count;
+ readsz += ctlv->head.length;
+ ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv +
+ ctlv->head.length);
}
}
- if (co.do_dynamic && ndyn) {
- for (n = 0, d = dynrules; n < ndyn; n++, d++) {
- if (co.use_set) {
- /* skip rules from another set */
- bcopy((char *)&d->rule + sizeof(uint16_t),
- &set, sizeof(uint8_t));
- if (set != co.use_set - 1)
- continue;
- }
- width = pr_u64(&d->pcnt, 0);
- if (width > pcwidth)
- pcwidth = width;
- width = pr_u64(&d->bcnt, 0);
- if (width > bcwidth)
- bcwidth = width;
- }
+ if ((cfg->flags & IPFW_CFG_GET_STATES) && (readsz != sz)) {
+ /* We may have some dynamic states */
+ dynsz = sz - readsz;
+ /* Skip empty header */
+ if (dynsz != sizeof(ipfw_obj_ctlv))
+ dynbase = (caddr_t)ctlv;
+ else
+ dynsz = 0;
}
+
+ prepare_format_opts(co, fo, rbase, rcnt, dynbase, dynsz);
+ bp_alloc(&bp, 4096);
+
/* if no rule numbers were specified, list all rules */
if (ac == 0) {
- for (n = 0, r = data; n < nstat; n++, r = NEXT(r)) {
- if (co.use_set && r->set != co.use_set - 1)
- continue;
- show_ipfw(r, pcwidth, bcwidth);
- }
+ fo->first = 0;
+ fo->last = IPFW_DEFAULT_RULE;
+ list_static_range(co, fo, &bp, rbase, rcnt);
- if (co.do_dynamic && ndyn) {
- printf("## Dynamic rules (%d):\n", ndyn);
- for (n = 0, d = dynrules; n < ndyn; n++, d++) {
- if (co.use_set) {
- bcopy((char *)&d->rule + sizeof(uint16_t),
- &set, sizeof(uint8_t));
- if (set != co.use_set - 1)
- continue;
- }
- show_dyn_ipfw(d, pcwidth, bcwidth);
- }
+ if (co->do_dynamic && dynsz > 0) {
+ printf("## Dynamic rules (%d %zu):\n", fo->dcnt, dynsz);
+ list_dyn_range(co, fo, &bp, dynbase, dynsz);
}
- goto done;
+
+ bp_free(&bp);
+ return (EX_OK);
}
/* display specific rules requested on command line */
-
for (lac = ac, lav = av; lac != 0; lac--) {
/* convert command line rule # */
- last = rnum = strtoul(*lav++, &endptr, 10);
+ fo->last = fo->first = strtoul(*lav++, &endptr, 10);
if (*endptr == '-')
- last = strtoul(endptr+1, &endptr, 10);
+ fo->last = strtoul(endptr + 1, &endptr, 10);
if (*endptr) {
exitval = EX_USAGE;
warnx("invalid rule number: %s", *(lav - 1));
continue;
}
- for (n = seen = 0, r = data; n < nstat; n++, r = NEXT(r) ) {
- if (r->rulenum > last)
- break;
- if (co.use_set && r->set != co.use_set - 1)
- continue;
- if (r->rulenum >= rnum && r->rulenum <= last) {
- show_ipfw(r, pcwidth, bcwidth);
- seen = 1;
- }
- }
- if (!seen) {
+
+ if (list_static_range(co, fo, &bp, rbase, rcnt) == 0) {
/* give precedence to other error(s) */
if (exitval == EX_OK)
exitval = EX_UNAVAILABLE;
- warnx("rule %lu does not exist", rnum);
+ if (fo->first == fo->last)
+ warnx("rule %u does not exist", fo->first);
+ else
+ warnx("no rules in range %u-%u",
+ fo->first, fo->last);
}
}
- if (co.do_dynamic && ndyn) {
+ if (co->do_dynamic && dynsz > 0) {
printf("## Dynamic rules:\n");
for (lac = ac, lav = av; lac != 0; lac--) {
- last = rnum = strtoul(*lav++, &endptr, 10);
+ fo->last = fo->first = strtoul(*lav++, &endptr, 10);
if (*endptr == '-')
- last = strtoul(endptr+1, &endptr, 10);
+ fo->last = strtoul(endptr+1, &endptr, 10);
if (*endptr)
/* already warned */
continue;
- for (n = 0, d = dynrules; n < ndyn; n++, d++) {
- uint16_t rulenum;
-
- bcopy(&d->rule, &rulenum, sizeof(rulenum));
- if (rulenum > rnum)
- break;
- if (co.use_set) {
- bcopy((char *)&d->rule + sizeof(uint16_t),
- &set, sizeof(uint8_t));
- if (set != co.use_set - 1)
- continue;
- }
- if (r->rulenum >= rnum && r->rulenum <= last)
- show_dyn_ipfw(d, pcwidth, bcwidth);
- }
+ list_dyn_range(co, fo, &bp, dynbase, dynsz);
}
}
- ac = 0;
+ bp_free(&bp);
+ return (exitval);
+}
-done:
- free(data);
- if (exitval != EX_OK)
- exit(exitval);
-#undef NEXT
+/*
+ * Retrieves current ipfw configuration of given type
+ * and stores its pointer to @pcfg.
+ *
+ * Caller is responsible for freeing @pcfg.
+ *
+ * Returns 0 on success.
+ */
+
+static int
+ipfw_get_config(struct cmdline_opts *co, struct format_opts *fo,
+ ipfw_cfg_lheader **pcfg, size_t *psize)
+{
+ ipfw_cfg_lheader *cfg;
+ size_t sz;
+ int i;
+
+
+ if (co->test_only != 0) {
+ fprintf(stderr, "Testing only, list disabled\n");
+ return (0);
+ }
+
+ /* Start with some data size */
+ sz = 4096;
+ cfg = NULL;
+
+ for (i = 0; i < 16; i++) {
+ if (cfg != NULL)
+ free(cfg);
+ if ((cfg = calloc(1, sz)) == NULL)
+ return (ENOMEM);
+
+ cfg->flags = fo->flags;
+ cfg->start_rule = fo->first;
+ cfg->end_rule = fo->last;
+
+ if (do_get3(IP_FW_XGET, &cfg->opheader, &sz) != 0) {
+ if (errno != ENOMEM) {
+ free(cfg);
+ return (errno);
+ }
+
+ /* Buffer size is not enough. Try to increase */
+ sz = sz * 2;
+ if (sz < cfg->size)
+ sz = cfg->size;
+ continue;
+ }
+
+ *pcfg = cfg;
+ *psize = sz;
+ return (0);
+ }
+
+ free(cfg);
+ return (ENOMEM);
}
static int
@@ -2189,6 +2710,79 @@ lookup_host (char *host, struct in_addr *ipaddr)
return(0);
}
+struct tidx {
+ ipfw_obj_ntlv *idx;
+ uint32_t count;
+ uint32_t size;
+ uint16_t counter;
+ uint8_t set;
+};
+
+static uint16_t
+pack_table(struct tidx *tstate, char *name)
+{
+ int i;
+ ipfw_obj_ntlv *ntlv;
+
+ if (table_check_name(name) != 0)
+ return (0);
+
+ for (i = 0; i < tstate->count; i++) {
+ if (strcmp(tstate->idx[i].name, name) != 0)
+ continue;
+ if (tstate->idx[i].set != tstate->set)
+ continue;
+
+ return (tstate->idx[i].idx);
+ }
+
+ if (tstate->count + 1 > tstate->size) {
+ tstate->size += 4;
+ tstate->idx = realloc(tstate->idx, tstate->size *
+ sizeof(ipfw_obj_ntlv));
+ if (tstate->idx == NULL)
+ return (0);
+ }
+
+ ntlv = &tstate->idx[i];
+ memset(ntlv, 0, sizeof(ipfw_obj_ntlv));
+ strlcpy(ntlv->name, name, sizeof(ntlv->name));
+ ntlv->head.type = IPFW_TLV_TBL_NAME;
+ ntlv->head.length = sizeof(ipfw_obj_ntlv);
+ ntlv->set = tstate->set;
+ ntlv->idx = ++tstate->counter;
+ tstate->count++;
+
+ return (ntlv->idx);
+}
+
+static void
+fill_table(ipfw_insn *cmd, char *av, uint8_t opcode, struct tidx *tstate)
+{
+ uint32_t *d = ((ipfw_insn_u32 *)cmd)->d;
+ uint16_t uidx;
+ char *p;
+
+ if ((p = strchr(av + 6, ')')) == NULL)
+ errx(EX_DATAERR, "forgotten parenthesis: '%s'", av);
+ *p = '\0';
+ p = strchr(av + 6, ',');
+ if (p)
+ *p++ = '\0';
+
+ if ((uidx = 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);
+}
+
+
/*
* fills the addr and mask fields in the instruction as appropriate from av.
* Update length as appropriate.
@@ -2201,11 +2795,10 @@ lookup_host (char *host, struct in_addr *ipaddr)
* We can have multiple comma-separated address/mask entries.
*/
static void
-fill_ip(ipfw_insn_ip *cmd, char *av, int cblen)
+fill_ip(ipfw_insn_ip *cmd, char *av, int cblen, struct tidx *tstate)
{
int len = 0;
uint32_t *d = ((ipfw_insn_u32 *)cmd)->d;
- uint32_t tables_max;
cmd->o.len &= ~F_LEN_MASK; /* zero len */
@@ -2218,21 +2811,7 @@ fill_ip(ipfw_insn_ip *cmd, char *av, int cblen)
}
if (strncmp(av, "table(", 6) == 0) {
- char *p = strchr(av + 6, ',');
-
- if (p)
- *p++ = '\0';
- cmd->o.opcode = O_IP_DST_LOOKUP;
- cmd->o.arg1 = strtoul(av + 6, NULL, 0);
- tables_max = ipfw_get_tables_max();
- if (cmd->o.arg1 > tables_max)
- errx(EX_USAGE, "The table number exceeds the maximum "
- "allowed value (%u)", tables_max - 1);
- if (p) {
- cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32);
- d[0] = strtoul(p, NULL, 0);
- } else
- cmd->o.len |= F_INSN_SIZE(ipfw_insn);
+ fill_table(&cmd->o, av, O_IP_DST_LOOKUP, tstate);
return;
}
@@ -2413,35 +2992,16 @@ n2mask(struct in6_addr *mask, int n)
return;
}
-/*
- * helper function to process a set of flags and set bits in the
- * appropriate masks.
- */
static void
-fill_flags(ipfw_insn *cmd, enum ipfw_opcodes opcode,
+fill_flags_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode,
struct _s_x *flags, char *p)
{
- uint8_t set=0, clear=0;
+ char *e;
+ uint32_t set = 0, clear = 0;
- while (p && *p) {
- char *q; /* points to the separator */
- int val;
- uint8_t *which; /* mask we are working on */
+ if (fill_flags(flags, p, &e, &set, &clear) != 0)
+ errx(EX_DATAERR, "invalid flag %s", e);
- if (*p == '!') {
- p++;
- which = &clear;
- } else
- which = &set;
- q = strchr(p, ',');
- if (q)
- *q++ = '\0';
- val = match_token(flags, p);
- if (val <= 0)
- errx(EX_DATAERR, "invalid flag %s", p);
- *which |= (uint8_t)val;
- p = q;
- }
cmd->opcode = opcode;
cmd->len = (cmd->len & (F_NOT | F_OR)) | 1;
cmd->arg1 = (set & 0xff) | ( (clear & 0xff) << 8);
@@ -2451,13 +3011,14 @@ fill_flags(ipfw_insn *cmd, enum ipfw_opcodes opcode,
void
ipfw_delete(char *av[])
{
- uint32_t rulenum;
int i;
int exitval = EX_OK;
int do_set = 0;
+ ipfw_range_tlv rt;
av++;
NEED1("missing rule specification");
+ memset(&rt, 0, sizeof(rt));
if ( *av && _substrcmp(*av, "set") == 0) {
/* Do not allow using the following syntax:
* ipfw set N delete set M
@@ -2480,16 +3041,34 @@ ipfw_delete(char *av[])
} else if (co.do_pipe) {
exitval = ipfw_delete_pipe(co.do_pipe, i);
} else {
- if (co.use_set)
- rulenum = (i & 0xffff) | (5 << 24) |
- ((co.use_set - 1) << 16);
- else
- rulenum = (i & 0xffff) | (do_set << 24);
- i = do_cmd(IP_FW_DEL, &rulenum, sizeof rulenum);
- if (i) {
+ if (do_set != 0) {
+ rt.set = i & 31;
+ rt.flags = IPFW_RCFLAG_SET;
+ } else {
+ rt.start_rule = i & 0xffff;
+ rt.end_rule = i & 0xffff;
+ if (rt.start_rule == 0 && rt.end_rule == 0)
+ rt.flags |= IPFW_RCFLAG_ALL;
+ else
+ rt.flags |= IPFW_RCFLAG_RANGE;
+ if (co.use_set != 0) {
+ rt.set = co.use_set - 1;
+ rt.flags |= IPFW_RCFLAG_SET;
+ }
+ }
+ i = do_range_cmd(IP_FW_XDEL, &rt);
+ if (i != 0) {
exitval = EX_UNAVAILABLE;
- warn("rule %u: setsockopt(IP_FW_DEL)",
- rulenum);
+ warn("rule %u: setsockopt(IP_FW_XDEL)",
+ rt.start_rule);
+ } else if (rt.new_set == 0) {
+ exitval = EX_UNAVAILABLE;
+ if (rt.start_rule != rt.end_rule)
+ warnx("no rules rules in %u-%u range",
+ rt.start_rule, rt.end_rule);
+ else
+ warnx("rule %u not found",
+ rt.start_rule);
}
}
}
@@ -2506,8 +3085,11 @@ ipfw_delete(char *av[])
* patterns which match interfaces.
*/
static void
-fill_iface(ipfw_insn_if *cmd, char *arg, int cblen)
+fill_iface(ipfw_insn_if *cmd, char *arg, int cblen, struct tidx *tstate)
{
+ char *p;
+ uint16_t uidx;
+
cmd->name[0] = '\0';
cmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
@@ -2517,11 +3099,17 @@ fill_iface(ipfw_insn_if *cmd, char *arg, int cblen)
if (strcmp(arg, "any") == 0)
cmd->o.len = 0; /* effectively ignore this command */
else if (strncmp(arg, "table(", 6) == 0) {
- char *p = strchr(arg + 6, ',');
+ if ((p = strchr(arg + 6, ')')) == NULL)
+ errx(EX_DATAERR, "forgotten parenthesis: '%s'", arg);
+ *p = '\0';
+ p = strchr(arg + 6, ',');
if (p)
*p++ = '\0';
+ if ((uidx = pack_table(tstate, arg + 6)) == 0)
+ errx(EX_DATAERR, "Invalid table name: %s", arg + 6);
+
cmd->name[0] = '\1'; /* Special value indicating table */
- cmd->p.glob = strtoul(arg + 6, NULL, 0);
+ cmd->p.kidx = uidx;
} else if (!isdigit(*arg)) {
strlcpy(cmd->name, arg, sizeof(cmd->name));
cmd->p.glob = strpbrk(arg, "*?[") != NULL ? 1 : 0;
@@ -2735,9 +3323,9 @@ add_proto_compat(ipfw_insn *cmd, char *av, u_char *protop)
}
static ipfw_insn *
-add_srcip(ipfw_insn *cmd, char *av, int cblen)
+add_srcip(ipfw_insn *cmd, char *av, int cblen, struct tidx *tstate)
{
- fill_ip((ipfw_insn_ip *)cmd, av, cblen);
+ fill_ip((ipfw_insn_ip *)cmd, av, cblen, tstate);
if (cmd->opcode == O_IP_DST_SET) /* set */
cmd->opcode = O_IP_SRC_SET;
else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */
@@ -2752,9 +3340,9 @@ add_srcip(ipfw_insn *cmd, char *av, int cblen)
}
static ipfw_insn *
-add_dstip(ipfw_insn *cmd, char *av, int cblen)
+add_dstip(ipfw_insn *cmd, char *av, int cblen, struct tidx *tstate)
{
- fill_ip((ipfw_insn_ip *)cmd, av, cblen);
+ fill_ip((ipfw_insn_ip *)cmd, av, cblen, tstate);
if (cmd->opcode == O_IP_DST_SET) /* set */
;
else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */
@@ -2768,13 +3356,34 @@ add_dstip(ipfw_insn *cmd, char *av, int cblen)
return cmd;
}
+static struct _s_x f_reserved_keywords[] = {
+ { "altq", TOK_OR },
+ { "//", TOK_OR },
+ { "diverted", TOK_OR },
+ { "dst-port", TOK_OR },
+ { "src-port", TOK_OR },
+ { "established", TOK_OR },
+ { "keep-state", TOK_OR },
+ { "frag", TOK_OR },
+ { "icmptypes", TOK_OR },
+ { "in", TOK_OR },
+ { "out", TOK_OR },
+ { "ip6", TOK_OR },
+ { "any", TOK_OR },
+ { "to", TOK_OR },
+ { "via", TOK_OR },
+ { "{", TOK_OR },
+ { NULL, 0 } /* terminator */
+};
+
static ipfw_insn *
add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode, int cblen)
{
- /* XXX "any" is trapped before. Perhaps "to" */
- if (_substrcmp(av, "any") == 0) {
- return NULL;
- } else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto, cblen)) {
+
+ if (match_token(f_reserved_keywords, av) != -1)
+ return (NULL);
+
+ if (fill_newports((ipfw_insn_u16 *)cmd, av, proto, cblen)) {
/* XXX todo: check that we have a protocol with ports */
cmd->opcode = opcode;
return cmd;
@@ -2783,7 +3392,7 @@ add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode, int cblen)
}
static ipfw_insn *
-add_src(ipfw_insn *cmd, char *av, u_char proto, int cblen)
+add_src(ipfw_insn *cmd, char *av, u_char proto, int cblen, struct tidx *tstate)
{
struct in6_addr a;
char *host, *ch, buf[INET6_ADDRSTRLEN];
@@ -2806,7 +3415,7 @@ add_src(ipfw_insn *cmd, char *av, u_char proto, int cblen)
/* XXX: should check for IPv4, not !IPv6 */
if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 ||
inet_pton(AF_INET6, host, &a) != 1))
- ret = add_srcip(cmd, av, cblen);
+ ret = add_srcip(cmd, av, cblen, tstate);
if (ret == NULL && strcmp(av, "any") != 0)
ret = cmd;
@@ -2814,7 +3423,7 @@ add_src(ipfw_insn *cmd, char *av, u_char proto, int cblen)
}
static ipfw_insn *
-add_dst(ipfw_insn *cmd, char *av, u_char proto, int cblen)
+add_dst(ipfw_insn *cmd, char *av, u_char proto, int cblen, struct tidx *tstate)
{
struct in6_addr a;
char *host, *ch, buf[INET6_ADDRSTRLEN];
@@ -2837,7 +3446,7 @@ add_dst(ipfw_insn *cmd, char *av, u_char proto, int cblen)
/* XXX: should check for IPv4, not !IPv6 */
if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 ||
inet_pton(AF_INET6, host, &a) != 1))
- ret = add_dstip(cmd, av, cblen);
+ ret = add_dstip(cmd, av, cblen, tstate);
if (ret == NULL && strcmp(av, "any") != 0)
ret = cmd;
@@ -2857,7 +3466,7 @@ add_dst(ipfw_insn *cmd, char *av, u_char proto, int cblen)
*
*/
void
-ipfw_add(char *av[])
+compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate)
{
/*
* rules are added into the 'rulebuf' and then copied in
@@ -2865,13 +3474,13 @@ ipfw_add(char *av[])
* Some things that need to go out of order (prob, action etc.)
* go into actbuf[].
*/
- static uint32_t rulebuf[255], actbuf[255], cmdbuf[255];
+ static uint32_t actbuf[255], cmdbuf[255];
int rblen, ablen, cblen;
ipfw_insn *src, *dst, *cmd, *action, *prev=NULL;
ipfw_insn *first_cmd; /* first match pattern */
- struct ip_fw *rule;
+ struct ip_fw_rule *rule;
/*
* various flags used to record that we entered some fields.
@@ -2891,14 +3500,14 @@ ipfw_add(char *av[])
bzero(actbuf, sizeof(actbuf)); /* actions go here */
bzero(cmdbuf, sizeof(cmdbuf));
- bzero(rulebuf, sizeof(rulebuf));
+ bzero(rbuf, *rbufsize);
- rule = (struct ip_fw *)rulebuf;
+ rule = (struct ip_fw_rule *)rbuf;
cmd = (ipfw_insn *)cmdbuf;
action = (ipfw_insn *)actbuf;
- rblen = sizeof(rulebuf) / sizeof(rulebuf[0]);
- rblen -= offsetof(struct ip_fw, cmd) / sizeof(rulebuf[0]);
+ 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]);
cblen -= F_INSN_SIZE(ipfw_insn_u32) + 1;
@@ -2920,6 +3529,7 @@ ipfw_add(char *av[])
if (set < 0 || set > RESVD_SET)
errx(EX_DATAERR, "illegal set %s", av[1]);
rule->set = set;
+ tstate->set = set;
av += 2;
}
@@ -3029,7 +3639,7 @@ chkarg:
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);
@@ -3153,7 +3763,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,
@@ -3161,6 +3771,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;
@@ -3173,13 +3785,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;
}
@@ -3386,7 +4001,7 @@ chkarg:
OR_START(source_ip);
NOT_BLOCK; /* optional "not" */
NEED1("missing source address");
- if (add_src(cmd, *av, proto, cblen)) {
+ if (add_src(cmd, *av, proto, cblen, tstate)) {
av++;
if (F_LEN(cmd) != 0) { /* ! any */
prev = cmd;
@@ -3422,7 +4037,7 @@ chkarg:
OR_START(dest_ip);
NOT_BLOCK; /* optional "not" */
NEED1("missing dst address");
- if (add_dst(cmd, *av, proto, cblen)) {
+ if (add_dst(cmd, *av, proto, cblen, tstate)) {
av++;
if (F_LEN(cmd) != 0) { /* ! any */
prev = cmd;
@@ -3451,7 +4066,7 @@ read_options:
* nothing specified so far, store in the rule to ease
* printout later.
*/
- rule->_pad = 1;
+ rule->flags |= IPFW_RULE_NOOPT;
}
prev = NULL;
while ( av[0] != NULL ) {
@@ -3529,7 +4144,7 @@ read_options:
case TOK_VIA:
NEED1("recv, xmit, via require interface name"
" or address");
- fill_iface((ipfw_insn_if *)cmd, av[0], cblen);
+ fill_iface((ipfw_insn_if *)cmd, av[0], cblen, tstate);
av++;
if (F_LEN(cmd) == 0) /* not a valid address */
break;
@@ -3604,13 +4219,13 @@ read_options:
case TOK_IPOPTS:
NEED1("missing argument for ipoptions");
- fill_flags(cmd, O_IPOPT, f_ipopts, *av);
+ fill_flags_cmd(cmd, O_IPOPT, f_ipopts, *av);
av++;
break;
case TOK_IPTOS:
NEED1("missing argument for iptos");
- fill_flags(cmd, O_IPTOS, f_iptos, *av);
+ fill_flags_cmd(cmd, O_IPTOS, f_iptos, *av);
av++;
break;
@@ -3688,7 +4303,7 @@ read_options:
case TOK_TCPOPTS:
NEED1("missing argument for tcpoptions");
- fill_flags(cmd, O_TCPOPTS, f_tcpopts, *av);
+ fill_flags_cmd(cmd, O_TCPOPTS, f_tcpopts, *av);
av++;
break;
@@ -3715,7 +4330,7 @@ read_options:
case TOK_TCPFLAGS:
NEED1("missing argument for tcpflags");
cmd->opcode = O_TCPFLAGS;
- fill_flags(cmd, O_TCPFLAGS, f_tcpflags, *av);
+ fill_flags_cmd(cmd, O_TCPFLAGS, f_tcpflags, *av);
av++;
break;
@@ -3775,14 +4390,14 @@ read_options:
case TOK_SRCIP:
NEED1("missing source IP");
- if (add_srcip(cmd, *av, cblen)) {
+ if (add_srcip(cmd, *av, cblen, tstate)) {
av++;
}
break;
case TOK_DSTIP:
NEED1("missing destination IP");
- if (add_dstip(cmd, *av, cblen)) {
+ if (add_dstip(cmd, *av, cblen, tstate)) {
av++;
}
break;
@@ -3901,7 +4516,6 @@ read_options:
case TOK_LOOKUP: {
ipfw_insn_u32 *c = (ipfw_insn_u32 *)cmd;
- char *p;
int j;
if (!av[0] || !av[1])
@@ -3917,12 +4531,22 @@ read_options:
errx(EX_USAGE, "format: cannot lookup on %s", *av);
__PAST_END(c->d, 1) = j; // i converted to option
av++;
- cmd->arg1 = strtoul(*av, &p, 0);
- if (p && *p)
- errx(EX_USAGE, "format: lookup argument tablenum");
+
+ if ((j = pack_table(tstate, *av)) == 0)
+ errx(EX_DATAERR, "Invalid table name: %s", *av);
+
+ cmd->arg1 = j;
av++;
}
break;
+ case TOK_FLOW:
+ NEED1("missing table name");
+ if (strncmp(*av, "table(", 6) != 0)
+ errx(EX_DATAERR,
+ "enclose table name into \"table()\"");
+ fill_table(cmd, *av, O_IP_FLOW_LOOKUP, tstate);
+ av++;
+ break;
default:
errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s);
@@ -4024,34 +4648,143 @@ done:
}
rule->cmd_len = (uint32_t *)dst - (uint32_t *)(rule->cmd);
- i = (char *)dst - (char *)rule;
- if (do_cmd(IP_FW_ADD, rule, (uintptr_t)&i) == -1)
- err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD");
- if (!co.do_quiet)
- show_ipfw(rule, 0, 0);
+ *rbufsize = (char *)dst - (char *)rule;
+}
+
+/*
+ * Adds one or more rules to ipfw chain.
+ * Data layout:
+ * Request:
+ * [
+ * ip_fw3_opheader
+ * [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional *1)
+ * [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) [ ip_fw_rule ip_fw_insn ] x N ] (*2) (*3)
+ * ]
+ * Reply:
+ * [
+ * ip_fw3_opheader
+ * [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional)
+ * [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) [ ip_fw_rule ip_fw_insn ] x N ]
+ * ]
+ *
+ * Rules in reply are modified to store their actual ruleset number.
+ *
+ * (*1) TLVs inside IPFW_TLV_TBL_LIST needs to be sorted ascending
+ * accoring to their idx field and there has to be no duplicates.
+ * (*2) Numbered rules inside IPFW_TLV_RULE_LIST needs to be sorted ascending.
+ * (*3) Each ip_fw structure needs to be aligned to u64 boundary.
+ */
+void
+ipfw_add(char *av[])
+{
+ uint32_t rulebuf[1024];
+ int rbufsize, default_off, tlen, rlen;
+ size_t sz;
+ struct tidx ts;
+ struct ip_fw_rule *rule;
+ caddr_t tbuf;
+ ip_fw3_opheader *op3;
+ ipfw_obj_ctlv *ctlv, *tstate;
+
+ rbufsize = sizeof(rulebuf);
+ memset(rulebuf, 0, rbufsize);
+ memset(&ts, 0, sizeof(ts));
+
+ /* Optimize case with no tables */
+ default_off = sizeof(ipfw_obj_ctlv) + sizeof(ip_fw3_opheader);
+ op3 = (ip_fw3_opheader *)rulebuf;
+ ctlv = (ipfw_obj_ctlv *)(op3 + 1);
+ rule = (struct ip_fw_rule *)(ctlv + 1);
+ rbufsize -= default_off;
+
+ compile_rule(av, (uint32_t *)rule, &rbufsize, &ts);
+ /* Align rule size to u64 boundary */
+ rlen = roundup2(rbufsize, sizeof(uint64_t));
+
+ tbuf = NULL;
+ sz = 0;
+ tstate = NULL;
+ if (ts.count != 0) {
+ /* Some tables. We have to alloc more data */
+ tlen = ts.count * sizeof(ipfw_obj_ntlv);
+ sz = default_off + sizeof(ipfw_obj_ctlv) + tlen + rlen;
+
+ if ((tbuf = calloc(1, sz)) == NULL)
+ err(EX_UNAVAILABLE, "malloc() failed for IP_FW_ADD");
+ op3 = (ip_fw3_opheader *)tbuf;
+ /* Tables first */
+ ctlv = (ipfw_obj_ctlv *)(op3 + 1);
+ ctlv->head.type = IPFW_TLV_TBLNAME_LIST;
+ ctlv->head.length = sizeof(ipfw_obj_ctlv) + tlen;
+ ctlv->count = ts.count;
+ ctlv->objsize = sizeof(ipfw_obj_ntlv);
+ memcpy(ctlv + 1, ts.idx, tlen);
+ table_sort_ctlv(ctlv);
+ tstate = ctlv;
+ /* Rule next */
+ ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length);
+ ctlv->head.type = IPFW_TLV_RULE_LIST;
+ ctlv->head.length = sizeof(ipfw_obj_ctlv) + rlen;
+ ctlv->count = 1;
+ memcpy(ctlv + 1, rule, rbufsize);
+ } else {
+ /* Simply add header */
+ sz = rlen + default_off;
+ memset(ctlv, 0, sizeof(*ctlv));
+ ctlv->head.type = IPFW_TLV_RULE_LIST;
+ ctlv->head.length = sizeof(ipfw_obj_ctlv) + rlen;
+ ctlv->count = 1;
+ }
+
+ if (do_get3(IP_FW_XADD, op3, &sz) != 0)
+ err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_XADD");
+
+ if (!co.do_quiet) {
+ struct format_opts sfo;
+ struct buf_pr bp;
+ memset(&sfo, 0, sizeof(sfo));
+ sfo.tstate = tstate;
+ sfo.set_mask = (uint32_t)(-1);
+ bp_alloc(&bp, 4096);
+ show_static_rule(&co, &sfo, &bp, rule, NULL);
+ printf("%s", bp.buf);
+ bp_free(&bp);
+ }
+
+ if (tbuf != NULL)
+ free(tbuf);
+
+ if (ts.idx != NULL)
+ free(ts.idx);
}
/*
* clear the counters or the log counters.
+ * optname has the following values:
+ * 0 (zero both counters and logging)
+ * 1 (zero logging only)
*/
void
-ipfw_zero(int ac, char *av[], int optname /* 0 = IP_FW_ZERO, 1 = IP_FW_RESETLOG */)
+ipfw_zero(int ac, char *av[], int optname)
{
- uint32_t arg, saved_arg;
+ ipfw_range_tlv rt;
+ uint32_t arg;
int failed = EX_OK;
char const *errstr;
char const *name = optname ? "RESETLOG" : "ZERO";
- optname = optname ? IP_FW_RESETLOG : IP_FW_ZERO;
+ optname = optname ? IP_FW_XRESETLOG : IP_FW_XZERO;
+ memset(&rt, 0, sizeof(rt));
av++; ac--;
- if (!ac) {
+ if (ac == 0) {
/* clear all entries */
- if (do_cmd(optname, NULL, 0) < 0)
- err(EX_UNAVAILABLE, "setsockopt(IP_FW_%s)", name);
+ rt.flags = IPFW_RCFLAG_ALL;
+ if (do_range_cmd(optname, &rt) < 0)
+ err(EX_UNAVAILABLE, "setsockopt(IP_FW_X%s)", name);
if (!co.do_quiet)
- printf("%s.\n", optname == IP_FW_ZERO ?
+ printf("%s.\n", optname == IP_FW_XZERO ?
"Accounting cleared":"Logging counts reset");
return;
@@ -4064,22 +4797,28 @@ ipfw_zero(int ac, char *av[], int optname /* 0 = IP_FW_ZERO, 1 = IP_FW_RESETLOG
if (errstr)
errx(EX_DATAERR,
"invalid rule number %s\n", *av);
- saved_arg = arg;
- if (co.use_set)
- arg |= (1 << 24) | ((co.use_set - 1) << 16);
- av++;
- ac--;
- if (do_cmd(optname, &arg, sizeof(arg))) {
- warn("rule %u: setsockopt(IP_FW_%s)",
- saved_arg, name);
+ rt.start_rule = arg;
+ rt.end_rule = arg;
+ rt.flags |= IPFW_RCFLAG_RANGE;
+ if (co.use_set != 0) {
+ rt.set = co.use_set - 1;
+ rt.flags |= IPFW_RCFLAG_SET;
+ }
+ if (do_range_cmd(optname, &rt) != 0) {
+ warn("rule %u: setsockopt(IP_FW_X%s)",
+ arg, name);
+ failed = EX_UNAVAILABLE;
+ } else if (rt.new_set == 0) {
+ printf("Entry %d not found\n", arg);
failed = EX_UNAVAILABLE;
} else if (!co.do_quiet)
- printf("Entry %d %s.\n", saved_arg,
- optname == IP_FW_ZERO ?
+ printf("Entry %d %s.\n", arg,
+ optname == IP_FW_XZERO ?
"cleared" : "logging count reset");
} else {
errx(EX_USAGE, "invalid rule number ``%s''", *av);
}
+ av++; ac--;
}
if (failed != EX_OK)
exit(failed);
@@ -4088,7 +4827,7 @@ ipfw_zero(int ac, char *av[], int optname /* 0 = IP_FW_ZERO, 1 = IP_FW_RESETLOG
void
ipfw_flush(int force)
{
- int cmd = co.do_pipe ? IP_DUMMYNET_FLUSH : IP_FW_FLUSH;
+ ipfw_range_tlv rt;
if (!force && !co.do_quiet) { /* need to ask user */
int c;
@@ -4110,316 +4849,121 @@ ipfw_flush(int force)
return;
}
/* `ipfw set N flush` - is the same that `ipfw delete set N` */
- if (co.use_set) {
- uint32_t arg = ((co.use_set - 1) & 0xffff) | (1 << 24);
- if (do_cmd(IP_FW_DEL, &arg, sizeof(arg)) < 0)
- err(EX_UNAVAILABLE, "setsockopt(IP_FW_DEL)");
- } else if (do_cmd(cmd, NULL, 0) < 0)
- err(EX_UNAVAILABLE, "setsockopt(IP_%s_FLUSH)",
- co.do_pipe ? "DUMMYNET" : "FW");
+ memset(&rt, 0, sizeof(rt));
+ if (co.use_set != 0) {
+ rt.set = co.use_set - 1;
+ rt.flags = IPFW_RCFLAG_SET;
+ } else
+ rt.flags = IPFW_RCFLAG_ALL;
+ if (do_range_cmd(IP_FW_XDEL, &rt) != 0)
+ err(EX_UNAVAILABLE, "setsockopt(IP_FW_XDEL)");
if (!co.do_quiet)
printf("Flushed all %s.\n", co.do_pipe ? "pipes" : "rules");
}
+static struct _s_x intcmds[] = {
+ { "talist", TOK_TALIST },
+ { "iflist", TOK_IFLIST },
+ { "vlist", TOK_VLIST },
+ { NULL, 0 }
+};
-static void table_list(uint16_t num, int need_header);
-static void table_fill_xentry(char *arg, ipfw_table_xentry *xent);
-
-/*
- * Retrieve maximum number of tables supported by ipfw(4) module.
- */
-uint32_t
-ipfw_get_tables_max()
-{
- size_t len;
- uint32_t tables_max;
-
- if (ipfw_tables_max != 0)
- return (ipfw_tables_max);
-
- len = sizeof(tables_max);
- if (sysctlbyname("net.inet.ip.fw.tables_max", &tables_max, &len,
- NULL, 0) == -1) {
- if (co.test_only)
- tables_max = 128; /* Old conservative default */
- else
- errx(1, "Can't determine maximum number of ipfw tables."
- " Perhaps you forgot to load ipfw module?");
- }
-
- ipfw_tables_max = tables_max;
-
- return (ipfw_tables_max);
-}
-
-/*
- * This one handles all table-related commands
- * ipfw table N add addr[/masklen] [value]
- * ipfw table N delete addr[/masklen]
- * ipfw table {N | all} flush
- * ipfw table {N | all} list
- */
void
-ipfw_table_handler(int ac, char *av[])
+ipfw_internal_handler(int ac, char *av[])
{
- ipfw_table_xentry xent;
- int do_add;
- int is_all;
- uint32_t a;
- uint32_t tables_max;
+ int tcmd;
- tables_max = ipfw_get_tables_max();
+ ac--; av++;
+ NEED1("internal cmd required");
- memset(&xent, 0, sizeof(xent));
+ if ((tcmd = match_token(intcmds, *av)) == -1)
+ errx(EX_USAGE, "invalid internal sub-cmd: %s", *av);
- ac--; av++;
- if (ac && isdigit(**av)) {
- xent.tbl = atoi(*av);
- is_all = 0;
- ac--; av++;
- } else if (ac && _substrcmp(*av, "all") == 0) {
- xent.tbl = 0;
- is_all = 1;
- ac--; av++;
- } else
- errx(EX_USAGE, "table number or 'all' keyword required");
- if (xent.tbl >= tables_max)
- errx(EX_USAGE, "The table number exceeds the maximum allowed "
- "value (%d)", tables_max - 1);
- NEED1("table needs command");
- if (is_all && _substrcmp(*av, "list") != 0
- && _substrcmp(*av, "flush") != 0)
- errx(EX_USAGE, "table number required");
-
- if (_substrcmp(*av, "add") == 0 ||
- _substrcmp(*av, "delete") == 0) {
- do_add = **av == 'a';
- ac--; av++;
- if (!ac)
- errx(EX_USAGE, "address required");
-
- table_fill_xentry(*av, &xent);
-
- ac--; av++;
- if (do_add && ac) {
- unsigned int tval;
- /* isdigit is a bit of a hack here.. */
- if (strchr(*av, (int)'.') == NULL && isdigit(**av)) {
- xent.value = strtoul(*av, NULL, 0);
- } else {
- if (lookup_host(*av, (struct in_addr *)&tval) == 0) {
- /* The value must be stored in host order *
- * so that the values < 65k can be distinguished */
- xent.value = ntohl(tval);
- } else {
- errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
- }
- }
- } else
- xent.value = 0;
- if (do_setcmd3(do_add ? IP_FW_TABLE_XADD : IP_FW_TABLE_XDEL,
- &xent, xent.len) < 0) {
- /* If running silent, don't bomb out on these errors. */
- if (!(co.do_quiet && (errno == (do_add ? EEXIST : ESRCH))))
- err(EX_OSERR, "setsockopt(IP_FW_TABLE_%s)",
- do_add ? "XADD" : "XDEL");
- /* In silent mode, react to a failed add by deleting */
- if (do_add) {
- do_setcmd3(IP_FW_TABLE_XDEL, &xent, xent.len);
- if (do_setcmd3(IP_FW_TABLE_XADD, &xent, xent.len) < 0)
- err(EX_OSERR,
- "setsockopt(IP_FW_TABLE_XADD)");
- }
- }
- } else if (_substrcmp(*av, "flush") == 0) {
- a = is_all ? tables_max : (uint32_t)(xent.tbl + 1);
- do {
- if (do_cmd(IP_FW_TABLE_FLUSH, &xent.tbl,
- sizeof(xent.tbl)) < 0)
- err(EX_OSERR, "setsockopt(IP_FW_TABLE_FLUSH)");
- } while (++xent.tbl < a);
- } else if (_substrcmp(*av, "list") == 0) {
- a = is_all ? tables_max : (uint32_t)(xent.tbl + 1);
- do {
- table_list(xent.tbl, is_all);
- } while (++xent.tbl < a);
- } else
- errx(EX_USAGE, "invalid table command %s", *av);
+ switch (tcmd) {
+ case TOK_IFLIST:
+ ipfw_list_tifaces();
+ break;
+ case TOK_TALIST:
+ ipfw_list_ta(ac, av);
+ break;
+ case TOK_VLIST:
+ ipfw_list_values(ac, av);
+ break;
+ }
}
-static void
-table_fill_xentry(char *arg, ipfw_table_xentry *xent)
+static int
+ipfw_get_tracked_ifaces(ipfw_obj_lheader **polh)
{
- int addrlen, mask, masklen, type;
- struct in6_addr *paddr;
- uint32_t *pkey;
- char *p;
- uint32_t key;
-
- mask = 0;
- type = 0;
- addrlen = 0;
- masklen = 0;
-
- /*
- * Let's try to guess type by agrument.
- * Possible types:
- * 1) IPv4[/mask]
- * 2) IPv6[/mask]
- * 3) interface name
- * 4) port, uid/gid or other u32 key (base 10 format)
- * 5) hostname
- */
- paddr = &xent->k.addr6;
- if (ishexnumber(*arg) != 0 || *arg == ':') {
- /* Remove / if exists */
- if ((p = strchr(arg, '/')) != NULL) {
- *p = '\0';
- mask = atoi(p + 1);
- }
-
- if (inet_pton(AF_INET, arg, paddr) == 1) {
- if (p != NULL && mask > 32)
- errx(EX_DATAERR, "bad IPv4 mask width: %s",
- p + 1);
+ ipfw_obj_lheader req, *olh;
+ size_t sz;
- type = IPFW_TABLE_CIDR;
- masklen = p ? mask : 32;
- addrlen = sizeof(struct in_addr);
- } else if (inet_pton(AF_INET6, arg, paddr) == 1) {
- if (IN6_IS_ADDR_V4COMPAT(paddr))
- errx(EX_DATAERR,
- "Use IPv4 instead of v4-compatible");
- if (p != NULL && mask > 128)
- errx(EX_DATAERR, "bad IPv6 mask width: %s",
- p + 1);
-
- type = IPFW_TABLE_CIDR;
- masklen = p ? mask : 128;
- addrlen = sizeof(struct in6_addr);
- } else {
- /* Port or any other key */
- /* Skip non-base 10 entries like 'fa1' */
- key = strtol(arg, &p, 10);
- if (*p == '\0') {
- pkey = (uint32_t *)paddr;
- *pkey = htonl(key);
- type = IPFW_TABLE_CIDR;
- masklen = 32;
- addrlen = sizeof(uint32_t);
- } else if ((p != arg) && (*p == '.')) {
- /*
- * Warn on IPv4 address strings
- * which are "valid" for inet_aton() but not
- * in inet_pton().
- *
- * Typical examples: '10.5' or '10.0.0.05'
- */
- errx(EX_DATAERR,
- "Invalid IPv4 address: %s", arg);
- }
- }
- }
+ memset(&req, 0, sizeof(req));
+ sz = sizeof(req);
- if (type == 0 && strchr(arg, '.') == NULL) {
- /* Assume interface name. Copy significant data only */
- mask = MIN(strlen(arg), IF_NAMESIZE - 1);
- memcpy(xent->k.iface, arg, mask);
- /* Set mask to exact match */
- masklen = 8 * IF_NAMESIZE;
- type = IPFW_TABLE_INTERFACE;
- addrlen = IF_NAMESIZE;
+ if (do_get3(IP_FW_XIFLIST, &req.opheader, &sz) != 0) {
+ if (errno != ENOMEM)
+ return (errno);
}
- if (type == 0) {
- if (lookup_host(arg, (struct in_addr *)paddr) != 0)
- errx(EX_NOHOST, "hostname ``%s'' unknown", arg);
+ sz = req.size;
+ if ((olh = calloc(1, sz)) == NULL)
+ return (ENOMEM);
- masklen = 32;
- type = IPFW_TABLE_CIDR;
- addrlen = sizeof(struct in_addr);
+ olh->size = sz;
+ if (do_get3(IP_FW_XIFLIST, &olh->opheader, &sz) != 0) {
+ free(olh);
+ return (errno);
}
- xent->type = type;
- xent->masklen = masklen;
- xent->len = offsetof(ipfw_table_xentry, k) + addrlen;
+ *polh = olh;
+ return (0);
}
-static void
-table_list(uint16_t num, int need_header)
+static int
+ifinfo_cmp(const void *a, const void *b)
{
- ipfw_xtable *tbl;
- ipfw_table_xentry *xent;
- socklen_t l;
- uint32_t *a, sz, tval;
- char tbuf[128];
- struct in6_addr *addr6;
- ip_fw3_opheader *op3;
+ ipfw_iface_info *ia, *ib;
- /* Prepend value with IP_FW3 header */
- l = sizeof(ip_fw3_opheader) + sizeof(uint32_t);
- op3 = alloca(l);
- /* Zero reserved fields */
- memset(op3, 0, sizeof(ip_fw3_opheader));
- a = (uint32_t *)(op3 + 1);
- *a = num;
- op3->opcode = IP_FW_TABLE_XGETSIZE;
- if (do_cmd(IP_FW3, op3, (uintptr_t)&l) < 0)
- err(EX_OSERR, "getsockopt(IP_FW_TABLE_XGETSIZE)");
-
- /* If a is zero we have nothing to do, the table is empty. */
- if (*a == 0)
- return;
+ ia = (ipfw_iface_info *)a;
+ ib = (ipfw_iface_info *)b;
- l = *a;
- tbl = safe_calloc(1, l);
- tbl->opheader.opcode = IP_FW_TABLE_XLIST;
- tbl->tbl = num;
- if (do_cmd(IP_FW3, tbl, (uintptr_t)&l) < 0)
- err(EX_OSERR, "getsockopt(IP_FW_TABLE_XLIST)");
- if (tbl->cnt && need_header)
- printf("---table(%d)---\n", tbl->tbl);
- sz = tbl->size - sizeof(ipfw_xtable);
- xent = &tbl->xent[0];
- while (sz > 0) {
- switch (tbl->type) {
- case IPFW_TABLE_CIDR:
- /* IPv4 or IPv6 prefixes */
- tval = xent->value;
- addr6 = &xent->k.addr6;
+ return (stringnum_cmp(ia->ifname, ib->ifname));
+}
+/*
+ * Retrieves table list from kernel,
+ * optionally sorts it and calls requested function for each table.
+ * Returns 0 on success.
+ */
+static void
+ipfw_list_tifaces()
+{
+ ipfw_obj_lheader *olh;
+ ipfw_iface_info *info;
+ int i, error;
- if ((xent->flags & IPFW_TCF_INET) != 0) {
- /* IPv4 address */
- inet_ntop(AF_INET, &addr6->s6_addr32[3], tbuf, sizeof(tbuf));
- } else {
- /* IPv6 address */
- inet_ntop(AF_INET6, addr6, tbuf, sizeof(tbuf));
- }
+ if ((error = ipfw_get_tracked_ifaces(&olh)) != 0)
+ err(EX_OSERR, "Unable to request ipfw tracked interface list");
- if (co.do_value_as_ip) {
- tval = htonl(tval);
- printf("%s/%u %s\n", tbuf, xent->masklen,
- inet_ntoa(*(struct in_addr *)&tval));
- } else
- printf("%s/%u %u\n", tbuf, xent->masklen, tval);
- break;
- case IPFW_TABLE_INTERFACE:
- /* Interface names */
- tval = xent->value;
- if (co.do_value_as_ip) {
- tval = htonl(tval);
- printf("%s %s\n", xent->k.iface,
- inet_ntoa(*(struct in_addr *)&tval));
- } else
- printf("%s %u\n", xent->k.iface, tval);
- }
- if (sz < xent->len)
- break;
- sz -= xent->len;
- xent = (ipfw_table_xentry *)((char *)xent + xent->len);
+ qsort(olh + 1, olh->count, olh->objsize, ifinfo_cmp);
+
+ info = (ipfw_iface_info *)(olh + 1);
+ for (i = 0; i < olh->count; i++) {
+ if (info->flags & IPFW_IFFLAG_RESOLVED)
+ printf("%s ifindex: %d refcount: %u changes: %u\n",
+ info->ifname, info->ifindex, info->refcnt,
+ info->gencnt);
+ else
+ printf("%s ifindex: unresolved refcount: %u changes: %u\n",
+ info->ifname, info->refcnt, info->gencnt);
+ info = (ipfw_iface_info *)((caddr_t)info + olh->objsize);
}
- free(tbl);
+ free(olh);
}
+
+
+
+