diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8 index 42656869eeb9..1845c68a9e6f 100644 --- a/sbin/ipfw/ipfw.8 +++ b/sbin/ipfw/ipfw.8 @@ -1,7 +1,7 @@ .\" .\" $FreeBSD$ .\" -.Dd December 1, 2003 +.Dd June 9, 2004 .Dt IPFW 8 .Os .Sh NAME @@ -43,6 +43,15 @@ .Cm set show .Pp .Nm +.Cm table Ar number Cm add Ar addr Ns Oo / Ns Ar masklen Oc Op Ar value +.Nm +.Cm table Ar number Cm delete Ar addr Ns Op / Ns Ar masklen +.Nm +.Cm table Ar number Cm flush +.Nm +.Cm table Ar number Cm list +.Pp +.Nm .Brq Cm pipe | queue .Ar number .Cm config @@ -758,13 +767,26 @@ The second format ( .Em or-block with multiple addresses) is provided for convenience only and its use is discouraged. -.It Ar addr : Oo Cm not Oc Brq Cm any | me | Ar addr-list | Ar addr-set +.It Ar addr : Oo Cm not Oc Bro +.Cm any | me | +.Cm table Ns Pq Ar number Ns Op , Ns Ar value +.Ar | addr-list | addr-set +.Brc .It Cm any matches any IP address. .It Cm me matches any IP address configured on an interface in the system. The address list is evaluated at the time the packet is analysed. +.It Cm table Ns Pq Ar number Ns Op , Ns Ar value +Matches any IP address for which an entry exists in the lookup table +.Ar number . +If an optional 32-bit unsigned +.Ar value +is also specified, an entry will match only if it has this value. +See the +.Sx LOOKUP TABLES +section below for more information on lookup tables. .It Ar addr-list : ip-addr Ns Op Ns , Ns Ar addr-list .It Ar ip-addr : A host or subnet address specified in one of the following ways: @@ -1248,6 +1270,43 @@ the Cisco IOS command: This option can be used to make anti-spoofing rules to reject all packets whose source address is unreachable. .El +.Sh LOOKUP TABLES +Lookup tables are useful to handle large sparse address sets, +typically from a hundred to several thousands of entries. +There could be 128 different lookup tables, numbered 0 to 127. +.Pp +Each entry is represented by an +.Ar addr Ns Op / Ns Ar masklen +and will match all addresses with base +.Ar addr +(specified as a dotted quad or a hostname) +and mask width of +.Ar masklen +bits. +If +.Ar masklen +is not specified, it defaults to 32. +When looking up an IP address in a table, the most specific +entry will match. +Associated with each entry is a 32-bit unsigned +.Ar value , +which can optionally be checked by a rule matching code. +When adding an entry, if +.Ar value +is not specified, it defaults to 0. +.Pp +An entry can be added to a table +.Pq Cm add , +removed from a table +.Pq Cm delete , +a table can be examined +.Pq Cm list +or flushed +.Pq Cm flush . +.Pp +Internally, each table is stored in a Radix tree, the same way as +the routing table (see +.Xr route 4 ) . .Sh SETS OF RULES Each rule belongs to one of 32 different .Em sets diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c index b2e4d107ee17..69561af8a1f3 100644 --- a/sbin/ipfw/ipfw2.c +++ b/sbin/ipfw/ipfw2.c @@ -385,7 +385,8 @@ do_cmd(int optname, void *optval, uintptr_t optlen) err(EX_UNAVAILABLE, "socket"); if (optname == IP_FW_GET || optname == IP_DUMMYNET_GET || - optname == IP_FW_ADD) + optname == IP_FW_ADD || optname == IP_FW_TABLE_LIST || + optname == IP_FW_TABLE_GETSIZE) i = getsockopt(s, IPPROTO_IP, optname, optval, (socklen_t *)optlen); else @@ -714,6 +715,14 @@ print_ip(ipfw_insn_ip *cmd, char const *s) printf("me"); return; } + if (cmd->o.opcode == O_IP_SRC_LOOKUP || + cmd->o.opcode == O_IP_DST_LOOKUP) { + printf("table(%u", ((ipfw_insn *)cmd)->arg1); + if (len == F_INSN_SIZE(ipfw_insn_u32)) + printf(",%u", *a); + printf(")"); + return; + } if (cmd->o.opcode == O_IP_SRC_SET || cmd->o.opcode == O_IP_DST_SET) { uint32_t x, *map = (uint32_t *)&(cmd->mask); int i, j; @@ -1088,6 +1097,7 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) break; case O_IP_SRC: + case O_IP_SRC_LOOKUP: case O_IP_SRC_MASK: case O_IP_SRC_ME: case O_IP_SRC_SET: @@ -1102,6 +1112,7 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) break; case O_IP_DST: + case O_IP_DST_LOOKUP: case O_IP_DST_MASK: case O_IP_DST_ME: case O_IP_DST_SET: @@ -1870,13 +1881,14 @@ help(void) "{pipe|queue} N config PIPE-BODY\n" "[pipe|queue] {zero|delete|show} [N{,N}]\n" "set [disable N... enable N...] | move [rule] X to Y | swap X Y | show\n" +"table N {add ip[/bits] [value] | delete ip[/bits] | flush | list}\n" "\n" "RULE-BODY: check-state [LOG] | ACTION [LOG] ADDR [OPTION_LIST]\n" "ACTION: check-state | allow | count | deny | reject | skipto N |\n" " {divert|tee} PORT | forward ADDR | pipe N | queue N\n" "ADDR: [ MAC dst src ether_type ] \n" " [ from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n" -"IPADDR: [not] { any | me | ip/bits{x,y,z} | IPLIST }\n" +"IPADDR: [not] { any | me | ip/bits{x,y,z} | table(t[,v]) | IPLIST }\n" "IPLIST: { ip | ip/bits | ip:mask }[,IPLIST]\n" "OPTION_LIST: OPTION [OPTION_LIST]\n" "OPTION: bridged | {dst-ip|src-ip} ADDR | {dst-port|src-port} LIST |\n" @@ -1932,6 +1944,21 @@ fill_ip(ipfw_insn_ip *cmd, char *av) return; } + if (!strncmp(av, "table(", 6)) { + char *p = strchr(av + 6, ','); + + if (p) + *p++ = '\0'; + cmd->o.opcode = O_IP_DST_LOOKUP; + cmd->o.arg1 = strtoul(av + 6, NULL, 0); + 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); + return; + } + while (av) { /* * After the address we can have '/' or ':' indicating a mask, @@ -2663,6 +2690,8 @@ add_srcip(ipfw_insn *cmd, char *av) fill_ip((ipfw_insn_ip *)cmd, av); if (cmd->opcode == O_IP_DST_SET) /* set */ cmd->opcode = O_IP_SRC_SET; + else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ + cmd->opcode = O_IP_SRC_LOOKUP; else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ cmd->opcode = O_IP_SRC_ME; else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ @@ -2678,6 +2707,8 @@ add_dstip(ipfw_insn *cmd, char *av) fill_ip((ipfw_insn_ip *)cmd, av); if (cmd->opcode == O_IP_DST_SET) /* set */ ; + else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ + ; else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ cmd->opcode = O_IP_DST_ME; else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ @@ -3592,6 +3623,79 @@ free_args(int ac, char **av) free(av); } +/* + * This one handles all table-related commands + * ipfw table N add addr[/masklen] [value] + * ipfw table N delete addr[/masklen] + * ipfw table N flush + * ipfw table N list + */ +static void +table_handler(int ac, char *av[]) +{ + ipfw_table_entry ent; + ipfw_table *tbl; + int do_add; + char *p; + socklen_t l; + uint32_t a; + + ac--; av++; + if (ac && isdigit(**av)) { + ent.tbl = atoi(*av); + ac--; av++; + } else + errx(EX_USAGE, "table number required"); + NEED1("table needs command"); + if (strncmp(*av, "add", strlen(*av)) == 0 || + strncmp(*av, "delete", strlen(*av)) == 0) { + do_add = **av == 'a'; + ac--; av++; + if (!ac) + errx(EX_USAGE, "IP address required"); + p = strchr(*av, '/'); + if (p) { + *p++ = '\0'; + ent.masklen = atoi(p); + if (ent.masklen > 32) + errx(EX_DATAERR, "bad width ``%s''", p); + } else + ent.masklen = 32; + if (lookup_host(*av, (struct in_addr *)&ent.addr) != 0) + errx(EX_NOHOST, "hostname ``%s'' unknown", av); + ac--; av++; + if (do_add && ac) + ent.value = strtoul(*av, NULL, 0); + else + ent.value = 0; + if (do_cmd(do_add ? IP_FW_TABLE_ADD : IP_FW_TABLE_DEL, + &ent, sizeof(ent)) < 0) + err(EX_OSERR, "setsockopt(IP_FW_TABLE_%s)", + do_add ? "ADD" : "DEL"); + } else if (strncmp(*av, "flush", strlen(*av)) == 0) { + if (do_cmd(IP_FW_TABLE_FLUSH, &ent.tbl, sizeof(ent.tbl)) < 0) + err(EX_OSERR, "setsockopt(IP_FW_TABLE_FLUSH)"); + } else if (strncmp(*av, "list", strlen(*av)) == 0) { + a = ent.tbl; + l = sizeof(a); + if (do_cmd(IP_FW_TABLE_GETSIZE, &a, (uintptr_t)&l) < 0) + err(EX_OSERR, "getsockopt(IP_FW_TABLE_GETSIZE)"); + l = sizeof(*tbl) + a * sizeof(ipfw_table_entry); + tbl = malloc(l); + if (tbl == NULL) + err(EX_OSERR, "malloc"); + tbl->tbl = ent.tbl; + if (do_cmd(IP_FW_TABLE_LIST, tbl, (uintptr_t)&l) < 0) + err(EX_OSERR, "getsockopt(IP_FW_TABLE_LIST)"); + for (a = 0; a < tbl->cnt; a++) { + printf("%s/%u %u\n", + inet_ntoa(*(struct in_addr *)&tbl->ent[a].addr), + tbl->ent[a].masklen, tbl->ent[a].value); + } + } else + errx(EX_USAGE, "invalid table command %s", *av); +} + /* * Called with the arguments (excluding program name). * Returns 0 if successful, 1 if empty command, errx() in case of errors. @@ -3822,6 +3926,8 @@ ipfw_main(int oldac, char **oldav) list(ac, av, do_acct); else if (!strncmp(*av, "set", strlen(*av))) sets_handler(ac, av); + else if (!strncmp(*av, "table", strlen(*av))) + table_handler(ac, av); else if (!strncmp(*av, "enable", strlen(*av))) sysctl_handler(ac, av, 1); else if (!strncmp(*av, "disable", strlen(*av))) diff --git a/sys/netinet/in.h b/sys/netinet/in.h index eb71af6a6c37..95c2fa3462a9 100644 --- a/sys/netinet/in.h +++ b/sys/netinet/in.h @@ -386,6 +386,12 @@ __END_DECLS #define IP_ONESBCAST 23 /* bool: send all-ones broadcast */ +#define IP_FW_TABLE_ADD 40 /* add entry */ +#define IP_FW_TABLE_DEL 41 /* delete entry */ +#define IP_FW_TABLE_FLUSH 42 /* flush table */ +#define IP_FW_TABLE_GETSIZE 43 /* get table size */ +#define IP_FW_TABLE_LIST 44 /* list table contents */ + #define IP_FW_ADD 50 /* add a firewall rule to chain */ #define IP_FW_DEL 51 /* delete a firewall rule from chain */ #define IP_FW_FLUSH 52 /* flush firewall rule chain */ diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index 7258b6c99931..d66335a07cb2 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -126,6 +126,8 @@ enum ipfw_opcodes { /* arguments (4 byte each) */ * More opcodes. */ O_IPSEC, /* has ipsec history */ + O_IP_SRC_LOOKUP, /* arg1=table number, u32=value */ + O_IP_DST_LOOKUP, /* arg1=table number, u32=value */ O_LAST_OPCODE /* not an opcode! */ }; @@ -375,6 +377,23 @@ struct _ipfw_dyn_rule { #define ICMP_REJECT_RST 0x100 /* fake ICMP code (send a TCP RST) */ +/* + * These are used for lookup tables. + */ +typedef struct _ipfw_table_entry { + in_addr_t addr; /* network address */ + u_int32_t value; /* value */ + u_int16_t tbl; /* table number */ + u_int8_t masklen; /* mask length */ +} ipfw_table_entry; + +typedef struct _ipfw_table { + u_int32_t size; /* size of entries in bytes */ + u_int32_t cnt; /* # of entries */ + u_int16_t tbl; /* table number */ + ipfw_table_entry ent[0]; /* entries */ +} ipfw_table; + /* * Main firewall chains definitions and global var's definitions. */ diff --git a/sys/netinet/ip_fw2.c b/sys/netinet/ip_fw2.c index ddccd485f613..a62bab4d211e 100644 --- a/sys/netinet/ip_fw2.c +++ b/sys/netinet/ip_fw2.c @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include @@ -131,6 +132,19 @@ struct ip_fw_chain { static struct ip_fw_chain layer3_chain; MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's"); +MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables"); + +struct table_entry { + struct radix_node rn[2]; + struct sockaddr_in addr, mask; + u_int32_t value; +}; + +#define IPFW_TABLES_MAX 128 +static struct { + struct radix_node_head *rnh; + int modified; +} ipfw_tables[IPFW_TABLES_MAX]; static int fw_debug = 1; static int autoinc_step = 100; /* bounded to 1..1000 in add_rule() */ @@ -1313,6 +1327,204 @@ lookup_next_rule(struct ip_fw *me) return rule; } +static void +init_tables(void) +{ + int i; + + for (i = 0; i < IPFW_TABLES_MAX; i++) { + rn_inithead((void **)&ipfw_tables[i].rnh, 32); + ipfw_tables[i].modified = 1; + } +} + +static int +add_table_entry(u_int16_t tbl, in_addr_t addr, u_int8_t mlen, u_int32_t value) +{ + struct radix_node_head *rnh; + struct table_entry *ent; + + if (tbl >= IPFW_TABLES_MAX) + return (EINVAL); + rnh = ipfw_tables[tbl].rnh; + ent = malloc(sizeof(*ent), M_IPFW_TBL, M_NOWAIT | M_ZERO); + if (ent == NULL) + return (ENOMEM); + ent->value = value; + ent->addr.sin_len = ent->mask.sin_len = 8; + ent->mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); + ent->addr.sin_addr.s_addr = addr & ent->mask.sin_addr.s_addr; + RADIX_NODE_HEAD_LOCK(rnh); + if (rnh->rnh_addaddr(&ent->addr, &ent->mask, rnh, (void *)ent) == + NULL) { + RADIX_NODE_HEAD_UNLOCK(rnh); + free(ent, M_IPFW_TBL); + return (EEXIST); + } + ipfw_tables[tbl].modified = 1; + RADIX_NODE_HEAD_UNLOCK(rnh); + return (0); +} + +static int +del_table_entry(u_int16_t tbl, in_addr_t addr, u_int8_t mlen) +{ + struct radix_node_head *rnh; + struct table_entry *ent; + struct sockaddr_in sa, mask; + + if (tbl >= IPFW_TABLES_MAX) + return (EINVAL); + rnh = ipfw_tables[tbl].rnh; + sa.sin_len = mask.sin_len = 8; + mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); + sa.sin_addr.s_addr = addr & mask.sin_addr.s_addr; + RADIX_NODE_HEAD_LOCK(rnh); + ent = (struct table_entry *)rnh->rnh_deladdr(&sa, &mask, rnh); + if (ent == NULL) { + RADIX_NODE_HEAD_UNLOCK(rnh); + return (ESRCH); + } + ipfw_tables[tbl].modified = 1; + RADIX_NODE_HEAD_UNLOCK(rnh); + free(ent, M_IPFW_TBL); + return (0); +} + +static int +flush_table_entry(struct radix_node *rn, void *arg) +{ + struct radix_node_head * const rnh = arg; + struct table_entry *ent; + + ent = (struct table_entry *) + rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh); + if (ent != NULL) + free(ent, M_IPFW_TBL); + return (0); +} + +static int +flush_table(u_int16_t tbl) +{ + struct radix_node_head *rnh; + + if (tbl >= IPFW_TABLES_MAX) + return (EINVAL); + rnh = ipfw_tables[tbl].rnh; + RADIX_NODE_HEAD_LOCK(rnh); + rnh->rnh_walktree(rnh, flush_table_entry, rnh); + ipfw_tables[tbl].modified = 1; + RADIX_NODE_HEAD_UNLOCK(rnh); + return (0); +} + +static void +flush_tables(void) +{ + u_int16_t tbl; + + for (tbl = 0; tbl < IPFW_TABLES_MAX; tbl++) + flush_table(tbl); +} + +static int +lookup_table(u_int16_t tbl, in_addr_t addr, u_int32_t *val) +{ + struct radix_node_head *rnh; + struct table_entry *ent; + struct sockaddr_in sa; + static in_addr_t last_addr; + static int last_tbl; + static int last_match; + static u_int32_t last_value; + + if (tbl >= IPFW_TABLES_MAX) + return (0); + if (tbl == last_tbl && addr == last_addr && + !ipfw_tables[tbl].modified) { + if (last_match) + *val = last_value; + return (last_match); + } + rnh = ipfw_tables[tbl].rnh; + sa.sin_len = 8; + sa.sin_addr.s_addr = addr; + RADIX_NODE_HEAD_LOCK(rnh); + ipfw_tables[tbl].modified = 0; + ent = (struct table_entry *)(rnh->rnh_lookup(&sa, NULL, rnh)); + RADIX_NODE_HEAD_UNLOCK(rnh); + last_addr = addr; + last_tbl = tbl; + if (ent != NULL) { + last_value = *val = ent->value; + last_match = 1; + return (1); + } + last_match = 0; + return (0); +} + +static int +count_table_entry(struct radix_node *rn, void *arg) +{ + u_int32_t * const cnt = arg; + + (*cnt)++; + return (0); +} + +static int +count_table(u_int32_t tbl, u_int32_t *cnt) +{ + struct radix_node_head *rnh; + + if (tbl >= IPFW_TABLES_MAX) + return (EINVAL); + rnh = ipfw_tables[tbl].rnh; + *cnt = 0; + RADIX_NODE_HEAD_LOCK(rnh); + rnh->rnh_walktree(rnh, count_table_entry, cnt); + RADIX_NODE_HEAD_UNLOCK(rnh); + return (0); +} + +static int +dump_table_entry(struct radix_node *rn, void *arg) +{ + struct table_entry * const n = (struct table_entry *)rn; + ipfw_table * const tbl = arg; + ipfw_table_entry *ent; + + if (tbl->cnt == tbl->size) + return (1); + ent = &tbl->ent[tbl->cnt]; + ent->tbl = tbl->tbl; + if (in_nullhost(n->mask.sin_addr)) + ent->masklen = 0; + else + ent->masklen = 33 - ffs(ntohl(n->mask.sin_addr.s_addr)); + ent->addr = n->addr.sin_addr.s_addr; + ent->value = n->value; + tbl->cnt++; + return (0); +} + +static int +dump_table(ipfw_table *tbl) +{ + struct radix_node_head *rnh; + + if (tbl->tbl >= IPFW_TABLES_MAX) + return (EINVAL); + rnh = ipfw_tables[tbl->tbl].rnh; + tbl->cnt = 0; + RADIX_NODE_HEAD_LOCK(rnh); + rnh->rnh_walktree(rnh, dump_table_entry, tbl); + RADIX_NODE_HEAD_UNLOCK(rnh); + return (0); +} + static int check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif, @@ -1751,6 +1963,23 @@ ipfw_chk(struct ip_fw_args *args) src_ip.s_addr); break; + case O_IP_SRC_LOOKUP: + case O_IP_DST_LOOKUP: + if (hlen > 0) { + uint32_t a = + (cmd->opcode == O_IP_DST_LOOKUP) ? + dst_ip.s_addr : src_ip.s_addr; + uint32_t v; + + match = lookup_table(cmd->arg1, a, &v); + if (!match) + break; + if (cmdlen == F_INSN_SIZE(ipfw_insn_u32)) + match = + ((ipfw_insn_u32 *)cmd)->d[0] == v; + } + break; + case O_IP_SRC_MASK: case O_IP_DST_MASK: if (hlen > 0) { @@ -2621,6 +2850,18 @@ check_ipfw_struct(struct ip_fw *rule, int size) goto bad_size; break; + case O_IP_SRC_LOOKUP: + case O_IP_DST_LOOKUP: + if (cmd->arg1 >= IPFW_TABLES_MAX) { + printf("ipfw: invalid table number %d\n", + cmd->arg1); + return (EINVAL); + } + if (cmdlen != F_INSN_SIZE(ipfw_insn) && + cmdlen != F_INSN_SIZE(ipfw_insn_u32)) + goto bad_size; + break; + case O_MACADDR2: if (cmdlen != F_INSN_SIZE(ipfw_insn_mac)) goto bad_size; @@ -2908,6 +3149,87 @@ ipfw_ctl(struct sockopt *sopt) sopt->sopt_name == IP_FW_RESETLOG); break; + case IP_FW_TABLE_ADD: + { + ipfw_table_entry ent; + + error = sooptcopyin(sopt, &ent, + sizeof(ent), sizeof(ent)); + if (error) + break; + error = add_table_entry(ent.tbl, ent.addr, + ent.masklen, ent.value); + } + break; + + case IP_FW_TABLE_DEL: + { + ipfw_table_entry ent; + + error = sooptcopyin(sopt, &ent, + sizeof(ent), sizeof(ent)); + if (error) + break; + error = del_table_entry(ent.tbl, ent.addr, ent.masklen); + } + break; + + case IP_FW_TABLE_FLUSH: + { + u_int16_t tbl; + + error = sooptcopyin(sopt, &tbl, + sizeof(tbl), sizeof(tbl)); + if (error) + break; + error = flush_table(tbl); + } + break; + + case IP_FW_TABLE_GETSIZE: + { + u_int32_t tbl, cnt; + + if ((error = sooptcopyin(sopt, &tbl, sizeof(tbl), + sizeof(tbl)))) + break; + if ((error = count_table(tbl, &cnt))) + break; + error = sooptcopyout(sopt, &cnt, sizeof(cnt)); + } + break; + + case IP_FW_TABLE_LIST: + { + ipfw_table *tbl; + + if (sopt->sopt_valsize < sizeof(*tbl)) { + error = EINVAL; + break; + } + size = sopt->sopt_valsize; + tbl = malloc(size, M_TEMP, M_WAITOK); + if (tbl == NULL) { + error = ENOMEM; + break; + } + error = sooptcopyin(sopt, tbl, size, sizeof(*tbl)); + if (error) { + free(tbl, M_TEMP); + break; + } + tbl->size = (size - sizeof(*tbl)) / + sizeof(ipfw_table_entry); + error = dump_table(tbl); + if (error) { + free(tbl, M_TEMP); + break; + } + error = sooptcopyout(sopt, tbl, size); + free(tbl, M_TEMP); + } + break; + default: printf("ipfw: ipfw_ctl invalid option %d\n", sopt->sopt_name); error = EINVAL; @@ -2972,6 +3294,7 @@ ipfw_init(void) layer3_chain.rules = NULL; IPFW_LOCK_INIT(&layer3_chain); IPFW_DYN_LOCK_INIT(); + init_tables(); callout_init(&ipfw_timeout, debug_mpsafenet ? CALLOUT_MPSAFE : 0); bzero(&default_rule, sizeof default_rule); @@ -3043,7 +3366,7 @@ ipfw_destroy(void) IPFW_UNLOCK(&layer3_chain); if (reap != NULL) reap_rules(reap); - + flush_tables(); IPFW_DYN_LOCK_DESTROY(); IPFW_LOCK_DESTROY(&layer3_chain); printf("IP firewall unloaded\n"); diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index 7cf1fea0bc5b..85eaaf2c3649 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -357,6 +357,8 @@ rip_ctloutput(struct socket *so, struct sockopt *sopt) case IP_FW_ADD: /* ADD actually returns the body... */ case IP_FW_GET: + case IP_FW_TABLE_GETSIZE: + case IP_FW_TABLE_LIST: if (IPFW_LOADED) error = ip_fw_ctl_ptr(sopt); else @@ -410,6 +412,9 @@ rip_ctloutput(struct socket *so, struct sockopt *sopt) case IP_FW_FLUSH: case IP_FW_ZERO: case IP_FW_RESETLOG: + case IP_FW_TABLE_ADD: + case IP_FW_TABLE_DEL: + case IP_FW_TABLE_FLUSH: if (IPFW_LOADED) error = ip_fw_ctl_ptr(sopt); else