1998-10-03 07:41:01 +02:00
|
|
|
/*
|
2005-02-01 01:59:09 +01:00
|
|
|
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
|
|
|
|
* Copyright (c) 1996,1999 by Internet Software Consortium.
|
1998-10-03 07:41:01 +02:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
2005-02-01 01:59:09 +01:00
|
|
|
* 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.
|
2003-11-10 20:40:46 +01:00
|
|
|
*
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/utils/adt/inet_net_ntop.c
|
1998-10-03 07:41:01 +02:00
|
|
|
*/
|
|
|
|
|
2005-02-01 01:59:09 +01:00
|
|
|
#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
|
|
|
|
|
2002-09-02 04:47:07 +02:00
|
|
|
#include "postgres.h"
|
|
|
|
|
1998-10-03 07:41:01 +02:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
2006-07-14 18:59:19 +02:00
|
|
|
#include "utils/builtins.h"
|
2003-06-25 00:21:24 +02:00
|
|
|
#include "utils/inet.h"
|
1998-10-04 17:35:12 +02:00
|
|
|
|
2005-02-01 01:59:09 +01:00
|
|
|
|
1998-10-03 07:41:01 +02:00
|
|
|
#ifdef SPRINTF_CHAR
|
|
|
|
#define SPRINTF(x) strlen(sprintf/**/x)
|
|
|
|
#else
|
|
|
|
#define SPRINTF(x) ((size_t)sprintf x)
|
|
|
|
#endif
|
|
|
|
|
1998-10-22 15:16:27 +02:00
|
|
|
static char *inet_cidr_ntop_ipv4(const u_char *src, int bits,
|
2003-08-04 02:43:34 +02:00
|
|
|
char *dst, size_t size);
|
2003-06-25 00:21:24 +02:00
|
|
|
static char *inet_cidr_ntop_ipv6(const u_char *src, int bits,
|
2003-08-04 02:43:34 +02:00
|
|
|
char *dst, size_t size);
|
1998-10-03 07:41:01 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* char *
|
1998-10-22 15:16:27 +02:00
|
|
|
* inet_cidr_ntop(af, src, bits, dst, size)
|
1998-10-03 07:41:01 +02:00
|
|
|
* convert network number from network to presentation format.
|
|
|
|
* generates CIDR style result always.
|
|
|
|
* return:
|
|
|
|
* pointer to dst, or NULL if an error occurred (check errno).
|
|
|
|
* author:
|
|
|
|
* Paul Vixie (ISC), July 1996
|
|
|
|
*/
|
|
|
|
char *
|
1998-10-22 15:16:27 +02:00
|
|
|
inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size)
|
1998-10-03 07:41:01 +02:00
|
|
|
{
|
|
|
|
switch (af)
|
|
|
|
{
|
2003-06-25 00:21:24 +02:00
|
|
|
case PGSQL_AF_INET:
|
1998-10-22 15:16:27 +02:00
|
|
|
return (inet_cidr_ntop_ipv4(src, bits, dst, size));
|
2003-06-25 00:21:24 +02:00
|
|
|
case PGSQL_AF_INET6:
|
|
|
|
return (inet_cidr_ntop_ipv6(src, bits, dst, size));
|
1998-10-03 07:41:01 +02:00
|
|
|
default:
|
|
|
|
errno = EAFNOSUPPORT;
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-10-22 15:16:27 +02:00
|
|
|
|
1998-10-03 07:41:01 +02:00
|
|
|
/*
|
|
|
|
* static char *
|
1998-10-22 15:16:27 +02:00
|
|
|
* inet_cidr_ntop_ipv4(src, bits, dst, size)
|
1998-10-03 07:41:01 +02:00
|
|
|
* convert IPv4 network number from network to presentation format.
|
|
|
|
* generates CIDR style result always.
|
|
|
|
* 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
|
2005-02-01 01:59:09 +01:00
|
|
|
* 0b11110000 in its fourth octet.
|
1998-10-03 07:41:01 +02:00
|
|
|
* author:
|
|
|
|
* Paul Vixie (ISC), July 1996
|
|
|
|
*/
|
|
|
|
static char *
|
1998-10-22 15:16:27 +02:00
|
|
|
inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
|
1998-10-03 07:41:01 +02:00
|
|
|
{
|
|
|
|
char *odst = dst;
|
|
|
|
char *t;
|
|
|
|
u_int m;
|
|
|
|
int b;
|
|
|
|
|
|
|
|
if (bits < 0 || bits > 32)
|
|
|
|
{
|
|
|
|
errno = EINVAL;
|
|
|
|
return (NULL);
|
|
|
|
}
|
2005-02-01 01:59:09 +01:00
|
|
|
|
1998-10-03 07:41:01 +02:00
|
|
|
if (bits == 0)
|
|
|
|
{
|
|
|
|
if (size < sizeof "0")
|
|
|
|
goto emsgsize;
|
|
|
|
*dst++ = '0';
|
2005-02-01 01:59:09 +01:00
|
|
|
size--;
|
1998-10-03 07:41:01 +02:00
|
|
|
*dst = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Format whole octets. */
|
|
|
|
for (b = bits / 8; b > 0; b--)
|
|
|
|
{
|
2005-02-01 01:59:09 +01:00
|
|
|
if (size <= sizeof "255.")
|
1998-10-03 07:41:01 +02:00
|
|
|
goto emsgsize;
|
|
|
|
t = dst;
|
2000-11-10 21:13:27 +01:00
|
|
|
dst += SPRINTF((dst, "%u", *src++));
|
2005-02-01 01:59:09 +01:00
|
|
|
if (b > 1)
|
|
|
|
{
|
|
|
|
*dst++ = '.';
|
|
|
|
*dst = '\0';
|
|
|
|
}
|
1998-10-03 07:41:01 +02:00
|
|
|
size -= (size_t) (dst - t);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Format partial octet. */
|
|
|
|
b = bits % 8;
|
|
|
|
if (b > 0)
|
|
|
|
{
|
2005-02-01 01:59:09 +01:00
|
|
|
if (size <= sizeof ".255")
|
1998-10-03 07:41:01 +02:00
|
|
|
goto emsgsize;
|
|
|
|
t = dst;
|
|
|
|
if (dst != odst)
|
|
|
|
*dst++ = '.';
|
|
|
|
m = ((1 << b) - 1) << (8 - b);
|
|
|
|
dst += SPRINTF((dst, "%u", *src & m));
|
|
|
|
size -= (size_t) (dst - t);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Format CIDR /width. */
|
2005-02-01 01:59:09 +01:00
|
|
|
if (size <= sizeof "/32")
|
1998-10-03 07:41:01 +02:00
|
|
|
goto emsgsize;
|
|
|
|
dst += SPRINTF((dst, "/%u", bits));
|
|
|
|
return (odst);
|
|
|
|
|
|
|
|
emsgsize:
|
|
|
|
errno = EMSGSIZE;
|
|
|
|
return (NULL);
|
|
|
|
}
|
1998-10-22 15:16:27 +02:00
|
|
|
|
2003-06-25 00:21:24 +02:00
|
|
|
/*
|
|
|
|
* static char *
|
2005-02-01 01:59:09 +01:00
|
|
|
* inet_cidr_ntop_ipv6(src, bits, fakebits, dst, size)
|
2003-06-25 00:21:24 +02:00
|
|
|
* convert IPv6 network number from network to presentation format.
|
|
|
|
* generates CIDR style result always. Picks the shortest representation
|
|
|
|
* unless the IP is really IPv4.
|
|
|
|
* always prints specified number of bits (bits).
|
|
|
|
* 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
|
|
|
|
* 0x11110000 in its fourth octet.
|
|
|
|
* author:
|
|
|
|
* Vadim Kogan (UCB), June 2001
|
2003-08-04 02:43:34 +02:00
|
|
|
* Original version (IPv4) by Paul Vixie (ISC), July 1996
|
2003-06-25 00:21:24 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
static char *
|
|
|
|
inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size)
|
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
u_int m;
|
|
|
|
int b;
|
|
|
|
int p;
|
|
|
|
int zero_s,
|
|
|
|
zero_l,
|
|
|
|
tmp_zero_s,
|
|
|
|
tmp_zero_l;
|
|
|
|
int i;
|
|
|
|
int is_ipv4 = 0;
|
2003-06-25 00:21:24 +02:00
|
|
|
unsigned char inbuf[16];
|
2003-08-04 02:43:34 +02:00
|
|
|
char outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
|
|
|
|
char *cp;
|
|
|
|
int words;
|
|
|
|
u_char *s;
|
2003-06-25 00:21:24 +02:00
|
|
|
|
2003-08-04 02:43:34 +02:00
|
|
|
if (bits < 0 || bits > 128)
|
|
|
|
{
|
2003-06-25 00:21:24 +02:00
|
|
|
errno = EINVAL;
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
cp = outbuf;
|
|
|
|
|
2003-08-04 02:43:34 +02:00
|
|
|
if (bits == 0)
|
|
|
|
{
|
2003-06-25 00:21:24 +02:00
|
|
|
*cp++ = ':';
|
|
|
|
*cp++ = ':';
|
|
|
|
*cp = '\0';
|
2003-08-04 02:43:34 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-05-06 18:12:18 +02:00
|
|
|
/* Copy src to private buffer. Zero host part. */
|
2003-06-25 00:21:24 +02:00
|
|
|
p = (bits + 7) / 8;
|
|
|
|
memcpy(inbuf, src, p);
|
|
|
|
memset(inbuf + p, 0, 16 - p);
|
|
|
|
b = bits % 8;
|
2003-08-04 02:43:34 +02:00
|
|
|
if (b != 0)
|
|
|
|
{
|
2003-06-25 00:21:24 +02:00
|
|
|
m = ~0 << (8 - b);
|
2003-08-04 02:43:34 +02:00
|
|
|
inbuf[p - 1] &= m;
|
2003-06-25 00:21:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
s = inbuf;
|
|
|
|
|
|
|
|
/* how many words need to be displayed in output */
|
|
|
|
words = (bits + 15) / 16;
|
|
|
|
if (words == 1)
|
|
|
|
words = 2;
|
|
|
|
|
|
|
|
/* Find the longest substring of zero's */
|
|
|
|
zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0;
|
2003-08-04 02:43:34 +02:00
|
|
|
for (i = 0; i < (words * 2); i += 2)
|
|
|
|
{
|
|
|
|
if ((s[i] | s[i + 1]) == 0)
|
|
|
|
{
|
2003-06-25 00:21:24 +02:00
|
|
|
if (tmp_zero_l == 0)
|
|
|
|
tmp_zero_s = i / 2;
|
|
|
|
tmp_zero_l++;
|
2003-08-04 02:43:34 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (tmp_zero_l && zero_l < tmp_zero_l)
|
|
|
|
{
|
2003-06-25 00:21:24 +02:00
|
|
|
zero_s = tmp_zero_s;
|
|
|
|
zero_l = tmp_zero_l;
|
|
|
|
tmp_zero_l = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-08-04 02:43:34 +02:00
|
|
|
if (tmp_zero_l && zero_l < tmp_zero_l)
|
|
|
|
{
|
2003-06-25 00:21:24 +02:00
|
|
|
zero_s = tmp_zero_s;
|
|
|
|
zero_l = tmp_zero_l;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (zero_l != words && zero_s == 0 && ((zero_l == 6) ||
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) ||
|
|
|
|
((zero_l == 7 && s[14] != 0 && s[15] != 1)))))
|
2003-06-25 00:21:24 +02:00
|
|
|
is_ipv4 = 1;
|
|
|
|
|
|
|
|
/* Format whole words. */
|
2003-08-04 02:43:34 +02:00
|
|
|
for (p = 0; p < words; p++)
|
|
|
|
{
|
|
|
|
if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l)
|
|
|
|
{
|
2003-06-25 00:21:24 +02:00
|
|
|
/* Time to skip some zeros */
|
|
|
|
if (p == zero_s)
|
|
|
|
*cp++ = ':';
|
2003-08-04 02:43:34 +02:00
|
|
|
if (p == words - 1)
|
2003-06-25 00:21:24 +02:00
|
|
|
*cp++ = ':';
|
|
|
|
s++;
|
|
|
|
s++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2003-08-04 02:43:34 +02:00
|
|
|
if (is_ipv4 && p > 5)
|
|
|
|
{
|
2003-06-25 00:21:24 +02:00
|
|
|
*cp++ = (p == 6) ? ':' : '.';
|
|
|
|
cp += SPRINTF((cp, "%u", *s++));
|
|
|
|
/* we can potentially drop the last octet */
|
2003-08-04 02:43:34 +02:00
|
|
|
if (p != 7 || bits > 120)
|
|
|
|
{
|
2003-06-25 00:21:24 +02:00
|
|
|
*cp++ = '.';
|
|
|
|
cp += SPRINTF((cp, "%u", *s++));
|
|
|
|
}
|
2003-08-04 02:43:34 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2003-06-25 00:21:24 +02:00
|
|
|
if (cp != outbuf)
|
|
|
|
*cp++ = ':';
|
|
|
|
cp += SPRINTF((cp, "%x", *s * 256 + s[1]));
|
|
|
|
s += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Format CIDR /width. */
|
2006-04-24 21:51:13 +02:00
|
|
|
(void) SPRINTF((cp, "/%u", bits));
|
2003-06-25 00:21:24 +02:00
|
|
|
if (strlen(outbuf) + 1 > size)
|
|
|
|
goto emsgsize;
|
|
|
|
strcpy(dst, outbuf);
|
2003-08-04 02:43:34 +02:00
|
|
|
|
2003-06-25 00:21:24 +02:00
|
|
|
return (dst);
|
|
|
|
|
|
|
|
emsgsize:
|
|
|
|
errno = EMSGSIZE;
|
|
|
|
return (NULL);
|
|
|
|
}
|