1 /*-------------------------------------------------------------------------
6 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/libpq/ip.c,v 1.2 2003/01/09 14:35:03 petere 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 *-------------------------------------------------------------------------
23 #include "postgres_fe.h"
28 #include <sys/types.h>
30 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #ifdef HAVE_NETINET_TCP_H
34 #include <netinet/tcp.h>
36 #include <arpa/inet.h>
39 #include "libpq/libpq.h"
40 #include "miscadmin.h"
47 #if defined(HAVE_UNIX_SOCKETS) && defined(HAVE_IPV6)
48 static int getaddrinfo_unix(const char *path, const struct addrinfo *hintsp,
49 struct addrinfo **result);
50 #endif /* HAVE_UNIX_SOCKETS */
53 * getaddrinfo2 - get address info for Unix, IPv4 and IPv6 sockets
56 getaddrinfo2(const char *hostname, const char *servname,
58 const struct addrinfo *hintp, struct addrinfo **result)
60 int family, SockAddr *result)
63 #ifdef HAVE_UNIX_SOCKETS
65 if (hintp != NULL && hintp->ai_family == AF_UNIX)
66 return getaddrinfo_unix(servname, hintp, result);
68 if (family == AF_UNIX)
73 #endif /* HAVE_UNIX_SOCKETS */
75 /* NULL has special meaning to getaddrinfo */
76 return getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname,
77 servname, hintp, result);
79 if (hostname[0] == '\0')
80 result->in.sin_addr.s_addr = htonl(INADDR_ANY);
85 hp = gethostbyname(hostname);
86 if ((hp == NULL) || (hp->h_addrtype != AF_INET))
88 elog(LOG, "getaddrinfo2: gethostbyname(%s) failed\n", hostname);
91 memmove((char *) &(result->in.sin_addr), (char *) hp->h_addr,
95 result->in.sin_port = htons((unsigned short)atoi(servname));
97 #endif /* HAVE_IPV6 */
99 #ifdef HAVE_UNIX_SOCKETS
101 #endif /* HAVE_UNIX_SOCKETS */
106 * freeaddrinfo2 - free IPv6 addrinfo structures
110 freeaddrinfo2(int hint_ai_family, struct addrinfo *ai)
112 #ifdef HAVE_UNIX_SOCKETS
113 if (hint_ai_family == AF_UNIX)
126 #endif /* HAVE_UNIX_SOCKETS */
132 #if defined(HAVE_UNIX_SOCKETS) && defined(HAVE_IPV6)
134 * getaddrinfo_unix - get unix socket info using IPv6
136 * Bug: only one addrinfo is set even though hintsp is NULL or
138 * AI_CANNONNAME does not support.
142 getaddrinfo_unix(const char *path, const struct addrinfo *hintsp,
143 struct addrinfo **result)
145 struct addrinfo hints;
146 struct addrinfo *aip;
147 struct sockaddr_un *unp;
149 MemSet(&hints, 0, sizeof(hints));
153 hints.ai_family = AF_UNIX;
154 hints.ai_socktype = SOCK_STREAM;
157 memcpy(&hints, hintsp, sizeof(hints));
159 if (hints.ai_socktype == 0)
160 hints.ai_socktype = SOCK_STREAM;
162 if (!(hints.ai_family == AF_UNIX))
164 elog(LOG, "hints.ai_family is invalied getaddrinfo_unix()\n");
165 return EAI_ADDRFAMILY;
168 aip = calloc(1, sizeof(struct addrinfo));
172 aip->ai_family = AF_UNIX;
173 aip->ai_socktype = hints.ai_socktype;
174 aip->ai_protocol = hints.ai_protocol;
176 aip->ai_canonname = NULL;
179 unp = calloc(1, sizeof(struct sockaddr_un));
183 unp->sun_family = AF_UNIX;
184 aip->ai_addr = (struct sockaddr *) unp;
185 aip->ai_addrlen = sizeof(struct sockaddr_un);
187 if (strlen(path) >= sizeof(unp->sun_path))
189 strcpy(unp->sun_path, path);
192 unp->sun_len = sizeof(struct sockaddr_un);
195 if (hints.ai_flags & AI_PASSIVE)
196 unlink(unp->sun_path);
200 #endif /* HAVE_UNIX_SOCKETS && HAVE_IPV6 */
203 * SockAddr_ntop - set IP address string from SockAddr
205 * parameters... sa : SockAddr union
206 * dst : buffer for address string
208 * v4conv: non-zero: if address is IPv4 mapped IPv6 address then
209 * convert to IPv4 address.
210 * returns... pointer to dst
211 * if sa.sa_family is not AF_INET or AF_INET6 dst is set as empy string.
215 SockAddr_ntop(const SockAddr *sa, char *dst, size_t cnt, int v4conv)
217 switch (sa->sa.sa_family)
221 inet_ntop(AF_INET, &sa->in.sin_addr, dst, cnt);
223 StrNCpy(dst, inet_ntoa(sa->in.sin_addr), cnt);
228 inet_ntop(AF_INET6, &sa->in6.sin6_addr, dst, cnt);
229 if (v4conv && IN6_IS_ADDR_V4MAPPED(&sa->in6.sin6_addr))
230 strcpy(dst, dst + 7);
242 * SockAddr_pton - IPv6 pton
245 SockAddr_pton(SockAddr *sa, const char *src)
247 int family = AF_INET;
251 for (ch = src; *ch != '\0'; ch++)
261 sa->sa.sa_family = family;
267 return inet_pton(AF_INET, src, &sa->in.sin_addr);
269 return inet_aton(src, &sa->in.sin_addr);
274 return inet_pton(AF_INET6, src, &sa->in6.sin6_addr);
286 * isAF_INETx - check to see if sa is AF_INET or AF_INET6
289 isAF_INETx(const int family)
291 if (family == AF_INET
293 || family == AF_INET6
303 rangeSockAddr(const SockAddr *addr, const SockAddr *netaddr, const SockAddr *netmask)
305 if (addr->sa.sa_family == AF_INET)
306 return rangeSockAddrAF_INET(addr, netaddr, netmask);
308 else if (addr->sa.sa_family == AF_INET6)
309 return rangeSockAddrAF_INET6(addr, netaddr, netmask);
316 rangeSockAddrAF_INET(const SockAddr *addr, const SockAddr *netaddr,
317 const SockAddr *netmask)
319 if (addr->sa.sa_family != AF_INET ||
320 netaddr->sa.sa_family != AF_INET ||
321 netmask->sa.sa_family != AF_INET)
323 if (((addr->in.sin_addr.s_addr ^ netaddr->in.sin_addr.s_addr) &
324 netmask->in.sin_addr.s_addr) == 0)
332 rangeSockAddrAF_INET6(const SockAddr *addr, const SockAddr *netaddr,
333 const SockAddr *netmask)
337 if (IN6_IS_ADDR_V4MAPPED(&addr->in6.sin6_addr))
341 convSockAddr6to4(addr, &addr4);
342 if (rangeSockAddrAF_INET(&addr4, netaddr, netmask))
346 if (netaddr->sa.sa_family != AF_INET6 ||
347 netmask->sa.sa_family != AF_INET6)
350 for (i = 0; i < 16; i++)
352 if (((addr->in6.sin6_addr.s6_addr[i] ^ netaddr->in6.sin6_addr.s6_addr[i]) &
353 netmask->in6.sin6_addr.s6_addr[i]) != 0)
361 convSockAddr6to4(const SockAddr *src, SockAddr *dst)
363 char addr_str[INET6_ADDRSTRLEN];
365 dst->in.sin_family = AF_INET;
366 dst->in.sin_port = src->in6.sin6_port;
368 dst->in.sin_addr.s_addr =
369 (src->in6.sin6_addr.s6_addr[15])
370 + (src->in6.sin6_addr.s6_addr[14] << 8)
371 + (src->in6.sin6_addr.s6_addr[13] << 16)
372 + (src->in6.sin6_addr.s6_addr[12] << 24);
373 SockAddr_ntop(src, addr_str, INET6_ADDRSTRLEN, 0);