diff options
-rw-r--r-- | bgpd/bgp_mplsvpn.c | 52 |
1 files changed, 36 insertions, 16 deletions
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index a72d5ede..75c90cd7 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -101,6 +101,7 @@ bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr, pnt = packet->nlri; lim = pnt + packet->length; +#define VPN_PREFIXLEN_MIN_BYTES (3 + 8) /* label + RD */ for (; pnt < lim; pnt += psize) { /* Clear prefix structure. */ @@ -108,17 +109,38 @@ bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr, /* Fetch prefix length. */ prefixlen = *pnt++; - p.family = AF_INET; + p.family = afi2family (packet->afi); psize = PSIZE (prefixlen); - - if (prefixlen < 88) - { - zlog_err ("prefix length is less than 88: %d", prefixlen); - return -1; - } - + + /* sanity check against packet data */ + if (prefixlen < VPN_PREFIXLEN_MIN_BYTES*8 || (pnt + psize) > lim) + { + zlog_err ("prefix length (%d) is less than 88" + " or larger than received (%u)", + prefixlen, (uint)(lim-pnt)); + return -1; + } + + /* sanity check against storage for the IP address portion */ + if ((psize - VPN_PREFIXLEN_MIN_BYTES) > (ssize_t) sizeof(p.u)) + { + zlog_err ("prefix length (%d) exceeds prefix storage (%zu)", + prefixlen - VPN_PREFIXLEN_MIN_BYTES*8, sizeof(p.u)); + return -1; + } + + /* Sanity check against max bitlen of the address family */ + if ((psize - VPN_PREFIXLEN_MIN_BYTES) > prefix_blen (&p)) + { + zlog_err ("prefix length (%d) exceeds family (%u) max byte length (%u)", + prefixlen - VPN_PREFIXLEN_MIN_BYTES*8, + p.family, prefix_blen (&p)); + return -1; + + } + /* Copyr label to prefix. */ - tagpnt = pnt;; + tagpnt = pnt; /* Copy routing distinguisher to rd. */ memcpy (&prd.val, pnt + 3, 8); @@ -137,8 +159,9 @@ bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr, return -1; } - p.prefixlen = prefixlen - 88; - memcpy (&p.u.prefix, pnt + 11, psize - 11); + p.prefixlen = prefixlen - VPN_PREFIXLEN_MIN_BYTES*8; + memcpy (&p.u.prefix, pnt + VPN_PREFIXLEN_MIN_BYTES, + psize - VPN_PREFIXLEN_MIN_BYTES); #if 0 if (type == RD_TYPE_AS) @@ -149,9 +172,6 @@ bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr, rd_ip.val, inet_ntoa (p.u.prefix4), p.prefixlen); #endif /* 0 */ - if (pnt + psize > lim) - return -1; - if (attr) bgp_update (peer, &p, attr, AFI_IP, SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, 0); @@ -159,12 +179,12 @@ bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr, bgp_withdraw (peer, &p, attr, AFI_IP, SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt); } - /* Packet length consistency check. */ if (pnt != lim) return -1; - + return 0; +#undef VPN_PREFIXLEN_MIN_BYTES } int |