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.3 2003/03/29 11:31:51 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)
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,
57 const struct addrinfo *hintp, struct addrinfo **result)
59 #ifdef HAVE_UNIX_SOCKETS
60 if (hintp != NULL && hintp->ai_family == AF_UNIX)
61 return getaddrinfo_unix(servname, hintp, result);
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
70 #endif /* HAVE_UNIX_SOCKETS */
75 * freeaddrinfo2 - free IPv6 addrinfo structures
78 freeaddrinfo2(int hint_ai_family, struct addrinfo *ai)
80 #ifdef HAVE_UNIX_SOCKETS
81 if (hint_ai_family == AF_UNIX)
94 #endif /* HAVE_UNIX_SOCKETS */
99 #if defined(HAVE_UNIX_SOCKETS)
101 * getaddrinfo_unix - get unix socket info using IPv6
103 * Bug: only one addrinfo is set even though hintsp is NULL or
105 * AI_CANNONNAME does not support.
109 getaddrinfo_unix(const char *path, const struct addrinfo *hintsp,
110 struct addrinfo **result)
112 struct addrinfo hints;
113 struct addrinfo *aip;
114 struct sockaddr_un *unp;
116 MemSet(&hints, 0, sizeof(hints));
120 hints.ai_family = AF_UNIX;
121 hints.ai_socktype = SOCK_STREAM;
124 memcpy(&hints, hintsp, sizeof(hints));
126 if (hints.ai_socktype == 0)
127 hints.ai_socktype = SOCK_STREAM;
129 if (hints.ai_family != AF_UNIX)
131 elog(LOG, "hints.ai_family is invalid in getaddrinfo_unix()\n");
132 return EAI_ADDRFAMILY;
135 aip = calloc(1, sizeof(struct addrinfo));
139 aip->ai_family = AF_UNIX;
140 aip->ai_socktype = hints.ai_socktype;
141 aip->ai_protocol = hints.ai_protocol;
143 aip->ai_canonname = NULL;
146 unp = calloc(1, sizeof(struct sockaddr_un));
150 unp->sun_family = AF_UNIX;
151 aip->ai_addr = (struct sockaddr *) unp;
152 aip->ai_addrlen = sizeof(struct sockaddr_un);
154 if (strlen(path) >= sizeof(unp->sun_path))
156 strcpy(unp->sun_path, path);
159 unp->sun_len = sizeof(struct sockaddr_un);
162 if (hints.ai_flags & AI_PASSIVE)
163 unlink(unp->sun_path);
167 #endif /* HAVE_UNIX_SOCKETS */
170 * SockAddr_ntop - set IP address string from SockAddr
172 * parameters... sa : SockAddr union
173 * dst : buffer for address string
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.
182 SockAddr_ntop(const SockAddr *sa, char *dst, size_t cnt, int v4conv)
184 switch (sa->sa.sa_family)
188 inet_ntop(AF_INET, &sa->in.sin_addr, dst, cnt);
190 StrNCpy(dst, inet_ntoa(sa->in.sin_addr), cnt);
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);
209 * SockAddr_pton - IPv6 pton
212 SockAddr_pton(SockAddr *sa, const char *src)
214 int family = AF_INET;
218 for (ch = src; *ch != '\0'; ch++)
228 sa->sa.sa_family = family;
234 return inet_pton(AF_INET, src, &sa->in.sin_addr);
236 return inet_aton(src, &sa->in.sin_addr);
241 return inet_pton(AF_INET6, src, &sa->in6.sin6_addr);
253 * isAF_INETx - check to see if sa is AF_INET or AF_INET6
256 isAF_INETx(const int family)
258 if (family == AF_INET
260 || family == AF_INET6
270 rangeSockAddr(const SockAddr *addr, const SockAddr *netaddr, const SockAddr *netmask)
272 if (addr->sa.sa_family == AF_INET)
273 return rangeSockAddrAF_INET(addr, netaddr, netmask);
275 else if (addr->sa.sa_family == AF_INET6)
276 return rangeSockAddrAF_INET6(addr, netaddr, netmask);
283 rangeSockAddrAF_INET(const SockAddr *addr, const SockAddr *netaddr,
284 const SockAddr *netmask)
286 if (addr->sa.sa_family != AF_INET ||
287 netaddr->sa.sa_family != AF_INET ||
288 netmask->sa.sa_family != AF_INET)
290 if (((addr->in.sin_addr.s_addr ^ netaddr->in.sin_addr.s_addr) &
291 netmask->in.sin_addr.s_addr) == 0)
299 rangeSockAddrAF_INET6(const SockAddr *addr, const SockAddr *netaddr,
300 const SockAddr *netmask)
304 if (IN6_IS_ADDR_V4MAPPED(&addr->in6.sin6_addr))
308 convSockAddr6to4(addr, &addr4);
309 if (rangeSockAddrAF_INET(&addr4, netaddr, netmask))
313 if (netaddr->sa.sa_family != AF_INET6 ||
314 netmask->sa.sa_family != AF_INET6)
317 for (i = 0; i < 16; i++)
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)
328 convSockAddr6to4(const SockAddr *src, SockAddr *dst)
330 char addr_str[INET6_ADDRSTRLEN];
332 dst->in.sin_family = AF_INET;
333 dst->in.sin_port = src->in6.sin6_port;
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);