unix_socket: add support for abstract unix domain socket

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
This commit is contained in:
Isaac Boukris 2017-01-09 00:51:08 +02:00 committed by Peter Wu
parent a7c73ae309
commit 1d786faee1
17 changed files with 139 additions and 19 deletions

View File

@ -22,7 +22,8 @@
AUTOMAKE_OPTIONS = foreign no-dependencies 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 \ 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 \ 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 \ create-dirs.d crlf.d crlfile.d data-ascii.d data-binary.d data.d \

View File

@ -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.

View 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 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 7.19.0. Previously most options were toggled on/off on repeated use of the
same command line option.) 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" .IP "--anyauth"
(HTTP) Tells curl to figure out authentication method by itself, and use the most (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 secure one the remote site claims to support. This is done by first doing a

View 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 Interval between keep-alive probes. See \fICURLOPT_TCP_KEEPINTVL(3)\fP
.IP CURLOPT_UNIX_SOCKET_PATH .IP CURLOPT_UNIX_SOCKET_PATH
Path to a Unix domain socket. See \fICURLOPT_UNIX_SOCKET_PATH(3)\fP 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) .SH NAMES and PASSWORDS OPTIONS (Authentication)
.IP CURLOPT_NETRC .IP CURLOPT_NETRC
Enable .netrc parsing. See \fICURLOPT_NETRC(3)\fP Enable .netrc parsing. See \fICURLOPT_NETRC(3)\fP

View File

@ -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), "

View File

@ -87,6 +87,7 @@ man_MANS = \
CURLMOPT_SOCKETFUNCTION.3 \ CURLMOPT_SOCKETFUNCTION.3 \
CURLMOPT_TIMERDATA.3 \ CURLMOPT_TIMERDATA.3 \
CURLMOPT_TIMERFUNCTION.3 \ CURLMOPT_TIMERFUNCTION.3 \
CURLOPT_ABSTRACT_UNIX_SOCKET.3 \
CURLOPT_ACCEPTTIMEOUT_MS.3 \ CURLOPT_ACCEPTTIMEOUT_MS.3 \
CURLOPT_ACCEPT_ENCODING.3 \ CURLOPT_ACCEPT_ENCODING.3 \
CURLOPT_ADDRESS_SCOPE.3 \ CURLOPT_ADDRESS_SCOPE.3 \
@ -397,6 +398,7 @@ HTMLPAGES = \
CURLMOPT_SOCKETFUNCTION.html \ CURLMOPT_SOCKETFUNCTION.html \
CURLMOPT_TIMERDATA.html \ CURLMOPT_TIMERDATA.html \
CURLMOPT_TIMERFUNCTION.html \ CURLMOPT_TIMERFUNCTION.html \
CURLOPT_ABSTRACT_UNIX_SOCKET.html \
CURLOPT_ACCEPTTIMEOUT_MS.html \ CURLOPT_ACCEPTTIMEOUT_MS.html \
CURLOPT_ACCEPT_ENCODING.html \ CURLOPT_ACCEPT_ENCODING.html \
CURLOPT_ADDRESS_SCOPE.html \ CURLOPT_ADDRESS_SCOPE.html \
@ -707,6 +709,7 @@ PDFPAGES = \
CURLMOPT_SOCKETFUNCTION.pdf \ CURLMOPT_SOCKETFUNCTION.pdf \
CURLMOPT_TIMERDATA.pdf \ CURLMOPT_TIMERDATA.pdf \
CURLMOPT_TIMERFUNCTION.pdf \ CURLMOPT_TIMERFUNCTION.pdf \
CURLOPT_ABSTRACT_UNIX_SOCKET.pdf \
CURLOPT_ACCEPTTIMEOUT_MS.pdf \ CURLOPT_ACCEPTTIMEOUT_MS.pdf \
CURLOPT_ACCEPT_ENCODING.pdf \ CURLOPT_ACCEPT_ENCODING.pdf \
CURLOPT_ADDRESS_SCOPE.pdf \ CURLOPT_ADDRESS_SCOPE.pdf \

View File

@ -317,6 +317,7 @@ CURLOPTTYPE_LONG 7.1
CURLOPTTYPE_OBJECTPOINT 7.1 CURLOPTTYPE_OBJECTPOINT 7.1
CURLOPTTYPE_OFF_T 7.11.0 CURLOPTTYPE_OFF_T 7.11.0
CURLOPTTYPE_STRINGPOINT 7.46.0 CURLOPTTYPE_STRINGPOINT 7.46.0
CURLOPT_ABSTRACT_UNIX_SOCKET 7.53.0
CURLOPT_ACCEPTTIMEOUT_MS 7.24.0 CURLOPT_ACCEPTTIMEOUT_MS 7.24.0
CURLOPT_ACCEPT_ENCODING 7.21.6 CURLOPT_ACCEPT_ENCODING 7.21.6
CURLOPT_ADDRESS_SCOPE 7.19.0 CURLOPT_ADDRESS_SCOPE 7.19.0

