diff options
-rw-r--r-- | package/network/ipv6/map/Makefile | 4 | ||||
-rw-r--r-- | package/network/ipv6/map/src/mapcalc.c | 92 |
2 files changed, 58 insertions, 38 deletions
diff --git a/package/network/ipv6/map/Makefile b/package/network/ipv6/map/Makefile index 09ba523ec0..89d34de1b4 100644 --- a/package/network/ipv6/map/Makefile +++ b/package/network/ipv6/map/Makefile @@ -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 diff --git a/package/network/ipv6/map/src/mapcalc.c b/package/network/ipv6/map/src/mapcalc.c index b61e157fc3..cd72138cc6 100644 --- a/package/network/ipv6/map/src/mapcalc.c +++ b/package/network/ipv6/map/src/mapcalc.c @@ -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; |