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