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