1 /*
2 * sock_addr - sockaddr manipulation
3 *
4 * Copyright(c) 2017 Glenn Strauss gstrauss()gluelogic.com All rights reserved
5 * License: BSD 3-clause (same as lighttpd)
6 */
7 #include "first.h"
8
9 #include "sock_addr.h"
10
11 #include "sys-socket.h"
12 #include <sys/types.h>
13 #include <errno.h>
14 #include <string.h>
15 #ifndef _WIN32
16 #include <netdb.h>
17 #include <arpa/inet.h>
18 #endif
19
20 #include "log.h"
21
22
sock_addr_get_port(const sock_addr * saddr)23 unsigned short sock_addr_get_port (const sock_addr *saddr)
24 {
25 switch (saddr->plain.sa_family) {
26 case AF_INET:
27 return ntohs(saddr->ipv4.sin_port);
28 #ifdef HAVE_IPV6
29 case AF_INET6:
30 return ntohs(saddr->ipv6.sin6_port);
31 #endif
32 #ifdef HAVE_SYS_UN_H
33 /*case AF_UNIX:*/
34 #endif
35 default:
36 return 0;
37 }
38 }
39
40
sock_addr_is_addr_wildcard(const sock_addr * saddr)41 int sock_addr_is_addr_wildcard (const sock_addr *saddr)
42 {
43 switch (saddr->plain.sa_family) {
44 case AF_INET:
45 return (saddr->ipv4.sin_addr.s_addr == INADDR_ANY); /*(htonl(0x0))*/
46 #ifdef HAVE_IPV6
47 case AF_INET6:
48 return !memcmp(&saddr->ipv6.sin6_addr,&in6addr_any,sizeof(in6addr_any));
49 #endif
50 #ifdef HAVE_SYS_UN_H
51 /*case AF_UNIX:*/
52 #endif
53 default:
54 return 0;
55 }
56 }
57
58
sock_addr_is_family_eq(const sock_addr * saddr1,const sock_addr * saddr2)59 int sock_addr_is_family_eq (const sock_addr *saddr1, const sock_addr *saddr2)
60 {
61 return saddr1->plain.sa_family == saddr2->plain.sa_family;
62 }
63
64
sock_addr_is_port_eq(const sock_addr * saddr1,const sock_addr * saddr2)65 int sock_addr_is_port_eq (const sock_addr *saddr1, const sock_addr *saddr2)
66 {
67 if (!sock_addr_is_family_eq(saddr1, saddr2)) return 0;
68 switch (saddr1->plain.sa_family) {
69 case AF_INET:
70 return saddr1->ipv4.sin_port == saddr2->ipv4.sin_port;
71 #ifdef HAVE_IPV6
72 case AF_INET6:
73 return saddr1->ipv6.sin6_port == saddr2->ipv6.sin6_port;
74 #endif
75 #ifdef HAVE_SYS_UN_H
76 case AF_UNIX:
77 return 1;
78 #endif
79 default:
80 return 0;
81 }
82 }
83
84
sock_addr_is_addr_eq(const sock_addr * saddr1,const sock_addr * saddr2)85 int sock_addr_is_addr_eq (const sock_addr *saddr1, const sock_addr *saddr2)
86 {
87 if (!sock_addr_is_family_eq(saddr1, saddr2)) return 0;
88 switch (saddr1->plain.sa_family) {
89 case AF_INET:
90 return saddr1->ipv4.sin_addr.s_addr == saddr2->ipv4.sin_addr.s_addr;
91 #ifdef HAVE_IPV6
92 case AF_INET6:
93 return 0 == memcmp(&saddr1->ipv6.sin6_addr, &saddr2->ipv6.sin6_addr,
94 sizeof(struct in6_addr));
95 #endif
96 #ifdef HAVE_SYS_UN_H
97 case AF_UNIX:
98 return 0 == strcmp(saddr1->un.sun_path, saddr2->un.sun_path);
99 #endif
100 default:
101 return 0;
102 }
103 }
104
105
106 #if 0
107 int sock_addr_is_addr_port_eq (const sock_addr *saddr1, const sock_addr *saddr2)
108 {
109 if (!sock_addr_is_family_eq(saddr1, saddr2)) return 0;
110 switch (saddr1->plain.sa_family) {
111 case AF_INET:
112 return saddr1->ipv4.sin_port == saddr2->ipv4.sin_port
113 && saddr1->ipv4.sin_addr.s_addr == saddr2->ipv4.sin_addr.s_addr;
114 #ifdef HAVE_IPV6
115 case AF_INET6:
116 return saddr1->ipv6.sin6_port == saddr2->ipv6.sin6_port
117 && 0 == memcmp(&saddr1->ipv6.sin6_addr, &saddr2->ipv6.sin6_addr,
118 sizeof(struct in6_addr));
119 #endif
120 #ifdef HAVE_SYS_UN_H
121 case AF_UNIX:
122 return 0 == strcmp(saddr1->un.sun_path, saddr2->un.sun_path);
123 #endif
124 default:
125 return 0;
126 }
127 }
128 #endif
129
130
sock_addr_is_addr_eq_bits(const sock_addr * a,const sock_addr * b,int bits)131 int sock_addr_is_addr_eq_bits(const sock_addr *a, const sock_addr *b, int bits) {
132 switch (a->plain.sa_family) {
133 case AF_INET:
134 {
135 uint32_t nm; /* build netmask */
136 if (bits > 32) bits = 32;
137 nm = htonl(~((1u << (32 - (0 != bits ? bits : 32))) - 1));
138 if (b->plain.sa_family == AF_INET) {
139 return
140 (a->ipv4.sin_addr.s_addr & nm) == (b->ipv4.sin_addr.s_addr & nm);
141 }
142 #ifdef HAVE_IPV6
143 else if (b->plain.sa_family == AF_INET6
144 && IN6_IS_ADDR_V4MAPPED(&b->ipv6.sin6_addr)) {
145 #ifdef s6_addr32
146 in_addr_t x = b->ipv6.sin6_addr.s6_addr32[3];
147 #else
148 in_addr_t x;
149 memcpy(&x, b->ipv6.sin6_addr.s6_addr+12, sizeof(in_addr_t));
150 #endif
151 return ((a->ipv4.sin_addr.s_addr & nm) == (x & nm));
152 }
153 #endif
154 return 0;
155 }
156 #ifdef HAVE_IPV6
157 case AF_INET6:
158 if (bits > 128) bits = 128;
159 if (b->plain.sa_family == AF_INET6) {
160 uint8_t *c = (uint8_t *)&a->ipv6.sin6_addr.s6_addr[0];
161 uint8_t *d = (uint8_t *)&b->ipv6.sin6_addr.s6_addr[0];
162 int match;
163 do {
164 match = (bits >= 8)
165 ? *c++ == *d++
166 : (*c >> (8 - bits)) == (*d >> (8 - bits));
167 } while (match && (bits -= 8) > 0);
168 return match;
169 }
170 else if (b->plain.sa_family == AF_INET
171 && IN6_IS_ADDR_V4MAPPED(&a->ipv6.sin6_addr)) {
172 uint32_t nm = bits < 128
173 ? htonl(~(~0u >> (bits > 96 ? bits - 96 : 0)))
174 : ~0u;
175 #ifdef s6_addr32
176 in_addr_t x = a->ipv6.sin6_addr.s6_addr32[3];
177 #else
178 in_addr_t x;
179 memcpy(&x, a->ipv6.sin6_addr.s6_addr+12, sizeof(in_addr_t));
180 #endif
181 return ((x & nm) == (b->ipv4.sin_addr.s_addr & nm));
182 }
183 return 0;
184 #endif
185 #ifdef HAVE_SYS_UN_H
186 /*case AF_UNIX:*/
187 #endif
188 default:
189 return 0;
190 }
191 }
192
193
sock_addr_set_port(sock_addr * const restrict saddr,const unsigned short port)194 void sock_addr_set_port (sock_addr * const restrict saddr, const unsigned short port)
195 {
196 switch (saddr->plain.sa_family) {
197 case AF_INET:
198 saddr->ipv4.sin_port = htons(port);
199 break;
200 #ifdef HAVE_IPV6
201 case AF_INET6:
202 saddr->ipv6.sin6_port = htons(port);
203 break;
204 #endif
205 #ifdef HAVE_SYS_UN_H
206 /*case AF_UNIX:*/
207 #endif
208 default:
209 break;
210 }
211 }
212
213
sock_addr_assign(sock_addr * const restrict saddr,int family,unsigned short nport,const void * const restrict naddr)214 int sock_addr_assign (sock_addr * const restrict saddr, int family, unsigned short nport, const void * const restrict naddr)
215 {
216 switch (family) {
217 case AF_INET:
218 memset(&saddr->ipv4, 0, sizeof(struct sockaddr_in));
219 saddr->ipv4.sin_family = AF_INET;
220 saddr->ipv4.sin_port = nport;
221 memcpy(&saddr->ipv4.sin_addr, naddr, 4);
222 return 0;
223 #ifdef HAVE_IPV6
224 case AF_INET6:
225 memset(&saddr->ipv6, 0, sizeof(struct sockaddr_in6));
226 saddr->ipv6.sin6_family = AF_INET6;
227 saddr->ipv6.sin6_port = nport;
228 memcpy(&saddr->ipv6.sin6_addr, naddr, 16);
229 return 0;
230 #endif
231 #ifdef HAVE_SYS_UN_H
232 case AF_UNIX:
233 {
234 size_t len = strlen((char *)naddr) + 1;
235 if (len > sizeof(saddr->un.sun_path)) {
236 errno = ENAMETOOLONG;
237 return -1;
238 }
239 memset(&saddr->un, 0, sizeof(struct sockaddr_un));
240 saddr->un.sun_family = AF_UNIX;
241 memcpy(saddr->un.sun_path, naddr, len);
242 return 0;
243 }
244 #endif
245 default:
246 errno = EAFNOSUPPORT;
247 return -1;
248 }
249 }
250
251
sock_addr_inet_pton(sock_addr * const restrict saddr,const char * const restrict str,int family,unsigned short port)252 int sock_addr_inet_pton(sock_addr * const restrict saddr,
253 const char * const restrict str,
254 int family, unsigned short port)
255 {
256 switch (family) {
257 case AF_INET:
258 memset(&saddr->ipv4, 0, sizeof(struct sockaddr_in));
259 saddr->ipv4.sin_family = AF_INET;
260 saddr->ipv4.sin_port = htons(port);
261 #ifdef HAVE_IPV6
262 return inet_pton(AF_INET, str, &saddr->ipv4.sin_addr);
263 #else
264 #if defined(HAVE_INET_ATON) /*(Windows does not provide inet_aton())*/
265 return (0 != inet_aton(str, &saddr->ipv4.sin_addr));
266 #else
267 return ((saddr->ipv4.sin_addr.s_addr = inet_addr(str)) != INADDR_NONE);
268 #endif
269 #endif
270 #ifdef HAVE_IPV6
271 case AF_INET6:
272 memset(&saddr->ipv6, 0, sizeof(struct sockaddr_in6));
273 saddr->ipv6.sin6_family = AF_INET6;
274 saddr->ipv6.sin6_port = htons(port);
275 return inet_pton(AF_INET6, str, &saddr->ipv6.sin6_addr);
276 #endif
277 default:
278 errno = EAFNOSUPPORT;
279 return -1;
280 }
281 }
282
283
sock_addr_inet_ntop(const sock_addr * const restrict saddr,char * const restrict buf,socklen_t sz)284 const char * sock_addr_inet_ntop(const sock_addr * const restrict saddr, char * const restrict buf, socklen_t sz)
285 {
286 switch (saddr->plain.sa_family) {
287 case AF_INET:
288 #if defined(HAVE_INET_PTON) /*(expect inet_ntop if inet_pton)*/
289 return inet_ntop(AF_INET,(const void *)&saddr->ipv4.sin_addr,buf,sz);
290 #else /*(inet_ntoa() not thread-safe)*/
291 return inet_ntoa(saddr->ipv4.sin_addr);
292 #endif
293 #ifdef HAVE_IPV6
294 case AF_INET6:
295 return inet_ntop(AF_INET6,(const void *)&saddr->ipv6.sin6_addr,buf,sz);
296 #endif
297 #ifdef HAVE_SYS_UN_H
298 case AF_UNIX:
299 return saddr->un.sun_path;
300 #endif
301 default:
302 errno = EAFNOSUPPORT;
303 return NULL;
304 }
305 }
306
307
sock_addr_inet_ntop_copy_buffer(buffer * const restrict b,const sock_addr * const restrict saddr)308 int sock_addr_inet_ntop_copy_buffer(buffer * const restrict b, const sock_addr * const restrict saddr)
309 {
310 /*(incur cost of extra copy to avoid potential extra memory allocation)*/
311 char buf[UNIX_PATH_MAX];
312 const char *s = sock_addr_inet_ntop(saddr, buf, sizeof(buf));
313 if (NULL == s) return -1; /*(buffer not modified if any error occurs)*/
314 buffer_copy_string(b, s);
315 return 0;
316 }
317
318
sock_addr_inet_ntop_append_buffer(buffer * const restrict b,const sock_addr * const restrict saddr)319 int sock_addr_inet_ntop_append_buffer(buffer * const restrict b, const sock_addr * const restrict saddr)
320 {
321 /*(incur cost of extra copy to avoid potential extra memory allocation)*/
322 char buf[UNIX_PATH_MAX];
323 const char *s = sock_addr_inet_ntop(saddr, buf, sizeof(buf));
324 if (NULL == s) return -1; /*(buffer not modified if any error occurs)*/
325 buffer_append_string(b, s);
326 return 0;
327 }
328
sock_addr_stringify_append_buffer(buffer * const restrict b,const sock_addr * const restrict saddr)329 int sock_addr_stringify_append_buffer(buffer * const restrict b, const sock_addr * const restrict saddr)
330 {
331 switch (saddr->plain.sa_family) {
332 case AF_INET:
333 if (0 != sock_addr_inet_ntop_append_buffer(b, saddr)) return -1;
334 buffer_append_string_len(b, CONST_STR_LEN(":"));
335 buffer_append_int(b, ntohs(saddr->ipv4.sin_port));
336 return 0;
337 #ifdef HAVE_IPV6
338 case AF_INET6:
339 buffer_append_string_len(b, CONST_STR_LEN("["));
340 if (0 != sock_addr_inet_ntop_append_buffer(b, saddr)) {
341 #ifdef __COVERITY__
342 force_assert(buffer_clen(b) > 0); /*(appended "[")*/
343 #endif
344 /* coverity[overflow_sink : FALSE] */
345 buffer_truncate(b, buffer_clen(b)-1);
346 return -1;
347 }
348 buffer_append_string_len(b, CONST_STR_LEN("]:"));
349 buffer_append_int(b, ntohs(saddr->ipv6.sin6_port));
350 return 0;
351 #endif
352 #ifdef HAVE_SYS_UN_H
353 case AF_UNIX:
354 buffer_append_string(b, saddr->un.sun_path);
355 return 0;
356 #endif
357 default:
358 return 0;
359 }
360 }
361
362
sock_addr_nameinfo_append_buffer(buffer * const restrict b,const sock_addr * const restrict saddr,log_error_st * const restrict errh)363 int sock_addr_nameinfo_append_buffer(buffer * const restrict b, const sock_addr * const restrict saddr, log_error_st * const restrict errh)
364 {
365 /*(this routine originates from
366 * http-header-glue.c:http_response_redirect_to_directory())*/
367 /*(note: name resolution here is *blocking*)*/
368 switch (saddr->plain.sa_family) {
369 #ifndef HAVE_IPV6
370 case AF_INET:
371 {
372 struct hostent *he = gethostbyaddr((char *)&saddr->ipv4.sin_addr,
373 sizeof(struct in_addr), AF_INET);
374 if (NULL == he) {
375 log_error(errh, __FILE__, __LINE__,
376 "NOTICE: gethostbyaddr failed: %d, using ip-address instead",
377 h_errno);
378
379 sock_addr_inet_ntop_append_buffer(b, saddr);
380 } else {
381 buffer_append_string(b, he->h_name);
382 }
383 return 0;
384 }
385 #else /* HAVE_IPV6 */
386 case AF_INET:
387 {
388 char hbuf[256];
389 int rc = getnameinfo((const struct sockaddr *)(&saddr->ipv4),
390 sizeof(saddr->ipv4),
391 hbuf, sizeof(hbuf), NULL, 0, 0);
392 if (0 != rc) {
393 log_error(errh, __FILE__, __LINE__,
394 "NOTICE: getnameinfo failed; using ip-address instead: %s",
395 gai_strerror(rc));
396
397 sock_addr_inet_ntop_append_buffer(b, saddr);
398 } else {
399 buffer_append_string(b, hbuf);
400 }
401 return 0;
402 }
403 case AF_INET6:
404 {
405 char hbuf[256];
406 int rc = getnameinfo((const struct sockaddr *)(&saddr->ipv6),
407 sizeof(saddr->ipv6),
408 hbuf, sizeof(hbuf), NULL, 0, 0);
409 if (0 != rc) {
410 log_error(errh, __FILE__, __LINE__,
411 "NOTICE: getnameinfo failed; using ip-address instead: %s",
412 gai_strerror(rc));
413
414 buffer_append_string_len(b, CONST_STR_LEN("["));
415 sock_addr_inet_ntop_append_buffer(b, saddr);
416 buffer_append_string_len(b, CONST_STR_LEN("]"));
417 } else {
418 buffer_append_string(b, hbuf);
419 }
420 return 0;
421 }
422 #endif
423 default:
424 log_error(errh, __FILE__, __LINE__, "ERROR: unsupported address-type");
425 return -1;
426 }
427 }
428
429
sock_addr_from_str_hints(sock_addr * const restrict saddr,socklen_t * const restrict len,const char * const restrict str,int family,unsigned short port,log_error_st * const restrict errh)430 int sock_addr_from_str_hints(sock_addr * const restrict saddr, socklen_t * const restrict len, const char * const restrict str, int family, unsigned short port, log_error_st * const restrict errh)
431 {
432 /*(note: name resolution here is *blocking*)*/
433 switch(family) {
434 case AF_UNSPEC:
435 if (0 == strcmp(str, "localhost")) {
436 /*(special-case "localhost" to IPv4 127.0.0.1)*/
437 memset(saddr, 0, sizeof(struct sockaddr_in));
438 saddr->ipv4.sin_family = AF_INET;
439 saddr->ipv4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
440 saddr->ipv4.sin_port = htons(port);
441 *len = sizeof(struct sockaddr_in);
442 return 1;
443 }
444 #ifdef HAVE_IPV6
445 else {
446 struct addrinfo hints, *res;
447 int rc;
448 memset(&hints, 0, sizeof(hints));
449 hints.ai_family = AF_UNSPEC;
450 hints.ai_socktype = SOCK_STREAM;
451 hints.ai_protocol = IPPROTO_TCP;
452
453 if (0 != (rc = getaddrinfo(str, NULL, &hints, &res))) {
454 log_error(errh, __FILE__, __LINE__,
455 "getaddrinfo failed: %s '%s'", gai_strerror(rc), str);
456 return 0;
457 }
458
459 memcpy(saddr, res->ai_addr, res->ai_addrlen);
460 freeaddrinfo(res);
461 if (AF_INET6 == saddr->plain.sa_family) {
462 saddr->ipv6.sin6_port = htons(port);
463 *len = sizeof(struct sockaddr_in6);
464 }
465 else { /* AF_INET */
466 saddr->ipv4.sin_port = htons(port);
467 *len = sizeof(struct sockaddr_in);
468 }
469 return 1;
470 }
471 #else
472 __attribute_fallthrough__
473 #endif
474 #ifdef HAVE_IPV6
475 case AF_INET6:
476 memset(saddr, 0, sizeof(struct sockaddr_in6));
477 saddr->ipv6.sin6_family = AF_INET6;
478 if (0 == strcmp(str, "::")) {
479 saddr->ipv6.sin6_addr = in6addr_any;
480 }
481 else if (0 == strcmp(str, "::1")) {
482 saddr->ipv6.sin6_addr = in6addr_loopback;
483 }
484 else {
485 struct addrinfo hints, *res;
486 int rc;
487
488 memset(&hints, 0, sizeof(hints));
489
490 hints.ai_family = AF_INET6;
491 hints.ai_socktype = SOCK_STREAM;
492 hints.ai_protocol = IPPROTO_TCP;
493
494 if (0 != (rc = getaddrinfo(str, NULL, &hints, &res))) {
495 hints.ai_family = AF_INET;
496 if (
497 #ifdef EAI_ADDRFAMILY
498 EAI_ADDRFAMILY == rc &&
499 #endif
500 0 == getaddrinfo(str, NULL, &hints, &res)) {
501 memcpy(saddr, res->ai_addr, res->ai_addrlen);
502 saddr->ipv4.sin_family = AF_INET;
503 saddr->ipv4.sin_port = htons(port);
504 *len = sizeof(struct sockaddr_in);
505 /*assert(*len == res->ai_addrlen);*/
506 freeaddrinfo(res);
507 return 1;
508 }
509
510 log_error(errh, __FILE__, __LINE__,
511 "getaddrinfo failed: %s '%s'", gai_strerror(rc), str);
512
513 return 0;
514 }
515
516 memcpy(saddr, res->ai_addr, res->ai_addrlen);
517 freeaddrinfo(res);
518 }
519 saddr->ipv6.sin6_port = htons(port);
520 *len = sizeof(struct sockaddr_in6);
521 return 1;
522 #endif
523 case AF_INET:
524 memset(saddr, 0, sizeof(struct sockaddr_in));
525 saddr->ipv4.sin_family = AF_INET;
526 if (0 == strcmp(str, "0.0.0.0")) {
527 saddr->ipv4.sin_addr.s_addr = htonl(INADDR_ANY);
528 }
529 else if (0 == strcmp(str, "127.0.0.1")) {
530 saddr->ipv4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
531 }
532 else {
533 #ifdef HAVE_INET_PTON
534 /*(reuse HAVE_INET_PTON for presence of getaddrinfo())*/
535 struct addrinfo hints, *res;
536 int rc;
537 memset(&hints, 0, sizeof(hints));
538 hints.ai_family = AF_INET;
539 hints.ai_socktype = SOCK_STREAM;
540 hints.ai_protocol = IPPROTO_TCP;
541
542 if (0 != (rc = getaddrinfo(str, NULL, &hints, &res))) {
543 log_error(errh, __FILE__, __LINE__,
544 "getaddrinfo failed: %s '%s'", gai_strerror(rc), str);
545 return 0;
546 }
547
548 memcpy(saddr, res->ai_addr, res->ai_addrlen);
549 freeaddrinfo(res);
550 #else
551 struct hostent *he = gethostbyname(str);
552 if (NULL == he) {
553 log_error(errh, __FILE__, __LINE__,
554 "gethostbyname failed: %d %s", h_errno, str);
555 return 0;
556 }
557
558 if (he->h_addrtype != AF_INET) {
559 log_error(errh, __FILE__, __LINE__,
560 "addr-type != AF_INET: %d", he->h_addrtype);
561 return 0;
562 }
563
564 if (he->h_length != sizeof(struct in_addr)) {
565 log_error(errh, __FILE__, __LINE__,
566 "addr-length != sizeof(in_addr): %d", he->h_length);
567 return 0;
568 }
569
570 memcpy(&saddr->ipv4.sin_addr.s_addr,
571 he->h_addr_list[0], he->h_length);
572 #endif
573 }
574 saddr->ipv4.sin_port = htons(port);
575 *len = sizeof(struct sockaddr_in);
576 return 1;
577 #ifdef HAVE_SYS_UN_H
578 case AF_UNIX:
579 memset(saddr, 0, sizeof(struct sockaddr_un));
580 saddr->un.sun_family = AF_UNIX;
581 {
582 size_t hostlen = strlen(str) + 1;
583 if (hostlen > sizeof(saddr->un.sun_path)) {
584 log_error(errh, __FILE__, __LINE__,
585 "unix socket filename too long: %s", str);
586 /*errno = ENAMETOOLONG;*/
587 return 0;
588 }
589 memcpy(saddr->un.sun_path, str, hostlen);
590 #if defined(SUN_LEN)
591 *len = SUN_LEN(&saddr->un)+1;
592 #else
593 *len = offsetof(struct sockaddr_un, sun_path) + hostlen;
594 #endif
595 }
596 return 1;
597 #else
598 case AF_UNIX:
599 log_error(errh, __FILE__, __LINE__,
600 "unix domain sockets are not supported.");
601 return 0;
602 #endif
603 default:
604 log_error(errh, __FILE__, __LINE__,
605 "address family unsupported: %d", family);
606 /*errno = EAFNOSUPPORT;*/
607 return 0;
608 }
609 }
610
611
sock_addr_from_str_numeric(sock_addr * const restrict saddr,const char * const restrict str,log_error_st * const restrict errh)612 int sock_addr_from_str_numeric(sock_addr * const restrict saddr, const char * const restrict str, log_error_st * const restrict errh)
613 {
614 /*(note: does not handle port if getaddrinfo() is not available)*/
615 /*(note: getaddrinfo() is stricter than inet_aton() in what is accepted)*/
616 /*(this routine originates from mod_extforward.c:ipstr_to_sockaddr()*/
617 #ifdef HAVE_IPV6
618 struct addrinfo hints, *addrlist = NULL;
619 int result;
620
621 /**
622 * quoting $ man getaddrinfo
623 *
624 * NOTES
625 * AI_ADDRCONFIG, AI_ALL, and AI_V4MAPPED are available since glibc 2.3.3.
626 * AI_NUMERICSERV is available since glibc 2.3.4.
627 */
628 #ifndef AI_NUMERICSERV
629 #define AI_NUMERICSERV 0
630 #endif
631 memset(&hints, 0, sizeof(hints));
632 hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
633
634 errno = 0;
635 result = getaddrinfo(str, NULL, &hints, &addrlist);
636
637 if (result != 0) {
638 log_perror(errh, __FILE__, __LINE__,
639 "could not parse ip address %s because %s",
640 str, gai_strerror(result));
641 return result;
642 } else if (addrlist == NULL) {
643 log_error(errh, __FILE__, __LINE__,
644 "Problem in parsing ip address %s:"
645 "succeeded, but no information returned", str);
646 return -1;
647 } else switch (addrlist->ai_family) {
648 case AF_INET:
649 memcpy(&saddr->ipv4, addrlist->ai_addr, sizeof(saddr->ipv4));
650 force_assert(AF_INET == saddr->plain.sa_family);
651 break;
652 case AF_INET6:
653 memcpy(&saddr->ipv6, addrlist->ai_addr, sizeof(saddr->ipv6));
654 force_assert(AF_INET6 == saddr->plain.sa_family);
655 break;
656 default:
657 log_error(errh, __FILE__, __LINE__,
658 "Problem in parsing ip address %s:"
659 "succeeded, but unknown family", str);
660 result = -1;
661 break;
662 }
663
664 freeaddrinfo(addrlist);
665 return (0 == result);
666 #else
667 UNUSED(errh);
668 saddr->ipv4.sin_addr.s_addr = inet_addr(str);
669 saddr->plain.sa_family = AF_INET;
670 return (saddr->ipv4.sin_addr.s_addr != 0xFFFFFFFF);
671 #endif
672 }
673
674
675 #if 0 /* unused */
676 int sock_addr_from_buffer_hints_numeric(sock_addr * const restrict saddr, socklen_t * const restrict len, const buffer * const restrict b, int family, unsigned short port, log_error_st * const restrict errh)
677 {
678 /*(this routine originates from mod_fastcgi.c and mod_scgi.c)*/
679 if (!b || buffer_is_blank(b)) {
680 /*(preserve existing behavior (for now))*/
681 /*(would be better if initialized default when reading config)*/
682 memset(&saddr->ipv4, 0, sizeof(struct sockaddr_in));
683 saddr->ipv4.sin_family = AF_INET;
684 saddr->ipv4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
685 saddr->ipv4.sin_port = htons(port);
686 *len = sizeof(struct sockaddr_in);
687 return 1;
688 }
689 else if (1 == sock_addr_inet_pton(saddr, b->ptr, family, port)) {
690 *len = (family == AF_INET)
691 ? sizeof(struct sockaddr_in) /* family == AF_INET */
692 : sizeof(struct sockaddr_in6); /* family == AF_INET6 */
693 return 1;
694 }
695 #if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
696 else if (family == AF_INET6) {
697 log_error(errh, __FILE__, __LINE__,
698 "invalid IPv6 address literal: %s", b->ptr);
699 return 0;
700 }
701 #endif
702 #ifndef HAVE_INET_PTON /*(preserve existing behavior (for now))*/
703 else {
704 struct hostent *he = gethostbyname(b->ptr);
705 if (NULL == he) {
706 log_error(errh, __FILE__, __LINE__,
707 "gethostbyname failed: %d %s", h_errno, b->ptr);
708 return 0;
709 }
710
711 if (he->h_addrtype != AF_INET) {
712 log_error(errh, __FILE__, __LINE__,
713 "addr-type != AF_INET: %d", he->h_addrtype);
714 return 0;
715 }
716
717 if (he->h_length != sizeof(struct in_addr)) {
718 log_error(errh, __FILE__, __LINE__,
719 "addr-length != sizeof(in_addr): %d", he->h_length);
720 return 0;
721 }
722
723 memset(&saddr->ipv4, 0, sizeof(struct sockaddr_in));
724 memcpy(&saddr->ipv4.sin_addr.s_addr, he->h_addr_list[0], he->h_length);
725 saddr->ipv4.sin_family = AF_INET;
726 saddr->ipv4.sin_port = htons(port);
727 *len = sizeof(struct sockaddr_in);
728 }
729 #else
730 UNUSED(errh);
731 #endif
732
733 return 0;
734 }
735 #endif
736