]> granicus.if.org Git - curl/commitdiff
unix_socket: add support for abstract unix domain socket
authorIsaac Boukris <iboukris@gmail.com>
Sun, 8 Jan 2017 22:51:08 +0000 (00:51 +0200)
committerPeter Wu <peter@lekensteyn.nl>
Fri, 13 Jan 2017 15:25:20 +0000 (16:25 +0100)
In addition to unix domain sockets, Linux also supports an
abstract namespace which is independent of the filesystem.

In order to support it, add new CURLOPT_ABSTRACT_UNIX_SOCKET
option which uses the same storage as CURLOPT_UNIX_SOCKET_PATH
internally, along with a flag to specify abstract socket.

On non-supporting platforms, the abstract address will be
interpreted as an empty string and fail gracefully.

Also add new --abstract-unix-socket tool parameter.

Signed-off-by: Isaac Boukris <iboukris@gmail.com>
Reported-by: Chungtsun Li (typeless)
Reviewed-by: Daniel Stenberg
Reviewed-by: Peter Wu
Closes #1197
Fixes #1061

17 files changed:
docs/cmdline-opts/Makefile.am
docs/cmdline-opts/abstract-unix-socket.d [new file with mode: 0644]
docs/curl.1
docs/libcurl/curl_easy_setopt.3
docs/libcurl/opts/CURLOPT_ABSTRACT_UNIX_SOCKET.3 [new file with mode: 0644]
docs/libcurl/opts/Makefile.am
docs/libcurl/symbols-in-versions
include/curl/curl.h
include/curl/typecheck-gcc.h
lib/curl_addrinfo.c
lib/curl_addrinfo.h
lib/url.c
lib/urldata.h
src/tool_cfgable.h
src/tool_getparam.c
src/tool_help.c
src/tool_operate.c

index 925f07fc13b1965ddebea11adc4da25cb4312898..4a10b9e5c5e615cbb76e5a6720f1e69e224660b3 100644 (file)
@@ -22,7 +22,8 @@
 
 AUTOMAKE_OPTIONS = foreign no-dependencies
 
-DPAGES = anyauth.d append.d basic.d cacert.d capath.d cert.d           \
+DPAGES = abstract-unix-socket.d anyauth.d                              \
+  append.d basic.d cacert.d capath.d cert.d                            \
   cert-status.d cert-type.d ciphers.d compressed.d config.d            \
   connect-timeout.d connect-to.d continue-at.d cookie.d cookie-jar.d   \
   create-dirs.d crlf.d crlfile.d data-ascii.d data-binary.d data.d     \
diff --git a/docs/cmdline-opts/abstract-unix-socket.d b/docs/cmdline-opts/abstract-unix-socket.d
new file mode 100644 (file)
index 0000000..bb4467b
--- /dev/null
@@ -0,0 +1,9 @@
+Long: abstract-unix-socket
+Arg: <path>
+Help: Connect through an abstract Unix domain socket
+Added: 7.53.0
+Protocols: HTTP
+---
+Connect through an abstract Unix domain socket, instead of using the network.
+Note: netstat shows the path of an abstract socket prefixed with '@', however
+the <path> argument should not have this leading character.
index ce54fb2f13e608f14897d32d8fd39acdc9599118..b930b246f6de3e7aff0db72739ad18d4c62120cb 100644 (file)
@@ -139,6 +139,10 @@ but prefix it with "no-". However, in this list we mostly only list and show
 the --option version of them. (This concept with --no options was added in
 7.19.0. Previously most options were toggled on/off on repeated use of the
 same command line option.)
+.IP "--abstract-unix-socket <path>"
+(HTTP) Connect through an abstract Unix domain socket, instead of using the network.
+
+Added in 7.53.0.
 .IP "--anyauth"
 (HTTP) Tells curl to figure out authentication method by itself, and use the most
 secure one the remote site claims to support. This is done by first doing a
index a130a8a082615708ff03e291c0922b9fdceaced4..66f573464bad629fd8edc69b65e86c5f25d37ff7 100644 (file)
@@ -207,6 +207,8 @@ Idle time before sending keep-alive. See \fICURLOPT_TCP_KEEPIDLE(3)\fP
 Interval between keep-alive probes. See \fICURLOPT_TCP_KEEPINTVL(3)\fP
 .IP CURLOPT_UNIX_SOCKET_PATH
 Path to a Unix domain socket. See \fICURLOPT_UNIX_SOCKET_PATH(3)\fP
