diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:17:33 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:17:33 +0000 |
commit | 5e45211a64149b3c659b90ff2de6fa982a5a93ed (patch) | |
tree | 739caf8c461053357daa9f162bef34516c7bf452 /src/port/inet_net_ntop.c | |
parent | Initial commit. (diff) | |
download | postgresql-15-5e45211a64149b3c659b90ff2de6fa982a5a93ed.tar.xz postgresql-15-5e45211a64149b3c659b90ff2de6fa982a5a93ed.zip |
Adding upstream version 15.5.upstream/15.5
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/port/inet_net_ntop.c')
-rw-r--r-- | src/port/inet_net_ntop.c | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/src/port/inet_net_ntop.c b/src/port/inet_net_ntop.c new file mode 100644 index 0000000..b8ad69c --- /dev/null +++ b/src/port/inet_net_ntop.c @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1996,1999 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * src/port/inet_net_ntop.c + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "Id: inet_net_ntop.c,v 1.1.2.2 2004/03/09 09:17:27 marka Exp $"; +#endif + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#ifndef FRONTEND +#include "utils/inet.h" +#else +/* + * In a frontend build, we can't include inet.h, but we still need to have + * sensible definitions of these two constants. Note that pg_inet_net_ntop() + * assumes that PGSQL_AF_INET is equal to AF_INET. + */ +#define PGSQL_AF_INET (AF_INET + 0) +#define PGSQL_AF_INET6 (AF_INET + 1) +#endif + + +#define NS_IN6ADDRSZ 16 +#define NS_INT16SZ 2 + +#ifdef SPRINTF_CHAR +#define SPRINTF(x) strlen(sprintf/**/x) +#else +#define SPRINTF(x) ((size_t)sprintf x) +#endif + +static char *inet_net_ntop_ipv4(const u_char *src, int bits, + char *dst, size_t size); +static char *inet_net_ntop_ipv6(const u_char *src, int bits, + char *dst, size_t size); + + +/* + * char * + * pg_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 pg_inet_net_pton() but it can be a host address with + * an included netmask. + * author: + * Paul Vixie (ISC), October 1998 + */ +char * +pg_inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size) +{ + /* + * We need to cover both the address family constants used by the PG inet + * type (PGSQL_AF_INET and PGSQL_AF_INET6) and those used by the system + * libraries (AF_INET and AF_INET6). We can safely assume PGSQL_AF_INET + * == AF_INET, but the INET6 constants are very likely to be different. If + * AF_INET6 isn't defined, silently ignore it. + */ + switch (af) + { + case PGSQL_AF_INET: + return (inet_net_ntop_ipv4(src, bits, dst, size)); + case PGSQL_AF_INET6: +#if defined(AF_INET6) && AF_INET6 != PGSQL_AF_INET6 + case AF_INET6: +#endif + return (inet_net_ntop_ipv6(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; + int len = 4; + int b; + + if (bits < 0 || bits > 32) + { + errno = EINVAL; + return (NULL); + } + + /* Always format all four octets, regardless of mask length. */ + for (b = len; b > 0; b--) + { + if (size <= sizeof ".255") + goto emsgsize; + t = dst; + if (dst != odst) + *dst++ = '.'; + dst += SPRINTF((dst, "%u", *src++)); + size -= (size_t) (dst - t); + } + + /* don't print masklen if 32 bits */ + if (bits != 32) + { + if (size <= sizeof "/32") + goto emsgsize; + dst += SPRINTF((dst, "/%u", bits)); + } + + return (odst); + +emsgsize: + errno = EMSGSIZE; + return (NULL); +} + +static int +decoct(const u_char *src, int bytes, char *dst, size_t size) +{ + char *odst = dst; + char *t; + int b; + + for (b = 1; b <= bytes; b++) + { + if (size <= sizeof "255.") + return (0); + t = dst; + dst += SPRINTF((dst, "%u", *src++)); + if (b != bytes) + { + *dst++ = '.'; + *dst = '\0'; + } + size -= (size_t) (dst - t); + } + return (dst - odst); +} + +static char * +inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) +{ + /* + * Note that int32_t and int16_t need only be "at least" large enough to + * contain a value of the specified size. On some systems, like Crays, + * there is no such thing as an integer variable with 16 bits. Keep this + * in mind if you think this function should have been coded to use + * pointer overlays. All the world's not a VAX. + */ + char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"]; + char *tp; + struct + { + int base, + len; + } best, cur; + u_int words[NS_IN6ADDRSZ / NS_INT16SZ]; + int i; + + if ((bits < -1) || (bits > 128)) + { + errno = EINVAL; + return (NULL); + } + + /* + * Preprocess: Copy the input (bytewise) array into a wordwise array. Find + * the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, '\0', sizeof words); + for (i = 0; i < NS_IN6ADDRSZ; i++) + words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); + best.base = -1; + cur.base = -1; + best.len = 0; + cur.len = 0; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) + { + if (words[i] == 0) + { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } + else + { + if (cur.base != -1) + { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) + { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + if (best.base != -1 && best.len < 2) + best.base = -1; + + /* + * Format the result. + */ + tp = tmp; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) + { + /* Are we inside the best run of 0x00's? */ + if (best.base != -1 && i >= best.base && + i < (best.base + best.len)) + { + if (i == best.base) + *tp++ = ':'; + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) + *tp++ = ':'; + /* Is this address an encapsulated IPv4? */ + if (i == 6 && best.base == 0 && (best.len == 6 || + (best.len == 7 && words[7] != 0x0001) || + (best.len == 5 && words[5] == 0xffff))) + { + int n; + + n = decoct(src + 12, 4, tp, sizeof tmp - (tp - tmp)); + if (n == 0) + { + errno = EMSGSIZE; + return (NULL); + } + tp += strlen(tp); + break; + } + tp += SPRINTF((tp, "%x", words[i])); + } + + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && (best.base + best.len) == + (NS_IN6ADDRSZ / NS_INT16SZ)) + *tp++ = ':'; + *tp = '\0'; + + if (bits != -1 && bits != 128) + tp += SPRINTF((tp, "/%u", bits)); + + /* + * Check for overflow, copy, and we're done. + */ + if ((size_t) (tp - tmp) > size) + { + errno = EMSGSIZE; + return (NULL); + } + strcpy(dst, tmp); + return (dst); +} |