/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 */ |