Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 14 Sep 2021 20:01:32 GMT
From:      Kristof Provost <kp@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 18fecda93605 - stable/12 - ipfw: Introduce dnctl
Message-ID:  <202109142001.18EK1Wki089562@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/12 has been updated by kp:

URL: https://cgit.FreeBSD.org/src/commit/?id=18fecda9360530bd616af5181554122db111d96b

commit 18fecda9360530bd616af5181554122db111d96b
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2021-05-25 14:54:32 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2021-09-14 08:16:02 +0000

    ipfw: Introduce dnctl
    
    Introduce a link to the ipfw command, dnctl, for dummynet configuration.
    dnctl only handles dummynet configuration, and is part of the effort to
    support dummynet in pf.
    
    /sbin/ipfw continues to accept pipe, queue and sched commands, but these can
    now also be issued via the new dnctl command.
    
    Reviewed by:    donner
    MFC after:      2 weeks
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D30465
    
    (cherry picked from commit 0b95680e077b7ef5bc6930c7c0f1a41106251d5d)
---
 sbin/ipfw/Makefile |   4 +
 sbin/ipfw/ipfw.8   |  68 ++++++++---------
 sbin/ipfw/ipfw2.c  |   6 ++
 sbin/ipfw/ipfw2.h  |   8 ++
 sbin/ipfw/main.c   | 219 +++++++++++++++++++++++++++++++++--------------------
 5 files changed, 189 insertions(+), 116 deletions(-)

diff --git a/sbin/ipfw/Makefile b/sbin/ipfw/Makefile
index 552755a16961..c0b7e56226c4 100644
--- a/sbin/ipfw/Makefile
+++ b/sbin/ipfw/Makefile
@@ -4,6 +4,10 @@
 
 PACKAGE=ipfw
 PROG=	ipfw
+
+LINKS=	${BINDIR}/ipfw ${BINDIR}/dnctl
+MLINKS=	ipfw.8 dnctl.8
+
 SRCS=	ipfw2.c dummynet.c ipv6.c main.c nat.c tables.c
 SRCS+=	nat64clat.c nat64lsn.c nat64stl.c nptv6.c
 
diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8
index be3f92f3bd6b..dc895310b638 100644
--- a/sbin/ipfw/ipfw.8
+++ b/sbin/ipfw/ipfw.8
@@ -1,11 +1,11 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd June 4, 2021
+.Dd June 14, 2021
 .Dt IPFW 8
 .Os
 .Sh NAME
-.Nm ipfw
+.Nm ipfw , dnctl
 .Nd User interface for firewall, traffic shaper, packet scheduler,
 in-kernel NAT.
 .Sh SYNOPSIS
@@ -88,12 +88,12 @@ in-kernel NAT.
 .Brq Ar name | all
 .Cm flush
 .Ss DUMMYNET CONFIGURATION (TRAFFIC SHAPER AND PACKET SCHEDULER)
-.Nm
+.Nm dnctl
 .Brq Cm pipe | queue | sched
 .Ar number
 .Cm config
 .Ar config-options
-.Nm
+.Nm dnctl
 .Op Fl s Op Ar field
 .Brq Cm pipe | queue | sched
 .Brq Cm delete | list | show
@@ -440,7 +440,7 @@ them on the local hostname) and the use of macros to centralize
 frequently required arguments like IP addresses.
 .Ss TRAFFIC SHAPER CONFIGURATION
 The
-.Nm
+.Nm dnctl
 .Cm pipe , queue
 and
 .Cm sched
@@ -2650,11 +2650,11 @@ Bandwidth, measured in
 A value of 0 (default) means unlimited bandwidth.
 The unit must immediately follow the number, as in
 .Pp
-.Dl "ipfw pipe 1 config bw 300Kbit/s"
+.Dl "dnctl pipe 1 config bw 300Kbit/s"
 .Pp
 If a device name is specified instead of a numeric value, as in
 .Pp
