ipfw3_nat: highspeed lockless in-kernel NAT
authorBill Yuan <bycn82@dragonflybsd.org>
Sat, 12 May 2018 15:26:07 +0000 (15:26 +0000)
committerBill Yuan <bycn82@dragonflybsd.org>
Sat, 12 May 2018 15:29:53 +0000 (15:29 +0000)
RB-Tree to stored the state for the outgoing packets, and multidimentional
array of pointers to keep the state for the incoming packets.

56 files changed:
lib/libipfw3/basic/ipfw3_basic.c
lib/libipfw3/basic/ipfw3_basic.h
lib/libipfw3/dummynet/ipfw3_dummynet.c
lib/libipfw3/dummynet/ipfw3_dummynet.h
lib/libipfw3/layer2/ipfw3_layer2.c
lib/libipfw3/layer2/ipfw3_layer2.h
lib/libipfw3/layer4/ipfw3_layer4.c
lib/libipfw3/layer4/ipfw3_layer4.h
lib/libipfw3/nat/ipfw3_nat.c
lib/libipfw3/nat/ipfw3_nat.h
sbin/ipfw3/Makefile
sbin/ipfw3/ipfw3.c
sbin/ipfw3/ipfw3.h
sbin/ipfw3/ipfw3basic.c [new file with mode: 0644]
sbin/ipfw3/ipfw3basic.h [copied from lib/libipfw3/nat/ipfw3_nat.h with 82% similarity]
sbin/ipfw3/ipfw3dummynet.c [new file with mode: 0644]
sbin/ipfw3/ipfw3dummynet.h [copied from lib/libipfw3/nat/ipfw3_nat.h with 75% similarity]
sbin/ipfw3/ipfw3log.c [new file with mode: 0644]
sbin/ipfw3/ipfw3log.h [copied from lib/libipfw3/nat/ipfw3_nat.h with 90% similarity]
sbin/ipfw3/ipfw3nat.c
sbin/ipfw3/ipfw3set.c [new file with mode: 0644]
sbin/ipfw3/ipfw3set.h [copied from lib/libipfw3/dummynet/ipfw3_dummynet.h with 80% similarity]
sbin/ipfw3/ipfw3state.c [copied from sbin/ipfw3/ipfw3nat.c with 54% similarity]
sbin/ipfw3/ipfw3state.h [copied from lib/libipfw3/nat/ipfw3_nat.h with 82% similarity]
sbin/ipfw3/ipfw3sync.c
sbin/ipfw3/ipfw3sync.h
sbin/ipfw3/ipfw3table.c [new file with mode: 0644]
sbin/ipfw3/ipfw3table.h [copied from lib/libipfw3/nat/ipfw3_nat.h with 75% similarity]
sys/net/dummynet3/Makefile
sys/net/dummynet3/ip_dummynet3.c
sys/net/ipfw3/Makefile
sys/net/ipfw3/ip_fw3.c
sys/net/ipfw3/ip_fw3.h
sys/net/ipfw3/ip_fw3_glue.c
sys/net/ipfw3/ip_fw3_set.c [new file with mode: 0644]
sys/net/ipfw3/ip_fw3_set.h [copied from sys/net/ipfw3_layer4/ip_fw3_layer4.h with 70% similarity]
sys/net/ipfw3_basic/Makefile
sys/net/ipfw3_basic/ip_fw3_basic.c
sys/net/ipfw3_basic/ip_fw3_basic.h
sys/net/ipfw3_basic/ip_fw3_log.c [moved from sys/net/ipfw3/ip_fw3_log.c with 80% similarity]
sys/net/ipfw3_basic/ip_fw3_log.h [moved from sys/net/ipfw3/ip_fw3_log.h with 90% similarity]
sys/net/ipfw3_basic/ip_fw3_state.c [new file with mode: 0644]
sys/net/ipfw3_basic/ip_fw3_state.h [new file with mode: 0644]
sys/net/ipfw3_basic/ip_fw3_sync.c [moved from sys/net/ipfw3/ip_fw3_sync.c with 63% similarity]
sys/net/ipfw3_basic/ip_fw3_sync.h [moved from sys/net/ipfw3/ip_fw3_sync.h with 61% similarity]
sys/net/ipfw3_basic/ip_fw3_table.c [moved from sys/net/ipfw3/ip_fw3_table.c with 88% similarity]
sys/net/ipfw3_basic/ip_fw3_table.h [moved from sys/net/ipfw3/ip_fw3_table.h with 83% similarity]
sys/net/ipfw3_layer2/Makefile
sys/net/ipfw3_layer2/ip_fw3_layer2.c
sys/net/ipfw3_layer2/ip_fw3_layer2.h
sys/net/ipfw3_layer4/Makefile
sys/net/ipfw3_layer4/ip_fw3_layer4.c
sys/net/ipfw3_layer4/ip_fw3_layer4.h
sys/net/ipfw3_nat/Makefile
sys/net/ipfw3_nat/ip_fw3_nat.c
sys/net/ipfw3_nat/ip_fw3_nat.h

index b79faf9..852d76f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2014 - 2018 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
  * by Bill Yuan <bycn82@dragonflybsd.org>
index 8a04278..79594eb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2014 -2018 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
  * by Bill Yuan <bycn82@dragonflybsd.org>
@@ -32,8 +32,8 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _IPFW_BASIC_H
-#define _IPFW_BASIC_H
+#ifndef _IPFW3_BASIC_H
+#define _IPFW3_BASIC_H
 
 #include <net/ipfw3_basic/ip_fw3_basic.h>
 
index 4090a65..27a3bea 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2014 -2018 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
  * by Bill Yuan <bycn82@dragonflybsd.org>
index 99eb9e1..a956a68 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2014 - 2018 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
  * by Bill Yuan <bycn82@dragonflybsd.org>
@@ -32,8 +32,8 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _IPFW_DUMMYNET_H
-#define _IPFW_DUMMYNET_H
+#ifndef _IPFW3_DUMMYNET_H
+#define _IPFW3_DUMMYNET_H
 
 #include <net/dummynet3/ip_dummynet3.h>
 
index 544de65..022f9a0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2014 - 2018 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
  * by Bill Yuan <bycn82@dragonflybsd.org>
index 5d605ed..4fdf1ee 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2014 -2018 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
  * by Bill Yuan <bycn82@dragonflybsd.org>
@@ -32,8 +32,8 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _IPFW_LAYER2_H
-#define _IPFW_LAYER2_H
+#ifndef _IPFW3_LAYER2_H
+#define _IPFW3_LAYER2_H
 
 #include <net/ipfw3_layer2/ip_fw3_layer2.h>
 
index 18b7f99..d376716 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2014 - 2018 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
  * by Bill Yuan <bycn82@dragonflybsd.org>
index 60224ee..8484a99 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2014 - 2018 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
  * by Bill Yuan <bycn82@dragonflybsd.org>
@@ -32,8 +32,8 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _IPFW_LAYER4_H
-#define _IPFW_LAYER4_H
+#ifndef _IPFW3_LAYER4_H
+#define _IPFW3_LAYER4_H
 
 #include <net/ipfw3_layer4/ip_fw3_layer4.h>
 
index d694991..293db4c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 - 2016 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2014 - 2018 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
  * by Bill Yuan <bycn82@dragonflybsd.org>
index 938e970..0b1454f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 - 2016 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2014 - 2018 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
  * by Bill Yuan <bycn82@dragonflybsd.org>
@@ -32,8 +32,8 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _IPFW_NAT_H
-#define _IPFW_NAT_H
+#ifndef _IPFW3_NAT_H
+#define _IPFW3_NAT_H
 
 #include <net/ipfw3_nat/ip_fw3_nat.h>
 
index d9aa998..4cf6d55 100644 (file)
@@ -3,7 +3,13 @@
 PROG = ipfw3
 MAN =  ipfw3.8
 SRCS = ipfw3.c
+SRCS += ipfw3basic.c ipfw3basic.h
+SRCS += ipfw3set.c ipfw3set.h
+SRCS += ipfw3log.c ipfw3log.h
 SRCS += ipfw3sync.c ipfw3sync.h
+SRCS += ipfw3state.c ipfw3state.h
+SRCS += ipfw3table.c ipfw3table.h
+SRCS += ipfw3dummynet.c ipfw3dummynet.h
 SRCS += ipfw3nat.c ipfw3nat.h
 WARNS?=        2
 
index f4bce50..d1e10e1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 - 2016 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2014 - 2018 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
  * by Bill Yuan <bycn82@dragonflybsd.org>
 
 
 #include <net/ipfw3/ip_fw3.h>
-#include <net/ipfw3/ip_fw3_table.h>
-#include <net/ipfw3/ip_fw3_sync.h>
-#include <net/dummynet3/ip_dummynet3.h>
+#include <net/ipfw3_basic/ip_fw3_table.h>
+#include <net/ipfw3_basic/ip_fw3_state.h>
+#include <net/ipfw3_basic/ip_fw3_sync.h>
 #include <net/ipfw3_basic/ip_fw3_basic.h>
 #include <net/ipfw3_nat/ip_fw3_nat.h>
+#include <net/dummynet3/ip_dummynet3.h>
 
 #include "ipfw3.h"
+#include "ipfw3basic.h"
+#include "ipfw3log.h"
+#include "ipfw3set.h"
+#include "ipfw3table.h"
+#include "ipfw3dummynet.h"
+#include "ipfw3state.h"
 #include "ipfw3sync.h"
 #include "ipfw3nat.h"
 
-
-#define KEYWORD_SIZE   256
-#define MAPPING_SIZE   256
-
-#define MAX_KEYWORD_LEN        20
 #define MAX_ARGS       32
 #define WHITESP                " \t\f\v\n\r"
-#define IPFW_LIB_PATH  "/usr/lib/libipfw3%s.so"
+#define IPFW3_LIB_PATH "/usr/lib/libipfw3%s.so"
 
-int            ipfw_socket = -1;       /* main RAW socket */
-int            do_resolv,              /* Would try to resolve all */
-               do_acct,                /* Show packet/byte count */
+int            fw3_socket = -1;        /* main RAW socket */
+int            do_acct,                /* Show packet/byte count */
                do_time,                /* Show time stamps */
                do_quiet = 1,           /* Be quiet , default is quiet*/
                do_force,               /* Don't ask for confirmation */
                do_pipe,                /* this cmd refers to a pipe */
                do_nat,                 /* Nat configuration. */
                do_sort,                /* field to sort results (0 = no) */
-               do_dynamic,             /* display dynamic rules */
                do_expired,             /* display expired dynamic rules */
                do_compact,             /* show rules in compact mode */
                show_sets,              /* display rule sets */
                verbose;
 
-struct char_int_map dummynet_params[] = {
-       { "plr",                TOK_PLR },
-       { "noerror",            TOK_NOERROR },
-       { "buckets",            TOK_BUCKETS },
-       { "dst-ip",             TOK_DSTIP },
-       { "src-ip",             TOK_SRCIP },
-       { "dst-port",           TOK_DSTPORT },
-       { "src-port",           TOK_SRCPORT },
-       { "proto",              TOK_PROTO },
-       { "weight",             TOK_WEIGHT },
-       { "all",                TOK_ALL },
-       { "mask",               TOK_MASK },
-       { "droptail",           TOK_DROPTAIL },
-       { "red",                TOK_RED },
-       { "gred",               TOK_GRED },
-       { "bw",                 TOK_BW },
-       { "bandwidth",          TOK_BW },
-       { "delay",              TOK_DELAY },
-       { "pipe",               TOK_PIPE },
-       { "queue",              TOK_QUEUE },
-       { "dummynet-params",    TOK_NULL },
-       { NULL, 0 }
-};
-
-struct ipfw_keyword {
-       int type;
-       char word[MAX_KEYWORD_LEN];
-       int module;
-       int opcode;
-};
-
-struct ipfw_mapping {
-       int type;
-       int module;
-       int opcode;
-       parser_func parser;
-       shower_func shower;
-};
-
-struct ipfw_keyword keywords[KEYWORD_SIZE];
-struct ipfw_mapping mappings[MAPPING_SIZE];
+struct ipfw3_keyword keywords[KEYWORD_SIZE];
+struct ipfw3_mapping mappings[MAPPING_SIZE];
 
 int
 match_token(struct char_int_map *table, char *string)
@@ -149,78 +110,27 @@ match_token(struct char_int_map *table, char *string)
        return 0;
 }
 
-static void
-get_modules(char *modules_str, int len)
+void
+module_get(char *modules_str, int len)
 {
        if (do_get_x(IP_FW_MODULE, modules_str, &len) < 0)
                errx(EX_USAGE, "ipfw3 not loaded.");
 }
 
-static void
-list_modules(int ac, char *av[])
+void
+module_list(int ac, char *av[])
 {
        void *module_str = NULL;
        int len = 1024;
        if ((module_str = realloc(module_str, len)) == NULL)
                err(EX_OSERR, "realloc");
 
-       get_modules(module_str, len);
+       module_get(module_str, len);
        printf("%s\n", (char *)module_str);
 }
-void
-parse_accept(ipfw_insn **cmd, int *ac, char **av[])
-{
-       (*cmd)->opcode = O_BASIC_ACCEPT;
-       (*cmd)->module = MODULE_BASIC_ID;
-       (*cmd)->len = (*cmd)->len|LEN_OF_IPFWINSN;
-       NEXT_ARG1;
-       if (!strncmp(**av, "log", strlen(**av))) {
-               (*cmd)->arg3 = 1;
-               NEXT_ARG1;
-               if (isdigit(***av)) {
-                       (*cmd)->arg1 = strtoul(**av, NULL, 10);
-                       NEXT_ARG1;
-               }
-       }
-}
-
-void
-parse_deny(ipfw_insn **cmd, int *ac, char **av[])
-{
-       (*cmd)->opcode = O_BASIC_DENY;
-       (*cmd)->module = MODULE_BASIC_ID;
-       (*cmd)->len = (*cmd)->len|LEN_OF_IPFWINSN;
-       NEXT_ARG1;
-       if (!strncmp(**av, "log", strlen(**av))) {
-               (*cmd)->arg3 = 1;
-               NEXT_ARG1;
-               if (isdigit(***av)) {
-                       (*cmd)->arg1 = strtoul(**av, NULL, 10);
-                       NEXT_ARG1;
-               }
-       }
-}
-
-void
-show_accept(ipfw_insn *cmd, int show_or)
-{
-       printf(" allow");
-       if (cmd->arg3) {
-               printf(" log %d", cmd->arg1);
-       }
-}
 
 void
-show_deny(ipfw_insn *cmd, int show_or)
-{
-       printf(" deny");
-       if (cmd->arg3) {
-               printf(" log %d", cmd->arg1);
-       }
-}
-
-static void
-load_modules(void)
+module_load(void)
 {
        const char *error;
        init_module mod_init_func;
@@ -232,13 +142,13 @@ load_modules(void)
        if ((module_str = realloc(module_str, len)) == NULL)
                err(EX_OSERR, "realloc");
 
-       get_modules(module_str, len);
+       module_get(module_str, len);
 
        const char s[2] = ",";
        char *token;
        token = strtok(module_str, s);
        while (token != NULL) {
-               sprintf(module_lib_file, IPFW_LIB_PATH, token);
+               sprintf(module_lib_file, IPFW3_LIB_PATH, token);
                token = strtok(NULL, s);
                module_lib = dlopen(module_lib_file, RTLD_LAZY);
                if (!module_lib) {
@@ -257,25 +167,10 @@ load_modules(void)
        }
 }
 
-void
-prepare_default_funcs(void)
-{
-       /* register allow */
-       register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_ACCEPT, "allow", ACTION);
-       register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_ACCEPT, "accept", ACTION);
-       register_ipfw_func(MODULE_BASIC_ID, O_BASIC_ACCEPT,
-                       (parser_func)parse_accept, (shower_func)show_accept);
-       /* register deny */
-       register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_DENY, "deny", ACTION);
-       register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_DENY, "reject", ACTION);
-       register_ipfw_func(MODULE_BASIC_ID, O_BASIC_DENY,
-                       (parser_func)parse_deny, (shower_func)show_deny);
-}
-
 void
 register_ipfw_keyword(int module, int opcode, char *word, int type)
 {
-       struct ipfw_keyword *tmp;
+       struct ipfw3_keyword *tmp;
 
        tmp=keywords;
        for (;;) {
@@ -297,7 +192,7 @@ register_ipfw_keyword(int module, int opcode, char *word, int type)
 void
 register_ipfw_func(int module, int opcode, parser_func parser, shower_func shower)
 {
-       struct ipfw_mapping *tmp;
+       struct ipfw3_mapping *tmp;
 
        tmp = mappings;
        while (1) {
@@ -364,8 +259,8 @@ void prev_show_chk(ipfw_insn *cmd, uint8_t *prev_module, uint8_t *prev_opcode,
  */
 int show_filter(ipfw_insn *cmd, char *word, int type)
 {
-       struct ipfw_keyword *k;
-       struct ipfw_mapping *m;
+       struct ipfw3_keyword *k;
+       struct ipfw3_mapping *m;
        shower_func fn;
        int i, j, show_or;
        uint8_t prev_module, prev_opcode;
@@ -396,1555 +291,43 @@ int show_filter(ipfw_insn *cmd, char *word, int type)
        return 0;
 }
 
-static void
-show_rules(struct ipfw_ioc_rule *rule, int pcwidth, int bcwidth)
-{
-       static int twidth = 0;
-       ipfw_insn *cmd;
-       int l;
-
-       u_int32_t set_disable = rule->set_disable;
-
-       if (set_disable & (1 << rule->set)) { /* disabled */
-               if (!show_sets)
-                       return;
-               else
-                       printf("# DISABLED ");
-       }
-       printf("%05u ", rule->rulenum);
-
-       if (do_acct)
-               printf("%*ju %*ju ", pcwidth, (uintmax_t)rule->pcnt, bcwidth,
-                       (uintmax_t)rule->bcnt);
-
-       if (do_time == 1) {
-               char timestr[30];
-
-               if (twidth == 0) {
-                       strcpy(timestr, ctime((time_t *)&twidth));
-                       *strchr(timestr, '\n') = '\0';
-                       twidth = strlen(timestr);
-               }
-               if (rule->timestamp) {
-                       time_t t = _long_to_time(rule->timestamp);
-
-                       strcpy(timestr, ctime(&t));
-                       *strchr(timestr, '\n') = '\0';
-                       printf("%s ", timestr);
-               } else {
-                       printf("%*s ", twidth, " ");
-               }
-       } else if (do_time == 2) {
-               printf( "%10u ", rule->timestamp);
-       }
-
-       if (show_sets)
-               printf("set %d ", rule->set);
-
-
-       struct ipfw_keyword *k;
-       struct ipfw_mapping *m;
-       shower_func fn, comment_fn = NULL;
-       ipfw_insn *comment_cmd;
-       int i, j, changed;
-
-       /*
-        * show others and actions
-        */
-       for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule);
-               l > 0; l -= F_LEN(cmd),
-               cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
-               k = keywords;
-               m = mappings;
-               for (i = 1; i< KEYWORD_SIZE; i++, k++) {
-                       if ( k->module == cmd->module && k->opcode == cmd->opcode ) {
-                               for (j = 1; j< MAPPING_SIZE; j++, m++) {
-                                       if (m->type == IN_USE &&
-                                               m->module == cmd->module &&
-                                               m->opcode == cmd->opcode) {
-                                               if (cmd->module == MODULE_BASIC_ID &&
-                                                       cmd->opcode == O_BASIC_COMMENT) {
-                                                       comment_fn = m->shower;
-                                                       comment_cmd = cmd;
-                                               } else {
-                                                       fn = m->shower;
-                                                       (*fn)(cmd, 0);
-                                               }
-                                               if (cmd->module == MODULE_BASIC_ID &&
-                                                       cmd->opcode ==
-                                                               O_BASIC_CHECK_STATE) {
-                                                       goto done;
-                                               }
-                                               break;
-                                       }
-                               }
-                               break;
-                       }
-               }
-       }
-
-       /*
-        * show proto
-        */
-       changed=0;
-       for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd),
-                       cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
-               changed = show_filter(cmd, "proto", PROTO);
-       }
-       if (!changed && !do_quiet)
-               printf(" ip");
-
-       /*
-        * show from
-        */
-       changed = 0;
-       for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd),
-                       cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
-               changed = show_filter(cmd, "from", FROM);
-       }
-       if (!changed && !do_quiet)
-               printf(" from any");
-
-       /*
-        * show to
-        */
-       changed = 0;
-       for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd),
-                       cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
-               changed = show_filter(cmd, "to", TO);
-       }
-       if (!changed && !do_quiet)
-               printf(" to any");
-
-       /*
-        * show other filters
-        */
-       for (l = rule->act_ofs, cmd = rule->cmd, m = mappings;
-                       l > 0; l -= F_LEN(cmd),
-                       cmd=(ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
-               show_filter(cmd, "other", FILTER);
-       }
-
-       /* show the comment in the end */
-       if (comment_fn != NULL) {
-               (*comment_fn)(comment_cmd, 0);
-       }
-done:
-       printf("\n");
-}
-
-static void
-show_states(struct ipfw_ioc_state *d, int pcwidth, int bcwidth)
-{
-       struct protoent *pe;
-       struct in_addr a;
-
-       printf("%05u ", d->rulenum);
-       if (do_acct) {
-               printf("%*ju %*ju ", pcwidth, (uintmax_t)d->pcnt,
-                               bcwidth, (uintmax_t)d->bcnt);
-       }
-
-       if (do_time == 1) {
-               /* state->timestamp */
-               char timestr[30];
-               time_t t = _long_to_time(d->timestamp);
-               strcpy(timestr, ctime(&t));
-               *strchr(timestr, '\n') = '\0';
-               printf(" (%s", timestr);
-
-               /* state->lifetime */
-               printf(" %ds", d->lifetime);
-
-               /* state->expiry */
-               if (d->expiry !=0) {
-                       t = _long_to_time(d->expiry);
-                       strcpy(timestr, ctime(&t));
-                       *strchr(timestr, '\n') = '\0';
-                       printf(" %s)", timestr);
-               } else {
-                       printf(" 0)");
-               }
-
-       } else if (do_time == 2) {
-               printf("(%u %ds %u) ", d->timestamp, d->lifetime, d->expiry);
-       }
-
-       if ((pe = getprotobynumber(d->flow_id.proto)) != NULL)
-               printf(" %s", pe->p_name);
-       else
-               printf(" proto %u", d->flow_id.proto);
-
-       a.s_addr = htonl(d->flow_id.src_ip);
-       printf(" %s %d", inet_ntoa(a), d->flow_id.src_port);
-
-       a.s_addr = htonl(d->flow_id.dst_ip);
-       printf(" <-> %s %d", inet_ntoa(a), d->flow_id.dst_port);
-       printf(" CPU %d", d->cpuid);
-       printf("\n");
-}
-
-int
-sort_q(const void *pa, const void *pb)
-{
-       int rev = (do_sort < 0);
-       int field = rev ? -do_sort : do_sort;
-       long long res = 0;
-       const struct dn_ioc_flowqueue *a = pa;
-       const struct dn_ioc_flowqueue *b = pb;
-
-       switch(field) {
-       case 1: /* pkts */
-               res = a->len - b->len;
-               break;
-       case 2: /* bytes */
-               res = a->len_bytes - b->len_bytes;
-               break;
-
-       case 3: /* tot pkts */
-               res = a->tot_pkts - b->tot_pkts;
-               break;
-
-       case 4: /* tot bytes */
-               res = a->tot_bytes - b->tot_bytes;
-               break;
-       }
-       if (res < 0)
-               res = -1;
-       if (res > 0)
-               res = 1;
-       return (int)(rev ? res : -res);
-}
-
-static void
-show_queues(struct dn_ioc_flowset *fs, struct dn_ioc_flowqueue *q)
-{
-       int l;
-
-       printf("mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
-               fs->flow_mask.u.ip.proto,
-               fs->flow_mask.u.ip.src_ip, fs->flow_mask.u.ip.src_port,
-               fs->flow_mask.u.ip.dst_ip, fs->flow_mask.u.ip.dst_port);
-       if (fs->rq_elements == 0)
-               return;
-
-       printf("BKT Prot ___Source IP/port____ "
-               "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
-       if (do_sort != 0)
-               heapsort(q, fs->rq_elements, sizeof(*q), sort_q);
-       for (l = 0; l < fs->rq_elements; l++) {
-               struct in_addr ina;
-               struct protoent *pe;
-
-               ina.s_addr = htonl(q[l].id.u.ip.src_ip);
-               printf("%3d ", q[l].hash_slot);
-               pe = getprotobynumber(q[l].id.u.ip.proto);
-               if (pe)
-                       printf("%-4s ", pe->p_name);
-               else
-                       printf("%4u ", q[l].id.u.ip.proto);
-               printf("%15s/%-5d ",
-                       inet_ntoa(ina), q[l].id.u.ip.src_port);
-               ina.s_addr = htonl(q[l].id.u.ip.dst_ip);
-               printf("%15s/%-5d ",
-                       inet_ntoa(ina), q[l].id.u.ip.dst_port);
-               printf("%4ju %8ju %2u %4u %3u\n",
-                       (uintmax_t)q[l].tot_pkts, (uintmax_t)q[l].tot_bytes,
-                       q[l].len, q[l].len_bytes, q[l].drops);
-               if (verbose)
-                       printf(" S %20ju F %20ju\n",
-                               (uintmax_t)q[l].S, (uintmax_t)q[l].F);
-       }
-}
-
-static void
-show_flowset_parms(struct dn_ioc_flowset *fs, char *prefix)
-{
-       char qs[30];
-       char plr[30];
-       char red[90];   /* Display RED parameters */
-       int l;
-
-       l = fs->qsize;
-       if (fs->flags_fs & DN_QSIZE_IS_BYTES) {
-               if (l >= 8192)
-                       sprintf(qs, "%d KB", l / 1024);
-               else
-                       sprintf(qs, "%d B", l);
-       } else
-               sprintf(qs, "%3d sl.", l);
-       if (fs->plr)
-               sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff));
-       else
-               plr[0] = '\0';
-       if (fs->flags_fs & DN_IS_RED)   /* RED parameters */
-               sprintf(red,
-                       "\n\t %cRED w_q %f min_th %d max_th %d max_p %f",
-                       (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ',
-                       1.0 * fs->w_q / (double)(1 << SCALE_RED),
-                       SCALE_VAL(fs->min_th),
-                       SCALE_VAL(fs->max_th),
-                       1.0 * fs->max_p / (double)(1 << SCALE_RED));
-       else
-               sprintf(red, "droptail");
-
-       printf("%s %s%s %d queues (%d buckets) %s\n",
-               prefix, qs, plr, fs->rq_elements, fs->rq_size, red);
-}
-
-static void
-show_pipes(void *data, int nbytes, int ac, char *av[])
-{
-       u_long rulenum;
-       void *next = data;
-       struct dn_ioc_pipe *p = (struct dn_ioc_pipe *)data;
-       struct dn_ioc_flowset *fs;
-       struct dn_ioc_flowqueue *q;
-       int l;
-
-       if (ac > 0)
-               rulenum = strtoul(*av++, NULL, 10);
-       else
-               rulenum = 0;
-       for (; nbytes >= sizeof(*p); p = (struct dn_ioc_pipe *)next) {
-               double b = p->bandwidth;
-               char buf[30];
-               char prefix[80];
-
-               if (p->fs.fs_type != DN_IS_PIPE)
-                       break;  /* done with pipes, now queues */
-
-               /*
-                * compute length, as pipe have variable size
-                */
-               l = sizeof(*p) + p->fs.rq_elements * sizeof(*q);
-               next = (void *)p + l;
-               nbytes -= l;
-
-               if (rulenum != 0 && rulenum != p->pipe_nr)
-                       continue;
-
-               /*
-                * Print rate
-                */
-               if (b == 0)
-                       sprintf(buf, "unlimited");
-               else if (b >= 1000000)
-                       sprintf(buf, "%7.3f Mbit/s", b/1000000);
-               else if (b >= 1000)
-                       sprintf(buf, "%7.3f Kbit/s", b/1000);
-               else
-                       sprintf(buf, "%7.3f bit/s ", b);
-
-               sprintf(prefix, "%05d: %s %4d ms ",
-                       p->pipe_nr, buf, p->delay);
-               show_flowset_parms(&p->fs, prefix);
-               if (verbose)
-                       printf(" V %20ju\n", (uintmax_t)p->V >> MY_M);
-
-               q = (struct dn_ioc_flowqueue *)(p+1);
-               show_queues(&p->fs, q);
-       }
-
-       for (fs = next; nbytes >= sizeof(*fs); fs = next) {
-               char prefix[80];
-
-               if (fs->fs_type != DN_IS_QUEUE)
-                       break;
-               l = sizeof(*fs) + fs->rq_elements * sizeof(*q);
-               next = (void *)fs + l;
-               nbytes -= l;
-               q = (struct dn_ioc_flowqueue *)(fs+1);
-               sprintf(prefix, "q%05d: weight %d pipe %d ",
-                       fs->fs_nr, fs->weight, fs->parent_nr);
-               show_flowset_parms(fs, prefix);
-               show_queues(fs, q);
-       }
-}
-
-/*
- * This one handles all set-related commands
- *     ipfw set { show | enable | disable }
- *     ipfw set swap X Y
- *     ipfw set move X to Y
- *     ipfw set move rule X to Y
- */
-static void
-sets_handler(int ac, char *av[])
+void
+help(void)
 {
-       u_int32_t set_disable, masks[2];
-       u_int16_t rulenum;
-       u_int8_t cmd, new_set;
-       int i, nbytes;
-
-       NEXT_ARG;
-       if (!ac)
-               errx(EX_USAGE, "set needs command");
-       if (!strncmp(*av, "show", strlen(*av)) ) {
-               void *data = NULL;
-               char *msg;
-               int nalloc=1000;
-               nbytes = nalloc;
-
-               while (nbytes >= nalloc) {
-                       nalloc = nalloc * 2+321;
-                       nbytes = nalloc;
-                       if (data == NULL) {
-                               if ((data = malloc(nbytes)) == NULL) {
-                                       err(EX_OSERR, "malloc");
-                               }
-                       } else if ((data = realloc(data, nbytes)) == NULL) {
-                               err(EX_OSERR, "realloc");
-                       }
-                       if (do_get_x(IP_FW_GET, data, &nbytes) < 0) {
-                               err(EX_OSERR, "getsockopt(IP_FW_GET)");
-                       }
-               }
-               set_disable = ((struct ipfw_ioc_rule *)data)->set_disable;
-               for (i = 0, msg = "disable" ; i < 31; i++)
-                       if ( (set_disable & (1<<i))) {
-                               printf("%s %d", msg, i);
-                               msg = "";
-                       }
-               msg = (set_disable) ? " enable" : "enable";
-               for (i = 0; i < 31; i++)
-                       if ( !(set_disable & (1<<i))) {
-                               printf("%s %d", msg, i);
-                               msg = "";
-                       }
-               printf("\n");
-       } else if (!strncmp(*av, "swap", strlen(*av))) {
-               NEXT_ARG;
-               if (ac != 2)
-                       errx(EX_USAGE, "set swap needs 2 set numbers\n");
-               rulenum = atoi(av[0]);
-               new_set = atoi(av[1]);
-               if (!isdigit(*(av[0])) || rulenum > 30)
-                       errx(EX_DATAERR, "invalid set number %s\n", av[0]);
-               if (!isdigit(*(av[1])) || new_set > 30)
-                       errx(EX_DATAERR, "invalid set number %s\n", av[1]);
-               masks[0] = (4 << 24) | (new_set << 16) | (rulenum);
-               i = do_set_x(IP_FW_DEL, masks, sizeof(u_int32_t));
-       } else if (!strncmp(*av, "move", strlen(*av))) {
-               NEXT_ARG;
-               if (ac && !strncmp(*av, "rule", strlen(*av))) {
-                       cmd = 2;
-                       NEXT_ARG;
-               } else
-                       cmd = 3;
-               if (ac != 3 || strncmp(av[1], "to", strlen(*av)))
-                       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 > 30) ||
-                               (cmd == 2 && rulenum == 65535) )
-                       errx(EX_DATAERR, "invalid source number %s\n", av[0]);
-               if (!isdigit(*(av[2])) || new_set > 30)
-                       errx(EX_DATAERR, "invalid dest. set %s\n", av[1]);
-               masks[0] = (cmd << 24) | (new_set << 16) | (rulenum);
-               i = do_set_x(IP_FW_DEL, masks, sizeof(u_int32_t));
-       } else if (!strncmp(*av, "disable", strlen(*av)) ||
-                       !strncmp(*av, "enable", strlen(*av)) ) {
-               int which = !strncmp(*av, "enable", strlen(*av)) ? 1 : 0;
-
-               NEXT_ARG;
-               masks[0] = masks[1] = 0;
-
-               while (ac) {
-                       if (isdigit(**av)) {
-                               i = atoi(*av);
-                               if (i < 0 || i > 30)
-                                       errx(EX_DATAERR, "invalid set number %d\n", i);
-                               masks[which] |= (1<<i);
-                       } else if (!strncmp(*av, "disable", strlen(*av)))
-                               which = 0;
-                       else if (!strncmp(*av, "enable", strlen(*av)))
-                               which = 1;
-                       else
-                               errx(EX_DATAERR, "invalid set command %s\n", *av);
-                       NEXT_ARG;
-               }
-               if ( (masks[0] & masks[1]) != 0 )
-                       errx(EX_DATAERR, "cannot enable and disable the same set\n");
-               i = do_set_x(IP_FW_DEL, masks, sizeof(masks));
-               if (i)
-                       warn("set enable/disable: setsockopt(IP_FW_DEL)");
-       } else
-               errx(EX_USAGE, "invalid set command %s\n", *av);
-}
-
-static void
-add_state(int ac, char *av[])
-{
-       struct ipfw_ioc_state ioc_state;
-       ioc_state.expiry = 0;
-       ioc_state.lifetime = 0;
-       NEXT_ARG;
-       if (strcmp(*av, "rulenum") == 0) {
-               NEXT_ARG;
-               ioc_state.rulenum = atoi(*av);
-       } else {
-               errx(EX_USAGE, "ipfw state add rule");
-       }
-       NEXT_ARG;
-       struct protoent *pe;
-       pe = getprotobyname(*av);
-       ioc_state.flow_id.proto = pe->p_proto;
-
-       NEXT_ARG;
-       ioc_state.flow_id.src_ip = inet_addr(*av);
-
-       NEXT_ARG;
-       ioc_state.flow_id.src_port = atoi(*av);
-
-       NEXT_ARG;
-       ioc_state.flow_id.dst_ip = inet_addr(*av);
-
-       NEXT_ARG;
-       ioc_state.flow_id.dst_port = atoi(*av);
-
-       NEXT_ARG;
-       if (strcmp(*av, "live") == 0) {
-               NEXT_ARG;
-               ioc_state.lifetime = atoi(*av);
-               NEXT_ARG;
-       }
-
-       if (strcmp(*av, "expiry") == 0) {
-               NEXT_ARG;
-               ioc_state.expiry = strtoul(*av, NULL, 10);
-               printf("ioc_state.expiry=%d\n", ioc_state.expiry);
-       }
-
-       if (do_set_x(IP_FW_STATE_ADD, &ioc_state, sizeof(struct ipfw_ioc_state)) < 0 ) {
-               err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_ADD)");
-       }
-       if (!do_quiet) {
-               printf("Flushed all states.\n");
-       }
-}
-
-static void
-delete_state(int ac, char *av[])
-{
-       int rulenum;
-       NEXT_ARG;
-       if (ac == 1 && isdigit(**av))
-               rulenum = atoi(*av);
-       if (do_set_x(IP_FW_STATE_DEL, &rulenum, sizeof(int)) < 0 )
-               err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_DEL)");
-       if (!do_quiet)
-               printf("Flushed all states.\n");
-}
-
-static void
-flush_state(int ac, char *av[])
-{
-       if (!do_force) {
-               int c;
-
-               printf("Are you sure? [yn] ");
-               fflush(stdout);
-               do {
-                       c = toupper(getc(stdin));
-                       while (c != '\n' && getc(stdin) != '\n')
-                               if (feof(stdin))
-                                       return; /* and do not flush */
-               } while (c != 'Y' && c != 'N');
-               if (c == 'N')   /* user said no */
-                       return;
-       }
-       if (do_set_x(IP_FW_STATE_FLUSH, NULL, 0) < 0 )
-               err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_FLUSH)");
-       if (!do_quiet)
-               printf("Flushed all states.\n");
-}
-
-static int
-lookup_host (char *host, struct in_addr *ipaddr)
-{
-       struct hostent *he;
-
-       if (!inet_aton(host, ipaddr)) {
-               if ((he = gethostbyname(host)) == NULL)
-                       return(-1);
-               *ipaddr = *(struct in_addr *)he->h_addr_list[0];
-       }
-       return(0);
-}
-
-static void
-table_append(int ac, char *av[])
-{
-       struct ipfw_ioc_table tbl;
-       char *p;
-       int size;
-
-       NEXT_ARG;
-       if (isdigit(**av))
-               tbl.id = atoi(*av);
-       else
-               errx(EX_USAGE, "table id `%s' invalid", *av);
-
-       if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
-               errx(EX_USAGE, "table id `%d' invalid", tbl.id);
-
-       NEXT_ARG;
-       if (strcmp(*av, "ip") == 0)
-               tbl.type = 1;
-       else if (strcmp(*av, "mac") == 0)
-               tbl.type = 2;
-       else
-               errx(EX_USAGE, "table type `%s' not supported", *av);
-
-       NEXT_ARG;
-        if (tbl.type == 1) { /* table type ipv4 */
-                struct ipfw_ioc_table_ip_entry ip_ent;
-                if (!ac)
-                        errx(EX_USAGE, "IP address required");
-
-                p = strchr(*av, '/');
-                if (p) {
-                        *p++ = '\0';
-                        ip_ent.masklen = atoi(p);
-                        if (ip_ent.masklen > 32)
-                                errx(EX_DATAERR, "bad width ``%s''", p);
-                } else {
-                        ip_ent.masklen = 32;
-                }
-
-                if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
-                        errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
-
-                tbl.ip_ent[0] = ip_ent;
-                size = sizeof(tbl) + sizeof(ip_ent);
-        } else if (tbl.type == 2) { /* table type mac */
-                struct ipfw_ioc_table_mac_entry mac_ent;
-                if (!ac)
-                        errx(EX_USAGE, "MAC address required");
-
-                mac_ent.addr = *ether_aton(*av);
-                tbl.mac_ent[0] = mac_ent;
-                size = sizeof(tbl) + sizeof(mac_ent);
-        }
-       if (do_set_x(IP_FW_TABLE_APPEND, &tbl, size) < 0 )
-               errx(EX_USAGE, "do_set_x(IP_FW_TABLE_APPEND) "
-                       "table `%d' append `%s' failed", tbl.id, *av);
-}
-
-static void
-table_remove(int ac, char *av[])
-{
-       struct ipfw_ioc_table tbl;
-       struct ipfw_ioc_table_ip_entry ip_ent;
-       char *p;
-       int size;
-
-       NEXT_ARG;
-       if (isdigit(**av))
-               tbl.id = atoi(*av);
-       else
-               errx(EX_USAGE, "table id `%s' invalid", *av);
-
-       if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
-               errx(EX_USAGE, "table id `%d' invalid", tbl.id);
-
-       NEXT_ARG;
-       if (strcmp(*av, "ip") == 0)
-               tbl.type = 1;
-       else if (strcmp(*av, "mac") == 0)
-               tbl.type = 2;
-       else
-               errx(EX_USAGE, "table type `%s' not supported", *av);
-
-       NEXT_ARG;
-       if (!ac)
-               errx(EX_USAGE, "IP address required");
-       p = strchr(*av, '/');
-       if (p) {
-               *p++ = '\0';
-               ip_ent.masklen = atoi(p);
-               if (ip_ent.masklen > 32)
-                       errx(EX_DATAERR, "bad width ``%s''", p);
-       } else {
-               ip_ent.masklen = 32;
-       }
-
-       if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
-               errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
-
-       tbl.ip_ent[0] = ip_ent;
-       size = sizeof(tbl) + sizeof(ip_ent);
-       if (do_set_x(IP_FW_TABLE_REMOVE, &tbl, size) < 0 ) {
-               errx(EX_USAGE, "do_set_x(IP_FW_TABLE_REMOVE) "
-                       "table `%d' append `%s' failed", tbl.id, *av);
-       }
-}
-
-static void
-table_flush(int ac, char *av[])
-{
-       struct ipfw_ioc_table ioc_table;
-       struct ipfw_ioc_table *t = &ioc_table;
-
-       NEXT_ARG;
-       if (isdigit(**av)) {
-               t->id = atoi(*av);
-               if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
-                       errx(EX_USAGE, "table id `%d' invalid", t->id);
-       } else {
-               errx(EX_USAGE, "table id `%s' invalid", *av);
-       }
-       if (do_set_x(IP_FW_TABLE_FLUSH, t, sizeof(struct ipfw_ioc_table)) < 0 )
-               errx(EX_USAGE, "do_set_x(IP_FW_TABLE_FLUSH) "
-                                       "table `%s' flush failed", *av);
-}
-
-static void
-table_list(int ac, char *av[])
-{
-       struct ipfw_ioc_table *ioc_table;
-       int i, count, nbytes, nalloc = 1024;
-       void *data = NULL;
-       NEXT_ARG;
-       if (strcmp(*av, "list") == 0) {
-               nbytes = nalloc;
-               while (nbytes >= nalloc) {
-                       nalloc = nalloc * 2 ;
-                       nbytes = nalloc;
-                       if ((data = realloc(data, nbytes)) == NULL)
-                               err(EX_OSERR, "realloc");
-                       if (do_get_x(IP_FW_TABLE_LIST, data, &nbytes) < 0)
-                               err(EX_OSERR, "do_get_x(IP_FW_TABLE_LIST)");
-               }
-               ioc_table = (struct ipfw_ioc_table *)data;
-               count = nbytes / sizeof(struct ipfw_ioc_table);
-               for (i = 0; i < count; i++, ioc_table++) {
-                       if (ioc_table->type > 0) {
-                               printf("table %d",ioc_table->id);
-                               if (ioc_table->type == 1)
-                                       printf(" type ip");
-                               else if (ioc_table->type == 2)
-                                       printf(" type mac");
-                               printf(" count %d",ioc_table->count);
-                               if (strlen(ioc_table->name) > 0)
-                                       printf(" name %s",ioc_table->name);
-                               printf("\n");
-
-                       }
-               }
-       } else {
-               errx(EX_USAGE, "ipfw3 table `%s' delete invalid", *av);
-       }
+       fprintf(stderr, "usage: ipfw3 [options]\n"
+                       "       ipfw3 add [rulenum] [set id] action filters\n"
+                       "       ipfw3 delete [rulenum]\n"
+                       "       ipfw3 flush\n"
+                       "       ipfw3 list [rulenum]\n"
+                       "       ipfw3 show [rulenum]\n"
+                       "       ipfw3 zero [rulenum]\n"
+                       "       ipfw3 set [show|enable|disable]\n"
+                       "       ipfw3 module\n"
+                       "       ipfw3 [enable|disable]\n"
+                       "       ipfw3 log [reset|off|on]\n"
+                       "       ipfw3 nat [config|show|delete]\n"
+                       "       ipfw3 pipe [config|show|delete]\n"
+                       "       ipfw3 state [add|delete|list|show]\n"
+                       "       ipfw3 nat [config|show]\n"
+                       "\nsee ipfw3 manpage for details\n");
+       exit(EX_USAGE);
 }
 
 void
