1 #include <sys/socket.h>
2 #include <sys/un.h>
3
4 #include <netinet/in.h>
5
6 #include <arpa/inet.h>
7
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <netdb.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14
15 #include "imalloc.h"
16 #include "warnp.h"
17
18 #include "sock.h"
19 #include "sock_internal.h"
20
21 /* Convert a path into a socket address. */
22 static struct sock_addr **
sock_resolve_unix(const char * addr)23 sock_resolve_unix(const char * addr)
24 {
25 struct sock_addr ** sas;
26 struct sock_addr * sa;
27 struct sockaddr_un * sa_un;
28
29 /* Allocate and populate a sockaddr_un structure. */
30 if ((sa_un = calloc(1, sizeof(struct sockaddr_un))) == NULL)
31 goto err0;
32 sa_un->sun_family = AF_UNIX;
33 if (strlen(addr) >= sizeof(sa_un->sun_path)) {
34 warn0("socket path too long: %s", addr);
35 goto err1;
36 }
37 strcpy(sa_un->sun_path, addr);
38
39 /* Allocate and populate our wrapper. */
40 if ((sa = malloc(sizeof(struct sock_addr))) == NULL)
41 goto err1;
42 sa->ai_family = AF_UNIX;
43 sa->ai_socktype = SOCK_STREAM;
44 sa->name = (struct sockaddr *)sa_un;
45 sa->namelen = sizeof(struct sockaddr_un);
46
47 /* Allocate and populate an array of pointers. */
48 if ((sas = malloc(2 * sizeof(struct sock_addr *))) == NULL)
49 goto err2;
50 sas[0] = sa;
51 sas[1] = NULL;
52
53 /* Success! */
54 return (sas);
55
56 err2:
57 free(sa);
58 err1:
59 free(sa_un);
60 err0:
61 /* Failure! */
62 return (NULL);
63 }
64
65 /* Resolve a host into a list of socket addresses. */
66 static struct sock_addr **
sock_resolve_host(const char * addr,const char * ports)67 sock_resolve_host(const char * addr, const char * ports)
68 {
69 struct addrinfo hints;
70 struct addrinfo * res;
71 struct addrinfo * r;
72 struct sock_addr ** sas;
73 size_t n;
74 int error;
75
76 /* Create hints structure. */
77 memset(&hints, 0, sizeof(hints));
78 hints.ai_family = AF_UNSPEC;
79 hints.ai_socktype = SOCK_STREAM;
80 hints.ai_protocol = IPPROTO_TCP;
81
82 /* Perform DNS lookup. */
83 if ((error = getaddrinfo(addr, ports, &hints, &res)) != 0) {
84 warn0("Error looking up %s: %s", addr, gai_strerror(error));
85 goto err0;
86 }
87
88 /* Count addresses returned. */
89 for (n = 0, r = res; r != NULL; r = r->ai_next)
90 n++;
91
92 /* Allocate our response array. */
93 if (IMALLOC(sas, n + 1, struct sock_addr *))
94 goto err1;
95
96 /* Create address structures. */
97 for (n = 0, r = res; r != NULL; n++, r = r->ai_next) {
98 /* Allocate a structure. */
99 if ((sas[n] = malloc(sizeof(struct sock_addr))) == NULL)
100 goto err2;
101
102 /* Copy in the address metadata. */
103 sas[n]->ai_family = r->ai_family;
104 sas[n]->ai_socktype = r->ai_socktype;
105 sas[n]->namelen = r->ai_addrlen;
106
107 /* Duplicate the address. */
108 if ((sas[n]->name = malloc(sas[n]->namelen)) == NULL)
109 goto err3;
110 memcpy(sas[n]->name, r->ai_addr, sas[n]->namelen);
111 }
112
113 /* Terminate array with a NULL. */
114 sas[n] = NULL;
115
116 /* Free the linked list of addresses returned by getaddrinfo. */
117 freeaddrinfo(res);
118
119 /* Success! */
120 return (sas);
121
122 err3:
123 free(sas[n]);
124 err2:
125 for (; n > 0; n--)
126 sock_addr_free(sas[n - 1]);
127 free(sas);
128 err1:
129 freeaddrinfo(res);
130 err0:
131 /* Failure! */
132 return (NULL);
133 }
134
135 /* Parse an IPv6 address into a socket address. */
136 static struct sock_addr **
sock_resolve_ipv6(const char * addr,in_port_t p)137 sock_resolve_ipv6(const char * addr, in_port_t p)
138 {
139 struct sock_addr ** sas;
140 struct sock_addr * sa;
141 struct sockaddr_in6 * sin6;
142
143 /* Allocate and populate a sockaddr_in6 structure. */
144 if ((sin6 = calloc(1, sizeof(struct sockaddr_in6))) == NULL)
145 goto err0;
146 sin6->sin6_family = AF_INET6;
147 sin6->sin6_port = htons(p);
148 if (inet_pton(AF_INET6, addr, &sin6->sin6_addr) != 1) {
149 warn0("Error parsing IP address: %s", addr);
150 goto err1;
151 }
152
153 /* Allocate and populate our wrapper. */
154 if ((sa = malloc(sizeof(struct sock_addr))) == NULL)
155 goto err1;
156 sa->ai_family = AF_INET6;
157 sa->ai_socktype = SOCK_STREAM;
158 sa->name = (struct sockaddr *)sin6;
159 sa->namelen = sizeof(struct sockaddr_in6);
160
161 /* Allocate and populate an array of pointers. */
162 if ((sas = malloc(2 * sizeof(struct sock_addr *))) == NULL)
163 goto err2;
164 sas[0] = sa;
165 sas[1] = NULL;
166
167 /* Success! */
168 return (sas);
169
170 err2:
171 free(sa);
172 err1:
173 free(sin6);
174 err0:
175 /* Failure! */
176 return (NULL);
177 }
178
179 /* Parse an IPv4 address into a socket address. */
180 static struct sock_addr **
sock_resolve_ipv4(const char * addr,in_port_t p)181 sock_resolve_ipv4(const char * addr, in_port_t p)
182 {
183 struct sock_addr ** sas;
184 struct sock_addr * sa;
185 struct sockaddr_in * sin;
186
187 /* Allocate and populate a sockaddr_in structure. */
188 if ((sin = calloc(1, sizeof(struct sockaddr_in))) == NULL)
189 goto err0;
190 sin->sin_family = AF_INET;
191 sin->sin_port = htons(p);
192 if (inet_pton(AF_INET, addr, &sin->sin_addr) != 1) {
193 warn0("Error parsing IP address: %s", addr);
194 goto err1;
195 }
196
197 /* Allocate and populate our wrapper. */
198 if ((sa = malloc(sizeof(struct sock_addr))) == NULL)
199 goto err1;
200 sa->ai_family = AF_INET;
201 sa->ai_socktype = SOCK_STREAM;
202 sa->name = (struct sockaddr *)sin;
203 sa->namelen = sizeof(struct sockaddr_in);
204
205 /* Allocate and populate an array of pointers. */
206 if ((sas = malloc(2 * sizeof(struct sock_addr *))) == NULL)
207 goto err2;
208 sas[0] = sa;
209 sas[1] = NULL;
210
211 /* Success! */
212 return (sas);
213
214 err2:
215 free(sa);
216 err1:
217 free(sin);
218 err0:
219 /* Failure! */
220 return (NULL);
221 }
222
223 /**
224 * sock_resolve(addr):
225 * Return a NULL-terminated array of pointers to sock_addr structures.
226 */
227 struct sock_addr **
sock_resolve(const char * addr)228 sock_resolve(const char * addr)
229 {
230 struct sock_addr ** res;
231 char * s;
232 char * ports;
233 char * ips;
234 long p;
235
236 /* If the address starts with '/', it's a Unix domain socket. */
237 if (addr[0] == '/') {
238 res = sock_resolve_unix(addr);
239 goto done0;
240 }
241
242 /* Copy the address so that we can mangle it. */
243 if ((s = strdup(addr)) == NULL)
244 goto err0;
245
246 /* The address should end with :port. Look for the last ':'. */
247 if ((ports = strrchr(s, ':')) == NULL) {
248 warn0("Address must contain port number: %s", s);
249 goto err1;
250 }
251 *ports++ = '\0';
252
253 /* If the address doesn't start with '[', it's a host name. */
254 if (s[0] != '[') {
255 res = sock_resolve_host(s, ports);
256 goto done1;
257 }
258
259 /* The address (sans :port) should end with ']'. */
260 if (s[strlen(s) - 1] != ']') {
261 warn0("Invalid [IP address]: %s", s);
262 goto err1;
263 }
264
265 /* Extract the IP address string. */
266 ips = &s[1];
267 ips[strlen(ips) - 1] = '\0';
268
269 /*
270 * Parse the port number. If strtol fails to parse the port number,
271 * it will return 0; but that's fine since port 0 is invalid anyway.
272 */
273 p = strtol(ports, NULL, 10);
274 if ((p <= 0) || (p >= 65536)) {
275 warn0("Invalid port number: %s", ports);
276 goto err1;
277 }
278
279 /* If the IP address contains ':', it's IPv6; otherwise, IPv4. */
280 if (strchr(ips, ':') != NULL)
281 res = sock_resolve_ipv6(ips, (in_port_t)p);
282 else
283 res = sock_resolve_ipv4(ips, (in_port_t)p);
284
285 done1:
286 /* Free string allocated by strdup. */
287 free(s);
288 done0:
289 /* Return result from sock_resolve_foo. */
290 return (res);
291
292 err1:
293 free(s);
294 err0:
295 /* Failure! */
296 return (NULL);
297 }
298
299 /**
300 * sock_listener(sa):
301 * Create a socket, set SO_REUSEADDR, bind it to the socket address ${sa},
302 * mark it for listening, and mark it as non-blocking.
303 */
304 int
sock_listener(const struct sock_addr * sa)305 sock_listener(const struct sock_addr * sa)
306 {
307 int s;
308 int val = 1;
309
310 /* Create a socket. */
311 if ((s = socket(sa->ai_family, sa->ai_socktype, 0)) == -1) {
312 warnp("socket(%d, %d)", sa->ai_family, sa->ai_socktype);
313 goto err0;
314 }
315
316 /* Set SO_REUSEADDR. */
317 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))) {
318 warnp("setsockopt(SO_REUSEADDR)");
319 goto err1;
320 }
321
322 /* Bind the socket. */
323 if (bind(s, sa->name, sa->namelen)) {
324 warnp("Error binding socket");
325 goto err1;
326 }
327
328 /* Mark the socket as listening. */
329 if (listen(s, 10)) {
330 warnp("Error marking socket as listening");
331 goto err1;
332 }
333
334 /* Mark the socket as non-blocking. */
335 if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) {
336 warnp("Error marking socket as non-blocking");
337 goto err1;
338 }
339
340 /* Success! */
341 return (s);
342
343 err1:
344 close(s);
345 err0:
346 /* Failure! */
347 return (-1);
348 }
349
350 /**
351 * sock_connect(sas):
352 * Iterate through the addresses in ${sas}, attempting to create a socket and
353 * connect (blockingly). Once connected, stop iterating, mark the socket as
354 * non-blocking, and return it.
355 */
356 int
sock_connect(struct sock_addr * const * sas)357 sock_connect(struct sock_addr * const * sas)
358 {
359 int s = -1;
360
361 /* Iterate through the addresses provided. */
362 for (; sas[0] != NULL; sas++) {
363 /* Create a socket. */
364 if ((s = socket(sas[0]->ai_family,
365 sas[0]->ai_socktype, 0)) == -1)
366 continue;
367
368 /* Attempt to connect. */
369 if (connect(s, sas[0]->name, sas[0]->namelen) == 0)
370 break;
371
372 /* Close the socket; this address didn't work. */
373 close(s);
374 }
375
376 /* Did we manage to connect? */
377 if (sas[0] == NULL) {
378 warn0("Could not connect");
379 goto err0;
380 }
381
382 /* Mark the socket as non-blocking. */
383 if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) {
384 warnp("Cannot make connection non-blocking");
385 goto err1;
386 }
387
388 /* Success! */
389 return (s);
390
391 err1:
392 close(s);
393 err0:
394 /* Failure! */
395 return (-1);
396 }
397
398 /**
399 * sock_connect_nb(sa):
400 * Create a socket, mark it as non-blocking, and attempt to connect to the
401 * address ${sa}. Return the socket (connected or in the process of
402 * connecting) or -1 on error.
403 */
404 int
sock_connect_nb(const struct sock_addr * sa)405 sock_connect_nb(const struct sock_addr * sa)
406 {
407 int s;
408
409 /* Create a socket. */
410 if ((s = socket(sa->ai_family, sa->ai_socktype, 0)) == -1)
411 goto err0;
412
413 /* Mark the socket as non-blocking. */
414 if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) {
415 warnp("Cannot make socket non-blocking");
416 goto err1;
417 }
418
419 /* Attempt to connect. */
420 if ((connect(s, sa->name, sa->namelen) == -1) &&
421 (errno != EINPROGRESS) &&
422 (errno != EINTR))
423 goto err1;
424
425 /* We have a connect(ed|ing) socket. */
426 return (s);
427
428 err1:
429 close(s);
430 err0:
431 /* We failed to connect to this address. */
432 return (-1);
433 }
434
435 /**
436 * sock_addr_free(sa):
437 * Free the provided sock_addr structure.
438 */
439 void
sock_addr_free(struct sock_addr * sa)440 sock_addr_free(struct sock_addr * sa)
441 {
442
443 /* Behave consistently with free(NULL). */
444 if (sa == NULL)
445 return;
446
447 /* Free the protocol-specific address structure and our struct. */
448 free(sa->name);
449 free(sa);
450 }
451
452 /**
453 * sock_addr_freelist(sas):
454 * Free the provided NULL-terminated array of sock_addr structures.
455 */
456 void
sock_addr_freelist(struct sock_addr ** sas)457 sock_addr_freelist(struct sock_addr ** sas)
458 {
459 struct sock_addr ** p;
460
461 /* Behave consistently with free(NULL). */
462 if (sas == NULL)
463 return;
464
465 /* Free structures until we hit NULL. */
466 for (p = sas; *p != NULL; p++)
467 sock_addr_free(*p);
468
469 /* Free the list. */
470 free(sas);
471 }
472