LCOV - code coverage report
Current view: top level - src/common - ip.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 78.6 % 98 77
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 5 5
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 58.3 % 60 35

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * ip.c
       4                 :             :  *        IPv6-aware network access.
       5                 :             :  *
       6                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :             :  *
       9                 :             :  *
      10                 :             :  * IDENTIFICATION
      11                 :             :  *        src/common/ip.c
      12                 :             :  *
      13                 :             :  * This file and the IPV6 implementation were initially provided by
      14                 :             :  * Nigel Kukard <nkukard@lbsd.net>, Linux Based Systems Design
      15                 :             :  * http://www.lbsd.net.
      16                 :             :  *
      17                 :             :  *-------------------------------------------------------------------------
      18                 :             :  */
      19                 :             : 
      20                 :             : #ifndef FRONTEND
      21                 :             : #include "postgres.h"
      22                 :             : #else
      23                 :             : #include "postgres_fe.h"
      24                 :             : #endif
      25                 :             : 
      26                 :             : #include <unistd.h>
      27                 :             : #include <sys/stat.h>
      28                 :             : #include <sys/socket.h>
      29                 :             : #include <netdb.h>
      30                 :             : #include <netinet/in.h>
      31                 :             : #include <netinet/tcp.h>
      32                 :             : #include <arpa/inet.h>
      33                 :             : #include <sys/file.h>
      34                 :             : 
      35                 :             : #include "common/ip.h"
      36                 :             : 
      37                 :             : 
      38                 :             : 
      39                 :             : static int      getaddrinfo_unix(const char *path,
      40                 :             :                                                          const struct addrinfo *hintsp,
      41                 :             :                                                          struct addrinfo **result);
      42                 :             : 
      43                 :             : static int      getnameinfo_unix(const struct sockaddr_un *sa, int salen,
      44                 :             :                                                          char *node, int nodelen,
      45                 :             :                                                          char *service, int servicelen,
      46                 :             :                                                          int flags);
      47                 :             : 
      48                 :             : 
      49                 :             : /*
      50                 :             :  *      pg_getaddrinfo_all - get address info for Unix, IPv4 and IPv6 sockets
      51                 :             :  *
      52                 :             :  * The API of this routine differs from the standard getaddrinfo() definition
      53                 :             :  * in that it requires a valid hintp, a null pointer is not allowed.
      54                 :             :  */
      55                 :             : int
      56                 :         331 : pg_getaddrinfo_all(const char *hostname, const char *servname,
      57                 :             :                                    const struct addrinfo *hintp, struct addrinfo **result)
      58                 :             : {
      59                 :         331 :         int                     rc;
      60                 :             : 
      61                 :             :         /* not all versions of getaddrinfo() zero *result on failure */
      62                 :         331 :         *result = NULL;
      63                 :             : 
      64         [ +  + ]:         331 :         if (hintp->ai_family == AF_UNIX)
      65                 :         319 :                 return getaddrinfo_unix(servname, hintp, result);
      66                 :             : 
      67                 :             :         /* NULL has special meaning to getaddrinfo(). */
      68   [ +  -  -  + ]:          12 :         rc = getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname,
      69                 :          12 :                                          servname, hintp, result);
      70                 :             : 
      71                 :          12 :         return rc;
      72                 :         331 : }
      73                 :             : 
      74                 :             : 
      75                 :             : /*
      76                 :             :  *      pg_freeaddrinfo_all - free addrinfo structures for IPv4, IPv6, or Unix
      77                 :             :  *
      78                 :             :  * Note: the ai_family field of the original hint structure must be passed
      79                 :             :  * so that we can tell whether the addrinfo struct was built by the system's
      80                 :             :  * getaddrinfo() routine or our own getaddrinfo_unix() routine.  Some versions
      81                 :             :  * of getaddrinfo() might be willing to return AF_UNIX addresses, so it's
      82                 :             :  * not safe to look at ai_family in the addrinfo itself.
      83                 :             :  */
      84                 :             : void
      85                 :         331 : pg_freeaddrinfo_all(int hint_ai_family, struct addrinfo *ai)
      86                 :             : {
      87         [ +  + ]:         331 :         if (hint_ai_family == AF_UNIX)
      88                 :             :         {
      89                 :             :                 /* struct was built by getaddrinfo_unix (see pg_getaddrinfo_all) */
      90         [ +  + ]:         638 :                 while (ai != NULL)
      91                 :             :                 {
      92                 :         319 :                         struct addrinfo *p = ai;
      93                 :             : 
      94                 :         319 :                         ai = ai->ai_next;
      95                 :         319 :                         free(p->ai_addr);
      96                 :         319 :                         free(p);
      97                 :         319 :                 }
      98                 :         319 :         }
      99                 :             :         else
     100                 :             :         {
     101                 :             :                 /* struct was built by getaddrinfo() */
     102         [ -  + ]:          12 :                 if (ai != NULL)
     103                 :          12 :                         freeaddrinfo(ai);
     104                 :             :         }
     105                 :         331 : }
     106                 :             : 
     107                 :             : 
     108                 :             : /*
     109                 :             :  *      pg_getnameinfo_all - get name info for Unix, IPv4 and IPv6 sockets
     110                 :             :  *
     111                 :             :  * The API of this routine differs from the standard getnameinfo() definition
     112                 :             :  * in two ways: first, the addr parameter is declared as sockaddr_storage
     113                 :             :  * rather than struct sockaddr, and second, the node and service fields are
     114                 :             :  * guaranteed to be filled with something even on failure return.
     115                 :             :  */
     116                 :             : int
     117                 :         640 : pg_getnameinfo_all(const struct sockaddr_storage *addr, int salen,
     118                 :             :                                    char *node, int nodelen,
     119                 :             :                                    char *service, int servicelen,
     120                 :             :                                    int flags)
     121                 :             : {
     122                 :         640 :         int                     rc;
     123                 :             : 
     124   [ +  -  +  + ]:         640 :         if (addr && addr->ss_family == AF_UNIX)
     125                 :        1264 :                 rc = getnameinfo_unix((const struct sockaddr_un *) addr, salen,
     126                 :         632 :                                                           node, nodelen,
     127                 :         632 :                                                           service, servicelen,
     128                 :         632 :                                                           flags);
     129                 :             :         else
     130                 :          16 :                 rc = getnameinfo((const struct sockaddr *) addr, salen,
     131                 :           8 :                                                  node, nodelen,
     132                 :           8 :                                                  service, servicelen,
     133                 :           8 :                                                  flags);
     134                 :             : 
     135         [ +  - ]:         640 :         if (rc != 0)
     136                 :             :         {
     137         [ #  # ]:           0 :                 if (node)
     138                 :           0 :                         strlcpy(node, "???", nodelen);
     139         [ #  # ]:           0 :                 if (service)
     140                 :           0 :                         strlcpy(service, "???", servicelen);
     141                 :           0 :         }
     142                 :             : 
     143                 :        1280 :         return rc;
     144                 :         640 : }
     145                 :             : 
     146                 :             : 
     147                 :             : /* -------
     148                 :             :  *      getaddrinfo_unix - get unix socket info using IPv6-compatible API
     149                 :             :  *
     150                 :             :  *      Bugs: only one addrinfo is set even though hintsp is NULL or
     151                 :             :  *                ai_socktype is 0
     152                 :             :  *                AI_CANONNAME is not supported.
     153                 :             :  * -------
     154                 :             :  */
     155                 :             : static int
     156                 :         319 : getaddrinfo_unix(const char *path, const struct addrinfo *hintsp,
     157                 :             :                                  struct addrinfo **result)
     158                 :             : {
     159                 :         319 :         struct addrinfo hints = {0};
     160                 :         319 :         struct addrinfo *aip;
     161                 :         319 :         struct sockaddr_un *unp;
     162                 :             : 
     163                 :         319 :         *result = NULL;
     164                 :             : 
     165         [ -  + ]:         319 :         if (strlen(path) >= sizeof(unp->sun_path))
     166                 :           0 :                 return EAI_FAIL;
     167                 :             : 
     168         [ +  - ]:         319 :         if (hintsp == NULL)
     169                 :             :         {
     170                 :           0 :                 hints.ai_family = AF_UNIX;
     171                 :           0 :                 hints.ai_socktype = SOCK_STREAM;
     172                 :           0 :         }
     173                 :             :         else
     174                 :         319 :                 memcpy(&hints, hintsp, sizeof(hints));
     175                 :             : 
     176         [ +  - ]:         319 :         if (hints.ai_socktype == 0)
     177                 :           0 :                 hints.ai_socktype = SOCK_STREAM;
     178                 :             : 
     179         [ -  + ]:         319 :         if (hints.ai_family != AF_UNIX)
     180                 :             :         {
     181                 :             :                 /* shouldn't have been called */
     182                 :           0 :                 return EAI_FAIL;
     183                 :             :         }
     184                 :             : 
     185                 :         319 :         aip = calloc(1, sizeof(struct addrinfo));
     186         [ +  - ]:         319 :         if (aip == NULL)
     187                 :           0 :                 return EAI_MEMORY;
     188                 :             : 
     189                 :         319 :         unp = calloc(1, sizeof(struct sockaddr_un));
     190         [ +  - ]:         319 :         if (unp == NULL)
     191                 :             :         {
     192                 :           0 :                 free(aip);
     193                 :           0 :                 return EAI_MEMORY;
     194                 :             :         }
     195                 :             : 
     196                 :         319 :         aip->ai_family = AF_UNIX;
     197                 :         319 :         aip->ai_socktype = hints.ai_socktype;
     198                 :         319 :         aip->ai_protocol = hints.ai_protocol;
     199                 :         319 :         aip->ai_next = NULL;
     200                 :         319 :         aip->ai_canonname = NULL;
     201                 :         319 :         *result = aip;
     202                 :             : 
     203                 :         319 :         unp->sun_family = AF_UNIX;
     204                 :         319 :         aip->ai_addr = (struct sockaddr *) unp;
     205                 :         319 :         aip->ai_addrlen = sizeof(struct sockaddr_un);
     206                 :             : 
     207                 :         319 :         strcpy(unp->sun_path, path);
     208                 :             : 
     209                 :             :         /*
     210                 :             :          * If the supplied path starts with @, replace that with a zero byte for
     211                 :             :          * the internal representation.  In that mode, the entire sun_path is the
     212                 :             :          * address, including trailing zero bytes.  But we set the address length
     213                 :             :          * to only include the length of the original string.  That way the
     214                 :             :          * trailing zero bytes won't show up in any network or socket lists of the
     215                 :             :          * operating system.  This is just a convention, also followed by other
     216                 :             :          * packages.
     217                 :             :          */
     218         [ +  - ]:         319 :         if (path[0] == '@')
     219                 :             :         {
     220                 :           0 :                 unp->sun_path[0] = '\0';
     221                 :           0 :                 aip->ai_addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(path);
     222                 :           0 :         }
     223                 :             : 
     224                 :         319 :         return 0;
     225                 :         319 : }
     226                 :             : 
     227                 :             : /*
     228                 :             :  * Convert an address to a hostname.
     229                 :             :  */
     230                 :             : static int
     231                 :         632 : getnameinfo_unix(const struct sockaddr_un *sa, int salen,
     232                 :             :                                  char *node, int nodelen,
     233                 :             :                                  char *service, int servicelen,
     234                 :             :                                  int flags)
     235                 :             : {
     236                 :         632 :         int                     ret;
     237                 :             : 
     238                 :             :         /* Invalid arguments. */
     239   [ +  -  +  -  :         949 :         if (sa == NULL || sa->sun_family != AF_UNIX ||
                   +  - ]
     240         [ +  + ]:         632 :                 (node == NULL && service == NULL))
     241                 :           0 :                 return EAI_FAIL;
     242                 :             : 
     243         [ +  + ]:         632 :         if (node)
     244                 :             :         {
     245                 :         315 :                 ret = snprintf(node, nodelen, "%s", "[local]");
     246   [ +  -  -  + ]:         315 :                 if (ret < 0 || ret >= nodelen)
     247                 :           0 :                         return EAI_MEMORY;
     248                 :         315 :         }
     249                 :             : 
     250         [ -  + ]:         632 :         if (service)
     251                 :             :         {
     252                 :             :                 /*
     253                 :             :                  * Check whether it looks like an abstract socket, but it could also
     254                 :             :                  * just be an empty string.
     255                 :             :                  */
     256   [ +  +  +  - ]:         632 :                 if (sa->sun_path[0] == '\0' && sa->sun_path[1] != '\0')
     257                 :           0 :                         ret = snprintf(service, servicelen, "@%s", sa->sun_path + 1);
     258                 :             :                 else
     259                 :         632 :                         ret = snprintf(service, servicelen, "%s", sa->sun_path);
     260   [ +  -  -  + ]:         632 :                 if (ret < 0 || ret >= servicelen)
     261                 :           0 :                         return EAI_MEMORY;
     262                 :         632 :         }
     263                 :             : 
     264                 :         632 :         return 0;
     265                 :         632 : }
        

Generated by: LCOV version 2.3.2-1