1
/*-------------------------------------------------------------------------
4
* IPv6-aware network access.
6
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
7
* Portions Copyright (c) 1994, Regents of the University of California
11
* $PostgreSQL: pgsql/src/backend/libpq/ip.c,v 1.31 2004-12-31 21:59:50 pgsql Exp $
13
* This file and the IPV6 implementation were initially provided by
14
* Nigel Kukard <nkukard@lbsd.net>, Linux Based Systems Design
15
* http://www.lbsd.net.
17
*-------------------------------------------------------------------------
20
/* This is intended to be used in both frontend and backend, so use c.h */
23
#ifndef WIN32_CLIENT_ONLY
26
#include <sys/types.h>
28
#include <sys/socket.h>
30
#include <netinet/in.h>
31
#ifdef HAVE_NETINET_TCP_H
32
#include <netinet/tcp.h>
34
#include <arpa/inet.h>
41
static int rangeSockAddrAF_INET(const struct sockaddr_in * addr,
42
const struct sockaddr_in * netaddr,
43
const struct sockaddr_in * netmask);
46
static int rangeSockAddrAF_INET6(const struct sockaddr_in6 * addr,
47
const struct sockaddr_in6 * netaddr,
48
const struct sockaddr_in6 * netmask);
51
#ifdef HAVE_UNIX_SOCKETS
52
static int getaddrinfo_unix(const char *path,
53
const struct addrinfo * hintsp,
54
struct addrinfo ** result);
56
static int getnameinfo_unix(const struct sockaddr_un * sa, int salen,
57
char *node, int nodelen,
58
char *service, int servicelen,
64
* getaddrinfo_all - get address info for Unix, IPv4 and IPv6 sockets
67
getaddrinfo_all(const char *hostname, const char *servname,
68
const struct addrinfo * hintp, struct addrinfo ** result)
70
/* not all versions of getaddrinfo() zero *result on failure */
73
#ifdef HAVE_UNIX_SOCKETS
74
if (hintp->ai_family == AF_UNIX)
75
return getaddrinfo_unix(servname, hintp, result);
78
/* NULL has special meaning to getaddrinfo(). */
79
return getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname,
80
servname, hintp, result);
85
* freeaddrinfo_all - free addrinfo structures for IPv4, IPv6, or Unix
87
* Note: the ai_family field of the original hint structure must be passed
88
* so that we can tell whether the addrinfo struct was built by the system's
89
* getaddrinfo() routine or our own getaddrinfo_unix() routine. Some versions
90
* of getaddrinfo() might be willing to return AF_UNIX addresses, so it's
91
* not safe to look at ai_family in the addrinfo itself.
94
freeaddrinfo_all(int hint_ai_family, struct addrinfo * ai)
96
#ifdef HAVE_UNIX_SOCKETS
97
if (hint_ai_family == AF_UNIX)
99
/* struct was built by getaddrinfo_unix (see getaddrinfo_all) */
102
struct addrinfo *p = ai;
110
#endif /* HAVE_UNIX_SOCKETS */
112
/* struct was built by getaddrinfo() */
120
* getnameinfo_all - get name info for Unix, IPv4 and IPv6 sockets
122
* The API of this routine differs from the standard getnameinfo() definition
123
* in two ways: first, the addr parameter is declared as sockaddr_storage
124
* rather than struct sockaddr, and second, the node and service fields are
125
* guaranteed to be filled with something even on failure return.
128
getnameinfo_all(const struct sockaddr_storage * addr, int salen,
129
char *node, int nodelen,
130
char *service, int servicelen,
135
#ifdef HAVE_UNIX_SOCKETS
136
if (addr && addr->ss_family == AF_UNIX)
137
rc = getnameinfo_unix((const struct sockaddr_un *) addr, salen,
143
rc = getnameinfo((const struct sockaddr *) addr, salen,
151
StrNCpy(node, "???", nodelen);
153
StrNCpy(service, "???", servicelen);
160
#if defined(HAVE_UNIX_SOCKETS)
163
* getaddrinfo_unix - get unix socket info using IPv6-compatible API
165
* Bugs: only one addrinfo is set even though hintsp is NULL or
167
* AI_CANONNAME is not supported.
171
getaddrinfo_unix(const char *path, const struct addrinfo * hintsp,
172
struct addrinfo ** result)
174
struct addrinfo hints;
175
struct addrinfo *aip;
176
struct sockaddr_un *unp;
180
MemSet(&hints, 0, sizeof(hints));
182
if (strlen(path) >= sizeof(unp->sun_path))
187
hints.ai_family = AF_UNIX;
188
hints.ai_socktype = SOCK_STREAM;
191
memcpy(&hints, hintsp, sizeof(hints));
193
if (hints.ai_socktype == 0)
194
hints.ai_socktype = SOCK_STREAM;
196
if (hints.ai_family != AF_UNIX)
198
/* shouldn't have been called */
202
aip = calloc(1, sizeof(struct addrinfo));
206
unp = calloc(1, sizeof(struct sockaddr_un));
213
aip->ai_family = AF_UNIX;
214
aip->ai_socktype = hints.ai_socktype;
215
aip->ai_protocol = hints.ai_protocol;
217
aip->ai_canonname = NULL;
220
unp->sun_family = AF_UNIX;
221
aip->ai_addr = (struct sockaddr *) unp;
222
aip->ai_addrlen = sizeof(struct sockaddr_un);
224
strcpy(unp->sun_path, path);
226
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
227
unp->sun_len = sizeof(struct sockaddr_un);
234
* Convert an address to a hostname.
237
getnameinfo_unix(const struct sockaddr_un * sa, int salen,
238
char *node, int nodelen,
239
char *service, int servicelen,
244
/* Invalid arguments. */
245
if (sa == NULL || sa->sun_family != AF_UNIX ||
246
(node == NULL && service == NULL))
249
/* We don't support those. */
250
if ((node && !(flags & NI_NUMERICHOST))
251
|| (service && !(flags & NI_NUMERICSERV)))
256
ret = snprintf(node, nodelen, "%s", "[local]");
257
if (ret == -1 || ret > nodelen)
263
ret = snprintf(service, servicelen, "%s", sa->sun_path);
264
if (ret == -1 || ret > servicelen)
270
#endif /* HAVE_UNIX_SOCKETS */
274
* rangeSockAddr - is addr within the subnet specified by netaddr/netmask ?
276
* Note: caller must already have verified that all three addresses are
277
* in the same address family; and AF_UNIX addresses are not supported.
280
rangeSockAddr(const struct sockaddr_storage * addr,
281
const struct sockaddr_storage * netaddr,
282
const struct sockaddr_storage * netmask)
284
if (addr->ss_family == AF_INET)
285
return rangeSockAddrAF_INET((struct sockaddr_in *) addr,
286
(struct sockaddr_in *) netaddr,
287
(struct sockaddr_in *) netmask);
289
else if (addr->ss_family == AF_INET6)
290
return rangeSockAddrAF_INET6((struct sockaddr_in6 *) addr,
291
(struct sockaddr_in6 *) netaddr,
292
(struct sockaddr_in6 *) netmask);
299
rangeSockAddrAF_INET(const struct sockaddr_in * addr,
300
const struct sockaddr_in * netaddr,
301
const struct sockaddr_in * netmask)
303
if (((addr->sin_addr.s_addr ^ netaddr->sin_addr.s_addr) &
304
netmask->sin_addr.s_addr) == 0)
313
rangeSockAddrAF_INET6(const struct sockaddr_in6 * addr,
314
const struct sockaddr_in6 * netaddr,
315
const struct sockaddr_in6 * netmask)
319
for (i = 0; i < 16; i++)
321
if (((addr->sin6_addr.s6_addr[i] ^ netaddr->sin6_addr.s6_addr[i]) &
322
netmask->sin6_addr.s6_addr[i]) != 0)
331
* SockAddr_cidr_mask - make a network mask of the appropriate family
332
* and required number of significant bits
334
* The resulting mask is placed in *mask, which had better be big enough.
336
* Return value is 0 if okay, -1 if not.
339
SockAddr_cidr_mask(struct sockaddr_storage * mask, char *numbits, int family)
344
bits = strtol(numbits, &endptr, 10);
346
if (*numbits == '\0' || *endptr != '\0')
353
struct sockaddr_in mask4;
356
if (bits < 0 || bits > 32)
358
/* avoid "x << 32", which is not portable */
360
maskl = (0xffffffffUL << (32 - (int) bits))
364
mask4.sin_addr.s_addr = htonl(maskl);
365
memcpy(mask, &mask4, sizeof(mask4));
372
struct sockaddr_in6 mask6;
375
if (bits < 0 || bits > 128)
377
for (i = 0; i < 16; i++)
380
mask6.sin6_addr.s6_addr[i] = 0;
382
mask6.sin6_addr.s6_addr[i] = 0xff;
385
mask6.sin6_addr.s6_addr[i] =
386
(0xff << (8 - (int) bits)) & 0xff;
390
memcpy(mask, &mask6, sizeof(mask6));
398
mask->ss_family = family;
406
* promote_v4_to_v6_addr --- convert an AF_INET addr to AF_INET6, using
407
* the standard convention for IPv4 addresses mapped into IPv6 world
409
* The passed addr is modified in place; be sure it is large enough to
410
* hold the result! Note that we only worry about setting the fields
411
* that rangeSockAddr will look at.
414
promote_v4_to_v6_addr(struct sockaddr_storage * addr)
416
struct sockaddr_in addr4;
417
struct sockaddr_in6 addr6;
420
memcpy(&addr4, addr, sizeof(addr4));
421
ip4addr = ntohl(addr4.sin_addr.s_addr);
423
memset(&addr6, 0, sizeof(addr6));
425
addr6.sin6_family = AF_INET6;
427
addr6.sin6_addr.s6_addr[10] = 0xff;
428
addr6.sin6_addr.s6_addr[11] = 0xff;
429
addr6.sin6_addr.s6_addr[12] = (ip4addr >> 24) & 0xFF;
430
addr6.sin6_addr.s6_addr[13] = (ip4addr >> 16) & 0xFF;
431
addr6.sin6_addr.s6_addr[14] = (ip4addr >> 8) & 0xFF;
432
addr6.sin6_addr.s6_addr[15] = (ip4addr) & 0xFF;
434
memcpy(addr, &addr6, sizeof(addr6));
438
* promote_v4_to_v6_mask --- convert an AF_INET netmask to AF_INET6, using
439
* the standard convention for IPv4 addresses mapped into IPv6 world
441
* This must be different from promote_v4_to_v6_addr because we want to
442
* set the high-order bits to 1's not 0's.
444
* The passed addr is modified in place; be sure it is large enough to
445
* hold the result! Note that we only worry about setting the fields
446
* that rangeSockAddr will look at.
449
promote_v4_to_v6_mask(struct sockaddr_storage * addr)
451
struct sockaddr_in addr4;
452
struct sockaddr_in6 addr6;
456
memcpy(&addr4, addr, sizeof(addr4));
457
ip4addr = ntohl(addr4.sin_addr.s_addr);
459
memset(&addr6, 0, sizeof(addr6));
461
addr6.sin6_family = AF_INET6;
463
for (i = 0; i < 12; i++)
464
addr6.sin6_addr.s6_addr[i] = 0xff;
466
addr6.sin6_addr.s6_addr[12] = (ip4addr >> 24) & 0xFF;
467
addr6.sin6_addr.s6_addr[13] = (ip4addr >> 16) & 0xFF;
468
addr6.sin6_addr.s6_addr[14] = (ip4addr >> 8) & 0xFF;
469
addr6.sin6_addr.s6_addr[15] = (ip4addr) & 0xFF;
471
memcpy(addr, &addr6, sizeof(addr6));
474
#endif /* HAVE_IPV6 */