xref: /lighttpd1.4/src/sock_addr.c (revision 3392e8fb)
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 
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 
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 
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 
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 
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 
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 
194 int sock_addr_assign (sock_addr * const restrict saddr, int family, unsigned short nport, const void * const restrict naddr)
195 {
196     switch (family) {
197       case AF_INET:
198         memset(&saddr->ipv4, 0, sizeof(struct sockaddr_in));
199         saddr->ipv4.sin_family = AF_INET;
200         saddr->ipv4.sin_port = nport;
201         memcpy(&saddr->ipv4.sin_addr, naddr, 4);
202         return 0;
203      #ifdef HAVE_IPV6
204       case AF_INET6:
205         memset(&saddr->ipv6, 0, sizeof(struct sockaddr_in6));
206         saddr->ipv6.sin6_family = AF_INET6;
207         saddr->ipv6.sin6_port = nport;
208         memcpy(&saddr->ipv6.sin6_addr, naddr, 16);
209         return 0;
210      #endif
211      #ifdef HAVE_SYS_UN_H
212       case AF_UNIX:
213       {
214         size_t len = strlen((char *)naddr) + 1;
215         if (len > sizeof(saddr->un.sun_path)) {
216             errno = ENAMETOOLONG;
217             return -1;
218         }
219         memset(&saddr->un, 0, sizeof(struct sockaddr_un));
220         saddr->un.sun_family = AF_UNIX;
221         memcpy(saddr->un.sun_path, naddr, len);
222         return 0;
223       }
224      #endif
225       default:
226         errno = EAFNOSUPPORT;
227         return -1;
228     }
229 }
230 
231 
232 int sock_addr_inet_pton(sock_addr * const restrict saddr,
233                         const char * const restrict str,
234                         int family, unsigned short port)
235 {
236     switch (family) {
237       case AF_INET:
238         memset(&saddr->ipv4, 0, sizeof(struct sockaddr_in));
239         saddr->ipv4.sin_family  = AF_INET;
240         saddr->ipv4.sin_port    = htons(port);
241      #ifdef HAVE_IPV6
242         return inet_pton(AF_INET, str, &saddr->ipv4.sin_addr);
243      #else
244       #if defined(HAVE_INET_ATON) /*(Windows does not provide inet_aton())*/
245         return (0 != inet_aton(str, &saddr->ipv4.sin_addr));
246       #else
247         return ((saddr->ipv4.sin_addr.s_addr = inet_addr(str)) != INADDR_NONE);
248       #endif
249      #endif
250      #ifdef HAVE_IPV6
251       case AF_INET6:
252         memset(&saddr->ipv6, 0, sizeof(struct sockaddr_in6));
253         saddr->ipv6.sin6_family = AF_INET6;
254         saddr->ipv6.sin6_port   = htons(port);
255         return inet_pton(AF_INET6, str, &saddr->ipv6.sin6_addr);
256      #endif
257       default:
258         errno = EAFNOSUPPORT;
259         return -1;
260     }
261 }
262 
263 
264 const char * sock_addr_inet_ntop(const sock_addr * const restrict saddr, char * const restrict buf, socklen_t sz)
265 {
266     switch (saddr->plain.sa_family) {
267       case AF_INET:
268        #if defined(HAVE_INET_PTON) /*(expect inet_ntop if inet_pton)*/
269         return inet_ntop(AF_INET,(const void *)&saddr->ipv4.sin_addr,buf,sz);
270        #else /*(inet_ntoa() not thread-safe)*/
271         return inet_ntoa(saddr->ipv4.sin_addr);
272        #endif
273      #ifdef HAVE_IPV6
274       case AF_INET6:
275         return inet_ntop(AF_INET6,(const void *)&saddr->ipv6.sin6_addr,buf,sz);
276      #endif
277      #ifdef HAVE_SYS_UN_H
278       case AF_UNIX:
279         return saddr->un.sun_path;
280      #endif
281       default:
282         errno = EAFNOSUPPORT;
283         return NULL;
284     }
285 }
286 
287 
288 int sock_addr_inet_ntop_copy_buffer(buffer * const restrict b, const sock_addr * const restrict saddr)
289 {
290     /*(incur cost of extra copy to avoid potential extra memory allocation)*/
291     char buf[UNIX_PATH_MAX];
292     const char *s = sock_addr_inet_ntop(saddr, buf, sizeof(buf));
293     if (NULL == s) return -1; /*(buffer not modified if any error occurs)*/
294     buffer_copy_string(b, s);
295     return 0;
296 }
297 
298 
299 int sock_addr_inet_ntop_append_buffer(buffer * const restrict b, const sock_addr * const restrict saddr)
300 {
301     /*(incur cost of extra copy to avoid potential extra memory allocation)*/
302     char buf[UNIX_PATH_MAX];
303     const char *s = sock_addr_inet_ntop(saddr, buf, sizeof(buf));
304     if (NULL == s) return -1; /*(buffer not modified if any error occurs)*/
305     buffer_append_string(b, s);
306     return 0;
307 }
308 
309 int sock_addr_stringify_append_buffer(buffer * const restrict b, const sock_addr * const restrict saddr)
310 {
311     switch (saddr->plain.sa_family) {
312       case AF_INET:
313         if (0 != sock_addr_inet_ntop_append_buffer(b, saddr)) return -1;
314         buffer_append_string_len(b, CONST_STR_LEN(":"));
315         buffer_append_int(b, ntohs(saddr->ipv4.sin_port));
316         return 0;
317      #ifdef HAVE_IPV6
318       case AF_INET6:
319         buffer_append_string_len(b, CONST_STR_LEN("["));
320         if (0 != sock_addr_inet_ntop_append_buffer(b, saddr)) {
321           #ifdef __COVERITY__
322             force_assert(buffer_string_length(b) > 0); /*(appended "[")*/
323           #endif
324             /* coverity[overflow_sink : FALSE] */
325             buffer_string_set_length(b, buffer_string_length(b)-1);
326             return -1;
327         }
328         buffer_append_string_len(b, CONST_STR_LEN("]:"));
329         buffer_append_int(b, ntohs(saddr->ipv6.sin6_port));
330         return 0;
331      #endif
332      #ifdef HAVE_SYS_UN_H
333       case AF_UNIX:
334         buffer_append_string(b, saddr->un.sun_path);
335         return 0;
336      #endif
337       default:
338         return 0;
339     }
340 }
341 
342 
343 int sock_addr_nameinfo_append_buffer(buffer * const restrict b, const sock_addr * const restrict saddr, log_error_st * const restrict errh)
344 {
345     /*(this routine originates from
346      * http-header-glue.c:http_response_redirect_to_directory())*/
347     /*(note: name resolution here is *blocking*)*/
348     switch (saddr->plain.sa_family) {
349      #ifndef HAVE_IPV6
350       case AF_INET:
351       {
352         struct hostent *he = gethostbyaddr((char *)&saddr->ipv4.sin_addr,
353                                            sizeof(struct in_addr), AF_INET);
354         if (NULL == he) {
355             log_error(errh, __FILE__, __LINE__,
356               "NOTICE: gethostbyaddr failed: %d, using ip-address instead",
357               h_errno);
358 
359             sock_addr_inet_ntop_append_buffer(b, saddr);
360         } else {
361             buffer_append_string(b, he->h_name);
362         }
363         return 0;
364       }
365      #else /* HAVE_IPV6 */
366       case AF_INET:
367       {
368         char hbuf[256];
369         int rc = getnameinfo((const struct sockaddr *)(&saddr->ipv4),
370                              sizeof(saddr->ipv4),
371                              hbuf, sizeof(hbuf), NULL, 0, 0);
372         if (0 != rc) {
373             log_error(errh, __FILE__, __LINE__,
374               "NOTICE: getnameinfo failed; using ip-address instead: %s",
375               gai_strerror(rc));
376 
377             sock_addr_inet_ntop_append_buffer(b, saddr);
378         } else {
379             buffer_append_string(b, hbuf);
380         }
381         return 0;
382       }
383       case AF_INET6:
384       {
385         char hbuf[256];
386         int rc = getnameinfo((const struct sockaddr *)(&saddr->ipv6),
387                              sizeof(saddr->ipv6),
388                              hbuf, sizeof(hbuf), NULL, 0, 0);
389         if (0 != rc) {
390             log_error(errh, __FILE__, __LINE__,
391               "NOTICE: getnameinfo failed; using ip-address instead: %s",
392               gai_strerror(rc));
393 
394             buffer_append_string_len(b, CONST_STR_LEN("["));
395             sock_addr_inet_ntop_append_buffer(b, saddr);
396             buffer_append_string_len(b, CONST_STR_LEN("]"));
397         } else {
398             buffer_append_string(b, hbuf);
399         }
400         return 0;
401       }
402      #endif
403       default:
404         log_error(errh, __FILE__, __LINE__, "ERROR: unsupported address-type");
405         return -1;
406     }
407 }
408 
409 
410 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)
411 {
412     /*(note: name resolution here is *blocking*)*/
413     switch(family) {
414       case AF_UNSPEC:
415         if (0 == strcmp(str, "localhost")) {
416             /*(special-case "localhost" to IPv4 127.0.0.1)*/
417             memset(saddr, 0, sizeof(struct sockaddr_in));
418             saddr->ipv4.sin_family = AF_INET;
419             saddr->ipv4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
420             saddr->ipv4.sin_port = htons(port);
421             *len = sizeof(struct sockaddr_in);
422             return 1;
423         }
424        #ifdef HAVE_IPV6
425         else {
426             struct addrinfo hints, *res;
427             int rc;
428             memset(&hints, 0, sizeof(hints));
429             hints.ai_family   = AF_UNSPEC;
430             hints.ai_socktype = SOCK_STREAM;
431             hints.ai_protocol = IPPROTO_TCP;
432 
433             if (0 != (rc = getaddrinfo(str, NULL, &hints, &res))) {
434                 log_error(errh, __FILE__, __LINE__,
435                   "getaddrinfo failed: %s '%s'", gai_strerror(rc), str);
436                 return 0;
437             }
438 
439             memcpy(saddr, res->ai_addr, res->ai_addrlen);
440             freeaddrinfo(res);
441             if (AF_INET6 == saddr->plain.sa_family) {
442                 saddr->ipv6.sin6_port = htons(port);
443                 *len = sizeof(struct sockaddr_in6);
444             }
445             else { /* AF_INET */
446                 saddr->ipv4.sin_port = htons(port);
447                 *len = sizeof(struct sockaddr_in);
448             }
449             return 1;
450         }
451        #else
452         __attribute_fallthrough__
453        #endif
454      #ifdef HAVE_IPV6
455       case AF_INET6:
456         memset(saddr, 0, sizeof(struct sockaddr_in6));
457         saddr->ipv6.sin6_family = AF_INET6;
458         if (0 == strcmp(str, "::")) {
459             saddr->ipv6.sin6_addr = in6addr_any;
460         }
461         else if (0 == strcmp(str, "::1")) {
462             saddr->ipv6.sin6_addr = in6addr_loopback;
463         }
464         else {
465             struct addrinfo hints, *res;
466             int rc;
467 
468             memset(&hints, 0, sizeof(hints));
469 
470             hints.ai_family   = AF_INET6;
471             hints.ai_socktype = SOCK_STREAM;
472             hints.ai_protocol = IPPROTO_TCP;
473 
474             if (0 != (rc = getaddrinfo(str, NULL, &hints, &res))) {
475                 hints.ai_family = AF_INET;
476                 if (
477                   #ifdef EAI_ADDRFAMILY
478                     EAI_ADDRFAMILY == rc &&
479                   #endif
480                     0 == getaddrinfo(str, NULL, &hints, &res)) {
481                     memcpy(saddr, res->ai_addr, res->ai_addrlen);
482                     saddr->ipv4.sin_family = AF_INET;
483                     saddr->ipv4.sin_port = htons(port);
484                     *len = sizeof(struct sockaddr_in);
485                     /*assert(*len == res->ai_addrlen);*/
486                     freeaddrinfo(res);
487                     return 1;
488                 }
489 
490                 log_error(errh, __FILE__, __LINE__,
491                   "getaddrinfo failed: %s '%s'", gai_strerror(rc), str);
492 
493                 return 0;
494             }
495 
496             memcpy(saddr, res->ai_addr, res->ai_addrlen);
497             freeaddrinfo(res);
498         }
499         saddr->ipv6.sin6_port = htons(port);
500         *len = sizeof(struct sockaddr_in6);
501         return 1;
502      #endif
503       case AF_INET:
504         memset(saddr, 0, sizeof(struct sockaddr_in));
505         saddr->ipv4.sin_family = AF_INET;
506         if (0 == strcmp(str, "0.0.0.0")) {
507             saddr->ipv4.sin_addr.s_addr = htonl(INADDR_ANY);
508         }
509         else if (0 == strcmp(str, "127.0.0.1")) {
510             saddr->ipv4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
511         }
512         else {
513           #ifdef HAVE_INET_PTON
514             /*(reuse HAVE_INET_PTON for presence of getaddrinfo())*/
515             struct addrinfo hints, *res;
516             int rc;
517             memset(&hints, 0, sizeof(hints));
518             hints.ai_family   = AF_INET;
519             hints.ai_socktype = SOCK_STREAM;
520             hints.ai_protocol = IPPROTO_TCP;
521 
522             if (0 != (rc = getaddrinfo(str, NULL, &hints, &res))) {
523                 log_error(errh, __FILE__, __LINE__,
524                   "getaddrinfo failed: %s '%s'", gai_strerror(rc), str);
525                 return 0;
526             }
527 
528             memcpy(saddr, res->ai_addr, res->ai_addrlen);
529             freeaddrinfo(res);
530           #else
531             struct hostent *he = gethostbyname(str);
532             if (NULL == he) {
533                 log_error(errh, __FILE__, __LINE__,
534                   "gethostbyname failed: %d %s", h_errno, str);
535                 return 0;
536             }
537 
538             if (he->h_addrtype != AF_INET) {
539                 log_error(errh, __FILE__, __LINE__,
540                   "addr-type != AF_INET: %d", he->h_addrtype);
541                 return 0;
542             }
543 
544             if (he->h_length != sizeof(struct in_addr)) {
545                 log_error(errh, __FILE__, __LINE__,
546                   "addr-length != sizeof(in_addr): %d", he->h_length);
547                 return 0;
548             }
549 
550             memcpy(&saddr->ipv4.sin_addr.s_addr,
551                    he->h_addr_list[0], he->h_length);
552           #endif
553         }
554         saddr->ipv4.sin_port = htons(port);
555         *len = sizeof(struct sockaddr_in);
556         return 1;
557      #ifdef HAVE_SYS_UN_H
558       case AF_UNIX:
559         memset(saddr, 0, sizeof(struct sockaddr_un));
560         saddr->un.sun_family = AF_UNIX;
561         {
562             size_t hostlen = strlen(str) + 1;
563             if (hostlen > sizeof(saddr->un.sun_path)) {
564                 log_error(errh, __FILE__, __LINE__,
565                   "unix socket filename too long: %s", str);
566                 /*errno = ENAMETOOLONG;*/
567                 return 0;
568             }
569             memcpy(saddr->un.sun_path, str, hostlen);
570           #if defined(SUN_LEN)
571             *len = SUN_LEN(&saddr->un)+1;
572           #else
573             *len = offsetof(struct sockaddr_un, sun_path) + hostlen;
574           #endif
575         }
576         return 1;
577      #else
578       case AF_UNIX:
579         log_error(errh, __FILE__, __LINE__,
580           "unix domain sockets are not supported.");
581         return 0;
582      #endif
583       default:
584         log_error(errh, __FILE__, __LINE__,
585           "address family unsupported: %d", family);
586         /*errno = EAFNOSUPPORT;*/
587         return 0;
588     }
589 }
590 
591 
592 int sock_addr_from_str_numeric(sock_addr * const restrict saddr, const char * const restrict str, log_error_st * const restrict errh)
593 {
594     /*(note: does not handle port if getaddrinfo() is not available)*/
595     /*(note: getaddrinfo() is stricter than inet_aton() in what is accepted)*/
596     /*(this routine originates from mod_extforward.c:ipstr_to_sockaddr()*/
597   #ifdef HAVE_IPV6
598     struct addrinfo hints, *addrlist = NULL;
599     int result;
600 
601     /**
602       * quoting $ man getaddrinfo
603       *
604       * NOTES
605       *  AI_ADDRCONFIG, AI_ALL, and AI_V4MAPPED are available since glibc 2.3.3.
606       *  AI_NUMERICSERV is available since glibc 2.3.4.
607       */
608    #ifndef AI_NUMERICSERV
609    #define AI_NUMERICSERV 0
610    #endif
611     memset(&hints, 0, sizeof(hints));
612     hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
613 
614     errno = 0;
615     result = getaddrinfo(str, NULL, &hints, &addrlist);
616 
617     if (result != 0) {
618         log_perror(errh, __FILE__, __LINE__,
619           "could not parse ip address %s because %s",
620           str, gai_strerror(result));
621         return result;
622     } else if (addrlist == NULL) {
623         log_error(errh, __FILE__, __LINE__,
624           "Problem in parsing ip address %s:"
625           "succeeded, but no information returned", str);
626         return -1;
627     } else switch (addrlist->ai_family) {
628     case AF_INET:
629         memcpy(&saddr->ipv4, addrlist->ai_addr, sizeof(saddr->ipv4));
630         force_assert(AF_INET == saddr->plain.sa_family);
631         break;
632     case AF_INET6:
633         memcpy(&saddr->ipv6, addrlist->ai_addr, sizeof(saddr->ipv6));
634         force_assert(AF_INET6 == saddr->plain.sa_family);
635         break;
636     default:
637         log_error(errh, __FILE__, __LINE__,
638           "Problem in parsing ip address %s:"
639           "succeeded, but unknown family", str);
640         result = -1;
641         break;
642     }
643 
644     freeaddrinfo(addrlist);
645     return (0 == result);
646   #else
647     UNUSED(errh);
648     saddr->ipv4.sin_addr.s_addr = inet_addr(str);
649     saddr->plain.sa_family = AF_INET;
650     return (saddr->ipv4.sin_addr.s_addr != 0xFFFFFFFF);
651   #endif
652 }
653 
654 
655 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)
656 {
657     /*(this routine originates from mod_fastcgi.c and mod_scgi.c)*/
658     if (buffer_string_is_empty(b)) {
659         /*(preserve existing behavior (for now))*/
660         /*(would be better if initialized default when reading config)*/
661         memset(&saddr->ipv4, 0, sizeof(struct sockaddr_in));
662         saddr->ipv4.sin_family = AF_INET;
663         saddr->ipv4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
664         saddr->ipv4.sin_port = htons(port);
665         *len = sizeof(struct sockaddr_in);
666         return 1;
667     }
668     else if (1 == sock_addr_inet_pton(saddr, b->ptr, family, port)) {
669         *len = (family == AF_INET)
670           ? sizeof(struct sockaddr_in)   /* family == AF_INET */
671           : sizeof(struct sockaddr_in6); /* family == AF_INET6 */
672         return 1;
673     }
674   #if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
675     else if (family == AF_INET6) {
676         log_error(errh, __FILE__, __LINE__,
677           "invalid IPv6 address literal: %s", b->ptr);
678         return 0;
679     }
680   #endif
681   #ifndef HAVE_INET_PTON /*(preserve existing behavior (for now))*/
682     else {
683         struct hostent *he = gethostbyname(b->ptr);
684         if (NULL == he) {
685             log_error(errh, __FILE__, __LINE__,
686               "gethostbyname failed: %d %s", h_errno, b->ptr);
687             return 0;
688         }
689 
690         if (he->h_addrtype != AF_INET) {
691             log_error(errh, __FILE__, __LINE__,
692               "addr-type != AF_INET: %d", he->h_addrtype);
693             return 0;
694         }
695 
696         if (he->h_length != sizeof(struct in_addr)) {
697             log_error(errh, __FILE__, __LINE__,
698               "addr-length != sizeof(in_addr): %d", he->h_length);
699             return 0;
700         }
701 
702         memset(&saddr->ipv4, 0, sizeof(struct sockaddr_in));
703         memcpy(&saddr->ipv4.sin_addr.s_addr, he->h_addr_list[0], he->h_length);
704         saddr->ipv4.sin_family = AF_INET;
705         saddr->ipv4.sin_port = htons(port);
706         *len = sizeof(struct sockaddr_in);
707     }
708   #else
709     UNUSED(errh);
710   #endif
711 
712     return 0;
713 }
714