View File

@ -1770,6 +1770,9 @@ typedef enum {
this option is used only if PROXY_SSL_VERIFYPEER is true */ this option is used only if PROXY_SSL_VERIFYPEER is true */
CINIT(PROXY_PINNEDPUBLICKEY, STRINGPOINT, 263), CINIT(PROXY_PINNEDPUBLICKEY, STRINGPOINT, 263),
/* Path to an abstract Unix domain socket */
CINIT(ABSTRACT_UNIX_SOCKET, STRINGPOINT, 264),
CURLOPT_LASTENTRY /* the last unused */ CURLOPT_LASTENTRY /* the last unused */
} CURLoption; } CURLoption;

View File

@ -219,7 +219,8 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist,
/* evaluates to true if option takes a char* argument */ /* evaluates to true if option takes a char* argument */
#define _curl_is_string_option(option) \ #define _curl_is_string_option(option) \
((option) == CURLOPT_ACCEPT_ENCODING || \ ((option) == CURLOPT_ABSTRACT_UNIX_SOCKET || \
(option) == CURLOPT_ACCEPT_ENCODING || \
(option) == CURLOPT_CAINFO || \ (option) == CURLOPT_CAINFO || \
(option) == CURLOPT_CAPATH || \ (option) == CURLOPT_CAPATH || \
(option) == CURLOPT_COOKIE || \ (option) == CURLOPT_COOKIE || \

View File

@ -47,6 +47,8 @@
# define in_addr_t unsigned long # define in_addr_t unsigned long
#endif #endif
#include <stddef.h>
#include "curl_addrinfo.h" #include "curl_addrinfo.h"
#include "inet_pton.h" #include "inet_pton.h"
#include "warnless.h" #include "warnless.h"
@ -483,24 +485,29 @@ Curl_addrinfo *Curl_str2addr(char *address, int port)
* struct initialized with this path. * struct initialized with this path.
* Set '*longpath' to TRUE if the error is a too long 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; Curl_addrinfo *ai;
struct sockaddr_un *sa_un; struct sockaddr_un *sa_un;
size_t path_len; size_t path_len;
*longpath = FALSE;
ai = calloc(1, sizeof(Curl_addrinfo)); ai = calloc(1, sizeof(Curl_addrinfo));
if(!ai) if(!ai)
return NULL; return NULL;
ai->ai_addr = calloc(1, sizeof(struct sockaddr_un)); ai->ai_addr = calloc(1, sizeof(struct sockaddr_un));
if(!ai->ai_addr) { if(!ai->ai_addr) {
free(ai); free(ai);
*longpath = FALSE;
return NULL; 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 */ /* sun_path must be able to store the NUL-terminated path */
path_len = strlen(path); path_len = strlen(path) + 1;
if(path_len >= sizeof(sa_un->sun_path)) { if(path_len > sizeof(sa_un->sun_path)) {
free(ai->ai_addr); free(ai->ai_addr);
free(ai); free(ai);
*longpath = TRUE; *longpath = TRUE;
@ -509,10 +516,14 @@ Curl_addrinfo *Curl_unix2addr(const char *path, int *longpath)
ai->ai_family = AF_UNIX; ai->ai_family = AF_UNIX;
ai->ai_socktype = SOCK_STREAM; /* assume reliable transport for HTTP */ ai->ai_socktype = SOCK_STREAM; /* assume reliable transport for HTTP */
ai->ai_addrlen = (curl_socklen_t) sizeof(struct sockaddr_un); ai->ai_addrlen = offsetof(struct sockaddr_un, sun_path) + path_len;
sa_un = (void *) ai->ai_addr;
sa_un->sun_family = AF_UNIX; /* Abstract Unix domain socket have NULL prefix instead of suffix */
memcpy(sa_un->sun_path, path, path_len + 1); /* copy NUL byte */ 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; return ai;
} }
#endif #endif

View 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); Curl_addrinfo *Curl_str2addr(char *dotted, int port);
#ifdef USE_UNIX_SOCKETS #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 #endif
#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) && \ #if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) && \

View File

@ -2814,6 +2814,12 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option,
#ifdef USE_UNIX_SOCKETS #ifdef USE_UNIX_SOCKETS
case CURLOPT_UNIX_SOCKET_PATH: 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], result = setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH],
va_arg(param, char *)); va_arg(param, char *));
break; break;
@ -3523,6 +3529,8 @@ ConnectionExists(struct Curl_easy *data,
continue; continue;
if(strcmp(needle->unix_domain_socket, check->unix_domain_socket)) if(strcmp(needle->unix_domain_socket, check->unix_domain_socket))
continue; continue;
if(needle->abstract_unix_socket != check->abstract_unix_socket)
continue;
} }
else if(check->unix_domain_socket) else if(check->unix_domain_socket)
continue; continue;
@ -5863,8 +5871,9 @@ static CURLcode resolve_server(struct Curl_easy *data,
if(!hostaddr) if(!hostaddr)
result = CURLE_OUT_OF_MEMORY; result = CURLE_OUT_OF_MEMORY;
else { else {
int longpath=0; bool longpath = FALSE;
hostaddr->addr = Curl_unix2addr(path, &longpath); hostaddr->addr = Curl_unix2addr(path, &longpath,
conn->abstract_unix_socket);
if(hostaddr->addr) if(hostaddr->addr)
hostaddr->inuse++; hostaddr->inuse++;
else { else {
@ -6273,6 +6282,7 @@ static CURLcode create_conn(struct Curl_easy *data,
result = CURLE_OUT_OF_MEMORY; result = CURLE_OUT_OF_MEMORY;
goto out; goto out;
} }
conn->abstract_unix_socket = data->set.abstract_unix_socket;
} }
#endif #endif

View File

@ -1133,6 +1133,7 @@ struct connectdata {
#ifdef USE_UNIX_SOCKETS #ifdef USE_UNIX_SOCKETS
char *unix_domain_socket; char *unix_domain_socket;
bool abstract_unix_socket;
#endif #endif
}; };
@ -1754,6 +1755,8 @@ struct UserDefined {
int stream_weight; int stream_weight;
struct Curl_http2_dep *stream_dependents; struct Curl_http2_dep *stream_dependents;
bool abstract_unix_socket;
}; };
struct Names { struct Names {

View File

@ -230,6 +230,7 @@ struct OperationConfig {
bool nonpn; /* enable/disable TLS NPN extension */ bool nonpn; /* enable/disable TLS NPN extension */
bool noalpn; /* enable/disable TLS ALPN extension */ bool noalpn; /* enable/disable TLS ALPN extension */
char *unix_socket_path; /* path to Unix domain socket */ char *unix_socket_path; /* path to Unix domain socket */
bool abstract_unix_socket; /* path to an abstract Unix domain socket */
bool falsestart; bool falsestart;
bool path_as_is; bool path_as_is;
double expect100timeout; double expect100timeout;

View File

@ -183,6 +183,7 @@ static const struct LongShort aliases[]= {
{"$R", "expect100-timeout", TRUE}, {"$R", "expect100-timeout", TRUE},
{"$S", "tftp-no-options", FALSE}, {"$S", "tftp-no-options", FALSE},
{"$U", "connect-to", TRUE}, {"$U", "connect-to", TRUE},
{"$W", "abstract-unix-socket", TRUE},
{"0", "http1.0", FALSE}, {"0", "http1.0", FALSE},
{"01", "http1.1", FALSE}, {"01", "http1.1", FALSE},
{"02", "http2", FALSE}, {"02", "http2", FALSE},
@ -1024,6 +1025,7 @@ ParameterError getparameter(char *flag, /* f or -long-flag */
#endif #endif
break; break;
case 'M': /* --unix-socket */ case 'M': /* --unix-socket */
config->abstract_unix_socket = FALSE;
GetStr(&config->unix_socket_path, nextarg); GetStr(&config->unix_socket_path, nextarg);
break; break;
case 'N': /* --path-as-is */ case 'N': /* --path-as-is */
@ -1054,6 +1056,10 @@ ParameterError getparameter(char *flag, /* f or -long-flag */
if(err) if(err)
return err; return err;
break; break;
case 'W': /* --abstract-unix-socket */
config->abstract_unix_socket = TRUE;
GetStr(&config->unix_socket_path, nextarg);
break;
} }
break; break;
case '#': /* --progress-bar */ case '#': /* --progress-bar */

View File

@ -271,7 +271,8 @@ static const char *const helptext[] = {
" --tlsuser USER TLS username", " --tlsuser USER TLS username",
" --tlspassword STRING TLS password", " --tlspassword STRING TLS password",
" --tlsauthtype STRING TLS authentication type (default: SRP)", " --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)", " -A, --user-agent STRING Send User-Agent STRING to server (H)",
" -v, --verbose Make the operation more talkative", " -v, --verbose Make the operation more talkative",
" -V, --version Show version number and quit", " -V, --version Show version number and quit",

View File

@ -1393,11 +1393,17 @@ static CURLcode operate_do(struct GlobalConfig *global,
my_setopt(curl, CURLOPT_SSL_ENABLE_ALPN, 0L); my_setopt(curl, CURLOPT_SSL_ENABLE_ALPN, 0L);
} }
/* new in 7.40.0 */ /* new in 7.40.0, abstract support added in 7.53.0 */
if(config->unix_socket_path) if(config->unix_socket_path) {
my_setopt_str(curl, CURLOPT_UNIX_SOCKET_PATH, if(config->abstract_unix_socket) {
config->unix_socket_path); 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 */ /* new in 7.45.0 */
if(config->proto_default) if(config->proto_default)
my_setopt_str(curl, CURLOPT_DEFAULT_PROTOCOL, config->proto_default); my_setopt_str(curl, CURLOPT_DEFAULT_PROTOCOL, config->proto_default);