+.IP CURLOPT_ABSTRACT_UNIX_SOCKET
+Path to an abstract Unix domain socket. See \fICURLOPT_ABSTRACT_UNIX_SOCKET(3)\fP
 .SH NAMES and PASSWORDS OPTIONS (Authentication)
 .IP CURLOPT_NETRC
 Enable .netrc parsing. See \fICURLOPT_NETRC(3)\fP
diff --git a/docs/libcurl/opts/CURLOPT_ABSTRACT_UNIX_SOCKET.3 b/docs/libcurl/opts/CURLOPT_ABSTRACT_UNIX_SOCKET.3
new file mode 100644 (file)
index 0000000..8b61854
--- /dev/null
@@ -0,0 +1,58 @@
+.\" **************************************************************************
+.\" *                                  _   _ ____  _
+.\" *  Project                     ___| | | |  _ \| |
+.\" *                             / __| | | | |_) | |
+.\" *                            | (__| |_| |  _ <| |___
+.\" *                             \___|\___/|_| \_\_____|
+.\" *
+.\" * Copyright (C) 1998 - 2017, 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
+.\" * are also available at https://curl.haxx.se/docs/copyright.html.
+.\" *
+.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+.\" * copies of the Software, and permit persons to whom the Software is
+.\" * furnished to do so, under the terms of the COPYING file.
+.\" *
+.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+.\" * KIND, either express or implied.
+.\" *
+.\" **************************************************************************
+.\"
+.TH CURLOPT_ABSTRACT_UNIX_SOCKET 3 "08 Jan 2017" "libcurl 7.53.0" "curl_easy_setopt options"
+.SH NAME
+CURLOPT_ABSTRACT_UNIX_SOCKET \- set an abstract Unix domain socket
+.SH SYNOPSIS
+#include <curl/curl.h>
+
+CURLcode curl_easy_setopt(CURL *handle, CURLOPT_ABSTRACT_UNIX_SOCKET, char *path);
+.SH DESCRIPTION
+Enables the use of an abstract Unix domain socket instead of establishing a TCP
+connection to a host. The parameter should be a char * to a zero terminated string
+holding the path of the socket. The path will be set to \fIpath\fP prefixed by a
+NULL byte (this is the convention for abstract sockets, however it should be stressed
+that the path passed to this function should not contain a leading NULL).
+
+On non-supporting platforms, the abstract address will be interpreted as an empty
+string and fail gracefully, generating a run-time error.
+
+This option shares the same semantics as
+.BR CURLOPT_UNIX_SOCKET_PATH "(3)
+in which documentation more details can be found. Internally, these two options share
+the same storage and therefore only one of them can be set per handle.
+
+.SH DEFAULT
+Default is NULL.
+.SH EXAMPLE
+.nf
+    curl_easy_setopt(curl_handle, CURLOPT_ABSTRACT_UNIX_SOCKET, "/tmp/foo.sock");
+    curl_easy_setopt(curl_handle, CURLOPT_URL, "http://localhost/");
+.fi
+
+.SH AVAILABILITY
+Since 7.53.0.
+.SH RETURN VALUE
+Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
+.SH "SEE ALSO"
+.BR CURLOPT_UNIX_SOCKET_PATH "(3), " unix "(7), "
index eb7ca1bb5bca4fad185c023ee551a29915c7188d..80f28ca9b4d3365b75207830c9ba07a19862b820 100644 (file)
@@ -87,6 +87,7 @@ man_MANS =                                      \
  CURLMOPT_SOCKETFUNCTION.3                      \
  CURLMOPT_TIMERDATA.3                           \
  CURLMOPT_TIMERFUNCTION.3                       \
+ CURLOPT_ABSTRACT_UNIX_SOCKET.3                 \
  CURLOPT_ACCEPTTIMEOUT_MS.3                     \
  CURLOPT_ACCEPT_ENCODING.3                      \
  CURLOPT_ADDRESS_SCOPE.3                        \
