diff --git a/docs/cmdline-opts/Makefile.am b/docs/cmdline-opts/Makefile.am index 925f07fc1..4a10b9e5c 100644 --- a/docs/cmdline-opts/Makefile.am +++ b/docs/cmdline-opts/Makefile.am @@ -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 index 000000000..bb4467b67 --- /dev/null +++ b/docs/cmdline-opts/abstract-unix-socket.d @@ -0,0 +1,9 @@ +Long: abstract-unix-socket +Arg: +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 argument should not have this leading character. diff --git a/docs/curl.1 b/docs/curl.1 index ce54fb2f1..b930b246f 100644 --- a/docs/curl.1 +++ b/docs/curl.1 @@ -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 " +(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 diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3 index a130a8a08..66f573464 100644 --- a/docs/libcurl/curl_easy_setopt.3 +++ b/docs/libcurl/curl_easy_setopt.3 @@ -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 index 000000000..8b61854c0 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_ABSTRACT_UNIX_SOCKET.3 @@ -0,0 +1,58 @@ +.\" ************************************************************************** +.\" * _ _ ____ _ +.\" * Project ___| | | | _ \| | +.\" * / __| | | | |_) | | +.\" * | (__| |_| | _ <| |___ +.\" * \___|\___/|_| \_\_____| +.\" * +.\" * Copyright (C) 1998 - 2017, 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 +.\" * 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 + +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), " diff --git a/docs/libcurl/opts/Makefile.am b/docs/libcurl/opts/Makefile.am index eb7ca1bb5..80f28ca9b 100644 --- a/docs/libcurl/opts/Makefile.am +++ b/docs/libcurl/opts/Makefile.am @@ -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 \ diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions index bd5960c2f..89672c5e9 100644 --- a/docs/libcurl/symbols-in-versions +++ b/docs/libcurl/symbols-in-versions @@ -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 diff --git a/include/curl/curl.h b/include/curl/curl.h index 9481aca8c..a626caf38 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -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; diff --git a/include/curl/typecheck-gcc.h b/include/curl/typecheck-gcc.h index 4eb896eaa..3d683152b 100644 --- a/include/curl/typecheck-gcc.h +++ b/include/curl/typecheck-gcc.h @@ -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 || \ diff --git a/lib/curl_addrinfo.c b/lib/curl_addrinfo.c index 61cdaddc1..7182a0066 100644 --- a/lib/curl_addrinfo.c +++ b/lib/curl_addrinfo.c @@ -47,6 +47,8 @@ # define in_addr_t unsigned long #endif +#include + #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 diff --git a/lib/curl_addrinfo.h b/lib/curl_addrinfo.h index 4f24730af..8f6f3d106 100644 --- a/lib/curl_addrinfo.h +++ b/lib/curl_addrinfo.h @@ -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) && \ diff --git a/lib/url.c b/lib/url.c index 074289ed4..edae1e3f3 100644 --- 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 diff --git a/lib/urldata.h b/lib/urldata.h index 0271d266b..96c0aca19 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -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 { diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h index 5db86f4e3..0d2f765d2 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h @@ -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; diff --git a/src/tool_getparam.c b/src/tool_getparam.c index d8a3c07bc..2777a0a2e 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -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 */ diff --git a/src/tool_help.c b/src/tool_help.c index a21a336d9..5085e542e 100644 --- a/src/tool_help.c +++ b/src/tool_help.c @@ -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", diff --git a/src/tool_operate.c b/src/tool_operate.c index eff939f8c..db53d0d5a 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -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);