From: Willy Tarreau Date: Fri, 28 Aug 2020 13:19:45 +0000 (+0200) Subject: MINOR: sock_inet: implement sock_inet_get_dst() X-Git-Tag: v2.3-dev4~58 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c5a94c936b26432488a1a7577a79e74d6b0d2ffa;p=thirdparty%2Fhaproxy.git MINOR: sock_inet: implement sock_inet_get_dst() This one is common to the TCPv4 and UDPv4 code, it retrieves the destination address of a socket, taking care of the possiblity that for an incoming connection the traffic was possibly redirected. The TCP and UDP definitions were updated to rely on it and remove duplicated code. --- diff --git a/include/haproxy/proto_tcp.h b/include/haproxy/proto_tcp.h index 2e20309116..8e57acfd68 100644 --- a/include/haproxy/proto_tcp.h +++ b/include/haproxy/proto_tcp.h @@ -31,7 +31,6 @@ int tcp_bind_socket(int fd, int flags, struct sockaddr_storage *local, struct sockaddr_storage *remote); int tcp_pause_listener(struct listener *l); int tcp_connect_server(struct connection *conn, int flags); -int tcp_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir); int tcp_is_foreign(int fd, sa_family_t family); #endif /* _HAPROXY_PROTO_TCP_H */ diff --git a/include/haproxy/proto_udp.h b/include/haproxy/proto_udp.h index 31e6a90523..6b91cea7c3 100644 --- a/include/haproxy/proto_udp.h +++ b/include/haproxy/proto_udp.h @@ -29,6 +29,7 @@ int udp_pause_listener(struct listener *l); int udp_get_src(int fd, struct sockaddr *sa, socklen_t salen, int dir); int udp6_get_src(int fd, struct sockaddr *sa, socklen_t salen, int dir); int udp_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir); +int udp6_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir); #endif /* _PROTO_PROTO_UDP_H */ diff --git a/include/haproxy/sock_inet.h b/include/haproxy/sock_inet.h index 814ae58393..8b1de095a3 100644 --- a/include/haproxy/sock_inet.h +++ b/include/haproxy/sock_inet.h @@ -29,5 +29,6 @@ int sock_inet4_addrcmp(const struct sockaddr_storage *a, const struct sockaddr_storage *b); int sock_inet6_addrcmp(const struct sockaddr_storage *a, const struct sockaddr_storage *b); +int sock_inet_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir); #endif /* _HAPROXY_SOCK_INET_H */ diff --git a/src/proto_tcp.c b/src/proto_tcp.c index 17da4033d4..675c686eee 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -65,7 +65,7 @@ static struct protocol proto_tcpv4 = { .unbind_all = unbind_all_listeners, .enable_all = enable_all_listeners, .get_src = sock_get_src, - .get_dst = tcp_get_dst, + .get_dst = sock_inet_get_dst, .pause = tcp_pause_listener, .add = tcpv4_add_listener, .addrcmp = sock_inet4_addrcmp, @@ -91,7 +91,7 @@ static struct protocol proto_tcpv6 = { .unbind_all = unbind_all_listeners, .enable_all = enable_all_listeners, .get_src = sock_get_src, - .get_dst = tcp_get_dst, + .get_dst = sock_get_dst, .pause = tcp_pause_listener, .add = tcpv6_add_listener, .addrcmp = sock_inet6_addrcmp, @@ -581,38 +581,6 @@ int tcp_connect_server(struct connection *conn, int flags) return SF_ERR_NONE; /* connection is OK */ } - -/* - * Retrieves the original destination address for the socket , with - * indicating if we're a listener (=0) or an initiator (!=0). In the case of a - * listener, if the original destination address was translated, the original - * address is retrieved. It returns 0 in case of success, -1 in case of error. - * The socket's source address is stored in for bytes. - */ -int tcp_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir) -{ - if (dir) - return getpeername(fd, sa, &salen); - else { - int ret = getsockname(fd, sa, &salen); - - if (ret < 0) - return ret; - -#if defined(USE_TPROXY) && defined(SO_ORIGINAL_DST) - /* For TPROXY and Netfilter's NAT, we can retrieve the original - * IPv4 address before DNAT/REDIRECT. We must not do that with - * other families because v6-mapped IPv4 addresses are still - * reported as v4. - */ - if (((struct sockaddr_storage *)sa)->ss_family == AF_INET - && getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, sa, &salen) == 0) - return 0; -#endif - return ret; - } -} - /* Returns true if the passed FD corresponds to a socket bound with LI_O_FOREIGN * according to the various supported socket options. The socket's address family * must be passed in . diff --git a/src/proto_udp.c b/src/proto_udp.c index 0bd903fb5b..96b878a345 100644 --- a/src/proto_udp.c +++ b/src/proto_udp.c @@ -87,7 +87,7 @@ static struct protocol proto_udp6 = { .unbind_all = unbind_all_listeners, .enable_all = enable_all_listeners, .get_src = udp6_get_src, - .get_dst = udp_get_dst, + .get_dst = udp6_get_dst, .pause = udp_pause_listener, .add = udp6_add_listener, .addrcmp = sock_inet6_addrcmp, @@ -142,34 +142,27 @@ int udp_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir) { int ret; - if (dir) - ret = getpeername(fd, sa, &salen); - else { - ret = getsockname(fd, sa, &salen); - - if (ret < 0) - return ret; - -#if defined(USE_TPROXY) && defined(SO_ORIGINAL_DST) - /* For TPROXY and Netfilter's NAT, we can retrieve the original - * IPv4 address before DNAT/REDIRECT. We must not do that with - * other families because v6-mapped IPv4 addresses are still - * reported as v4. - */ - if (((struct sockaddr_storage *)sa)->ss_family == AF_INET - && getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, sa, &salen) == 0) { - sa->sa_family = AF_CUST_UDP4; - return 0; - } -#endif - } + ret = sock_inet_get_dst(fd, sa, salen, dir); + if (!ret) + sa->sa_family = AF_CUST_UDP4; - if (!ret) { - if (sa->sa_family == AF_INET) - sa->sa_family = AF_CUST_UDP4; - else if (sa->sa_family == AF_INET6) - sa->sa_family = AF_CUST_UDP6; - } + return ret; +} + +/* + * Retrieves the original destination address for the socket , with + * indicating if we're a listener (=0) or an initiator (!=0). In the case of a + * listener, if the original destination address was translated, the original + * address is retrieved. It returns 0 in case of success, -1 in case of error. + * The socket's source address is stored in for bytes. + */ +int udp6_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir) +{ + int ret; + + ret = sock_get_dst(fd, sa, salen, dir); + if (!ret) + sa->sa_family = AF_CUST_UDP6; return ret; } diff --git a/src/sock_inet.c b/src/sock_inet.c index 21a024ab4b..b82a920add 100644 --- a/src/sock_inet.c +++ b/src/sock_inet.c @@ -75,3 +75,34 @@ int sock_inet6_addrcmp(const struct sockaddr_storage *a, const struct sockaddr_s return memcmp(&a6->sin6_addr, &b6->sin6_addr, sizeof(a6->sin6_addr)); } + +/* + * Retrieves the original destination address for the socket which must be + * of family AF_INET (not AF_INET6), with indicating if we're a listener + * (=0) or an initiator (!=0). In the case of a listener, if the original + * destination address was translated, the original address is retrieved. It + * returns 0 in case of success, -1 in case of error. The socket's source + * address is stored in for bytes. + */ +int sock_inet_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir) +{ + if (dir) + return getpeername(fd, sa, &salen); + else { + int ret = getsockname(fd, sa, &salen); + + if (ret < 0) + return ret; + +#if defined(USE_TPROXY) && defined(SO_ORIGINAL_DST) + /* For TPROXY and Netfilter's NAT, we can retrieve the original + * IPv4 address before DNAT/REDIRECT. We must not do that with + * other families because v6-mapped IPv4 addresses are still + * reported as v4. + */ + if (getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, sa, &salen) == 0) + return 0; +#endif + return ret; + } +}