]> granicus.if.org Git - postgresql/blob - src/backend/libpq/ip.c
Simplify the socket handling code by supplying a replacement getaddrinfo()
[postgresql] / src / backend / libpq / ip.c
1 /*-------------------------------------------------------------------------
2  *
3  * ip.c
4  *        Handles IPv6
5  *
6  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/libpq/ip.c,v 1.3 2003/03/29 11:31:51 petere 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 #ifndef FRONTEND
21 #include "postgres.h"
22 #else
23 #include "postgres_fe.h"
24 #endif
25
26 #include <errno.h>
27 #include <unistd.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/socket.h>
31 #include <netdb.h>
32 #include <netinet/in.h>
33 #ifdef HAVE_NETINET_TCP_H
34 #include <netinet/tcp.h>
35 #endif
36 #include <arpa/inet.h>
37 #include <sys/file.h>
38
39 #include "libpq/libpq.h"
40 #include "miscadmin.h"
41
42 #ifdef FRONTEND
43 #define elog fprintf
44 #define LOG  stderr
45 #endif
46
47 #if defined(HAVE_UNIX_SOCKETS)
48 static int getaddrinfo_unix(const char *path, const struct addrinfo *hintsp,
49                                                         struct addrinfo **result);
50 #endif   /* HAVE_UNIX_SOCKETS */
51
52 /*
53  *      getaddrinfo2 - get address info for Unix, IPv4 and IPv6 sockets
54  */
55 int
56 getaddrinfo2(const char *hostname, const char *servname,
57                          const struct addrinfo *hintp, struct addrinfo **result)
58 {
59 #ifdef HAVE_UNIX_SOCKETS
60         if (hintp != NULL && hintp->ai_family == AF_UNIX)
61                 return getaddrinfo_unix(servname, hintp, result);
62         else
63         {
64 #endif   /* HAVE_UNIX_SOCKETS */
65                 /* NULL has special meaning to getaddrinfo */
66                 return getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname,
67                                                    servname, hintp, result);
68 #ifdef HAVE_UNIX_SOCKETS
69         }
70 #endif   /* HAVE_UNIX_SOCKETS */
71 }
72
73
74 /*
75  *      freeaddrinfo2 - free IPv6 addrinfo structures
76  */
77 void
78 freeaddrinfo2(int hint_ai_family, struct addrinfo *ai)
79 {
80 #ifdef HAVE_UNIX_SOCKETS
81         if (hint_ai_family == AF_UNIX)
82         {
83                 struct addrinfo *p;
84
85                 while (ai != NULL)
86                 {
87                         p = ai;
88                         ai = ai->ai_next;
89                         free(p->ai_addr);
90                         free(p);
91                 }
92         }
93         else
94 #endif   /* HAVE_UNIX_SOCKETS */
95                 freeaddrinfo(ai);
96 }
97
98
99 #if defined(HAVE_UNIX_SOCKETS)
100 /* -------
101  *      getaddrinfo_unix - get unix socket info using IPv6
102  *
103  *      Bug:  only one addrinfo is set even though hintsp is NULL or
104  *                ai_socktype is 0
105  *                AI_CANNONNAME does not support.
106  * -------
107  */
108 static int
109 getaddrinfo_unix(const char *path, const struct addrinfo *hintsp,
110                                  struct addrinfo **result)
111 {
112         struct addrinfo hints;
113         struct addrinfo *aip;
114         struct sockaddr_un *unp;
115
116         MemSet(&hints, 0, sizeof(hints));
117
118         if (hintsp == NULL)
119         {
120                 hints.ai_family = AF_UNIX;
121                 hints.ai_socktype = SOCK_STREAM;
122         }
123         else
124                 memcpy(&hints, hintsp, sizeof(hints));
125
126         if (hints.ai_socktype == 0)
127                 hints.ai_socktype = SOCK_STREAM;
128
129         if (hints.ai_family != AF_UNIX)
130         {
131                 elog(LOG, "hints.ai_family is invalid in getaddrinfo_unix()\n");
132                 return EAI_ADDRFAMILY;
133         }
134
135         aip = calloc(1, sizeof(struct addrinfo));
136         if (aip == NULL)
137                 return EAI_MEMORY;
138
139         aip->ai_family = AF_UNIX;
140         aip->ai_socktype = hints.ai_socktype;
141         aip->ai_protocol = hints.ai_protocol;
142         aip->ai_next = NULL;
143         aip->ai_canonname = NULL;
144         *result = aip;
145
146         unp = calloc(1, sizeof(struct sockaddr_un));
147         if (aip == NULL)
148                 return EAI_MEMORY;
149
150         unp->sun_family = AF_UNIX;
151         aip->ai_addr = (struct sockaddr *) unp;
152         aip->ai_addrlen = sizeof(struct sockaddr_un);
153
154         if (strlen(path) >= sizeof(unp->sun_path))
155                 return EAI_SERVICE;
156         strcpy(unp->sun_path, path);
157
158 #if SALEN
159         unp->sun_len = sizeof(struct sockaddr_un);
160 #endif   /* SALEN */
161
162         if (hints.ai_flags & AI_PASSIVE)
163                 unlink(unp->sun_path);
164
165         return 0;
166 }
167 #endif   /* HAVE_UNIX_SOCKETS */
168
169 /* ----------
170  * SockAddr_ntop - set IP address string from SockAddr
171  *
172  * parameters...  sa    : SockAddr union
173  *                                dst   : buffer for address string
174  *                                cnt   : sizeof dst
175  *                                v4conv: non-zero: if address is IPv4 mapped IPv6 address then
176  *                                                convert to IPv4 address.
177  * returns... pointer to dst
178  * if sa.sa_family is not AF_INET or AF_INET6 dst is set as empy string.
179  * ----------
180  */
181 char *
182 SockAddr_ntop(const SockAddr *sa, char *dst, size_t cnt, int v4conv)
183 {
184         switch (sa->sa.sa_family)
185         {
186                 case AF_INET:
187 #ifdef HAVE_IPV6
188                         inet_ntop(AF_INET, &sa->in.sin_addr, dst, cnt);
189 #else
190                         StrNCpy(dst, inet_ntoa(sa->in.sin_addr), cnt);
191 #endif
192                         break;
193 #ifdef HAVE_IPV6
194                 case AF_INET6:
195                         inet_ntop(AF_INET6, &sa->in6.sin6_addr, dst, cnt);
196                         if (v4conv && IN6_IS_ADDR_V4MAPPED(&sa->in6.sin6_addr))
197                                 strcpy(dst, dst + 7);
198                         break;
199 #endif
200                 default:
201                         dst[0] = '\0';
202                         break;
203         }
204         return dst;
205 }
206
207
208 /*
209  *      SockAddr_pton - IPv6 pton
210  */
211 int
212 SockAddr_pton(SockAddr *sa, const char *src)
213 {
214         int                     family = AF_INET;
215 #ifdef HAVE_IPV6
216         const char              *ch;
217
218         for (ch = src; *ch != '\0'; ch++)
219         {
220                 if (*ch == ':')
221                 {
222                         family = AF_INET6;
223                         break;
224                 }
225         }
226 #endif
227
228         sa->sa.sa_family = family;
229
230         switch (family)
231         {
232                 case AF_INET:
233 #ifdef HAVE_IPV6
234                         return inet_pton(AF_INET, src, &sa->in.sin_addr);
235 #else
236                         return inet_aton(src, &sa->in.sin_addr);
237 #endif
238
239 #ifdef HAVE_IPV6
240                 case AF_INET6:
241                         return inet_pton(AF_INET6, src, &sa->in6.sin6_addr);
242                         break;
243 #endif
244                 default:
245                         return -1;
246         }
247 }
248
249
250
251
252 /*
253  *      isAF_INETx - check to see if sa is AF_INET or AF_INET6
254  */
255 int
256 isAF_INETx(const int family)
257 {
258         if (family == AF_INET
259 #ifdef HAVE_IPV6
260                 || family == AF_INET6
261 #endif
262                 )
263                 return 1;
264         else
265                 return 0;
266 }
267
268
269 int
270 rangeSockAddr(const SockAddr *addr, const SockAddr *netaddr, const SockAddr *netmask)
271 {
272         if (addr->sa.sa_family == AF_INET)
273                 return rangeSockAddrAF_INET(addr, netaddr, netmask);
274 #ifdef HAVE_IPV6
275         else if (addr->sa.sa_family == AF_INET6)
276                 return rangeSockAddrAF_INET6(addr, netaddr, netmask);
277 #endif
278         else
279                 return 0;
280 }
281
282 int
283 rangeSockAddrAF_INET(const SockAddr *addr, const SockAddr *netaddr,
284                                          const SockAddr *netmask)
285 {
286         if (addr->sa.sa_family != AF_INET ||
287                 netaddr->sa.sa_family != AF_INET ||
288                 netmask->sa.sa_family != AF_INET)
289                 return 0;
290         if (((addr->in.sin_addr.s_addr ^ netaddr->in.sin_addr.s_addr) &
291                  netmask->in.sin_addr.s_addr) == 0)
292                 return 1;
293         else
294                 return 0;
295 }
296
297 #ifdef HAVE_IPV6
298 int
299 rangeSockAddrAF_INET6(const SockAddr *addr, const SockAddr *netaddr,
300                                           const SockAddr *netmask)
301 {
302         int                     i;
303
304         if (IN6_IS_ADDR_V4MAPPED(&addr->in6.sin6_addr))
305         {
306                 SockAddr        addr4;
307
308                 convSockAddr6to4(addr, &addr4);
309                 if (rangeSockAddrAF_INET(&addr4, netaddr, netmask))
310                         return 1;
311         }
312
313         if (netaddr->sa.sa_family != AF_INET6 ||
314                 netmask->sa.sa_family != AF_INET6)
315                 return 0;
316
317         for (i = 0; i < 16; i++)
318         {
319                 if (((addr->in6.sin6_addr.s6_addr[i] ^ netaddr->in6.sin6_addr.s6_addr[i]) &
320                          netmask->in6.sin6_addr.s6_addr[i]) != 0)
321                         return 0;
322         }
323
324         return 1;
325 }
326
327 void
328 convSockAddr6to4(const SockAddr *src, SockAddr *dst)
329 {
330         char            addr_str[INET6_ADDRSTRLEN];
331
332         dst->in.sin_family = AF_INET;
333         dst->in.sin_port = src->in6.sin6_port;
334
335         dst->in.sin_addr.s_addr =
336                 (src->in6.sin6_addr.s6_addr[15])
337                 + (src->in6.sin6_addr.s6_addr[14] << 8)
338                 + (src->in6.sin6_addr.s6_addr[13] << 16)
339                 + (src->in6.sin6_addr.s6_addr[12] << 24);
340         SockAddr_ntop(src, addr_str, INET6_ADDRSTRLEN, 0);
341 }
342 #endif