mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-07 15:47:01 +02:00
MEDIUM: tools/ip: v4tov6() and v6tov4() rework
v4tov6() and v6tov4() helper function were initially implemented in4f92d3200
("[MEDIUM] IPv6 support for stick-tables"). However, sinceceb4ac9c3
("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:
parent
d3e379b3ce
commit
72514a4467
46
src/tools.c
46
src/tools.c
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user