~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to src/backend/libpq/ip.c

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * ip.c
 
4
 *        IPv6-aware network access.
 
5
 *
 
6
 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
 
7
 * Portions Copyright (c) 1994, Regents of the University of California
 
8
 *
 
9
 *
 
10
 * IDENTIFICATION
 
11
 *        $PostgreSQL: pgsql/src/backend/libpq/ip.c,v 1.31 2004-12-31 21:59:50 pgsql Exp $
 
12
 *
 
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.
 
16
 *
 
17
 *-------------------------------------------------------------------------
 
18
 */
 
19
 
 
20
/* This is intended to be used in both frontend and backend, so use c.h */
 
21
#include "c.h"
 
22
 
 
23
#ifndef WIN32_CLIENT_ONLY
 
24
#include <errno.h>
 
25
#include <unistd.h>
 
26
#include <sys/types.h>
 
27
#include <sys/stat.h>
 
28
#include <sys/socket.h>
 
29
#include <netdb.h>
 
30
#include <netinet/in.h>
 
31
#ifdef HAVE_NETINET_TCP_H
 
32
#include <netinet/tcp.h>
 
33
#endif
 
34
#include <arpa/inet.h>
 
35
#include <sys/file.h>
 
36
#endif
 
37
 
 
38
#include "libpq/ip.h"
 
39
 
 
40
 
 
41
static int rangeSockAddrAF_INET(const struct sockaddr_in * addr,
 
42
                                         const struct sockaddr_in * netaddr,
 
43
                                         const struct sockaddr_in * netmask);
 
44
 
 
45
#ifdef HAVE_IPV6
 
46
static int rangeSockAddrAF_INET6(const struct sockaddr_in6 * addr,
 
47
                                          const struct sockaddr_in6 * netaddr,
 
48
                                          const struct sockaddr_in6 * netmask);
 
49
#endif
 
50
 
 
51
#ifdef  HAVE_UNIX_SOCKETS
 
52
static int getaddrinfo_unix(const char *path,
 
53
                                 const struct addrinfo * hintsp,
 
54
                                 struct addrinfo ** result);
 
55
 
 
56
static int getnameinfo_unix(const struct sockaddr_un * sa, int salen,
 
57
                                 char *node, int nodelen,
 
58
                                 char *service, int servicelen,
 
59
                                 int flags);
 
60
#endif
 
61
 
 
62
 
 
63
/*
 
64
 *      getaddrinfo_all - get address info for Unix, IPv4 and IPv6 sockets
 
65
 */
 
66
int
 
67
getaddrinfo_all(const char *hostname, const char *servname,
 
68
                                const struct addrinfo * hintp, struct addrinfo ** result)
 
69
{
 
70
        /* not all versions of getaddrinfo() zero *result on failure */
 
71
        *result = NULL;
 
72
 
 
73
#ifdef HAVE_UNIX_SOCKETS
 
74
        if (hintp->ai_family == AF_UNIX)
 
75
                return getaddrinfo_unix(servname, hintp, result);
 
76
#endif
 
77
 
 
78
        /* NULL has special meaning to getaddrinfo(). */
 
79
        return getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname,
 
80
                                           servname, hintp, result);
 
81
}
 
82
 
 
83
 
 
84
/*
 
85
 *      freeaddrinfo_all - free addrinfo structures for IPv4, IPv6, or Unix
 
86
 *
 
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.
 
92
 */
 
93
void
 
94
freeaddrinfo_all(int hint_ai_family, struct addrinfo * ai)
 
95
{
 
96
#ifdef HAVE_UNIX_SOCKETS
 
97
        if (hint_ai_family == AF_UNIX)
 
98
        {
 
99
                /* struct was built by getaddrinfo_unix (see getaddrinfo_all) */
 
100
                while (ai != NULL)
 
101
                {
 
102
                        struct addrinfo *p = ai;
 
103
 
 
104
                        ai = ai->ai_next;
 
105
                        free(p->ai_addr);
 
106
                        free(p);
 
107
                }
 
108
        }
 
109
        else
 
110
#endif   /* HAVE_UNIX_SOCKETS */
 
111
        {
 
112
                /* struct was built by getaddrinfo() */
 
113
                if (ai != NULL)
 
114
                        freeaddrinfo(ai);
 
115
        }
 
116
}
 
