Hi, On 26.12.24 14:00, Gert Doering wrote: > On Wed, Dec 25, 2024 at 05:21:35PM +0100, Gert Doering wrote: >> I'm fine with the idea, but I do not like the implementation with >> "yet another localized sockaddr manipulation function" - we already >> have similar code in socket.c/setenv_sockaddr(), so maybe we need >> to make this a more general thing. > > I now see that it's not *that* easy, as transform_mapped_v4_sockaddr() > is also used by part 2/3 of the series... so maybe we'll just take 1/3 > as it is, and see if we can overhaul the whole handling of v4-mapped > addresses in a more coordinated way later.
I actually had initially implemented it in socket.c, but reverted it to a local and simpler implementation because I was sure to otherwise break stuff with it. I dug it up again and refined it a bit, feel free to have a look at the attached patch and form an opinion. But please consider it still WIP, it is not intended as a v3 of the original patch. Best regards -- Corubba
From f749d6ab799cc40e33c15fdd95841ab19c9c39fa Mon Sep 17 00:00:00 2001 From: Corubba Smith <coru...@gmx.de> Date: Thu, 26 Dec 2024 21:23:30 +0100 Subject: [PATCH] WIP: generic v4-mapped-normalize implementation in socket.c Implement three functions to do v4-mapped normalization of openvpn_sockaddr: in-place, into an existing struct, and with a new gc-allocated struct. Also do the normalization in print_sockaddr by default because I feel that is what users expect, and add a flag do disable it (in case it is ever needed). Since print_sockaddr does normalization by default and the journal directory is solely based on that, no explicit normalization is needed anymore. Haven't tested the dco part, but the rest works. mroute doesn't use a sockaddr but only the addr structs, requires more code to also support. Signed-off-by: Corubba Smith <coru...@gmx.de> --- src/openvpn/dco_linux.c | 13 +------- src/openvpn/socket.c | 72 +++++++++++++++++++++++++++++++++-------- src/openvpn/socket.h | 7 ++++ 3 files changed, 67 insertions(+), 25 deletions(-) diff --git a/src/openvpn/dco_linux.c b/src/openvpn/dco_linux.c index b0383828..ad4b110f 100644 --- a/src/openvpn/dco_linux.c +++ b/src/openvpn/dco_linux.c @@ -203,18 +203,7 @@ ovpn_nl_msg_send(dco_context_t *dco, struct nl_msg *nl_msg, ovpn_nl_cb cb, struct sockaddr * mapped_v4_to_v6(struct sockaddr *sock, struct gc_arena *gc) { - struct sockaddr_in6 *sock6 = (struct sockaddr_in6 *)sock; - if (sock->sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sock6->sin6_addr)) - { - - struct sockaddr_in *sock4; - ALLOC_OBJ_CLEAR_GC(sock4, struct sockaddr_in, gc); - memcpy(&sock4->sin_addr, sock6->sin6_addr.s6_addr + 12, 4); - sock4->sin_port = sock6->sin6_port; - sock4->sin_family = AF_INET; - return (struct sockaddr *)sock4; - } - return sock; + return (struct sockaddr *) normalized_sockaddr((const struct openvpn_sockaddr *) sock, gc); } int diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 01874fe2..c9677335 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -2756,6 +2756,11 @@ print_sockaddr_ex(const struct sockaddr *sa, char servname[NI_MAXSERV] = ""; int status; + if (!(flags & PS_DONT_NORMALIZE)) + { + sa = &(normalized_sockaddr((struct openvpn_sockaddr *) sa, gc)->addr.sa); + } + socklen_t salen = 0; switch (sa->sa_family) { @@ -2939,6 +2944,54 @@ print_in6_addr(struct in6_addr a6, unsigned int flags, struct gc_arena *gc) return out; } +/* + * In-place transformation of an openvpn_sockaddr with an IPv4-mapped + * IPv6 address to one with a plain IPv4 address. No-op otherwise. + */ +void +normalize_sockaddr(struct openvpn_sockaddr *sock) +{ + if (sock->addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sock->addr.in6.sin6_addr)) + { + sock->addr.in4.sin_family = AF_INET; + assert(sock->addr.in4.sin_port == sock->addr.in6.sin6_port); + memcpy(&sock->addr.in4.sin_addr, &sock->addr.in6.sin6_addr.s6_addr[12], 4); + memset(&sock->addr.in4 + 1, 0, sizeof(sock->addr) - sizeof(sock->addr.in4)); + } +} + +/* + * Copy src to dst. If src is an IPv4-mapped IPv6 address, dst will + * be its plain IPv4 address equivalent. + */ +void +copy_normalized_sockaddr(const struct openvpn_sockaddr *src, struct openvpn_sockaddr *dst) +{ + ASSERT(src != dst); + memcpy(dst, src, sizeof(*dst)); + normalize_sockaddr(dst); +} + +/* + * If sock is an IPv4-mapped IPv6 address, returns a pointer to a new + * gc-allocated struct with equivalent plain IPv4 address. No-op + * otherwise, returning the passed-in struct pointer. + */ +struct openvpn_sockaddr * +normalized_sockaddr(const struct openvpn_sockaddr *sock, struct gc_arena *gc) +{ + if (sock->addr.sa.sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sock->addr.in6.sin6_addr)) + { + struct openvpn_sockaddr *sock4; + ALLOC_OBJ_CLEAR_GC(sock4, struct openvpn_sockaddr, gc); + copy_normalized_sockaddr(sock, sock4); + return sock4; + } + + /* horrible: returning the passed-in const pointer as non-const */ + return (struct openvpn_sockaddr *) sock; +} + /* * Convert an in_port_t in host byte order to a string */ @@ -2985,6 +3038,10 @@ setenv_sockaddr(struct env_set *es, const char *name_prefix, const struct openvp { char name_buf[256]; + struct openvpn_sockaddr addr_struct = {0}; + copy_normalized_sockaddr(addr, &addr_struct); + addr = &addr_struct; + char buf[INET6_ADDRSTRLEN]; switch (addr->addr.sa.sa_family) { @@ -3009,19 +3066,8 @@ setenv_sockaddr(struct env_set *es, const char *name_prefix, const struct openvp break; case AF_INET6: - if (IN6_IS_ADDR_V4MAPPED( &addr->addr.in6.sin6_addr )) - { - struct in_addr ia; - memcpy(&ia.s_addr, &addr->addr.in6.sin6_addr.s6_addr[12], - sizeof(ia.s_addr)); - snprintf(name_buf, sizeof(name_buf), "%s_ip", name_prefix); - inet_ntop(AF_INET, &ia, buf, sizeof(buf)); - } - else - { - snprintf(name_buf, sizeof(name_buf), "%s_ip6", name_prefix); - inet_ntop(AF_INET6, &addr->addr.in6.sin6_addr, buf, sizeof(buf)); - } + snprintf(name_buf, sizeof(name_buf), "%s_ip6", name_prefix); + inet_ntop(AF_INET6, &addr->addr.in6.sin6_addr, buf, sizeof(buf)); setenv_str(es, name_buf, buf); if ((flags & SA_IP_PORT) && addr->addr.in6.sin6_port) diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h index 465d92ba..07fb7b73 100644 --- a/src/openvpn/socket.h +++ b/src/openvpn/socket.h @@ -359,6 +359,7 @@ void sd_close(socket_descriptor_t *sd); #define PS_SHOW_PKTINFO (1<<2) #define PS_DONT_SHOW_ADDR (1<<3) #define PS_DONT_SHOW_FAMILY (1<<4) +#define PS_DONT_NORMALIZE (1<<5) const char *print_sockaddr_ex(const struct sockaddr *addr, const char *separator, @@ -398,6 +399,12 @@ const char *print_in_addr_t(in_addr_t addr, unsigned int flags, struct gc_arena const char *print_in6_addr(struct in6_addr addr6, unsigned int flags, struct gc_arena *gc); +void normalize_sockaddr(struct openvpn_sockaddr *sock); + +void copy_normalized_sockaddr(const struct openvpn_sockaddr *src, struct openvpn_sockaddr *dst); + +struct openvpn_sockaddr * normalized_sockaddr(const struct openvpn_sockaddr *sock, struct gc_arena *gc); + const char *print_in_port_t(in_port_t port, struct gc_arena *gc); struct in6_addr add_in6_addr( struct in6_addr base, uint32_t add ); -- 2.47.1
_______________________________________________ Openvpn-devel mailing list Openvpn-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openvpn-devel