From 33129481cf61c4ce106d7dcb7d617b5ae9a4339a Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Tue, 22 Aug 2023 11:23:55 +0200 Subject: [PATCH] fix handling of IPv6 UDP connections Problem: IPv6 addresses are 4 bytes long and don't fit inside a `sockaddr`, so `recvfrom` will truncate the address to the first half. When generating a reply, the remaining half of the address is filled with garbage and the packet is subsequently delivered to the wrong host, if not immediately dropped. Solution: replace `sockaddr` with `sockaddr_storage`, the latter is guaranteed to be large enough to hold an IPv6 address and pointers can be cast to `sockaddr *` when needed. --- common.h | 2 +- udp-listener.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/common.h b/common.h index 6f6e76c..6a011f4 100644 --- a/common.h +++ b/common.h @@ -112,7 +112,7 @@ struct connection { struct queue q[2]; /* SOCK_DGRAM */ - struct sockaddr client_addr; /* Contains the remote client address */ + struct sockaddr_storage client_addr; /* Contains the remote client address */ socklen_t addrlen; int local_endpoint; /* Contains the local address */ diff --git a/udp-listener.c b/udp-listener.c index 54881e2..0fb82ca 100644 --- a/udp-listener.c +++ b/udp-listener.c @@ -129,7 +129,7 @@ void udp_init(struct loop_info* fd_info) * If yes, returns file descriptor of connection * If not, returns -1 * */ -static int known_source(hash* h, struct sockaddr* addr, socklen_t addrlen) +static int known_source(hash* h, struct sockaddr_storage* addr, socklen_t addrlen) { struct connection search; search.client_addr = *addr; @@ -243,7 +243,7 @@ static int nonblocking_socket(struct sslhcfg_protocols_item* proto) struct connection* udp_c2s_forward(int sockfd, struct loop_info* fd_info) { char addr_str[NI_MAXHOST+1+NI_MAXSERV+1]; - struct sockaddr src_addr; + struct sockaddr_storage src_addr; struct addrinfo addrinfo; struct sslhcfg_protocols_item* proto; cnx_collection* collection = fd_info->collection; @@ -259,13 +259,13 @@ struct connection* udp_c2s_forward(int sockfd, struct loop_info* fd_info) udp_timeouts(fd_info); addrlen = sizeof(src_addr); - len = recvfrom(sockfd, data, sizeof(data), 0, &src_addr, &addrlen); + len = recvfrom(sockfd, data, sizeof(data), 0, (struct sockaddr*) &src_addr, &addrlen); if (len < 0) { perror("recvfrom"); return NULL; } target = known_source(fd_info->hash_sources, &src_addr, addrlen); - addrinfo.ai_addr = &src_addr; + addrinfo.ai_addr = (struct sockaddr*) &src_addr; addrinfo.ai_addrlen = addrlen; print_message(msg_probe_info, "received %ld UDP from %d:%s\n", len, target, sprintaddr(addr_str, sizeof(addr_str), &addrinfo));