From: Balakrishnan Balasubramanian <3070606-balki@users.noreply.gitlab.com> Date: Sun, 17 Apr 2022 09:43:36 +0000 (+0200) Subject: tests: refactor server/socksd.c to support --unix-socket X-Git-Tag: curl-7_83_0~42 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=80eb71a3f5146f2ab5c5f8d8655d6861b5472668;p=thirdparty%2Fcurl.git tests: refactor server/socksd.c to support --unix-socket Closes #8687 --- diff --git a/.gitignore b/.gitignore index 4807c9beb1..4d4a92d961 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,4 @@ scripts/curl.fish curl_fuzzer curl_fuzzer_seed_corpus.zip libstandaloneengine.a +tests/string diff --git a/tests/server/socksd.c b/tests/server/socksd.c index 6867141e3d..1f0ca1287f 100644 --- a/tests/server/socksd.c +++ b/tests/server/socksd.c @@ -143,10 +143,7 @@ const char *serverlogfile = DEFAULT_LOGFILE; const char *reqlogfile = DEFAULT_REQFILE; static const char *configfile = DEFAULT_CONFIG; -#ifdef ENABLE_IPV6 -static bool use_ipv6 = FALSE; -#endif -static const char *ipv_inuse = "IPv4"; +static const char *socket_type = "IPv4"; static unsigned short port = DEFAULT_PORT; static void resetdefaults(void) @@ -177,6 +174,16 @@ static unsigned short shortval(char *value) return num & 0xffff; } +static enum { + socket_domain_inet = AF_INET +#ifdef ENABLE_IPV6 + , socket_domain_inet6 = AF_INET6 +#endif +#ifdef USE_UNIX_SOCKETS + , socket_domain_unix = AF_UNIX +#endif +} socket_domain = AF_INET; + static void getconfig(void) { FILE *fp = fopen(configfile, FOPEN_READTEXT); @@ -777,7 +784,11 @@ static bool incoming(curl_socket_t listenfd) } static curl_socket_t sockdaemon(curl_socket_t sock, - unsigned short *listenport) + unsigned short *listenport +#ifdef USE_UNIX_SOCKETS + , const char *unix_socket +#endif + ) { /* passive daemon style */ srvr_sockaddr_union_t listener; @@ -828,24 +839,29 @@ static curl_socket_t sockdaemon(curl_socket_t sock, /* When the specified listener port is zero, it is actually a request to let the system choose a non-zero available port. */ + switch(socket_domain) { + case AF_INET: + memset(&listener.sa4, 0, sizeof(listener.sa4)); + listener.sa4.sin_family = AF_INET; + listener.sa4.sin_addr.s_addr = INADDR_ANY; + listener.sa4.sin_port = htons(*listenport); + rc = bind(sock, &listener.sa, sizeof(listener.sa4)); + break; #ifdef ENABLE_IPV6 - if(!use_ipv6) { + case AF_INET6: + memset(&listener.sa6, 0, sizeof(listener.sa6)); + listener.sa6.sin6_family = AF_INET6; + listener.sa6.sin6_addr = in6addr_any; + listener.sa6.sin6_port = htons(*listenport); + rc = bind(sock, &listener.sa, sizeof(listener.sa6)); + break; +#endif /* ENABLE_IPV6 */ +#ifdef USE_UNIX_SOCKETS + case AF_UNIX: + rc = bind_unix_socket(sock, unix_socket, &listener.sau); #endif - memset(&listener.sa4, 0, sizeof(listener.sa4)); - listener.sa4.sin_family = AF_INET; - listener.sa4.sin_addr.s_addr = INADDR_ANY; - listener.sa4.sin_port = htons(*listenport); - rc = bind(sock, &listener.sa, sizeof(listener.sa4)); -#ifdef ENABLE_IPV6 - } - else { - memset(&listener.sa6, 0, sizeof(listener.sa6)); - listener.sa6.sin6_family = AF_INET6; - listener.sa6.sin6_addr = in6addr_any; - listener.sa6.sin6_port = htons(*listenport); - rc = bind(sock, &listener.sa, sizeof(listener.sa6)); } -#endif /* ENABLE_IPV6 */ + if(rc) { error = SOCKERRNO; logmsg("Error binding socket on port %hu: (%d) %s", @@ -854,19 +870,21 @@ static curl_socket_t sockdaemon(curl_socket_t sock, return CURL_SOCKET_BAD; } - if(!*listenport) { + if(!*listenport +#ifdef USE_UNIX_SOCKETS + && !unix_socket +#endif + ) { /* The system was supposed to choose a port number, figure out which port we actually got and update the listener port value with it. */ curl_socklen_t la_size; srvr_sockaddr_union_t localaddr; #ifdef ENABLE_IPV6 - if(!use_ipv6) -#endif - la_size = sizeof(localaddr.sa4); -#ifdef ENABLE_IPV6 - else + if(socket_domain == AF_INET6) la_size = sizeof(localaddr.sa6); + else #endif + la_size = sizeof(localaddr.sa4); memset(&localaddr.sa, 0, (size_t)la_size); if(getsockname(sock, &localaddr.sa, &la_size) < 0) { error = SOCKERRNO; @@ -924,6 +942,11 @@ int main(int argc, char *argv[]) int error; int arg = 1; +#ifdef USE_UNIX_SOCKETS + const char *unix_socket = NULL; + bool unlink_socket = false; +#endif + while(argc>arg) { if(!strcmp("--version", argv[arg])) { printf("socksd IPv4%s\n", @@ -972,19 +995,36 @@ int main(int argc, char *argv[]) } else if(!strcmp("--ipv6", argv[arg])) { #ifdef ENABLE_IPV6 - ipv_inuse = "IPv6"; - use_ipv6 = TRUE; + socket_domain = AF_INET6; + socket_type = "IPv6"; #endif arg++; } else if(!strcmp("--ipv4", argv[arg])) { /* for completeness, we support this option as well */ #ifdef ENABLE_IPV6 - ipv_inuse = "IPv4"; - use_ipv6 = FALSE; + socket_type = "IPv4"; #endif arg++; } + else if(!strcmp("--unix-socket", argv[arg])) { + arg++; + if(argc>arg) { +#ifdef USE_UNIX_SOCKETS + struct sockaddr_un sau; + unix_socket = argv[arg]; + if(strlen(unix_socket) >= sizeof(sau.sun_path)) { + fprintf(stderr, + "socksd: socket path must be shorter than %zu chars\n", + sizeof(sau.sun_path)); + return 0; + } + socket_domain = AF_UNIX; + socket_type = "unix"; +#endif + arg++; + } + } else if(!strcmp("--port", argv[arg])) { arg++; if(argc>arg) { @@ -1006,6 +1046,7 @@ int main(int argc, char *argv[]) " --reqfile [file]\n" " --ipv4\n" " --ipv6\n" + " --unix-socket [file]\n" " --bindonly\n" " --port [port]\n"); return 0; @@ -1023,14 +1064,7 @@ int main(int argc, char *argv[]) install_signal_handlers(false); -#ifdef ENABLE_IPV6 - if(!use_ipv6) -#endif - sock = socket(AF_INET, SOCK_STREAM, 0); -#ifdef ENABLE_IPV6 - else - sock = socket(AF_INET6, SOCK_STREAM, 0); -#endif + sock = socket(socket_domain, SOCK_STREAM, 0); if(CURL_SOCKET_BAD == sock) { error = SOCKERRNO; @@ -1041,14 +1075,27 @@ int main(int argc, char *argv[]) { /* passive daemon style */ - sock = sockdaemon(sock, &port); + sock = sockdaemon(sock, &port +#ifdef USE_UNIX_SOCKETS + , unix_socket +#endif + ); if(CURL_SOCKET_BAD == sock) { goto socks5_cleanup; } +#ifdef USE_UNIX_SOCKETS + unlink_socket = true; +#endif msgsock = CURL_SOCKET_BAD; /* no stream socket yet */ } - logmsg("Running %s version", ipv_inuse); + logmsg("Running %s version", socket_type); + +#ifdef USE_UNIX_SOCKETS + if(socket_domain == AF_UNIX) + logmsg("Listening on unix socket %s", unix_socket); + else +#endif logmsg("Listening on port %hu", port); wrotepidfile = write_pidfile(pidname); @@ -1075,6 +1122,13 @@ socks5_cleanup: if(sock != CURL_SOCKET_BAD) sclose(sock); +#ifdef USE_UNIX_SOCKETS + if(unlink_socket && socket_domain == AF_UNIX) { + error = unlink(unix_socket); + logmsg("unlink(%s) = %d (%s)", unix_socket, error, strerror(error)); + } +#endif + if(wrotepidfile) unlink(pidname); if(wroteportfile) diff --git a/tests/server/sws.c b/tests/server/sws.c index 6ce0d3b9fc..6a894987d5 100644 --- a/tests/server/sws.c +++ b/tests/server/sws.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2022, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -2066,59 +2066,7 @@ int main(int argc, char *argv[]) #endif /* ENABLE_IPV6 */ #ifdef USE_UNIX_SOCKETS case AF_UNIX: - memset(&me.sau, 0, sizeof(me.sau)); - me.sau.sun_family = AF_UNIX; - strncpy(me.sau.sun_path, unix_socket, sizeof(me.sau.sun_path) - 1); - rc = bind(sock, &me.sa, sizeof(me.sau)); - if(0 != rc && errno == EADDRINUSE) { - struct_stat statbuf; - /* socket already exists. Perhaps it is stale? */ - curl_socket_t unixfd = socket(AF_UNIX, SOCK_STREAM, 0); - if(CURL_SOCKET_BAD == unixfd) { - error = SOCKERRNO; - logmsg("Error binding socket, failed to create socket at %s: (%d) %s", - unix_socket, error, strerror(error)); - goto sws_cleanup; - } - /* check whether the server is alive */ - rc = connect(unixfd, &me.sa, sizeof(me.sau)); - error = errno; - sclose(unixfd); - if(ECONNREFUSED != error) { - logmsg("Error binding socket, failed to connect to %s: (%d) %s", - unix_socket, error, strerror(error)); - goto sws_cleanup; - } - /* socket server is not alive, now check if it was actually a socket. */ -#ifdef WIN32 - /* Windows does not have lstat function. */ - rc = curlx_win32_stat(unix_socket, &statbuf); -#else - rc = lstat(unix_socket, &statbuf); -#endif - if(0 != rc) { - logmsg("Error binding socket, failed to stat %s: (%d) %s", - unix_socket, errno, strerror(errno)); - goto sws_cleanup; - } -#ifdef S_IFSOCK - if((statbuf.st_mode & S_IFSOCK) != S_IFSOCK) { - logmsg("Error binding socket, failed to stat %s: (%d) %s", - unix_socket, error, strerror(error)); - goto sws_cleanup; - } -#endif - /* dead socket, cleanup and retry bind */ - rc = unlink(unix_socket); - if(0 != rc) { - logmsg("Error binding socket, failed to unlink %s: (%d) %s", - unix_socket, errno, strerror(errno)); - goto sws_cleanup; - } - /* stale socket is gone, retry bind */ - rc = bind(sock, &me.sa, sizeof(me.sau)); - } - break; + rc = bind_unix_socket(sock, unix_socket, &me.sau); #endif /* USE_UNIX_SOCKETS */ } if(0 != rc) { diff --git a/tests/server/util.c b/tests/server/util.c index 3b98e71660..d6ef5bf81a 100644 --- a/tests/server/util.c +++ b/tests/server/util.c @@ -809,3 +809,66 @@ void restore_signal_handlers(bool keep_sigalrm) } #endif } + +#ifdef USE_UNIX_SOCKETS + +int bind_unix_socket(curl_socket_t sock, const char *unix_socket, + struct sockaddr_un *sau) { + int error; + int rc; + + memset(sau, 0, sizeof(struct sockaddr_un)); + sau->sun_family = AF_UNIX; + strncpy(sau->sun_path, unix_socket, sizeof(sau->sun_path) - 1); + rc = bind(sock, (struct sockaddr*)sau, sizeof(struct sockaddr_un)); + if(0 != rc && errno == EADDRINUSE) { + struct_stat statbuf; + /* socket already exists. Perhaps it is stale? */ + curl_socket_t unixfd = socket(AF_UNIX, SOCK_STREAM, 0); + if(CURL_SOCKET_BAD == unixfd) { + error = SOCKERRNO; + logmsg("Error binding socket, failed to create socket at %s: (%d) %s", + unix_socket, error, strerror(error)); + return rc; + } + /* check whether the server is alive */ + rc = connect(unixfd, (struct sockaddr*)sau, sizeof(struct sockaddr_un)); + error = errno; + sclose(unixfd); + if(ECONNREFUSED != error) { + logmsg("Error binding socket, failed to connect to %s: (%d) %s", + unix_socket, error, strerror(error)); + return rc; + } + /* socket server is not alive, now check if it was actually a socket. */ +#ifdef WIN32 + /* Windows does not have lstat function. */ + rc = curlx_win32_stat(unix_socket, &statbuf); +#else + rc = lstat(unix_socket, &statbuf); +#endif + if(0 != rc) { + logmsg("Error binding socket, failed to stat %s: (%d) %s", + unix_socket, errno, strerror(errno)); + return rc; + } +#ifdef S_IFSOCK + if((statbuf.st_mode & S_IFSOCK) != S_IFSOCK) { + logmsg("Error binding socket, failed to stat %s: (%d) %s", + unix_socket, error, strerror(error)); + return rc; + } +#endif + /* dead socket, cleanup and retry bind */ + rc = unlink(unix_socket); + if(0 != rc) { + logmsg("Error binding socket, failed to unlink %s: (%d) %s", + unix_socket, errno, strerror(errno)); + return rc; + } + /* stale socket is gone, retry bind */ + rc = bind(sock, (struct sockaddr*)sau, sizeof(struct sockaddr_un)); + } + return rc; +} +#endif diff --git a/tests/server/util.h b/tests/server/util.h index f67b685279..739486e9f1 100644 --- a/tests/server/util.h +++ b/tests/server/util.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2022, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -79,4 +79,14 @@ extern HANDLE exit_event; void install_signal_handlers(bool keep_sigalrm); void restore_signal_handlers(bool keep_sigalrm); +#ifdef USE_UNIX_SOCKETS + +#ifdef HAVE_SYS_UN_H +#include /* for sockaddr_un */ +#endif /* HAVE_SYS_UN_H */ + +int bind_unix_socket(curl_socket_t sock, const char *unix_socket, + struct sockaddr_un *sau); +#endif /* USE_UNIX_SOCKETS */ + #endif /* HEADER_CURL_SERVER_UTIL_H */