117
 
 
118
 
 
119
/*
 
120
 *      getnameinfo_all - get name info for Unix, IPv4 and IPv6 sockets
 
121
 *
 
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.
 
126
 */
 
127
int
 
128
getnameinfo_all(const struct sockaddr_storage * addr, int salen,
 
129
                                char *node, int nodelen,
 
130
                                char *service, int servicelen,
 
131
                                int flags)
 
132
{
 
133
        int                     rc;
 
134
 
 
135
#ifdef HAVE_UNIX_SOCKETS
 
136
        if (addr && addr->ss_family == AF_UNIX)
 
137
                rc = getnameinfo_unix((const struct sockaddr_un *) addr, salen,
 
138
                                                          node, nodelen,
 
139
                                                          service, servicelen,
 
140
                                                          flags);
 
141
        else
 
142
#endif
 
143
                rc = getnameinfo((const struct sockaddr *) addr, salen,
 
144
                                                 node, nodelen,
 
145
                                                 service, servicelen,
 
146
                                                 flags);
 
147
 
 
148
        if (rc != 0)
 
149
        {
 
150
                if (node)
 
151
                        StrNCpy(node, "???", nodelen);
 
152
                if (service)
 
153
                        StrNCpy(service, "???", servicelen);
 
154
        }
 
155
 
 
156
        return rc;
 
157
}
 
158
 
 
159
 
 
160
#if defined(HAVE_UNIX_SOCKETS)
 
161
 
 
162
/* -------
 
163
 *      getaddrinfo_unix - get unix socket info using IPv6-compatible API
 
164
 *
 
165
 *      Bugs: only one addrinfo is set even though hintsp is NULL or
 
166
 *                ai_socktype is 0
 
167
 *                AI_CANONNAME is not supported.
 
168
 * -------
 
169
 */
 
170
static int
 
171
getaddrinfo_unix(const char *path, const struct addrinfo * hintsp,
 
172
                                 struct addrinfo ** result)
 
173
{
 
174
        struct addrinfo hints;
 
175
        struct addrinfo *aip;
 
176
        struct sockaddr_un *unp;
 
177
 
 
178
        *result = NULL;
 
179
 
 
180
        MemSet(&hints, 0, sizeof(hints));
 
181
 
 
182
        if (strlen(path) >= sizeof(unp->sun_path))
 
183
                return EAI_FAIL;
 
184
 
 
185
        if (hintsp == NULL)
 
186
        {
 
187
                hints.ai_family = AF_UNIX;
 
188
                hints.ai_socktype = SOCK_STREAM;
 
189
        }
 
190
        else
 
191
                memcpy(&hints, hintsp, sizeof(hints));
 
192
 
 
193
        if (hints.ai_socktype == 0)
 
194
                hints.ai_socktype = SOCK_STREAM;
 
195
 
 
196
        if (hints.ai_family != AF_UNIX)
 
197
        {
 
198
                /* shouldn't have been called */
 
199
                return EAI_FAIL;
 
200
        }
 
201
 
 
202
        aip = calloc(1, sizeof(struct addrinfo));
 
203
        if (aip == NULL)
 
204
                return EAI_MEMORY;
 
205
 
 
206
        unp = calloc(1, sizeof(struct sockaddr_un));
 
207
        if (unp == NULL)
 
208
        {
 
209
                free(aip);
 
210
                return EAI_MEMORY;
 
211
        }
 
212
 
 
213
        aip->ai_family = AF_UNIX;
 
214
        aip->ai_socktype = hints.ai_socktype;
 
215
        aip->ai_protocol = hints.ai_protocol;
 
216
        aip->ai_next = NULL;
 
217
        aip->ai_canonname = NULL;
 
218
        *result = aip;
 
219
 
 
220
        unp->sun_family = AF_UNIX;
 
221
        aip->ai_addr = (struct sockaddr *) unp;
 
222
        aip->ai_addrlen = sizeof(struct sockaddr_un);
 
223
 
 
224
        strcpy(unp->sun_path, path);
 
225
 
 
226
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
 
227
        unp->sun_len = sizeof(struct sockaddr_un);
 
228
#endif
 
229
 
 
230
        return 0;
 
231
}
 