@@ -397,6 +398,7 @@ HTMLPAGES =                                     \
  CURLMOPT_SOCKETFUNCTION.html                   \
  CURLMOPT_TIMERDATA.html                        \
  CURLMOPT_TIMERFUNCTION.html                    \
+ CURLOPT_ABSTRACT_UNIX_SOCKET.html              \
  CURLOPT_ACCEPTTIMEOUT_MS.html                  \
  CURLOPT_ACCEPT_ENCODING.html                   \
  CURLOPT_ADDRESS_SCOPE.html                     \
@@ -707,6 +709,7 @@ PDFPAGES =                                      \
  CURLMOPT_SOCKETFUNCTION.pdf                    \
  CURLMOPT_TIMERDATA.pdf                         \
  CURLMOPT_TIMERFUNCTION.pdf                     \
+ CURLOPT_ABSTRACT_UNIX_SOCKET.pdf               \
  CURLOPT_ACCEPTTIMEOUT_MS.pdf                   \
  CURLOPT_ACCEPT_ENCODING.pdf                    \
  CURLOPT_ADDRESS_SCOPE.pdf                      \
index bd5960c2fe7b7c536a606a43e4e02146bb95b233..89672c5e9af7ae497b01b712e95c077736276fd0 100644 (file)
@@ -317,6 +317,7 @@ CURLOPTTYPE_LONG                7.1
 CURLOPTTYPE_OBJECTPOINT         7.1
 CURLOPTTYPE_OFF_T               7.11.0
 CURLOPTTYPE_STRINGPOINT         7.46.0
+CURLOPT_ABSTRACT_UNIX_SOCKET    7.53.0
 CURLOPT_ACCEPTTIMEOUT_MS        7.24.0
 CURLOPT_ACCEPT_ENCODING         7.21.6
 CURLOPT_ADDRESS_SCOPE           7.19.0
