1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

Add support for abstract Unix-domain sockets

This is a variant of the normal Unix-domain sockets that don't use the
file system but a separate "abstract" namespace.  At the user
interface, such sockets are represented by names starting with "@".
Supported on Linux and Windows right now.

Reviewed-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://www.postgresql.org/message-id/flat/6dee8574-b0ad-fc49-9c8c-2edc796f0033@2ndquadrant.com
This commit is contained in:
Peter Eisentraut
2020-11-25 08:14:23 +01:00
parent a7e65dc88b
commit c9f0624bc2
8 changed files with 76 additions and 16 deletions

View File

@ -611,6 +611,10 @@ StreamServerPort(int family, const char *hostName, unsigned short portNumber,
static int
Lock_AF_UNIX(const char *unixSocketDir, const char *unixSocketPath)
{
/* no lock file for abstract sockets */
if (unixSocketPath[0] == '@')
return STATUS_OK;
/*
* Grab an interlock file associated with the socket file.
*
@ -642,6 +646,10 @@ Lock_AF_UNIX(const char *unixSocketDir, const char *unixSocketPath)
static int
Setup_AF_UNIX(const char *sock_path)
{
/* no file system permissions for abstract sockets */
if (sock_path[0] == '@')
return STATUS_OK;
/*
* Fix socket ownership/permission if requested. Note we must do this
* before we listen() to avoid a window where unwanted connections could

View File

@ -37,6 +37,7 @@
#include "input.h"
#include "large_obj.h"
#include "libpq-fe.h"
#include "libpq/pqcomm.h"
#include "mainloop.h"
#include "portability/instr_time.h"
#include "pqexpbuffer.h"
@ -604,12 +605,9 @@ exec_command_conninfo(PsqlScanState scan_state, bool active_branch)
char *host = PQhost(pset.db);
char *hostaddr = PQhostaddr(pset.db);
/*
* If the host is an absolute path, the connection is via socket
* unless overridden by hostaddr
*/
if (is_absolute_path(host))
if (is_unixsock_path(host))
{
/* hostaddr overrides host */
if (hostaddr && *hostaddr)
printf(_("You are connected to database \"%s\" as user \"%s\" on address \"%s\" at port \"%s\".\n"),
db, PQuser(pset.db), hostaddr, PQport(pset.db));
@ -3407,12 +3405,9 @@ do_connect(enum trivalue reuse_previous_specification,
char *host = PQhost(pset.db);
char *hostaddr = PQhostaddr(pset.db);
/*
* If the host is an absolute path, the connection is via socket
* unless overridden by hostaddr
*/
if (is_absolute_path(host))
if (is_unixsock_path(host))
{
/* hostaddr overrides host */
if (hostaddr && *hostaddr)
printf(_("You are now connected to database \"%s\" as user \"%s\" on address \"%s\" at port \"%s\".\n"),
PQdb(pset.db), PQuser(pset.db), hostaddr, PQport(pset.db));

View File

@ -15,6 +15,7 @@
#include "common.h"
#include "common/string.h"
#include "input.h"
#include "libpq/pqcomm.h"
#include "prompt.h"
#include "settings.h"
@ -136,7 +137,7 @@ get_prompt(promptStatus_t status, ConditionalStack cstack)
const char *host = PQhost(pset.db);
/* INET socket */
if (host && host[0] && !is_absolute_path(host))
if (host && host[0] && !is_unixsock_path(host))
{
strlcpy(buf, host, sizeof(buf));
if (*p == 'm')

View File

@ -217,6 +217,21 @@ getaddrinfo_unix(const char *path, const struct addrinfo *hintsp,
strcpy(unp->sun_path, path);
/*
* If the supplied path starts with @, replace that with a zero byte for
* the internal representation. In that mode, the entire sun_path is the
* address, including trailing zero bytes. But we set the address length
* to only include the length of the original string. That way the
* trailing zero bytes won't show up in any network or socket lists of the
* operating system. This is just a convention, also followed by other
* packages.
*/
if (path[0] == '@')
{
unp->sun_path[0] = '\0';
aip->ai_addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(path);
}
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
unp->sun_len = sizeof(struct sockaddr_un);
#endif
@ -249,7 +264,14 @@ getnameinfo_unix(const struct sockaddr_un *sa, int salen,
if (service)
{
ret = snprintf(service, servicelen, "%s", sa->sun_path);
/*
* Check whether it looks like an abstract socket, but it could also
* just be an empty string.
*/
if (sa->sun_path[0] == '\0' && sa->sun_path[1] != '\0')
ret = snprintf(service, servicelen, "@%s", sa->sun_path + 1);
else
ret = snprintf(service, servicelen, "%s", sa->sun_path);
if (ret < 0 || ret >= servicelen)
return EAI_MEMORY;
}

View File

@ -85,6 +85,15 @@ typedef struct
*/
#define UNIXSOCK_PATH_BUFLEN sizeof(((struct sockaddr_un *) NULL)->sun_path)
/*
* A host that looks either like an absolute path or starts with @ is
* interpreted as a Unix-domain socket address.
*/
static inline bool
is_unixsock_path(const char *path)
{
return is_absolute_path(path) || path[0] == '@';
}
/*
* These manipulate the frontend/backend protocol version number.

View File

@ -1093,7 +1093,7 @@ connectOptions2(PGconn *conn)
{
ch->type = CHT_HOST_NAME;
#ifdef HAVE_UNIX_SOCKETS
if (is_absolute_path(ch->host))
if (is_unixsock_path(ch->host))
ch->type = CHT_UNIX_SOCKET;
#endif
}
@ -6945,7 +6945,7 @@ passwordFromFile(const char *hostname, const char *port, const char *dbname,
/* 'localhost' matches pghost of '' or the default socket directory */
if (hostname == NULL || hostname[0] == '\0')
hostname = DefaultHost;
else if (is_absolute_path(hostname))
else if (is_unixsock_path(hostname))
/*
* We should probably use canonicalize_path(), but then we have to