YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/build/debugcov-clang-dynamic-arm64-ninja/postgres_build/src/interfaces/libpq/ip.c
Line
Count
Source (jump to first uncovered line)
1
/*-------------------------------------------------------------------------
2
 *
3
 * ip.c
4
 *    IPv6-aware network access.
5
 *
6
 * Portions Copyright (c) 1996-2018, 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
#ifdef HAVE_NETINET_TCP_H
32
#include <netinet/tcp.h>
33
#endif
34
#include <arpa/inet.h>
35
#include <sys/file.h>
36
37
#include "common/ip.h"
38
39
40
41
#ifdef  HAVE_UNIX_SOCKETS
42
static int getaddrinfo_unix(const char *path,
43
         const struct addrinfo *hintsp,
44
         struct addrinfo **result);
45
46
static int getnameinfo_unix(const struct sockaddr_un *sa, int salen,
47
         char *node, int nodelen,
48
         char *service, int servicelen,
49
         int flags);
50
#endif
51
52
53
/*
54
 *  pg_getaddrinfo_all - get address info for Unix, IPv4 and IPv6 sockets
55
 */
56
int
57
pg_getaddrinfo_all(const char *hostname, const char *servname,
58
           const struct addrinfo *hintp, struct addrinfo **result)
59
3.59k
{
60
3.59k
  int     rc;
61
62
  /* not all versions of getaddrinfo() zero *result on failure */
63
3.59k
  *result = NULL;
64
65
3.59k
#ifdef HAVE_UNIX_SOCKETS
66
3.59k
  if (hintp->ai_family == AF_UNIX)
67
1.13k
    return getaddrinfo_unix(servname, hintp, result);
68
2.45k
#endif
69
70
  /* NULL has special meaning to getaddrinfo(). */
71
2.45k
  rc = getaddrinfo((!hostname || hostname[0] == '\0') ? NULL : hostname,
72
2.45k
           servname, hintp, result);
73
74
2.45k
  return rc;
75
2.45k
}
76
77
78
/*
79
 *  pg_freeaddrinfo_all - free addrinfo structures for IPv4, IPv6, or Unix
80
 *
81
 * Note: the ai_family field of the original hint structure must be passed
82
 * so that we can tell whether the addrinfo struct was built by the system's
83
 * getaddrinfo() routine or our own getaddrinfo_unix() routine.  Some versions
84
 * of getaddrinfo() might be willing to return AF_UNIX addresses, so it's
85
 * not safe to look at ai_family in the addrinfo itself.
86
 */
87
void
88
pg_freeaddrinfo_all(int hint_ai_family, struct addrinfo *ai)
89
3.59k
{
90
3.59k
#ifdef HAVE_UNIX_SOCKETS
91
3.59k
  if (hint_ai_family == AF_UNIX)
92
1.13k
  {
93
    /* struct was built by getaddrinfo_unix (see pg_getaddrinfo_all) */
94
2.27k
    while (ai != NULL)
95
1.13k
    {
96
1.13k
      struct addrinfo *p = ai;
97
98
1.13k
      ai = ai->ai_next;
99
1.13k
      free(p->ai_addr);
100
1.13k
      free(p);
101
1.13k
    }
102
1.13k
  }
103
2.45k
  else
104
2.45k
#endif              /* HAVE_UNIX_SOCKETS */
105
2.45k
  {
106
    /* struct was built by getaddrinfo() */
107
2.45k
    if (ai != NULL)
108
2.45k
      freeaddrinfo(ai);
109
2.45k
  }
110
3.59k
}
111
112
113
/*
114
 *  pg_getnameinfo_all - get name info for Unix, IPv4 and IPv6 sockets
115
 *
116
 * The API of this routine differs from the standard getnameinfo() definition
117
 * in two ways: first, the addr parameter is declared as sockaddr_storage
118
 * rather than struct sockaddr, and second, the node and service fields are
119
 * guaranteed to be filled with something even on failure return.
120
 */
121
int
122
pg_getnameinfo_all(const struct sockaddr_storage *addr, int salen,
123
           char *node, int nodelen,
124
           char *service, int servicelen,
125
           int flags)