index 9481aca8c21372171edbcdf0a6f8627de8372259..a626caf386491cbbf1d9333c2b7d9c78232d7e27 100644 (file)
@@ -1770,6 +1770,9 @@ typedef enum {
      this option is used only if PROXY_SSL_VERIFYPEER is true */
   CINIT(PROXY_PINNEDPUBLICKEY, STRINGPOINT, 263),
 
+  /* Path to an abstract Unix domain socket */
+  CINIT(ABSTRACT_UNIX_SOCKET, STRINGPOINT, 264),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
index 4eb896eaa8c8b60b866af8eb3f52741a2a41efd4..3d683152b656c0ce62c0c7e7cd6b97cd7b22dd05 100644 (file)
@@ -219,7 +219,8 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist,
 
 /* evaluates to true if option takes a char* argument */
 #define _curl_is_string_option(option)                                        \
-  ((option) == CURLOPT_ACCEPT_ENCODING ||                                     \
+  ((option) == CURLOPT_ABSTRACT_UNIX_SOCKET ||                                \
+   (option) == CURLOPT_ACCEPT_ENCODING ||                                     \
    (option) == CURLOPT_CAINFO ||                                              \
    (option) == CURLOPT_CAPATH ||                                              \
    (option) == CURLOPT_COOKIE ||                                              \
index 61cdaddc1bee93ae58a13772d3aa0dcea318d4b6..7182a0066f745d2d18c823811e5d9a08c1dbf3b2 100644 (file)
@@ -47,6 +47,8 @@
 #  define in_addr_t unsigned long
 #endif
 
+#include <stddef.h>
+
 #include "curl_addrinfo.h"
 #include "inet_pton.h"
 #include "warnless.h"
@@ -483,24 +485,29 @@ Curl_addrinfo *Curl_str2addr(char *address, int port)
  * struct initialized with this path.
  * Set '*longpath' to TRUE if the error is a too long path.
  */
-Curl_addrinfo *Curl_unix2addr(const char *path, int *longpath)
+Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, bool abstract)
 {
   Curl_addrinfo *ai;
   struct sockaddr_un *sa_un;
   size_t path_len;
 
+  *longpath = FALSE;
+
   ai = calloc(1, sizeof(Curl_addrinfo));
   if(!ai)
     return NULL;
   ai->ai_addr = calloc(1, sizeof(struct sockaddr_un));
   if(!ai->ai_addr) {
     free(ai);
-    *longpath = FALSE;
     return NULL;
   }
+
+  sa_un = (void *) ai->ai_addr;
+  sa_un->sun_family = AF_UNIX;
+
   /* sun_path must be able to store the NUL-terminated path */
-  path_len = strlen(path);
-  if(path_len >= sizeof(sa_un->sun_path)) {
+  path_len = strlen(path) + 1;
+  if(path_len > sizeof(sa_un->sun_path)) {
     free(ai->ai_addr);
     free(ai);
     *longpath = TRUE;
@@ -509,10 +516,14 @@ Curl_addrinfo *Curl_unix2addr(const char *path, int *longpath)
 
   ai->ai_family = AF_UNIX;
   ai->ai_socktype = SOCK_STREAM; /* assume reliable transport for HTTP */
-  ai->ai_addrlen = (curl_socklen_t) sizeof(struct sockaddr_un);
-  sa_un = (void *) ai->ai_addr;
-  sa_un->sun_family = AF_UNIX;
-  memcpy(sa_un->sun_path, path, path_len + 1); /* copy NUL byte */
+  ai->ai_addrlen = offsetof(struct sockaddr_un, sun_path) + path_len;
+
+  /* Abstract Unix domain socket have NULL prefix instead of suffix */
+  if(abstract)
+    memcpy(sa_un->sun_path + 1, path, path_len - 1);
+  else
+    memcpy(sa_un->sun_path, path, path_len); /* copy NUL byte */
+
   return ai;
 }
 #endif
index 4f24730af638a20e2400f3cad38f23a533a81762..8f6f3d106478a4b67410b7b9069f6fa10db18b0f 100644 (file)
@@ -80,7 +80,7 @@ Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port);
 Curl_addrinfo *Curl_str2addr(char *dotted, int port);
 
 #ifdef USE_UNIX_SOCKETS
-Curl_addrinfo *Curl_unix2addr(const char *path, int *longpath);
+Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, bool abstract);
 #endif
 
 #if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) && \
index 074289ed4bc2027ea30a2b926b1f2e647d6da419..edae1e3f3719a32a550730b916f8e51c9ad8b016 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -2814,6 +2814,12 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option,
 
 #ifdef USE_UNIX_SOCKETS
   case CURLOPT_UNIX_SOCKET_PATH:
+    data->set.abstract_unix_socket = FALSE;
+    result = setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH],
+                       va_arg(param, char *));
+    break;
+  case CURLOPT_ABSTRACT_UNIX_SOCKET:
+    data->set.abstract_unix_socket = TRUE;
     result = setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH],
                        va_arg(param, char *));
     break;
@@ -3523,6 +3529,8 @@ ConnectionExists(struct Curl_easy *data,
           continue;
         if(strcmp(needle->unix_domain_socket, check->unix_domain_socket))
           continue;
+        if(needle->abstract_unix_socket != check->abstract_unix_socket)
+          continue;
       }
       else if(check->unix_domain_socket)
         continue;
