MEDIUM: tools/ip: v4tov6() and v6tov4() rework

v4tov6() and v6tov4() helper function were initially implemented in
4f92d3200 ("[MEDIUM] IPv6 support for stick-tables").

However, since ceb4ac9c3 ("MEDIUM: acl: support IPv6 address matching")
support for legacy ip6 to ip4 conversion formats were added, with the
parsing logic directly performed in acl_match_ip (which later became
pat_match_ip)

The issue is that the original v6tov4() function which is used for sample
expressions handling lacks those additional formats, so we could face
inconsistencies whether we rely on ip4/ip6 conversions from an acl context
or an expression context.

To unify ip4/ip6 automatic mapping behavior, we reworked v4tov6 and v6tov4
functions so that they now behave like in pat_match_ip() function.

Note: '6to4 (RFC3056)' and 'RFC4291 ipv4 compatible address' formats are
still supported for legacy purposes despite being deprecated for a while
now.
This commit is contained in:
Aurelien DARRAGON 2023-09-05 14:04:51 +02:00 committed by Christopher Faulet
parent d3e379b3ce
commit 72514a4467

View File

@ -3327,35 +3327,47 @@ int in_net_ipv6(const void *addr, const struct in6_addr *mask, const struct in6_
return 1;
}
/* RFC 4291 prefix */
const char rfc4291_pfx[] = { 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF };
/* Map IPv4 address on IPv6 address, as specified in RFC 3513.
/* Map IPv4 address on IPv6 address, as specified in RFC4291
* "IPv4-Mapped IPv6 Address" (using the :ffff: prefix)
*
* Input and output may overlap.
*/
void v4tov6(struct in6_addr *sin6_addr, struct in_addr *sin_addr)
{
struct in_addr tmp_addr;
uint32_t ip4_addr;
tmp_addr.s_addr = sin_addr->s_addr;
memcpy(sin6_addr->s6_addr, rfc4291_pfx, sizeof(rfc4291_pfx));
memcpy(sin6_addr->s6_addr+12, &tmp_addr.s_addr, 4);
ip4_addr = sin_addr->s_addr;
memset(&sin6_addr->s6_addr, 0, 10);
write_u16(&sin6_addr->s6_addr[10], htons(0xFFFF));
write_u32(&sin6_addr->s6_addr[12], ip4_addr);
}
/* Map IPv6 address on IPv4 address, as specified in RFC 3513.
/* Try to convert IPv6 address to IPv4 address thanks to the
* following mapping methods:
* - RFC4291 IPv4-Mapped IPv6 Address (prefered method)
* -> ::ffff:ip:v4
* - RFC4291 IPv4-Compatible IPv6 Address (deprecated, RFC3513 legacy for
* "IPv6 Addresses with Embedded IPv4 Addresses)
* -> ::0000:ip:v4
* - 6to4 (defined in RFC3056 proposal, seems deprecated nowadays)
* -> 2002:ip:v4::
* Return true if conversion is possible and false otherwise.
*/
int v6tov4(struct in_addr *sin_addr, struct in6_addr *sin6_addr)
{
if (memcmp(sin6_addr->s6_addr, rfc4291_pfx, sizeof(rfc4291_pfx)) == 0) {
memcpy(&(sin_addr->s_addr), &(sin6_addr->s6_addr[12]),
sizeof(struct in_addr));
return 1;
if (read_u64(&sin6_addr->s6_addr[0]) == 0 &&
(read_u32(&sin6_addr->s6_addr[8]) == htonl(0xFFFF) ||
read_u32(&sin6_addr->s6_addr[8]) == 0)) {
// RFC4291 ipv4 mapped or compatible ipv6 address
sin_addr->s_addr = read_u32(&sin6_addr->s6_addr[12]);
} else if (read_u16(&sin6_addr->s6_addr[0]) == htons(0x2002)) {
// RFC3056 6to4 address
sin_addr->s_addr = htonl((ntohs(read_u16(&sin6_addr->s6_addr[2])) << 16) +
ntohs(read_u16(&sin6_addr->s6_addr[4])));
}
return 0;
else
return 0; /* unrecognized input */
return 1; /* mapping completed */
}
/* compare two struct sockaddr_storage, including port if <check_port> is true,