This commit is contained in:
karthikeyav 2025-04-29 16:22:43 +00:00 committed by GitHub
commit 876197608f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 122 additions and 28 deletions

View file

@ -86,14 +86,6 @@ static inline int str2ipaddr(const char *str, struct ipaddr *ip)
return -1;
}
static inline char *ipaddr2str(const struct ipaddr *ip, char *buf, int size)
{
buf[0] = '\0';
if (ip)
inet_ntop(ip->ipa_type, &ip->ip.addr, buf, size);
return buf;
}
#define IS_MAPPED_IPV6(A) \
((A)->s6_addr32[0] == 0x00000000 \
? ((A)->s6_addr32[1] == 0x00000000 \
@ -127,6 +119,41 @@ static inline void ipv4_mapped_ipv6_to_ipv4(const struct in6_addr *in6,
memcpy(in, (char *)in6 + 12, sizeof(struct in_addr));
}
static inline char *ipaddr2str(const struct ipaddr *ip, char *buf, int size)
{
buf[0] = '\0';
if (ip) {
if (IS_IPADDR_V6(ip) && IN6_IS_ADDR_V4MAPPED(&ip->ipaddr_v6)) {
/* Handle IPv4-mapped IPv6 addresses specially */
struct in_addr ipv4;
char ipv4str[INET_ADDRSTRLEN];
/*
* Extract the IPv4 address from the mapped IPv6 address.
* Per RFC 5952 section 5, it is RECOMMENDED to represent
* IPv4-mapped IPv6 addresses using "mixed notation" with the
* IPv4 part in dot-decimal format: ::ffff:192.0.2.1
* instead of ::ffff:c000:0201
*/
ipv4_mapped_ipv6_to_ipv4(&ip->ipaddr_v6, &ipv4);
/* Format as IPv4-mapped IPv6 address (::ffff:a.b.c.d) */
inet_ntop(AF_INET, &ipv4, ipv4str, sizeof(ipv4str));
/*
* 1. Copy prefix (7 chars for "::ffff:")
* 2. Append IPv4 address safely with strlcat
*/
snprintf(buf, size, "::ffff:");
strlcat(buf, ipv4str, size);
} else {
/* Regular IP address formatting */
inet_ntop(ipaddr_family(ip), &ip->ip.addr, buf, size);
}
}
return buf;
}
/*
* generic ordering comparison between IP addresses
*/

View file

@ -1075,36 +1075,81 @@ static const char *prefixevpn2str(const struct prefix_evpn *p, char *str,
return str;
}
/* Helper function to format the prefix length in the format /xx */
static size_t format_prefixlen(char *buf, size_t l, int prefixlen, size_t buf_size)
{
int byte, tmp, a, b;
bool z = false;
/*
* Ensure buffer has enough space for the maximum prefix length case.
* For IPv6 with prefix length 128, we need:
* - 1 byte for '/'
* - 1 byte for '1' (hundreds place)
* - 1 byte for '2' (tens place)
* - 1 byte for '8' (ones place)
* - 1 byte for the null terminator
* Total: 5 bytes from the current position
*/
if (l + 4 >= buf_size)
return l;
buf[l++] = '/';
byte = prefixlen;
tmp = prefixlen - 100;
if (tmp >= 0) {
buf[l++] = '1';
z = true;
byte = tmp;
}
b = byte % 10;
a = byte / 10;
if (a || z)
buf[l++] = '0' + a;
buf[l++] = '0' + b;
buf[l] = '\0';
return l;
}
const char *prefix2str(union prefixconstptr pu, char *str, int size)
{
const struct prefix *p = pu.p;
char buf[PREFIX2STR_BUFFER];
int byte, tmp, a, b;
bool z = false;
size_t l;
switch (p->family) {
case AF_INET:
case AF_INET6:
inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf));
l = strlen(buf);
buf[l++] = '/';
byte = p->prefixlen;
tmp = p->prefixlen - 100;
if (tmp >= 0) {
buf[l++] = '1';
z = true;
byte = tmp;
}
b = byte % 10;
a = byte / 10;
if (a || z)
buf[l++] = '0' + a;
buf[l++] = '0' + b;
buf[l] = '\0';
format_prefixlen(buf, strlen(buf), p->prefixlen, sizeof(buf));
strlcpy(str, buf, size);
break;
case AF_INET6:
/* Check if it's an IPv4-mapped IPv6 address */
if (IN6_IS_ADDR_V4MAPPED(&p->u.prefix6)) {
struct in_addr ipv4;
char ipv4str[INET_ADDRSTRLEN];
ipv4_mapped_ipv6_to_ipv4(&p->u.prefix6, &ipv4);
/* Format as ::ffff:a.b.c.d/plen format */
inet_ntop(AF_INET, &ipv4, ipv4str, sizeof(ipv4str));
/*
* 1. Copy prefix (7 chars for "::ffff:")
* 2. Append IPv4 address safely with strlcat
*/
snprintf(buf, sizeof(buf), "::ffff:");
strlcat(buf, ipv4str, sizeof(buf));
format_prefixlen(buf, strlen(buf), p->prefixlen, sizeof(buf));
strlcpy(str, buf, size);
} else {
/* Regular IPv6 address */
inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf));
format_prefixlen(buf, strlen(buf), p->prefixlen, sizeof(buf));
strlcpy(str, buf, size);
}
break;
case AF_ETHERNET:
snprintf(str, size, "%s/%d",
prefix_mac2str(&p->u.prefix_eth, buf, sizeof(buf)),
@ -1614,7 +1659,29 @@ static ssize_t printfrr_i6(struct fbuf *buf, struct printfrr_eargs *ea,
if (use_star && !memcmp(ptr, &zero, sizeof(zero)))
return bputch(buf, '*');
inet_ntop(AF_INET6, ptr, cbuf, sizeof(cbuf));
/* Handle IPv4-mapped IPv6 addresses specially */
const struct in6_addr *addr = ptr;
if (IN6_IS_ADDR_V4MAPPED(addr)) {
struct in_addr ipv4;
char ipv4str[INET_ADDRSTRLEN];
/* Extract the IPv4 address from the mapped IPv6 address */
ipv4_mapped_ipv6_to_ipv4(addr, &ipv4);
/* Format as ::ffff:a.b.c.d */
inet_ntop(AF_INET, &ipv4, ipv4str, sizeof(ipv4str));
/*
* 1. Copy prefix (7 chars for "::ffff:")
* 2. Append IPv4 address safely with strlcat
*/
snprintf(cbuf, sizeof(cbuf), "::ffff:");
strlcat(cbuf, ipv4str, sizeof(cbuf));
} else {
/* Regular IPv6 address formatting */
inet_ntop(AF_INET6, ptr, cbuf, sizeof(cbuf));
}
return bputs(buf, cbuf);
}