@@ -5863,8 +5871,9 @@ static CURLcode resolve_server(struct Curl_easy *data,
       if(!hostaddr)
         result = CURLE_OUT_OF_MEMORY;
       else {
-        int longpath=0;
-        hostaddr->addr = Curl_unix2addr(path, &longpath);
+        bool longpath = FALSE;
+        hostaddr->addr = Curl_unix2addr(path, &longpath,
+                                        conn->abstract_unix_socket);
         if(hostaddr->addr)
           hostaddr->inuse++;
         else {
@@ -6273,6 +6282,7 @@ static CURLcode create_conn(struct Curl_easy *data,
       result = CURLE_OUT_OF_MEMORY;
       goto out;
     }
+    conn->abstract_unix_socket = data->set.abstract_unix_socket;
   }
 #endif
 
index 0271d266ba373b750c7efe6dacd263ddb686ab98..96c0aca199d258152e2f2c94de1e22597c46426a 100644 (file)
@@ -1133,6 +1133,7 @@ struct connectdata {
 
 #ifdef USE_UNIX_SOCKETS
   char *unix_domain_socket;
+  bool abstract_unix_socket;
 #endif
 };
 
@@ -1754,6 +1755,8 @@ struct UserDefined {
   int stream_weight;
 
   struct Curl_http2_dep *stream_dependents;
+
+  bool abstract_unix_socket;
 };
 
 struct Names {
index 5db86f4e358ae467758c0e10b258981c41bf24b0..0d2f765d2066547b4d5cb7d7ddd10475e58002bd 100644 (file)
@@ -230,6 +230,7 @@ struct OperationConfig {
   bool nonpn;                     /* enable/disable TLS NPN extension */
   bool noalpn;                    /* enable/disable TLS ALPN extension */
   char *unix_socket_path;         /* path to Unix domain socket */
+  bool abstract_unix_socket;      /* path to an abstract Unix domain socket */
   bool falsestart;
   bool path_as_is;
   double expect100timeout;
index d8a3c07bc8f4bf8cb8086c98c752a93f786dd4d0..2777a0a2eaa0fd4b455f4147f4ec4c0fdbe95402 100644 (file)
@@ -183,6 +183,7 @@ static const struct LongShort aliases[]= {
   {"$R", "expect100-timeout",        TRUE},
   {"$S", "tftp-no-options",          FALSE},
   {"$U", "connect-to",               TRUE},
+  {"$W", "abstract-unix-socket",     TRUE},
   {"0",   "http1.0",                 FALSE},
   {"01",  "http1.1",                 FALSE},
   {"02",  "http2",                   FALSE},
@@ -1024,6 +1025,7 @@ ParameterError getparameter(char *flag,    /* f or -long-flag */
 #endif
         break;
       case 'M': /* --unix-socket */
+        config->abstract_unix_socket = FALSE;
         GetStr(&config->unix_socket_path, nextarg);
         break;
       case 'N': /* --path-as-is */
@@ -1054,6 +1056,10 @@ ParameterError getparameter(char *flag,    /* f or -long-flag */
         if(err)
           return err;
         break;
+      case 'W': /* --abstract-unix-socket */
+        config->abstract_unix_socket = TRUE;
+        GetStr(&config->unix_socket_path, nextarg);
+        break;
       }
       break;
     case '#': /* --progress-bar */
index a21a336d9fd29fe5a7803d087591e1ba80d8b9e1..5085e542ecad9eb502f8fbccb9d49a59dd208b23 100644 (file)
@@ -271,7 +271,8 @@ static const char *const helptext[] = {
   "     --tlsuser USER  TLS username",
   "     --tlspassword STRING  TLS password",
   "     --tlsauthtype STRING  TLS authentication type (default: SRP)",
-  "     --unix-socket FILE    Connect through this Unix domain socket",
+  "     --unix-socket PATH    Connect through this Unix domain socket",
+  "     --abstract-unix-socket PATH Connect to an abstract Unix domain socket",
   " -A, --user-agent STRING  Send User-Agent STRING to server (H)",
   " -v, --verbose       Make the operation more talkative",
   " -V, --version       Show version number and quit",
index eff939f8c2e961bf0526e56b4ce85fb1f90267e3..db53d0d5a933a5250f3c287923303955d97c7043 100644 (file)
@@ -1393,11 +1393,17 @@ static CURLcode operate_do(struct GlobalConfig *global,
           my_setopt(curl, CURLOPT_SSL_ENABLE_ALPN, 0L);
         }
 
-        /* new in 7.40.0 */
-        if(config->unix_socket_path)
-          my_setopt_str(curl, CURLOPT_UNIX_SOCKET_PATH,
-                        config->unix_socket_path);
-
+        /* new in 7.40.0, abstract support added in 7.53.0 */
+        if(config->unix_socket_path) {
+          if(config->abstract_unix_socket) {
+            my_setopt_str(curl, CURLOPT_ABSTRACT_UNIX_SOCKET,
+                          config->unix_socket_path);
+          }
+          else {
+            my_setopt_str(curl, CURLOPT_UNIX_SOCKET_PATH,
+                          config->unix_socket_path);
+          }
+        }
         /* new in 7.45.0 */
         if(config->proto_default)
           my_setopt_str(curl, CURLOPT_DEFAULT_PROTOCOL, config->proto_default);