126
2.56k
{
127
2.56k
  int     rc;
128
129
2.56k
#ifdef HAVE_UNIX_SOCKETS
130
2.56k
  if (addr && addr->ss_family == AF_UNIX)
131
235
    rc = getnameinfo_unix((const struct sockaddr_un *) addr, salen,
132
235
                node, nodelen,
133
235
                service, servicelen,
134
235
                flags);
135
2.32k
  else
136
2.32k
#endif
137
2.32k
    rc = getnameinfo((const struct sockaddr *) addr, salen,
138
2.32k
             node, nodelen,
139
2.32k
             service, servicelen,
140
2.32k
             flags);
141
142
2.56k
  if (rc != 0)
143
0
  {
144
0
    if (node)
145
0
      strlcpy(node, "???", nodelen);
146
0
    if (service)
147
0
      strlcpy(service, "???", servicelen);
148
0
  }
149
150
2.56k
  return rc;
151
2.56k
}
152
153
154
#if defined(HAVE_UNIX_SOCKETS)
155
156
/* -------
157
 *  getaddrinfo_unix - get unix socket info using IPv6-compatible API
158
 *
159
 *  Bugs: only one addrinfo is set even though hintsp is NULL or
160
 *      ai_socktype is 0
161
 *      AI_CANONNAME is not supported.
162
 * -------
163
 */
164
static int
165
getaddrinfo_unix(const char *path, const struct addrinfo *hintsp,
166
         struct addrinfo **result)
167
1.13k
{
168
1.13k
  struct addrinfo hints;
169
1.13k
  struct addrinfo *aip;
170
1.13k
  struct sockaddr_un *unp;
171
172
1.13k
  *result = NULL;
173
174
1.13k
  MemSet(&hints, 0, sizeof(hints));
175
176
1.13k
  if (strlen(path) >= sizeof(unp->sun_path))
177
0
    return EAI_FAIL;
178
179
1.13k
  if (hintsp == NULL)
180
0
  {
181
0
    hints.ai_family = AF_UNIX;
182
0
    hints.ai_socktype = SOCK_STREAM;
183
0
  }
184
1.13k
  else
185
1.13k
    memcpy(&hints, hintsp, sizeof(hints));
186
187
1.13k
  if (hints.ai_socktype == 0)
188
0
    hints.ai_socktype = SOCK_STREAM;
189
190
1.13k
  if (hints.ai_family != AF_UNIX)
191
0
  {
192
    /* shouldn't have been called */
193
0
    return EAI_FAIL;
194
0
  }
195
196
1.13k
  aip = calloc(1, sizeof(struct addrinfo));
197
1.13k
  if (aip == NULL)
198
0
    return EAI_MEMORY;
199
200
1.13k
  unp = calloc(1, sizeof(struct sockaddr_un));
201
1.13k
  if (unp == NULL)
202
0
  {
203
0
    free(aip);
204
0
    return EAI_MEMORY;
205
0
  }
206
207
1.13k
  aip->ai_family = AF_UNIX;
208
1.13k
  aip->ai_socktype = hints.ai_socktype;
209
1.13k
  aip->ai_protocol = hints.ai_protocol;
210
1.13k
  aip->ai_next = NULL;
211
1.13k
  aip->ai_canonname = NULL;
212
1.13k
  *result = aip;
213
214
1.13k
  unp->sun_family = AF_UNIX;
215
1.13k
  aip->ai_addr = (struct sockaddr *) unp;
216
1.13k
  aip->ai_addrlen = sizeof(struct sockaddr_un);
217
218
1.13k
  strcpy(unp->sun_path, path);
219
220
1.13k
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN
221
1.13k
  unp->sun_len = sizeof(struct sockaddr_un);
222
1.13k
#endif
223
224
1.13k
  return 0;
225
1.13k
}
226
227
/*
228
 * Convert an address to a hostname.
229
 */
230
static int
231
getnameinfo_unix(const struct sockaddr_un *sa, int salen,
232
         char *node, int nodelen,
233
         char *service, int servicelen,
234
         int flags)
235
235
{
236
235
  int     ret;
237
238
  /* Invalid arguments. */
239
235
  if (sa == NULL || sa->sun_family != AF_UNIX ||
240
235
    (node == NULL && service == NULL))
241
0
    return EAI_FAIL;
242
243
235
  if (node)
244
235
  {
245
235
    ret = snprintf(node, nodelen, "%s", "[local]");
246
235
    if (ret < 0 || ret >= nodelen)
247
0
      return EAI_MEMORY;
248
235
  }
249
250
235
  if (service)
251
235
  {
252
235
    ret = snprintf(service, servicelen, "%s", sa->sun_path);
253
235
    if (ret < 0 || ret >= servicelen)
254
0
      return EAI_MEMORY;
255
235
  }
256
257
235
  return 0;
258
235
}
259
#endif              /* HAVE_UNIX_SOCKETS */