summaryrefslogtreecommitdiffstats
path: root/sbin/ipfw
diff options
context:
space:
mode:
authorluigi <luigi@FreeBSD.org>2002-08-10 04:37:32 +0000
committerluigi <luigi@FreeBSD.org>2002-08-10 04:37:32 +0000
commite3c4c6c9daa5f8657f056c8088ad060282c15bbe (patch)
treef7920d98ba96bcec6ea0554ffeab5871047ce1d5 /sbin/ipfw
parent1627a3b4bec29eb5ba77515bce9ea0fcde4b5c43 (diff)
downloadFreeBSD-src-e3c4c6c9daa5f8657f056c8088ad060282c15bbe.zip
FreeBSD-src-e3c4c6c9daa5f8657f056c8088ad060282c15bbe.tar.gz
One bugfix and one new feature.
The bugfix (ipfw2.c) makes the handling of port numbers with a dash in the name, e.g. ftp-data, consistent with old ipfw: use \\ before the - to consider it as part of the name and not a range separator. The new feature (all this description will go in the manpage): each rule now belongs to one of 32 different sets, which can be optionally specified in the following form: ipfw add 100 set 23 allow ip from any to any If "set N" is not specified, the rule belongs to set 0. Individual sets can be disabled, enabled, and deleted with the commands: ipfw disable set N ipfw enable set N ipfw delete set N Enabling/disabling of a set is atomic. Rules belonging to a disabled set are skipped during packet matching, and they are not listed unless you use the '-S' flag in the show/list commands. Note that dynamic rules, once created, are always active until they expire or their parent rule is deleted. Set 31 is reserved for the default rule and cannot be disabled. All sets are enabled by default. The enable/disable status of the sets can be shown with the command ipfw show sets Hopefully, this feature will make life easier to those who want to have atomic ruleset addition/deletion/tests. Examples: To add a set of rules atomically: ipfw disable set 18 ipfw add ... set 18 ... # repeat as needed ipfw enable set 18 To delete a set of rules atomically ipfw disable set 18 ipfw delete set 18 ipfw enable set 18 To test a ruleset and disable it and regain control if something goes wrong: ipfw disable set 18 ipfw add ... set 18 ... # repeat as needed ipfw enable set 18 ; echo "done "; sleep 30 && ipfw disable set 18 here if everything goes well, you press control-C before the "sleep" terminates, and your ruleset will be left active. Otherwise, e.g. if you cannot access your box, the ruleset will be disabled after the sleep terminates. I think there is only one more thing that one might want, namely a command to assign all rules in set X to set Y, so one can test a ruleset using the above mechanisms, and once it is considered acceptable, make it part of an existing ruleset.
Diffstat (limited to 'sbin/ipfw')
-rw-r--r--sbin/ipfw/ipfw2.c107
1 files changed, 85 insertions, 22 deletions
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
index 31458e6..78b32a1 100644
--- a/sbin/ipfw/ipfw2.c
+++ b/sbin/ipfw/ipfw2.c
@@ -65,6 +65,7 @@ int s, /* main RAW socket */
do_sort, /* field to sort results (0 = no) */
do_dynamic, /* display dynamic rules */
do_expired, /* display expired dynamic rules */
+ show_sets, /* display rule sets */
verbose;
#define IP_MASK_ALL 0xffffffff
@@ -410,34 +411,45 @@ print_newports(ipfw_insn_u16 *cmd, int proto)
* proto == -1 disables the protocol check;
* proto == IPPROTO_ETHERTYPE looks up an internal table
* proto == <some value in /etc/protocols> matches the values there.
+ * Returns *end == s in case the parameter is not found.
*/
static int
strtoport(char *s, char **end, int base, int proto)
{
- char *s1, sep;
+ char *p, *buf;
+ char *s1;
int i;
+ *end = s; /* default - not found */
if ( *s == '\0')
- goto none;
-
+ return 0; /* not found */
+
if (isdigit(*s))
return strtol(s, end, base);
/*
- * find separator and replace with a '\0'
+ * find separator. '\\' escapes the next char.
*/
- for (s1 = s; *s1 && isalnum(*s1) ; s1++)
- ;
- sep = *s1;
- *s1 = '\0';
+ for (s1 = s; *s1 && (isalnum(*s1) || *s1 == '\\') ; s1++)
+ if (*s1 == '\\' && s1[1] != '\0')
+ s1++;
+
+ buf = malloc(s1 - s + 1);
+ if (buf == NULL)
+ return 0;
+
+ /*
+ * copy into a buffer skipping backslashes
+ */
+ for (p = s, i = 0; p != s1 ; p++)
+ if ( *p != '\\')
+ buf[i++] = *p;
+ buf[i++] = '\0';
if (proto == IPPROTO_ETHERTYPE) {
- i = match_token(ether_types, s);
- *s1 = sep;
- if (i == -1) { /* not found */
- *end = s;
- return 0;
- } else {
+ i = match_token(ether_types, buf);
+ free(buf);
+ if (i != -1) { /* found */
*end = s1;
return i;
}
@@ -448,16 +460,14 @@ strtoport(char *s, char **end, int base, int proto)
if (proto != 0)
pe = getprotobynumber(proto);
setservent(1);
- se = getservbyname(s, pe ? pe->p_name : NULL);
- *s1 = sep;
+ se = getservbyname(buf, pe ? pe->p_name : NULL);
+ free(buf);
if (se != NULL) {
*end = s1;
return ntohs(se->s_port);
}
}
-none:
- *end = s;
- return 0;
+ return 0; /* not found */
}
/*
@@ -749,6 +759,14 @@ show_ipfw(struct ip_fw *rule)
ipfw_insn_log *logptr = NULL; /* set if we find an O_LOG */
int or_block = 0; /* we are in an or block */
+ u_int32_t set_disable = (u_int32_t)(rule->next_rule);
+
+ if (set_disable & (1 << rule->set)) { /* disabled */
+ if (!show_sets)
+ return;
+ else
+ printf("# DISABLED ");
+ }
printf("%05u ", rule->rulenum);
if (do_acct)
@@ -767,6 +785,9 @@ show_ipfw(struct ip_fw *rule)
}
}
+ if (show_sets)
+ printf("set %d ", rule->set);
+
/*
* first print actions
*/
@@ -1332,6 +1353,23 @@ list(int ac, char *av[])
ac--;
av++;
+ if (ac && !strncmp(*av, "sets", strlen(*av)) ) {
+ int i;
+ u_int32_t set_disable;
+
+ nbytes = sizeof(struct ip_fw);
+ if ((data = malloc(nbytes)) == NULL)
+ err(EX_OSERR, "malloc");
+ if (getsockopt(s, IPPROTO_IP, IP_FW_GET, data, &nbytes) < 0)
+ err(EX_OSERR, "getsockopt(IP_FW_GET)");
+ set_disable = (u_int32_t)(((struct ip_fw *)data)->next_rule);
+
+ for (i = 0; i < 31; i++)
+ printf("%s set %d\n",
+ set_disable & (1<<i) ? "disable" : "enable", i);
+ return;
+ }
+
/* get rules or pipes from kernel, resizing array as necessary */
nbytes = nalloc;
@@ -1649,10 +1687,21 @@ delete(int ac, char *av[])
struct dn_pipe pipe;
int i;
int exitval = EX_OK;
+ int do_set = 0;
memset(&pipe, 0, sizeof pipe);
+ if (!strncmp(*av, "disable", strlen(*av)))
+ do_set = 2; /* disable set */
+ else if (!strncmp(*av, "enable", strlen(*av)))
+ do_set = 3; /* enable set */
av++; ac--;
+ if (!strncmp(*av, "set", strlen(*av))) {
+ if (do_set == 0)
+ do_set = 1; /* delete set */
+ ac--; av++;
+ } else if (do_set != 0)
+ errx(EX_DATAERR, "missing 'set' keyword");
/* Rule number */
while (ac && isdigit(**av)) {
@@ -1671,7 +1720,7 @@ delete(int ac, char *av[])
pipe.fs.fs_nr);
}
} else {
- rulenum = i;
+ rulenum = (i & 0xffff) | (do_set << 16);
i = setsockopt(s, IPPROTO_IP, IP_FW_DEL, &rulenum,
sizeof rulenum);
if (i) {
@@ -2194,6 +2243,15 @@ add(int ac, char *av[])
ac--;
}
+ /* [set N] -- set number (0..30), optional */
+ if (ac > 1 && !strncmp(*av, "set", strlen(*av))) {
+ int set = strtoul(av[1], NULL, 10);
+ if (set < 0 || set > 30)
+ errx(EX_DATAERR, "illegal set %s", av[1]);
+ rule->set = set;
+ av += 2; ac -= 2;
+ }
+
/* [prob D] -- match probability, optional */
if (ac > 1 && !strncmp(*av, "prob", strlen(*av))) {
double d = strtod(av[1], NULL);
@@ -2930,7 +2988,7 @@ ipfw_main(int ac, char **av)
do_force = !isatty(STDIN_FILENO);
optind = optreset = 1;
- while ((ch = getopt(ac, av, "hs:adefNqtv")) != -1)
+ while ((ch = getopt(ac, av, "hs:adefNqStv")) != -1)
switch (ch) {
case 'h': /* help */
help();
@@ -2957,6 +3015,9 @@ ipfw_main(int ac, char **av)
case 'q':
do_quiet = 1;
break;
+ case 'S':
+ show_sets = 1;
+ break;
case 't':
do_time = 1;
break;
@@ -2999,7 +3060,9 @@ ipfw_main(int ac, char **av)
add(ac, av);
else if (do_pipe && !strncmp(*av, "config", strlen(*av)))
config_pipe(ac, av);
- else if (!strncmp(*av, "delete", strlen(*av)))
+ else if (!strncmp(*av, "delete", strlen(*av)) ||
+ !strncmp(*av, "disable", strlen(*av)) ||
+ !strncmp(*av, "enable", strlen(*av)))
delete(ac, av);
else if (!strncmp(*av, "flush", strlen(*av)))
flush();
OpenPOWER on IntegriCloud