-print_table(struct ipfw_ioc_table * tbl)
-{
-       int i;
-        if (tbl->type == 0)
-                errx(EX_USAGE, "table %d is not in use", tbl->id);
-
-        printf("table %d", tbl->id);
-        if (tbl->type == 1)
-                printf(" type ip");
-        else if (tbl->type == 2)
-                printf(" type mac");
-
-        printf(" count %d", tbl->count);
-       if (strlen(tbl->name) > 0)
-               printf(" name %s", tbl->name);
-
-       printf("\n");
-
-        if (tbl->type == 1) {
-                struct ipfw_ioc_table_ip_entry *ip_ent;
-                ip_ent = tbl->ip_ent;
-                for (i = 0; i < tbl->count; i++) {
-                        printf("%s", inet_ntoa(*(struct in_addr *)&ip_ent->addr));
-                        printf("/%d ", ip_ent->masklen);
-                        printf("\n");
-                        ip_ent++;
-                }
-        } else if (tbl->type == 2) {
-                struct ipfw_ioc_table_mac_entry *mac_ent;
-                mac_ent = tbl->mac_ent;
-                for (i = 0; i < tbl->count; i++) {
-                        printf("%s", ether_ntoa(&mac_ent->addr));
-                        printf("\n");
-                        mac_ent++;
-                }
-        }
-}
-
-static void
-table_show(int ac, char *av[])
-{
-       int nbytes, nalloc = 1024;
-       void *data = NULL;
-       NEXT_ARG;
-       if (isdigit(**av)) {
-               nbytes = nalloc;
-               while (nbytes >= nalloc) {
-                       nalloc = nalloc * 2 + 256;
-                       nbytes = nalloc;
-                       if (data == NULL) {
-                               if ((data = malloc(nbytes)) == NULL) {
-                                       err(EX_OSERR, "malloc");
-                               }
-                       } else if ((data = realloc(data, nbytes)) == NULL) {
-                               err(EX_OSERR, "realloc");
-                       }
-                       /* store table id in the header of data */
-                       int *head = (int *)data;
-                       *head = atoi(*av);
-                       if (*head < 0 || *head > IPFW_TABLES_MAX - 1)
-                               errx(EX_USAGE, "table id `%d' invalid", *head);
-                       if (do_get_x(IP_FW_TABLE_SHOW, data, &nbytes) < 0)
-                               err(EX_OSERR, "do_get_x(IP_FW_TABLE_LIST)");
-                       struct ipfw_ioc_table *tbl;
-                       tbl = (struct ipfw_ioc_table *)data;
-                       print_table(tbl);
-               }
-       } else {
-               errx(EX_USAGE, "ipfw3 table `%s' show invalid", *av);
-       }
-}
-
-static void
-table_create(int ac, char *av[])
-{
-       struct ipfw_ioc_table ioc_table;
-       struct ipfw_ioc_table *t = &ioc_table;
-
-       NEXT_ARG;
-       if (ac < 2)
-               errx(EX_USAGE, "table parameters invalid");
-       if (isdigit(**av)) {
-               t->id = atoi(*av);
-               if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
-                       errx(EX_USAGE, "table id `%d' invalid", t->id);
-       } else {
-               errx(EX_USAGE, "table id `%s' invalid", *av);
-       }
-       NEXT_ARG;
-       if (strcmp(*av, "ip") == 0)
-               t->type = 1;
-       else if (strcmp(*av, "mac") == 0)
-               t->type = 2;
-       else
-               errx(EX_USAGE, "table type `%s' not supported", *av);
-
-       NEXT_ARG;
-       memset(t->name, 0, IPFW_TABLE_NAME_LEN);
-       if (ac == 2 && strcmp(*av, "name") == 0) {
-               NEXT_ARG;
-               if (strlen(*av) < IPFW_TABLE_NAME_LEN) {
-                       strncpy(t->name, *av, strlen(*av));
-               } else {
-                       errx(EX_USAGE, "table name `%s' too long", *av);
-               }
-       } else if (ac == 1) {
-               errx(EX_USAGE, "table `%s' invalid", *av);
-       }
-
-       if (do_set_x(IP_FW_TABLE_CREATE, t, sizeof(struct ipfw_ioc_table)) < 0)
-               errx(EX_USAGE, "do_set_x(IP_FW_TABLE_CREATE) "
-                                       "table `%d' in use", t->id);
-}
-
-static void
-table_delete(int ac, char *av[])
-{
-       struct ipfw_ioc_table ioc_table;
-       struct ipfw_ioc_table *t = &ioc_table;
-
-       NEXT_ARG;
-       if (isdigit(**av)) {
-               t->id = atoi(*av);
-               if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
-                       errx(EX_USAGE, "table id `%d' invalid", t->id);
-       } else {
-               errx(EX_USAGE, "table id `%s' invalid", *av);
-       }
-       if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
-               errx(EX_USAGE, "table id `%d' invalid", t->id);
-
-       if (do_set_x(IP_FW_TABLE_DELETE, t, sizeof(struct ipfw_ioc_table)) < 0)
-               errx(EX_USAGE, "do_set_x(IP_FW_TABLE_DELETE) "
-                                       "table `%s' delete failed", *av);
-}
-
-static void
-table_test(int ac, char *av[])
-{
-       struct ipfw_ioc_table tbl;
-       int size;
-
-       NEXT_ARG;
-       if (isdigit(**av))
-               tbl.id = atoi(*av);
-       else
-               errx(EX_USAGE, "table id `%s' invalid", *av);
-
-       if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
-               errx(EX_USAGE, "table id `%d' invalid", tbl.id);
-
-       NEXT_ARG;
-       if (strcmp(*av, "ip") == 0)
-               tbl.type = 1;
-       else if (strcmp(*av, "mac") == 0)
-               tbl.type = 2;
-       else
-               errx(EX_USAGE, "table type `%s' not supported", *av);
-
-       NEXT_ARG;
-        if (tbl.type == 1) { /* table type ipv4 */
-                struct ipfw_ioc_table_ip_entry ip_ent;
-                if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
-                        errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
-
-                tbl.ip_ent[0] = ip_ent;
-                size = sizeof(tbl) + sizeof(ip_ent);
-        } else if (tbl.type == 2) { /* table type mac */
-                struct ipfw_ioc_table_mac_entry mac_ent;
-                if (!ac)
-                        errx(EX_USAGE, "MAC address required");
-
-                mac_ent.addr = *ether_aton(*av);
-                tbl.mac_ent[0] = mac_ent;
-                size = sizeof(tbl) + sizeof(mac_ent);
-        }
-       if (do_set_x(IP_FW_TABLE_TEST, &tbl, size) < 0 ) {
-               printf("NO, %s not exists in table %d\n", *av, tbl.id);
-       } else {
-               printf("YES, %s exists in table %d\n", *av, tbl.id);
-       }
-}
-
-static void
-table_rename(int ac, char *av[])
-{
-       struct ipfw_ioc_table tbl;
-       int size;
-
-       bzero(&tbl, sizeof(tbl));
-       NEXT_ARG;
-       if (isdigit(**av))
-               tbl.id = atoi(*av);
-       else
-               errx(EX_USAGE, "table id `%s' invalid", *av);
-
-       if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
-               errx(EX_USAGE, "table id `%d' invalid", tbl.id);
-
-       NEXT_ARG;
-       strlcpy(tbl.name, *av, IPFW_TABLE_NAME_LEN);
-       size = sizeof(tbl);
-       if (do_set_x(IP_FW_TABLE_RENAME, &tbl, size) < 0 )
-               errx(EX_USAGE, "do_set_x(IP_FW_TABLE_RENAME) "
-                                       "table `%d' not in use", tbl.id);
-}
-
-static void
-list(int ac, char *av[])
-{
-       struct ipfw_ioc_state *dynrules, *d;
-       struct ipfw_ioc_rule *r;
-
-       u_long rnum;
-       void *data = NULL;
-       int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width;
-       int exitval = EX_OK, lac;
-       char **lav, *endptr;
-       int seen = 0;
-       int nalloc = 1024;
-
-       NEXT_ARG;
-
-       /* get rules or pipes from kernel, resizing array as necessary */
-       nbytes = nalloc;
-
-       while (nbytes >= nalloc) {
-               nalloc = nalloc * 2 ;
-               nbytes = nalloc;
-               if ((data = realloc(data, nbytes)) == NULL)
-                       err(EX_OSERR, "realloc");
-               if (do_get_x(IP_FW_GET, data, &nbytes) < 0)
-                       err(EX_OSERR, "do_get_x(IP_FW_GET)");
-       }
-
-       /*
-        * Count static rules.
-        */
-       r = data;
-       nstat = r->static_count;
-
-       /*
-        * Count dynamic rules. This is easier as they have
-        * fixed size.
-        */
-       dynrules = (struct ipfw_ioc_state *)((void *)r + r->static_len);
-       ndyn = (nbytes - r->static_len) / sizeof(*dynrules);
-
-       /* if showing stats, figure out column widths ahead of time */
-       bcwidth = pcwidth = 0;
-       if (do_acct) {
-               for (n = 0, r = data; n < nstat;
-                       n++, r = (void *)r + IOC_RULESIZE(r)) {
-                       /* packet counter */
-                       width = snprintf(NULL, 0, "%ju", (uintmax_t)r->pcnt);
-                       if (width > pcwidth)
-                               pcwidth = width;
-
-                       /* byte counter */
-                       width = snprintf(NULL, 0, "%ju", (uintmax_t)r->bcnt);
-                       if (width > bcwidth)
-                               bcwidth = width;
-               }
-       }
-       if (do_dynamic && ndyn) {
-               for (n = 0, d = dynrules; n < ndyn; n++, d++) {
-                       width = snprintf(NULL, 0, "%ju", (uintmax_t)d->pcnt);
-                       if (width > pcwidth)
-                               pcwidth = width;
-
-                       width = snprintf(NULL, 0, "%ju", (uintmax_t)d->bcnt);
-                       if (width > bcwidth)
-                               bcwidth = width;
-               }
-       }
-
-       /* if no rule numbers were specified, list all rules */
-       if (ac == 0) {
-               if (do_dynamic != 2) {
-                       for (n = 0, r = data; n < nstat; n++,
-                               r = (void *)r + IOC_RULESIZE(r)) {
-                               show_rules(r, pcwidth, bcwidth);
-                       }
-               }
-               if (do_dynamic && ndyn) {
-                       if (do_dynamic != 2) {
-                               printf("## States (%d):\n", ndyn);
-                       }
-                       for (n = 0, d = dynrules; n < ndyn; n++, d++)
-                               show_states(d, pcwidth, bcwidth);
-               }
-               goto done;
-       }
-
-       /* display specific rules requested on command line */
-
-       if (do_dynamic != 2) {
-               for (lac = ac, lav = av; lac != 0; lac--) {
-                       /* convert command line rule # */
-                       rnum = strtoul(*lav++, &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 = (void *)r + IOC_RULESIZE(r) ) {
-                               if (r->rulenum > rnum)
-                                       break;
-                               if (r->rulenum == rnum) {
-                                       show_rules(r, pcwidth, bcwidth);
-                                       seen = 1;
-                               }
-                       }
-                       if (!seen) {
-                               /* give precedence to other error(s) */
-                               if (exitval == EX_OK)
-                                       exitval = EX_UNAVAILABLE;
-                               warnx("rule %lu does not exist", rnum);
-                       }
-               }
-       }
-
-       if (do_dynamic && ndyn) {
-               if (do_dynamic != 2) {
-                       printf("## States (%d):\n", ndyn);
-               }
-               for (lac = ac, lav = av; lac != 0; lac--) {
-                       rnum = strtoul(*lav++, &endptr, 10);
-                       if (*endptr)
-                               /* already warned */
-                               continue;
-                       for (n = 0, d = dynrules; n < ndyn; n++, d++) {
-                               if (d->rulenum > rnum)
-                                       break;
-                               if (d->rulenum == rnum)
-                                       show_states(d, pcwidth, bcwidth);
-                       }
-               }
-       }
-
-       ac = 0;
-
-done:
-       free(data);
-
-       if (exitval != EX_OK)
-               exit(exitval);
-}
-
-static void
-show_dummynet(int ac, char *av[])
-{
-       void *data = NULL;
-       int nbytes;
-       int nalloc = 1024;      /* start somewhere... */
-
-       NEXT_ARG;
-
-       nbytes = nalloc;
-       while (nbytes >= nalloc) {
-               nalloc = nalloc * 2 + 200;
-               nbytes = nalloc;
-               if ((data = realloc(data, nbytes)) == NULL)
-                       err(EX_OSERR, "realloc");
-               if (do_get_x(IP_DUMMYNET_GET, data, &nbytes) < 0) {
-                       err(EX_OSERR, "do_get_x(IP_%s_GET)",
-                               do_pipe ? "DUMMYNET" : "FW");
-               }
-       }
-
-       show_pipes(data, nbytes, ac, av);
-       free(data);
-}
-
-static void
-help(void)
-{
-       fprintf(stderr, "usage: ipfw [options]\n"
-                       "       ipfw add [rulenum] [set id] action filters\n"
-                       "       ipfw delete [rulenum]\n"
-                       "       ipfw flush\n"
-                       "       ipfw list [rulenum]\n"
-                       "       ipfw show [rulenum]\n"
-                       "       ipfw zero [rulenum]\n"
-                       "       ipfw set [show|enable|disable]\n"
-                       "       ipfw module\n"
-                       "       ipfw [enable|disable]\n"
-                       "       ipfw log [reset|off|on]\n"
-                       "       ipfw nat [config|show|delete]\n"
-                       "       ipfw pipe [config|show|delete]\n"
-                       "       ipfw state [add|delete|list|show]"
-                       "\nsee ipfw manpage for details\n");
-       exit(EX_USAGE);
-}
-
-
-static void
-delete_rules(int ac, char *av[])
-{
-       struct dn_ioc_pipe pipe;
-       u_int32_t rulenum;
-       int exitval = EX_OK;
-       int do_set = 0;
-       int i;
-
-       memset(&pipe, 0, sizeof pipe);
-
-       NEXT_ARG;
-       if (ac > 0 && !strncmp(*av, "set", strlen(*av))) {
-               do_set = 1;     /* delete set */
-               NEXT_ARG;
-       }
-
-       /* Rule number */
-       while (ac && isdigit(**av)) {
-               i = atoi(*av);
-               NEXT_ARG;
-               if (do_pipe) {
-                       if (do_pipe == 1)
-                               pipe.pipe_nr = i;
-                       else
-                               pipe.fs.fs_nr = i;
-
-                       i = do_set_x(IP_DUMMYNET_DEL, &pipe, sizeof pipe);
-                       if (i) {
-                               exitval = 1;
-                               warn("rule %u: setsockopt(IP_DUMMYNET_DEL)",
-                                       do_pipe == 1 ? pipe.pipe_nr :
-                                       pipe.fs.fs_nr);
-                       }
-               } else {
-                       rulenum = (i & 0xffff) | (do_set << 24);
-                       i = do_set_x(IP_FW_DEL, &rulenum, sizeof rulenum);
-                       if (i) {
-                               exitval = EX_UNAVAILABLE;
-                               warn("rule %u: setsockopt(IP_FW_DEL)",
-                                       rulenum);
-                       }
-               }
-       }
-       if (exitval != EX_OK)
-               exit(exitval);
-}
-
-
-static unsigned long
-getbw(const char *str, u_short *flags, int kb)
-{
-       unsigned long val;
-       int inbytes = 0;
-       char *end;
-
-       val = strtoul(str, &end, 0);
-       if (*end == 'k' || *end == 'K') {
-               ++end;
-               val *= kb;
-       } else if (*end == 'm' || *end == 'M') {
-               ++end;
-               val *= kb * kb;
-       }
-
-       /*
-        * Deal with bits or bytes or b(bits) or B(bytes). If there is no
-        * trailer assume bits.
-        */
-       if (strncasecmp(end, "bit", 3) == 0) {
-               ;
-       } else if (strncasecmp(end, "byte", 4) == 0) {
-               inbytes = 1;
-       } else if (*end == 'b') {
-               ;
-       } else if (*end == 'B') {
-               inbytes = 1;
-       }
-
-       /*
-        * Return in bits if flags is NULL, else flag bits
-        * or bytes in flags and return the unconverted value.
-        */
-       if (inbytes && flags)
-               *flags |= DN_QSIZE_IS_BYTES;
-       else if (inbytes && flags == NULL)
-               val *= 8;
-
-       return(val);
-}
-
-/*
- * config dummynet pipe/queue
- */
-static void
-config_dummynet(int ac, char **av)
-{
-       struct dn_ioc_pipe pipe;
-       u_int32_t a;
-       void *par = NULL;
-       int i;
-       char *end;
-
-       NEXT_ARG;
-       memset(&pipe, 0, sizeof pipe);
-       /* Pipe number */
-       if (ac && isdigit(**av)) {
-               i = atoi(*av);
-               NEXT_ARG;
-               if (do_pipe == 1)
-                       pipe.pipe_nr = i;
-               else
-                       pipe.fs.fs_nr = i;
-       }
-
-       while (ac > 0) {
-               double d;
-
-               int tok = match_token(dummynet_params, *av);
-               NEXT_ARG;
-
-               switch(tok) {
-               case TOK_NOERROR:
-                       pipe.fs.flags_fs |= DN_NOERROR;
-                       break;
-
-               case TOK_PLR:
-                       NEED1("plr needs argument 0..1\n");
-                       d = strtod(av[0], NULL);
-                       if (d > 1)
-                               d = 1;
-                       else if (d < 0)
-                               d = 0;
-                       pipe.fs.plr = (int)(d*0x7fffffff);
-                       NEXT_ARG;
-                       break;
-
-               case TOK_QUEUE:
-                       NEED1("queue needs queue size\n");
-                       end = NULL;
-                       pipe.fs.qsize = getbw(av[0], &pipe.fs.flags_fs, 1024);
-                       NEXT_ARG;
-                       break;
-
-               case TOK_BUCKETS:
-                       NEED1("buckets needs argument\n");
-                       pipe.fs.rq_size = strtoul(av[0], NULL, 0);
-                       NEXT_ARG;
-                       break;
-
-               case TOK_MASK:
-                       NEED1("mask needs mask specifier\n");
-                       /*
-                        * per-flow queue, mask is dst_ip, dst_port,
-                        * src_ip, src_port, proto measured in bits
-                        */
-                       par = NULL;
-
-                       pipe.fs.flow_mask.type = ETHERTYPE_IP;
-                       pipe.fs.flow_mask.u.ip.dst_ip = 0;
-                       pipe.fs.flow_mask.u.ip.src_ip = 0;
-                       pipe.fs.flow_mask.u.ip.dst_port = 0;
-                       pipe.fs.flow_mask.u.ip.src_port = 0;
-                       pipe.fs.flow_mask.u.ip.proto = 0;
-                       end = NULL;
-
-                       while (ac >= 1) {
-                               u_int32_t *p32 = NULL;
-                               u_int16_t *p16 = NULL;
-
-                               tok = match_token(dummynet_params, *av);
-                               NEXT_ARG;
-                               switch(tok) {
-                               case TOK_ALL:
-                                       /*
-                                        * special case, all bits significant
-                                        */
-                                       pipe.fs.flow_mask.u.ip.dst_ip = ~0;
-                                       pipe.fs.flow_mask.u.ip.src_ip = ~0;
-                                       pipe.fs.flow_mask.u.ip.dst_port = ~0;
-                                       pipe.fs.flow_mask.u.ip.src_port = ~0;
-                                       pipe.fs.flow_mask.u.ip.proto = ~0;
-                                       pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK;
-                                       goto end_mask;
-
-                               case TOK_DSTIP:
-                                       p32 = &pipe.fs.flow_mask.u.ip.dst_ip;
-                                       break;
-
-                               case TOK_SRCIP:
-                                       p32 = &pipe.fs.flow_mask.u.ip.src_ip;
-                                       break;
-
-                               case TOK_DSTPORT:
-                                       p16 = &pipe.fs.flow_mask.u.ip.dst_port;
-                                       break;
-
-                               case TOK_SRCPORT:
-                                       p16 = &pipe.fs.flow_mask.u.ip.src_port;
-                                       break;
-
-                               case TOK_PROTO:
-                                       break;
-
-                               default:
-                                       NEXT_ARG;
-                                       goto end_mask;
-                               }
-                               if (ac < 1)
-                                       errx(EX_USAGE, "mask: value missing");
-                               if (*av[0] == '/') {
-                                       a = strtoul(av[0]+1, &end, 0);
-                                       a = (a == 32) ? ~0 : (1 << a) - 1;
-                               } else
-                                       a = strtoul(av[0], &end, 0);
-                               if (p32 != NULL)
-                                       *p32 = a;
-                               else if (p16 != NULL) {
-                                       if (a > 65535)
-                                               errx(EX_DATAERR,
-                                               "mask: must be 16 bit");
-                                       *p16 = (u_int16_t)a;
-                               } else {
-                                       if (a > 255)
-                                               errx(EX_DATAERR,
-                                               "mask: must be 8 bit");
-                                       pipe.fs.flow_mask.u.ip.proto =
-                                               (uint8_t)a;
-                               }
-                               if (a != 0)
-                                       pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK;
-                               NEXT_ARG;
-                       } /* end while, config masks */
-
-end_mask:
-                       break;
-
-               case TOK_RED:
-               case TOK_GRED:
-                       NEED1("red/gred needs w_q/min_th/max_th/max_p\n");
-                       pipe.fs.flags_fs |= DN_IS_RED;
-                       if (tok == TOK_GRED)
-                               pipe.fs.flags_fs |= DN_IS_GENTLE_RED;
-                       /*
-                        * the format for parameters is w_q/min_th/max_th/max_p
-                        */
-                       if ((end = strsep(&av[0], "/"))) {
-                               double w_q = strtod(end, NULL);
-                               if (w_q > 1 || w_q <= 0)
-                                       errx(EX_DATAERR, "0 < w_q <= 1");
-                               pipe.fs.w_q = (int) (w_q * (1 << SCALE_RED));
-                       }
-                       if ((end = strsep(&av[0], "/"))) {
-                               pipe.fs.min_th = strtoul(end, &end, 0);
-                               if (*end == 'K' || *end == 'k')
-                                       pipe.fs.min_th *= 1024;
-                       }
-                       if ((end = strsep(&av[0], "/"))) {
-                               pipe.fs.max_th = strtoul(end, &end, 0);
-                               if (*end == 'K' || *end == 'k')
-                                       pipe.fs.max_th *= 1024;
-                       }
-                       if ((end = strsep(&av[0], "/"))) {
-                               double max_p = strtod(end, NULL);
-                               if (max_p > 1 || max_p <= 0)
-                                       errx(EX_DATAERR, "0 < max_p <= 1");
-                               pipe.fs.max_p = (int)(max_p * (1 << SCALE_RED));
-                       }
-                       NEXT_ARG;
-                       break;
-
-               case TOK_DROPTAIL:
-                       pipe.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED);
-                       break;
-
-               case TOK_BW:
-                       NEED1("bw needs bandwidth\n");
-                       if (do_pipe != 1)
-                               errx(EX_DATAERR,
-                                       "bandwidth only valid for pipes");
-                       /*
-                        * set bandwidth value
-                        */
-                       pipe.bandwidth = getbw(av[0], NULL, 1000);
-                       if (pipe.bandwidth < 0)
-                               errx(EX_DATAERR, "bandwidth too large");
-                       NEXT_ARG;
-                       break;
-
-               case TOK_DELAY:
-                       if (do_pipe != 1)
-                               errx(EX_DATAERR, "delay only valid for pipes");
-                       NEED1("delay needs argument 0..10000ms\n");
-                       pipe.delay = strtoul(av[0], NULL, 0);
-                       NEXT_ARG;
-                       break;
-
-               case TOK_WEIGHT:
-                       if (do_pipe == 1)
-                               errx(EX_DATAERR,
-                                       "weight only valid for queues");
-                       NEED1("weight needs argument 0..100\n");
-                       pipe.fs.weight = strtoul(av[0], &end, 0);
-                       NEXT_ARG;
-                       break;
-
-               case TOK_PIPE:
-                       if (do_pipe == 1)
-                               errx(EX_DATAERR, "pipe only valid for queues");
-                       NEED1("pipe needs pipe_number\n");
-                       pipe.fs.parent_nr = strtoul(av[0], &end, 0);
-                       NEXT_ARG;
-                       break;
-
-               default:
-                       errx(EX_DATAERR, "unrecognised option ``%s''", *av);
-               }
-       }
-       if (do_pipe == 1) {
-               if (pipe.pipe_nr == 0)
-                       errx(EX_DATAERR, "pipe_nr must be > 0");
-               if (pipe.delay > 10000)
-                       errx(EX_DATAERR, "delay must be < 10000");
-       } else { /* do_pipe == 2, queue */
-               if (pipe.fs.parent_nr == 0)
-                       errx(EX_DATAERR, "pipe must be > 0");
-               if (pipe.fs.weight >100)
-                       errx(EX_DATAERR, "weight must be <= 100");
-       }
-       if (pipe.fs.flags_fs & DN_QSIZE_IS_BYTES) {
-               if (pipe.fs.qsize > 1024*1024)
-                       errx(EX_DATAERR, "queue size must be < 1MB");
-       } else {
-               if (pipe.fs.qsize > 100)
-                       errx(EX_DATAERR, "2 <= queue size <= 100");
-       }
-       if (pipe.fs.flags_fs & DN_IS_RED) {
-               size_t len;
-               int lookup_depth, avg_pkt_size;
-               double s, idle, weight, w_q;
-               int clock_hz;
-               int t;
-
-               if (pipe.fs.min_th >= pipe.fs.max_th)
-                       errx(EX_DATAERR, "min_th %d must be < than max_th %d",
-                       pipe.fs.min_th, pipe.fs.max_th);
-               if (pipe.fs.max_th == 0)
-                       errx(EX_DATAERR, "max_th must be > 0");
-
-               len = sizeof(int);
-               if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth",
-                       &lookup_depth, &len, NULL, 0) == -1)
-
-                       errx(1, "sysctlbyname(\"%s\")",
-                               "net.inet.ip.dummynet.red_lookup_depth");
-               if (lookup_depth == 0)
-                       errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth"
-                               " must be greater than zero");
-
-               len = sizeof(int);
-               if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size",
-                       &avg_pkt_size, &len, NULL, 0) == -1)
-
-                       errx(1, "sysctlbyname(\"%s\")",
-                               "net.inet.ip.dummynet.red_avg_pkt_size");
-               if (avg_pkt_size == 0)
-                       errx(EX_DATAERR,
-                               "net.inet.ip.dummynet.red_avg_pkt_size must"
-                               " be greater than zero");
-
-               len = sizeof(clock_hz);
-               if (sysctlbyname("net.inet.ip.dummynet.hz", &clock_hz, &len,
-                                NULL, 0) == -1) {
-                       errx(1, "sysctlbyname(\"%s\")",
-                                "net.inet.ip.dummynet.hz");
-               }
+rule_delete(int ac, char *av[])
+{
+       int error, rulenum;
 
-               /*
-                * Ticks needed for sending a medium-sized packet.
-                * Unfortunately, when we are configuring a WF2Q+ queue, we
-                * do not have bandwidth information, because that is stored
-                * in the parent pipe, and also we have multiple queues
-                * competing for it. So we set s=0, which is not very
-                * correct. But on the other hand, why do we want RED with
-                * WF2Q+ ?
-                */
-               if (pipe.bandwidth == 0) /* this is a WF2Q+ queue */
-                       s = 0;
-               else
-                       s = clock_hz * avg_pkt_size * 8 / pipe.bandwidth;
-
-               /*
-                * max idle time (in ticks) before avg queue size becomes 0.
-                * NOTA: (3/w_q) is approx the value x so that
-                * (1-w_q)^x < 10^-3.
-                */
-               w_q = ((double)pipe.fs.w_q) / (1 << SCALE_RED);
-               idle = s * 3. / w_q;
-               pipe.fs.lookup_step = (int)idle / lookup_depth;
-               if (!pipe.fs.lookup_step)
-                       pipe.fs.lookup_step = 1;
-               weight = 1 - w_q;
-               for (t = pipe.fs.lookup_step; t > 0; --t)
-                       weight *= weight;
-               pipe.fs.lookup_weight = (int)(weight * (1 << SCALE_RED));
+       NEXT_ARG;
+
+       while (ac && isdigit(**av)) {
+               rulenum = atoi(*av);
+               error = do_set_x(IP_FW_DEL, &rulenum, sizeof(int));
+               if (error) {
+                       err(EX_OSERR, "do_get_x(IP_FW_DEL)");
+               }
+               NEXT_ARG;
        }
-       i = do_set_x(IP_DUMMYNET_CONFIGURE, &pipe, sizeof pipe);
-       if (i)
-               err(1, "do_set_x(%s)", "IP_DUMMYNET_CONFIGURE");
 }
 
 /*
@@ -1952,7 +335,7 @@ end_mask:
  * of the current command, and also cleans up the first word of
  * the new command in case it has been clobbered before.
  */
