transparent: workaround old glibc bug on RHEL7

it's been reported[0] that RHEL7 fails to properly set the length
parameter of the getsockname() call to the length of the required
struct sockaddr type, and always returns the length passed if it
is big enough.

the SOCKADDR_UNION_* macros originate from my microsocks[1] project,
and facilitate handling of the sockaddr mess without nasty casts.

[0]: https://github.com/tinyproxy/tinyproxy/issues/45#issuecomment-694594990
[1]: https://github.com/rofl0r/microsocks
master
rofl0r 2020-09-18 12:12:14 +01:00
parent d4ef2cfa62
commit c74fe57262
2 changed files with 17 additions and 5 deletions

View File

@ -31,6 +31,20 @@
#include "common.h"
#include "sblist.h"
#define SOCKADDR_UNION_AF(PTR) (PTR)->v4.sin_family
#define SOCKADDR_UNION_LENGTH(PTR) ( \
( SOCKADDR_UNION_AF(PTR) == AF_INET ) ? sizeof((PTR)->v4) : ( \
( SOCKADDR_UNION_AF(PTR) == AF_INET6 ) ? sizeof((PTR)->v6) : 0 ) )
#define SOCKADDR_UNION_ADDRESS(PTR) ( \
( SOCKADDR_UNION_AF(PTR) == AF_INET ) ? (void*) &(PTR)->v4.sin_addr : ( \
( SOCKADDR_UNION_AF(PTR) == AF_INET6 ) ? (void*) &(PTR)->v6.sin6_addr : (void*) 0 ) )
#define SOCKADDR_UNION_PORT(PTR) ( \
( SOCKADDR_UNION_AF(PTR) == AF_INET ) ? (PTR)->v4.sin_port : ( \
( SOCKADDR_UNION_AF(PTR) == AF_INET6 ) ? (PTR)->v6.sin6_port : 0 ) )
union sockaddr_union {
struct sockaddr_in v4;
struct sockaddr_in6 v6;

View File

@ -83,16 +83,14 @@ do_transparent_proxy (struct conn_s *connptr, orderedmap hashofheaders,
return 0;
}
af = length == sizeof(dest_addr.v4) ? AF_INET : AF_INET6;
if (af == AF_INET) dest_inaddr = &dest_addr.v4.sin_addr;
else dest_inaddr = &dest_addr.v6.sin6_addr;
af = SOCKADDR_UNION_AF(&dest_addr);
dest_inaddr = SOCKADDR_UNION_ADDRESS(&dest_addr);
if (!inet_ntop(af, dest_inaddr, namebuf, sizeof namebuf))
goto addr_err;
request->host = safestrdup (namebuf);
request->port = ntohs (af == AF_INET ? dest_addr.v4.sin_port
: dest_addr.v6.sin6_port);
request->port = ntohs (SOCKADDR_UNION_PORT(&dest_addr));
request->path = (char *) safemalloc (ulen + 1);
strlcpy (request->path, *url, ulen + 1);