-.Dl "ipfw pipe 1 config bw tun0"
+.Dl "dnctl pipe 1 config bw tun0"
 .Pp
 then the transmit clock is supplied by the specified device.
 At the moment only the
@@ -2731,7 +2731,7 @@ The file format is the following, with whitespace acting as
 a separator and '#' indicating the beginning a comment:
 .Bl -tag -width indent
 .It Cm name Ar identifier
-optional name (listed by "ipfw pipe show")
+optional name (listed by "dnctl pipe show")
 to identify the delay distribution;
 .It Cm bw Ar value
 the bandwidth used for the pipe.
@@ -4356,15 +4356,15 @@ A similar effect can be achieved making use of
 .Nm dummynet
 pipes:
 .Pp
-.Dl "ipfw add pipe 10 ip from any to any"
-.Dl "ipfw pipe 10 config plr 0.05"
+.Dl "dnctl add pipe 10 ip from any to any"
+.Dl "dnctl pipe 10 config plr 0.05"
 .Pp
 We can use pipes to artificially limit bandwidth, e.g.\& on a
 machine acting as a router, if we want to limit traffic from
 local clients on 192.168.2.0/24 we do:
 .Pp
 .Dl "ipfw add pipe 1 ip from 192.168.2.0/24 to any out"
-.Dl "ipfw pipe 1 config bw 300Kbit/s queue 50KBytes"
+.Dl "dnctl pipe 1 config bw 300Kbit/s queue 50KBytes"
 .Pp
 note that we use the
 .Cm out
@@ -4378,8 +4378,8 @@ limitations, the correct way is the following:
 .Pp
 .Dl "ipfw add pipe 1 ip from any to any out"
 .Dl "ipfw add pipe 2 ip from any to any in"
-.Dl "ipfw pipe 1 config bw 64Kbit/s queue 10Kbytes"
-.Dl "ipfw pipe 2 config bw 64Kbit/s queue 10Kbytes"
+.Dl "dnctl pipe 1 config bw 64Kbit/s queue 10Kbytes"
+.Dl "dnctl pipe 2 config bw 64Kbit/s queue 10Kbytes"
 .Pp
 The above can be very useful, e.g.\& if you want to see how
 your fancy Web page will look for a residential user who
@@ -4394,7 +4394,7 @@ Should we want to verify network performance with the RED queue
 management algorithm:
 .Pp
 .Dl "ipfw add pipe 1 ip from any to any"
-.Dl "ipfw pipe 1 config bw 500Kbit/s queue 100 red 0.002/30/80/0.1"
+.Dl "dnctl pipe 1 config bw 500Kbit/s queue 100 red 0.002/30/80/0.1"
 .Pp
 Another typical application of the traffic shaper is to
 introduce some delay in the communication.
@@ -4405,8 +4405,8 @@ bandwidth:
 .Pp
 .Dl "ipfw add pipe 1 ip from any to any out"
 .Dl "ipfw add pipe 2 ip from any to any in"
-.Dl "ipfw pipe 1 config delay 250ms bw 1Mbit/s"
-.Dl "ipfw pipe 2 config delay 250ms bw 1Mbit/s"
+.Dl "dnctl pipe 1 config delay 250ms bw 1Mbit/s"
+.Dl "dnctl pipe 2 config delay 250ms bw 1Mbit/s"
 .Pp
 Per-flow queueing can be useful for a variety of purposes.
 A very simple one is counting traffic:
@@ -4414,7 +4414,7 @@ A very simple one is counting traffic:
 .Dl "ipfw add pipe 1 tcp from any to any"
 .Dl "ipfw add pipe 1 udp from any to any"
 .Dl "ipfw add pipe 1 ip from any to any"
-.Dl "ipfw pipe 1 config mask all"
+.Dl "dnctl pipe 1 config mask all"
 .Pp
 The above set of rules will create queues (and collect
 statistics) for all traffic.