-static ipfw_insn*
+ipfw_insn*
 next_cmd(ipfw_insn *cmd)
 {
        cmd += F_LEN(cmd);
@@ -1967,8 +350,8 @@ next_cmd(ipfw_insn *cmd)
  *
  *
  */
-static void
-add(int ac, char *av[])
+void
+rule_add(int ac, char *av[])
 {
        /*
         * rules are added into the 'rulebuf' and then copied in
@@ -1986,8 +369,8 @@ add(int ac, char *av[])
        char *prev_av;
        ipfw_insn *the_comment = NULL;
        struct ipfw_ioc_rule *rule;
-       struct ipfw_keyword *key;
-       struct ipfw_mapping *map;
+       struct ipfw3_keyword *key;
+       struct ipfw3_mapping *map;
        parser_func fn;
        int i, j;
 
@@ -2218,11 +601,11 @@ done:
                err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD");
        }
        if (!do_quiet)
-               show_rules(rule, 10, 10);
+               rule_show(rule, 10, 10);
 }
 
-static void
-zero(int ac, char *av[])
+void
+rule_zero(int ac, char *av[])
 {
        int rulenum;
        int failed = EX_OK;
@@ -2256,48 +639,8 @@ zero(int ac, char *av[])
                exit(failed);
 }
 
-static void
-resetlog(int ac, char *av[])
-{
-       int rulenum;
-       int failed = EX_OK;
-
-       NEXT_ARG;
-
-       if (!ac) {
-               /* clear all entries */
-               if (setsockopt(ipfw_socket, IPPROTO_IP,
-                                       IP_FW_RESETLOG, NULL, 0) < 0)
-                       err(EX_UNAVAILABLE, "setsockopt(IP_FW_RESETLOG)");
-               if (!do_quiet)
-                       printf("Logging counts reset.\n");
-
-               return;
-       }
-
-       while (ac) {
-               /* Rule number */
-               if (isdigit(**av)) {
-                       rulenum = atoi(*av);
-                       NEXT_ARG;
-                       if (setsockopt(ipfw_socket, IPPROTO_IP,
-                               IP_FW_RESETLOG, &rulenum, sizeof rulenum)) {
-                               warn("rule %u: setsockopt(IP_FW_RESETLOG)",
-                                               rulenum);
-                               failed = EX_UNAVAILABLE;
-                       } else if (!do_quiet)
-                               printf("Entry %d logging count reset\n",
-                                               rulenum);
-               } else {
-                       errx(EX_DATAERR, "invalid rule number ``%s''", *av);
-               }
-       }
-       if (failed != EX_OK)
-               exit(failed);
-}
-
-static void
-flush(void)
+void
+rule_flush(void)
 {
        int cmd = IP_FW_FLUSH;
        if (do_pipe) {
@@ -2328,6 +671,224 @@ flush(void)
        }
 }
 
+void
+rule_list(int ac, char *av[])
+{
+       struct ipfw_ioc_rule *rule;
+
+       void *data = NULL;
+       int bcwidth, nbytes, pcwidth, width;
+       int nalloc = 1024;
+       int the_rule_num = 0;
+       int total_len;
+
+       NEXT_ARG;
+
+       /* get rules or pipes from kernel, resizing array as necessary */
+       nbytes = nalloc;
+
+       while (nbytes >= nalloc) {
+               nalloc = nalloc * 2 ;
+               nbytes = nalloc;
+               if ((data = realloc(data, nbytes)) == NULL)
+                       err(EX_OSERR, "realloc");
+               if (do_get_x(IP_FW_GET, data, &nbytes) < 0)
+                       err(EX_OSERR, "do_get_x(IP_FW_GET)");
+       }
+
+       /*
+        * Count static rules.
+        */
+       rule = data;
+       bcwidth = pcwidth = 0;
+       if (do_acct) {
+               total_len = 0;
+               for (rule = data; rule != NULL; rule = (void *)rule + IOC_RULESIZE(rule)) {
+                       /* packet counter */
+                       width = snprintf(NULL, 0, "%ju", (uintmax_t)rule->pcnt);
+                       if (width > pcwidth)
+                               pcwidth = width;
+
+                       /* byte counter */
+                       width = snprintf(NULL, 0, "%ju", (uintmax_t)rule->bcnt);
+                       if (width > bcwidth)
+                               bcwidth = width;
+
+                       total_len += IOC_RULESIZE(rule);
+                       if (total_len == nbytes) {
+                               break;
+                       }
+               }
+       }
+
+
+       if (ac == 1) {
+               the_rule_num = atoi(*av);
+       }
+
+       total_len = 0;
+       for (rule = data; rule != NULL; rule = (void *)rule + IOC_RULESIZE(rule)) {
+               if(the_rule_num == 0 || rule->rulenum == the_rule_num) {
+                       rule_show(rule, pcwidth, bcwidth);
+               }
+               total_len += IOC_RULESIZE(rule);
+               if (total_len == nbytes) {
+                       break;
+               }
+       }
+
+}
+
+void
+rule_show(struct ipfw_ioc_rule *rule, int pcwidth, int bcwidth)
+{
+       static int twidth = 0;
+       ipfw_insn *cmd;
+       int l;
+
+       u_int32_t set_disable = rule->sets;
+
+       if (set_disable & (1 << rule->set)) { /* disabled */
+               if (!show_sets)
+                       return;
+               else
+                       printf("# DISABLED ");
+       }
+       if (do_compact) {
+               printf("%u", rule->rulenum);
+       } else {
+               printf("%05u", rule->rulenum);
+       }
+
+       if (do_acct) {
+               if (do_compact) {
+                       printf(" %ju %ju", (uintmax_t)rule->pcnt,
+                                               (uintmax_t)rule->bcnt);
+               } else {
+                       printf(" %*ju %*ju", pcwidth, (uintmax_t)rule->pcnt,
+                               bcwidth, (uintmax_t)rule->bcnt);
+               }
+       }
+
+       if (do_time == 1) {
+               char timestr[30];
+
+               if (twidth == 0) {
+                       strcpy(timestr, ctime((time_t *)&twidth));
+                       *strchr(timestr, '\n') = '\0';
+                       twidth = strlen(timestr);
+               }
+               if (rule->timestamp) {
+                       time_t t = _long_to_time(rule->timestamp);
+
+                       strcpy(timestr, ctime(&t));
+                       *strchr(timestr, '\n') = '\0';
+                       printf(" %s", timestr);
+               } else {
+                       printf(" %*s", twidth, " ");
+               }
+       } else if (do_time == 2) {
+               printf( " %10u", rule->timestamp);
+       }
+
+       if (show_sets)
+               printf(" set %d", rule->set);
+
+
+       struct ipfw3_keyword *k;
+       struct ipfw3_mapping *m;
+       shower_func fn, comment_fn = NULL;
+       ipfw_insn *comment_cmd;
+       int i, j, changed;
+
+       /*
+        * show others and actions
+        */
+       for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule);
+               l > 0; l -= F_LEN(cmd),
+               cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
+               k = keywords;
+               m = mappings;
+               for (i = 1; i< KEYWORD_SIZE; i++, k++) {
+                       if ( k->module == cmd->module && k->opcode == cmd->opcode ) {
+                               for (j = 1; j< MAPPING_SIZE; j++, m++) {
+                                       if (m->type == IN_USE &&
+                                               m->module == cmd->module &&
+                                               m->opcode == cmd->opcode) {
+                                               if (cmd->module == MODULE_BASIC_ID &&
+                                                       cmd->opcode == O_BASIC_COMMENT) {
+                                                       comment_fn = m->shower;
+                                                       comment_cmd = cmd;
+                                               } else {
+                                                       fn = m->shower;
+                                                       (*fn)(cmd, 0);
+                                               }
+                                               if (cmd->module == MODULE_BASIC_ID &&
+                                                       cmd->opcode ==
+                                                               O_BASIC_CHECK_STATE) {
+                                                       goto done;
+                                               }
+                                               break;
+                                       }
+                               }
+                               break;
+                       }
+               }
+       }
+
+       /*
+        * show proto
+        */
+       changed=0;
+       for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd),
+                       cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
+               changed = show_filter(cmd, "proto", PROTO);
+       }
+       if (!changed && !do_quiet)
+               printf(" ip");
+
+       /*
+        * show from
+        */
+       changed = 0;
+       for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd),
+                       cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
+               changed = show_filter(cmd, "from", FROM);
+       }
+       if (!changed && !do_quiet)
+               printf(" from any");
+
+       /*
+        * show to
+        */
+       changed = 0;
+       for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd),
+                       cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
+               changed = show_filter(cmd, "to", TO);
+       }
+       if (!changed && !do_quiet)
+               printf(" to any");
+
+       /*
+        * show other filters
+        */
+       l = rule->act_ofs;
+       cmd = rule->cmd;
+       m = mappings;
+       for ( ; l > 0; ) {
+               show_filter(cmd, "other", FILTER);
+               l -= F_LEN(cmd);
+               cmd=(ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd));
+       }
+
+       /* show the comment in the end */
+       if (comment_fn != NULL) {
+               (*comment_fn)(comment_cmd, 0);
+       }
+done:
+       printf("\n");
+}
+
 /*
  * do_set_x - extended version og do_set
  * insert a x_header in the beginning of the rule buf
@@ -2336,21 +897,25 @@ flush(void)
 int
 do_set_x(int optname, void *rule, int optlen)
 {
-       int len, *newbuf;
-
+       int len, *newbuf, retval;
        ip_fw_x_header *x_header;
-       if (ipfw_socket < 0)
+
+       if (fw3_socket < 0)
                err(EX_UNAVAILABLE, "socket not avaialble");
+
        len = optlen + sizeof(ip_fw_x_header);
        newbuf = malloc(len);
        if (newbuf == NULL)
                err(EX_OSERR, "malloc newbuf in do_set_x");
+
        bzero(newbuf, len);
        x_header = (ip_fw_x_header *)newbuf;
        x_header->opcode = optname;
        /* copy the rule into the newbuf, just after the x_header*/
        bcopy(rule, ++x_header, optlen);
-       return setsockopt(ipfw_socket, IPPROTO_IP, IP_FW_X, newbuf, len);
+       retval = setsockopt(fw3_socket, IPPROTO_IP, IP_FW_X, newbuf, len);
+       free(newbuf);
+       return retval;
 }
 
 /*
@@ -2360,27 +925,30 @@ int
 do_get_x(int optname, void *rule, int *optlen)
 {
        int len, *newbuf, retval;
-
        ip_fw_x_header *x_header;
-       if (ipfw_socket < 0)
+
+       if (fw3_socket < 0)
                err(EX_UNAVAILABLE, "socket not avaialble");
+
        len = *optlen + sizeof(ip_fw_x_header);
        newbuf = malloc(len);
        if (newbuf == NULL)
                err(EX_OSERR, "malloc newbuf in do_get_x");
+
        bzero(newbuf, len);
        x_header = (ip_fw_x_header *)newbuf;
        x_header->opcode = optname;
        /* copy the rule into the newbuf, just after the x_header*/
        bcopy(rule, ++x_header, *optlen);
-       retval = getsockopt(ipfw_socket, IPPROTO_IP, IP_FW_X, newbuf, &len);
+       retval = getsockopt(fw3_socket, IPPROTO_IP, IP_FW_X, newbuf, &len);
        bcopy(newbuf, rule, len);
-       *optlen=len;
+       free(newbuf);
+       *optlen = len;
        return retval;
 }
 
-static int
-ipfw_main(int ac, char **av)
+int
+ipfw3_main(int ac, char **av)
 {
        int ch;
 
@@ -2391,7 +959,7 @@ ipfw_main(int ac, char **av)
        do_force = !isatty(STDIN_FILENO);
 
        optind = optreset = 1;
-       while ((ch = getopt(ac, av, "hs:acdDefNStTv")) != -1)
+       while ((ch = getopt(ac, av, "hs:acefStTv")) != -1)
                switch (ch) {
                case 'h': /* help */
                        help();
@@ -2406,21 +974,12 @@ ipfw_main(int ac, char **av)
                case 'c':
                        do_compact = 1;
                        break;
-               case 'd':
-                       do_dynamic = 1;
-                       break;
-               case 'D':
-                       do_dynamic = 2;
-                       break;
                case 'e':
                        do_expired = 1;
                        break;
                case 'f':
                        do_force = 1;
                        break;
-               case 'N':
-                       do_resolv = 1;
-                       break;
                case 'S':
                        show_sets = 1;
                        break;
@@ -2440,7 +999,7 @@ ipfw_main(int ac, char **av)
 
        ac -= optind;
        av += optind;
-       NEED1("bad arguments, for usage summary ``ipfw''");
+       NEED1("bad arguments, for usage summary ``ipfw3''");
 
        /*
         * optional: pipe or queue or nat
@@ -2468,76 +1027,43 @@ ipfw_main(int ac, char **av)
        }
 
        if (!strncmp(*av, "add", strlen(*av))) {
-               load_modules();
-               add(ac, av);
+               module_load();
+               rule_add(ac, av);
        } else if (!strncmp(*av, "delete", strlen(*av))) {
-               delete_rules(ac, av);
+               rule_delete(ac, av);
        } else if (!strncmp(*av, "flush", strlen(*av))) {
-               flush();
+               rule_flush();
        } else if (!strncmp(*av, "list", strlen(*av))) {
-               load_modules();
-               list(ac, av);
+               module_load();
+               rule_list(ac, av);
        } else if (!strncmp(*av, "show", strlen(*av))) {
                do_acct++;
-               load_modules();
-               list(ac, av);
+               module_load();
+               rule_list(ac, av);
        } else if (!strncmp(*av, "zero", strlen(*av))) {
-               zero(ac, av);
+               rule_zero(ac, av);
        } else if (!strncmp(*av, "set", strlen(*av))) {
-               sets_handler(ac, av);
+               set_main(ac, av);
        } else if (!strncmp(*av, "module", strlen(*av))) {
                NEXT_ARG;
                if (!strncmp(*av, "list", strlen(*av))) {
-                       list_modules(ac, av);
+                       module_list(ac, av);
                } else {
-                       errx(EX_USAGE, "bad ipfw module command `%s'", *av);
+                       errx(EX_USAGE, "bad ipfw3 module command `%s'", *av);
                }
-       } else if (!strncmp(*av, "resetlog", strlen(*av))) {
-               resetlog(ac, av);
        } else if (!strncmp(*av, "log", strlen(*av))) {
                NEXT_ARG;
-               if (!strncmp(*av, "reset", strlen(*av))) {
-                       resetlog(ac, av);
-               } else if (!strncmp(*av, "off", strlen(*av))) {
-
-               } else if (!strncmp(*av, "on", strlen(*av))) {
-
-               } else {
-                       errx(EX_USAGE, "bad command `%s'", *av);
-               }
+               log_main(ac, av);
        } else if (!strncmp(*av, "nat", strlen(*av))) {
                NEXT_ARG;
                nat_main(ac, av);
        } else if (!strncmp(*av, "pipe", strlen(*av)) ||
                !strncmp(*av, "queue", strlen(*av))) {
                NEXT_ARG;
-               if (!strncmp(*av, "config", strlen(*av))) {
-                       config_dummynet(ac, av);
-               } else if (!strncmp(*av, "flush", strlen(*av))) {
-                       flush();
-               } else if (!strncmp(*av, "show", strlen(*av))) {
-                       show_dummynet(ac, av);
-               } else {
-                       errx(EX_USAGE, "bad ipfw pipe command `%s'", *av);
-               }
+               dummynet_main(ac, av);
        } else if (!strncmp(*av, "state", strlen(*av))) {
                NEXT_ARG;
-               if (!strncmp(*av, "add", strlen(*av))) {
-                       add_state(ac, av);
-               } else if (!strncmp(*av, "delete", strlen(*av))) {
-                       delete_state(ac, av);
-               } else if (!strncmp(*av, "flush", strlen(*av))) {
-                       flush_state(ac, av);
-               } else if (!strncmp(*av, "list", strlen(*av))) {
-                       do_dynamic = 2;
-                       list(ac, av);
-               } else if (!strncmp(*av, "show", strlen(*av))) {
-                       do_acct = 1;
-                       do_dynamic =2;
-                       list(ac, av);
-               } else {
-                       errx(EX_USAGE, "bad ipfw state command `%s'", *av);
-               }
+               state_main(ac, av);
        } else if (!strncmp(*av, "table", strlen(*av))) {
                if (ac > 2 && isdigit(*(av[1]))) {
                        char *p = av[1];
@@ -2545,81 +1071,18 @@ ipfw_main(int ac, char **av)
                        av[2] = p;
                }
                NEXT_ARG;
-               if (!strncmp(*av, "append", strlen(*av))) {
-                       table_append(ac, av);
-               } else if (!strncmp(*av, "remove", strlen(*av))) {
-                       table_remove(ac, av);
-               } else if (!strncmp(*av, "flush", strlen(*av))) {
-                       table_flush(ac, av);
-               } else if (!strncmp(*av, "list", strlen(*av))) {
-                       table_list(ac, av);
-               } else if (!strncmp(*av, "show", strlen(*av))) {
-                       table_show(ac, av);
-               } else if (!strncmp(*av, "type", strlen(*av))) {
-                       table_create(ac, av);
-               } else if (!strncmp(*av, "delete", strlen(*av))) {
-                       table_delete(ac, av);
-               } else if (!strncmp(*av, "test", strlen(*av))) {
-                       table_test(ac,av);
-               } else if (!strncmp(*av, "name", strlen(*av))) {
-                       table_rename(ac, av);
-               } else {
-                       errx(EX_USAGE, "bad ipfw table command `%s'", *av);
-               }
+               table_main(ac, av);
        } else if (!strncmp(*av, "sync", strlen(*av))) {
                NEXT_ARG;
-               if (!strncmp(*av, "edge", strlen(*av))) {
-                       sync_config_edge(ac, av);
-               } else if (!strncmp(*av, "centre", strlen(*av))) {
-                       sync_config_centre(ac, av);
-               } else if (!strncmp(*av, "show", strlen(*av))) {
-                       NEXT_ARG;
-                       if (!strncmp(*av, "config", strlen(*av))) {
-                               sync_show_config(ac, av);
-                       } else if (!strncmp(*av, "status", strlen(*av))) {
-                               sync_show_status(ac, av);
-                       } else {
-                               errx(EX_USAGE, "bad show command `%s'", *av);
-                       }
-               } else if (!strncmp(*av, "start", strlen(*av))) {
-                       NEXT_ARG;
-                       if (!strncmp(*av, "edge", strlen(*av))) {
-                               sync_edge_start(ac, av);
-                       } else if (!strncmp(*av, "centre", strlen(*av))) {
-                               sync_centre_start(ac, av);
-                       }
-               } else if (!strncmp(*av, "stop", strlen(*av))) {
-                       NEXT_ARG;
-                       if (!strncmp(*av, "edge", strlen(*av))) {
-                               sync_edge_stop(ac, av);
-                       } else if (!strncmp(*av, "centre", strlen(*av))) {
-                               sync_centre_stop(ac, av);
-                       }
-               } else if (!strncmp(*av, "clear", strlen(*av))) {
-                       NEXT_ARG;
-                       if (!strncmp(*av, "edge", strlen(*av))) {
-                               sync_edge_clear(ac, av);
-                       } else if (!strncmp(*av, "centre", strlen(*av))) {
-                               sync_centre_clear(ac, av);
-                       }
-               } else if (!strncmp(*av, "test", strlen(*av))) {
-                       NEXT_ARG;
-                       if (!strncmp(*av, "edge", strlen(*av))) {
-                               sync_edge_test(ac, av);
-                       } else if (!strncmp(*av, "centre", strlen(*av))) {
-                               sync_centre_test(ac, av);
-                       }
-               } else {
-                       errx(EX_USAGE, "bad ipfw sync command `%s'", *av);
-               }
+               sync_main(ac, av);
        } else {
-               errx(EX_USAGE, "bad ipfw command `%s'", *av);
+               errx(EX_USAGE, "bad ipfw3 command `%s'", *av);
        }
        return 0;
 }
 
-static void
-ipfw_readfile(int ac, char *av[])
+void
+ipfw3_readfile(int ac, char *av[])
 {
        char    buf[BUFSIZ];
        char    *a, *p, *args[MAX_ARGS], *cmd = NULL;
@@ -2736,7 +1199,7 @@ ipfw_readfile(int ac, char *av[])
                        errx(EX_USAGE, "%s: too many arguments", linename);
 
                args[i] = NULL;
-               ipfw_main(i, args);
+               ipfw3_main(i, args);
        }
        fclose(f);
        if (pflag) {
@@ -2754,18 +1217,18 @@ ipfw_readfile(int ac, char *av[])
 int
 main(int ac, char *av[])
 {
-       ipfw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
-       if (ipfw_socket < 0)
+       fw3_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+       if (fw3_socket < 0)
                err(EX_UNAVAILABLE, "socket");
 
-       memset(keywords, 0, sizeof(struct ipfw_keyword) * KEYWORD_SIZE);
-       memset(mappings, 0, sizeof(struct ipfw_mapping) * MAPPING_SIZE);
+       memset(keywords, 0, LEN_FW3_KEYWORD * KEYWORD_SIZE);
+       memset(mappings, 0, LEN_FW3_MAPPING * MAPPING_SIZE);
 
        prepare_default_funcs();
 
        if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0)
-               ipfw_readfile(ac, av);
+               ipfw3_readfile(ac, av);
        else
-               ipfw_main(ac, av);
+               ipfw3_main(ac, av);
        return EX_OK;
 }
index b60a6cc..5e8021b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 - 2016 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2014 - 2018 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
  * by Bill Yuan <bycn82@dragonflybsd.org>
@@ -121,10 +121,52 @@ typedef void (*register_func)(int, int, parser_func, shower_func);
 typedef void (*register_keyword)(int, int, char *, int);
 typedef void (*init_module)(register_func, register_keyword);
 
+#define MAX_KEYWORD_LEN        20
+#define KEYWORD_SIZE   256
+#define MAPPING_SIZE   256
+
+struct ipfw3_keyword {
+       int type;
+       char word[MAX_KEYWORD_LEN];
+       int module;
+       int opcode;
+};
+#define LEN_FW3_KEYWORD sizeof(struct ipfw3_keyword)
+
+struct ipfw3_mapping {
+       int type;
+       int module;
+       int opcode;
+       parser_func parser;
+       shower_func shower;
+};
+#define LEN_FW3_MAPPING sizeof(struct ipfw3_mapping)
+
+ipfw_insn*     next_cmd(ipfw_insn *cmd);
 void   register_ipfw_keyword(int module, int opcode, char *word, int type);
 void   register_ipfw_func(int, int, parser_func, shower_func);
 int    do_get_x(int optname, void *rule, int *optlen);
 int    do_set_x(int optname, void *rule, int optlen);
 
 int    match_token(struct char_int_map *table, char *string);
+void   module_get(char *modules_str, int len);
+void   module_list(int ac, char **av);
+void   module_load(void);
+void   register_ipfw_keyword(int module, int opcode, char *word, int type);
+void   register_ipfw_func(int module, int opcode,
+                       parser_func parser, shower_func shower);
+void   prev_show_chk(ipfw_insn *cmd, uint8_t *prev_module,
+                       uint8_t *prev_opcode, int *show_or);
+int    show_filter(ipfw_insn *cmd, char *word, int type);
+void   help(void);
+void   rule_delete(int ac, char **av);
+void   rule_list(int ac, char **av);
+void   rule_add(int ac, char **av);
+void   rule_zero(int ac, char **av);
+void   rule_flush(void);
+void   rule_show(struct ipfw_ioc_rule *rule, int pcwidth, int bcwidth);
+int    do_set_x(int optname, void *rule, int optlen);
+int    do_get_x(int optname, void *rule, int *optlen);
+int    ipfw3_main(int ac, char **av);
+void   ipfw3_readfile(int ac, char **av);
 #endif
diff --git a/sbin/ipfw3/ipfw3basic.c b/sbin/ipfw3/ipfw3basic.c
new file mode 100644 (file)
index 0000000..ceb54ff
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2014 - 2018 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Bill Yuan <bycn82@dragonflybsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <dlfcn.h>
+#include <err.h>
+#include <errno.h>
+#include <grp.h>
+#include <limits.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <sysexits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <timeconv.h>
+#include <unistd.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/tcp.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <net/ethernet.h>
+
+#include <net/ipfw3/ip_fw3.h>
+#include <net/ipfw3_basic/ip_fw3_table.h>
+#include <net/ipfw3_basic/ip_fw3_sync.h>
+#include <net/ipfw3_basic/ip_fw3_basic.h>
+#include <net/ipfw3_nat/ip_fw3_nat.h>
+#include <net/dummynet3/ip_dummynet3.h>
+
+#include "ipfw3.h"
+#include "ipfw3basic.h"
+
+
+void
+parse_accept(ipfw_insn **cmd, int *ac, char **av[])
+{
+       (*cmd)->opcode = O_BASIC_ACCEPT;
+       (*cmd)->module = MODULE_BASIC_ID;
+       (*cmd)->len = (*cmd)->len|LEN_OF_IPFWINSN;
+       NEXT_ARG1;
+       if (!strncmp(**av, "log", strlen(**av))) {
+               (*cmd)->arg3 = 1;
+               NEXT_ARG1;
+               if (isdigit(***av)) {
+                       (*cmd)->arg1 = strtoul(**av, NULL, 10);
+                       NEXT_ARG1;
+               }
+       }
+}
+
+void
+parse_deny(ipfw_insn **cmd, int *ac, char **av[])
+{
+       (*cmd)->opcode = O_BASIC_DENY;
+       (*cmd)->module = MODULE_BASIC_ID;
+       (*cmd)->len = (*cmd)->len|LEN_OF_IPFWINSN;
+       NEXT_ARG1;
+       if (!strncmp(**av, "log", strlen(**av))) {
+               (*cmd)->arg3 = 1;
+               NEXT_ARG1;
+               if (isdigit(***av)) {
+                       (*cmd)->arg1 = strtoul(**av, NULL, 10);
+                       NEXT_ARG1;
+               }
+       }
+}
+
+void
+show_accept(ipfw_insn *cmd, int show_or)
+{
+       printf(" allow");
+       if (cmd->arg3) {
+               printf(" log %d", cmd->arg1);
+       }
+}
+
+void
+show_deny(ipfw_insn *cmd, int show_or)
+{
+       printf(" deny");
+       if (cmd->arg3) {
+               printf(" log %d", cmd->arg1);
+       }
+}
+
+void
+prepare_default_funcs(void)
+{
+       /* register allow */
+       register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_ACCEPT, "allow", ACTION);
+       register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_ACCEPT, "accept", ACTION);
+       register_ipfw_func(MODULE_BASIC_ID, O_BASIC_ACCEPT,
+                       (parser_func)parse_accept, (shower_func)show_accept);
+       /* register deny */
+       register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_DENY, "deny", ACTION);
+       register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_DENY, "reject", ACTION);
+       register_ipfw_func(MODULE_BASIC_ID, O_BASIC_DENY,
+                       (parser_func)parse_deny, (shower_func)show_deny);
+}
+
similarity index 82%
copy from lib/libipfw3/nat/ipfw3_nat.h
copy to sbin/ipfw3/ipfw3basic.h
index 938e970..dc6c4b6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 - 2016 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2014 - 2018 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
  * by Bill Yuan <bycn82@dragonflybsd.org>
  * SUCH DAMAGE.
  */
 
