]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgp_flowspec_util.c
bgpd: ipv6 flowspec address decoding and validation
[mirror_frr.git] / bgpd / bgp_flowspec_util.c
index 0e879e8168d09cade99fb8a063b147618d9530ff..2dd35696d0f66f2c8c7af3691748de4c015817ed 100644 (file)
@@ -101,7 +101,7 @@ bool bgp_flowspec_contains_prefix(const struct prefix *pfs,
                                        nlri_content+offset,
                                        len - offset,
                                        &compare, &error,
-                                       afi);
+                                       afi, NULL);
                        if (ret <= 0)
                                break;
                        if (prefix_check &&
@@ -162,13 +162,15 @@ int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type,
                            uint8_t *nlri_ptr,
                            uint32_t max_len,
                            void *result, int *error,
-                           afi_t afi)
+                           afi_t afi,
+                           uint8_t *ipv6_offset)
 {
        char *display = (char *)result; /* for return_string */
        struct prefix *prefix = (struct prefix *)result;
        uint32_t offset = 0;
        struct prefix prefix_local;
        int psize;
+       uint8_t prefix_offset = 0;
 
        *error = 0;
        memset(&prefix_local, 0, sizeof(struct prefix));
@@ -176,8 +178,13 @@ int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type,
        prefix_local.prefixlen = nlri_ptr[offset];
        psize = PSIZE(prefix_local.prefixlen);
        offset++;
-       /* TODO Flowspec IPv6 Support */
-       prefix_local.family = AF_INET;
+       prefix_local.family = afi2family(afi);
+       if (prefix_local.family == AF_INET6) {
+               prefix_offset = nlri_ptr[offset];
+               if (ipv6_offset)
+                       *ipv6_offset = prefix_offset;
+               offset++;
+       }
        /* Prefix length check. */
        if (prefix_local.prefixlen > prefix_blen(&prefix_local) * 8)
                *error = -1;
@@ -193,11 +200,28 @@ int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type,
        offset += psize;
        switch (type) {
        case BGP_FLOWSPEC_RETURN_STRING:
-               prefix2str(&prefix_local, display,
-                          BGP_FLOWSPEC_STRING_DISPLAY_MAX);
+               if (prefix_local.family == AF_INET6) {
+                       char str[BGP_FLOWSPEC_STRING_DISPLAY_MAX];
+                       int ret;
+
+                       prefix2str(&prefix_local, str,
+                                  BGP_FLOWSPEC_STRING_DISPLAY_MAX);
+                       ret = snprintf(display, BGP_FLOWSPEC_STRING_DISPLAY_MAX,
+                                      "%s/off %u",
+                                      str, prefix_offset);
+                       if (ret < 0) {
+                               *error = -1;
+                               break;
+                       }
+               } else
+                       prefix2str(&prefix_local, display,
+                                  BGP_FLOWSPEC_STRING_DISPLAY_MAX);
                break;
        case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
-               PREFIX_COPY_IPV4(prefix, &prefix_local)
+               if (prefix_local.family == AF_INET)
+                       PREFIX_COPY_IPV4(prefix, &prefix_local)
+               else
+                       PREFIX_COPY_IPV6(prefix, &prefix_local)
                break;
        case BGP_FLOWSPEC_VALIDATE_ONLY:
        default:
@@ -430,6 +454,7 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
        uint8_t *match_num;
        uint8_t bitmask = 0;
        int ret = 0, type;
+       uint8_t *prefix_offset;
 
        while (offset < len - 1 && error >= 0) {
                type = nlri_content[offset];
@@ -441,16 +466,18 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
                        if (type == FLOWSPEC_DEST_PREFIX) {
                                bitmask |= PREFIX_DST_PRESENT;
                                prefix = &bpem->dst_prefix;
+                               prefix_offset = &bpem->dst_prefix_offset;
                        } else {
                                bitmask |= PREFIX_SRC_PRESENT;
                                prefix = &bpem->src_prefix;
+                               prefix_offset = &bpem->src_prefix_offset;
                        }
                        ret = bgp_flowspec_ip_address(
                                        BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
                                        nlri_content + offset,
                                        len - offset,
                                        prefix, &error,
-                                       afi);
+                                       afi, prefix_offset);
                        if (error < 0)
                                flog_err(EC_BGP_FLOWSPEC_PACKET,
                                         "%s: flowspec_ip_address error %d",
@@ -462,6 +489,11 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
                                if (prefix->family == AF_INET
                                    && prefix->u.prefix4.s_addr == INADDR_ANY)
                                        bpem->match_bitmask_iprule |= bitmask;
+                               else if (prefix->family == AF_INET6
+                                        && !memcmp(&prefix->u.prefix6,
+                                                   &in6addr_any,
+                                                   sizeof(struct in6_addr)))
+                                       bpem->match_bitmask_iprule |= bitmask;
                                else
                                        bpem->match_bitmask |= bitmask;
                        }