@@ -4432,8 +4432,8 @@ on a net with per-host limits, rather than per-network limits:
 .Pp
 .Dl "ipfw add pipe 1 ip from 192.168.2.0/24 to any out"
 .Dl "ipfw add pipe 2 ip from any to 192.168.2.0/24 in"
-.Dl "ipfw pipe 1 config mask src-ip 0x000000ff bw 200Kbit/s queue 20Kbytes"
-.Dl "ipfw pipe 2 config mask dst-ip 0x000000ff bw 200Kbit/s queue 20Kbytes"
+.Dl "dnctl pipe 1 config mask src-ip 0x000000ff bw 200Kbit/s queue 20Kbytes"
+.Dl "dnctl pipe 2 config mask dst-ip 0x000000ff bw 200Kbit/s queue 20Kbytes"
 .Ss LOOKUP TABLES
 In the following example, we need to create several traffic bandwidth
 classes and we need different hosts/networks to fall into different classes.
@@ -4443,8 +4443,8 @@ For each subnet/host we set the argument equal to the number of the pipe
 that it should use.
 Then we classify traffic using a single rule:
 .Pp
-.Dl "ipfw pipe 1 config bw 1000Kbyte/s"
-.Dl "ipfw pipe 4 config bw 4000Kbyte/s"
+.Dl "dnctl pipe 1 config bw 1000Kbyte/s"
+.Dl "dnctl pipe 4 config bw 4000Kbyte/s"
 .Dl "..."
 .Dl "ipfw table T1 create type addr"
 .Dl "ipfw table T1 add 192.168.2.0/24 1"
@@ -4626,7 +4626,7 @@ with
 AQM using default configuration for traffic from 192.168.0.0/24 and 1Mbits/s
 rate limit, we do:
 .Pp
-.Dl "ipfw pipe 1 config bw 1mbits/s codel"
+.Dl "dnctl pipe 1 config bw 1mbits/s codel"
 .Dl "ipfw add 100 pipe 1 ip from 192.168.0.0/24 to any"
 .Pp
 To configure a
@@ -4636,8 +4636,8 @@ with
 AQM using different configurations parameters for traffic from
 192.168.0.0/24 and 1Mbits/s rate limit, we do:
 .Pp
-.Dl "ipfw pipe 1 config bw 1mbits/s"
-.Dl "ipfw queue 1 config pipe 1 codel target 8ms interval 160ms ecn"
+.Dl "dnctl pipe 1 config bw 1mbits/s"
+.Dl "dnctl queue 1 config pipe 1 codel target 8ms interval 160ms ecn"
 .Dl "ipfw add 100 queue 1 ip from 192.168.0.0/24 to any"
 .Pp
 To configure a
@@ -4647,7 +4647,7 @@ with
 AQM using default configuration for traffic from 192.168.0.0/24 and 1Mbits/s
 rate limit, we do:
 .Pp
-.Dl "ipfw pipe 1 config bw 1mbits/s pie"
+.Dl "dnctl pipe 1 config bw 1mbits/s pie"
 .Dl "ipfw add 100 pipe 1 ip from 192.168.0.0/24 to any"
 .Pp
 To configure a
@@ -4657,8 +4657,8 @@ with
 AQM using different configuration parameters for traffic from
 192.168.0.0/24 and 1Mbits/s rate limit, we do:
 .Pp
-.Dl "ipfw pipe 1 config bw 1mbits/s"
-.Dl "ipfw queue 1 config pipe 1 pie target 20ms tupdate 30ms ecn"
+.Dl "dnctl pipe 1 config bw 1mbits/s"
+.Dl "dnctl queue 1 config pipe 1 pie target 20ms tupdate 30ms ecn"
 .Dl "ipfw add 100 queue 1 ip from 192.168.0.0/24 to any"
 .Pp
 .Cm fq_codel