-#ifndef _IPFW_NAT_H
-#define _IPFW_NAT_H
+#ifndef _IPFW3BASIC_H_
+#define _IPFW3BASIC_H_
 
-#include <net/ipfw3_nat/ip_fw3_nat.h>
+void   parse_accept(ipfw_insn **cmd, int *ac, char **av[]);
+void   parse_deny(ipfw_insn **cmd, int *ac, char **av[]);
+void   show_accept(ipfw_insn *cmd, int show_or);
+void   show_deny(ipfw_insn *cmd, int show_or);
 
+void   prepare_default_funcs(void);
 #endif
diff --git a/sbin/ipfw3/ipfw3dummynet.c b/sbin/ipfw3/ipfw3dummynet.c
new file mode 100644 (file)
index 0000000..e3d0b40
--- /dev/null
@@ -0,0 +1,727 @@
+/*
+ * Copyright (c) 2014 - 2018 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Bill Yuan <bycn82@dragonflybsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <dlfcn.h>
+#include <err.h>
+#include <errno.h>
+#include <grp.h>
+#include <limits.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <sysexits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <timeconv.h>
+#include <unistd.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/tcp.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <net/ethernet.h>
+
+#include <net/ipfw3/ip_fw3.h>
+#include <net/ipfw3_basic/ip_fw3_table.h>
+#include <net/ipfw3_basic/ip_fw3_sync.h>
+#include <net/ipfw3_basic/ip_fw3_basic.h>
+#include <net/ipfw3_nat/ip_fw3_nat.h>
+#include <net/dummynet3/ip_dummynet3.h>
+
+#include "ipfw3.h"
+#include "ipfw3dummynet.h"
+
+
+extern int verbose;
+extern int do_time;
+extern int do_quiet;
+extern int do_force;
+extern int do_pipe;
+extern int do_sort;
+
+
+struct char_int_map dummynet_params[] = {
+       { "plr",                TOK_PLR },
+       { "noerror",            TOK_NOERROR },
+       { "buckets",            TOK_BUCKETS },
+       { "dst-ip",             TOK_DSTIP },
+       { "src-ip",             TOK_SRCIP },
+       { "dst-port",           TOK_DSTPORT },
+       { "src-port",           TOK_SRCPORT },
+       { "proto",              TOK_PROTO },
+       { "weight",             TOK_WEIGHT },
+       { "all",                TOK_ALL },
+       { "mask",               TOK_MASK },
+       { "droptail",           TOK_DROPTAIL },
+       { "red",                TOK_RED },
+       { "gred",               TOK_GRED },
+       { "bw",                 TOK_BW },
+       { "bandwidth",          TOK_BW },
+       { "delay",              TOK_DELAY },
+       { "pipe",               TOK_PIPE },
+       { "queue",              TOK_QUEUE },
+       { "dummynet-params",    TOK_NULL },
+       { NULL, 0 }
+};
+
+
+int
+sort_q(const void *pa, const void *pb)
+{
+       int rev = (do_sort < 0);
+       int field = rev ? -do_sort : do_sort;
+       long long res = 0;
+       const struct dn_ioc_flowqueue *a = pa;
+       const struct dn_ioc_flowqueue *b = pb;
+
+       switch(field) {
+       case 1: /* pkts */
+               res = a->len - b->len;
+               break;
+       case 2: /* bytes */
+               res = a->len_bytes - b->len_bytes;
+               break;
+
+       case 3: /* tot pkts */
+               res = a->tot_pkts - b->tot_pkts;
+               break;
+
+       case 4: /* tot bytes */
+               res = a->tot_bytes - b->tot_bytes;
+               break;
+       }
+       if (res < 0)
+               res = -1;
+       if (res > 0)
+               res = 1;
+       return (int)(rev ? res : -res);
+}
+
+
+
+/*
+ * config dummynet pipe/queue
+ */
+void
+config_dummynet(int ac, char **av)
+{
+       struct dn_ioc_pipe pipe;
+       u_int32_t a;
+       void *par = NULL;
+       int i;
+       char *end;
+
+       NEXT_ARG;
+       memset(&pipe, 0, sizeof pipe);
+       /* Pipe number */
+       if (ac && isdigit(**av)) {
+               i = atoi(*av);
+               NEXT_ARG;
+               if (do_pipe == 1)
+                       pipe.pipe_nr = i;
+               else
+                       pipe.fs.fs_nr = i;
+       }
+
+       while (ac > 0) {
+               double d;
+
+               int tok = match_token(dummynet_params, *av);
+               NEXT_ARG;
+
+               switch(tok) {
+               case TOK_NOERROR:
+                       pipe.fs.flags_fs |= DN_NOERROR;
+                       break;
+
+               case TOK_PLR:
+                       NEED1("plr needs argument 0..1\n");
+                       d = strtod(av[0], NULL);
+                       if (d > 1)
+                               d = 1;
+                       else if (d < 0)
+                               d = 0;
+                       pipe.fs.plr = (int)(d*0x7fffffff);
+                       NEXT_ARG;
+                       break;
+
+               case TOK_QUEUE:
+                       NEED1("queue needs queue size\n");
+                       end = NULL;
+                       pipe.fs.qsize = getbw(av[0], &pipe.fs.flags_fs, 1024);
+                       NEXT_ARG;
+                       break;
+
+               case TOK_BUCKETS:
+                       NEED1("buckets needs argument\n");
+                       pipe.fs.rq_size = strtoul(av[0], NULL, 0);
+                       NEXT_ARG;
+                       break;
+
+               case TOK_MASK:
+                       NEED1("mask needs mask specifier\n");
+                       /*
+                        * per-flow queue, mask is dst_ip, dst_port,
+                        * src_ip, src_port, proto measured in bits
+                        */
+                       par = NULL;
+
+                       pipe.fs.flow_mask.type = ETHERTYPE_IP;
+                       pipe.fs.flow_mask.u.ip.dst_ip = 0;
+                       pipe.fs.flow_mask.u.ip.src_ip = 0;
+                       pipe.fs.flow_mask.u.ip.dst_port = 0;
+                       pipe.fs.flow_mask.u.ip.src_port = 0;
+                       pipe.fs.flow_mask.u.ip.proto = 0;
+                       end = NULL;
+
+                       while (ac >= 1) {
+                               u_int32_t *p32 = NULL;
+                               u_int16_t *p16 = NULL;
+
+                               tok = match_token(dummynet_params, *av);
+                               NEXT_ARG;
+                               switch(tok) {
+                               case TOK_ALL:
+                                       /*
+                                        * special case, all bits significant
+                                        */
+                                       pipe.fs.flow_mask.u.ip.dst_ip = ~0;
+                                       pipe.fs.flow_mask.u.ip.src_ip = ~0;
+                                       pipe.fs.flow_mask.u.ip.dst_port = ~0;
+                                       pipe.fs.flow_mask.u.ip.src_port = ~0;
+                                       pipe.fs.flow_mask.u.ip.proto = ~0;
+                                       pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK;
+                                       goto end_mask;
+
+                               case TOK_DSTIP:
+                                       p32 = &pipe.fs.flow_mask.u.ip.dst_ip;
+                                       break;
+
+                               case TOK_SRCIP:
+                                       p32 = &pipe.fs.flow_mask.u.ip.src_ip;
+                                       break;
+
+                               case TOK_DSTPORT:
+                                       p16 = &pipe.fs.flow_mask.u.ip.dst_port;
+                                       break;
+
+                               case TOK_SRCPORT:
+                                       p16 = &pipe.fs.flow_mask.u.ip.src_port;
+                                       break;
+
+                               case TOK_PROTO:
+                                       break;
+
+                               default:
+                                       NEXT_ARG;
+                                       goto end_mask;
+                               }
+                               if (ac < 1)
+                                       errx(EX_USAGE, "mask: value missing");
+                               if (*av[0] == '/') {
+                                       a = strtoul(av[0]+1, &end, 0);
+                                       a = (a == 32) ? ~0 : (1 << a) - 1;
+                               } else
+                                       a = strtoul(av[0], &end, 0);
+                               if (p32 != NULL)
+                                       *p32 = a;
+                               else if (p16 != NULL) {
+                                       if (a > 65535)
+                                               errx(EX_DATAERR,
+                                               "mask: must be 16 bit");
+                                       *p16 = (u_int16_t)a;
+                               } else {
+                                       if (a > 255)
+                                               errx(EX_DATAERR,
+                                               "mask: must be 8 bit");
+                                       pipe.fs.flow_mask.u.ip.proto =
+                                               (uint8_t)a;
+                               }
+                               if (a != 0)
+                                       pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK;
+                               NEXT_ARG;
+                       } /* end while, config masks */
+
+end_mask:
+                       break;
+
+               case TOK_RED:
+               case TOK_GRED:
+                       NEED1("red/gred needs w_q/min_th/max_th/max_p\n");
+                       pipe.fs.flags_fs |= DN_IS_RED;
+                       if (tok == TOK_GRED)
+                               pipe.fs.flags_fs |= DN_IS_GENTLE_RED;
+                       /*
+                        * the format for parameters is w_q/min_th/max_th/max_p
+                        */
+                       if ((end = strsep(&av[0], "/"))) {
+                               double w_q = strtod(end, NULL);
+                               if (w_q > 1 || w_q <= 0)
+                                       errx(EX_DATAERR, "0 < w_q <= 1");
+                               pipe.fs.w_q = (int) (w_q * (1 << SCALE_RED));
+                       }
+                       if ((end = strsep(&av[0], "/"))) {
+                               pipe.fs.min_th = strtoul(end, &end, 0);
+                               if (*end == 'K' || *end == 'k')
+                                       pipe.fs.min_th *= 1024;
+                       }
+                       if ((end = strsep(&av[0], "/"))) {
+                               pipe.fs.max_th = strtoul(end, &end, 0);
+                               if (*end == 'K' || *end == 'k')
+                                       pipe.fs.max_th *= 1024;
+                       }
+                       if ((end = strsep(&av[0], "/"))) {
+                               double max_p = strtod(end, NULL);
+                               if (max_p > 1 || max_p <= 0)
+                                       errx(EX_DATAERR, "0 < max_p <= 1");
+                               pipe.fs.max_p = (int)(max_p * (1 << SCALE_RED));
+                       }
+                       NEXT_ARG;
+                       break;
+
+               case TOK_DROPTAIL:
+                       pipe.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED);
+                       break;
+
+               case TOK_BW:
+                       NEED1("bw needs bandwidth\n");
+                       if (do_pipe != 1)
+                               errx(EX_DATAERR,
+                                       "bandwidth only valid for pipes");
+                       /*
+                        * set bandwidth value
+                        */
+                       pipe.bandwidth = getbw(av[0], NULL, 1000);
+                       if (pipe.bandwidth < 0)
+                               errx(EX_DATAERR, "bandwidth too large");
+                       NEXT_ARG;
+                       break;
+
+               case TOK_DELAY:
+                       if (do_pipe != 1)
+                               errx(EX_DATAERR, "delay only valid for pipes");
+                       NEED1("delay needs argument 0..10000ms\n");
+                       pipe.delay = strtoul(av[0], NULL, 0);
+                       NEXT_ARG;
+                       break;
+
+               case TOK_WEIGHT:
+                       if (do_pipe == 1)
+                               errx(EX_DATAERR,
+                                       "weight only valid for queues");
+                       NEED1("weight needs argument 0..100\n");
+                       pipe.fs.weight = strtoul(av[0], &end, 0);
+                       NEXT_ARG;
+                       break;
+
+               case TOK_PIPE:
+                       if (do_pipe == 1)
+                               errx(EX_DATAERR, "pipe only valid for queues");
+                       NEED1("pipe needs pipe_number\n");
+                       pipe.fs.parent_nr = strtoul(av[0], &end, 0);
+                       NEXT_ARG;
+                       break;
+
+               default:
+                       errx(EX_DATAERR, "unrecognised option ``%s''", *av);
+               }
+       }
+       if (do_pipe == 1) {
+               if (pipe.pipe_nr == 0)
+                       errx(EX_DATAERR, "pipe_nr must be > 0");
+               if (pipe.delay > 10000)
+                       errx(EX_DATAERR, "delay must be < 10000");
+       } else { /* do_pipe == 2, queue */
+               if (pipe.fs.parent_nr == 0)
+                       errx(EX_DATAERR, "pipe must be > 0");
+               if (pipe.fs.weight >100)
+                       errx(EX_DATAERR, "weight must be <= 100");
+       }
+       if (pipe.fs.flags_fs & DN_QSIZE_IS_BYTES) {
+               if (pipe.fs.qsize > 1024*1024)
+                       errx(EX_DATAERR, "queue size must be < 1MB");
+       } else {
+               if (pipe.fs.qsize > 100)
+                       errx(EX_DATAERR, "2 <= queue size <= 100");
+       }
+       if (pipe.fs.flags_fs & DN_IS_RED) {
+               size_t len;
+               int lookup_depth, avg_pkt_size;
+               double s, idle, weight, w_q;
+               int clock_hz;
+               int t;
+
+               if (pipe.fs.min_th >= pipe.fs.max_th)
+                       errx(EX_DATAERR, "min_th %d must be < than max_th %d",
+                       pipe.fs.min_th, pipe.fs.max_th);
+               if (pipe.fs.max_th == 0)
+                       errx(EX_DATAERR, "max_th must be > 0");
+
+               len = sizeof(int);
+               if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth",
+                       &lookup_depth, &len, NULL, 0) == -1)
+
+                       errx(1, "sysctlbyname(\"%s\")",
+                               "net.inet.ip.dummynet.red_lookup_depth");
+               if (lookup_depth == 0)
+                       errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth"
+                               " must be greater than zero");
+
+               len = sizeof(int);
+               if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size",
+                       &avg_pkt_size, &len, NULL, 0) == -1)
+
+                       errx(1, "sysctlbyname(\"%s\")",
+                               "net.inet.ip.dummynet.red_avg_pkt_size");
+               if (avg_pkt_size == 0)
+                       errx(EX_DATAERR,
+                               "net.inet.ip.dummynet.red_avg_pkt_size must"
+                               " be greater than zero");
+
+               len = sizeof(clock_hz);
+               if (sysctlbyname("net.inet.ip.dummynet.hz", &clock_hz, &len,
+                                NULL, 0) == -1) {
+                       errx(1, "sysctlbyname(\"%s\")",
+                                "net.inet.ip.dummynet.hz");
+               }
+
+               /*
+                * Ticks needed for sending a medium-sized packet.
+                * Unfortunately, when we are configuring a WF2Q+ queue, we
+                * do not have bandwidth information, because that is stored
+                * in the parent pipe, and also we have multiple queues
+                * competing for it. So we set s=0, which is not very
+                * correct. But on the other hand, why do we want RED with
+                * WF2Q+ ?
+                */
+               if (pipe.bandwidth == 0) /* this is a WF2Q+ queue */
+                       s = 0;
+               else
+                       s = clock_hz * avg_pkt_size * 8 / pipe.bandwidth;
+
+               /*
+                * max idle time (in ticks) before avg queue size becomes 0.
+                * NOTA: (3/w_q) is approx the value x so that
+                * (1-w_q)^x < 10^-3.
+                */
+               w_q = ((double)pipe.fs.w_q) / (1 << SCALE_RED);
+               idle = s * 3. / w_q;
+               pipe.fs.lookup_step = (int)idle / lookup_depth;
+               if (!pipe.fs.lookup_step)
+                       pipe.fs.lookup_step = 1;
+               weight = 1 - w_q;
+               for (t = pipe.fs.lookup_step; t > 0; --t)
+                       weight *= weight;
+               pipe.fs.lookup_weight = (int)(weight * (1 << SCALE_RED));
+       }
+       i = do_set_x(IP_DUMMYNET_CONFIGURE, &pipe, sizeof pipe);
+       if (i)
+               err(1, "do_set_x(%s)", "IP_DUMMYNET_CONFIGURE");
+}
+
+
+void
+show_dummynet(int ac, char *av[])
+{
+       void *data = NULL;
+       int nbytes;
+       int nalloc = 1024;      /* start somewhere... */
+
+       NEXT_ARG;
+
+       nbytes = nalloc;
+       while (nbytes >= nalloc) {
+               nalloc = nalloc * 2 + 200;
+               nbytes = nalloc;
+               if ((data = realloc(data, nbytes)) == NULL)
+                       err(EX_OSERR, "realloc");
+               if (do_get_x(IP_DUMMYNET_GET, data, &nbytes) < 0) {
+                       err(EX_OSERR, "do_get_x(IP_%s_GET)",
+                               do_pipe ? "DUMMYNET" : "FW");
+               }
+       }
+
+       show_pipes(data, nbytes, ac, av);
+       free(data);
+}
+
+void
+show_pipes(void *data, int nbytes, int ac, char *av[])
+{
+       u_long rulenum;
+       void *next = data;
+       struct dn_ioc_pipe *p = (struct dn_ioc_pipe *)data;
+       struct dn_ioc_flowset *fs;
+       struct dn_ioc_flowqueue *q;
+       int l;
+
+       if (ac > 0)
+               rulenum = strtoul(*av++, NULL, 10);
+       else
+               rulenum = 0;
+       for (; nbytes >= sizeof(*p); p = (struct dn_ioc_pipe *)next) {
+               double b = p->bandwidth;
+               char buf[30];
+               char prefix[80];
+
+               if (p->fs.fs_type != DN_IS_PIPE)
+                       break;  /* done with pipes, now queues */
+
+               /*
+                * compute length, as pipe have variable size
+                */
+               l = sizeof(*p) + p->fs.rq_elements * sizeof(*q);
+               next = (void *)p + l;
+               nbytes -= l;
+
+               if (rulenum != 0 && rulenum != p->pipe_nr)
+                       continue;
+
+               /*
+                * Print rate
+                */
+               if (b == 0)
+                       sprintf(buf, "unlimited");
+               else if (b >= 1000000)
+                       sprintf(buf, "%7.3f Mbit/s", b/1000000);
+               else if (b >= 1000)
+                       sprintf(buf, "%7.3f Kbit/s", b/1000);
+               else
+                       sprintf(buf, "%7.3f bit/s ", b);
+
+               sprintf(prefix, "%05d: %s %4d ms ",
+                       p->pipe_nr, buf, p->delay);
+               show_flowset_parms(&p->fs, prefix);
+               if (verbose)
+                       printf(" V %20ju\n", (uintmax_t)p->V >> MY_M);
+
+               q = (struct dn_ioc_flowqueue *)(p+1);
+               show_queues(&p->fs, q);
+       }
+
+       for (fs = next; nbytes >= sizeof(*fs); fs = next) {
+               char prefix[80];
+
+               if (fs->fs_type != DN_IS_QUEUE)
+                       break;
+               l = sizeof(*fs) + fs->rq_elements * sizeof(*q);
+               next = (void *)fs + l;
+               nbytes -= l;
+               q = (struct dn_ioc_flowqueue *)(fs+1);
+               sprintf(prefix, "q%05d: weight %d pipe %d ",
+                       fs->fs_nr, fs->weight, fs->parent_nr);
+               show_flowset_parms(fs, prefix);
+               show_queues(fs, q);
+       }
+}
+
+void
+show_queues(struct dn_ioc_flowset *fs, struct dn_ioc_flowqueue *q)
+{
+       int l;
+
+       printf("mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
+               fs->flow_mask.u.ip.proto,
+               fs->flow_mask.u.ip.src_ip, fs->flow_mask.u.ip.src_port,
+               fs->flow_mask.u.ip.dst_ip, fs->flow_mask.u.ip.dst_port);
+       if (fs->rq_elements == 0)
+               return;
+
+       printf("BKT Prot ___Source IP/port____ "
+               "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
+       if (do_sort != 0)
+               heapsort(q, fs->rq_elements, sizeof(*q), sort_q);
+       for (l = 0; l < fs->rq_elements; l++) {
+               struct in_addr ina;
+               struct protoent *pe;
+
+               ina.s_addr = htonl(q[l].id.u.ip.src_ip);
+               printf("%3d ", q[l].hash_slot);
+               pe = getprotobynumber(q[l].id.u.ip.proto);
+               if (pe)
+                       printf("%-4s ", pe->p_name);
+               else
+                       printf("%4u ", q[l].id.u.ip.proto);
+               printf("%15s/%-5d ",
+                       inet_ntoa(ina), q[l].id.u.ip.src_port);
+               ina.s_addr = htonl(q[l].id.u.ip.dst_ip);
+               printf("%15s/%-5d ",
+                       inet_ntoa(ina), q[l].id.u.ip.dst_port);
+               printf("%4ju %8ju %2u %4u %3u\n",
+                       (uintmax_t)q[l].tot_pkts, (uintmax_t)q[l].tot_bytes,
+                       q[l].len, q[l].len_bytes, q[l].drops);
+               if (verbose)
+                       printf(" S %20ju F %20ju\n",
+                               (uintmax_t)q[l].S, (uintmax_t)q[l].F);
+       }
+}
+
+void
+show_flowset_parms(struct dn_ioc_flowset *fs, char *prefix)
+{
+       char qs[30];
+       char plr[30];
+       char red[90];   /* Display RED parameters */
+       int l;
+
+       l = fs->qsize;
+       if (fs->flags_fs & DN_QSIZE_IS_BYTES) {
+               if (l >= 8192)
+                       sprintf(qs, "%d KB", l / 1024);
+               else
+                       sprintf(qs, "%d B", l);
+       } else
+               sprintf(qs, "%3d sl.", l);
+       if (fs->plr)
+               sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff));
+       else
+               plr[0] = '\0';
+       if (fs->flags_fs & DN_IS_RED)   /* RED parameters */
+               sprintf(red,
+                       "\n\t %cRED w_q %f min_th %d max_th %d max_p %f",
+                       (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ',
+                       1.0 * fs->w_q / (double)(1 << SCALE_RED),
+                       SCALE_VAL(fs->min_th),
+                       SCALE_VAL(fs->max_th),
+                       1.0 * fs->max_p / (double)(1 << SCALE_RED));
+       else
+               sprintf(red, "droptail");
+
+       printf("%s %s%s %d queues (%d buckets) %s\n",
+               prefix, qs, plr, fs->rq_elements, fs->rq_size, red);
+}
+
+unsigned long
+getbw(const char *str, u_short *flags, int kb)
+{
+       unsigned long val;
+       int inbytes = 0;
+       char *end;
+
+       val = strtoul(str, &end, 0);
+       if (*end == 'k' || *end == 'K') {
+               ++end;
+               val *= kb;
+       } else if (*end == 'm' || *end == 'M') {
+               ++end;
+               val *= kb * kb;
+       }
+
+       /*
+        * Deal with bits or bytes or b(bits) or B(bytes). If there is no
+        * trailer assume bits.
+        */
+       if (strncasecmp(end, "bit", 3) == 0) {
+               ;
+       } else if (strncasecmp(end, "byte", 4) == 0) {
+               inbytes = 1;
+       } else if (*end == 'b') {
+               ;
+       } else if (*end == 'B') {
+               inbytes = 1;
+       }
+
+       /*
+        * Return in bits if flags is NULL, else flag bits
+        * or bytes in flags and return the unconverted value.
+        */
+       if (inbytes && flags)
+               *flags |= DN_QSIZE_IS_BYTES;
+       else if (inbytes && flags == NULL)
+               val *= 8;
+
+       return(val);
+}
+
+void
+dummynet_flush(void)
+{
+       int cmd = IP_FW_FLUSH;
+       if (do_pipe) {
+               cmd = IP_DUMMYNET_FLUSH;
+       }
+       if (!do_force) {
+               int c;
+
+               printf("Are you sure? [yn] ");
+               fflush(stdout);
+               do {
+                       c = toupper(getc(stdin));
+                       while (c != '\n' && getc(stdin) != '\n')
+                               if (feof(stdin))
+                                       return; /* and do not flush */
+               } while (c != 'Y' && c != 'N');
+               if (c == 'N')   /* user said no */
+                       return;
+       }
+       if (do_set_x(cmd, NULL, 0) < 0 ) {
+               if (do_pipe)
+                       errx(EX_USAGE, "pipe/queue in use");
+               else
+                       errx(EX_USAGE, "do_set_x(IP_FW_FLUSH) failed");
+       }
+       if (!do_quiet) {
+               printf("Flushed all %s.\n", do_pipe ? "pipes" : "rules");
+       }
+}
+
+void
+dummynet_main(int ac, char **av)
+{
+       if (!strncmp(*av, "config", strlen(*av))) {
+               config_dummynet(ac, av);
+       } else if (!strncmp(*av, "flush", strlen(*av))) {
+               dummynet_flush();
+       } else if (!strncmp(*av, "show", strlen(*av))) {
+               show_dummynet(ac, av);
+       } else {
+               errx(EX_USAGE, "bad ipfw pipe command `%s'", *av);
+       }
+}
similarity index 75%
copy from lib/libipfw3/nat/ipfw3_nat.h
copy to sbin/ipfw3/ipfw3dummynet.h
index 938e970..395846b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 - 2016 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2014 - 2018 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
  * by Bill Yuan <bycn82@dragonflybsd.org>
  * SUCH DAMAGE.
  */
 
-#ifndef _IPFW_NAT_H
-#define _IPFW_NAT_H
+#ifndef _IPFW3DUMMYNET_H_
+#define _IPFW3DUMMYNET_H_
 
-#include <net/ipfw3_nat/ip_fw3_nat.h>
 
+int    sort_q(const void *pa, const void *pb);
+
+
+void   config_dummynet(int ac, char **av);
+void   show_dummynet(int ac, char **av);
+void   show_pipes(void *data, int nbytes, int ac, char **av);
+void   show_queues(struct dn_ioc_flowset *fs, struct dn_ioc_flowqueue *q);
+void   show_flowset_parms(struct dn_ioc_flowset *fs, char *prefix);
+
+unsigned long  getbw(const char *str, u_short *flags, int kb);
+void   dummynet_flush(void);
+
+void   dummynet_main(int ac, char **av);
 #endif
