aboutsummaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
authorLuigi Rizzo <luigi@FreeBSD.org>2003-06-23 08:20:28 +0000
committerLuigi Rizzo <luigi@FreeBSD.org>2003-06-23 08:20:28 +0000
commit9ef3f16d0801f7fe19d2b64a0f1ca5b64e2858a8 (patch)
tree460a55242ad470dbd4dacf37e16a0bb45c00bb4f /sbin
parent064d54a2480a257586fcf0f9b5a00858ccc44a2b (diff)
downloadsrc-9ef3f16d0801f7fe19d2b64a0f1ca5b64e2858a8.tar.gz
src-9ef3f16d0801f7fe19d2b64a0f1ca5b64e2858a8.zip
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
Notes
Notes: svn path=/head/; revision=116716
Diffstat (limited to 'sbin')
-rw-r--r--sbin/ipfw/ipfw2.c37
1 files changed, 32 insertions, 5 deletions
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
index 3a3ff3aac3a0..e02f48b4fec5 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;