@@ -4673,9 +4673,9 @@ To configure
 scheduler using different configurations parameters for traffic from
 192.168.0.0/24 and 1Mbits/s rate limit, we do:
 .Pp
-.Dl "ipfw pipe 1 config bw 1mbits/s"
-.Dl "ipfw sched 1 config pipe 1 type fq_codel"
-.Dl "ipfw queue 1 config sched 1"
+.Dl "dnctl pipe 1 config bw 1mbits/s"
+.Dl "dnctl sched 1 config pipe 1 type fq_codel"
+.Dl "dnctl queue 1 config sched 1"
 .Dl "ipfw add 100 queue 1 ip from 192.168.0.0/24 to any"
 .Pp
 To change
@@ -4686,7 +4686,7 @@ such as disable ECN and change the
 .Ar target
 to 10ms, we do:
 .Pp
-.Dl "ipfw sched 1 config pipe 1 type fq_codel target 10ms noecn"
+.Dl "dnctl sched 1 config pipe 1 type fq_codel target 10ms noecn"
 .Pp
 Similar to
 .Cm fq_codel ,
@@ -4695,9 +4695,9 @@ to configure
 scheduler using different configurations parameters for traffic from
 192.168.0.0/24 and 1Mbits/s rate limit, we do:
 .Pp
-.Dl "ipfw pipe 1 config bw 1mbits/s"
-.Dl "ipfw sched 1 config pipe 1 type fq_pie"
-.Dl "ipfw queue 1 config sched 1"
+.Dl "dnctl pipe 1 config bw 1mbits/s"
+.Dl "dnctl sched 1 config pipe 1 type fq_pie"
+.Dl "dnctl queue 1 config sched 1"
 .Dl "ipfw add 100 queue 1 ip from 192.168.0.0/24 to any"
 .Pp
 The configurations of
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
index feb55b403f0a..6239674f108b 100644
--- a/sbin/ipfw/ipfw2.c
+++ b/sbin/ipfw/ipfw2.c
@@ -411,6 +411,12 @@ static void object_sort_ctlv(ipfw_obj_ctlv *ctlv);
 static char *object_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx,
     uint16_t type);
 
+int
+is_ipfw(void)
+{
+	return (g_co.prog == cmdline_prog_ipfw);
+}
+
 /*
  * Simple string buffer API.
  * Used to simplify buffer passing between function and for
diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h
index 42e4f4777792..9a39c215692d 100644
--- a/sbin/ipfw/ipfw2.h
+++ b/sbin/ipfw/ipfw2.h
@@ -20,6 +20,11 @@
  * $FreeBSD$
  */
 
+enum cmdline_prog {
+	cmdline_prog_ipfw,
+	cmdline_prog_dnctl
+};
+
 /*
  * Options that can be set on the command line.
  * When reading commands from a file, a subset of the options can also
@@ -54,8 +59,11 @@ struct cmdline_opts {
 	uint32_t use_set;	/* work with specified set number */
 		/* 0 means all sets, otherwise apply to set use_set - 1 */
 
+	enum cmdline_prog	prog;	/* Are we ipfw or dnctl? */
 };
 
