LCOV - differential code coverage report
Current view: top level - src/common - ip.c (source / functions) Coverage Total Hit LBC UIC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 76.0 % 75 57 4 14 4 39 1 13 9 32 5 8
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 5 5 5 5
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * ip.c
       4                 :  *    IPv6-aware network access.
       5                 :  *
       6                 :  * Portions Copyright (c) 1996-2023, 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 ECB             : /*
      50                 :  *  pg_getaddrinfo_all - get address info for Unix, IPv4 and IPv6 sockets
      51                 :  */
      52                 : int
      53 GIC       12531 : pg_getaddrinfo_all(const char *hostname, const char *servname,
      54                 :                    const struct addrinfo *hintp, struct addrinfo **result)
      55 ECB             : {
      56                 :     int         rc;
      57                 : 
      58                 :     /* not all versions of getaddrinfo() zero *result on failure */
      59 GIC       12531 :     *result = NULL;
      60                 : 
      61           12531 :     if (hintp->ai_family == AF_UNIX)
      62            9637 :         return getaddrinfo_unix(servname, hintp, result);
      63                 : 
      64                 :     /* NULL has special meaning to getaddrinfo(). */
      65            2894 :     rc = getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname,
      66                 :                      servname, hintp, result);
      67                 : 
      68            2894 :     return rc;
      69                 : }
      70                 : 
      71                 : 
      72                 : /*
      73                 :  *  pg_freeaddrinfo_all - free addrinfo structures for IPv4, IPv6, or Unix
      74                 :  *
      75                 :  * Note: the ai_family field of the original hint structure must be passed
      76 ECB             :  * so that we can tell whether the addrinfo struct was built by the system's
      77                 :  * getaddrinfo() routine or our own getaddrinfo_unix() routine.  Some versions
      78                 :  * of getaddrinfo() might be willing to return AF_UNIX addresses, so it's
      79                 :  * not safe to look at ai_family in the addrinfo itself.
      80                 :  */
      81                 : void
      82 GIC       12531 : pg_freeaddrinfo_all(int hint_ai_family, struct addrinfo *ai)
      83 ECB             : {
      84 CBC       12531 :     if (hint_ai_family == AF_UNIX)
      85 ECB             :     {
      86                 :         /* struct was built by getaddrinfo_unix (see pg_getaddrinfo_all) */
      87 GIC       19274 :         while (ai != NULL)
      88                 :         {
      89            9637 :             struct addrinfo *p = ai;
      90                 : 
      91            9637 :             ai = ai->ai_next;
      92 CBC        9637 :             free(p->ai_addr);
      93            9637 :             free(p);
      94                 :         }
      95 ECB             :     }
      96                 :     else
      97                 :     {
      98                 :         /* struct was built by getaddrinfo() */
      99 GIC        2894 :         if (ai != NULL)
     100            2894 :             freeaddrinfo(ai);
     101                 :     }
     102           12531 : }
     103                 : 
     104                 : 
     105                 : /*
     106 ECB             :  *  pg_getnameinfo_all - get name info for Unix, IPv4 and IPv6 sockets
     107                 :  *
     108                 :  * The API of this routine differs from the standard getnameinfo() definition
     109                 :  * in two ways: first, the addr parameter is declared as sockaddr_storage
     110                 :  * rather than struct sockaddr, and second, the node and service fields are
     111                 :  * guaranteed to be filled with something even on failure return.
     112                 :  */
     113                 : int
     114 CBC       17901 : pg_getnameinfo_all(const struct sockaddr_storage *addr, int salen,
     115                 :                    char *node, int nodelen,
     116                 :                    char *service, int servicelen,
     117                 :                    int flags)
     118                 : {
     119 ECB             :     int         rc;
     120                 : 
     121 GIC       17901 :     if (addr && addr->ss_family == AF_UNIX)
     122           17625 :         rc = getnameinfo_unix((const struct sockaddr_un *) addr, salen,
     123 ECB             :                               node, nodelen,
     124                 :                               service, servicelen,
     125 EUB             :                               flags);
     126                 :     else
     127 GBC         276 :         rc = getnameinfo((const struct sockaddr *) addr, salen,
     128                 :                          node, nodelen,
     129                 :                          service, servicelen,
     130 ECB             :                          flags);
     131                 : 
     132 GIC       17901 :     if (rc != 0)
     133                 :     {
     134 UIC           0 :         if (node)
     135               0 :             strlcpy(node, "???", nodelen);
     136               0 :         if (service)
     137               0 :             strlcpy(service, "???", servicelen);
     138                 :     }
     139                 : 
     140 GIC       17901 :     return rc;
     141                 : }
     142                 : 
     143 ECB             : 
     144                 : /* -------
     145                 :  *  getaddrinfo_unix - get unix socket info using IPv6-compatible API
     146                 :  *
     147                 :  *  Bugs: only one addrinfo is set even though hintsp is NULL or
     148                 :  *        ai_socktype is 0
     149                 :  *        AI_CANONNAME is not supported.
     150                 :  * -------
     151 EUB             :  */
     152                 : static int
     153 CBC        9637 : getaddrinfo_unix(const char *path, const struct addrinfo *hintsp,
     154                 :                  struct addrinfo **result)
     155 EUB             : {
     156 GNC        9637 :     struct addrinfo hints = {0};
     157                 :     struct addrinfo *aip;
     158                 :     struct sockaddr_un *unp;
     159 ECB             : 
     160 GIC        9637 :     *result = NULL;
     161 ECB             : 
     162 CBC        9637 :     if (strlen(path) >= sizeof(unp->sun_path))
     163 UIC           0 :         return EAI_FAIL;
     164                 : 
     165 GBC        9637 :     if (hintsp == NULL)
     166                 :     {
     167 UIC           0 :         hints.ai_family = AF_UNIX;
     168 LBC           0 :         hints.ai_socktype = SOCK_STREAM;
     169 ECB             :     }
     170 EUB             :     else
     171 GIC        9637 :         memcpy(&hints, hintsp, sizeof(hints));
     172 ECB             : 
     173 CBC        9637 :     if (hints.ai_socktype == 0)
     174 UIC           0 :         hints.ai_socktype = SOCK_STREAM;
     175 EUB             : 
     176 GBC        9637 :     if (hints.ai_family != AF_UNIX)
     177                 :     {
     178                 :         /* shouldn't have been called */
     179 LBC           0 :         return EAI_FAIL;
     180 ECB             :     }
     181                 : 
     182 CBC        9637 :     aip = calloc(1, sizeof(struct addrinfo));
     183            9637 :     if (aip == NULL)
     184 LBC           0 :         return EAI_MEMORY;
     185                 : 
     186 CBC        9637 :     unp = calloc(1, sizeof(struct sockaddr_un));
     187            9637 :     if (unp == NULL)
     188 ECB             :     {
     189 UIC           0 :         free(aip);
     190 LBC           0 :         return EAI_MEMORY;
     191                 :     }
     192                 : 
     193 GIC        9637 :     aip->ai_family = AF_UNIX;
     194            9637 :     aip->ai_socktype = hints.ai_socktype;
     195            9637 :     aip->ai_protocol = hints.ai_protocol;
     196            9637 :     aip->ai_next = NULL;
     197            9637 :     aip->ai_canonname = NULL;
     198            9637 :     *result = aip;
     199                 : 
     200            9637 :     unp->sun_family = AF_UNIX;
     201 CBC        9637 :     aip->ai_addr = (struct sockaddr *) unp;
     202 GIC        9637 :     aip->ai_addrlen = sizeof(struct sockaddr_un);
     203 EUB             : 
     204 GBC        9637 :     strcpy(unp->sun_path, path);
     205                 : 
     206                 :     /*
     207 ECB             :      * If the supplied path starts with @, replace that with a zero byte for
     208                 :      * the internal representation.  In that mode, the entire sun_path is the
     209                 :      * address, including trailing zero bytes.  But we set the address length
     210                 :      * to only include the length of the original string.  That way the
     211                 :      * trailing zero bytes won't show up in any network or socket lists of the
     212                 :      * operating system.  This is just a convention, also followed by other
     213                 :      * packages.
     214                 :      */
     215 GIC        9637 :     if (path[0] == '@')
     216                 :     {
     217 UIC           0 :         unp->sun_path[0] = '\0';
     218               0 :         aip->ai_addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(path);
     219                 :     }
     220                 : 
     221 GIC        9637 :     return 0;
     222                 : }
     223                 : 
     224                 : /*
     225 ECB             :  * Convert an address to a hostname.
     226 EUB             :  */
     227                 : static int
     228 CBC       17625 : getnameinfo_unix(const struct sockaddr_un *sa, int salen,
     229 ECB             :                  char *node, int nodelen,
     230 EUB             :                  char *service, int servicelen,
     231                 :                  int flags)
     232                 : {
     233 ECB             :     int         ret;
     234                 : 
     235                 :     /* Invalid arguments. */
     236 GIC       17625 :     if (sa == NULL || sa->sun_family != AF_UNIX ||
     237            9047 :         (node == NULL && service == NULL))
     238 UIC           0 :         return EAI_FAIL;
     239                 : 
     240 GIC       17625 :     if (node)
     241                 :     {
     242            8578 :         ret = snprintf(node, nodelen, "%s", "[local]");
     243            8578 :         if (ret < 0 || ret >= nodelen)
     244 UIC           0 :             return EAI_MEMORY;
     245                 :     }
     246                 : 
     247 GIC       17625 :     if (service)
     248                 :     {
     249                 :         /*
     250                 :          * Check whether it looks like an abstract socket, but it could also
     251                 :          * just be an empty string.
     252                 :          */
     253           17618 :         if (sa->sun_path[0] == '\0' && sa->sun_path[1] != '\0')
     254 UIC           0 :             ret = snprintf(service, servicelen, "@%s", sa->sun_path + 1);
     255                 :         else
     256 GIC       17618 :             ret = snprintf(service, servicelen, "%s", sa->sun_path);
     257           17618 :         if (ret < 0 || ret >= servicelen)
     258 UIC           0 :             return EAI_MEMORY;
     259                 :     }
     260                 : 
     261 GIC       17625 :     return 0;
     262                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a