diff --git a/sbin/ipfw3/ipfw3log.c b/sbin/ipfw3/ipfw3log.c
new file mode 100644 (file)
index 0000000..4514964
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2014 - 2018 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Bill Yuan <bycn82@dragonflybsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <dlfcn.h>
+#include <err.h>
+#include <errno.h>
+#include <grp.h>
+#include <limits.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <sysexits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <timeconv.h>
+#include <unistd.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/tcp.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <net/ethernet.h>
+
+#include <net/ipfw3/ip_fw3.h>
+#include <net/ipfw3_basic/ip_fw3_table.h>
+#include <net/ipfw3_basic/ip_fw3_sync.h>
+#include <net/ipfw3_basic/ip_fw3_basic.h>
+#include <net/ipfw3_nat/ip_fw3_nat.h>
+#include <net/dummynet3/ip_dummynet3.h>
+
+#include "ipfw3.h"
+#include "ipfw3log.h"
+
+extern int     fw3_socket;
+extern int     do_quiet;
+
+
+void
+resetlog(int ac, char *av[])
+{
+       int rulenum;
+       int failed = EX_OK;
+
+       NEXT_ARG;
+
+       if (!ac) {
+               /* clear all entries */
+               if (setsockopt(fw3_socket, IPPROTO_IP,
+                                       IP_FW_RESETLOG, NULL, 0) < 0)
+                       err(EX_UNAVAILABLE, "setsockopt(IP_FW_RESETLOG)");
+               if (!do_quiet)
+                       printf("Logging counts reset.\n");
+
+               return;
+       }
+
+       while (ac) {
+               /* Rule number */
+               if (isdigit(**av)) {
+                       rulenum = atoi(*av);
+                       NEXT_ARG;
+                       if (setsockopt(fw3_socket, IPPROTO_IP,
+                               IP_FW_RESETLOG, &rulenum, sizeof rulenum)) {
+                               warn("rule %u: setsockopt(IP_FW_RESETLOG)",
+                                               rulenum);
+                               failed = EX_UNAVAILABLE;
+                       } else if (!do_quiet)
+                               printf("Entry %d logging count reset\n",
+                                               rulenum);
+               } else {
+                       errx(EX_DATAERR, "invalid rule number ``%s''", *av);
+               }
+       }
+       if (failed != EX_OK)
+               exit(failed);
+}
+
+void
+log_main(int ac, char **av)
+{
+       if (!strncmp(*av, "reset", strlen(*av))) {
+               resetlog(ac, av);
+       } else if (!strncmp(*av, "off", strlen(*av))) {
+
+       } else if (!strncmp(*av, "on", strlen(*av))) {
+
+       } else {
+               errx(EX_USAGE, "bad command `%s'", *av);
+       }
+}
+
similarity index 90%
copy from lib/libipfw3/nat/ipfw3_nat.h
copy to sbin/ipfw3/ipfw3log.h
index 938e970..edad517 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 - 2016 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2014 - 2018 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
  * by Bill Yuan <bycn82@dragonflybsd.org>
  * SUCH DAMAGE.
  */
 
-#ifndef _IPFW_NAT_H
-#define _IPFW_NAT_H
+#ifndef _IPFW3LOG_H_
+#define _IPFW3LOG_H_
 
-#include <net/ipfw3_nat/ip_fw3_nat.h>
+void   resetlog(int ac, char **av);
 
+void   log_main(int ac, char **av);
 #endif
index a73c5bb..c059598 100644 (file)
 #include <net/ethernet.h>
 
 #include <net/ipfw3/ip_fw3.h>
-#include <net/ipfw3/ip_fw3_table.h>
-#include <net/ipfw3/ip_fw3_sync.h>
-#include <net/dummynet3/ip_dummynet3.h>
+#include <net/ipfw3_basic/ip_fw3_table.h>
+#include <net/ipfw3_basic/ip_fw3_sync.h>
 #include <net/ipfw3_basic/ip_fw3_basic.h>
 #include <net/ipfw3_nat/ip_fw3_nat.h>
+#include <net/dummynet3/ip_dummynet3.h>
 
 #include "ipfw3.h"
 #include "ipfw3nat.h"
diff --git a/sbin/ipfw3/ipfw3set.c b/sbin/ipfw3/ipfw3set.c
new file mode 100644 (file)
index 0000000..a32d70b
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2014 - 2018 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Bill Yuan <bycn82@dragonflybsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <dlfcn.h>
+#include <err.h>
+#include <errno.h>
+#include <grp.h>
+#include <limits.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <sysexits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <timeconv.h>
+#include <unistd.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/tcp.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <net/ethernet.h>
+
+#include <net/ipfw3/ip_fw3.h>
+#include <net/ipfw3_basic/ip_fw3_table.h>
+#include <net/ipfw3_basic/ip_fw3_sync.h>
+#include <net/ipfw3_basic/ip_fw3_basic.h>
+#include <net/ipfw3_nat/ip_fw3_nat.h>
+#include <net/dummynet3/ip_dummynet3.h>
+
+#include "ipfw3.h"
+#include "ipfw3set.h"
+
+void
+set_toggle(int ac, char **av)
+{
+       int error, num;
+
+       NEXT_ARG;
+
+       num = atoi(av[0]);
+       if (num > 0 && num < 32) {
+               error = do_set_x(IP_FW_SET_TOGGLE, &num, sizeof num);
+               if (error) {
+                       err(EX_OSERR, "getsockopt(IP_FW_SET_TOGGLE)");
+               }
+       } else {
+               errx(EX_USAGE, "invalid set %s", *av);
+       }
+}
+
+void
+set_show(int ac, char **av)
+{
+       int i, sets = 0, len;
+
+       len = sizeof(int);
+       if (do_get_x(IP_FW_SET_GET, &sets, &len) < 0) {
+               err(EX_OSERR, "getsockopt(IP_FW_SET_GET)");
+       }
+
+       printf("disable:");
+       for (i = 0; i < 32; i++) {
+               if (sets & (1<<i)) {
+                       printf(" %d", i);
+               }
+       }
+       printf("\n");
+       printf("enable:");
+       for (i = 0; i < 32; i++) {
+               if (!(sets & (1<<i))) {
+                       printf(" %d", i);
+               }
+       }
+       printf("\n");
+}
+
+void
+set_swap(int ac, char **av)
+{
+       int num[2], error;
+
+       NEXT_ARG;
+
+       if (ac != 2)
+               errx(EX_USAGE, "set swap needs 2 set numbers");
+
+       num[0] = atoi(av[0]);
+       num[1] = atoi(av[1]);
+       if (num[0] < 1 || num[0] > 31) {
+                errx(EX_DATAERR, "invalid set number %s", av[0]);
+       }
+       if (num[1] < 1 || num[1] > 31) {
+                errx(EX_DATAERR, "invalid set number %s", av[1]);
+       }
+       if (num[0] == num[1]) {
+                errx(EX_DATAERR, "same set numbers %s", av[0]);
+       }
+
+       error = do_set_x(IP_FW_SET_SWAP, num, sizeof(num));
+       if (error) {
+               err(EX_OSERR, "getsockopt(IP_FW_SET_SWAP)");
+       }
+}
+
+void
+set_move_rule(int ac, char **av)
+{
+       int num[2], error;
+
+       NEXT_ARG;
+
+       if (ac != 2)
+               errx(EX_USAGE, "move rule needs 2 numbers");
+
+       num[0] = atoi(av[0]);
+       num[1] = atoi(av[1]);
+       if (num[0] < 1 || num[0] > 65534) {
+                errx(EX_DATAERR, "invalid rule number %s", av[0]);
+       }
+       if (num[1] < 1 || num[1] > 31) {
+                errx(EX_DATAERR, "invalid set number %s", av[1]);
+       }
+       if (num[0] == num[1]) {
+                errx(EX_DATAERR, "same set numbers %s", av[0]);
+       }
+
+       error = do_set_x(IP_FW_SET_MOVE_RULE, num, sizeof(num));
+       if (error) {
+               err(EX_OSERR, "getsockopt(IP_FW_SET_MOVE_RULE)");
+       }
+}
+
+void
+set_move_set(int ac, char **av)
+{
+       int num[2], error;
+
+       NEXT_ARG;
+
+       if (ac != 2)
+               errx(EX_USAGE, "move set needs 2 set numbers");
+
+       num[0] = atoi(av[0]);
+       num[1] = atoi(av[1]);
+       if (num[0] < 1 || num[0] > 31) {
+                errx(EX_DATAERR, "invalid set number %s", av[0]);
+       }
+       if (num[1] < 1 || num[1] > 31) {
+                errx(EX_DATAERR, "invalid set number %s", av[1]);
+       }
+       if (num[0] == num[1]) {
+                errx(EX_DATAERR, "same set numbers %s", av[0]);
+       }
+
+       error = do_set_x(IP_FW_SET_MOVE_SET, num, sizeof(num));
+       if (error) {
+               err(EX_OSERR, "getsockopt(IP_FW_SET_MOVE_SET)");
+       }
+}
+
+void
+set_flush(int ac, char **av)
+{
+       int error, num;
+
+       NEXT_ARG;
+
+       num = atoi(av[0]);
+       if (num > 0 && num < 32) {
+               error = do_set_x(IP_FW_SET_FLUSH, &num, sizeof num);
+               if (error) {
+                       err(EX_OSERR, "getsockopt(IP_FW_SET_FLUSH)");
+               }
+       } else {
+               errx(EX_USAGE, "invalid set %s", *av);
+       }
+}
+/*
+ * ipfw3 set show
+ * ipfw3 set <set num> toggle
+ * ipfw3 set swap <old set num> <new set num>
+ * ipfw3 set move set <old set num> to <new set num>
+ * ipfw3 set move rule <rule num> to <set num>
+ * ipfw3 set <set num> flush
+ */
+void
+set_main(int ac, char **av)
+{
+       SWAP_ARG;
+       NEXT_ARG;
+
+       if (!ac)
+               errx(EX_USAGE, "set needs command");
+       if (!strncmp(*av, "show", strlen(*av)) ) {
+               set_show(ac, av);
+       } else if (!strncmp(*av, "swap", strlen(*av))) {
+               set_swap(ac, av);
+       } else if (!strncmp(*av, "move", strlen(*av))) {
+               NEXT_ARG;
+               if (!strncmp(*av, "set", strlen(*av)) ) {
+                       set_move_set(ac, av);
+               } else if (!strncmp(*av, "rule", strlen(*av)) ) {
+                       set_move_rule(ac, av);
+               } else {
+                       errx(EX_USAGE, "invalid move command %s", *av);
+               }
+
+       } else if (!strncmp(*av, "toggle", strlen(*av))) {
+               set_toggle(ac, av);
+       } else if (!strncmp(*av, "flush", strlen(*av))) {
+               set_flush(ac, av);
+       } else {
+               errx(EX_USAGE, "invalid set command %s", *av);
+       }
+}
+
similarity index 80%
copy from lib/libipfw3/dummynet/ipfw3_dummynet.h
copy to sbin/ipfw3/ipfw3set.h
index 99eb9e1..0af18ed 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2016 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
  * by Bill Yuan <bycn82@dragonflybsd.org>
  * SUCH DAMAGE.
  */
 
-#ifndef _IPFW_DUMMYNET_H
-#define _IPFW_DUMMYNET_H
+#ifndef _IPFW3SET_H_
+#define _IPFW3SET_H_
 
-#include <net/dummynet3/ip_dummynet3.h>
+void   set_enable(int ac, char **av);
+void   set_disable(int ac, char **av);
+void   set_show(int ac, char **av);
+void   set_swap(int ac, char **av);
+void   set_flush(int ac, char **av);
+void   set_move_rule(int ac, char **av);
+void   set_move_set(int ac, char **av);
+void   set_main(int ac, char **av);
 
 #endif
similarity index 54%
copy from sbin/ipfw3/ipfw3nat.c
copy to sbin/ipfw3/ipfw3state.c
index a73c5bb..f93b730 100644 (file)
 #include <net/ethernet.h>
 
 #include <net/ipfw3/ip_fw3.h>
-#include <net/ipfw3/ip_fw3_table.h>
-#include <net/ipfw3/ip_fw3_sync.h>
-#include <net/dummynet3/ip_dummynet3.h>
 #include <net/ipfw3_basic/ip_fw3_basic.h>
+#include <net/ipfw3_basic/ip_fw3_table.h>
+#include <net/ipfw3_basic/ip_fw3_state.h>
+#include <net/ipfw3_basic/ip_fw3_sync.h>
 #include <net/ipfw3_nat/ip_fw3_nat.h>
+#include <net/dummynet3/ip_dummynet3.h>
 
 #include "ipfw3.h"
-#include "ipfw3nat.h"
+#include "ipfw3basic.h"
 
 extern int verbose;
 extern int do_time;
 extern int do_quiet;
 extern int do_force;
+extern int do_acct;
+extern int do_compact;
 
 
 void
-nat_config_add(int ac, char **av)
+state_add(int ac, char *av[])
 {
-       struct ioc_nat *ioc;
-       struct in_addr *ip;
-       int error, len = 0;
-       char *id, buf[LEN_NAT_CMD_BUF];
-
-       memset(buf, 0, LEN_NAT_CMD_BUF);
-       ioc = (struct ioc_nat *)buf;
-
-       NEXT_ARG;
-       if (ac && isdigit(**av)) {
-               id = *av;
-               ioc->id = atoi(*av);
-               if (ioc->id <= 0 || ioc->id > NAT_ID_MAX) {
-                       errx(EX_DATAERR, "invalid nat id");
-               }
-       } else {
-               errx(EX_DATAERR, "missing nat id");
-       }
-       len += LEN_IOC_NAT;
-
-       NEXT_ARG;
-       if (strncmp(*av, "ip", strlen(*av))) {
-               errx(EX_DATAERR, "missing `ip'");
-       }
-       NEXT_ARG;
-       ip = &ioc->ip;
-       while (ac > 0){
-               if (!inet_aton(*av, ip)) {
-                       errx(EX_DATAERR, "bad ip addr `%s'", *av);
-               }
-               ioc->count++;
-               len += LEN_IN_ADDR;
-               ip++;
-               NEXT_ARG;
-       }
-
-       error = do_set_x(IP_FW_NAT_ADD, ioc, len);
-       if (error) {
-               err(1, "do_set_x(%s)", "IP_FW_NAT_ADD");
-       }
-
-       /* show the rule after configured */
-       int _ac = 2;
-       char *_av[] = {"config", id};
-       nat_config_get(_ac, _av);
+       /* TODO */
 }
 
 void
-nat_config_show(char *buf, int nbytes, int nat_id)
+state_delete(int ac, char *av[])
 {
-       struct ioc_nat *ioc;
-       struct in_addr *ip;
-       int n, len = 0;
-
-       while (len < nbytes) {
-               ioc = (struct ioc_nat *)(buf + len);
-               if (nat_id == 0 || ioc->id == nat_id) {
-                       printf("ipfw3 nat %u config ip", ioc->id);
-               }
-               ip = &ioc->ip;
-               len += LEN_IOC_NAT;
-               for (n = 0; n < ioc->count; n++) {
-                       if (nat_id == 0 || ioc->id == nat_id) {
-                               printf(" %s", inet_ntoa(*ip));
-                       }
-                       ip++;
-                       len += LEN_IN_ADDR;
-               }
-               if (nat_id == 0 || ioc->id == nat_id) {
-                       printf("\n");
-               }
-       }
-}
-
-void
-nat_config_get(int ac, char **av)
-{
-       int nbytes, nalloc;
-       int nat_id;
-       uint8_t *data;
-
-       nalloc = 1024;
-       data = NULL;
-       nat_id = 0;
-
+       int rulenum;
        NEXT_ARG;
-       if (ac == 1) {
-               nat_id = strtoul(*av, NULL, 10);
-       }
-
-       nbytes = nalloc;
-       while (nbytes >= nalloc) {
-               nalloc = nalloc * 2;
-               nbytes = nalloc;
-               if ((data = realloc(data, nbytes)) == NULL) {
-                       err(EX_OSERR, "realloc");
-               }
-               if (do_get_x(IP_FW_NAT_GET, data, &nbytes) < 0) {
-                       err(EX_OSERR, "do_get_x(IP_FW_NAT_GET)");
-               }
-       }
-       if (nbytes == 0) {
-               exit(EX_OK);
-       }
-       nat_config_show(data, nbytes, nat_id);
+       if (ac == 1 && isdigit(**av))
+               rulenum = atoi(*av);
+       if (do_set_x(IP_FW_STATE_DEL, &rulenum, sizeof(int)) < 0 )
+               err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_DEL)");
 }
 
 void
-nat_config_delete(int ac, char *av[])
+state_flush(int ac, char *av[])
 {
-       NEXT_ARG;
-       int i = 0;
-       if (ac > 0) {
-               i = atoi(*av);
+       if (!do_force) {
+               int c;
+
+               printf("Are you sure? [yn] ");
+               fflush(stdout);
+               do {
+                       c = toupper(getc(stdin));
+                       while (c != '\n' && getc(stdin) != '\n')
+                               if (feof(stdin))
+                                       return; /* and do not flush */
+               } while (c != 'Y' && c != 'N');
+               if (c == 'N')   /* user said no */
+                       return;
        }
-       if (do_set_x(IP_FW_NAT_DEL, &i, sizeof(i)) == -1)
-               errx(EX_USAGE, "NAT %d in use or not exists", i);
+       if (do_set_x(IP_FW_STATE_FLUSH, NULL, 0) < 0 )
+               err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_FLUSH)");
+       if (!do_quiet)
+               printf("Flushed all states.\n");
 }
 
 void