232
 
 
233
/*
 
234
 * Convert an address to a hostname.
 
235
 */
 
236
static int
 
237
getnameinfo_unix(const struct sockaddr_un * sa, int salen,
 
238
                                 char *node, int nodelen,
 
239
                                 char *service, int servicelen,
 
240
                                 int flags)
 
241
{
 
242
        int                     ret = -1;
 
243
 
 
244
        /* Invalid arguments. */
 
245
        if (sa == NULL || sa->sun_family != AF_UNIX ||
 
246
                (node == NULL && service == NULL))
 
247
                return EAI_FAIL;
 
248
 
 
249
        /* We don't support those. */
 
250
        if ((node && !(flags & NI_NUMERICHOST))
 
251
                || (service && !(flags & NI_NUMERICSERV)))
 
252
                return EAI_FAIL;
 
253
 
 
254
        if (node)
 
255
        {
 
256
                ret = snprintf(node, nodelen, "%s", "[local]");
 
257
                if (ret == -1 || ret > nodelen)
 
258
                        return EAI_MEMORY;
 
259
        }
 
260
 
 
261
        if (service)
 
262
        {
 
263
                ret = snprintf(service, servicelen, "%s", sa->sun_path);
 
264
                if (ret == -1 || ret > servicelen)
 
265
                        return EAI_MEMORY;
 
266
        }
 
267
 
 
268
        return 0;
 
269
}
 
270
#endif   /* HAVE_UNIX_SOCKETS */
 
271
 
 
272
 
 
273
/*
 
274
 * rangeSockAddr - is addr within the subnet specified by netaddr/netmask ?
 
275
 *
 
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.
 
278
 */
 
279
int
 
280
rangeSockAddr(const struct sockaddr_storage * addr,
 
281
                          const struct sockaddr_storage * netaddr,
 
282
                          const struct sockaddr_storage * netmask)
 
283
{
 
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);
 
288
#ifdef HAVE_IPV6
 
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);
 
293
#endif
 
294
        else
 
295
                return 0;
 
296
}
 
297
 
 
298
static int
 
299
rangeSockAddrAF_INET(const struct sockaddr_in * addr,
 
300
                                         const struct sockaddr_in * netaddr,
 
301
                                         const struct sockaddr_in * netmask)
 
302
{
 
303
        if (((addr->sin_addr.s_addr ^ netaddr->sin_addr.s_addr) &
 
304
                 netmask->sin_addr.s_addr) == 0)
 
305
                return 1;
 
306
        else
 
307
                return 0;
 
308
}
 
309
 
 
310
 
 
311
#ifdef HAVE_IPV6
 
312
static int
 
313
rangeSockAddrAF_INET6(const struct sockaddr_in6 * addr,
 
314
                                          const struct sockaddr_in6 * netaddr,
 
315
                                          const struct sockaddr_in6 * netmask)
 
316
{
 
317
        int                     i;
 
318
 
 
319
        for (i = 0; i < 16; i++)
 
320
        {
 
321
                if (((addr->sin6_addr.s6_addr[i] ^ netaddr->sin6_addr.s6_addr[i]) &
 
322
                         netmask->sin6_addr.s6_addr[i]) != 0)
 
323
                        return 0;
 
324
        }
 
325
 
 
326
        return 1;
 
327
}
 
328
#endif
 
329
 
 
330
/*
 
331
 *      SockAddr_cidr_mask - make a network mask of the appropriate family
 
332
 *        and required number of significant bits
 
333
 *
 
334
 * The resulting mask is placed in *mask, which had better be big enough.
 
335
 *
 
336
 * Return value is 0 if okay, -1 if not.
 
337
 */
 
338
int
 
339
SockAddr_cidr_mask(struct sockaddr_storage * mask, char *numbits, int family)
 
