From ae659ef435156d011821295969f63c5f4dcfb1d2 Mon Sep 17 00:00:00 2001 From: ae Date: Mon, 3 Apr 2017 07:40:38 +0000 Subject: [PATCH] MFC r307570: 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 Obtained from: Yandex LLC Sponsored by: Yandex LLC --- sbin/ipfw/ipfw.8 | 18 ++++++++++++++++++ sbin/ipfw/ipv6.c | 46 ++++++++++++++++++++++++++-------------------- 2 files changed, 44 insertions(+), 20 deletions(-) diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8 index 0ea43a6adf4..0317026753d 100644 --- a/sbin/ipfw/ipfw.8 +++ b/sbin/ipfw/ipfw.8 @@ -1316,6 +1316,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 f6b858d59fd..fca666d394b 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. @@ -371,13 +372,18 @@ fill_ip6(ipfw_insn_ip6 *cmd, char *av, int cblen, struct tidx *tstate) * 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 */ @@ -390,22 +396,22 @@ fill_ip6(ipfw_insn_ip6 *cmd, char *av, int cblen, struct tidx *tstate) 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) { -- 2.45.0