-nat_state_show(int ac, char **av)
+state_list(int ac, char *av[])
 {
        int nbytes, nalloc;
-       int nat_id;
+       int rule_id;
        uint8_t *data;
 
        nalloc = 1024;
@@ -218,9 +139,9 @@ nat_state_show(int ac, char **av)
 
        NEXT_ARG;
        if (ac == 0)
-               nat_id = 0;
+               rule_id = 0;
        else
-               nat_id = strtoul(*av, NULL, 10);
+               rule_id = strtoul(*av, NULL, 10);
 
        nbytes = nalloc;
        while (nbytes >= nalloc) {
@@ -229,20 +150,21 @@ nat_state_show(int ac, char **av)
                if ((data = realloc(data, nbytes)) == NULL) {
                        err(EX_OSERR, "realloc");
                }
-               memcpy(data, &nat_id, sizeof(int));
-               if (do_get_x(IP_FW_NAT_GET_RECORD, data, &nbytes) < 0) {
+               memcpy(data, &rule_id, sizeof(int));
+               if (do_get_x(IP_FW_STATE_GET, data, &nbytes) < 0) {
                        err(EX_OSERR, "do_get_x(IP_FW_NAT_GET_RECORD)");
                }
        }
+
        if (nbytes == 0)
                exit(EX_OK);
 
-       struct ioc_nat_state *ioc;
-       ioc =(struct ioc_nat_state *)data;
-       int count = nbytes / LEN_IOC_NAT_STATE;
+       struct ipfw3_ioc_state *ioc;
+       ioc =(struct ipfw3_ioc_state *)data;
+       int count = nbytes / LEN_IOC_FW3_STATE;
        int i;
        for (i = 0; i < count; i ++) {
-               printf("%d %d", ioc->nat_id, ioc->cpu_id);
+               printf("%05u %d", ioc->rule_id, ioc->cpu_id);
                if (ioc->proto == IPPROTO_ICMP) {
                        printf(" icmp");
                } else if (ioc->proto == IPPROTO_TCP) {
@@ -252,8 +174,6 @@ nat_state_show(int ac, char **av)
                }
                printf(" %s:%hu",inet_ntoa(ioc->src_addr),
                        htons(ioc->src_port));
-               printf(" %s:%hu",inet_ntoa(ioc->alias_addr),
-                       htons(ioc->alias_port));
                printf(" %s:%hu",inet_ntoa(ioc->dst_addr),
                        htons(ioc->dst_port));
                printf(" %c", ioc->direction? 'o' : 'i');
@@ -264,55 +184,22 @@ nat_state_show(int ac, char **av)
 }
 
 void
-nat_config_flush(void)
+state_main(int ac, char **av)
 {
-       int cmd = IP_FW_NAT_FLUSH;
-       if (!do_force) {
-               int c;
-
-               printf("Are you sure? [yn] ");
-               fflush(stdout);
-               do {
-                       c = toupper(getc(stdin));
-                       while (c != '\n' && getc(stdin) != '\n')
-                               if (feof(stdin))
-                                       return; /* and do not flush */
-               } while (c != 'Y' && c != 'N');
-               if (c == 'N')   /* user said no */
-                       return;
-       }
-       if (do_set_x(cmd, NULL, 0) < 0 ) {
-               errx(EX_USAGE, "NAT configuration in use");
-       }
-       if (!do_quiet) {
-               printf("Flushed all nat configurations");
-       }
-}
-
-void
-nat_main(int ac, char **av)
-{
-       if (!strncmp(*av, "config", strlen(*av))) {
-               nat_config_add(ac, av);
+       if (!strncmp(*av, "add", strlen(*av))) {
+               state_add(ac, av);
+       } else if (!strncmp(*av, "delete", strlen(*av))) {
+               state_delete(ac, av);
        } else if (!strncmp(*av, "flush", strlen(*av))) {
-               nat_config_flush();
+               state_flush(ac, av);
+       } else if (!strncmp(*av, "list", strlen(*av))) {
+               state_list(ac, av);
        } else if (!strncmp(*av, "show", strlen(*av))) {
-               if (ac > 2 && isdigit(*(av[1]))) {
-                       char *p = av[1];
-                       av[1] = av[2];
-                       av[2] = p;
-               }
-               NEXT_ARG;
-               if (!strncmp(*av, "config", strlen(*av))) {
-                       nat_config_get(ac, av);
-               } else if (!strncmp(*av, "state", strlen(*av))) {
-                       nat_state_show(ac,av);
-               } else {
-                       errx(EX_USAGE, "bad nat show command `%s'", *av);
-               }
-       } else if (!strncmp(*av, "delete", strlen(*av))) {
-               nat_config_delete(ac, av);
+               do_acct = 1;
+               state_list(ac, av);
        } else {
-               errx(EX_USAGE, "bad ipfw nat command `%s'", *av);
+               errx(EX_USAGE, "bad ipfw3 state command `%s'", *av);
        }
 }
+
+
similarity index 82%
copy from lib/libipfw3/nat/ipfw3_nat.h
copy to sbin/ipfw3/ipfw3state.h
index 938e970..e4bcb42 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 - 2016 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2014 - 2018 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
  * by Bill Yuan <bycn82@dragonflybsd.org>
  * SUCH DAMAGE.
  */
 
-#ifndef _IPFW_NAT_H
-#define _IPFW_NAT_H
-
-#include <net/ipfw3_nat/ip_fw3_nat.h>
-
+#ifndef _IPFW3STATE_H_
+#define _IPFW3STATE_H_
+void   state_add(int ac, char **av);
+void   state_delete(int ac, char **av);
+void   state_flush(int ac, char **av);
+void   state_show(struct ipfw3_ioc_state *d, int pcwidth, int bcwidth);
+void   state_list(int ac, char **av);
+void   state_main(int ac, char **av);
 #endif
index 837cbbe..6b7c7a2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2016 - 2018 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
  * by Bill Yuan <bycn82@dragonflybsd.org>
 #include <net/ethernet.h>
 
 #include <net/ipfw3/ip_fw3.h>
-#include <net/ipfw3/ip_fw3_table.h>
-#include <net/ipfw3/ip_fw3_sync.h>
-#include <net/dummynet3/ip_dummynet3.h>
+#include <net/ipfw3_basic/ip_fw3_table.h>
+#include <net/ipfw3_basic/ip_fw3_sync.h>
 #include <net/ipfw3_basic/ip_fw3_basic.h>
 #include <net/ipfw3_nat/ip_fw3_nat.h>
+#include <net/dummynet3/ip_dummynet3.h>
 
 #include "ipfw3.h"
 #include "ipfw3sync.h"
@@ -81,7 +81,7 @@
 void
 sync_config_edge(int ac, char *av[])
 {
-       struct ipfw_ioc_sync_edge ioc_edge;
+       struct ipfw3_ioc_sync_edge ioc_edge;
        NEXT_ARG;
        if (isdigit(**av)) {
                ioc_edge.port = atoi(*av);
@@ -106,8 +106,8 @@ sync_config_edge(int ac, char *av[])
 void
 sync_config_centre(int ac, char *av[])
 {
-       struct ipfw_ioc_sync_centre *centre;
-       struct ipfw_sync_edge *edge;
+       struct ipfw3_ioc_sync_centre *centre;
+       struct ipfw3_sync_edge *edge;
        struct in_addr addr;
        char *tok;
        char *str;
@@ -119,9 +119,9 @@ sync_config_centre(int ac, char *av[])
        tok = strtok(*av, ",");
        len = sizeof(int);
 
-       data_len = len + step * sizeof(struct ipfw_sync_edge);
+       data_len = len + step * LEN_SYNC_EDGE;
        data = malloc(data_len);
-       centre = (struct ipfw_ioc_sync_centre *)data;
+       centre = (struct ipfw3_ioc_sync_centre *)data;
        edge = centre->edges;
        while (tok != NULL) {
                str = strchr(tok,':');
@@ -139,7 +139,7 @@ sync_config_centre(int ac, char *av[])
                edge->addr = addr.s_addr;
                if (count >= step) {
                        step += 10;
-                       data_len = len + step * sizeof(struct ipfw_sync_edge);
+                       data_len = len + step * LEN_SYNC_EDGE;
                        if ((data = realloc(data, data_len)) == NULL) {
                                err(EX_OSERR, "realloc in config sync centre");
                        }
@@ -153,7 +153,7 @@ sync_config_centre(int ac, char *av[])
                err(EX_OSERR,"too much edges");
        }
        centre->count = count;
-       len += count * sizeof(struct ipfw_sync_edge);
+       len += count * LEN_SYNC_EDGE;
        if(do_set_x(IP_FW_SYNC_CENTRE_CONF, data, len) < 0) {
                err(EX_UNAVAILABLE, "do_set_x(IP_FW_SYNC_CENTRE_CONF)");
        }
@@ -181,14 +181,14 @@ sync_show_config(int ac, char *av[])
                        err(EX_OSERR, "getsockopt(IP_FW_SYNC_SHOW_CONF)");
                }
        }
-       struct ipfw_ioc_sync_context *sync_ctx;
-       sync_ctx = (struct ipfw_ioc_sync_context *)data;
+       struct ipfw3_ioc_sync_context *sync_ctx;
+       sync_ctx = (struct ipfw3_ioc_sync_context *)data;
        if (sync_ctx->edge_port != 0) {
                printf("ipfw3sync edge on %d %s\n", sync_ctx->edge_port,
                                sync_ctx->hw_same == 1 ? "all" : "");
        }
        if (sync_ctx->count > 0) {
-               struct ipfw_sync_edge *edge;
+               struct ipfw3_sync_edge *edge;
                int i;
 
                edge = sync_ctx->edges;
@@ -200,7 +200,6 @@ sync_show_config(int ac, char *av[])
                        edge++;
                }
        }
-
 }
 
 void
@@ -296,3 +295,54 @@ sync_centre_test(int ac, char *av[])
        }
        printf("centre test %d sent\n", n);
 }
+
+
+void
+sync_main(int ac, char **av)
+{
+       if (!strncmp(*av, "edge", strlen(*av))) {
+               sync_config_edge(ac, av);
+       } else if (!strncmp(*av, "centre", strlen(*av))) {
+               sync_config_centre(ac, av);
+       } else if (!strncmp(*av, "show", strlen(*av))) {
+               NEXT_ARG;
+               if (!strncmp(*av, "config", strlen(*av))) {
+                       sync_show_config(ac, av);
+               } else if (!strncmp(*av, "status", strlen(*av))) {
+                       sync_show_status(ac, av);
+               } else {
+                       errx(EX_USAGE, "bad show command `%s'", *av);
+               }
+       } else if (!strncmp(*av, "start", strlen(*av))) {
+               NEXT_ARG;
+               if (!strncmp(*av, "edge", strlen(*av))) {
+                       sync_edge_start(ac, av);
+               } else if (!strncmp(*av, "centre", strlen(*av))) {
+                       sync_centre_start(ac, av);
+               }
+       } else if (!strncmp(*av, "stop", strlen(*av))) {
+               NEXT_ARG;
+               if (!strncmp(*av, "edge", strlen(*av))) {
+                       sync_edge_stop(ac, av);
+               } else if (!strncmp(*av, "centre", strlen(*av))) {
+                       sync_centre_stop(ac, av);
+               }
+       } else if (!strncmp(*av, "clear", strlen(*av))) {
+               NEXT_ARG;
+               if (!strncmp(*av, "edge", strlen(*av))) {
+                       sync_edge_clear(ac, av);
+               } else if (!strncmp(*av, "centre", strlen(*av))) {
+                       sync_centre_clear(ac, av);
+               }
+       } else if (!strncmp(*av, "test", strlen(*av))) {
+               NEXT_ARG;
+               if (!strncmp(*av, "edge", strlen(*av))) {
+                       sync_edge_test(ac, av);
+               } else if (!strncmp(*av, "centre", strlen(*av))) {
+                       sync_centre_test(ac, av);
+               }
+       } else {
+               errx(EX_USAGE, "bad ipfw sync command `%s'", *av);
+       }
+}
+
index e4b4a97..1629393 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2016 - 2018 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
  * by Bill Yuan <bycn82@dragonflybsd.org>
 #ifndef _IPFW3SYNC_H_
 #define _IPFW3SYNC_H_
 
-void sync_config_edge(int ac, char *av[]);
-void sync_config_centre(int ac, char *av[]);
-void sync_show_config(int ac, char *av[]);
-void sync_show_status(int ac, char *av[]);
-void sync_edge_start(int ac, char *av[]);
-void sync_centre_start(int ac, char *av[]);
-void sync_edge_stop(int ac, char *av[]);
-void sync_centre_stop(int ac, char *av[]);
-void sync_edge_clear(int ac, char *av[]);
-void sync_centre_clear(int ac, char *av[]);
-void sync_edge_test(int ac, char *av[]);
-void sync_centre_test(int ac, char *av[]);
+void   sync_config_edge(int ac, char **av);
+void   sync_config_centre(int ac, char **av);
+void   sync_show_config(int ac, char **av);
+void   sync_show_status(int ac, char **av);
+void   sync_edge_start(int ac, char **av);
+void   sync_centre_start(int ac, char **av);
+void   sync_edge_stop(int ac, char **av);
+void   sync_centre_stop(int ac, char **av);
+void   sync_edge_clear(int ac, char **av);
+void   sync_centre_clear(int ac, char **av);
+void   sync_edge_test(int ac, char **av);
+void   sync_centre_test(int ac, char **av);
 
+void   sync_main(int ac, char **av);
 #endif
diff --git a/sbin/ipfw3/ipfw3table.c b/sbin/ipfw3/ipfw3table.c
new file mode 100644 (file)
index 0000000..067782c
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 2014 - 2018 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Bill Yuan <bycn82@dragonflybsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <dlfcn.h>
+#include <err.h>
+#include <errno.h>
+#include <grp.h>
+#include <limits.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <sysexits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <timeconv.h>
+#include <unistd.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/tcp.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <net/ethernet.h>
+
+#include <net/ipfw3/ip_fw3.h>
+#include <net/ipfw3_basic/ip_fw3_table.h>
+#include <net/ipfw3_basic/ip_fw3_sync.h>
+#include <net/ipfw3_basic/ip_fw3_basic.h>
+#include <net/ipfw3_nat/ip_fw3_nat.h>
+#include <net/dummynet3/ip_dummynet3.h>
+
+#include "ipfw3.h"
+#include "ipfw3table.h"
+
+int
+lookup_host (char *host, struct in_addr *ipaddr)
+{
+       struct hostent *he;
+
+       if (!inet_aton(host, ipaddr)) {
+               if ((he = gethostbyname(host)) == NULL)
+                       return(-1);
+               *ipaddr = *(struct in_addr *)he->h_addr_list[0];
+       }
+       return(0);
+}
+
+
+void
+table_append(int ac, char *av[])
+{
+       struct ipfw_ioc_table tbl;
+       char *p;
+       int size;
+
+       NEXT_ARG;
+       if (isdigit(**av))
+               tbl.id = atoi(*av);
+       else
+               errx(EX_USAGE, "table id `%s' invalid", *av);
+
+       if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
+               errx(EX_USAGE, "table id `%d' invalid", tbl.id);
+
+       NEXT_ARG;
+       if (strcmp(*av, "ip") == 0)
+               tbl.type = 1;
+       else if (strcmp(*av, "mac") == 0)
+               tbl.type = 2;
+       else
+               errx(EX_USAGE, "table type `%s' not supported", *av);
+
+       NEXT_ARG;
+        if (tbl.type == 1) { /* table type ipv4 */
+                struct ipfw_ioc_table_ip_entry ip_ent;
+                if (!ac)
+                        errx(EX_USAGE, "IP address required");
+
+                p = strchr(*av, '/');
+                if (p) {
+                        *p++ = '\0';
+                        ip_ent.masklen = atoi(p);
+                        if (ip_ent.masklen > 32)
+                                errx(EX_DATAERR, "bad width ``%s''", p);
+                } else {
+                        ip_ent.masklen = 32;
+                }
+
+                if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
+                        errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
+
+                tbl.ip_ent[0] = ip_ent;
+                size = sizeof(tbl) + sizeof(ip_ent);
+        } else if (tbl.type == 2) { /* table type mac */
+                struct ipfw_ioc_table_mac_entry mac_ent;
+                if (!ac)
+                        errx(EX_USAGE, "MAC address required");
+
+                mac_ent.addr = *ether_aton(*av);
+                tbl.mac_ent[0] = mac_ent;
+                size = sizeof(tbl) + sizeof(mac_ent);
+        }
+       if (do_set_x(IP_FW_TABLE_APPEND, &tbl, size) < 0 )
+               errx(EX_USAGE, "do_set_x(IP_FW_TABLE_APPEND) "
+                       "table `%d' append `%s' failed", tbl.id, *av);
+}
+
+void
+table_remove(int ac, char *av[])
+{
+       struct ipfw_ioc_table tbl;
+       struct ipfw_ioc_table_ip_entry ip_ent;
+       char *p;
+       int size;
+
+       NEXT_ARG;
+       if (isdigit(**av))
+               tbl.id = atoi(*av);
+       else
+               errx(EX_USAGE, "table id `%s' invalid", *av);
+
+       if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
+               errx(EX_USAGE, "table id `%d' invalid", tbl.id);
+
+       NEXT_ARG;
+       if (strcmp(*av, "ip") == 0)
+               tbl.type = 1;
+       else if (strcmp(*av, "mac") == 0)
+               tbl.type = 2;
+       else
+               errx(EX_USAGE, "table type `%s' not supported", *av);
+
+       NEXT_ARG;
+       if (!ac)
+               errx(EX_USAGE, "IP address required");
+       p = strchr(*av, '/');
+       if (p) {
+               *p++ = '\0';
+               ip_ent.masklen = atoi(p);
+               if (ip_ent.masklen > 32)
+                       errx(EX_DATAERR, "bad width ``%s''", p);
+       } else {
+               ip_ent.masklen = 32;
+       }
+
+       if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
+               errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
+
+       tbl.ip_ent[0] = ip_ent;
+       size = sizeof(tbl) + sizeof(ip_ent);
+       if (do_set_x(IP_FW_TABLE_REMOVE, &tbl, size) < 0 ) {
+               errx(EX_USAGE, "do_set_x(IP_FW_TABLE_REMOVE) "
+                       "table `%d' append `%s' failed", tbl.id, *av);
+       }
+}
+
+void
+table_flush(int ac, char *av[])
+{
+       struct ipfw_ioc_table ioc_table;
+       struct ipfw_ioc_table *t = &ioc_table;
+
+       NEXT_ARG;
+       if (isdigit(**av)) {
+               t->id = atoi(*av);
+               if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
+                       errx(EX_USAGE, "table id `%d' invalid", t->id);
+       } else {
+               errx(EX_USAGE, "table id `%s' invalid", *av);
+       }
+       if (do_set_x(IP_FW_TABLE_FLUSH, t, sizeof(struct ipfw_ioc_table)) < 0 )
+               errx(EX_USAGE, "do_set_x(IP_FW_TABLE_FLUSH) "
+                                       "table `%s' flush failed", *av);
+}
+
+void
+table_list(int ac, char *av[])
+{
+       struct ipfw_ioc_table *ioc_table;
+       int i, count, nbytes, nalloc = 1024;
+       void *data = NULL;
+       NEXT_ARG;
+       if (strcmp(*av, "list") == 0) {
+               nbytes = nalloc;
+               while (nbytes >= nalloc) {
+                       nalloc = nalloc * 2 ;
+                       nbytes = nalloc;
+                       if ((data = realloc(data, nbytes)) == NULL)
+                               err(EX_OSERR, "realloc");
+                       if (do_get_x(IP_FW_TABLE_LIST, data, &nbytes) < 0)
+                               err(EX_OSERR, "do_get_x(IP_FW_TABLE_LIST)");
+               }
+               ioc_table = (struct ipfw_ioc_table *)data;
+               count = nbytes / sizeof(struct ipfw_ioc_table);
+               for (i = 0; i < count; i++, ioc_table++) {
+                       if (ioc_table->type > 0) {
+                               printf("table %d",ioc_table->id);
+                               if (ioc_table->type == 1)
+                                       printf(" type ip");
+                               else if (ioc_table->type == 2)
+                                       printf(" type mac");
+                               printf(" count %d",ioc_table->count);
+                               if (strlen(ioc_table->name) > 0)
+                                       printf(" name %s",ioc_table->name);
+                               printf("\n");
+
+                       }
+               }
+       } else {
+               errx(EX_USAGE, "ipfw3 table `%s' delete invalid", *av);
+       }
+}
+
+void
+table_print(struct ipfw_ioc_table * tbl)
+{
+       int i;
+        if (tbl->type == 0)
+                errx(EX_USAGE, "table %d is not in use", tbl->id);
+
+        printf("table %d", tbl->id);
+        if (tbl->type == 1)
+                printf(" type ip");
+        else if (tbl->type == 2)
+                printf(" type mac");
+
+        printf(" count %d", tbl->count);
+       if (strlen(tbl->name) > 0)
+               printf(" name %s", tbl->name);
+
+       printf("\n");
+
+        if (tbl->type == 1) {
+                struct ipfw_ioc_table_ip_entry *ip_ent;
+                ip_ent = tbl->ip_ent;
+                for (i = 0; i < tbl->count; i++) {
+                        printf("%s", inet_ntoa(*(struct in_addr *)&ip_ent->addr));
+                        printf("/%d ", ip_ent->masklen);
+                        printf("\n");
+                        ip_ent++;
+                }
+        } else if (tbl->type == 2) {
+                struct ipfw_ioc_table_mac_entry *mac_ent;
+                mac_ent = tbl->mac_ent;
+                for (i = 0; i < tbl->count; i++) {
+                        printf("%s", ether_ntoa(&mac_ent->addr));
+                        printf("\n");
+                        mac_ent++;
+                }
+        }
+}
+
+void
+table_show(int ac, char *av[])
+{
+       int nbytes, nalloc = 1024;
+       void *data = NULL;
+       NEXT_ARG;
+       if (isdigit(**av)) {
+               nbytes = nalloc;
+               while (nbytes >= nalloc) {
+                       nalloc = nalloc * 2 + 256;
+                       nbytes = nalloc;
+                       if (data == NULL) {
+                               if ((data = malloc(nbytes)) == NULL) {
+                                       err(EX_OSERR, "malloc");
+                               }
+                       } else if ((data = realloc(data, nbytes)) == NULL) {
+                               err(EX_OSERR, "realloc");
+                       }
+                       /* store table id in the header of data */
+                       int *head = (int *)data;
+                       *head = atoi(*av);
+                       if (*head < 0 || *head > IPFW_TABLES_MAX - 1)
+                               errx(EX_USAGE, "table id `%d' invalid", *head);
+                       if (do_get_x(IP_FW_TABLE_SHOW, data, &nbytes) < 0)
+                               err(EX_OSERR, "do_get_x(IP_FW_TABLE_LIST)");
+                       struct ipfw_ioc_table *tbl;
+                       tbl = (struct ipfw_ioc_table *)data;
+                       table_print(tbl);
+               }
+       } else {
+               errx(EX_USAGE, "ipfw3 table `%s' show invalid", *av);
+       }
+}
+
+void
+table_create(int ac, char *av[])
+{
+       struct ipfw_ioc_table ioc_table;
+       struct ipfw_ioc_table *t = &ioc_table;
+
+       NEXT_ARG;
+       if (ac < 2)
+               errx(EX_USAGE, "table parameters invalid");
+       if (isdigit(**av)) {
+               t->id = atoi(*av);
+               if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
+                       errx(EX_USAGE, "table id `%d' invalid", t->id);
+       } else {
+               errx(EX_USAGE, "table id `%s' invalid", *av);
+       }
+       NEXT_ARG;
+       if (strcmp(*av, "ip") == 0)
+               t->type = 1;
+       else if (strcmp(*av, "mac") == 0)
+               t->type = 2;
+       else
+               errx(EX_USAGE, "table type `%s' not supported", *av);
+
+       NEXT_ARG;
+       memset(t->name, 0, IPFW_TABLE_NAME_LEN);
+       if (ac == 2 && strcmp(*av, "name") == 0) {
+               NEXT_ARG;
+               if (strlen(*av) < IPFW_TABLE_NAME_LEN) {
+                       strncpy(t->name, *av, strlen(*av));
+               } else {
+                       errx(EX_USAGE, "table name `%s' too long", *av);
+               }
+       } else if (ac == 1) {
+               errx(EX_USAGE, "table `%s' invalid", *av);
+       }
+
+       if (do_set_x(IP_FW_TABLE_CREATE, t, sizeof(struct ipfw_ioc_table)) < 0)
+               errx(EX_USAGE, "do_set_x(IP_FW_TABLE_CREATE) "
+                                       "table `%d' in use", t->id);
+}
+
+void
+table_delete(int ac, char *av[])
+{
+       struct ipfw_ioc_table ioc_table;
+       struct ipfw_ioc_table *t = &ioc_table;
+
+       NEXT_ARG;
+       if (isdigit(**av)) {
+               t->id = atoi(*av);
+               if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
+                       errx(EX_USAGE, "table id `%d' invalid", t->id);
+       } else {
+               errx(EX_USAGE, "table id `%s' invalid", *av);
+       }
+       if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
+               errx(EX_USAGE, "table id `%d' invalid", t->id);
+
+       if (do_set_x(IP_FW_TABLE_DELETE, t, sizeof(struct ipfw_ioc_table)) < 0)
+               errx(EX_USAGE, "do_set_x(IP_FW_TABLE_DELETE) "
+                                       "table `%s' delete failed", *av);
+}
+
+void
+table_test(int ac, char *av[])
+{
+       struct ipfw_ioc_table tbl;
+       int size;
+
+       NEXT_ARG;
+       if (isdigit(**av))
+               tbl.id = atoi(*av);
+       else
+               errx(EX_USAGE, "table id `%s' invalid", *av);
+
+       if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
+               errx(EX_USAGE, "table id `%d' invalid", tbl.id);
+
+       NEXT_ARG;
+       if (strcmp(*av, "ip") == 0)
+               tbl.type = 1;
+       else if (strcmp(*av, "mac") == 0)
+               tbl.type = 2;
+       else
+               errx(EX_USAGE, "table type `%s' not supported", *av);
+
+       NEXT_ARG;
+        if (tbl.type == 1) { /* table type ipv4 */
+                struct ipfw_ioc_table_ip_entry ip_ent;
+                if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
+                        errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
+
+                tbl.ip_ent[0] = ip_ent;
+                size = sizeof(tbl) + sizeof(ip_ent);
+        } else if (tbl.type == 2) { /* table type mac */
+                struct ipfw_ioc_table_mac_entry mac_ent;
+                if (!ac)
+                        errx(EX_USAGE, "MAC address required");
+
+                mac_ent.addr = *ether_aton(*av);
+                tbl.mac_ent[0] = mac_ent;
+                size = sizeof(tbl) + sizeof(mac_ent);
+        }
+       if (do_set_x(IP_FW_TABLE_TEST, &tbl, size) < 0 ) {
+               printf("NO, %s not exists in table %d\n", *av, tbl.id);
+       } else {
+               printf("YES, %s exists in table %d\n", *av, tbl.id);
+       }
+}
+
+static void
+table_rename(int ac, char *av[])
+{
+       struct ipfw_ioc_table tbl;
+       int size;
+
+       bzero(&tbl, sizeof(tbl));
+       NEXT_ARG;
+       if (isdigit(**av))
+               tbl.id = atoi(*av);
+       else
+               errx(EX_USAGE, "table id `%s' invalid", *av);
+
+       if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
+               errx(EX_USAGE, "table id `%d' invalid", tbl.id);
+
+       NEXT_ARG;
+       strlcpy(tbl.name, *av, IPFW_TABLE_NAME_LEN);
+       size = sizeof(tbl);
+       if (do_set_x(IP_FW_TABLE_RENAME, &tbl, size) < 0 )
+               errx(EX_USAGE, "do_set_x(IP_FW_TABLE_RENAME) "
+                                       "table `%d' not in use", tbl.id);
+}
+
+void
+table_main(int ac, char **av)
+{
+       if (!strncmp(*av, "append", strlen(*av))) {
+               table_append(ac, av);
+       } else if (!strncmp(*av, "remove", strlen(*av))) {
+               table_remove(ac, av);
+       } else if (!strncmp(*av, "flush", strlen(*av))) {
+               table_flush(ac, av);
+       } else if (!strncmp(*av, "list", strlen(*av))) {
+               table_list(ac, av);
+       } else if (!strncmp(*av, "show", strlen(*av))) {
+               table_show(ac, av);
+       } else if (!strncmp(*av, "type", strlen(*av))) {
+               table_create(ac, av);
+       } else if (!strncmp(*av, "delete", strlen(*av))) {
+               table_delete(ac, av);
+       } else if (!strncmp(*av, "test", strlen(*av))) {
+               table_test(ac,av);
+       } else if (!strncmp(*av, "name", strlen(*av))) {
+               table_rename(ac, av);
+       } else {
+               errx(EX_USAGE, "bad ipfw table command `%s'", *av);
+       }
+}
+
similarity index 75%
copy from lib/libipfw3/nat/ipfw3_nat.h
copy to sbin/ipfw3/ipfw3table.h
index 938e970..889751b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 - 2016 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2014 - 2018 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
  * by Bill Yuan <bycn82@dragonflybsd.org>
  * SUCH DAMAGE.
  */
 
-#ifndef _IPFW_NAT_H
-#define _IPFW_NAT_H
+#ifndef _IPFW3TABLE_H_
+#define _IPFW3TABLE_H_
 
-#include <net/ipfw3_nat/ip_fw3_nat.h>
+int    lookup_host (char *host, struct in_addr *ipaddr);
 
+void   table_append(int ac, char **av);
+void   table_remove(int ac, char **av);
+void   table_flush(int ac, char **av);
+void   table_list(int ac, char **av);
+void   table_print(struct ipfw_ioc_table * tbl);
+void   table_show(int ac, char **av);
+void   table_create(int ac, char **av);
+void   table_delete(int ac, char **av);
+void   table_test(int ac, char **av);
+
+void   table_main(int ac, char **av);
 #endif
index 0451941..3280b9b 100644 (file)
@@ -1,15 +1,21 @@
-# $FreeBSD: src/sys/modules/dummynet/Makefile,v 1.1.2.2 2003/04/08 10:18:00 maxim Exp $
-# $DragonFly: src/sys/net/dummynet/Makefile,v 1.7 2008/09/16 12:30:57 sephe Exp $
-
 KMOD=  dummynet3
 SRCS=  ip_dummynet3.c
-SRCS+= opt_ipdn.h
+SRCS+= opt_ipfw.h opt_inet.h
 
 .ifndef BUILDING_WITH_KERNEL
-opt_ipdn.h:
-       echo '#define DUMMYNET 1' > ${.OBJDIR}/${.TARGET}
+opt_inet.h:
+       echo '#define INET 1' > ${.OBJDIR}/${.TARGET}
+
+opt_ipfw.h:
+       echo '#define IPFIREWALL3 1' > ${.OBJDIR}/${.TARGET}
        # Debug prints
-       #echo '#define DUMMYNET_DEBUG 1' >> ${.OBJDIR}/${.TARGET}
+       #echo '#define IPFIREWALL_DEBUG 1' >> ${.OBJDIR}/${.TARGET}
+       #
+       # If you want it verbose
+       #echo '#define IPFIREWALL_VERBOSE 1' >> ${.OBJDIR}/${.TARGET}
+       #
+       # If you want it to pass all packets by default
+       #echo '#define IPFIREWALL_DEFAULT_TO_ACCEPT 1' >> ${.OBJDIR}/${.TARGET}
 .endif
 
 .include <bsd.kmod.mk>
index cbb1613..7c71cfb 100644 (file)
  * $FreeBSD: src/sys/netinet/ip_dummynet.c,v 1.24.2.22 2003/05/13 09:31:06 maxim Exp $
  */
 
-#include "opt_ipdn.h"
+#include "opt_ipfw.h"
+#include "opt_inet.h"
+#ifndef INET
+#error IPFIREWALL3 requires INET.
+#endif /* INET */
 
 /*
  * This module implements IP dummynet, a bandwidth limiter/delay emulator.
@@ -876,7 +880,7 @@ red_drops(struct dn_flow_set *fs, struct dn_flow_queue *q, int len)
        int64_t p_b = 0;
        u_int q_size = (fs->flags_fs & DN_QSIZE_IS_BYTES) ? q->len_bytes : q->len;
 
-       DPRINTF("\n%d q: %2u ", (int)curr_time, q_size);
+       DEBUG("\n%d q: %2u ", (int)curr_time, q_size);
 
        /* Average queue size estimation */
        if (q_size != 0) {
@@ -902,7 +906,7 @@ red_drops(struct dn_flow_set *fs, struct dn_flow_queue *q, int len)
                                SCALE_MUL(q->avg, fs->w_q_lookup[t]) : 0;
                }
        }
-       DPRINTF("avg: %u ", SCALE_VAL(q->avg));
+       DEBUG("avg: %u ", SCALE_VAL(q->avg));
 
        /* Should i drop? */
 