340
{
 
341
        long            bits;
 
342
        char       *endptr;
 
343
 
 
344
        bits = strtol(numbits, &endptr, 10);
 
345
 
 
346
        if (*numbits == '\0' || *endptr != '\0')
 
347
                return -1;
 
348
 
 
349
        switch (family)
 
350
        {
 
351
                case AF_INET:
 
352
                        {
 
353
                                struct sockaddr_in mask4;
 
354
                                long            maskl;
 
355
 
 
356
                                if (bits < 0 || bits > 32)
 
357
                                        return -1;
 
358
                                /* avoid "x << 32", which is not portable */
 
359
                                if (bits > 0)
 
360
                                        maskl = (0xffffffffUL << (32 - (int) bits))
 
361
                                                & 0xffffffffUL;
 
362
                                else
 
363
                                        maskl = 0;
 
364
                                mask4.sin_addr.s_addr = htonl(maskl);
 
365
                                memcpy(mask, &mask4, sizeof(mask4));
 
366
                                break;
 
367
                        }
 
368
 
 
369
#ifdef HAVE_IPV6
 
370
                case AF_INET6:
 
371
                        {
 
372
                                struct sockaddr_in6 mask6;
 
373
                                int                     i;
 
374
 
 
375
                                if (bits < 0 || bits > 128)
 
376
                                        return -1;
 
377
                                for (i = 0; i < 16; i++)
 
378
                                {
 
379
                                        if (bits <= 0)
 
380
                                                mask6.sin6_addr.s6_addr[i] = 0;
 
381
                                        else if (bits >= 8)
 
382
                                                mask6.sin6_addr.s6_addr[i] = 0xff;
 
383
                                        else
 
384
                                        {
 
385
                                                mask6.sin6_addr.s6_addr[i] =
 
386
                                                        (0xff << (8 - (int) bits)) & 0xff;
 
387
                                        }
 
388
                                        bits -= 8;
 
389
                                }
 
390
                                memcpy(mask, &mask6, sizeof(mask6));
 
391
                                break;
 
392
                        }
 
393
#endif
 
394
                default:
 
395
                        return -1;
 
396
        }
 
397
 
 
398
        mask->ss_family = family;
 
399
        return 0;
 
400
}
 
401
 
 
402
 
 
403
#ifdef HAVE_IPV6
 
404
 
 
405
/*
 
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
 
408
 *
 
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.
 
412
 */
 
413
void
 
414
promote_v4_to_v6_addr(struct sockaddr_storage * addr)
 
415
{
 
416
        struct sockaddr_in addr4;
 
417
        struct sockaddr_in6 addr6;
 
418
        uint32          ip4addr;
 
419
 
 
420
        memcpy(&addr4, addr, sizeof(addr4));
 
421
        ip4addr = ntohl(addr4.sin_addr.s_addr);
 
422
 
 
423
        memset(&addr6, 0, sizeof(addr6));
 
424
 
 
425
        addr6.sin6_family = AF_INET6;
 
426
 
 
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;
 
433
 
 
434
        memcpy(addr, &addr6, sizeof(addr6));
 
435
}
 
436
 
 
437
/*
 
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
 
440
 *
 
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.
 
443
 *
 
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.
 
447
 */
 
448
void
 
449
promote_v4_to_v6_mask(struct sockaddr_storage * addr)
 
450
{
 
451
        struct sockaddr_in addr4;
 
452
        struct sockaddr_in6 addr6;
 
453
        uint32          ip4addr;
 
454
        int                     i;
 
455
 
 
456
        memcpy(&addr4, addr, sizeof(addr4));
 
457
        ip4addr = ntohl(addr4.sin_addr.s_addr);
 
458
 
 
459
        memset(&addr6, 0, sizeof(addr6));
 
460
 
 
461
        addr6.sin6_family = AF_INET6;
 
462
 
 
463
        for (i = 0; i < 12; i++)
 
464
                addr6.sin6_addr.s6_addr[i] = 0xff;
 
465
 
 
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;
 
470
 
 
471
        memcpy(addr, &addr6, sizeof(addr6));
 
472
}
 
473
 
 
474
#endif   /* HAVE_IPV6 */