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