@@ -946,7 +950,7 @@ red_drops(struct dn_flow_set *fs, struct dn_flow_queue *q, int len)
                 */
                if (SCALE_MUL(p_b, SCALE((int64_t)q->count)) > q->random) {
                        q->count = 0;
-                       DPRINTF("%s", "- red drop");
+                       DEBUG("%s", "- red drop");
                        /* After a drop we calculate a new random value */
                        q->random = krandom() & 0xffff;
                        return 1;       /* Drop */
@@ -1177,7 +1181,7 @@ dummynet_io(struct mbuf *m)
                        if (pipe->numbytes >= 0) {      /* Pipe is idle */
                                if (pipe->scheduler_heap.elements != 1)
                                        kprintf("*** OUCH! pipe should have been idle!\n");
-                               DPRINTF("Waking up pipe %d at %d\n",
+                               DEBUG("Waking up pipe %d at %d\n",
                                                pipe->pipe_nr, (int)(q->F >> MY_M));
                                pipe->sched_time = curr_time;
                                ready_event_wfq(pipe);
@@ -1987,10 +1991,10 @@ ip_dn_init(void)
                ip_dn_cpu = 0;
        }
 
-       register_ipfw_module(MODULE_DUMMYNET_ID, MODULE_DUMMYNET_NAME);
-       register_ipfw_filter_funcs(MODULE_DUMMYNET_ID, O_DUMMYNET_PIPE,
+       ip_fw3_register_module(MODULE_DUMMYNET_ID, MODULE_DUMMYNET_NAME);
+       ip_fw3_register_filter_funcs(MODULE_DUMMYNET_ID, O_DUMMYNET_PIPE,
                        (filter_func)check_pipe);
-       register_ipfw_filter_funcs(MODULE_DUMMYNET_ID, O_DUMMYNET_QUEUE,
+       ip_fw3_register_filter_funcs(MODULE_DUMMYNET_ID, O_DUMMYNET_QUEUE,
                        (filter_func)check_pipe);
 
        netmsg_init(&smsg, NULL, &curthread->td_msgport,
index 5b61919..b717649 100644 (file)
@@ -1,11 +1,7 @@
-# $FreeBSD: src/sys/modules/ipfw/Makefile,v 1.11.2.1 2003/02/14 14:09:21 maxim Exp $
-# $DragonFly: src/sys/net/ipfw/Makefile,v 1.6 2008/09/16 12:16:08 sephe Exp $
-
 KMOD=  ipfw3
-SRCS=  ip_fw3.c
-SRCS+= ip_fw3_log.c ip_fw3_log.h
-SRCS+=  ip_fw3_table.c ip_fw3_table.h
-SRCS+=  ip_fw3_sync.c ip_fw3_sync.h
+SRCS=  opt_fw3.h
+SRCS=  ip_fw3.c ip_fw3.h
+SRCS+= ip_fw3_set.c ip_fw3_set.h
 SRCS+= opt_ipfw.h opt_inet.h
 
 .ifndef BUILDING_WITH_KERNEL
index 26e799d..a75900f 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (c) 1993 Daniel Boulet
  * Copyright (c) 1994 Ugen J.S.Antsilevich
  * Copyright (c) 2002 Luigi Rizzo, Universita` di Pisa
- * Copyright (c) 2015 - 2016 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2014 - 2018 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
  * by Bill Yuan <bycn82@dragonflybsd.org>
 #endif /* INET */
 
 #include <sys/param.h>
-#include <sys/systm.h>
+#include <sys/kernel.h>
 #include <sys/malloc.h>
 #include <sys/mbuf.h>
-#include <sys/kernel.h>
-#include <sys/proc.h>
-#include <sys/socket.h>
 #include <sys/socketvar.h>
 #include <sys/sysctl.h>
+#include <sys/systimer.h>
+#include <sys/thread2.h>
+#include <sys/in_cksum.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
 #include <sys/syslog.h>
 #include <sys/ucred.h>
-#include <sys/in_cksum.h>
 #include <sys/lock.h>
-#include <sys/thread2.h>
 #include <sys/mplock2.h>
 
 #include <netinet/in.h>
 #include <net/netmsg2.h>
 
 #include <net/ipfw3/ip_fw.h>
-#include <net/ipfw3/ip_fw3_log.h>
-#include <net/ipfw3/ip_fw3_table.h>
-#include <net/ipfw3/ip_fw3_sync.h>
+#include <net/ipfw3/ip_fw3_set.h>
+#include <net/ipfw3_basic/ip_fw3_log.h>
+#include <net/ipfw3_basic/ip_fw3_table.h>
+#include <net/ipfw3_basic/ip_fw3_sync.h>
 #include <net/ipfw3_basic/ip_fw3_basic.h>
+#include <net/ipfw3_basic/ip_fw3_state.h>
 #include <net/ipfw3_nat/ip_fw3_nat.h>
 #include <net/dummynet3/ip_dummynet3.h>
 
-MALLOC_DEFINE(M_IPFW3, "IPFW3", "ip_fw3 default module");
-
-#ifdef IPFIREWALL_DEBUG
-#define DPRINTF(fmt, ...)                      \
-do {                                           \
-       if (fw_debug > 0)                       \
-               kprintf(fmt, __VA_ARGS__);      \
-} while (0)
-#else
-#define DPRINTF(fmt, ...)      ((void)0)
-#endif
+MALLOC_DEFINE(M_IPFW3, "IPFW3", "ipfw3 module");
 
 #define MAX_MODULE             10
 #define MAX_OPCODE_PER_MODULE  100
@@ -124,8 +117,9 @@ struct netmsg_del {
        struct ip_fw    *prev_rule;
        struct ipfw_ioc_state *ioc_state;
        uint16_t        rulenum;
-       uint8_t         from_set;
-       uint8_t         to_set;
+       uint8_t         set_from;
+       uint8_t         set_to;
+       int             kill_default;
 };
 
 struct netmsg_zent {
@@ -135,62 +129,52 @@ struct netmsg_zent {
        uint16_t        log_only;
 };
 
-ip_fw_ctl_t *ipfw_ctl_nat_ptr = NULL;
-
-/* handlers which implemented in ipfw_basic module */
-ipfw_basic_delete_state_t *ipfw_basic_flush_state_prt = NULL;
-ipfw_basic_append_state_t *ipfw_basic_append_state_prt = NULL;
+ip_fw_ctl_t    *ip_fw3_ctl_nat_ptr = NULL;
+ip_fw_ctl_t    *ip_fw3_ctl_state_ptr = NULL;
+ip_fw_ctl_t    *ip_fw3_ctl_table_ptr = NULL;
+ip_fw_ctl_t    *ip_fw3_ctl_sync_ptr = NULL;
+ip_fw_log_t    *ip_fw3_log_ptr = NULL;
 
 extern int ip_fw_loaded;
-static uint32_t static_count;  /* # of static rules */
-static uint32_t static_ioc_len;        /* bytes of static rules */
-static int ipfw_flushing;
-int fw_verbose = 0;
-static int fw_debug;
-static int autoinc_step = IPFW_AUTOINC_STEP_DEF;
+extern struct ipfw3_state_context      *fw3_state_ctx[MAXCPU];
+int                    sysctl_var_fw3_enable = 1;
+int                    sysctl_var_fw3_one_pass = 1;
+int                    sysctl_var_fw3_verbose = 0;
+static int             sysctl_var_fw3_flushing;
+static int             sysctl_var_fw3_debug;
+static int             sysctl_var_autoinc_step = IPFW_AUTOINC_STEP_DEF;
 
-static int     ipfw_sysctl_enable(SYSCTL_HANDLER_ARGS);
-static int     ipfw_sysctl_autoinc_step(SYSCTL_HANDLER_ARGS);
+int    ip_fw3_sysctl_enable(SYSCTL_HANDLER_ARGS);
+int    ip_fw3_sysctl_autoinc_step(SYSCTL_HANDLER_ARGS);
 
 SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw3, CTLFLAG_RW, 0, "Firewall");
 SYSCTL_PROC(_net_inet_ip_fw3, OID_AUTO, enable, CTLTYPE_INT | CTLFLAG_RW,
-       &fw3_enable, 0, ipfw_sysctl_enable, "I", "Enable ipfw");
-SYSCTL_PROC(_net_inet_ip_fw3, OID_AUTO, autoinc_step, CTLTYPE_INT | CTLFLAG_RW,
-       &autoinc_step, 0, ipfw_sysctl_autoinc_step, "I",
-       "Rule number autincrement step");
+       &sysctl_var_fw3_enable, 0, ip_fw3_sysctl_enable, "I", "Enable ipfw");
+SYSCTL_PROC(_net_inet_ip_fw3, OID_AUTO, sysctl_var_autoinc_step,
+       CTLTYPE_INT | CTLFLAG_RW, &sysctl_var_autoinc_step, 0,
+       ip_fw3_sysctl_autoinc_step, "I", "Rule number autincrement step");
 SYSCTL_INT(_net_inet_ip_fw3, OID_AUTO,one_pass,CTLFLAG_RW,
-       &fw3_one_pass, 0,
-       "Only do a single pass through ipfw when using dummynet(4)");
+       &sysctl_var_fw3_one_pass, 0,
+       "Only do a single pass through ipfw3 when using dummynet(4)");
 SYSCTL_INT(_net_inet_ip_fw3, OID_AUTO, debug, CTLFLAG_RW,
-       &fw_debug, 0, "Enable printing of debug ip_fw statements");
+       &sysctl_var_fw3_debug, 0, "Enable printing of debug ip_fw statements");
 SYSCTL_INT(_net_inet_ip_fw3, OID_AUTO, verbose, CTLFLAG_RW,
-       &fw_verbose, 0, "Log matches to ipfw rules");
-SYSCTL_INT(_net_inet_ip_fw3, OID_AUTO, static_count, CTLFLAG_RD,
-       &static_count, 0, "Number of static rules");
+       &sysctl_var_fw3_verbose, 0, "Log matches to ipfw3 rules");
 
-filter_func filter_funcs[MAX_MODULE][MAX_OPCODE_PER_MODULE];
-struct ipfw_module ipfw_modules[MAX_MODULE];
-struct ipfw_context *ipfw_ctx[MAXCPU];
-struct ipfw_sync_context sync_ctx;
-static int ipfw_ctl(struct sockopt *sopt);
 
-
-void
-check_accept(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
-               struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
-void
-check_deny(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
-               struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
-void init_module(void);
+filter_func                    filter_funcs[MAX_MODULE][MAX_OPCODE_PER_MODULE];
+struct ipfw3_module            fw3_modules[MAX_MODULE];
+struct ipfw3_context           *fw3_ctx[MAXCPU];
+struct ipfw3_sync_context      fw3_sync_ctx;
 
 
 void
-register_ipfw_module(int module_id,char *module_name)
+ip_fw3_register_module(int module_id,char *module_name)
 {
-       struct ipfw_module *tmp;
+       struct ipfw3_module *tmp;
        int i;
 
-       tmp = ipfw_modules;
+       tmp = fw3_modules;
        for (i=0; i < MAX_MODULE; i++) {
                if (tmp->type == 0) {
                        tmp->type = 1;
@@ -204,17 +188,17 @@ register_ipfw_module(int module_id,char *module_name)
 }
 
 int
-unregister_ipfw_module(int module_id)
+ip_fw3_unregister_module(int module_id)
 {
-       struct ipfw_module *tmp;
+       struct ipfw3_module *tmp;
        struct ip_fw *fw;
        ipfw_insn *cmd;
        int i, len, cmdlen, found;
 
        found = 0;
-       tmp = ipfw_modules;
-       struct ipfw_context *ctx = ipfw_ctx[mycpuid];
-       fw = ctx->ipfw_rule_chain;
+       tmp = fw3_modules;
+       struct ipfw3_context *ctx = fw3_ctx[mycpuid];
+       fw = ctx->rules;
        for (; fw; fw = fw->next) {
                for (len = fw->cmd_len, cmd = fw->cmd; len > 0;
                        len -= cmdlen,
@@ -256,7 +240,7 @@ decide:
 }
 
 void
-register_ipfw_filter_funcs(int module, int opcode, filter_func func)
+ip_fw3_register_filter_funcs(int module, int opcode, filter_func func)
 {
        filter_funcs[module][opcode] = func;
 }
@@ -267,8 +251,8 @@ check_accept(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
 {
        *cmd_val = IP_FW_PASS;
        *cmd_ctl = IP_FW_CTL_DONE;
-       if (cmd->arg3) {
-               ipfw_log((*args)->m, (*args)->eh, cmd->arg1);
+       if (cmd->arg3 && ip_fw3_log_ptr != NULL) {
+               ip_fw3_log_ptr((*args)->m, (*args)->eh, cmd->arg1);
        }
 }
 
@@ -278,24 +262,24 @@ check_deny(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
 {
        *cmd_val = IP_FW_DENY;
        *cmd_ctl = IP_FW_CTL_DONE;
-       if (cmd->arg3) {
-               ipfw_log((*args)->m, (*args)->eh, cmd->arg1);
+       if (cmd->arg3 && ip_fw3_log_ptr != NULL) {
+               ip_fw3_log_ptr((*args)->m, (*args)->eh, cmd->arg1);
        }
 }
 
 void
 init_module(void)
 {
-       memset(ipfw_modules, 0, sizeof(struct ipfw_module) * MAX_MODULE);
+       memset(fw3_modules, 0, sizeof(struct ipfw3_module) * MAX_MODULE);
        memset(filter_funcs, 0, sizeof(filter_func) *
                        MAX_OPCODE_PER_MODULE * MAX_MODULE);
-       register_ipfw_filter_funcs(0, O_BASIC_ACCEPT,
+       ip_fw3_register_filter_funcs(0, O_BASIC_ACCEPT,
                        (filter_func)check_accept);
-       register_ipfw_filter_funcs(0, O_BASIC_DENY, (filter_func)check_deny);
+       ip_fw3_register_filter_funcs(0, O_BASIC_DENY, (filter_func)check_deny);
 }
 
-static __inline int
-ipfw_free_rule(struct ip_fw *rule)
+int
+ip_fw3_free_rule(struct ip_fw *rule)
 {
        kfree(rule, M_IPFW3);
        rule = NULL;
@@ -332,9 +316,13 @@ lookup_next_rule(struct ip_fw *me)
  * it will invoke the cmds relatived function according to the cmd's
  * module id and opcode id. and process according to return value.
  */
-static int
-ipfw_chk(struct ip_fw_args *args)
+int
+ip_fw3_chk(struct ip_fw_args *args)
 {
+       struct tcphdr *tcp;
+       struct udphdr *udp;
+       struct icmp *icmp;
+
        struct mbuf *m = args->m;
        struct ip *ip = mtod(m, struct ip *);
        struct ip_fw *f = NULL;         /* matching rule */
@@ -361,7 +349,7 @@ ipfw_chk(struct ip_fw_args *args)
        struct in_addr src_ip, dst_ip;          /* NOTE: network format */
        uint16_t ip_len = 0;
        uint8_t prev_module = -1, prev_opcode = -1; /* previous module & opcode */
-       struct ipfw_context *ctx = ipfw_ctx[mycpuid];
+       struct ipfw3_context *ctx = fw3_ctx[mycpuid];
 
        if (m->m_pkthdr.fw_flags & IPFW_MBUF_GENERATED)
                return IP_FW_PASS;      /* accept */
@@ -403,34 +391,25 @@ do {                                                      \
        if (offset == 0) {
                switch (proto) {
                        case IPPROTO_TCP:
-                               {
-                                       struct tcphdr *tcp;
-
-                                       PULLUP_TO(hlen + sizeof(struct tcphdr));
-                                       tcp = L3HDR(struct tcphdr, ip);
-                                       dst_port = tcp->th_dport;
-                                       src_port = tcp->th_sport;
-                                       args->f_id.flags = tcp->th_flags;
-                               }
+                               PULLUP_TO(hlen + sizeof(struct tcphdr));
+                               tcp = L3HDR(struct tcphdr, ip);
+                               dst_port = tcp->th_dport;
+                               src_port = tcp->th_sport;
+                               args->f_id.flags = tcp->th_flags;
                                break;
-
                        case IPPROTO_UDP:
-                               {
-                                       struct udphdr *udp;
-
-                                       PULLUP_TO(hlen + sizeof(struct udphdr));
-                                       udp = L3HDR(struct udphdr, ip);
-                                       dst_port = udp->uh_dport;
-                                       src_port = udp->uh_sport;
-                               }
+                               PULLUP_TO(hlen + sizeof(struct udphdr));
+                               udp = L3HDR(struct udphdr, ip);
+                               dst_port = udp->uh_dport;
+                               src_port = udp->uh_sport;
                                break;
-
                        case IPPROTO_ICMP:
                                PULLUP_TO(hlen + 4);
-                               args->f_id.flags =
-                                       L3HDR(struct icmp, ip)->icmp_type;
+                               icmp = L3HDR(struct icmp, ip);
+                               args->f_id.flags = icmp->icmp_type;
+                               dst_port = icmp->icmp_id;
+                               src_port = dst_port;
                                break;
-
                        default:
                                break;
                }
@@ -449,15 +428,15 @@ after_ip_checks:
                 * Packet has already been tagged. Look for the next rule
                 * to restart processing.
                 *
-                * If fw3_one_pass != 0 then just accept it.
+                * If sysctl_var_fw3_one_pass != 0 then just accept it.
                 * XXX should not happen here, but optimized out in
                 * the caller.
                 */
-               if (fw3_one_pass)
+               if (sysctl_var_fw3_one_pass)
                        return IP_FW_PASS;
 
                /* This rule is being/has been flushed */
-               if (ipfw_flushing)
+               if (sysctl_var_fw3_flushing)
                        return IP_FW_DENY;
 
                f = args->rule->next_rule;
@@ -478,10 +457,10 @@ after_ip_checks:
                        skipto = 0;
                }
 
-               f = ctx->ipfw_rule_chain;
+               f = ctx->rules;
                if (args->eh == NULL && skipto != 0) {
                        /* No skipto during rule flushing */
-                       if (ipfw_flushing) {
+                       if (sysctl_var_fw3_flushing) {
                                return IP_FW_DENY;
                        }
                        if (skipto >= IPFW_DEFAULT_RULE) {
@@ -493,9 +472,9 @@ after_ip_checks:
                        if (f == NULL) {        /* drop packet */
                                return IP_FW_DENY;
                        }
-               } else if (ipfw_flushing) {
+               } else if (sysctl_var_fw3_flushing) {
                        /* Rules are being flushed; skip to default rule */
-                       f = ctx->ipfw_default_rule;
+                       f = ctx->default_rule;
                }
        }
        if ((mtag = m_tag_find(m, PACKET_TAG_IPFW_DIVERT, NULL)) != NULL) {
@@ -512,7 +491,7 @@ after_ip_checks:
        /* foreach rule in chain */
        for (; f; f = f->next) {
 again:  /* check the rule again*/
-               if (ctx->ipfw_set_disable & (1 << f->set)) {
+               if (ctx->sets & (1 << f->set)) {
                        continue;
                }
 
@@ -606,13 +585,13 @@ done:
        return cmd_val;
 
 pullup_failed:
-       if (fw_verbose)
+       if (sysctl_var_fw3_verbose)
                kprintf("pullup failed\n");
        return IP_FW_DENY;
 }
 
-static struct mbuf *
-ipfw_dummynet_io(struct mbuf *m, int pipe_nr, int dir, struct ip_fw_args *fwa)
+struct mbuf *
+ip_fw3_dummynet_io(struct mbuf *m, int pipe_nr, int dir, struct ip_fw_args *fwa)
 {
        struct m_tag *mtag;
        struct dn_pkt *pkt;
@@ -664,37 +643,12 @@ ipfw_dummynet_io(struct mbuf *m, int pipe_nr, int dir, struct ip_fw_args *fwa)
        return (m);
 }
 
-static __inline void
-ipfw_inc_static_count(struct ip_fw *rule)
-{
-       /* Static rule's counts are updated only on CPU0 */
-       KKASSERT(mycpuid == 0);
-
-       static_count++;
-       static_ioc_len += IOC_RULESIZE(rule);
-}
-
-static __inline void
-ipfw_dec_static_count(struct ip_fw *rule)
-{
-       int l = IOC_RULESIZE(rule);
-
-       /* Static rule's counts are updated only on CPU0 */
-       KKASSERT(mycpuid == 0);
-
-       KASSERT(static_count > 0, ("invalid static count %u", static_count));
-       static_count--;
-
-       KASSERT(static_ioc_len >= l,
-                       ("invalid static len %u", static_ioc_len));
-       static_ioc_len -= l;
-}
 
-static void
-ipfw_add_rule_dispatch(netmsg_t nmsg)
+void
+add_rule_dispatch(netmsg_t nmsg)
 {
        struct netmsg_ipfw *fwmsg = (struct netmsg_ipfw *)nmsg;
-       struct ipfw_context *ctx = ipfw_ctx[mycpuid];
+       struct ipfw3_context *ctx = fw3_ctx[mycpuid];
        struct ip_fw *rule, *prev,*next;
        const struct ipfw_ioc_rule *ioc_rule;
 
@@ -707,7 +661,7 @@ ipfw_add_rule_dispatch(netmsg_t nmsg)
        rule->set = ioc_rule->set;
        bcopy(ioc_rule->cmd, rule->cmd, rule->cmd_len * 4);
 
-       for (prev = NULL, next = ctx->ipfw_rule_chain;
+       for (prev = NULL, next = ctx->rules;
                next; prev = next, next = next->next) {
                if (next->rulenum > ioc_rule->rulenum) {
                        break;
@@ -722,8 +676,8 @@ ipfw_add_rule_dispatch(netmsg_t nmsg)
                rule->next = next;
                prev->next = rule;
        } else {
-               rule->next = ctx->ipfw_rule_chain;
-               ctx->ipfw_rule_chain = rule;
+               rule->next = ctx->rules;
+               ctx->rules = rule;
        }
 
        /*
@@ -736,10 +690,6 @@ ipfw_add_rule_dispatch(netmsg_t nmsg)
        /* prepare for next CPU */
        fwmsg->sibling = rule;
 
-       if (mycpuid == 0) {
-               /* Statistics only need to be updated once */
-               ipfw_inc_static_count(rule);
-       }
        netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
 }
 
@@ -748,10 +698,10 @@ ipfw_add_rule_dispatch(netmsg_t nmsg)
  * call dispatch function to add rule into the list
  * Update the statistic
  */
-static void
-ipfw_add_rule(struct ipfw_ioc_rule *ioc_rule)
+void
+ip_fw3_add_rule(struct ipfw_ioc_rule *ioc_rule)
 {
-       struct ipfw_context *ctx = ipfw_ctx[mycpuid];
+       struct ipfw3_context *ctx = fw3_ctx[mycpuid];
        struct netmsg_ipfw fwmsg;
        struct netmsg_base *nmsg;
        struct ip_fw *f;
@@ -763,7 +713,7 @@ ipfw_add_rule(struct ipfw_ioc_rule *ioc_rule)
         * default rule, and add rule number incremental step.
         */
        if (ioc_rule->rulenum == 0) {
-               int step = autoinc_step;
+               int step = sysctl_var_autoinc_step;
 
                KKASSERT(step >= IPFW_AUTOINC_STEP_MIN &&
                                step <= IPFW_AUTOINC_STEP_MAX);
@@ -771,7 +721,7 @@ ipfw_add_rule(struct ipfw_ioc_rule *ioc_rule)
                /*
                 * Locate the highest numbered rule before default
                 */
-               for (f = ctx->ipfw_rule_chain; f; f = f->next) {
+               for (f = ctx->rules; f; f = f->next) {
                        if (f->rulenum == IPFW_DEFAULT_RULE)
                                break;
                        ioc_rule->rulenum = f->rulenum;
@@ -786,12 +736,12 @@ ipfw_add_rule(struct ipfw_ioc_rule *ioc_rule)
        bzero(&fwmsg, sizeof(fwmsg));
        nmsg = &fwmsg.base;
        netmsg_init(nmsg, NULL, &curthread->td_msgport,
-                       0, ipfw_add_rule_dispatch);
+                       0, add_rule_dispatch);
        fwmsg.ioc_rule = ioc_rule;
 
        netisr_domsg(nmsg, 0);
 
-       DPRINTF("++ installed rule %d, static count now %d\n",
+       DEBUG("++ installed rule %d, static count now %d\n",
                        ioc_rule->rulenum, static_count);
 }
 
@@ -804,41 +754,36 @@ ipfw_add_rule(struct ipfw_ioc_rule *ioc_rule)
  * Arguments are not checked, so they better be correct.
  * Must be called at splimp().
  */
-static struct ip_fw *
-ipfw_delete_rule(struct ipfw_context *ctx,
+struct ip_fw *
+ip_fw3_delete_rule(struct ipfw3_context *ctx,
                 struct ip_fw *prev, struct ip_fw *rule)
 {
        if (prev == NULL)
-               ctx->ipfw_rule_chain = rule->next;
+               ctx->rules = rule->next;
        else
                prev->next = rule->next;
 
-       if (mycpuid == IPFW_CFGCPUID)
-               ipfw_dec_static_count(rule);
-
        kfree(rule, M_IPFW3);
        rule = NULL;
        return NULL;
 }
 
-static void
-ipfw_flush_rule_dispatch(netmsg_t nmsg)
+void
+flush_rule_dispatch(netmsg_t nmsg)
 {
-       struct lwkt_msg *lmsg = &nmsg->lmsg;
-       struct ipfw_context *ctx = ipfw_ctx[mycpuid];
+       struct netmsg_del *dmsg = (struct netmsg_del *)nmsg;
+       struct ipfw3_context *ctx = fw3_ctx[mycpuid];
        struct ip_fw *rule, *the_rule;
-       int kill_default = lmsg->u.ms_result;
+       int kill_default = dmsg->kill_default;
 
-       rule = ctx->ipfw_rule_chain;
+       rule = ctx->rules;
        while (rule != NULL) {
                if (rule->rulenum == IPFW_DEFAULT_RULE && kill_default == 0) {
-                       ctx->ipfw_rule_chain = rule;
+                       ctx->rules = rule;
                        break;
                }
                the_rule = rule;
                rule = rule->next;
-               if (mycpuid == IPFW_CFGCPUID)
-                       ipfw_dec_static_count(the_rule);
 
                kfree(the_rule, M_IPFW3);
        }
@@ -846,102 +791,47 @@ ipfw_flush_rule_dispatch(netmsg_t nmsg)
        netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
 }
 
-static void
-ipfw_append_state_dispatch(netmsg_t nmsg)
-{
-       struct netmsg_del *dmsg = (struct netmsg_del *)nmsg;
-       struct ipfw_ioc_state *ioc_state = dmsg->ioc_state;
-       (*ipfw_basic_append_state_prt)(ioc_state);
-       netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
-}
-
-static void
-ipfw_delete_state_dispatch(netmsg_t nmsg)
-{
-       struct netmsg_del *dmsg = (struct netmsg_del *)nmsg;
-       struct ipfw_context *ctx = ipfw_ctx[mycpuid];
-       struct ip_fw *rule = ctx->ipfw_rule_chain;
-       while (rule != NULL) {
-               if (rule->rulenum == dmsg->rulenum) {
-                       break;
-               }
-               rule = rule->next;
-       }
-
-       (*ipfw_basic_flush_state_prt)(rule);
-       netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
-}
 
 /*
  * Deletes all rules from a chain (including the default rule
  * if the second argument is set).
  * Must be called at splimp().
  */
-static void
-ipfw_ctl_flush_rule(int kill_default)
+void
+ip_fw3_ctl_flush_rule(int kill_default)
 {
        struct netmsg_del dmsg;
-       struct netmsg_base nmsg;
-       struct lwkt_msg *lmsg;
 
        IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
 
-       /*
-        * If 'kill_default' then caller has done the necessary
-        * msgport syncing; unnecessary to do it again.
-        */
        if (!kill_default) {
-               /*
-                * Let ipfw_chk() know the rules are going to
-                * be flushed, so it could jump directly to
-                * the default rule.
-                */
-               ipfw_flushing = 1;
+               sysctl_var_fw3_flushing = 1;
                netmsg_service_sync();
        }
-
-       /*
-        * if ipfw_basic_flush_state_prt
-        * flush all states in all CPU
-        */
-       if (ipfw_basic_flush_state_prt != NULL) {
-               bzero(&dmsg, sizeof(dmsg));
-               netmsg_init(&dmsg.base, NULL, &curthread->td_msgport,
-                               0, ipfw_delete_state_dispatch);
-               netisr_domsg(&dmsg.base, 0);
-       }
        /*
         * Press the 'flush' button
         */
-       bzero(&nmsg, sizeof(nmsg));
-       netmsg_init(&nmsg, NULL, &curthread->td_msgport,
-                       0, ipfw_flush_rule_dispatch);
-       lmsg = &nmsg.lmsg;
-       lmsg->u.ms_result = kill_default;
-       netisr_domsg(&nmsg, 0);
-
-       if (kill_default) {
-               KASSERT(static_count == 0,
-                               ("%u static rules remain", static_count));
-               KASSERT(static_ioc_len == 0,
-                               ("%u bytes of static rules remain", static_ioc_len));
-       }
+       bzero(&dmsg, sizeof(dmsg));
+       netmsg_init(&dmsg.base, NULL, &curthread->td_msgport,
+                       0, flush_rule_dispatch);
+       dmsg.kill_default = kill_default;
+       netisr_domsg(&dmsg.base, 0);
 
        /* Flush is done */
-       ipfw_flushing = 0;
+       sysctl_var_fw3_flushing = 0;
 }
 
-static void
-ipfw_delete_rule_dispatch(netmsg_t nmsg)
+void
+delete_rule_dispatch(netmsg_t nmsg)
 {
        struct netmsg_del *dmsg = (struct netmsg_del *)nmsg;
-       struct ipfw_context *ctx = ipfw_ctx[mycpuid];
+       struct ipfw3_context *ctx = fw3_ctx[mycpuid];
        struct ip_fw *rule, *prev = NULL;
 
-       rule = ctx->ipfw_rule_chain;
+       rule = ctx->rules;
        while (rule!=NULL) {
                if (rule->rulenum == dmsg->rulenum) {
-                       ipfw_delete_rule(ctx, prev, rule);
+                       ip_fw3_delete_rule(ctx, prev, rule);
                        break;
                }
                prev = rule;
@@ -951,329 +841,57 @@ ipfw_delete_rule_dispatch(netmsg_t nmsg)
        netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
 }
 
-static int
-ipfw_alt_delete_rule(uint16_t rulenum)
-{
-       struct netmsg_del dmsg;
-       struct netmsg_base *nmsg;
-
-       /*
-        * delete the state which stub is the rule
-        * which belongs to the CPU and the rulenum
-        */
-       bzero(&dmsg, sizeof(dmsg));
-       nmsg = &dmsg.base;
-       netmsg_init(nmsg, NULL, &curthread->td_msgport,
-                       0, ipfw_delete_state_dispatch);
-       dmsg.rulenum = rulenum;
-       netisr_domsg(nmsg, 0);
-
-       /*
-        * Get rid of the rule duplications on all CPUs
-        */
-       bzero(&dmsg, sizeof(dmsg));
-       nmsg = &dmsg.base;
-       netmsg_init(nmsg, NULL, &curthread->td_msgport,
-                       0, ipfw_delete_rule_dispatch);
-       dmsg.rulenum = rulenum;
-       netisr_domsg(nmsg, 0);
-       return 0;
-}
-
-static void
-ipfw_alt_delete_ruleset_dispatch(netmsg_t nmsg)
-{
-       struct netmsg_del *dmsg = (struct netmsg_del *)nmsg;
-       struct ipfw_context *ctx = ipfw_ctx[mycpuid];
-       struct ip_fw *prev, *rule;
-#ifdef INVARIANTS
-       int del = 0;
-#endif
-
-       prev = NULL;
-       rule = ctx->ipfw_rule_chain;
-       while (rule != NULL) {
-               if (rule->set == dmsg->from_set) {
-                       rule = ipfw_delete_rule(ctx, prev, rule);
-#ifdef INVARIANTS
-                       del = 1;
-#endif
-               } else {
-                       prev = rule;
-                       rule = rule->next;
-               }
-       }
-       KASSERT(del, ("no match set?!"));
-
-       netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
-}
-
-static void
-ipfw_disable_ruleset_state_dispatch(netmsg_t nmsg)
-{
-       struct netmsg_del *dmsg = (struct netmsg_del *)nmsg;
-       struct ipfw_context *ctx = ipfw_ctx[mycpuid];
-       struct ip_fw *rule;
-#ifdef INVARIANTS
-       int cleared = 0;
-#endif
-
-       for (rule = ctx->ipfw_rule_chain; rule; rule = rule->next) {
-               if (rule->set == dmsg->from_set) {
-#ifdef INVARIANTS
-                       cleared = 1;
-#endif
-               }
-       }
-       KASSERT(cleared, ("no match set?!"));
-
-       netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
-}
-
-static int
-ipfw_alt_delete_ruleset(uint8_t set)
+int
+ip_fw3_ctl_delete_rule(struct sockopt *sopt)
 {
        struct netmsg_del dmsg;
        struct netmsg_base *nmsg;
-       int state, del;
-       struct ip_fw *rule;
-       struct ipfw_context *ctx = ipfw_ctx[mycpuid];
-
-       /*
-        * Check whether the 'set' exists.  If it exists,
-        * then check whether any rules within the set will
-        * try to create states.
-        */
-       state = 0;
-       del = 0;
-       for (rule = ctx->ipfw_rule_chain; rule; rule = rule->next) {
-               if (rule->set == set) {
-                       del = 1;
-               }
-       }
-       if (!del)
-               return 0; /* XXX EINVAL? */
+       int *rulenum;
 
-       if (state) {
-               /*
-                * Clear the STATE flag, so no more states will be
-                * created based the rules in this set.
-                */
-               bzero(&dmsg, sizeof(dmsg));
-               nmsg = &dmsg.base;
-               netmsg_init(nmsg, NULL, &curthread->td_msgport,
-                               0, ipfw_disable_ruleset_state_dispatch);
-               dmsg.from_set = set;
+       rulenum = (int *) sopt->sopt_val;
 
-               netisr_domsg(nmsg, 0);
-       }
 
        /*
-        * Delete this set
-        */
-       bzero(&dmsg, sizeof(dmsg));
-       nmsg = &dmsg.base;
-       netmsg_init(nmsg, NULL, &curthread->td_msgport,
-                       0, ipfw_alt_delete_ruleset_dispatch);
-       dmsg.from_set = set;
-
-       netisr_domsg(nmsg, 0);
-       return 0;
-}
-
-static void
-ipfw_alt_move_rule_dispatch(netmsg_t nmsg)
-{
-       struct netmsg_del *dmsg = (struct netmsg_del *)nmsg;
-       struct ip_fw *rule;
-
-       rule = dmsg->start_rule;
-
-       /*
-        * Move to the position on the next CPU
-        * before the msg is forwarded.
-        */
-
-       while (rule && rule->rulenum <= dmsg->rulenum) {
-               if (rule->rulenum == dmsg->rulenum)
-                       rule->set = dmsg->to_set;
-               rule = rule->next;
-       }
-       netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
-}
-
-static int
-ipfw_alt_move_rule(uint16_t rulenum, uint8_t set)
-{
-       struct netmsg_del dmsg;
-       struct netmsg_base *nmsg;
-       struct ip_fw *rule;
-       struct ipfw_context *ctx = ipfw_ctx[mycpuid];
-
-       /*
-        * Locate first rule to move
+        * Get rid of the rule duplications on all CPUs
         */
-       for (rule = ctx->ipfw_rule_chain;
-               rule && rule->rulenum <= rulenum; rule = rule->next) {
-               if (rule->rulenum == rulenum && rule->set != set)
-                       break;
-       }
-       if (rule == NULL || rule->rulenum > rulenum)
-               return 0; /* XXX error? */
-
        bzero(&dmsg, sizeof(dmsg));
        nmsg = &dmsg.base;
        netmsg_init(nmsg, NULL, &curthread->td_msgport,
-                       0, ipfw_alt_move_rule_dispatch);
-       dmsg.start_rule = rule;
-       dmsg.rulenum = rulenum;
-       dmsg.to_set = set;
-
-       netisr_domsg(nmsg, 0);
-       KKASSERT(dmsg.start_rule == NULL);
-       return 0;
-}
-
-static void
-ipfw_alt_move_ruleset_dispatch(netmsg_t nmsg)
-{
-       struct netmsg_del *dmsg = (struct netmsg_del *)nmsg;
-       struct ipfw_context *ctx = ipfw_ctx[mycpuid];
-       struct ip_fw *rule;
-
-       for (rule = ctx->ipfw_rule_chain; rule; rule = rule->next) {
-               if (rule->set == dmsg->from_set)
-                       rule->set = dmsg->to_set;
-       }
-       netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
-}
-
-static int
-ipfw_alt_move_ruleset(uint8_t from_set, uint8_t to_set)
-{
-       struct netmsg_del dmsg;
-       struct netmsg_base *nmsg;
-
-       bzero(&dmsg, sizeof(dmsg));
-       nmsg = &dmsg.base;
-       netmsg_init(nmsg, NULL, &curthread->td_msgport,
-                       0, ipfw_alt_move_ruleset_dispatch);
-       dmsg.from_set = from_set;
-       dmsg.to_set = to_set;
-
-       netisr_domsg(nmsg, 0);
-       return 0;
-}
-
-static void
-ipfw_alt_swap_ruleset_dispatch(netmsg_t nmsg)
-{
-       struct netmsg_del *dmsg = (struct netmsg_del *)nmsg;
-       struct ipfw_context *ctx = ipfw_ctx[mycpuid];
-       struct ip_fw *rule;
-
-       for (rule = ctx->ipfw_rule_chain; rule; rule = rule->next) {
-               if (rule->set == dmsg->from_set)
-                       rule->set = dmsg->to_set;
-               else if (rule->set == dmsg->to_set)
-                       rule->set = dmsg->from_set;
-       }
-       netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
-}
-
-static int
-ipfw_alt_swap_ruleset(uint8_t set1, uint8_t set2)
-{
-       struct netmsg_del dmsg;
-       struct netmsg_base *nmsg;
-
-       bzero(&dmsg, sizeof(dmsg));
-       nmsg = &dmsg.base;
-       netmsg_init(nmsg, NULL, &curthread->td_msgport,
-                       0, ipfw_alt_swap_ruleset_dispatch);
-       dmsg.from_set = set1;
-       dmsg.to_set = set2;
-
+                       0, delete_rule_dispatch);
+       dmsg.rulenum = *rulenum;
        netisr_domsg(nmsg, 0);
        return 0;
 }
 
-
-static int
-ipfw_ctl_alter(uint32_t arg)
-{
-       uint16_t rulenum;
-       uint8_t cmd, new_set;
-       int error = 0;
-
-       rulenum = arg & 0xffff;
-       cmd = (arg >> 24) & 0xff;
-       new_set = (arg >> 16) & 0xff;
-
-       if (cmd > 4)
-               return EINVAL;
-       if (new_set >= IPFW_DEFAULT_SET)
-               return EINVAL;
-       if (cmd == 0 || cmd == 2) {
-               if (rulenum == IPFW_DEFAULT_RULE)
-                       return EINVAL;
-       } else {
-               if (rulenum >= IPFW_DEFAULT_SET)
-                       return EINVAL;
-       }
-
-       switch (cmd) {
-       case 0: /* delete rules with given number */
-               error = ipfw_alt_delete_rule(rulenum);
-               break;
-
-       case 1: /* delete all rules with given set number */
-               error = ipfw_alt_delete_ruleset(rulenum);
-               break;
-
-       case 2: /* move rules with given number to new set */
-               error = ipfw_alt_move_rule(rulenum, new_set);
-               break;
-
-       case 3: /* move rules with given set number to new set */
-               error = ipfw_alt_move_ruleset(rulenum, new_set);
-               break;
-
-       case 4: /* swap two sets */
-               error = ipfw_alt_swap_ruleset(rulenum, new_set);
-               break;
-       }
-       return error;
-}
-
 /*
  * Clear counters for a specific rule.
  */
-static void
-clear_counters(struct ip_fw *rule)
+void
+ip_fw3_clear_counters(struct ip_fw *rule)
 {
        rule->bcnt = rule->pcnt = 0;
        rule->timestamp = 0;
 }
 
-static void
-ipfw_zero_entry_dispatch(netmsg_t nmsg)
+void
+ip_fw3_zero_entry_dispatch(netmsg_t nmsg)
 {
        struct netmsg_zent *zmsg = (struct netmsg_zent *)nmsg;
-       struct ipfw_context *ctx = ipfw_ctx[mycpuid];
+       struct ipfw3_context *ctx = fw3_ctx[mycpuid];
        struct ip_fw *rule;
 
        if (zmsg->rulenum == 0) {
-               for (rule = ctx->ipfw_rule_chain; rule; rule = rule->next) {
-                       clear_counters(rule);
+               for (rule = ctx->rules; rule; rule = rule->next) {
+                       ip_fw3_clear_counters(rule);
                }
        } else {
-               for (rule = ctx->ipfw_rule_chain; rule; rule = rule->next) {
+               for (rule = ctx->rules; rule; rule = rule->next) {
                        if (rule->rulenum == zmsg->rulenum) {
-                               clear_counters(rule);
+                               ip_fw3_clear_counters(rule);
                        }
                }
        }
+       ip_fw3_clear_counters(ctx->default_rule);
        netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
 }
 
@@ -1283,18 +901,18 @@ ipfw_zero_entry_dispatch(netmsg_t nmsg)
  * rule number.
  * @arg log_only is 1 if we only want to reset logs, zero otherwise.
  */
-static int
-ipfw_ctl_zero_entry(int rulenum, int log_only)
+int
+ip_fw3_ctl_zero_entry(int rulenum, int log_only)
 {
        struct netmsg_zent zmsg;
        struct netmsg_base *nmsg;
        const char *msg;
-       struct ipfw_context *ctx = ipfw_ctx[mycpuid];
+       struct ipfw3_context *ctx = fw3_ctx[mycpuid];
 
        bzero(&zmsg, sizeof(zmsg));
        nmsg = &zmsg.base;
        netmsg_init(nmsg, NULL, &curthread->td_msgport,
-                       0, ipfw_zero_entry_dispatch);
+                       0, ip_fw3_zero_entry_dispatch);
        zmsg.log_only = log_only;
 
        if (rulenum == 0) {
@@ -1306,7 +924,7 @@ ipfw_ctl_zero_entry(int rulenum, int log_only)
                /*
                 * Locate the first rule with 'rulenum'
                 */
-               for (rule = ctx->ipfw_rule_chain; rule; rule = rule->next) {
+               for (rule = ctx->rules; rule; rule = rule->next) {
                        if (rule->rulenum == rulenum)
                                break;
                }
@@ -1321,89 +939,17 @@ ipfw_ctl_zero_entry(int rulenum, int log_only)
        netisr_domsg(nmsg, 0);
        KKASSERT(zmsg.start_rule == NULL);
 
-       if (fw_verbose)
+       if (sysctl_var_fw3_verbose)
                log(LOG_SECURITY | LOG_NOTICE, msg, rulenum);
        return (0);
 }
 
-static int
-ipfw_ctl_add_state(struct sockopt *sopt)
-{
-       struct ipfw_ioc_state *ioc_state;
-       ioc_state = sopt->sopt_val;
-       if (ipfw_basic_append_state_prt != NULL) {
-               struct netmsg_del dmsg;
-               bzero(&dmsg, sizeof(dmsg));
-               netmsg_init(&dmsg.base, NULL, &curthread->td_msgport,
-                       0, ipfw_append_state_dispatch);
-               (&dmsg)->ioc_state = ioc_state;
-               netisr_domsg(&dmsg.base, 0);
-       }
-       return 0;
-}
-
-static int
-ipfw_ctl_delete_state(struct sockopt *sopt)
-{
-       int rulenum = 0, error;
-       if (sopt->sopt_valsize != 0) {
-               error = soopt_to_kbuf(sopt, &rulenum, sizeof(int), sizeof(int));
-               if (error) {
-                       return -1;
-               }
-       }
-       struct ipfw_context *ctx = ipfw_ctx[mycpuid];
-       struct ip_fw *rule = ctx->ipfw_rule_chain;
-
-       while (rule!=NULL) {
-               if (rule->rulenum == rulenum) {
-                       break;
-               }
-               rule = rule->next;
-       }
-       if (rule == NULL) {
-               return -1;
-       }
-
-       struct netmsg_del dmsg;
-       struct netmsg_base *nmsg;
-       /*
-        * delete the state which stub is the rule
-        * which belongs to the CPU and the rulenum
-        */
-       bzero(&dmsg, sizeof(dmsg));
-       nmsg = &dmsg.base;
-       netmsg_init(nmsg, NULL, &curthread->td_msgport,
-                       0, ipfw_delete_state_dispatch);
-       dmsg.rulenum = rulenum;
-       netisr_domsg(nmsg, 0);
-       return 0;
-}
-
-static int
-ipfw_ctl_flush_state(struct sockopt *sopt)
-{
-       struct netmsg_del dmsg;
-       struct netmsg_base *nmsg;
-       /*
-        * delete the state which stub is the rule
-        * which belongs to the CPU and the rulenum
-        */
-       bzero(&dmsg, sizeof(dmsg));
-       nmsg = &dmsg.base;
-       netmsg_init(nmsg, NULL, &curthread->td_msgport,
-                       0, ipfw_delete_state_dispatch);
-       dmsg.rulenum = 0;
-       netisr_domsg(nmsg, 0);
-       return 0;
-}
-
 /*
  * Get the ioc_rule from the sopt
- * call ipfw_add_rule to add the rule
+ * call ip_fw3_add_rule to add the rule
  */
-static int
-ipfw_ctl_add_rule(struct sockopt *sopt)
+int
+ip_fw3_ctl_add_rule(struct sockopt *sopt)
 {
        struct ipfw_ioc_rule *ioc_rule;
        size_t size;
@@ -1419,77 +965,18 @@ ipfw_ctl_add_rule(struct sockopt *sopt)
        }
        ioc_rule = sopt->sopt_val;
 
-       ipfw_add_rule(ioc_rule);
+       ip_fw3_add_rule(ioc_rule);
        return 0;
 }
 
-static void *
-ipfw_copy_state(struct ip_fw_state *state, struct ipfw_ioc_state *ioc_state, int cpuid)
-{
-       ioc_state->pcnt = state->pcnt;
-       ioc_state->bcnt = state->bcnt;
-       ioc_state->lifetime = state->lifetime;
-       ioc_state->timestamp = state->timestamp;
-       ioc_state->cpuid = cpuid;
-       ioc_state->expiry = state->expiry;
-       ioc_state->rulenum = state->stub->rulenum;
-
-       bcopy(&state->flow_id, &ioc_state->flow_id, sizeof(struct ipfw_flow_id));
-       return ioc_state + 1;
-}
-
-static void *
-ipfw_copy_rule(const struct ip_fw *rule, struct ipfw_ioc_rule *ioc_rule)
-{
-       const struct ip_fw *sibling;
-#ifdef INVARIANTS
-       int i;
-#endif
-
-       ioc_rule->act_ofs = rule->act_ofs;
-       ioc_rule->cmd_len = rule->cmd_len;
-       ioc_rule->rulenum = rule->rulenum;
-       ioc_rule->set = rule->set;
-
-       ioc_rule->set_disable = ipfw_ctx[mycpuid]->ipfw_set_disable;
-       ioc_rule->static_count = static_count;
-       ioc_rule->static_len = static_ioc_len;
-
-       ioc_rule->pcnt = 1;
-       ioc_rule->bcnt = 0;
-       ioc_rule->timestamp = 0;
-
-#ifdef INVARIANTS
-       i = 0;
-#endif
-       ioc_rule->pcnt = 0;
-       ioc_rule->bcnt = 0;
-       ioc_rule->timestamp = 0;
-       for (sibling = rule; sibling != NULL; sibling = sibling->sibling) {
-               ioc_rule->pcnt += sibling->pcnt;
-               ioc_rule->bcnt += sibling->bcnt;
-               if (sibling->timestamp > ioc_rule->timestamp)
-                       ioc_rule->timestamp = sibling->timestamp;
-#ifdef INVARIANTS
-               ++i;
-#endif
-       }
-
-       KASSERT(i == ncpus, ("static rule is not duplicated on every cpu"));
-
-       bcopy(rule->cmd, ioc_rule->cmd, ioc_rule->cmd_len * 4 /* XXX */);
-
-       return ((uint8_t *)ioc_rule + IOC_RULESIZE(ioc_rule));
-}
-
-static int
-ipfw_ctl_get_modules(struct sockopt *sopt)
+int
+ip_fw3_ctl_get_modules(struct sockopt *sopt)
 {
        int i;
-       struct ipfw_module *mod;
+       struct ipfw3_module *mod;
        char module_str[1024];
        memset(module_str,0,1024);
-       for (i = 0, mod = ipfw_modules; i < MAX_MODULE; i++, mod++) {
+       for (i = 0, mod = fw3_modules; i < MAX_MODULE; i++, mod++) {
                if (mod->type != 0) {
                        if (i > 0)
                                strcat(module_str,",");
@@ -1505,182 +992,96 @@ ipfw_ctl_get_modules(struct sockopt *sopt)
 /*
  * Copy all static rules and states on all CPU
  */
-static int
-ipfw_ctl_get_rules(struct sockopt *sopt)
+int
+ip_fw3_ctl_get_rules(struct sockopt *sopt)
 {
-       struct ipfw_context *ctx = ipfw_ctx[mycpuid];
-       struct ipfw_state_context *state_ctx;
+       struct ipfw3_context *ctx = fw3_ctx[mycpuid];
        struct ip_fw *rule;
-       struct ip_fw_state *state;
-       void *bp;
-       size_t size;
-       int i, j, state_count = 0;
-
-       size = static_ioc_len;
-       for (i = 0; i < ncpus; i++) {
-               for (j = 0; j < ctx->state_hash_size; j++) {
-                       state_ctx = &ipfw_ctx[i]->state_ctx[j];
-                       state_count += state_ctx->count;
-               }
-       }
-       if (state_count > 0) {
-               size += state_count * sizeof(struct ipfw_ioc_state);
-       }
-
-       if (sopt->sopt_valsize < size) {
-               /* XXX TODO sopt_val is not big enough */
-               bzero(sopt->sopt_val, sopt->sopt_valsize);
-               return 0;
-       }
+       struct ipfw_ioc_rule *ioc;
+       const struct ip_fw *sibling;
+       int total_len = 0;
 
-       sopt->sopt_valsize = size;
-       bp = sopt->sopt_val;
+       ioc = (struct ipfw_ioc_rule *)sopt->sopt_val;
 
-       for (rule = ctx->ipfw_rule_chain; rule; rule = rule->next) {
-               bp = ipfw_copy_rule(rule, bp);
-       }
-       if (state_count > 0 ) {
-               for (i = 0; i < ncpus; i++) {
-                       for (j = 0; j < ctx->state_hash_size; j++) {
-                               state_ctx = &ipfw_ctx[i]->state_ctx[j];
-                               state = state_ctx->state;
-                               while (state != NULL) {
-                                       bp = ipfw_copy_state(state, bp, i);
-                                       state = state->next;
-                               }
-                       }
+       for (rule = ctx->rules; rule; rule = rule->next) {
+               total_len += IOC_RULESIZE(rule);
+               if (total_len > sopt->sopt_valsize) {
+                       bzero(sopt->sopt_val, sopt->sopt_valsize);
+                       return 0;
+               }
+               ioc->act_ofs = rule->act_ofs;
+               ioc->cmd_len = rule->cmd_len;
+               ioc->rulenum = rule->rulenum;
+               ioc->set = rule->set;
+
+               ioc->sets = fw3_ctx[mycpuid]->sets;
+               ioc->pcnt = 0;
+               ioc->bcnt = 0;
+               ioc->timestamp = 0;
+               for (sibling = rule; sibling != NULL; sibling = sibling->sibling) {
+                       ioc->pcnt += sibling->pcnt;
+                       ioc->bcnt += sibling->bcnt;
+                       if (sibling->timestamp > ioc->timestamp)
+                               ioc->timestamp = sibling->timestamp;
                }
+               bcopy(rule->cmd, ioc->cmd, ioc->cmd_len * 4);
+               ioc = (struct ipfw_ioc_rule *)((uint8_t *)ioc + IOC_RULESIZE(ioc));
        }
+       sopt->sopt_valsize = total_len;
        return 0;
 }
 
-static void
-ipfw_set_disable_dispatch(netmsg_t nmsg)
-{
-       struct lwkt_msg *lmsg = &nmsg->lmsg;
-       struct ipfw_context *ctx = ipfw_ctx[mycpuid];
-
-       ctx->ipfw_set_disable = lmsg->u.ms_result32;
-
-       netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
-}
-
-static void
-ipfw_ctl_set_disable(uint32_t disable, uint32_t enable)
-{
-       struct netmsg_base nmsg;
-       struct lwkt_msg *lmsg;
-       uint32_t set_disable;
-
-       /* IPFW_DEFAULT_SET is always enabled */
-       enable |= (1 << IPFW_DEFAULT_SET);
-       set_disable = (ipfw_ctx[mycpuid]->ipfw_set_disable | disable) & ~enable;
-
-       bzero(&nmsg, sizeof(nmsg));
-       netmsg_init(&nmsg, NULL, &curthread->td_msgport,
-                       0, ipfw_set_disable_dispatch);
-       lmsg = &nmsg.lmsg;
-       lmsg->u.ms_result32 = set_disable;
-
-       netisr_domsg(&nmsg, 0);
-}
-
 
 /*
- * ipfw_ctl_x - extended version of ipfw_ctl
+ * ip_fw3_ctl_x - extended version of ip_fw3_ctl
  * remove the x_header, and adjust the sopt_name,sopt_val and sopt_valsize.
  */
 int
-ipfw_ctl_x(struct sockopt *sopt)
+ip_fw3_ctl_x(struct sockopt *sopt)
 {
        ip_fw_x_header *x_header;
        x_header = (ip_fw_x_header *)(sopt->sopt_val);
        sopt->sopt_name = x_header->opcode;
        sopt->sopt_valsize -= sizeof(ip_fw_x_header);
        bcopy(++x_header, sopt->sopt_val, sopt->sopt_valsize);
-       return ipfw_ctl(sopt);
+       return ip_fw3_ctl(sopt);
 }
 
 
 /**
  * {set|get}sockopt parser.
  */
-static int
-ipfw_ctl(struct sockopt *sopt)
+int
+ip_fw3_ctl(struct sockopt *sopt)
 {
-       int error, rulenum;
-       uint32_t *masks;
-       size_t size;
-
-       error = 0;
+       int error = 0;
        switch (sopt->sopt_name) {
                case IP_FW_X:
-                       ipfw_ctl_x(sopt);
+                       ip_fw3_ctl_x(sopt);
                        break;
                case IP_FW_GET:
-                       error = ipfw_ctl_get_rules(sopt);
-                       break;
                case IP_FW_MODULE:
-                       error = ipfw_ctl_get_modules(sopt);
-                       break;
-
                case IP_FW_FLUSH:
-                       ipfw_ctl_flush_rule(0);
-                       break;
-
                case IP_FW_ADD:
-                       error = ipfw_ctl_add_rule(sopt);
-                       break;
-
                case IP_FW_DEL:
-                       /*
-                        * IP_FW_DEL is used for deleting single rules or sets,
-                        * and (ab)used to atomically manipulate sets.
-                        * Argument size is used to distinguish between the two:
-                        *      sizeof(uint32_t)
-                        *      delete single rule or set of rules,
-                        *      or reassign rules (or sets) to a different set.
-                        *      2 * sizeof(uint32_t)
-                        *      atomic disable/enable sets.
-                        *      first uint32_t contains sets to be disabled,
-                        *      second uint32_t contains sets to be enabled.
-                        */
-                       masks = sopt->sopt_val;
-                       size = sopt->sopt_valsize;
-                       if (size == sizeof(*masks)) {
-                               /*
-                                * Delete or reassign static rule
-                                */
-                               error = ipfw_ctl_alter(masks[0]);
-                       } else if (size == (2 * sizeof(*masks))) {
-                               /*
-                                * Set enable/disable
-                                */
-                               ipfw_ctl_set_disable(masks[0], masks[1]);
-                       } else {
-                               error = EINVAL;
-                       }
-                       break;
                case IP_FW_ZERO:
-               case IP_FW_RESETLOG: /* argument is an int, the rule number */
-                       rulenum = 0;
-                       if (sopt->sopt_valsize != 0) {
-                               error = soopt_to_kbuf(sopt, &rulenum,
-                                               sizeof(int), sizeof(int));
-                               if (error) {
-                                       break;
-                               }
-                       }
-                       error = ipfw_ctl_zero_entry(rulenum,
-                                       sopt->sopt_name == IP_FW_RESETLOG);
+               case IP_FW_RESETLOG:
+                       error = ip_fw3_ctl_sockopt(sopt);
+                       break;
+               case IP_FW_SET_GET:
+               case IP_FW_SET_MOVE_RULE:
+               case IP_FW_SET_MOVE_SET:
+               case IP_FW_SET_SWAP:
+               case IP_FW_SET_TOGGLE:
+                       error = ip_fw3_ctl_set_sockopt(sopt);
                        break;
                case IP_FW_NAT_ADD:
                case IP_FW_NAT_DEL:
                case IP_FW_NAT_FLUSH:
                case IP_FW_NAT_GET:
                case IP_FW_NAT_GET_RECORD:
-                       if (ipfw_ctl_nat_ptr != NULL) {
-                               error = ipfw_ctl_nat_ptr(sopt);
+                       if (ip_fw3_ctl_nat_ptr != NULL) {
+                               error = ip_fw3_ctl_nat_ptr(sopt);
                        }
                        break;
                case IP_DUMMYNET_GET:
@@ -1690,13 +1091,12 @@ ipfw_ctl(struct sockopt *sopt)
                        error = ip_dn_sockopt(sopt);
                        break;
                case IP_FW_STATE_ADD:
-                       error = ipfw_ctl_add_state(sopt);
-                       break;
                case IP_FW_STATE_DEL:
-                       error = ipfw_ctl_delete_state(sopt);
-                       break;
                case IP_FW_STATE_FLUSH:
-                       error = ipfw_ctl_flush_state(sopt);
+               case IP_FW_STATE_GET:
+                       if (ip_fw3_ctl_state_ptr != NULL) {
+                               error = ip_fw3_ctl_state_ptr(sopt);
+                       }
                        break;
                case IP_FW_TABLE_CREATE:
                case IP_FW_TABLE_DELETE:
@@ -1707,7 +1107,9 @@ ipfw_ctl(struct sockopt *sopt)
                case IP_FW_TABLE_SHOW:
                case IP_FW_TABLE_TEST:
                case IP_FW_TABLE_RENAME:
-                       error = ipfw_ctl_table_sockopt(sopt);
+                       if (ip_fw3_ctl_table_ptr != NULL) {
+                               error = ip_fw3_ctl_table_ptr(sopt);
+                       }
                        break;
                case IP_FW_SYNC_SHOW_CONF:
                case IP_FW_SYNC_SHOW_STATUS:
@@ -1721,18 +1123,62 @@ ipfw_ctl(struct sockopt *sopt)
                case IP_FW_SYNC_CENTRE_STOP:
                case IP_FW_SYNC_CENTRE_TEST:
                case IP_FW_SYNC_CENTRE_CLEAR:
-                       error = ipfw_ctl_sync_sockopt(sopt);
+                       if (ip_fw3_ctl_sync_ptr != NULL) {
+                               error = ip_fw3_ctl_sync_ptr(sopt);
+                       }
                        break;
                default:
-                       kprintf("ipfw_ctl invalid option %d\n",
+                       kprintf("ip_fw3_ctl invalid option %d\n",
                                sopt->sopt_name);
                        error = EINVAL;
        }
        return error;
 }
 
-static int
-ipfw_check_in(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir)
+int
+ip_fw3_ctl_sockopt(struct sockopt *sopt)
+{
+       int error = 0, rulenum;
+
+       switch (sopt->sopt_name) {
+               case IP_FW_GET:
+                       error = ip_fw3_ctl_get_rules(sopt);
+                       break;
+               case IP_FW_MODULE:
+                       error = ip_fw3_ctl_get_modules(sopt);
+                       break;
+               case IP_FW_FLUSH:
+                       ip_fw3_ctl_flush_rule(0);
+                       break;
+               case IP_FW_ADD:
+                       error = ip_fw3_ctl_add_rule(sopt);
+                       break;
+               case IP_FW_DEL:
+                       error = ip_fw3_ctl_delete_rule(sopt);
+                       break;
+               case IP_FW_ZERO:
+               case IP_FW_RESETLOG: /* argument is an int, the rule number */
+                       rulenum = 0;
+                       if (sopt->sopt_valsize != 0) {
+                               error = soopt_to_kbuf(sopt, &rulenum,
+                                               sizeof(int), sizeof(int));
+                               if (error) {
+                                       break;
+                               }
+                       }
+                       error = ip_fw3_ctl_zero_entry(rulenum,
+                                       sopt->sopt_name == IP_FW_RESETLOG);
+                       break;
+               default:
+                       kprintf("ip_fw3_ctl invalid option %d\n",
+                               sopt->sopt_name);
+                       error = EINVAL;
+       }
+       return error;
+}
+
+int
+ip_fw3_check_in(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir)
 {
        struct ip_fw_args args;
        struct mbuf *m = *m0;
@@ -1755,7 +1201,7 @@ ipfw_check_in(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir)
        args.eh = NULL;
        args.oif = NULL;
        args.m = m;
-       ret = ipfw_chk(&args);
+       ret = ip_fw3_chk(&args);
        m = args.m;
 
        if (m == NULL) {
@@ -1774,14 +1220,12 @@ ipfw_check_in(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir)
 
                case IP_FW_DUMMYNET:
                        /* Send packet to the appropriate pipe */
-                       m = ipfw_dummynet_io(m, args.cookie, DN_TO_IP_IN,
+                       m = ip_fw3_dummynet_io(m, args.cookie, DN_TO_IP_IN,
                            &args);
                        break;
-
                case IP_FW_TEE:
                        tee = 1;
                        /* FALL THROUGH */
-
                case IP_FW_DIVERT:
                        /*
                         * Must clear bridge tag when changing
@@ -1796,21 +1240,20 @@ ipfw_check_in(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir)
                                error = EACCES;
                        }
                        break;
-
                case IP_FW_NAT:
                        break;
                case IP_FW_ROUTE:
                        break;
                default:
-                       panic("unknown ipfw return value: %d", ret);
+                       panic("unknown ipfw3 return value: %d", ret);
        }
 back:
        *m0 = m;
        return error;
 }
 
-static int
-ipfw_check_out(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir)
+int
+ip_fw3_check_out(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir)
 {
        struct ip_fw_args args;
        struct mbuf *m = *m0;
@@ -1833,7 +1276,7 @@ ipfw_check_out(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir)
        args.eh = NULL;
        args.m = m;
        args.oif = ifp;
-       ret = ipfw_chk(&args);
+       ret = ip_fw3_chk(&args);
        m = args.m;
 
        if (m == NULL) {
@@ -1852,7 +1295,7 @@ ipfw_check_out(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir)
                        break;
 
                case IP_FW_DUMMYNET:
-                       m = ipfw_dummynet_io(m, args.cookie, DN_TO_IP_OUT,
+                       m = ip_fw3_dummynet_io(m, args.cookie, DN_TO_IP_OUT,
                            &args);
                        break;
 
@@ -1876,15 +1319,15 @@ ipfw_check_out(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir)
                case IP_FW_ROUTE:
                        break;
                default:
-                       panic("unknown ipfw return value: %d", ret);
+                       panic("unknown ipfw3 return value: %d", ret);
        }
 back:
        *m0 = m;
        return error;
 }
 
-static void
-ipfw_hook(void)
+void
+ip_fw3_hook(void)
 {
        struct pfil_head *pfh;
        IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
@@ -1893,12 +1336,12 @@ ipfw_hook(void)
        if (pfh == NULL)
                return;
 
-       pfil_add_hook(ipfw_check_in, NULL, PFIL_IN, pfh);
-       pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT, pfh);
+       pfil_add_hook(ip_fw3_check_in, NULL, PFIL_IN, pfh);
+       pfil_add_hook(ip_fw3_check_out, NULL, PFIL_OUT, pfh);
 }
 
-static void
-ipfw_dehook(void)
+void
+ip_fw3_dehook(void)
 {
        struct pfil_head *pfh;
 
@@ -1908,68 +1351,68 @@ ipfw_dehook(void)
        if (pfh == NULL)
                return;
 
-       pfil_remove_hook(ipfw_check_in, NULL, PFIL_IN, pfh);
-       pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT, pfh);
+       pfil_remove_hook(ip_fw3_check_in, NULL, PFIL_IN, pfh);
+       pfil_remove_hook(ip_fw3_check_out, NULL, PFIL_OUT, pfh);
 }
 
-static void
-ipfw_sysctl_enable_dispatch(netmsg_t nmsg)
+void
+ip_fw3_sysctl_enable_dispatch(netmsg_t nmsg)
 {
        struct lwkt_msg *lmsg = &nmsg->lmsg;
        int enable = lmsg->u.ms_result;
 
-       if (fw3_enable == enable)
+       if (sysctl_var_fw3_enable == enable)
                goto reply;
 
-       fw3_enable = enable;
-       if (fw3_enable)
-               ipfw_hook();
+       sysctl_var_fw3_enable = enable;
+       if (sysctl_var_fw3_enable)
+               ip_fw3_hook();
        else
-               ipfw_dehook();
+               ip_fw3_dehook();
 
 reply:
        lwkt_replymsg(lmsg, 0);
 }
 
-static int
-ipfw_sysctl_enable(SYSCTL_HANDLER_ARGS)
+int
+ip_fw3_sysctl_enable(SYSCTL_HANDLER_ARGS)
 {
        struct netmsg_base nmsg;
        struct lwkt_msg *lmsg;
        int enable, error;
 
-       enable = fw3_enable;
+       enable = sysctl_var_fw3_enable;
        error = sysctl_handle_int(oidp, &enable, 0, req);
        if (error || req->newptr == NULL)
                return error;
 
        netmsg_init(&nmsg, NULL, &curthread->td_msgport,
-                       0, ipfw_sysctl_enable_dispatch);
+                       0, ip_fw3_sysctl_enable_dispatch);
        lmsg = &nmsg.lmsg;
        lmsg->u.ms_result = enable;
 
        return lwkt_domsg(IPFW_CFGPORT, lmsg, 0);
 }
 
-static int
-ipfw_sysctl_autoinc_step(SYSCTL_HANDLER_ARGS)
+int
+ip_fw3_sysctl_autoinc_step(SYSCTL_HANDLER_ARGS)
 {
        return sysctl_int_range(oidp, arg1, arg2, req,
                        IPFW_AUTOINC_STEP_MIN, IPFW_AUTOINC_STEP_MAX);
 }
 
-
-static void
-ipfw_ctx_init_dispatch(netmsg_t nmsg)
+void
+ctx_init_dispatch(netmsg_t nmsg)
 {
        struct netmsg_ipfw *fwmsg = (struct netmsg_ipfw *)nmsg;
-       struct ipfw_context *ctx;
+       struct ipfw3_context *ctx;
        struct ip_fw *def_rule;
 
-       ctx = kmalloc(sizeof(struct ipfw_context), M_IPFW3, M_WAITOK | M_ZERO);
-       ipfw_ctx[mycpuid] = ctx;
+       ctx = kmalloc(LEN_FW3_CTX, M_IPFW3, M_WAITOK | M_ZERO);
+       fw3_ctx[mycpuid] = ctx;
+       ctx->sets = IPFW_ALL_SETS;
 
-       def_rule = kmalloc(sizeof(struct ip_fw), M_IPFW3, M_WAITOK | M_ZERO);
+       def_rule = kmalloc(LEN_FW3, M_IPFW3, M_WAITOK | M_ZERO);
        def_rule->act_ofs = 0;
        def_rule->rulenum = IPFW_DEFAULT_RULE;
        def_rule->cmd_len = 2;
@@ -1987,8 +1430,8 @@ ipfw_ctx_init_dispatch(netmsg_t nmsg)
 #endif
 
        /* Install the default rule */
-       ctx->ipfw_default_rule = def_rule;
-       ctx->ipfw_rule_chain = def_rule;
+       ctx->default_rule = def_rule;
+       ctx->rules = def_rule;
 
        /*
         * if sibiling in last CPU is exists,
@@ -2000,15 +1443,11 @@ ipfw_ctx_init_dispatch(netmsg_t nmsg)
        /* prepare for next CPU */
        fwmsg->sibling = def_rule;
 
-       /* Statistics only need to be updated once */
-       if (mycpuid == 0)
-               ipfw_inc_static_count(def_rule);
-
        netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
 }
 
-static void
-ipfw_init_dispatch(netmsg_t nmsg)
+void
+init_dispatch(netmsg_t nmsg)
 {
        struct netmsg_ipfw fwmsg;
        int error = 0;
@@ -2020,63 +1459,56 @@ ipfw_init_dispatch(netmsg_t nmsg)
 
        bzero(&fwmsg, sizeof(fwmsg));
        netmsg_init(&fwmsg.base, NULL, &curthread->td_msgport,
-                       0, ipfw_ctx_init_dispatch);
+                       0, ctx_init_dispatch);
        netisr_domsg(&fwmsg.base, 0);
 
-       ip_fw_chk_ptr = ipfw_chk;
-       ip_fw_ctl_x_ptr = ipfw_ctl_x;
-       ip_fw_dn_io_ptr = ipfw_dummynet_io;
+       ip_fw_chk_ptr = ip_fw3_chk;
+       ip_fw_ctl_x_ptr = ip_fw3_ctl_x;
+       ip_fw_dn_io_ptr = ip_fw3_dummynet_io;
 
        kprintf("ipfw3 initialized, default to %s\n",
                        filters_default_to_accept ? "accept" : "deny");
 
        ip_fw3_loaded = 1;
-       if (fw3_enable)
-               ipfw_hook();
+       if (sysctl_var_fw3_enable)
+               ip_fw3_hook();
 reply:
        lwkt_replymsg(&nmsg->lmsg, error);
 }
 
-static int
-ipfw3_init(void)
+int
+ip_fw3_init(void)
 {
        struct netmsg_base smsg;
        int error;
 
-       ipfw3_log_modevent(MOD_LOAD);
-       ipfw3_sync_modevent(MOD_LOAD);
-
        init_module();
        netmsg_init(&smsg, NULL, &curthread->td_msgport,
-                       0, ipfw_init_dispatch);
-       error = lwkt_domsg(IPFW_CFGPORT, &smsg.lmsg, 0);
-       netmsg_init(&smsg, NULL, &curthread->td_msgport,
-                       0, table_init_dispatch);
+                       0, init_dispatch);
        error = lwkt_domsg(IPFW_CFGPORT, &smsg.lmsg, 0);
        return error;
 }
 
 #ifdef KLD_MODULE
 
-static void
-ipfw_fini_dispatch(netmsg_t nmsg)
+void
+fini_dispatch(netmsg_t nmsg)
 {
        int error = 0, cpu;
 
        ip_fw3_loaded = 0;
 
-       ipfw_dehook();
+       ip_fw3_dehook();
        netmsg_service_sync();
        ip_fw_chk_ptr = NULL;
        ip_fw_ctl_x_ptr = NULL;
        ip_fw_dn_io_ptr = NULL;
-       ipfw_ctl_flush_rule(1 /* kill default rule */);
-       table_fini();
+       ip_fw3_ctl_flush_rule(1);
        /* Free pre-cpu context */
        for (cpu = 0; cpu < ncpus; ++cpu) {
-               if (ipfw_ctx[cpu] != NULL) {
-                       kfree(ipfw_ctx[cpu], M_IPFW3);
-                       ipfw_ctx[cpu] = NULL;
+               if (fw3_ctx[cpu] != NULL) {
+                       kfree(fw3_ctx[cpu], M_IPFW3);
+                       fw3_ctx[cpu] = NULL;
                }
        }
        kprintf("ipfw3 unloaded\n");
@@ -2084,38 +1516,35 @@ ipfw_fini_dispatch(netmsg_t nmsg)
        lwkt_replymsg(&nmsg->lmsg, error);
 }
 
-static int
-ipfw3_fini(void)
+int
+ip_fw3_fini(void)
 {
        struct netmsg_base smsg;
 
-       ipfw3_log_modevent(MOD_UNLOAD);
-       ipfw3_sync_modevent(MOD_UNLOAD);
-
        netmsg_init(&smsg, NULL, &curthread->td_msgport,
-                       0, ipfw_fini_dispatch);
+                       0, fini_dispatch);
        return lwkt_domsg(IPFW_CFGPORT, &smsg.lmsg, 0);
 }
 
 #endif /* KLD_MODULE */
 
 static int
-ipfw3_modevent(module_t mod, int type, void *unused)
+ip_fw3_modevent(module_t mod, int type, void *unused)
 {
        int err = 0;
 
        switch (type) {
                case MOD_LOAD:
-                       err = ipfw3_init();
+                       err = ip_fw3_init();
                        break;
 
                case MOD_UNLOAD:
 
 #ifndef KLD_MODULE
-                       kprintf("ipfw statically compiled, cannot unload\n");
+                       kprintf("ipfw3 statically compiled, cannot unload\n");
                        err = EBUSY;
 #else
-                       err = ipfw3_fini();
+                       err = ip_fw3_fini();
 #endif
                        break;
                default:
@@ -2126,7 +1555,7 @@ ipfw3_modevent(module_t mod, int type, void *unused)
 
 static moduledata_t ipfw3mod = {
        "ipfw3",
-       ipfw3_modevent,
+       ip_fw3_modevent,
        0
 };
 /* ipfw3 must init before ipfw3_basic */
index a6699dc..c5f6817 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (c) 1993 Daniel Boulet
  * Copyright (c) 1994 Ugen J.S.Antsilevich
  * Copyright (c) 2002 Luigi Rizzo, Universita` di Pisa
- * Copyright (c) 2015 The DragonFly Project.  All rights reserved.
+ * Copyright (c) 2015 - 2018 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
  * by Bill Yuan <bycn82@dragonflybsd.org>
 #ifndef _IP_FW3_H_
 #define _IP_FW3_H_
 
+/*
+ * _IPFW2_H is from ipfw/ip_fw2.h, both cannot be included past this
+ * point but we need both the IPFW2_LOADED and IPFW3_LOADED macros
+ */
+#ifndef _IPFW2_H
+
+
 #include <net/bpf.h>
 
-#ifdef _KERNEL
-#include <net/netisr2.h>
 
-int     ip_fw3_sockopt(struct sockopt *);
-extern int ip_fw3_loaded;
-#endif
+#define NEED1(msg)  {if (ac < 1) errx(EX_USAGE, msg);}
+#define NEED2(msg)  {if (ac < 2) errx(EX_USAGE, msg);}
+#define NEED(c, n, msg) {if (c < n) errx(EX_USAGE, msg);}
 
-#define        IPFW3_LOADED    (ip_fw3_loaded)
+#define NEXT_ARG       ac--; if(ac > 0){av++;}
+#define NEXT_ARG1      (*ac)--; if(*ac > 0){(*av)++;}
+#define SWAP_ARG                               \
+do {                                           \
+       if (ac > 2 && isdigit(*(av[1]))) {      \
+               char *p = av[1];                \
+               av[1] = av[2];                  \
+               av[2] = p;                      \
+       }                                       \
+} while (0)
+
+#define IPFW_RULE_SIZE_MAX     255     /* unit: uint32_t */
 
 /*
- * _IPFW2_H is from ipfw/ip_fw2.h, both cannot be included past this
- * point but we need both the IPFW2_LOADED and IPFW3_LOADED macros
+ * type of the keyword, it indecates the position of the keyword in the rule
+ *