map: add support for lw4o6 address matching, minor optimizations
authorSteven Barth <cyrus@openwrt.org>
Tue, 26 May 2015 14:36:20 +0000 (14:36 +0000)
committerSteven Barth <cyrus@openwrt.org>
Tue, 26 May 2015 14:36:20 +0000 (14:36 +0000)
Signed-off-by: Steven Barth <steven@midlink.org>
SVN-Revision: 45770

package/network/ipv6/map/Makefile
package/network/ipv6/map/src/mapcalc.c

index 09ba523..89d34de 100644 (file)
@@ -8,8 +8,8 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=map
-PKG_VERSION:=3
-PKG_RELEASE:=4
+PKG_VERSION:=4
+PKG_RELEASE:=1
 PKG_LICENSE:=GPL-2.0
 
 include $(INCLUDE_DIR)/package.mk
index b61e157..cd72138 100644 (file)
@@ -37,12 +37,14 @@ static const struct blobmsg_policy dump_attrs[DUMP_ATTR_MAX] = {
 enum {
        IFACE_ATTR_INTERFACE,
        IFACE_ATTR_PREFIX,
+       IFACE_ATTR_ADDRESS,
        IFACE_ATTR_MAX,
 };
 
 static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = {
        [IFACE_ATTR_INTERFACE] = { .name = "interface", .type = BLOBMSG_TYPE_STRING },
        [IFACE_ATTR_PREFIX] = { .name = "ipv6-prefix", .type = BLOBMSG_TYPE_ARRAY },
+       [IFACE_ATTR_ADDRESS] = { .name = "ipv6-address", .type = BLOBMSG_TYPE_ARRAY },
 };
 
 
@@ -109,6 +111,39 @@ static void handle_dump(struct ubus_request *req __attribute__((unused)),
        dump = blob_memdup(tb[DUMP_ATTR_INTERFACE]);
 }
 
+static void match_prefix(int *pdlen, struct in6_addr *pd, struct blob_attr *cur,
+               const struct in6_addr *ipv6prefix, int prefix6len)
+{
+       struct blob_attr *d;
+       unsigned drem;
+
+       if (!cur || blobmsg_type(cur) != BLOBMSG_TYPE_ARRAY || !blobmsg_check_attr(cur, NULL))
+               return;
+
+       blobmsg_for_each_attr(d, cur, drem) {
+               struct blob_attr *ptb[PREFIX_ATTR_MAX];
+               blobmsg_parse(prefix_attrs, PREFIX_ATTR_MAX, ptb,
+                               blobmsg_data(d), blobmsg_data_len(d));
+
+               if (!ptb[PREFIX_ATTR_ADDRESS] || !ptb[PREFIX_ATTR_MASK])
+                       continue;
+
+               struct in6_addr prefix = IN6ADDR_ANY_INIT;
+               int mask = blobmsg_get_u32(ptb[PREFIX_ATTR_MASK]);
+               inet_pton(AF_INET6, blobmsg_get_string(ptb[PREFIX_ATTR_ADDRESS]), &prefix);
+
+               // lw4over6 /128-address-as-PD matching madness workaround
+               if (mask == 128)
+                       mask = 64;
+
+               if (*pdlen < mask && mask >= prefix6len &&
+                               !bmemcmp(&prefix, ipv6prefix, prefix6len)) {
+                       bmemcpy(pd, &prefix, mask);
+                       *pdlen = mask;
+               }
+       }
+}
+
 enum {
        OPT_TYPE,
        OPT_FMR,
@@ -226,11 +261,16 @@ int main(int argc, char *argv[])
                if (offset < 0)
                        offset = (lw4o6) ? 0 : (legacy) ? 4 : 6;
 
-               if (lw4o6 && ealen < 0 && psidlen >= 0)
+               // LW4over6 doesn't have an EALEN and has no psid-autodetect
+               if (lw4o6) {
+                       if (psidlen < 0)
+                               psidlen = 0;
+
                        ealen = psidlen;
+               }
 
                // Find PD
-               struct blob_attr *c, *cur;
+               struct blob_attr *c;
                unsigned rem;
                blobmsg_for_each_attr(c, dump, rem) {
                        struct blob_attr *tb[IFACE_ATTR_MAX];
@@ -240,34 +280,14 @@ int main(int argc, char *argv[])
                                        blobmsg_get_string(tb[IFACE_ATTR_INTERFACE]))))
                                continue;
 
-                       if ((cur = tb[IFACE_ATTR_PREFIX])) {
-                               if (blobmsg_type(cur) != BLOBMSG_TYPE_ARRAY || !blobmsg_check_attr(cur, NULL))
-                                       continue;
-
-                               struct blob_attr *d;
-                               unsigned drem;
-                               blobmsg_for_each_attr(d, cur, drem) {
-                                       struct blob_attr *ptb[PREFIX_ATTR_MAX];
-                                       blobmsg_parse(prefix_attrs, PREFIX_ATTR_MAX, ptb,
-                                                       blobmsg_data(d), blobmsg_data_len(d));
-
-                                       if (!ptb[PREFIX_ATTR_ADDRESS] || !ptb[PREFIX_ATTR_MASK])
-                                               continue;
-
-                                       struct in6_addr prefix = IN6ADDR_ANY_INIT;
-                                       int mask = blobmsg_get_u32(ptb[PREFIX_ATTR_MASK]);
-                                       inet_pton(AF_INET6, blobmsg_get_string(ptb[PREFIX_ATTR_ADDRESS]), &prefix);
-
-                                       if (mask >= prefix6len && !bmemcmp(&prefix, &ipv6prefix, prefix6len)) {
-                                               pd = prefix;
-                                               pdlen = mask;
-                                               iface = blobmsg_get_string(tb[IFACE_ATTR_INTERFACE]);
-                                               break;
-                                       }
-                               }
-
-                               if (pdlen >= 0)
-                                       break;
+                       match_prefix(&pdlen, &pd, tb[IFACE_ATTR_PREFIX], &ipv6prefix, prefix6len);
+
+                       if (lw4o6)
+                               match_prefix(&pdlen, &pd, tb[IFACE_ATTR_ADDRESS], &ipv6prefix, prefix6len);
+
+                       if (pdlen >= 0) {
+                               iface = blobmsg_get_string(tb[IFACE_ATTR_INTERFACE]);
+                               break;
                        }
                }
 
@@ -286,6 +306,12 @@ int main(int argc, char *argv[])
 
                psid16 = cpu_to_be16(psid >> (16 - psidlen));
 
+               if (prefix4len < 0 || prefix6len < 0 || ealen < 0 || ealen < psidlen) {
+                       fprintf(stderr, "Skipping invalid or incomplete rule: %s\n", argv[i]);
+                       status = 1;
+                       continue;
+               }
+
                if ((pdlen >= 0 || ealen == psidlen) && ealen >= psidlen) {
                        bmemcpys64(&ipv4addr, &pd, prefix6len, ealen - psidlen);
                        ipv4addr.s_addr = htonl(ntohl(ipv4addr.s_addr) >> prefix4len);
@@ -295,12 +321,6 @@ int main(int argc, char *argv[])
                                addr4len = prefix4len + ealen;
                }
 
-               if (prefix4len < 0 || prefix6len < 0 || ealen < 0 || ealen < psidlen) {
-                       fprintf(stderr, "Skipping invalid or incomplete rule: %s\n", argv[i]);
-                       status = 1;
-                       continue;
-               }
-
                if (pdlen < 0 && !fmr) {
                        fprintf(stderr, "Skipping non-FMR without matching PD: %s\n", argv[i]);
                        status = 1;