LCOV - code coverage report
Current view: top level - src/port - inet_net_ntop.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 82.5 % 97 80
Test Date: 2026-03-02 14:15:04 Functions: 100.0 % 4 4
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*
       2              :  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
       3              :  * Copyright (c) 1996,1999 by Internet Software Consortium.
       4              :  *
       5              :  * Permission to use, copy, modify, and distribute this software for any
       6              :  * purpose with or without fee is hereby granted, provided that the above
       7              :  * copyright notice and this permission notice appear in all copies.
       8              :  *
       9              :  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
      10              :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      11              :  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
      12              :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      13              :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      14              :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
      15              :  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      16              :  *
      17              :  *    src/port/inet_net_ntop.c
      18              :  */
      19              : 
      20              : #if defined(LIBC_SCCS) && !defined(lint)
      21              : static const char rcsid[] = "Id: inet_net_ntop.c,v 1.1.2.2 2004/03/09 09:17:27 marka Exp $";
      22              : #endif
      23              : 
      24              : #ifndef FRONTEND
      25              : #include "postgres.h"
      26              : #else
      27              : #include "postgres_fe.h"
      28              : #endif
      29              : 
      30              : #include <sys/socket.h>
      31              : #include <netinet/in.h>
      32              : #include <arpa/inet.h>
      33              : 
      34              : #ifndef FRONTEND
      35              : #include "utils/inet.h"
      36              : #else
      37              : /*
      38              :  * In a frontend build, we can't include inet.h, but we still need to have
      39              :  * sensible definitions of these two constants.  Note that pg_inet_net_ntop()
      40              :  * assumes that PGSQL_AF_INET is equal to AF_INET.
      41              :  */
      42              : #define PGSQL_AF_INET   (AF_INET + 0)
      43              : #define PGSQL_AF_INET6  (AF_INET + 1)
      44              : #endif
      45              : 
      46              : 
      47              : #define NS_IN6ADDRSZ 16
      48              : #define NS_INT16SZ 2
      49              : 
      50              : #ifdef SPRINTF_CHAR
      51              : #define SPRINTF(x) strlen(sprintf/**/x)
      52              : #else
      53              : #define SPRINTF(x) ((size_t)sprintf x)
      54              : #endif
      55              : 
      56              : static char *inet_net_ntop_ipv4(const u_char *src, int bits,
      57              :                                 char *dst, size_t size);
      58              : static char *inet_net_ntop_ipv6(const u_char *src, int bits,
      59              :                                 char *dst, size_t size);
      60              : 
      61              : 
      62              : /*
      63              :  * char *
      64              :  * pg_inet_net_ntop(af, src, bits, dst, size)
      65              :  *  convert host/network address from network to presentation format.
      66              :  *  "src"'s size is determined from its "af".
      67              :  * return:
      68              :  *  pointer to dst, or NULL if an error occurred (check errno).
      69              :  * note:
      70              :  *  192.5.5.1/28 has a nonzero host part, which means it isn't a network
      71              :  *  as called for by pg_inet_net_pton() but it can be a host address with
      72              :  *  an included netmask.
      73              :  * author:
      74              :  *  Paul Vixie (ISC), October 1998
      75              :  */
      76              : char *
      77         8986 : pg_inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size)
      78              : {
      79              :     /*
      80              :      * We need to cover both the address family constants used by the PG inet
      81              :      * type (PGSQL_AF_INET and PGSQL_AF_INET6) and those used by the system
      82              :      * libraries (AF_INET and AF_INET6).  We can safely assume PGSQL_AF_INET
      83              :      * == AF_INET, but the INET6 constants are very likely to be different.
      84              :      */
      85         8986 :     switch (af)
      86              :     {
      87         7137 :         case PGSQL_AF_INET:
      88         7137 :             return (inet_net_ntop_ipv4(src, bits, dst, size));
      89         1849 :         case PGSQL_AF_INET6:
      90              : #if AF_INET6 != PGSQL_AF_INET6
      91              :         case AF_INET6:
      92              : #endif
      93         1849 :             return (inet_net_ntop_ipv6(src, bits, dst, size));
      94            0 :         default:
      95            0 :             errno = EAFNOSUPPORT;
      96            0 :             return (NULL);
      97              :     }
      98              : }
      99              : 
     100              : /*
     101              :  * static char *
     102              :  * inet_net_ntop_ipv4(src, bits, dst, size)
     103              :  *  convert IPv4 network address from network to presentation format.
     104              :  *  "src"'s size is determined from its "af".
     105              :  * return:
     106              :  *  pointer to dst, or NULL if an error occurred (check errno).
     107              :  * note:
     108              :  *  network byte order assumed.  this means 192.5.5.240/28 has
     109              :  *  0b11110000 in its fourth octet.
     110              :  * author:
     111              :  *  Paul Vixie (ISC), October 1998
     112              :  */
     113              : static char *
     114         7137 : inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
     115              : {
     116         7137 :     char       *odst = dst;
     117              :     char       *t;
     118         7137 :     int         len = 4;
     119              :     int         b;
     120              : 
     121         7137 :     if (bits < 0 || bits > 32)
     122              :     {
     123            0 :         errno = EINVAL;
     124            0 :         return (NULL);
     125              :     }
     126              : 
     127              :     /* Always format all four octets, regardless of mask length. */
     128        35685 :     for (b = len; b > 0; b--)
     129              :     {
     130        28548 :         if (size <= sizeof ".255")
     131            0 :             goto emsgsize;
     132        28548 :         t = dst;
     133        28548 :         if (dst != odst)
     134        21411 :             *dst++ = '.';
     135        28548 :         dst += SPRINTF((dst, "%u", *src++));
     136        28548 :         size -= (size_t) (dst - t);
     137              :     }
     138              : 
     139              :     /* don't print masklen if 32 bits */
     140         7137 :     if (bits != 32)
     141              :     {
     142         5743 :         if (size <= sizeof "/32")
     143            0 :             goto emsgsize;
     144         5743 :         dst += SPRINTF((dst, "/%u", bits));
     145              :     }
     146              : 
     147         7137 :     return (odst);
     148              : 
     149            0 : emsgsize:
     150            0 :     errno = EMSGSIZE;
     151            0 :     return (NULL);
     152              : }
     153              : 
     154              : static int
     155          176 : decoct(const u_char *src, int bytes, char *dst, size_t size)
     156              : {
     157          176 :     char       *odst = dst;
     158              :     char       *t;
     159              :     int         b;
     160              : 
     161          880 :     for (b = 1; b <= bytes; b++)
     162              :     {
     163          704 :         if (size <= sizeof "255.")
     164            0 :             return (0);
     165          704 :         t = dst;
     166          704 :         dst += SPRINTF((dst, "%u", *src++));
     167          704 :         if (b != bytes)
     168              :         {
     169          528 :             *dst++ = '.';
     170          528 :             *dst = '\0';
     171              :         }
     172          704 :         size -= (size_t) (dst - t);
     173              :     }
     174          176 :     return (dst - odst);
     175              : }
     176              : 
     177              : static char *
     178         1849 : inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size)
     179              : {
     180              :     /*
     181              :      * Note that int32_t and int16_t need only be "at least" large enough to
     182              :      * contain a value of the specified size.  On some systems, like Crays,
     183              :      * there is no such thing as an integer variable with 16 bits. Keep this
     184              :      * in mind if you think this function should have been coded to use
     185              :      * pointer overlays.  All the world's not a VAX.
     186              :      */
     187              :     char        tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"];
     188              :     char       *tp;
     189              :     struct
     190              :     {
     191              :         int         base,
     192              :                     len;
     193              :     }           best, cur;
     194              :     u_int       words[NS_IN6ADDRSZ / NS_INT16SZ];
     195              :     int         i;
     196              : 
     197         1849 :     if ((bits < -1) || (bits > 128))
     198              :     {
     199            0 :         errno = EINVAL;
     200            0 :         return (NULL);
     201              :     }
     202              : 
     203              :     /*
     204              :      * Preprocess: Copy the input (bytewise) array into a wordwise array. Find
     205              :      * the longest run of 0x00's in src[] for :: shorthanding.
     206              :      */
     207         1849 :     memset(words, '\0', sizeof words);
     208        31433 :     for (i = 0; i < NS_IN6ADDRSZ; i++)
     209        29584 :         words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
     210         1849 :     best.base = -1;
     211         1849 :     cur.base = -1;
     212         1849 :     best.len = 0;
     213         1849 :     cur.len = 0;
     214        16641 :     for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++)
     215              :     {
     216        14792 :         if (words[i] == 0)
     217              :         {
     218         7469 :             if (cur.base == -1)
     219         1763 :                 cur.base = i, cur.len = 1;
     220              :             else
     221         5706 :                 cur.len++;
     222              :         }
     223              :         else
     224              :         {
     225         7323 :             if (cur.base != -1)
     226              :             {
     227         1663 :                 if (best.base == -1 || cur.len > best.len)
     228         1663 :                     best = cur;
     229         1663 :                 cur.base = -1;
     230              :             }
     231              :         }
     232              :     }
     233         1849 :     if (cur.base != -1)
     234              :     {
     235          100 :         if (best.base == -1 || cur.len > best.len)
     236           97 :             best = cur;
     237              :     }
     238         1849 :     if (best.base != -1 && best.len < 2)
     239           12 :         best.base = -1;
     240              : 
     241              :     /*
     242              :      * Format the result.
     243              :      */
     244         1849 :     tp = tmp;
     245        16289 :     for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++)
     246              :     {
     247              :         /* Are we inside the best run of 0x00's? */
     248        14616 :         if (best.base != -1 && i >= best.base &&
     249        11995 :             i < (best.base + best.len))
     250              :         {
     251         7454 :             if (i == best.base)
     252         1748 :                 *tp++ = ':';
     253         7454 :             continue;
     254              :         }
     255              :         /* Are we following an initial run of 0x00s or any real hex? */
     256         7162 :         if (i != 0)
     257         5676 :             *tp++ = ':';
     258              :         /* Is this address an encapsulated IPv4? */
     259         7162 :         if (i == 6 && best.base == 0 && (best.len == 6 ||
     260           91 :                                          (best.len == 7 && words[7] != 0x0001) ||
     261           91 :                                          (best.len == 5 && words[5] == 0xffff)))
     262              :         {
     263              :             int         n;
     264              : 
     265          176 :             n = decoct(src + 12, 4, tp, sizeof tmp - (tp - tmp));
     266          176 :             if (n == 0)
     267              :             {
     268            0 :                 errno = EMSGSIZE;
     269            0 :                 return (NULL);
     270              :             }
     271          176 :             tp += strlen(tp);
     272          176 :             break;
     273              :         }
     274         6986 :         tp += SPRINTF((tp, "%x", words[i]));
     275              :     }
     276              : 
     277              :     /* Was it a trailing run of 0x00's? */
     278         1849 :     if (best.base != -1 && (best.base + best.len) ==
     279              :         (NS_IN6ADDRSZ / NS_INT16SZ))
     280           91 :         *tp++ = ':';
     281         1849 :     *tp = '\0';
     282              : 
     283         1849 :     if (bits != -1 && bits != 128)
     284          454 :         tp += SPRINTF((tp, "/%u", bits));
     285              : 
     286              :     /*
     287              :      * Check for overflow, copy, and we're done.
     288              :      */
     289         1849 :     if ((size_t) (tp - tmp) > size)
     290              :     {
     291            0 :         errno = EMSGSIZE;
     292            0 :         return (NULL);
     293              :     }
     294         1849 :     strcpy(dst, tmp);
     295         1849 :     return (dst);
     296              : }
        

Generated by: LCOV version 2.0-1