Re: IPV4 addresses on IPV6 machines in pg_hba.conf - Mailing list pgsql-patches
From | Tom Lane |
---|---|
Subject | Re: IPV4 addresses on IPV6 machines in pg_hba.conf |
Date | |
Msg-id | 14993.1062794082@sss.pgh.pa.us Whole thread Raw |
In response to | Re: IPV4 addresses on IPV6 machines in pg_hba.conf (Andreas Pflug <pgadmin@pse-consulting.de>) |
Responses |
Re: IPV4 addresses on IPV6 machines in pg_hba.conf
|
List | pgsql-patches |
Andreas Pflug <pgadmin@pse-consulting.de> writes: > Andrew Dunstan wrote: >> You should check that the CIDR mask is a valid integer. You would need >> to use strtol() rather than atoi() to do that. Perhaps this should be >> hoisted out of ip.c:SockAddr_cidr_mask() and put in hba.c. > Right, I added this. I thought this was still really messy, so I modified it to use a separate "promote v4 address to v6" subroutine. I've applied the attached patch (plus docs). It's not very well tested since I don't have an IPv6 setup here; please check that it does what you want. regards, tom lane *** src/backend/libpq/hba.c.orig Fri Sep 5 10:35:54 2003 --- src/backend/libpq/hba.c Fri Sep 5 16:24:41 2003 *************** *** 673,685 **** if (cidr_slash) *cidr_slash = '/'; - if (file_ip_addr->ai_family != port->raddr.addr.ss_family) - { - /* Wrong address family. */ - freeaddrinfo_all(hints.ai_family, file_ip_addr); - return; - } - /* Get the netmask */ if (cidr_slash) { --- 673,678 ---- *************** *** 703,708 **** --- 696,723 ---- if (file_ip_addr->ai_family != mask->ss_family) goto hba_syntax; + } + + if (file_ip_addr->ai_family != port->raddr.addr.ss_family) + { + /* + * Wrong address family. We allow only one case: if the + * file has IPv4 and the port is IPv6, promote the file + * address to IPv6 and try to match that way. + */ + #ifdef HAVE_IPV6 + if (file_ip_addr->ai_family == AF_INET && + port->raddr.addr.ss_family == AF_INET6) + { + promote_v4_to_v6_addr((struct sockaddr_storage *) file_ip_addr->ai_addr); + promote_v4_to_v6_mask(mask); + } + else + #endif /* HAVE_IPV6 */ + { + freeaddrinfo_all(hints.ai_family, file_ip_addr); + return; + } } /* Read the rest of the line. */ *** src/backend/libpq/ip.c.orig Sun Aug 3 23:00:36 2003 --- src/backend/libpq/ip.c Fri Sep 5 16:24:42 2003 *************** *** 34,40 **** #endif #include <arpa/inet.h> #include <sys/file.h> ! #endif #include "libpq/ip.h" --- 34,41 ---- #endif #include <arpa/inet.h> #include <sys/file.h> ! ! #endif /* !defined(_MSC_VER) && !defined(__BORLANDC__) */ #include "libpq/ip.h" *************** *** 265,273 **** --- 266,281 ---- return 0; } + #endif /* HAVE_UNIX_SOCKETS */ + /* + * rangeSockAddr - is addr within the subnet specified by netaddr/netmask ? + * + * Note: caller must already have verified that all three addresses are + * in the same address family; and AF_UNIX addresses are not supported. + */ int rangeSockAddr(const struct sockaddr_storage * addr, const struct sockaddr_storage * netaddr, *************** *** 287,292 **** --- 295,333 ---- return 0; } + static int + rangeSockAddrAF_INET(const struct sockaddr_in * addr, + const struct sockaddr_in * netaddr, + const struct sockaddr_in * netmask) + { + if (((addr->sin_addr.s_addr ^ netaddr->sin_addr.s_addr) & + netmask->sin_addr.s_addr) == 0) + return 1; + else + return 0; + } + + + #ifdef HAVE_IPV6 + static int + rangeSockAddrAF_INET6(const struct sockaddr_in6 * addr, + const struct sockaddr_in6 * netaddr, + const struct sockaddr_in6 * netmask) + { + int i; + + for (i = 0; i < 16; i++) + { + if (((addr->sin6_addr.s6_addr[i] ^ netaddr->sin6_addr.s6_addr[i]) & + netmask->sin6_addr.s6_addr[i]) != 0) + return 0; + } + + return 1; + } + + #endif + /* * SockAddr_cidr_mask - make a network mask of the appropriate family * and required number of significant bits *************** *** 358,391 **** return 0; } ! static int ! rangeSockAddrAF_INET(const struct sockaddr_in * addr, const struct sockaddr_in * netaddr, ! const struct sockaddr_in * netmask) { ! if (((addr->sin_addr.s_addr ^ netaddr->sin_addr.s_addr) & ! netmask->sin_addr.s_addr) == 0) ! return 1; ! else ! return 0; ! } ! #ifdef HAVE_IPV6 ! static int ! rangeSockAddrAF_INET6(const struct sockaddr_in6 * addr, ! const struct sockaddr_in6 * netaddr, ! const struct sockaddr_in6 * netmask) { int i; ! for (i = 0; i < 16; i++) ! { ! if (((addr->sin6_addr.s6_addr[i] ^ netaddr->sin6_addr.s6_addr[i]) & ! netmask->sin6_addr.s6_addr[i]) != 0) ! return 0; ! } ! return 1; } ! #endif --- 399,472 ---- return 0; } ! ! #ifdef HAVE_IPV6 ! ! /* ! * promote_v4_to_v6_addr --- convert an AF_INET addr to AF_INET6, using ! * the standard convention for IPv4 addresses mapped into IPv6 world ! * ! * The passed addr is modified in place. Note that we only worry about ! * setting the fields that rangeSockAddr will look at. ! */ ! void ! promote_v4_to_v6_addr(struct sockaddr_storage * addr) { ! struct sockaddr_in addr4; ! struct sockaddr_in6 addr6; ! uint32 s_addr; + memcpy(&addr4, addr, sizeof(addr4)); + s_addr = ntohl(addr4.sin_addr.s_addr); ! memset(&addr6, 0, sizeof(addr6)); ! ! addr6.sin6_family = AF_INET6; ! ! addr6.sin6_addr.s6_addr[10] = 0xff; ! addr6.sin6_addr.s6_addr[11] = 0xff; ! addr6.sin6_addr.s6_addr[12] = (s_addr >> 24) & 0xFF; ! addr6.sin6_addr.s6_addr[13] = (s_addr >> 16) & 0xFF; ! addr6.sin6_addr.s6_addr[14] = (s_addr >> 8) & 0xFF; ! addr6.sin6_addr.s6_addr[15] = (s_addr) & 0xFF; ! ! memcpy(addr, &addr6, sizeof(addr6)); ! } ! ! /* ! * promote_v4_to_v6_mask --- convert an AF_INET netmask to AF_INET6, using ! * the standard convention for IPv4 addresses mapped into IPv6 world ! * ! * This must be different from promote_v4_to_v6_addr because we want to ! * set the high-order bits to 1's not 0's. ! * ! * The passed addr is modified in place. Note that we only worry about ! * setting the fields that rangeSockAddr will look at. ! */ ! void ! promote_v4_to_v6_mask(struct sockaddr_storage * addr) { + struct sockaddr_in addr4; + struct sockaddr_in6 addr6; + uint32 s_addr; int i; ! memcpy(&addr4, addr, sizeof(addr4)); ! s_addr = ntohl(addr4.sin_addr.s_addr); ! memset(&addr6, 0, sizeof(addr6)); ! ! addr6.sin6_family = AF_INET6; ! ! for (i = 0; i < 12; i++) ! addr6.sin6_addr.s6_addr[i] = 0xff; ! ! addr6.sin6_addr.s6_addr[12] = (s_addr >> 24) & 0xFF; ! addr6.sin6_addr.s6_addr[13] = (s_addr >> 16) & 0xFF; ! addr6.sin6_addr.s6_addr[14] = (s_addr >> 8) & 0xFF; ! addr6.sin6_addr.s6_addr[15] = (s_addr) & 0xFF; ! ! memcpy(addr, &addr6, sizeof(addr6)); } ! #endif /* HAVE_IPV6 */ *** src/include/libpq/ip.h.orig Sun Aug 3 23:01:33 2003 --- src/include/libpq/ip.h Fri Sep 5 16:24:36 2003 *************** *** 33,38 **** --- 33,43 ---- extern int SockAddr_cidr_mask(struct sockaddr_storage ** mask, char *numbits, int family); + #ifdef HAVE_IPV6 + extern void promote_v4_to_v6_addr(struct sockaddr_storage * addr); + extern void promote_v4_to_v6_mask(struct sockaddr_storage * addr); + #endif + #ifdef HAVE_UNIX_SOCKETS #define IS_AF_UNIX(fam) ((fam) == AF_UNIX) #else
pgsql-patches by date: