summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhrs <hrs@FreeBSD.org>2015-09-20 01:09:23 +0000
committerhrs <hrs@FreeBSD.org>2015-09-20 01:09:23 +0000
commita3fcca6713520dc0bf112298215886bcceed5a0f (patch)
tree77e76ada766a17a7c962eca30f68e4bcd6ba0307
parent92177854740b4059d4a698eddb8a7cc0f09188d5 (diff)
downloadFreeBSD-src-a3fcca6713520dc0bf112298215886bcceed5a0f.zip
FreeBSD-src-a3fcca6713520dc0bf112298215886bcceed5a0f.tar.gz
Add PF_LOCAL support in getaddrinfo(3) and getnameinfo(3):
- In a PF_LOCAL address, "hostname" must begins with '/' and "servname" is always NULL. All of ai_flags are ignored. - PF_UNSPEC matches PF_LOCAL. EAI_SERVICE is not returned to make AF-independent programming easier; "servname" is always ignored in PF_LOCAL. In practice, PF_INET* and PF_LOCAL are mutually-exclusive because a hostname which begins with '/' is invalid in PF_INET*. No domain name resolution is performed for a PF_LOCAL address. Differential Revision: https://reviews.freebsd.org/D3634
-rw-r--r--lib/libc/net/getaddrinfo.320
-rw-r--r--lib/libc/net/getaddrinfo.c92
-rw-r--r--lib/libc/net/getnameinfo.323
-rw-r--r--lib/libc/net/getnameinfo.c148
4 files changed, 205 insertions, 78 deletions
diff --git a/lib/libc/net/getaddrinfo.3 b/lib/libc/net/getaddrinfo.3
index 570fc2e..e13c667 100644
--- a/lib/libc/net/getaddrinfo.3
+++ b/lib/libc/net/getaddrinfo.3
@@ -18,7 +18,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd February 14, 2013
+.Dd September 20, 2015
.Dt GETADDRINFO 3
.Os
.Sh NAME
@@ -40,7 +40,6 @@
The
.Fn getaddrinfo
function is used to get a list of
-.Tn IP
addresses and port numbers for host
.Fa hostname
and service
@@ -59,7 +58,9 @@ arguments are either pointers to NUL-terminated strings or the null pointer.
An acceptable value for
.Fa hostname
is either a valid host name or a numeric host address string consisting
-of a dotted decimal IPv4 address or an IPv6 address.
+of a dotted decimal IPv4 address,
+an IPv6 address,
+or a UNIX-domain address.
The
.Fa servname
is either a decimal port number or a service name listed in
@@ -105,6 +106,7 @@ operating system.
Denotes the type of socket that is wanted:
.Dv SOCK_STREAM ,
.Dv SOCK_DGRAM ,
+.Dv SOCK_SEQPACKET ,
or
.Dv SOCK_RAW .
When
@@ -112,9 +114,11 @@ When
is zero the caller will accept any socket type.
.It Fa ai_protocol
Indicates which transport protocol is desired,
-.Dv IPPROTO_UDP
+.Dv IPPROTO_UDP ,
+.Dv IPPROTO_TCP ,
+.Dv IPPROTO_SCTP ,
or
-.Dv IPPROTO_TCP .
+.Dv IPPROTO_UDPLITE .
If
.Fa ai_protocol
is zero the caller will accept any protocol.
@@ -131,6 +135,9 @@ or be the bitwise-inclusive OR of one or more of the values
.Dv AI_NUMERICSERV
and
.Dv AI_PASSIVE .
+For a UNIX-domain address,
+.Fa ai_flags
+is ignored.
.Bl -tag -width "AI_CANONNAMEXX"
.It Dv AI_ADDRCONFIG
If the
@@ -419,6 +426,9 @@ freeaddrinfo(res0);
.Xr getnameinfo 3 ,
.Xr getservbyname 3 ,
.Xr resolver 3 ,
+.Xr inet 4 ,
+.Xr inet6 4 ,
+.Xr unix 4 ,
.Xr hosts 5 ,
.Xr resolv.conf 5 ,
.Xr services 5 ,
diff --git a/lib/libc/net/getaddrinfo.c b/lib/libc/net/getaddrinfo.c
index 17c9b65..8b47aef 100644
--- a/lib/libc/net/getaddrinfo.c
+++ b/lib/libc/net/getaddrinfo.c
@@ -137,13 +137,20 @@ static const struct afd {
offsetof(struct sockaddr_in6, sin6_addr),
in6_addrany, in6_loopback, 1},
#define N_INET 1
+#define N_LOCAL 2
#else
#define N_INET 0
+#define N_LOCAL 1
#endif
{PF_INET, sizeof(struct in_addr),
sizeof(struct sockaddr_in),
offsetof(struct sockaddr_in, sin_addr),
in_addrany, in_loopback, 0},
+#define sizeofmember(type, member) (sizeof(((type *)0)->member))
+ {PF_LOCAL, sizeofmember(struct sockaddr_un, sun_path),
+ sizeof(struct sockaddr_un),
+ offsetof(struct sockaddr_un, sun_path),
+ NULL, NULL, 0},
{0, 0, 0, 0, NULL, NULL, 0},
};
@@ -152,29 +159,47 @@ struct explore {
int e_socktype;
int e_protocol;
int e_wild;
-#define WILD_AF(ex) ((ex)->e_wild & 0x01)
-#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
-#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
+#define AF_ANY 0x01
+#define SOCKTYPE_ANY 0x02
+#define PROTOCOL_ANY 0x04
+#define WILD_AF(ex) ((ex)->e_wild & AF_ANY)
+#define WILD_SOCKTYPE(ex) ((ex)->e_wild & SOCKTYPE_ANY)
+#define WILD_PROTOCOL(ex) ((ex)->e_wild & PROTOCOL_ANY)
};
static const struct explore explore[] = {
-#if 0
- { PF_LOCAL, ANY, ANY, 0x01 },
-#endif
+ { PF_LOCAL, SOCK_DGRAM, ANY,
+ AF_ANY | PROTOCOL_ANY },
+ { PF_LOCAL, SOCK_STREAM, ANY,
+ AF_ANY | PROTOCOL_ANY },
+ { PF_LOCAL, SOCK_SEQPACKET, ANY,
+ AF_ANY | PROTOCOL_ANY },
#ifdef INET6
- { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, 0x07 },
- { PF_INET6, SOCK_STREAM, IPPROTO_TCP, 0x07 },
- { PF_INET6, SOCK_STREAM, IPPROTO_SCTP, 0x03 },
- { PF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP, 0x07 },
- { PF_INET6, SOCK_DGRAM, IPPROTO_UDPLITE, 0x03 },
- { PF_INET6, SOCK_RAW, ANY, 0x05 },
+ { PF_INET6, SOCK_DGRAM, IPPROTO_UDP,
+ AF_ANY | SOCKTYPE_ANY | PROTOCOL_ANY },
+ { PF_INET6, SOCK_STREAM, IPPROTO_TCP,
+ AF_ANY | SOCKTYPE_ANY | PROTOCOL_ANY },
+ { PF_INET6, SOCK_STREAM, IPPROTO_SCTP,
+ AF_ANY | SOCKTYPE_ANY },
+ { PF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP,
+ AF_ANY | SOCKTYPE_ANY | PROTOCOL_ANY },
+ { PF_INET6, SOCK_DGRAM, IPPROTO_UDPLITE,
+ AF_ANY | SOCKTYPE_ANY },
+ { PF_INET6, SOCK_RAW, ANY,
+ AF_ANY | PROTOCOL_ANY },
#endif
- { PF_INET, SOCK_DGRAM, IPPROTO_UDP, 0x07 },
- { PF_INET, SOCK_STREAM, IPPROTO_TCP, 0x07 },
- { PF_INET, SOCK_STREAM, IPPROTO_SCTP, 0x03 },
- { PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP, 0x07 },
- { PF_INET, SOCK_DGRAM, IPPROTO_UDPLITE, 0x03 },
- { PF_INET, SOCK_RAW, ANY, 0x05 },
+ { PF_INET, SOCK_DGRAM, IPPROTO_UDP,
+ AF_ANY | SOCKTYPE_ANY | PROTOCOL_ANY },
+ { PF_INET, SOCK_STREAM, IPPROTO_TCP,
+ AF_ANY | SOCKTYPE_ANY | PROTOCOL_ANY },
+ { PF_INET, SOCK_STREAM, IPPROTO_SCTP,
+ AF_ANY | SOCKTYPE_ANY },
+ { PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP,
+ AF_ANY | SOCKTYPE_ANY | PROTOCOL_ANY },
+ { PF_INET, SOCK_DGRAM, IPPROTO_UDPLITE,
+ AF_ANY | SOCKTYPE_ANY },
+ { PF_INET, SOCK_RAW, ANY,
+ AF_ANY | PROTOCOL_ANY },
{ -1, 0, 0, 0 },
};
@@ -408,6 +433,7 @@ getaddrinfo(const char *hostname, const char *servname,
ERR(EAI_BADFLAGS);
switch (hints->ai_family) {
case PF_UNSPEC:
+ case PF_LOCAL:
case PF_INET:
#ifdef INET6
case PF_INET6:
@@ -1130,6 +1156,9 @@ explore_null(const struct addrinfo *pai, const char *servname,
*res = NULL;
ai = NULL;
+ if (pai->ai_family == PF_LOCAL)
+ return (0);
+
/*
* filter out AFs that are not supported by the kernel
* XXX errno?
@@ -1172,8 +1201,11 @@ explore_numeric(const struct addrinfo *pai, const char *hostname,
const struct afd *afd;
struct addrinfo *ai;
int error;
- char pton[PTON_MAX];
+ char pton[PTON_MAX], path[PATH_MAX], *p;
+#ifdef CTASSERT
+ CTASSERT(sizeofmember(struct sockaddr_un, sun_path) <= PATH_MAX);
+#endif
*res = NULL;
ai = NULL;
@@ -1182,6 +1214,15 @@ explore_numeric(const struct addrinfo *pai, const char *hostname,
return 0;
switch (afd->a_af) {
+ case AF_LOCAL:
+ if (hostname[0] != '/')
+ ERR(EAI_NONAME);
+ if (strlen(hostname) > afd->a_addrlen)
+ ERR(EAI_MEMORY);
+ /* NUL-termination does not need to be guaranteed. */
+ strncpy(path, hostname, afd->a_addrlen);
+ p = &path[0];
+ break;
case AF_INET:
/*
* RFC3493 requires getaddrinfo() to accept AF_INET formats
@@ -1192,15 +1233,17 @@ explore_numeric(const struct addrinfo *pai, const char *hostname,
*/
if (inet_aton(hostname, (struct in_addr *)pton) != 1)
return 0;
+ p = pton;
break;
default:
if (inet_pton(afd->a_af, hostname, pton) != 1)
return 0;
+ p = pton;
break;
}
if (pai->ai_family == afd->a_af) {
- GET_AI(ai, afd, pton);
+ GET_AI(ai, afd, p);
GET_PORT(ai, servname);
if ((pai->ai_flags & AI_CANONNAME)) {
/*
@@ -1320,6 +1363,12 @@ get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr)
memset(ai->ai_addr, 0, (size_t)afd->a_socklen);
ai->ai_addr->sa_len = afd->a_socklen;
ai->ai_addrlen = afd->a_socklen;
+ if (ai->ai_family == PF_LOCAL) {
+ size_t n = strnlen(addr, afd->a_addrlen);
+
+ ai->ai_addrlen -= afd->a_addrlen - n;
+ ai->ai_addr->sa_len -= afd->a_addrlen - n;
+ }
ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
p = (char *)(void *)(ai->ai_addr);
memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
@@ -1378,6 +1427,9 @@ get_port(struct addrinfo *ai, const char *servname, int matchonly)
if (servname == NULL)
return 0;
switch (ai->ai_family) {
+ case AF_LOCAL:
+ /* AF_LOCAL ignores servname silently. */
+ return (0);
case AF_INET:
#ifdef AF_INET6
case AF_INET6:
diff --git a/lib/libc/net/getnameinfo.3 b/lib/libc/net/getnameinfo.3
index 0549ccd..ff227fd 100644
--- a/lib/libc/net/getnameinfo.3
+++ b/lib/libc/net/getnameinfo.3
@@ -18,7 +18,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd February 14, 2013
+.Dd September 20, 2015
.Dt GETNAMEINFO 3
.Os
.Sh NAME
@@ -47,7 +47,7 @@ functions and is the converse of the
.Xr getaddrinfo 3
function.
.Pp
-If a link-layer address is passed to
+If a link-layer address or UNIX-domain address is passed to
.Fn getnameinfo ,
its ASCII representation will be stored in
.Fa host .
@@ -56,7 +56,8 @@ The string pointed to by
will be set to the empty string if non-NULL;
.Fa flags
will always be ignored.
-This is intended as a replacement for the legacy
+For a link-layer address,
+this can be used as a replacement of the legacy
.Xr link_ntoa 3
function.
.Pp
@@ -66,10 +67,17 @@ structure
.Fa sa
should point to either a
.Li sockaddr_in ,
-.Li sockaddr_in6
+.Li sockaddr_in6 ,
+.Li sockaddr_dl ,
or
-.Li sockaddr_dl
-structure (for IPv4, IPv6 or link-layer respectively) that is
+.Li sockaddr_un
+structure
+.Po for IPv4 ,
+IPv6,
+link-layer,
+or UNIX-domain respectively
+.Pc
+that is
.Fa salen
bytes long.
.Pp
@@ -182,6 +190,9 @@ printf("host=%s\en", hbuf);
.Xr inet_ntop 3 ,
.Xr link_ntoa 3 ,
.Xr resolver 3 ,
+.Xr inet 4 ,
+.Xr inet6 4 ,
+.Xr unix 4 ,
.Xr hosts 5 ,
.Xr resolv.conf 5 ,
.Xr services 5 ,
diff --git a/lib/libc/net/getnameinfo.c b/lib/libc/net/getnameinfo.c
index d7e7971..c813189 100644
--- a/lib/libc/net/getnameinfo.c
+++ b/lib/libc/net/getnameinfo.c
@@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
@@ -62,67 +63,102 @@ __FBSDID("$FreeBSD$");
#include <stddef.h>
#include <errno.h>
-static int getnameinfo_inet(const struct sockaddr *, socklen_t, char *,
+static const struct afd *find_afd(int);
+static int getnameinfo_inet(const struct afd *,
+ const struct sockaddr *, socklen_t, char *,
size_t, char *, size_t, int);
#ifdef INET6
static int ip6_parsenumeric(const struct sockaddr *, const char *, char *,
size_t, int);
static int ip6_sa2str(const struct sockaddr_in6 *, char *, size_t, int);
#endif
-static int getnameinfo_link(const struct sockaddr *, socklen_t, char *,
+static int getnameinfo_link(const struct afd *,
+ const struct sockaddr *, socklen_t, char *,
+ size_t, char *, size_t, int);
+static int hexname(const u_int8_t *, size_t, char *, size_t);
+static int getnameinfo_un(const struct afd *,
+ const struct sockaddr *, socklen_t, char *,
size_t, char *, size_t, int);
-static int hexname(const u_int8_t *, size_t, char *, size_t);
-
-int
-getnameinfo(const struct sockaddr *sa, socklen_t salen,
- char *host, size_t hostlen, char *serv, size_t servlen,
- int flags)
-{
- if (sa == NULL)
- return (EAI_FAIL);
-
- switch (sa->sa_family) {
- case AF_INET:
-#ifdef INET6
- case AF_INET6:
-#endif
- return getnameinfo_inet(sa, salen, host, hostlen, serv,
- servlen, flags);
- case AF_LINK:
- return getnameinfo_link(sa, salen, host, hostlen, serv,
- servlen, flags);
- default:
- return EAI_FAMILY;
- }
-}
static const struct afd {
int a_af;
size_t a_addrlen;
socklen_t a_socklen;
int a_off;
+ int (*a_func)(const struct afd *,
+ const struct sockaddr *, socklen_t, char *,
+ size_t, char *, size_t, int);
} afdl [] = {
#ifdef INET6
{PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
- offsetof(struct sockaddr_in6, sin6_addr)},
+ offsetof(struct sockaddr_in6, sin6_addr),
+ getnameinfo_inet},
#endif
{PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
- offsetof(struct sockaddr_in, sin_addr)},
+ offsetof(struct sockaddr_in, sin_addr),
+ getnameinfo_inet},
+#define sizeofmember(type, member) (sizeof(((type *)0)->member))
+ {PF_LOCAL, sizeofmember(struct sockaddr_un, sun_path),
+ sizeof(struct sockaddr_un),
+ offsetof(struct sockaddr_un, sun_path),
+ getnameinfo_un},
+ {PF_LINK, sizeofmember(struct sockaddr_dl, sdl_data),
+ sizeof(struct sockaddr_dl),
+ offsetof(struct sockaddr_dl, sdl_data),
+ getnameinfo_link},
{0, 0, 0},
};
-struct sockinet {
- u_char si_len;
- u_char si_family;
- u_short si_port;
-};
+int
+getnameinfo(const struct sockaddr *sa, socklen_t salen,
+ char *host, size_t hostlen, char *serv, size_t servlen,
+ int flags)
+{
+ const struct afd *afd;
+
+ if (sa == NULL)
+ return (EAI_FAIL);
+
+ afd = find_afd(sa->sa_family);
+ if (afd == NULL)
+ return (EAI_FAMILY);
+ if (sa->sa_family == PF_LOCAL) {
+ /*
+ * PF_LOCAL uses variable sa->sa_len depending on the
+ * content length of sun_path. Require 1 byte in
+ * sun_path at least.
+ */
+ if (salen > afd->a_socklen ||
+ salen <= afd->a_socklen -
+ sizeofmember(struct sockaddr_un, sun_path))
+ return (EAI_FAIL);
+ } else if (salen != afd->a_socklen)
+ return (EAI_FAIL);
+
+ return ((*afd->a_func)(afd, sa, salen, host, hostlen,
+ serv, servlen, flags));
+}
+
+static const struct afd *
+find_afd(int af)
+{
+ const struct afd *afd;
+
+ if (af == PF_UNSPEC)
+ return (NULL);
+ for (afd = &afdl[0]; afd->a_af > 0; afd++) {
+ if (afd->a_af == af)
+ return (afd);
+ }
+ return (NULL);
+}
static int
-getnameinfo_inet(const struct sockaddr *sa, socklen_t salen,
+getnameinfo_inet(const struct afd *afd,
+ const struct sockaddr *sa, socklen_t salen,
char *host, size_t hostlen, char *serv, size_t servlen,
int flags)
{
- const struct afd *afd;
struct servent *sp;
struct hostent *hp;
u_short port;
@@ -132,18 +168,8 @@ getnameinfo_inet(const struct sockaddr *sa, socklen_t salen,
char numserv[512];
char numaddr[512];
- for (afd = &afdl[0]; afd->a_af > 0; afd++) {
- if (afd->a_af == sa->sa_family)
- break;
- }
- if (afd->a_af == 0)
- return (EAI_FAMILY);
-
- if (salen != afd->a_socklen)
- return EAI_FAIL;
-
/* network byte order */
- port = ((const struct sockinet *)sa)->si_port;
+ port = ((const struct sockaddr_in *)sa)->sin_port;
addr = (const char *)sa + afd->a_off;
if (serv == NULL || servlen == 0) {
@@ -377,7 +403,8 @@ ip6_sa2str(const struct sockaddr_in6 *sa6, char *buf, size_t bufsiz, int flags)
*/
/* ARGSUSED */
static int
-getnameinfo_link(const struct sockaddr *sa, socklen_t salen,
+getnameinfo_link(const struct afd *afd,
+ const struct sockaddr *sa, socklen_t salen,
char *host, size_t hostlen, char *serv, size_t servlen, int flags)
{
const struct sockaddr_dl *sdl =
@@ -465,3 +492,30 @@ hexname(const u_int8_t *cp, size_t len, char *host, size_t hostlen)
}
return 0;
}
+
+/*
+ * getnameinfo_un():
+ * Format a UNIX IPC domain address (pathname).
+ */
+/* ARGSUSED */
+static int
+getnameinfo_un(const struct afd *afd,
+ const struct sockaddr *sa, socklen_t salen,
+ char *host, size_t hostlen, char *serv, size_t servlen, int flags)
+{
+ size_t pathlen;
+
+ if (serv != NULL && servlen > 0)
+ *serv = '\0';
+ if (host != NULL && hostlen > 0) {
+ pathlen = sa->sa_len - afd->a_off;
+
+ if (pathlen + 1 > hostlen) {
+ *host = '\0';
+ return (EAI_MEMORY);
+ }
+ strlcpy(host, (const char *)sa + afd->a_off, pathlen + 1);
+ }
+
+ return (0);
+}
OpenPOWER on IntegriCloud