LCOV - code coverage report
Current view: top level - src/backend/utils/adt - inet_cidr_ntop.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 73.0 % 111 81
Test Date: 2026-03-01 17:14:43 Functions: 100.0 % 3 3
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/backend/utils/adt/inet_cidr_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              : #include "postgres.h"
      25              : 
      26              : #include <sys/socket.h>
      27              : #include <netinet/in.h>
      28              : #include <arpa/inet.h>
      29              : 
      30              : #include "utils/builtins.h"
      31              : #include "utils/inet.h"
      32              : 
      33              : 
      34              : #ifdef SPRINTF_CHAR
      35              : #define SPRINTF(x) strlen(sprintf/**/x)
      36              : #else
      37              : #define SPRINTF(x) ((size_t)sprintf x)
      38              : #endif
      39              : 
      40              : static char *inet_cidr_ntop_ipv4(const u_char *src, int bits,
      41              :                                  char *dst, size_t size);
      42              : static char *inet_cidr_ntop_ipv6(const u_char *src, int bits,
      43              :                                  char *dst, size_t size);
      44              : 
      45              : /*
      46              :  * char *
      47              :  * pg_inet_cidr_ntop(af, src, bits, dst, size)
      48              :  *  convert network number from network to presentation format.
      49              :  *  generates CIDR style result always.
      50              :  * return:
      51              :  *  pointer to dst, or NULL if an error occurred (check errno).
      52              :  * author:
      53              :  *  Paul Vixie (ISC), July 1996
      54              :  */
      55              : char *
      56           51 : pg_inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size)
      57              : {
      58           51 :     switch (af)
      59              :     {
      60           42 :         case PGSQL_AF_INET:
      61           42 :             return inet_cidr_ntop_ipv4(src, bits, dst, size);
      62            9 :         case PGSQL_AF_INET6:
      63            9 :             return inet_cidr_ntop_ipv6(src, bits, dst, size);
      64            0 :         default:
      65            0 :             errno = EAFNOSUPPORT;
      66            0 :             return NULL;
      67              :     }
      68              : }
      69              : 
      70              : 
      71              : /*
      72              :  * static char *
      73              :  * inet_cidr_ntop_ipv4(src, bits, dst, size)
      74              :  *  convert IPv4 network number from network to presentation format.
      75              :  *  generates CIDR style result always.
      76              :  * return:
      77              :  *  pointer to dst, or NULL if an error occurred (check errno).
      78              :  * note:
      79              :  *  network byte order assumed.  this means 192.5.5.240/28 has
      80              :  *  0b11110000 in its fourth octet.
      81              :  * author:
      82              :  *  Paul Vixie (ISC), July 1996
      83              :  */
      84              : static char *
      85           42 : inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
      86              : {
      87           42 :     char       *odst = dst;
      88              :     char       *t;
      89              :     u_int       m;
      90              :     int         b;
      91              : 
      92           42 :     if (bits < 0 || bits > 32)
      93              :     {
      94            0 :         errno = EINVAL;
      95            0 :         return NULL;
      96              :     }
      97              : 
      98           42 :     if (bits == 0)
      99              :     {
     100            0 :         if (size < sizeof "0")
     101            0 :             goto emsgsize;
     102            0 :         *dst++ = '0';
     103            0 :         size--;
     104            0 :         *dst = '\0';
     105              :     }
     106              : 
     107              :     /* Format whole octets. */
     108          147 :     for (b = bits / 8; b > 0; b--)
     109              :     {
     110          105 :         if (size <= sizeof "255.")
     111            0 :             goto emsgsize;
     112          105 :         t = dst;
     113          105 :         dst += SPRINTF((dst, "%u", *src++));
     114          105 :         if (b > 1)
     115              :         {
     116           63 :             *dst++ = '.';
     117           63 :             *dst = '\0';
     118              :         }
     119          105 :         size -= (size_t) (dst - t);
     120              :     }
     121              : 
     122              :     /* Format partial octet. */
     123           42 :     b = bits % 8;
     124           42 :     if (b > 0)
     125              :     {
     126            3 :         if (size <= sizeof ".255")
     127            0 :             goto emsgsize;
     128            3 :         t = dst;
     129            3 :         if (dst != odst)
     130            3 :             *dst++ = '.';
     131            3 :         m = ((1 << b) - 1) << (8 - b);
     132            3 :         dst += SPRINTF((dst, "%u", *src & m));
     133            3 :         size -= (size_t) (dst - t);
     134              :     }
     135              : 
     136              :     /* Format CIDR /width. */
     137           42 :     if (size <= sizeof "/32")
     138            0 :         goto emsgsize;
     139           42 :     dst += SPRINTF((dst, "/%u", bits));
     140           42 :     return odst;
     141              : 
     142            0 : emsgsize:
     143            0 :     errno = EMSGSIZE;
     144            0 :     return NULL;
     145              : }
     146              : 
     147              : /*
     148              :  * static char *
     149              :  * inet_cidr_ntop_ipv6(src, bits, dst, size)
     150              :  *  convert IPv6 network number from network to presentation format.
     151              :  *  generates CIDR style result always. Picks the shortest representation
     152              :  *  unless the IP is really IPv4.
     153              :  *  always prints specified number of bits (bits).
     154              :  * return:
     155              :  *  pointer to dst, or NULL if an error occurred (check errno).
     156              :  * note:
     157              :  *  network byte order assumed.  this means 192.5.5.240/28 has
     158              :  *  0x11110000 in its fourth octet.
     159              :  * author:
     160              :  *  Vadim Kogan (UCB), June 2001
     161              :  *  Original version (IPv4) by Paul Vixie (ISC), July 1996
     162              :  */
     163              : 
     164              : static char *
     165            9 : inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size)
     166              : {
     167              :     u_int       m;
     168              :     int         b;
     169              :     int         p;
     170              :     int         zero_s,
     171              :                 zero_l,
     172              :                 tmp_zero_s,
     173              :                 tmp_zero_l;
     174              :     int         i;
     175            9 :     int         is_ipv4 = 0;
     176              :     unsigned char inbuf[16];
     177              :     char        outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
     178              :     char       *cp;
     179              :     int         words;
     180              :     u_char     *s;
     181              : 
     182            9 :     if (bits < 0 || bits > 128)
     183              :     {
     184            0 :         errno = EINVAL;
     185            0 :         return NULL;
     186              :     }
     187              : 
     188            9 :     cp = outbuf;
     189              : 
     190            9 :     if (bits == 0)
     191              :     {
     192            0 :         *cp++ = ':';
     193            0 :         *cp++ = ':';
     194            0 :         *cp = '\0';
     195              :     }
     196              :     else
     197              :     {
     198              :         /* Copy src to private buffer.  Zero host part. */
     199            9 :         p = (bits + 7) / 8;
     200            9 :         memcpy(inbuf, src, p);
     201            9 :         memset(inbuf + p, 0, 16 - p);
     202            9 :         b = bits % 8;
     203            9 :         if (b != 0)
     204              :         {
     205            3 :             m = ((u_int) ~0) << (8 - b);
     206            3 :             inbuf[p - 1] &= m;
     207              :         }
     208              : 
     209            9 :         s = inbuf;
     210              : 
     211              :         /* how many words need to be displayed in output */
     212            9 :         words = (bits + 15) / 16;
     213            9 :         if (words == 1)
     214            0 :             words = 2;
     215              : 
     216              :         /* Find the longest substring of zero's */
     217            9 :         zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0;
     218           81 :         for (i = 0; i < (words * 2); i += 2)
     219              :         {
     220           72 :             if ((s[i] | s[i + 1]) == 0)
     221              :             {
     222           45 :                 if (tmp_zero_l == 0)
     223            9 :                     tmp_zero_s = i / 2;
     224           45 :                 tmp_zero_l++;
     225              :             }
     226              :             else
     227              :             {
     228           27 :                 if (tmp_zero_l && zero_l < tmp_zero_l)
     229              :                 {
     230            9 :                     zero_s = tmp_zero_s;
     231            9 :                     zero_l = tmp_zero_l;
     232            9 :                     tmp_zero_l = 0;
     233              :                 }
     234              :             }
     235              :         }
     236              : 
     237            9 :         if (tmp_zero_l && zero_l < tmp_zero_l)
     238              :         {
     239            0 :             zero_s = tmp_zero_s;
     240            0 :             zero_l = tmp_zero_l;
     241              :         }
     242              : 
     243            9 :         if (zero_l != words && zero_s == 0 && ((zero_l == 6) ||
     244            3 :                                                ((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) ||
     245            0 :                                                 ((zero_l == 7 && s[14] != 0 && s[15] != 1)))))
     246            3 :             is_ipv4 = 1;
     247              : 
     248              :         /* Format whole words. */
     249           81 :         for (p = 0; p < words; p++)
     250              :         {
     251           72 :             if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l)
     252              :             {
     253              :                 /* Time to skip some zeros */
     254           45 :                 if (p == zero_s)
     255            9 :                     *cp++ = ':';
     256           45 :                 if (p == words - 1)
     257            0 :                     *cp++ = ':';
     258           45 :                 s++;
     259           45 :                 s++;
     260           45 :                 continue;
     261              :             }
     262              : 
     263           27 :             if (is_ipv4 && p > 5)
     264              :             {
     265            6 :                 *cp++ = (p == 6) ? ':' : '.';
     266            6 :                 cp += SPRINTF((cp, "%u", *s++));
     267              :                 /* we can potentially drop the last octet */
     268            6 :                 if (p != 7 || bits > 120)
     269              :                 {
     270            6 :                     *cp++ = '.';
     271            6 :                     cp += SPRINTF((cp, "%u", *s++));
     272              :                 }
     273              :             }
     274              :             else
     275              :             {
     276           21 :                 if (cp != outbuf)
     277           15 :                     *cp++ = ':';
     278           21 :                 cp += SPRINTF((cp, "%x", *s * 256 + s[1]));
     279           21 :                 s += 2;
     280              :             }
     281              :         }
     282              :     }
     283              :     /* Format CIDR /width. */
     284            9 :     (void) SPRINTF((cp, "/%u", bits));
     285            9 :     if (strlen(outbuf) + 1 > size)
     286            0 :         goto emsgsize;
     287            9 :     strcpy(dst, outbuf);
     288              : 
     289            9 :     return dst;
     290              : 
     291            0 : emsgsize:
     292            0 :     errno = EMSGSIZE;
     293            0 :     return NULL;
     294              : }
        

Generated by: LCOV version 2.0-1