]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
tests: refactor server/socksd.c to support --unix-socket
authorBalakrishnan Balasubramanian <3070606-balki@users.noreply.gitlab.com>
Sun, 17 Apr 2022 09:43:36 +0000 (11:43 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Sun, 17 Apr 2022 09:43:57 +0000 (11:43 +0200)
Closes #8687

.gitignore
tests/server/socksd.c
tests/server/sws.c
tests/server/util.c
tests/server/util.h

index 4807c9beb179f6322f08544a814ef9ed1a1f6765..4d4a92d96160d7507ecc79928f0bc03262289b76 100644 (file)
@@ -59,3 +59,4 @@ scripts/curl.fish
 curl_fuzzer
 curl_fuzzer_seed_corpus.zip
 libstandaloneengine.a
+tests/string
index 6867141e3dda9ad203009ff28a71aa3a0a672fb7..1f0ca1287f4409bbee1aaee601dbd67884445110 100644 (file)
@@ -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)
index 6ce0d3b9fcadcc46f5c63a92f0c4c5bd33697832..6a894987d55ef4b01cc0deff729bec7dd84c043c 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, 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) {
index 3b98e71660282bd98d0cd8d548137fe26d23736e..d6ef5bf81a324b7a9c5a7ad6502b55efba84982a 100644 (file)
@@ -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
index f67b685279546daa2651084d92d1bbad8d062710..739486e9f1a64b80237c7dc0de1689aa27152dce 100644 (file)
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, 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 <sys/un.h> /* 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 */