Author: ae
Date: Tue Oct 18 15:14:46 2016
New Revision: 307570
URL: https://svnweb.freebsd.org/changeset/base/307570

Log:
  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

Modified:
  head/sbin/ipfw/ipfw.8
  head/sbin/ipfw/ipv6.c

Modified: head/sbin/ipfw/ipfw.8
==============================================================================
--- head/sbin/ipfw/ipfw.8       Tue Oct 18 14:48:41 2016        (r307569)
+++ head/sbin/ipfw/ipfw.8       Tue Oct 18 15:14:46 2016        (r307570)
@@ -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

Modified: head/sbin/ipfw/ipv6.c
==============================================================================
--- head/sbin/ipfw/ipv6.c       Tue Oct 18 14:48:41 2016        (r307569)
+++ head/sbin/ipfw/ipv6.c       Tue Oct 18 15:14:46 2016        (r307570)
@@ -124,8 +124,8 @@ print_ip6(struct buf_pr *bp, ipfw_insn_i
               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_add
  *     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, i
                 * 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, i
                        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) {
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to