summaryrefslogtreecommitdiff
path: root/src/backend/libpq/ip.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/libpq/ip.c')
-rw-r--r--src/backend/libpq/ip.c371
1 files changed, 371 insertions, 0 deletions
diff --git a/src/backend/libpq/ip.c b/src/backend/libpq/ip.c
new file mode 100644
index 00000000000..21f5c2fe1d5
--- /dev/null
+++ b/src/backend/libpq/ip.c
@@ -0,0 +1,371 @@
+/*-------------------------------------------------------------------------
+ *
+ * ip.c
+ * Handles IPv6
+ *
+ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/backend/libpq/ip.c,v 1.1 2003/01/06 03:18:26 momjian Exp $
+ *
+ * This file and the IPV6 implementation were initially provided by
+ * Nigel Kukard <nkukard@lbsd.net>, Linux Based Systems Design
+ * http://www.lbsd.net.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+#include <arpa/inet.h>
+#include <sys/file.h>
+
+#include "libpq/libpq.h"
+#include "miscadmin.h"
+
+#ifdef FRONTEND
+#define elog fprintf
+#define LOG stderr
+#endif
+
+#if defined(HAVE_UNIX_SOCKETS) && defined(HAVE_IPV6)
+static int getaddrinfo_unix(const char *path, const struct addrinfo *hintsp,
+ struct addrinfo **result);
+#endif /* HAVE_UNIX_SOCKETS */
+
+/*
+ * getaddrinfo2 - get address info for Unix, IPv4 and IPv6 sockets
+ */
+int
+getaddrinfo2(const char *hostname, const char *servname,
+#ifdef HAVE_IPV6
+ const struct addrinfo *hintp, struct addrinfo **result)
+#else
+ int family, SockAddr *result)
+#endif
+{
+#ifdef HAVE_UNIX_SOCKETS
+#ifdef HAVE_IPV6
+ if (hintp != NULL && hintp->ai_family == AF_UNIX)
+ return getaddrinfo_unix(servname, hintp, result);
+#else
+ if (family == AF_UNIX)
+ return 0;
+#endif
+ else
+ {
+#endif /* HAVE_UNIX_SOCKETS */
+#ifdef HAVE_IPV6
+ /* NULL has special meaning to getaddrinfo */
+ return getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname,
+ servname, hintp, result);
+#else
+ if (hostname[0] == '\0')
+ result->in.sin_addr.s_addr = htonl(INADDR_ANY);
+ else
+ {
+ struct hostent *hp;
+
+ hp = gethostbyname(hostname);
+ if ((hp == NULL) || (hp->h_addrtype != AF_INET))
+ {
+ elog(LOG, "getaddrinfo2: gethostbyname(%s) failed\n", hostname);
+ return STATUS_ERROR;
+ }
+ memmove((char *) &(result->in.sin_addr), (char *) hp->h_addr,
+ hp->h_length);
+ }
+
+ result->in.sin_port = htons((unsigned short)atoi(servname));
+ return 0;
+#endif /* HAVE_IPV6 */
+
+#ifdef HAVE_UNIX_SOCKETS
+ }
+#endif /* HAVE_UNIX_SOCKETS */
+}
+
+
+/*
+ * freeaddrinfo2 - free IPv6 addrinfo structures
+ */
+#ifdef HAVE_IPV6
+void
+freeaddrinfo2(int hint_ai_family, struct addrinfo *ai)
+{
+#ifdef HAVE_UNIX_SOCKETS
+ if (hint_ai_family == AF_UNIX)
+ {
+ struct addrinfo *p;
+
+ while (ai != NULL)
+ {
+ p = ai;
+ ai = ai->ai_next;
+ free(p->ai_addr);
+ free(p);
+ }
+ }
+ else
+#endif /* HAVE_UNIX_SOCKETS */
+ freeaddrinfo(ai);
+}
+#endif
+
+
+#if defined(HAVE_UNIX_SOCKETS) && defined(HAVE_IPV6)
+/* -------
+ * getaddrinfo_unix - get unix socket info using IPv6
+ *
+ * Bug: only one addrinfo is set even though hintsp is NULL or
+ * ai_socktype is 0
+ * AI_CANNONNAME does not support.
+ * -------
+ */
+static int
+getaddrinfo_unix(const char *path, const struct addrinfo *hintsp,
+ struct addrinfo **result)
+{
+ struct addrinfo hints;
+ struct addrinfo *aip;
+ struct sockaddr_un *unp;
+
+ MemSet(&hints, 0, sizeof(hints));
+
+ if (hintsp == NULL)
+ {
+ hints.ai_family = AF_UNIX;
+ hints.ai_socktype = SOCK_STREAM;
+ }
+ else
+ memcpy(&hints, hintsp, sizeof(hints));
+
+ if (hints.ai_socktype == 0)
+ hints.ai_socktype = SOCK_STREAM;
+
+ if (!(hints.ai_family == AF_UNIX))
+ {
+ elog(LOG, "hints.ai_family is invalied getaddrinfo_unix()\n");
+ return EAI_ADDRFAMILY;
+ }
+
+ aip = calloc(1, sizeof(struct addrinfo));
+ if (aip == NULL)
+ return EAI_MEMORY;
+
+ aip->ai_family = AF_UNIX;
+ aip->ai_socktype = hints.ai_socktype;
+ aip->ai_protocol = hints.ai_protocol;
+ aip->ai_next = NULL;
+ aip->ai_canonname = NULL;
+ *result = aip;
+
+ unp = calloc(1, sizeof(struct sockaddr_un));
+ if (aip == NULL)
+ return EAI_MEMORY;
+
+ unp->sun_family = AF_UNIX;
+ aip->ai_addr = (struct sockaddr *) unp;
+ aip->ai_addrlen = sizeof(struct sockaddr_un);
+
+ if (strlen(path) >= sizeof(unp->sun_path))
+ return EAI_SERVICE;
+ strcpy(unp->sun_path, path);
+
+#if SALEN
+ unp->sun_len = sizeof(struct sockaddr_un);
+#endif /* SALEN */
+
+ if (hints.ai_flags & AI_PASSIVE)
+ unlink(unp->sun_path);
+
+ return 0;
+}
+#endif /* HAVE_UNIX_SOCKETS && HAVE_IPV6 */
+
+/* ----------
+ * SockAddr_ntop - set IP address string from SockAddr
+ *
+ * parameters... sa : SockAddr union
+ * dst : buffer for address string
+ * cnt : sizeof dst
+ * v4conv: non-zero: if address is IPv4 mapped IPv6 address then
+ * convert to IPv4 address.
+ * returns... pointer to dst
+ * if sa.sa_family is not AF_INET or AF_INET6 dst is set as empy string.
+ * ----------
+ */
+char *
+SockAddr_ntop(const SockAddr *sa, char *dst, size_t cnt, int v4conv)
+{
+ switch (sa->sa.sa_family)
+ {
+ case AF_INET:
+#ifdef HAVE_IPV6
+ inet_ntop(AF_INET, &sa->in.sin_addr, dst, cnt);
+#else
+ StrNCpy(dst, inet_ntoa(sa->in.sin_addr), cnt);
+#endif
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ inet_ntop(AF_INET6, &sa->in6.sin6_addr, dst, cnt);
+ if (v4conv && IN6_IS_ADDR_V4MAPPED(&sa->in6.sin6_addr))
+ strcpy(dst, dst + 7);
+ break;
+#endif
+ default:
+ dst[0] = '\0';
+ break;
+ }
+ return dst;
+}
+
+
+/*
+ * SockAddr_pton - IPv6 pton
+ */
+int
+SockAddr_pton(SockAddr *sa, const char *src)
+{
+ int family = AF_INET;
+#ifdef HAVE_IPV6
+ const char *ch;
+
+ for (ch = src; *ch != '\0'; ch++)
+ {
+ if (*ch == ':')
+ {
+ family = AF_INET6;
+ break;
+ }
+ }
+#endif
+
+ sa->sa.sa_family = family;
+
+ switch (family)
+ {
+ case AF_INET:
+#ifdef HAVE_IPV6
+ return inet_pton(AF_INET, src, &sa->in.sin_addr);
+#else
+ return inet_aton(src, &sa->in.sin_addr);
+#endif
+
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ return inet_pton(AF_INET6, src, &sa->in6.sin6_addr);
+ break;
+#endif
+ default:
+ return -1;
+ }
+}
+
+
+
+
+/*
+ * isAF_INETx - check to see if sa is AF_INET or AF_INET6
+ */
+int
+isAF_INETx(const int family)
+{
+ if (family == AF_INET
+#ifdef HAVE_IPV6
+ || family == AF_INET6
+#endif
+ )
+ return 1;
+ else
+ return 0;
+}
+
+
+int
+rangeSockAddr(const SockAddr *addr, const SockAddr *netaddr, const SockAddr *netmask)
+{
+ if (addr->sa.sa_family == AF_INET)
+ return rangeSockAddrAF_INET(addr, netaddr, netmask);
+#ifdef HAVE_IPV6
+ else if (addr->sa.sa_family == AF_INET6)
+ return rangeSockAddrAF_INET6(addr, netaddr, netmask);
+#endif
+ else
+ return 0;
+}
+
+int
+rangeSockAddrAF_INET(const SockAddr *addr, const SockAddr *netaddr,
+ const SockAddr *netmask)
+{
+ if (addr->sa.sa_family != AF_INET ||
+ netaddr->sa.sa_family != AF_INET ||
+ netmask->sa.sa_family != AF_INET)
+ return 0;
+ if (((addr->in.sin_addr.s_addr ^ netaddr->in.sin_addr.s_addr) &
+ netmask->in.sin_addr.s_addr) == 0)
+ return 1;
+ else
+ return 0;
+}
+
+#ifdef HAVE_IPV6
+int
+rangeSockAddrAF_INET6(const SockAddr *addr, const SockAddr *netaddr,
+ const SockAddr *netmask)
+{
+ int i;
+
+ if (IN6_IS_ADDR_V4MAPPED(&addr->in6.sin6_addr))
+ {
+ SockAddr addr4;
+
+ convSockAddr6to4(addr, &addr4);
+ if (rangeSockAddrAF_INET(&addr4, netaddr, netmask))
+ return 1;
+ }
+
+ if (netaddr->sa.sa_family != AF_INET6 ||
+ netmask->sa.sa_family != AF_INET6)
+ return 0;
+
+ for (i = 0; i < 16; i++)
+ {
+ if (((addr->in6.sin6_addr.s6_addr[i] ^ netaddr->in6.sin6_addr.s6_addr[i]) &
+ netmask->in6.sin6_addr.s6_addr[i]) != 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+void
+convSockAddr6to4(const SockAddr *src, SockAddr *dst)
+{
+ char addr_str[INET6_ADDRSTRLEN];
+
+ dst->in.sin_family = AF_INET;
+ dst->in.sin_port = src->in6.sin6_port;
+
+ dst->in.sin_addr.s_addr = src->in6.sin6_addr.s6_addr32[3];
+ SockAddr_ntop(src, addr_str, INET6_ADDRSTRLEN, 0);
+}
+#endif