+int is_ipfw(void);
+
 enum {
 	TIMESTAMP_NONE = 0,
 	TIMESTAMP_STRING,
diff --git a/sbin/ipfw/main.c b/sbin/ipfw/main.c
index 89f21062811c..f7aa6af5369c 100644
--- a/sbin/ipfw/main.c
+++ b/sbin/ipfw/main.c
@@ -36,7 +36,8 @@
 static void
 help(void)
 {
-	fprintf(stderr,
+	if (is_ipfw()) {
+		fprintf(stderr,
 "ipfw syntax summary (but please do read the ipfw(8) manpage):\n\n"
 "\tipfw [-abcdefhnNqStTv] <command>\n\n"
 "where <command> is one of the following:\n\n"
@@ -76,6 +77,16 @@ help(void)
 "	setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n"
 "	tcpdatalen LIST | verrevpath | versrcreach | antispoof\n"
 );
+	} else {
+		fprintf(stderr,
+"dnctl syntax summary (but please do read the dnctl(8) manpage):\n\n"
+"\tdnctl [-hnsv] <command>\n\n"
+"where <command> is one of the following:\n\n"
+"[pipe|queue|sched] N config PIPE-BODY\n"
+"[pipe|queue|sched] {delete|list|show} [N{,N}]\n"
+"\n"
+);
+	}
 
 	exit(0);
 }
@@ -231,7 +242,8 @@ ipfw_main(int oldac, char **oldav)
 		g_co.do_force = !isatty(STDIN_FILENO);
 
 #ifdef EMULATE_SYSCTL /* sysctl emulation */
-	if ( ac >= 2 && !strcmp(av[1], "sysctl")) {
+	if (is_ipfw() && ac >= 2 &&
+	    !strcmp(av[1], "sysctl")) {
 		char *s;
 		int i;
 
@@ -263,87 +275,115 @@ ipfw_main(int oldac, char **oldav)
 	save_av = av;
 
 	optind = optreset = 1;	/* restart getopt() */
-	while ((ch = getopt(ac, av, "abcdDefhinNp:qs:STtv")) != -1)
-		switch (ch) {
-		case 'a':
-			do_acct = 1;
-			break;
+	if (is_ipfw()) {
+		while ((ch = getopt(ac, av, "abcdDefhinNp:qs:STtv")) != -1)
+			switch (ch) {
+			case 'a':
+				do_acct = 1;
+				break;
 
-		case 'b':
-			g_co.comment_only = 1;
-			g_co.do_compact = 1;
-			break;
+			case 'b':
+				g_co.comment_only = 1;
+				g_co.do_compact = 1;
+				break;
 
-		case 'c':
-			g_co.do_compact = 1;
-			break;
+			case 'c':
+				g_co.do_compact = 1;
+				break;
 
-		case 'd':
-			g_co.do_dynamic = 1;
-			break;
+			case 'd':
+				g_co.do_dynamic = 1;
+				break;
 
-		case 'D':
-			g_co.do_dynamic = 2;
-			break;
+			case 'D':
+				g_co.do_dynamic = 2;
+				break;
 
-		case 'e':
-			/* nop for compatibility */
-			break;
+			case 'e':
+				/* nop for compatibility */
+				break;
 
-		case 'f':
-			g_co.do_force = 1;
-			break;
+			case 'f':
+				g_co.do_force = 1;
+				break;
 
-		case 'h': /* help */
-			free(save_av);
-			help();
-			break;	/* NOTREACHED */
+			case 'h': /* help */
+				free(save_av);
+				help();
+				break;	/* NOTREACHED */
 
-		case 'i':
-			g_co.do_value_as_ip = 1;
-			break;
+			case 'i':
+				g_co.do_value_as_ip = 1;
+				break;
 
-		case 'n':
-			g_co.test_only = 1;
-			break;
+			case 'n':
+				g_co.test_only = 1;
+				break;
 
-		case 'N':
-			g_co.do_resolv = 1;
-			break;
+			case 'N':
+				g_co.do_resolv = 1;
+				break;
 
-		case 'p':
-			errx(EX_USAGE, "An absolute pathname must be used "
-			    "with -p option.");
-			/* NOTREACHED */
+			case 'p':
+				errx(EX_USAGE, "An absolute pathname must be used "
+				    "with -p option.");
+				/* NOTREACHED */
 
-		case 'q':
-			g_co.do_quiet = 1;
-			break;
+			case 'q':
+				g_co.do_quiet = 1;
+				break;
 
-		case 's': /* sort */
-			g_co.do_sort = atoi(optarg);
-			break;
+			case 's': /* sort */
+				g_co.do_sort = atoi(optarg);
+				break;
 
-		case 'S':
-			g_co.show_sets = 1;
-			break;
+			case 'S':
+				g_co.show_sets = 1;
+				break;
 
-		case 't':
-			g_co.do_time = TIMESTAMP_STRING;
-			break;
+			case 't':
+				g_co.do_time = TIMESTAMP_STRING;
+				break;
 
-		case 'T':
-			g_co.do_time = TIMESTAMP_NUMERIC;
-			break;
+			case 'T':
+				g_co.do_time = TIMESTAMP_NUMERIC;
+				break;
 
-		case 'v': /* verbose */
-			g_co.verbose = 1;
-			break;
+			case 'v': /* verbose */
+				g_co.verbose = 1;
+				break;
 
-		default:
-			free(save_av);
-			return 1;
-		}
+			default:
+				free(save_av);
+				return 1;
+			}
+	} else {
+		while ((ch = getopt(ac, av, "hns:v")) != -1)
+			switch (ch) {
+
+			case 'h': /* help */
+				free(save_av);
+				help();
+				break;	/* NOTREACHED */
+
+			case 'n':
+				g_co.test_only = 1;
+				break;
+
+			case 's': /* sort */
+				g_co.do_sort = atoi(optarg);
+				break;
+
+			case 'v': /* verbose */
+				g_co.verbose = 1;
+				break;
+
+			default:
+				free(save_av);
+				return 1;
+			}
+
+	}
 
 	ac -= optind;
 	av += optind;
@@ -367,7 +407,7 @@ ipfw_main(int oldac, char **oldav)
 	g_co.do_nat = 0;
 	g_co.do_pipe = 0;
 	g_co.use_set = 0;
-	if (!strncmp(*av, "nat", strlen(*av)))
+	if (is_ipfw() && !strncmp(*av, "nat", strlen(*av)))
 		g_co.do_nat = 1;
 	else if (!strncmp(*av, "pipe", strlen(*av)))
 		g_co.do_pipe = 1;
@@ -377,7 +417,7 @@ ipfw_main(int oldac, char **oldav)
 		g_co.do_pipe = 2;
 	else if (_substrcmp(*av, "sched") == 0)
 		g_co.do_pipe = 3;
-	else if (!strncmp(*av, "set", strlen(*av))) {
+	else if (is_ipfw() && !strncmp(*av, "set", strlen(*av))) {
 		if (ac > 1 && isdigit(av[1][0])) {
 			g_co.use_set = strtonum(av[1], 0, resvd_set_number,
 					&errstr);
@@ -406,8 +446,12 @@ ipfw_main(int oldac, char **oldav)
 		av[1] = p;
 	}
 
+	if (! is_ipfw() && g_co.do_pipe == 0) {
+		help();
+	}
+
 	if (g_co.use_set == 0) {
-		if (_substrcmp(*av, "add") == 0)
+		if (is_ipfw() && _substrcmp(*av, "add") == 0)
 			ipfw_add(av);
 		else if (g_co.do_nat && _substrcmp(*av, "show") == 0)
  			ipfw_show_nat(ac, av);
@@ -415,13 +459,13 @@ ipfw_main(int oldac, char **oldav)
 			ipfw_config_pipe(ac, av);
 		else if (g_co.do_nat && _substrcmp(*av, "config") == 0)
  			ipfw_config_nat(ac, av);
-		else if (_substrcmp(*av, "set") == 0)
+		else if (is_ipfw() && _substrcmp(*av, "set") == 0)
 			ipfw_sets_handler(av);
-		else if (_substrcmp(*av, "table") == 0)
+		else if (is_ipfw() && _substrcmp(*av, "table") == 0)
 			ipfw_table_handler(ac, av);
-		else if (_substrcmp(*av, "enable") == 0)
+		else if (is_ipfw() && _substrcmp(*av, "enable") == 0)
 			ipfw_sysctl_handler(av, 1);
-		else if (_substrcmp(*av, "disable") == 0)
+		else if (is_ipfw() && _substrcmp(*av, "disable") == 0)
 			ipfw_sysctl_handler(av, 0);
 		else
 			try_next = 1;
@@ -430,28 +474,28 @@ ipfw_main(int oldac, char **oldav)
 	if (g_co.use_set || try_next) {
 		if (_substrcmp(*av, "delete") == 0)
 			ipfw_delete(av);
-		else if (!strncmp(*av, "nat64clat", strlen(*av)))
+		else if (is_ipfw() && !strncmp(*av, "nat64clat", strlen(*av)))
 			ipfw_nat64clat_handler(ac, av);
-		else if (!strncmp(*av, "nat64stl", strlen(*av)))
+		else if (is_ipfw() && !strncmp(*av, "nat64stl", strlen(*av)))
 			ipfw_nat64stl_handler(ac, av);
-		else if (!strncmp(*av, "nat64lsn", strlen(*av)))
+		else if (is_ipfw() && !strncmp(*av, "nat64lsn", strlen(*av)))
 			ipfw_nat64lsn_handler(ac, av);
-		else if (!strncmp(*av, "nptv6", strlen(*av)))
+		else if (is_ipfw() && !strncmp(*av, "nptv6", strlen(*av)))
 			ipfw_nptv6_handler(ac, av);
 		else if (_substrcmp(*av, "flush") == 0)
 			ipfw_flush(g_co.do_force);
-		else if (_substrcmp(*av, "zero") == 0)
+		else if (is_ipfw() && _substrcmp(*av, "zero") == 0)
 			ipfw_zero(ac, av, 0 /* IP_FW_ZERO */);
-		else if (_substrcmp(*av, "resetlog") == 0)
+		else if (is_ipfw() && _substrcmp(*av, "resetlog") == 0)
 			ipfw_zero(ac, av, 1 /* IP_FW_RESETLOG */);
 		else if (_substrcmp(*av, "print") == 0 ||
 			 _substrcmp(*av, "list") == 0)
 			ipfw_list(ac, av, do_acct);
 		else if (_substrcmp(*av, "show") == 0)
 			ipfw_list(ac, av, 1 /* show counters */);
-		else if (_substrcmp(*av, "table") == 0)
+		else if (is_ipfw() && _substrcmp(*av, "table") == 0)
 			ipfw_table_handler(ac, av);
-		else if (_substrcmp(*av, "internal") == 0)
+		else if (is_ipfw() && _substrcmp(*av, "internal") == 0)
 			ipfw_internal_handler(ac, av);
 		else
 			errx(EX_USAGE, "bad command `%s'", *av);
@@ -620,12 +664,22 @@ main(int ac, char *av[])
 		}
 	}
 #endif
+
+	if (strcmp(av[0], "dnctl") == 0)
+		g_co.prog = cmdline_prog_dnctl;
+	else
+		g_co.prog = cmdline_prog_ipfw;
+
 	/*
 	 * If the last argument is an absolute pathname, interpret it
 	 * as a file to be preprocessed.
 	 */
 
 	if (ac > 1 && av[ac - 1][0] == '/') {
+		if (! is_ipfw())
+			errx(EX_USAGE, "usage: dnctl [options]\n"
+			    "do \"dnctl -h\" for details");
+
 		if (access(av[ac - 1], R_OK) == 0)
 			ipfw_readfile(ac, av);
 		else
@@ -633,8 +687,9 @@ main(int ac, char *av[])
 	} else {
 		if (ipfw_main(ac, av)) {
 			errx(EX_USAGE,
-			    "usage: ipfw [options]\n"
-			    "do \"ipfw -h\" or \"man ipfw\" for details");
+			    "usage: %s [options]\n"
+			    "do \"%s -h\" or \"man %s\" for details", av[0],
+			    av[0], av[0]);
 		}
 	}
 	return EX_OK;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202109142001.18EK1Wki089562>