]> git.8kb.co.uk Git - pgpool-ii/pgpool-ii_2.2.5/blob - pool_ip.c
Attempt to send a proper failure message to frontend when authentication
[pgpool-ii/pgpool-ii_2.2.5] / pool_ip.c
1 /* -*-pgsql-c-*- */
2 /*
3  *
4  * $Header: /cvsroot/pgpool/pgpool-II/pool_ip.c,v 1.2.2.1 2009/08/22 04:19:49 t-ishii Exp $
5  *
6  * This file was imported from PostgreSQL 8.0.8 source code.
7  * See below for the copyright and description.
8  *
9  * pgpool: a language independent connection pool server for PostgreSQL
10  * written by Tatsuo Ishii
11  *
12  * Portions Copyright (c) 2003-2008     PgPool Global Development Group
13  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
14  * Portions Copyright (c) 1994, Regents of the University of California
15  *
16  * Permission to use, copy, modify, and distribute this software and
17  * its documentation for any purpose and without fee is hereby
18  * granted, provided that the above copyright notice appear in all
19  * copies and that both that copyright notice and this permission
20  * notice appear in supporting documentation, and that the name of the
21  * author not be used in advertising or publicity pertaining to
22  * distribution of the software without specific, written prior
23  * permission. The author makes no representations about the
24  * suitability of this software for any purpose.  It is provided "as
25  * is" without express or implied warranty.
26  *
27  * ------------------------------
28  *
29  *
30  * This file and the IPV6 implementation were initially provided by
31  * Nigel Kukard <nkukard@lbsd.net>, Linux Based Systems Design
32  * http://www.lbsd.net.
33  *
34  * pool_ip.c.: IPv6-aware network access.
35  *
36  */
37
38 #include <errno.h>
39 #include <unistd.h>
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <netdb.h>
43 #include <netinet/in.h>
44 #include <netinet/tcp.h>
45
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <sys/un.h>
50 #include "pool.h"
51 #include "pool_ip.h"
52
53
54 static int rangeSockAddrAF_INET(const struct sockaddr_in * addr,
55                                          const struct sockaddr_in * netaddr,
56                                          const struct sockaddr_in * netmask);
57
58 #ifdef HAVE_IPV6
59 static int rangeSockAddrAF_INET6(const struct sockaddr_in6 * addr,
60                                           const struct sockaddr_in6 * netaddr,
61                                           const struct sockaddr_in6 * netmask);
62 #endif
63
64 static int getaddrinfo_unix(const char *path,
65                                  const struct addrinfo * hintsp,
66                                  struct addrinfo ** result);
67
68 static int getnameinfo_unix(const struct sockaddr_un * sa, int salen,
69                                  char *node, int nodelen,
70                                  char *service, int servicelen,
71                                  int flags);
72
73 /*
74  * pool_getnameinfo_all - get name info for Unix, IPv4 and IPv6 sockets
75  * caller MUST allocate NI_MAXHOST, NI_MAXSERV bytes for remote_host and remote_port
76  */
77 void pool_getnameinfo_all(SockAddr *saddr, char *remote_host, char *remote_port)
78 {
79         remote_host[0] = '\0';
80         remote_port[0] = '\0';
81
82         if (getnameinfo_all(&saddr->addr, saddr->salen,
83                                                 remote_host, NI_MAXHOST,
84                                                 remote_port, NI_MAXSERV,
85                                                 (pool_config->log_hostname ? 0 : NI_NUMERICHOST) | NI_NUMERICSERV))
86         {
87                 int ret = getnameinfo_all(&saddr->addr, saddr->salen,
88                                                                   remote_host, NI_MAXHOST,
89                                                                   remote_port, NI_MAXSERV,
90                                                                   NI_NUMERICHOST | NI_NUMERICSERV);
91                 if (ret)
92                         pool_error("getnameinfo_all() failed: %s", gai_strerror(ret));
93         }
94 }
95
96 /*
97  *      getaddrinfo_all - get address info for Unix, IPv4 and IPv6 sockets
98  */
99 int
100 getaddrinfo_all(const char *hostname, const char *servname,
101                                 const struct addrinfo * hintp, struct addrinfo ** result)
102 {
103         /* not all versions of getaddrinfo() zero *result on failure */
104         *result = NULL;
105
106         if (hintp->ai_family == AF_UNIX)
107                 return getaddrinfo_unix(servname, hintp, result);
108
109         /* NULL has special meaning to getaddrinfo(). */
110         return getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname,
111                                            servname, hintp, result);
112 }
113
114
115 /*
116  *      freeaddrinfo_all - free addrinfo structures for IPv4, IPv6, or Unix
117  *
118  * Note: the ai_family field of the original hint structure must be passed
119  * so that we can tell whether the addrinfo struct was built by the system's
120  * getaddrinfo() routine or our own getaddrinfo_unix() routine.  Some versions
121  * of getaddrinfo() might be willing to return AF_UNIX addresses, so it's
122  * not safe to look at ai_family in the addrinfo itself.
123  */
124 void
125 freeaddrinfo_all(int hint_ai_family, struct addrinfo * ai)
126 {
127         if (hint_ai_family == AF_UNIX)
128         {
129                 /* struct was built by getaddrinfo_unix (see getaddrinfo_all) */
130                 while (ai != NULL)
131                 {
132                         struct addrinfo *p = ai;
133
134                         ai = ai->ai_next;
135                         free(p->ai_addr);
136                         free(p);
137                 }
138         }
139         else
140         {
141                 /* struct was built by getaddrinfo() */
142                 if (ai != NULL)
143                         freeaddrinfo(ai);
144         }
145 }
146
147
148 /*
149  *      getnameinfo_all - get name info for Unix, IPv4 and IPv6 sockets
150  *
151  * The API of this routine differs from the standard getnameinfo() definition
152  * in two ways: first, the addr parameter is declared as sockaddr_storage
153  * rather than struct sockaddr, and second, the node and service fields are
154  * guaranteed to be filled with something even on failure return.
155  */
156 int
157 getnameinfo_all(const struct sockaddr_storage * addr, int salen,
158                                 char *node, int nodelen,
159                                 char *service, int servicelen,
160                                 int flags)
161 {
162         int                     rc;
163
164         if (addr && addr->ss_family == AF_UNIX)
165                 rc = getnameinfo_unix((const struct sockaddr_un *) addr, salen,
166                                                           node, nodelen,
167                                                           service, servicelen,
168                                                           flags);
169         else
170                 rc = getnameinfo((const struct sockaddr *) addr, salen,
171                                                  node, nodelen,
172                                                  service, servicelen,
173                                                  flags);
174
175         if (rc != 0)
176         {
177                 if (node)
178                         strncpy(node, "???", nodelen);
179                 if (service)
180                         strncpy(service, "???", servicelen);
181         }
182
183         return rc;
184 }
185
186
187 #ifndef HAVE_GAI_STRERROR
188 const char *
189 gai_strerror(int errcode)
190 {
191 #ifdef HAVE_HSTRERROR
192         int         hcode;
193
194         switch (errcode)
195         {
196                 case EAI_NONAME:
197                         hcode = HOST_NOT_FOUND;
198                         break;
199                 case EAI_AGAIN:
200                         hcode = TRY_AGAIN;
201                         break;
202                 case EAI_FAIL:
203                 default:
204                         hcode = NO_RECOVERY;
205                         break;
206         }
207
208         return hstrerror(hcode);
209 #else                                                   /* !HAVE_HSTRERROR */
210
211         switch (errcode)
212         {
213                 case EAI_NONAME:
214                         return "Unknown host";
215                 case EAI_AGAIN:
216                         return "Host name lookup failure";
217                         /* Errors below are probably WIN32 only */
218 #ifdef EAI_BADFLAGS
219                 case EAI_BADFLAGS:
220                         return "Invalid argument";
221 #endif
222 #ifdef EAI_FAMILY
223                 case EAI_FAMILY:
224                         return "Address family not supported";
225 #endif
226 #ifdef EAI_MEMORY
227                 case EAI_MEMORY:
228                         return "Not enough memory";
229 #endif
230 #ifdef EAI_NODATA
231 #ifndef WIN32_ONLY_COMPILER             /* MSVC complains because another case has the
232                                                                  * same value */
233                 case EAI_NODATA:
234                         return "No host data of that type was found";
235 #endif
236 #endif
237 #ifdef EAI_SERVICE
238                 case EAI_SERVICE:
239                         return "Class type not found";
240 #endif
241 #ifdef EAI_SOCKTYPE
242                 case EAI_SOCKTYPE:
243                         return "Socket type not supported";
244 #endif
245                 default:
246                         return "Unknown server error";
247         }
248 #endif   /* HAVE_HSTRERROR */
249 }
250 #endif /* HAVE_GAI_STRERROR */
251
252
253 /*
254  *      getaddrinfo_unix - get unix socket info using IPv6-compatible API
255  *
256  *      Bugs: only one addrinfo is set even though hintsp is NULL or
257  *                ai_socktype is 0
258  *                AI_CANONNAME is not supported.
259  *
260  */
261 static int
262 getaddrinfo_unix(const char *path, const struct addrinfo * hintsp,
263                                  struct addrinfo ** result)
264 {
265         struct addrinfo hints;
266         struct addrinfo *aip;
267         struct sockaddr_un *unp;
268
269         *result = NULL;
270
271         memset(&hints, 0, sizeof(hints));
272
273         if (strlen(path) >= sizeof(unp->sun_path))
274                 return EAI_FAIL;
275
276         if (hintsp == NULL)
277         {
278                 hints.ai_family = AF_UNIX;
279                 hints.ai_socktype = SOCK_STREAM;
280         }
281         else
282                 memcpy(&hints, hintsp, sizeof(hints));
283
284         if (hints.ai_socktype == 0)
285                 hints.ai_socktype = SOCK_STREAM;
286
287         if (hints.ai_family != AF_UNIX)
288         {
289                 /* shouldn't have been called */
290                 return EAI_FAIL;
291         }
292
293         aip = calloc(1, sizeof(struct addrinfo));
294         if (aip == NULL)
295                 return EAI_MEMORY;
296
297         unp = calloc(1, sizeof(struct sockaddr_un));
298         if (unp == NULL)
299         {
300                 free(aip);
301                 return EAI_MEMORY;
302         }
303
304         aip->ai_family = AF_UNIX;
305         aip->ai_socktype = hints.ai_socktype;
306         aip->ai_protocol = hints.ai_protocol;
307         aip->ai_next = NULL;
308         aip->ai_canonname = NULL;
309         *result = aip;
310
311         unp->sun_family = AF_UNIX;
312         aip->ai_addr = (struct sockaddr *) unp;
313         aip->ai_addrlen = sizeof(struct sockaddr_un);
314
315         strcpy(unp->sun_path, path);
316
317 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
318         unp->sun_len = sizeof(struct sockaddr_un);
319 #endif
320
321         return 0;
322 }
323
324 /*
325  * Convert an address to a hostname.
326  */
327 static int
328 getnameinfo_unix(const struct sockaddr_un * sa, int salen,
329                                  char *node, int nodelen,
330                                  char *service, int servicelen,
331                                  int flags)
332 {
333         int                     ret = -1;
334
335         /* Invalid arguments. */
336         if (sa == NULL || sa->sun_family != AF_UNIX ||
337                 (node == NULL && service == NULL))
338                 return EAI_FAIL;
339
340         /* We don't support those. */
341         if ((node && !(flags & NI_NUMERICHOST))
342                 || (service && !(flags & NI_NUMERICSERV)))
343                 return EAI_FAIL;
344
345         if (node)
346         {
347                 ret = snprintf(node, nodelen, "%s", "[local]");
348                 if (ret == -1 || ret > nodelen)
349                         return EAI_MEMORY;
350         }
351
352         if (service)
353         {
354                 ret = snprintf(service, servicelen, "%s", sa->sun_path);
355                 if (ret == -1 || ret > servicelen)
356                         return EAI_MEMORY;
357         }
358
359         return 0;
360 }
361
362
363 /*
364  * rangeSockAddr - is addr within the subnet specified by netaddr/netmask ?
365  *
366  * Note: caller must already have verified that all three addresses are
367  * in the same address family; and AF_UNIX addresses are not supported.
368  */
369 int
370 rangeSockAddr(const struct sockaddr_storage * addr,
371                           const struct sockaddr_storage * netaddr,
372                           const struct sockaddr_storage * netmask)
373 {
374         if (addr->ss_family == AF_INET)
375                 return rangeSockAddrAF_INET((struct sockaddr_in *) addr,
376                                                                         (struct sockaddr_in *) netaddr,
377                                                                         (struct sockaddr_in *) netmask);
378 #ifdef HAVE_IPV6
379         else if (addr->ss_family == AF_INET6)
380                 return rangeSockAddrAF_INET6((struct sockaddr_in6 *) addr,
381                                                                          (struct sockaddr_in6 *) netaddr,
382                                                                          (struct sockaddr_in6 *) netmask);
383 #endif
384         else
385                 return 0;
386 }
387
388 static int
389 rangeSockAddrAF_INET(const struct sockaddr_in * addr,
390                                          const struct sockaddr_in * netaddr,
391                                          const struct sockaddr_in * netmask)
392 {
393         if (((addr->sin_addr.s_addr ^ netaddr->sin_addr.s_addr) &
394                  netmask->sin_addr.s_addr) == 0)
395                 return 1;
396         else
397                 return 0;
398 }
399
400
401 #ifdef HAVE_IPV6
402 static int
403 rangeSockAddrAF_INET6(const struct sockaddr_in6 * addr,
404                                           const struct sockaddr_in6 * netaddr,
405                                           const struct sockaddr_in6 * netmask)
406 {
407         int                     i;
408
409         for (i = 0; i < 16; i++)
410         {
411                 if (((addr->sin6_addr.s6_addr[i] ^ netaddr->sin6_addr.s6_addr[i]) &
412                          netmask->sin6_addr.s6_addr[i]) != 0)
413                         return 0;
414         }
415
416         return 1;
417 }
418 #endif
419
420 /*
421  *      SockAddr_cidr_mask - make a network mask of the appropriate family
422  *        and required number of significant bits
423  *
424  * The resulting mask is placed in *mask, which had better be big enough.
425  *
426  * Return value is 0 if okay, -1 if not.
427  */
428 int
429 SockAddr_cidr_mask(struct sockaddr_storage * mask, char *numbits, int family)
430 {
431         long            bits;
432         char       *endptr;
433
434         bits = strtol(numbits, &endptr, 10);
435
436         if (*numbits == '\0' || *endptr != '\0')
437                 return -1;
438
439         switch (family)
440         {
441                 case AF_INET:
442                         {
443                                 struct sockaddr_in mask4;
444                                 long            maskl;
445
446                                 if (bits < 0 || bits > 32)
447                                         return -1;
448                                 /* avoid "x << 32", which is not portable */
449                                 if (bits > 0)
450                                         maskl = (0xffffffffUL << (32 - (int) bits))
451                                                 & 0xffffffffUL;
452                                 else
453                                         maskl = 0;
454                                 mask4.sin_addr.s_addr = htonl(maskl);
455                                 memcpy(mask, &mask4, sizeof(mask4));
456                                 break;
457                         }
458
459 #ifdef HAVE_IPV6
460                 case AF_INET6:
461                         {
462                                 struct sockaddr_in6 mask6;
463                                 int                     i;
464
465                                 if (bits < 0 || bits > 128)
466                                         return -1;
467                                 for (i = 0; i < 16; i++)
468                                 {
469                                         if (bits <= 0)
470                                                 mask6.sin6_addr.s6_addr[i] = 0;
471                                         else if (bits >= 8)
472                                                 mask6.sin6_addr.s6_addr[i] = 0xff;
473                                         else
474                                         {
475                                                 mask6.sin6_addr.s6_addr[i] =
476                                                         (0xff << (8 - (int) bits)) & 0xff;
477                                         }
478                                         bits -= 8;
479                                 }
480                                 memcpy(mask, &mask6, sizeof(mask6));
481                                 break;
482                         }
483 #endif
484                 default:
485                         return -1;
486         }
487
488         mask->ss_family = family;
489         return 0;
490 }
491
492
493 #ifdef HAVE_IPV6
494
495 /*
496  * promote_v4_to_v6_addr --- convert an AF_INET addr to AF_INET6, using
497  *              the standard convention for IPv4 addresses mapped into IPv6 world
498  *
499  * The passed addr is modified in place; be sure it is large enough to
500  * hold the result!  Note that we only worry about setting the fields
501  * that rangeSockAddr will look at.
502  */
503 static void
504 promote_v4_to_v6_addr(struct sockaddr_storage * addr)
505 {
506         struct sockaddr_in addr4;
507         struct sockaddr_in6 addr6;
508         uint32          ip4addr;
509
510         memcpy(&addr4, addr, sizeof(addr4));
511         ip4addr = ntohl(addr4.sin_addr.s_addr);
512
513         memset(&addr6, 0, sizeof(addr6));
514
515         addr6.sin6_family = AF_INET6;
516
517         addr6.sin6_addr.s6_addr[10] = 0xff;
518         addr6.sin6_addr.s6_addr[11] = 0xff;
519         addr6.sin6_addr.s6_addr[12] = (ip4addr >> 24) & 0xFF;
520         addr6.sin6_addr.s6_addr[13] = (ip4addr >> 16) & 0xFF;
521         addr6.sin6_addr.s6_addr[14] = (ip4addr >> 8) & 0xFF;
522         addr6.sin6_addr.s6_addr[15] = (ip4addr) & 0xFF;
523
524         memcpy(addr, &addr6, sizeof(addr6));
525 }
526
527 /*
528  * promote_v4_to_v6_mask --- convert an AF_INET netmask to AF_INET6, using
529  *              the standard convention for IPv4 addresses mapped into IPv6 world
530  *
531  * This must be different from promote_v4_to_v6_addr because we want to
532  * set the high-order bits to 1's not 0's.
533  *
534  * The passed addr is modified in place; be sure it is large enough to
535  * hold the result!  Note that we only worry about setting the fields
536  * that rangeSockAddr will look at.
537  */
538 static void
539 promote_v4_to_v6_mask(struct sockaddr_storage * addr)
540 {
541         struct sockaddr_in addr4;
542         struct sockaddr_in6 addr6;
543         uint32          ip4addr;
544         int                     i;
545
546         memcpy(&addr4, addr, sizeof(addr4));
547         ip4addr = ntohl(addr4.sin_addr.s_addr);
548
549         memset(&addr6, 0, sizeof(addr6));
550
551         addr6.sin6_family = AF_INET6;
552
553         for (i = 0; i < 12; i++)
554                 addr6.sin6_addr.s6_addr[i] = 0xff;
555
556         addr6.sin6_addr.s6_addr[12] = (ip4addr >> 24) & 0xFF;
557         addr6.sin6_addr.s6_addr[13] = (ip4addr >> 16) & 0xFF;
558         addr6.sin6_addr.s6_addr[14] = (ip4addr >> 8) & 0xFF;
559         addr6.sin6_addr.s6_addr[15] = (ip4addr) & 0xFF;
560
561         memcpy(addr, &addr6, sizeof(addr6));
562 }
563
564 #endif   /* HAVE_IPV6 */
565