Date: Sat, 28 Jun 2014 23:20:24 +0000 (UTC) From: "Alexander V. Chernikov" <melifaro@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r268009 - in projects/ipfw: sbin/ipfw sys/netinet sys/netpfil/ipfw Message-ID: <201406282320.s5SNKOGS036400@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: melifaro Date: Sat Jun 28 23:20:24 2014 New Revision: 268009 URL: http://svnweb.freebsd.org/changeset/base/268009 Log: Suppord showing named tables in ipfw(8) rule listing. Kernel changes: * change base TLV header to be u64 (so size can be u32). * Introduce ipfw_obj_ctlv generc container TLV. * Add IP_FW_XGET opcode which is now used for atomic configuration retrieval. One can specify needed configuration pieces to retrieve via flags field. Currently supported are IPFW_CFG_GET_STATIC (static rules) and IPFW_CFG_GET_STATES (dynamic states). Other configuration pieces (tables, pipes, etc..) support is planned. Userland changes: * Switch ipfw(8) to use new IP_FW_XGET for rule listing. * Split rule listing code get and show pieces. * Make several steps forward towards libipfw: permit printing states and rules(paritally) to supplied buffer. do not die on malloc/kernel failure inside given printing functions. stop assuming cmdline_opts is global symbol. Modified: projects/ipfw/sbin/ipfw/altq.c projects/ipfw/sbin/ipfw/dummynet.c projects/ipfw/sbin/ipfw/ipfw2.c projects/ipfw/sbin/ipfw/ipfw2.h projects/ipfw/sbin/ipfw/tables.c projects/ipfw/sys/netinet/ip_fw.h projects/ipfw/sys/netpfil/ipfw/ip_fw_dynamic.c projects/ipfw/sys/netpfil/ipfw/ip_fw_private.h projects/ipfw/sys/netpfil/ipfw/ip_fw_sockopt.c projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h Modified: projects/ipfw/sbin/ipfw/altq.c ============================================================================== --- projects/ipfw/sbin/ipfw/altq.c Sat Jun 28 21:47:15 2014 (r268008) +++ projects/ipfw/sbin/ipfw/altq.c Sat Jun 28 23:20:24 2014 (r268009) @@ -137,15 +137,15 @@ altq_qid_to_name(u_int32_t qid) } void -print_altq_cmd(ipfw_insn_altq *altqptr) +print_altq_cmd(struct buf_pr *bp, ipfw_insn_altq *altqptr) { if (altqptr) { const char *qname; qname = altq_qid_to_name(altqptr->qid); if (qname == NULL) - printf(" altq ?<%u>", altqptr->qid); + bprintf(bp, " altq ?<%u>", altqptr->qid); else - printf(" altq %s", qname); + bprintf(bp, " altq %s", qname); } } Modified: projects/ipfw/sbin/ipfw/dummynet.c ============================================================================== --- projects/ipfw/sbin/ipfw/dummynet.c Sat Jun 28 21:47:15 2014 (r268008) +++ projects/ipfw/sbin/ipfw/dummynet.c Sat Jun 28 23:20:24 2014 (r268009) @@ -174,48 +174,44 @@ print_header(struct ipfw_flow_id *id) } static void -list_flow(struct dn_flow *ni, int *print) +list_flow(struct buf_pr *bp, struct dn_flow *ni) { char buff[255]; struct protoent *pe = NULL; struct in_addr ina; struct ipfw_flow_id *id = &ni->fid; - if (*print) { - print_header(&ni->fid); - *print = 0; - } pe = getprotobynumber(id->proto); /* XXX: Should check for IPv4 flows */ - printf("%3u%c", (ni->oid.id) & 0xff, + bprintf(bp, "%3u%c", (ni->oid.id) & 0xff, id->extra ? '*' : ' '); if (!IS_IP6_FLOW_ID(id)) { if (pe) - printf("%-4s ", pe->p_name); + bprintf(bp, "%-4s ", pe->p_name); else - printf("%4u ", id->proto); + bprintf(bp, "%4u ", id->proto); ina.s_addr = htonl(id->src_ip); - printf("%15s/%-5d ", + bprintf(bp, "%15s/%-5d ", inet_ntoa(ina), id->src_port); ina.s_addr = htonl(id->dst_ip); - printf("%15s/%-5d ", + bprintf(bp, "%15s/%-5d ", inet_ntoa(ina), id->dst_port); } else { /* Print IPv6 flows */ if (pe != NULL) - printf("%9s ", pe->p_name); + bprintf(bp, "%9s ", pe->p_name); else - printf("%9u ", id->proto); - printf("%7d %39s/%-5d ", id->flow_id6, + bprintf(bp, "%9u ", id->proto); + bprintf(bp, "%7d %39s/%-5d ", id->flow_id6, inet_ntop(AF_INET6, &(id->src_ip6), buff, sizeof(buff)), id->src_port); - printf(" %39s/%-5d ", + bprintf(bp, " %39s/%-5d ", inet_ntop(AF_INET6, &(id->dst_ip6), buff, sizeof(buff)), id->dst_port); } - pr_u64(&ni->tot_pkts, 4); - pr_u64(&ni->tot_bytes, 8); - printf("%2u %4u %3u\n", + pr_u64(bp, &ni->tot_pkts, 4); + pr_u64(bp, &ni->tot_bytes, 8); + bprintf(bp, "%2u %4u %3u", ni->length, ni->len_bytes, ni->drops); } @@ -303,8 +299,10 @@ list_pipes(struct dn_id *oid, struct dn_ { char buf[160]; /* pending buffer */ int toPrint = 1; /* print header */ + struct buf_pr bp; buf[0] = '\0'; + bp_alloc(&bp, 4096); for (; oid != end; oid = O_NEXT(oid, oid->len)) { if (oid->len < sizeof(*oid)) errx(1, "invalid oid len %d\n", oid->len); @@ -346,7 +344,12 @@ list_pipes(struct dn_id *oid, struct dn_ break; case DN_FLOW: - list_flow((struct dn_flow *)oid, &toPrint); + if (toPrint != 0) { + print_header(&((struct dn_flow *)oid)->fid); + toPrint = 0; + } + list_flow(&bp, (struct dn_flow *)oid); + printf("%s\n", bp.buf); break; case DN_LINK: { @@ -384,6 +387,8 @@ list_pipes(struct dn_id *oid, struct dn_ } flush_buf(buf); // XXX does it really go here ? } + + bp_free(&bp); } /* Modified: projects/ipfw/sbin/ipfw/ipfw2.c ============================================================================== --- projects/ipfw/sbin/ipfw/ipfw2.c Sat Jun 28 21:47:15 2014 (r268008) +++ projects/ipfw/sbin/ipfw/ipfw2.c Sat Jun 28 23:20:24 2014 (r268009) @@ -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,6 +57,15 @@ struct cmdline_opts co; /* global options */ +struct format_opts { + int bcwidth; + int pcwidth; + int show_counters; + int first; + int last; + ipfw_obj_ctlv *tstate; +}; + int resvd_set_number = RESVD_SET; int ipfw_socket = -1; @@ -364,6 +374,102 @@ 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, uint32_t flags, + 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); + +/* + * 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_TABLEARG) + 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 @@ -371,7 +477,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" @@ -384,11 +490,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) { @@ -866,14 +973,14 @@ fill_reject_code(u_short *codep, char *s } 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); } /* @@ -937,7 +1044,7 @@ print_flags(char const *name, ipfw_insn * Print the ip address contained in a command. */ static void -print_ip(ipfw_insn_ip *cmd, char const *s) +print_ip(struct format_opts *fo, ipfw_insn_ip *cmd, char const *s) { struct hostent *he = NULL; uint32_t len = F_LEN((ipfw_insn *)cmd); @@ -961,7 +1068,9 @@ print_ip(ipfw_insn_ip *cmd, char const * } if (cmd->o.opcode == O_IP_SRC_LOOKUP || cmd->o.opcode == O_IP_DST_LOOKUP) { - printf("table(%u", ((ipfw_insn *)cmd)->arg1); + char *t; + t = table_search_ctlv(fo->tstate, ((ipfw_insn *)cmd)->arg1); + printf("table(%s", t); if (len == F_INSN_SIZE(ipfw_insn_u32)) printf(",%u", *a); printf(")"); @@ -1162,7 +1271,8 @@ show_prerequisites(int *flags, int 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) { static int twidth = 0; int l; @@ -1178,21 +1288,21 @@ show_ipfw(struct ip_fw *rule, int pcwidt bcopy(&rule->next_rule, &set_disable, sizeof(set_disable)); if (set_disable & (1 << rule->set)) { /* disabled */ - if (!co.show_sets) + 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); + if (fo->pcwidth > 0 || fo->bcwidth > 0) { + pr_u64(bp, &rule->pcnt, fo->pcwidth); + pr_u64(bp, &rule->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 ", rule->timestamp); + else if (co->do_time == 1) { char timestr[30]; time_t t = (time_t)0; @@ -1206,14 +1316,14 @@ show_ipfw(struct ip_fw *rule, int pcwidt 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" @@ -1225,7 +1335,7 @@ show_ipfw(struct ip_fw *rule, int pcwidt double d = 1.0 * p->d[0]; d = (d / 0x7fffffff); - printf("prob %f ", d); + bprintf(bp, "prob %f ", d); } } @@ -1236,66 +1346,66 @@ show_ipfw(struct ip_fw *rule, int pcwidt 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: @@ -1303,12 +1413,12 @@ show_ipfw(struct ip_fw *rule, int pcwidt 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; @@ -1317,10 +1427,10 @@ show_ipfw(struct ip_fw *rule, int pcwidt 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; @@ -1338,13 +1448,13 @@ show_ipfw(struct ip_fw *rule, int pcwidt 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); break; case O_SETDSCP: @@ -1352,47 +1462,53 @@ show_ipfw(struct ip_fw *rule, int pcwidt const char *code; if ((code = match_value(f_ipdscp, cmd->arg1)) != NULL) - printf("setdscp %s", code); + bprintf(bp, "setdscp %s", code); else - PRINT_UINT_ARG("setdscp ", cmd->arg1); + bprint_uint_arg(bp, "setdscp ", cmd->arg1); } 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); } /* + * TODO: convert remainings to use @bp buffer + * + */ + printf("%s", bp->buf); + + /* * then print the body. */ for (l = rule->act_ofs, cmd = rule->cmd ; @@ -1408,7 +1524,7 @@ show_ipfw(struct ip_fw *rule, int pcwidt } } if (rule->_pad & 1) { /* empty rules before options */ - if (!co.do_compact) { + if (!co->do_compact) { show_prerequisites(&flags, HAVE_PROTO, 0); printf(" from any to any"); } @@ -1416,7 +1532,7 @@ show_ipfw(struct ip_fw *rule, int pcwidt HAVE_SRCIP | HAVE_DSTIP; } - if (co.comment_only) + if (co->comment_only) comment = "..."; for (l = rule->act_ofs, cmd = rule->cmd ; @@ -1424,7 +1540,7 @@ show_ipfw(struct ip_fw *rule, int pcwidt /* 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)); @@ -1450,7 +1566,7 @@ show_ipfw(struct ip_fw *rule, int pcwidt printf(" from"); if ((cmd->len & F_OR) && !or_block) printf(" {"); - print_ip((ipfw_insn_ip *)cmd, + print_ip(fo, (ipfw_insn_ip *)cmd, (flags & HAVE_OPTIONS) ? " src-ip" : ""); flags |= HAVE_SRCIP; break; @@ -1465,7 +1581,7 @@ show_ipfw(struct ip_fw *rule, int pcwidt printf(" to"); if ((cmd->len & F_OR) && !or_block) printf(" {"); - print_ip((ipfw_insn_ip *)cmd, + print_ip(fo, (ipfw_insn_ip *)cmd, (flags & HAVE_OPTIONS) ? " dst-ip" : ""); flags |= HAVE_DSTIP; break; @@ -1610,7 +1726,7 @@ show_ipfw(struct ip_fw *rule, int pcwidt 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) @@ -1622,9 +1738,12 @@ show_ipfw(struct ip_fw *rule, int pcwidt if (cmdif->name[0] == '\0') printf(" %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 + else if (cmdif->name[0] == '\1') { + /* interface table */ + t = table_search_ctlv(fo->tstate, + cmdif->p.glob); + printf(" %s table(%s)", s, t); + } else printf(" %s %s", s, cmdif->name); break; @@ -1825,57 +1944,56 @@ show_ipfw(struct ip_fw *rule, int pcwidt } 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"); - - printf("\n"); + bprintf(bp, " UNKNOWN <-> UNKNOWN\n"); } /* @@ -2026,28 +2144,112 @@ ipfw_sysctl_handler(char *av[], int whic } } -void -ipfw_list(int ac, char *av[], int show_counters) +static void +prepare_format_opts(struct cmdline_opts *co, struct format_opts *fo, + struct ip_fw *r, ipfw_dyn_rule *d, int rcnt, int dcnt) { - struct ip_fw *r; - ipfw_dyn_rule *dynrules, *d; - + int bcwidth, pcwidth, width; + int n; + uint32_t set; #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; - int lac; - char **lav; - u_long rnum, last; - char *endptr; - int seen = 0; + + bcwidth = 0; + pcwidth = 0; + if (fo->show_counters != 0) { + for (n = 0; n < rcnt; 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(NULL, &r->pcnt, 0); + if (width > pcwidth) + pcwidth = width; + + /* byte counter */ + width = pr_u64(NULL, &r->bcnt, 0); + if (width > bcwidth) + bcwidth = width; + } + } + if (co->do_dynamic && dcnt > 0) { + for (n = 0; n < dcnt; 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(NULL, &d->pcnt, 0); + if (width > pcwidth) + pcwidth = width; + + width = pr_u64(NULL, &d->bcnt, 0); + if (width > bcwidth) + bcwidth = width; + } + } + + fo->bcwidth = bcwidth; + fo->pcwidth = pcwidth; +} + +static int +ipfw_list_static_range(struct cmdline_opts *co, struct format_opts *fo, + struct buf_pr *bp, struct ip_fw *r, int nstat) +{ + int n, seen; + + for (n = seen = 0; n < nstat; n++, r = NEXT(r) ) { + 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); + bp_flush(bp); + seen++; + } + } + + return (seen); +} + +static void +ipfw_list_dyn_range(struct cmdline_opts *co, struct format_opts *fo, + struct buf_pr *bp, ipfw_dyn_rule *d, int ndyn) +{ + int n; uint8_t set; + uint16_t rulenum; - const int ocmd = co.do_pipe ? IP_DUMMYNET_GET : IP_FW_GET; - int nalloc = 1024; /* start somewhere... */ + for (n = 0; n < ndyn; n++, d++) { + bcopy(&d->rule, &rulenum, sizeof(rulenum)); + if (rulenum > fo->last) + break; + if (co->use_set) { + bcopy((char *)&d->rule + sizeof(uint16_t), + &set, sizeof(uint8_t)); + if (set != co->use_set - 1) + continue; + } + if (rulenum >= fo->first) { + show_dyn_state(co, fo, bp, d); + printf("%s\n", bp->buf); + bp_flush(bp); + } + } +} - last = 0; +void +ipfw_list(int ac, char *av[], int show_counters) +{ + ipfw_cfg_lheader *cfg; + struct format_opts sfo; + size_t sz; + int error; + uint32_t flags; if (co.test_only) { fprintf(stderr, "Testing only, list disabled\n"); @@ -2061,119 +2263,108 @@ ipfw_list(int ac, char *av[], int show_c ac--; av++; - /* get rules or pipes from kernel, resizing array as necessary */ - nbytes = nalloc; + /* get configuraion from kernel */ + cfg = NULL; + flags = IPFW_CFG_GET_STATIC; + if (co.do_dynamic != 0) + flags |= IPFW_CFG_GET_STATES; + if ((error = ipfw_get_config(&co, flags, &cfg, &sz)) != 0) + err(EX_OSERR, "retrieving config failed"); + + memset(&sfo, 0, sizeof(sfo)); + sfo.show_counters = show_counters; + error = ipfw_show_config(&co, &sfo, cfg, sz, ac, av); - 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"); - } + free(cfg); - /* - * 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 */ + if (error != EX_OK) + exit(error); +#undef NEXT +} + +static int +ipfw_show_config(struct cmdline_opts *co, struct format_opts *fo, + ipfw_cfg_lheader *cfg, size_t sz, int ac, char *av[]) +{ + struct ip_fw *rbase; + ipfw_dyn_rule *dynbase; + int rcnt, dcnt; + int exitval = EX_OK; + int lac; + char **lav; + u_long rnum; + char *endptr; + size_t read; + struct buf_pr bp; + ipfw_obj_ctlv *ctlv, *tstate; /* - * 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; + tstate = NULL; + rbase = NULL; + dynbase = NULL; + read = 0; - /* packet counter */ - width = pr_u64(&r->pcnt, 0); - if (width > pcwidth) - pcwidth = width; + ctlv = (ipfw_obj_ctlv *)(cfg + 1); - /* byte counter */ - width = pr_u64(&r->bcnt, 0); - if (width > bcwidth) - bcwidth = width; + if (cfg->flags & IPFW_CFG_GET_STATIC) { + /* We've requested static rules */ + if (ctlv->head.type == IPFW_TLV_TBLNAME_LIST) { + fo->tstate = ctlv; + read += 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 (ctlv->head.type == IPFW_TLV_RULE_LIST) { + rbase = (struct ip_fw *)(ctlv + 1); + rcnt = ctlv->count; + read += ctlv->head.length; + ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + + ctlv->head.length); } } + + if ((cfg->flags & IPFW_CFG_GET_STATES) && (read != sz)) { + /* We may have some dynamic rules */ + read += sizeof(ipfw_obj_ctlv); + dcnt = ((sz - read) / ctlv->objsize); + if (dcnt != 0) + dynbase = (ipfw_dyn_rule *)(ctlv + 1); + } + + prepare_format_opts(co, fo, rbase, dynbase, rcnt, dcnt); + 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; + ipfw_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++) { *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201406282320.s5SNKOGS036400>