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-24 01:16:09 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        10597 : 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        10597 :     switch (af)
      86              :     {
      87         8451 :         case PGSQL_AF_INET:
      88         8451 :             return (inet_net_ntop_ipv4(src, bits, dst, size));
      89         2146 :         case PGSQL_AF_INET6:
      90              : #if AF_INET6 != PGSQL_AF_INET6
      91              :         case AF_INET6:
      92              : #endif
      93         2146 :             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         8451 : inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
     115              : {
     116         8451 :     char       *odst = dst;
     117              :     char       *t;
     118         8451 :     int         len = 4;
     119              :     int         b;
     120              : 
     121         8451 :     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        42255 :     for (b = len; b > 0; b--)
     129              :     {
     130        33804 :         if (size <= sizeof ".255")
     131            0 :             goto emsgsize;
     132        33804 :         t = dst;
     133        33804 :         if (dst != odst)
     134        25353 :             *dst++ = '.';
     135        33804 :         dst += SPRINTF((dst, "%u", *src++));
     136        33804 :         size -= (size_t) (dst - t);
     137              :     }
     138              : 
     139              :     /* don't print masklen if 32 bits */
     140         8451 :     if (bits != 32)
     141              :     {
     142         6647 :         if (size <= sizeof "/32")
     143            0 :             goto emsgsize;
     144         6647 :         dst += SPRINTF((dst, "/%u", bits));
     145              :     }
     146              : 
     147         8451 :     return (odst);
     148              : 
     149            0 : emsgsize:
     150            0 :     errno = EMSGSIZE;
     151            0 :     return (NULL);
     152              : }
     153              : 
     154              : static int
     155          232 : decoct(const u_char *src, int bytes, char *dst, size_t size)
     156              : {
     157          232 :     char       *odst = dst;
     158              :     char       *t;
     159              :     int         b;
     160              : 
     161         1160 :     for (b = 1; b <= bytes; b++)
     162              :     {
     163          928 :         if (size <= sizeof "255.")
     164            0 :             return (0);
     165          928 :         t = dst;
     166          928 :         dst += SPRINTF((dst, "%u", *src++));
     167          928 :         if (b != bytes)
     168              :         {
     169          696 :             *dst++ = '.';
     170          696 :             *dst = '\0';
     171              :         }
     172          928 :         size -= (size_t) (dst - t);
     173              :     }
     174          232 :     return (dst - odst);
     175              : }
     176              : 
     177              : static char *
     178         2146 : 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         2146 :     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         2146 :     memset(words, '\0', sizeof words);
     208        36482 :     for (i = 0; i < NS_IN6ADDRSZ; i++)
     209        34336 :         words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
     210         2146 :     best.base = -1;
     211         2146 :     cur.base = -1;
     212         2146 :     best.len = 0;
     213         2146 :     cur.len = 0;
     214        19314 :     for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++)
     215              :     {
     216        17168 :         if (words[i] == 0)
     217              :         {
     218         8784 :             if (cur.base == -1)
     219         2032 :                 cur.base = i, cur.len = 1;
     220              :             else
     221         6752 :                 cur.len++;
     222              :         }
     223              :         else
     224              :         {
     225         8384 :             if (cur.base != -1)
     226              :             {
     227         1900 :                 if (best.base == -1 || cur.len > best.len)
     228         1900 :                     best = cur;
     229         1900 :                 cur.base = -1;
     230              :             }
     231              :         }
     232              :     }
     233         2146 :     if (cur.base != -1)
     234              :     {
     235          132 :         if (best.base == -1 || cur.len > best.len)
     236          128 :             best = cur;
     237              :     }
     238         2146 :     if (best.base != -1 && best.len < 2)
     239           16 :         best.base = -1;
     240              : 
     241              :     /*
     242              :      * Format the result.
     243              :      */
     244         2146 :     tp = tmp;
     245        18850 :     for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++)
     246              :     {
     247              :         /* Are we inside the best run of 0x00's? */
     248        16936 :         if (best.base != -1 && i >= best.base &&
     249        13724 :             i < (best.base + best.len))
     250              :         {
     251         8764 :             if (i == best.base)
     252         2012 :                 *tp++ = ':';
     253         8764 :             continue;
     254              :         }
     255              :         /* Are we following an initial run of 0x00s or any real hex? */
     256         8172 :         if (i != 0)
     257         6460 :             *tp++ = ':';
     258              :         /* Is this address an encapsulated IPv4? */
     259         8172 :         if (i == 6 && best.base == 0 && (best.len == 6 ||
     260          120 :                                          (best.len == 7 && words[7] != 0x0001) ||
     261          120 :                                          (best.len == 5 && words[5] == 0xffff)))
     262              :         {
     263              :             int         n;
     264              : 
     265          232 :             n = decoct(src + 12, 4, tp, sizeof tmp - (tp - tmp));
     266          232 :             if (n == 0)
     267              :             {
     268            0 :                 errno = EMSGSIZE;
     269            0 :                 return (NULL);
     270              :             }
     271          232 :             tp += strlen(tp);
     272          232 :             break;
     273              :         }
     274         7940 :         tp += SPRINTF((tp, "%x", words[i]));
     275              :     }
     276              : 
     277              :     /* Was it a trailing run of 0x00's? */
     278         2146 :     if (best.base != -1 && (best.base + best.len) ==
     279              :         (NS_IN6ADDRSZ / NS_INT16SZ))
     280          120 :         *tp++ = ':';
     281         2146 :     *tp = '\0';
     282              : 
     283         2146 :     if (bits != -1 && bits != 128)
     284          600 :         tp += SPRINTF((tp, "/%u", bits));
     285              : 
     286              :     /*
     287              :      * Check for overflow, copy, and we're done.
     288              :      */
     289         2146 :     if ((size_t) (tp - tmp) > size)
     290              :     {
     291            0 :         errno = EMSGSIZE;
     292            0 :         return (NULL);
     293              :     }
     294         2146 :     strcpy(dst, tmp);
     295         2146 :     return (dst);
     296              : }
        

Generated by: LCOV version 2.0-1