aboutsummaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
authorAndrey V. Elsukov <ae@FreeBSD.org>2016-10-18 15:14:46 +0000
committerAndrey V. Elsukov <ae@FreeBSD.org>2016-10-18 15:14:46 +0000
commit23b93085c2797a48ef90fe50281ea5535fce1602 (patch)
tree0c2e1c32a2194f00fbd14d819efe7048fabc402a /sbin
parent225d33ff5cbe004a82d564af350db745b33e0d7a (diff)
downloadsrc-23b93085c2797a48ef90fe50281ea5535fce1602.tar.gz
src-23b93085c2797a48ef90fe50281ea5535fce1602.zip
Add support for non-contiguous IPv6 masks in ipfw(8) rules.
For example fe::640:0:0/ffff::ffff:ffff:0:0 will match addresses fe:*:*:*:0:640:*:* Submitted by: Eugene Mamchits <mamchits at yandex-team dot ru> Obtained from: Yandex LLC MFC after: 2 weeks Sponsored by: Yandex LLC
Notes
Notes: svn path=/head/; revision=307570
Diffstat (limited to 'sbin')
-rw-r--r--sbin/ipfw/ipfw.820
-rw-r--r--sbin/ipfw/ipv6.c46
2 files changed, 45 insertions, 21 deletions
diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8
index 7577f9413d29..dd8f34b3b6a0 100644
--- a/sbin/ipfw/ipfw.8
+++ b/sbin/ipfw/ipfw.8
@@ -1,7 +1,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd August 21, 2016
+.Dd October 18, 2016
.Dt IPFW 8
.Os
.Sh NAME
@@ -1357,6 +1357,24 @@ or a hostname)
and mask width of
.Cm masklen
bits.
+.It Ar addr Ns / Ns Ar mask
+Matches all IPv6 addresses with base
+.Ar addr
+(specified as allowed by
+.Xr inet_pton
+or a hostname)
+and the mask of
+.Ar mask ,
+specified as allowed by
+.Xr inet_pton.
+As an example, fe::640:0:0/ffff::ffff:ffff:0:0 will match
+fe:*:*:*:0:640:*:*.
+This form is advised only for non-contiguous
+masks.
+It is better to resort to the
+.Ar addr Ns / Ns Ar masklen
+format for contiguous masks, which is more compact and less
+error-prone.
.El
.Pp
No support for sets of IPv6 addresses is provided because IPv6 addresses
diff --git a/sbin/ipfw/ipv6.c b/sbin/ipfw/ipv6.c
index 6d884ee9100c..e54ad512d943 100644
--- a/sbin/ipfw/ipv6.c
+++ b/sbin/ipfw/ipv6.c
@@ -124,8 +124,8 @@ print_ip6(struct buf_pr *bp, ipfw_insn_ip6 *cmd, char const *s)
if (inet_ntop(AF_INET6, a, trad, sizeof( trad ) ) == NULL)
bprintf(bp, "Error ntop in print_ip6\n");
bprintf(bp, "%s", trad );
- if (mb < 0) /* XXX not really legal... */
- bprintf(bp, ":%s",
+ if (mb < 0) /* mask not contiguous */
+ bprintf(bp, "/%s",
inet_ntop(AF_INET6, &a[1], trad, sizeof(trad)));
else if (mb < 128)
bprintf(bp, "/%d", mb);
@@ -325,9 +325,10 @@ lookup_host6 (char *host, struct in6_addr *ip6addr)
* any matches any IP6. Actually returns an empty instruction.
* me returns O_IP6_*_ME
*
- * 03f1::234:123:0342 single IP6 address
- * 03f1::234:123:0342/24 address/mask
- * 03f1::234:123:0342/24,03f1::234:123:0343/ List of address
+ * 03f1::234:123:0342 single IP6 address
+ * 03f1::234:123:0342/24 address/masklen
+ * 03f1::234:123:0342/ffff::ffff:ffff address/mask
+ * 03f1::234:123:0342/24,03f1::234:123:0343/ List of address
*
* Set of address (as in ipv6) not supported because ipv6 address
* are typically random past the initial prefix.
@@ -382,13 +383,18 @@ fill_ip6(ipfw_insn_ip6 *cmd, char *av, int cblen)
* or ',' indicating another address follows.
*/
- char *p;
+ char *p, *q;
int masklen;
char md = '\0';
CHECK_LENGTH(cblen, 1 + len + 2 * F_INSN_SIZE(struct in6_addr));
- if ((p = strpbrk(av, "/,")) ) {
+ if ((q = strchr(av, ',')) ) {
+ *q = '\0';
+ q++;
+ }
+
+ if ((p = strchr(av, '/')) ) {
md = *p; /* save the separator */
*p = '\0'; /* terminate address string */
p++; /* and skip past it */
@@ -401,22 +407,22 @@ fill_ip6(ipfw_insn_ip6 *cmd, char *av, int cblen)
errx(EX_DATAERR, "bad address \"%s\"", av);
}
/* next, look at the mask, if any */
- masklen = (md == '/') ? atoi(p) : 128;
- if (masklen > 128 || masklen < 0)
- errx(EX_DATAERR, "bad width \"%s\''", p);
- else
- n2mask(&d[1], masklen);
+ if (md == '/' && strchr(p, ':')) {
+ if (!inet_pton(AF_INET6, p, &d[1]))
+ errx(EX_DATAERR, "bad mask \"%s\"", p);
+
+ masklen = contigmask((uint8_t *)&(d[1]), 128);
+ } else {
+ masklen = (md == '/') ? atoi(p) : 128;
+ if (masklen > 128 || masklen < 0)
+ errx(EX_DATAERR, "bad width \"%s\''", p);
+ else
+ n2mask(&d[1], masklen);
+ }
APPLY_MASK(d, &d[1]) /* mask base address with mask */
- /* find next separator */
-
- if (md == '/') { /* find separator past the mask */
- p = strpbrk(p, ",");
- if (p != NULL)
- p++;
- }
- av = p;
+ av = q;
/* Check this entry */
if (masklen == 0) {