From 9ac0c1e371a9fffda489a358e39130baf8e657aa Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Thu, 22 Oct 1998 13:16:27 +0000 Subject: [PATCH] CIDR/INET fixes from D'Arcy. --- src/backend/utils/adt/inet.c | 100 ++++++++++++---------------- src/backend/utils/adt/inet_net_ntop.c | 111 +++++++++++++++++++++++++++++-- src/backend/utils/adt/inet_net_pton.c | 121 ++++++++++++++++++++++++++++++++-- src/include/utils/builtins.h | 12 ++-- 4 files changed, 267 insertions(+), 77 deletions(-) diff --git a/src/backend/utils/adt/inet.c b/src/backend/utils/adt/inet.c index c8daa75d9e..3afdf1437e 100644 --- a/src/backend/utils/adt/inet.c +++ b/src/backend/utils/adt/inet.c @@ -3,7 +3,7 @@ * is for IP V4 CIDR notation, but prepared for V6: just * add the necessary bits where the comments indicate. * - * $Id: inet.c,v 1.11 1998/10/22 04:58:07 momjian Exp $ + * $Id: inet.c,v 1.12 1998/10/22 13:16:23 momjian Exp $ * Jon Postel RIP 16 Oct 1998 */ @@ -43,12 +43,9 @@ static int v4bitncmp(unsigned int a1, unsigned int a2, int bits); #define ip_v4addr(inetptr) \ (((inet_struct *)VARDATA(inetptr))->addr.ipv4_addr) -/* - * INET address reader. - */ - -inet * -inet_in(char *src) +/* Common input routine */ +static inet * +inet_common_in(char *src, int type) { int bits; inet *dst; @@ -57,24 +54,39 @@ inet_in(char *src) if (dst == NULL) { elog(ERROR, "unable to allocate memory in inet_in()"); - return (NULL); + return NULL; } /* First, try for an IP V4 address: */ ip_family(dst) = AF_INET; - bits = inet_net_pton(ip_family(dst), src, &ip_v4addr(dst), ip_addrsize(dst)); + bits = inet_net_pton(ip_family(dst), src, &ip_v4addr(dst), + type ? ip_addrsize(dst) : -1); if ((bits < 0) || (bits > 32)) { /* Go for an IPV6 address here, before faulting out: */ elog(ERROR, "could not parse \"%s\"", src); pfree(dst); - return (NULL); + return NULL; } VARSIZE(dst) = VARHDRSZ + ((char *) &ip_v4addr(dst) - (char *) VARDATA(dst)) + ip_addrsize(dst); ip_bits(dst) = bits; - ip_type(dst) = 0; - return (dst); + ip_type(dst) = type; + return dst; +} + +/* INET address reader. */ +inet * +inet_in(char *src) +{ + return inet_common_in(src, 0); +} + +/* CIDR address reader. */ +inet * +cidr_in(char *src) +{ + return inet_common_in(src, 1); } /* @@ -90,8 +102,14 @@ inet_out(inet *src) if (ip_family(src) == AF_INET) { /* It's an IP V4 address: */ - if (inet_net_ntop(AF_INET, &ip_v4addr(src), ip_bits(src), - tmp, sizeof(tmp)) < 0) + if (ip_type(src)) + dst = inet_cidr_ntop(AF_INET, &ip_v4addr(src), ip_bits(src), + tmp, sizeof(tmp)); + else + dst = inet_net_ntop(AF_INET, &ip_v4addr(src), ip_bits(src), + tmp, sizeof(tmp)); + + if (dst == NULL) { elog(ERROR, "unable to print address (%s)", strerror(errno)); return (NULL); @@ -101,52 +119,18 @@ inet_out(inet *src) { /* Go for an IPV6 address here, before faulting out: */ elog(ERROR, "unknown address family (%d)", ip_family(src)); - return (NULL); + return NULL; } - if (ip_type(src) == 0 && ip_bits(src) == 32 && (dst = strchr(tmp, '/')) != NULL) - *dst = 0; dst = palloc(strlen(tmp) + 1); if (dst == NULL) { elog(ERROR, "unable to allocate memory in inet_out()"); - return (NULL); + return NULL; } strcpy(dst, tmp); - return (dst); + return dst; } -/* - * CIDR uses all of INET's funcs, just has a separate input func. - */ - -inet * -cidr_in(char *src) -{ - int bits; - inet *dst; - - dst = palloc(VARHDRSZ + sizeof(inet_struct)); - if (dst == NULL) - { - elog(ERROR, "unable to allocate memory in cidr_in()"); - return (NULL); - } - /* First, try for an IP V4 address: */ - ip_family(dst) = AF_INET; - bits = inet_net_pton(ip_family(dst), src, &ip_v4addr(dst), ip_addrsize(dst)); - if ((bits < 0) || (bits > 32)) - { - /* Go for an IPV6 address here, before faulting out: */ - elog(ERROR, "could not parse \"%s\"", src); - pfree(dst); - return (NULL); - } - VARSIZE(dst) = VARHDRSZ - + ((char *) &ip_v4addr(dst) - (char *) VARDATA(dst)) - + ip_addrsize(dst); - ip_bits(dst) = bits; - return (dst); -} /* just a stub */ char * @@ -331,7 +315,7 @@ inet_host(inet *ip) /* It's an IP V4 address: */ if (inet_net_ntop(AF_INET, &ip_v4addr(ip), 32, tmp, sizeof(tmp)) < 0) { - elog(ERROR, "unable to print netmask (%s)", strerror(errno)); + elog(ERROR, "unable to print host (%s)", strerror(errno)); return (NULL); } } @@ -343,7 +327,7 @@ inet_host(inet *ip) } if ((ptr = strchr(tmp, '/')) != NULL) *ptr = 0; - len = VARHDRSZ + strlen(tmp); + len = VARHDRSZ + strlen(tmp) + 1; ret = palloc(len); if (ret == NULL) { @@ -358,7 +342,7 @@ inet_host(inet *ip) text * cidr_host(inet *ip) { - inet_host(ip); + return inet_host(ip); } int4 @@ -402,7 +386,7 @@ inet_broadcast(inet *ip) } if ((ptr = strchr(tmp, '/')) != NULL) *ptr = 0; - len = VARHDRSZ + strlen(tmp); + len = VARHDRSZ + strlen(tmp) + 1; ret = palloc(len); if (ret == NULL) { @@ -417,7 +401,7 @@ inet_broadcast(inet *ip) text * cidr_broadcast(inet *ip) { - inet_broadcast(ip); + return inet_broadcast(ip); } text * @@ -447,7 +431,7 @@ inet_netmask(inet *ip) } if ((ptr = strchr(tmp, '/')) != NULL) *ptr = 0; - len = VARHDRSZ + strlen(tmp); + len = VARHDRSZ + strlen(tmp) + 1; ret = palloc(len); if (ret == NULL) { @@ -462,7 +446,7 @@ inet_netmask(inet *ip) text * cidr_netmask(inet *ip) { - inet_netmask(ip); + return inet_netmask(ip); } /* diff --git a/src/backend/utils/adt/inet_net_ntop.c b/src/backend/utils/adt/inet_net_ntop.c index 6d835df0c0..87f14dec94 100644 --- a/src/backend/utils/adt/inet_net_ntop.c +++ b/src/backend/utils/adt/inet_net_ntop.c @@ -16,7 +16,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.2 1998/10/04 15:35:08 momjian Exp $"; +static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.3 1998/10/22 13:16:25 momjian Exp $"; #endif @@ -41,10 +41,12 @@ static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.2 1998/10/04 15:35:08 momj static char *inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size); +static char *inet_cidr_ntop_ipv4(const u_char *src, int bits, + char *dst, size_t size); /* * char * - * inet_net_ntop(af, src, bits, dst, size) + * inet_cidr_ntop(af, src, bits, dst, size) * convert network number from network to presentation format. * generates CIDR style result always. * return: @@ -53,21 +55,22 @@ static char *inet_net_ntop_ipv4(const u_char *src, int bits, * Paul Vixie (ISC), July 1996 */ char * -inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size) +inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size) { switch (af) { case AF_INET: - return (inet_net_ntop_ipv4(src, bits, dst, size)); + return (inet_cidr_ntop_ipv4(src, bits, dst, size)); default: errno = EAFNOSUPPORT; return (NULL); } } + /* * static char * - * inet_net_ntop_ipv4(src, bits, dst, size) + * inet_cidr_ntop_ipv4(src, bits, dst, size) * convert IPv4 network number from network to presentation format. * generates CIDR style result always. * return: @@ -79,7 +82,7 @@ inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size) * Paul Vixie (ISC), July 1996 */ static char * -inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) +inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) { char *odst = dst; char *t; @@ -138,3 +141,99 @@ emsgsize: errno = EMSGSIZE; return (NULL); } + + +/* + * char * + * inet_net_ntop(af, src, bits, dst, size) + * convert host/network address from network to presentation format. + * "src"'s size is determined from its "af". + * return: + * pointer to dst, or NULL if an error occurred (check errno). + * note: + * 192.5.5.1/28 has a nonzero host part, which means it isn't a network + * as called for by inet_net_pton() but it can be a host address with + * an included netmask. + * author: + * Paul Vixie (ISC), October 1998 + */ +char * +inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size) +{ + switch (af) + { + case AF_INET: + return (inet_net_ntop_ipv4(src, bits, dst, size)); + default: + errno = EAFNOSUPPORT; + return (NULL); + } +} + +/* + * static char * + * inet_net_ntop_ipv4(src, bits, dst, size) + * convert IPv4 network address from network to presentation format. + * "src"'s size is determined from its "af". + * return: + * pointer to dst, or NULL if an error occurred (check errno). + * note: + * network byte order assumed. this means 192.5.5.240/28 has + * 0b11110000 in its fourth octet. + * author: + * Paul Vixie (ISC), October 1998 + */ +static char * +inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) +{ + char *odst = dst; + char *t; + size_t len = 4; + u_int m; + int b, tb; + + if (bits < 0 || bits > 32) + { + errno = EINVAL; + return (NULL); + } + if (bits == 0) + { + if (size < sizeof "0") + goto emsgsize; + *dst++ = '0'; + size--; + *dst = '\0'; + } + + /* Format whole octets plus nonzero trailing octets. */ + tb = (bits == 32) ? 31 : bits; + for (b = 0; b <= (tb / 8) || (b < len && *src != 0); b++) + { + if (size < sizeof "255.") + goto emsgsize; + t = dst; + dst += SPRINTF((dst, "%u", *src++)); + if (b + 1 <= (tb / 8) || (b + 1 < len && *src != 0)) + { + *dst++ = '.'; + *dst = '\0'; + } + size -= (size_t)(dst - t); + } + + /* don't print masklen if 32 bits */ + if (bits == 32) + return odst; + + /* Format CIDR /width. */ + if (size < sizeof "/32") + goto emsgsize; + dst += SPRINTF((dst, "/%u", bits)); + + return (odst); + + emsgsize: + errno = EMSGSIZE; + return (NULL); +} diff --git a/src/backend/utils/adt/inet_net_pton.c b/src/backend/utils/adt/inet_net_pton.c index af34a15e59..bd07e32fd2 100644 --- a/src/backend/utils/adt/inet_net_pton.c +++ b/src/backend/utils/adt/inet_net_pton.c @@ -16,7 +16,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static const char rcsid[] = "$Id: inet_net_pton.c,v 1.5 1998/10/17 03:59:14 momjian Exp $"; +static const char rcsid[] = "$Id: inet_net_pton.c,v 1.6 1998/10/22 13:16:26 momjian Exp $"; #endif @@ -41,7 +41,8 @@ static const char rcsid[] = "$Id: inet_net_pton.c,v 1.5 1998/10/17 03:59:14 momj #define SPRINTF(x) ((size_t)sprintf x) #endif -static int inet_net_pton_ipv4(const char *src, u_char *dst, size_t size); +static int inet_net_pton_ipv4(const char *src, u_char *dst); +static int inet_cidr_pton_ipv4(const char *src, u_char *dst, size_t size); /* * static int @@ -55,6 +56,11 @@ static int inet_net_pton_ipv4(const char *src, u_char *dst, size_t size); * not a valid network specification. * author: * Paul Vixie (ISC), June 1996 + * + * Changes: + * I added the inet_cidr_pton function (also from Paul) and changed + * the names to reflect their current use. + * */ int inet_net_pton(int af, const char *src, void *dst, size_t size) @@ -62,7 +68,9 @@ inet_net_pton(int af, const char *src, void *dst, size_t size) switch (af) { case AF_INET: - return (inet_net_pton_ipv4(src, dst, size)); + return size == -1 ? + inet_net_pton_ipv4(src, dst) : + inet_cidr_pton_ipv4(src, dst, size); default: errno = EAFNOSUPPORT; return (-1); @@ -71,7 +79,7 @@ inet_net_pton(int af, const char *src, void *dst, size_t size) /* * static int - * inet_net_pton_ipv4(src, dst, size) + * inet_cidr_pton_ipv4(src, dst, size) * convert IPv4 network number from presentation to network format. * accepts hex octets, hex strings, decimal octets, and /CIDR. * "size" is in bytes and describes "dst". @@ -86,7 +94,7 @@ inet_net_pton(int af, const char *src, void *dst, size_t size) * Paul Vixie (ISC), June 1996 */ static int -inet_net_pton_ipv4(const char *src, u_char *dst, size_t size) +inet_cidr_pton_ipv4(const char *src, u_char *dst, size_t size) { static const char xdigits[] = "0123456789abcdef", @@ -221,3 +229,106 @@ emsgsize: errno = EMSGSIZE; return (-1); } + +/* + * int + * inet_net_pton(af, src, dst, *bits) + * convert network address from presentation to network format. + * accepts inet_pton()'s input for this "af" plus trailing "/CIDR". + * "dst" is assumed large enough for its "af". "bits" is set to the + * /CIDR prefix length, which can have defaults (like /32 for IPv4). + * return: + * -1 if an error occurred (inspect errno; ENOENT means bad format). + * 0 if successful conversion occurred. + * note: + * 192.5.5.1/28 has a nonzero host part, which means it isn't a network + * as called for by inet_cidr_pton() but it can be a host address with + * an included netmask. + * author: + * Paul Vixie (ISC), October 1998 + */ +static int +inet_net_pton_ipv4(const char *src, u_char *dst) +{ + static const char digits[] = "0123456789"; + const u_char *odst = dst; + int n, ch, tmp, bits; + size_t size = 4; + + /* Get the mantissa. */ + while (ch = *src++, (isascii(ch) && isdigit(ch))) + { + tmp = 0; + do + { + n = strchr(digits, ch) - digits; + assert(n >= 0 && n <= 9); + tmp *= 10; + tmp += n; + if (tmp > 255) + goto enoent; + } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch)); + if (size-- == 0) + goto emsgsize; + *dst++ = (u_char) tmp; + if (ch == '\0' || ch == '/') + break; + if (ch != '.') + goto enoent; + } + + /* Get the prefix length if any. */ + bits = -1; + if (ch == '/' && isascii(src[0]) && isdigit(src[0]) && dst > odst) + { + /* CIDR width specifier. Nothing can follow it. */ + ch = *src++; /* Skip over the /. */ + bits = 0; + do + { + n = strchr(digits, ch) - digits; + assert(n >= 0 && n <= 9); + bits *= 10; + bits += n; + } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch)); + if (ch != '\0') + goto enoent; + if (bits > 32) + goto emsgsize; + } + + /* Firey death and destruction unless we prefetched EOS. */ + if (ch != '\0') + goto enoent; + + /* Prefix length can default to /32 only if all four octets spec'd. */ + if (bits == -1) + { + if (dst - odst == 4) + bits = 32; + else + goto enoent; + } + + /* If nothing was written to the destination, we found no address. */ + if (dst == odst) + goto enoent; + + /* If prefix length overspecifies mantissa, life is bad. */ + if ((bits / 8) > (dst - odst)) + goto enoent; + + /* Extend address to four octets. */ + while (size-- > 0) + *dst++ = 0; + + return bits; + + enoent: + errno = ENOENT; + return (-1); + + emsgsize: + errno = EMSGSIZE; + return (-1); +} diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 430303b28d..c6b4a816bc 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: builtins.h,v 1.65 1998/10/22 04:58:11 momjian Exp $ + * $Id: builtins.h,v 1.66 1998/10/22 13:16:27 momjian Exp $ * * NOTES * This should normally only be included by fmgr.h. @@ -511,20 +511,16 @@ extern text *translate(text *string, char from, char to); /* inet_net_ntop.c */ char *inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size); +char *inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size); /* inet_net_pton.c */ int inet_net_pton(int af, const char *src, void *dst, size_t size); -char *inet_cidr_ntop(int af, const void *src, size_t len, int bits, char *dst, size_t size); -int inet_cidr_pton(int af, const void *src, void *dst, size_t size, int *used); - -/* cidr.c */ -inet *cidr_in(char *str); -char *cidr_out(inet *addr); - /* inet.c */ inet *inet_in(char *str); char *inet_out(inet * addr); +inet *cidr_in(char *str); +char *cidr_out(inet *addr); bool inet_lt(inet * a1, inet * a2); bool inet_le(inet * a1, inet * a2); bool inet_eq(inet * a1, inet * a2); -- 2.11.0