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