From 7d1080fe33a6ce1eb16aa602b1d5bb9918f0c09f Mon Sep 17 00:00:00 2001 From: luigi Date: Mon, 23 Jun 2003 08:20:28 +0000 Subject: syntactic sugar: support range notation such as 1.2.3.4/24{5,6,7,10-20,60-90} for set of ip addresses. Previously you needed to specify every address in the range, which was unconvenient and lead to very long lines. Internally the set is still stored in the same way, just the input and output routines are modified. Manpage update still missing. Perhaps a similar preprocessing step would be useful for port ranges. MFC after: 3 days --- sbin/ipfw/ipfw2.c | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) (limited to 'sbin') diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c index 3a3ff3a..e02f48b 100644 --- a/sbin/ipfw/ipfw2.c +++ b/sbin/ipfw/ipfw2.c @@ -687,7 +687,7 @@ print_ip(ipfw_insn_ip *cmd, char *s) } if (cmd->o.opcode == O_IP_SRC_SET || cmd->o.opcode == O_IP_DST_SET) { u_int32_t x, *d; - int i; + int i, j; char comma = '{'; x = cmd->o.arg1 - 1; @@ -698,9 +698,22 @@ print_ip(ipfw_insn_ip *cmd, char *s) x = cmd->addr.s_addr = htonl(cmd->addr.s_addr); x &= 0xff; /* base */ d = (u_int32_t *)&(cmd->mask); + /* + * Print bits and ranges. + * Locate first bit set (i), then locate first bit unset (j). + * If we have 3+ consecutive bits set, then print them as a + * range, otherwise only print the initial bit and rescan. + */ for (i=0; i < cmd->o.arg1; i++) - if (d[ i/32] & (1<<(i & 31))) { + if (d[i/32] & (1<<(i & 31))) { + for (j=i+1; j < cmd->o.arg1; j++) + if (!(d[ j/32] & (1<<(j & 31)))) + break; printf("%c%d", comma, i+x); + if (j>i+2) { /* range has at least 3 elements */ + printf("-%d", j-1+x); + i = j-1; + } comma = ','; } printf("}"); @@ -1906,6 +1919,7 @@ fill_ip(ipfw_insn_ip *cmd, char *av) av = p+1; low = cmd->addr.s_addr & 0xff; high = low + cmd->o.arg1 - 1; + i = -1; /* previous value in a range */ while (isdigit(*av)) { char *s; u_int16_t a = strtol(av, &s, 0); @@ -1918,9 +1932,22 @@ fill_ip(ipfw_insn_ip *cmd, char *av) exit(0); } a -= low; - d[ a/32] |= 1<<(a & 31); - if (*s != ',') - break; + if (i == -1) /* no previous in range */ + i = a; + else { /* check that range is valid */ + if (i > a) + errx(EX_DATAERR, "invalid range %d-%d", + i+low, a+low); + if (*s == '-') + errx(EX_DATAERR, "double '-' in range"); + } + for (; i <= a; i++) + d[i/32] |= 1<<(i & 31); + i = -1; + if (*s == '-') + i = a; + else if (*s != ',') + break; av = s+1; } return; -- cgit v1.1