5 #include "sys-socket.h"
11 #include <arpa/inet.h>
18 unsigned short sock_addr_get_port (const sock_addr
*saddr
)
20 switch (saddr
->plain
.sa_family
) {
22 return ntohs(saddr
->ipv4
.sin_port
);
25 return ntohs(saddr
->ipv6
.sin6_port
);
36 int sock_addr_is_addr_wildcard (const sock_addr
*saddr
)
38 switch (saddr
->plain
.sa_family
) {
40 return (saddr
->ipv4
.sin_addr
.s_addr
== INADDR_ANY
); /*(htonl(0x0))*/
43 return !memcmp(&saddr
->ipv6
.sin6_addr
,&in6addr_any
,sizeof(in6addr_any
));
54 int sock_addr_is_family_eq (const sock_addr
*saddr1
, const sock_addr
*saddr2
)
56 return saddr1
->plain
.sa_family
== saddr2
->plain
.sa_family
;
60 int sock_addr_is_port_eq (const sock_addr
*saddr1
, const sock_addr
*saddr2
)
62 if (!sock_addr_is_family_eq(saddr1
, saddr2
)) return 0;
63 switch (saddr1
->plain
.sa_family
) {
65 return saddr1
->ipv4
.sin_port
== saddr2
->ipv4
.sin_port
;
68 return saddr1
->ipv6
.sin6_port
== saddr2
->ipv6
.sin6_port
;
80 int sock_addr_is_addr_eq (const sock_addr
*saddr1
, const sock_addr
*saddr2
)
82 if (!sock_addr_is_family_eq(saddr1
, saddr2
)) return 0;
83 switch (saddr1
->plain
.sa_family
) {
85 return saddr1
->ipv4
.sin_addr
.s_addr
== saddr2
->ipv4
.sin_addr
.s_addr
;
88 return 0 == memcmp(&saddr1
->ipv6
.sin6_addr
, &saddr2
->ipv6
.sin6_addr
,
89 sizeof(struct in6_addr
));
93 return 0 == strcmp(saddr1
->un
.sun_path
, saddr2
->un
.sun_path
);
102 int sock_addr_is_addr_port_eq (const sock_addr
*saddr1
, const sock_addr
*saddr2
)
104 if (!sock_addr_is_family_eq(saddr1
, saddr2
)) return 0;
105 switch (saddr1
->plain
.sa_family
) {
107 return saddr1
->ipv4
.sin_port
== saddr2
->ipv4
.sin_port
108 && saddr1
->ipv4
.sin_addr
.s_addr
== saddr2
->ipv4
.sin_addr
.s_addr
;
111 return saddr1
->ipv6
.sin6_port
== saddr2
->ipv6
.sin6_port
112 && 0 == memcmp(&saddr1
->ipv6
.sin6_addr
, &saddr2
->ipv6
.sin6_addr
,
113 sizeof(struct in6_addr
));
117 return 0 == strcmp(saddr1
->un
.sun_path
, saddr2
->un
.sun_path
);
126 int sock_addr_is_addr_eq_bits(const sock_addr
*a
, const sock_addr
*b
, int bits
) {
127 switch (a
->plain
.sa_family
) {
130 uint32_t nm
; /* build netmask */
131 if (bits
> 32) bits
= 32;
132 nm
= htonl(~((1u << (32 - (0 != bits
? bits
: 32))) - 1));
133 if (b
->plain
.sa_family
== AF_INET
) {
135 (a
->ipv4
.sin_addr
.s_addr
& nm
) == (b
->ipv4
.sin_addr
.s_addr
& nm
);
138 else if (b
->plain
.sa_family
== AF_INET6
139 && IN6_IS_ADDR_V4MAPPED(&b
->ipv6
.sin6_addr
)) {
141 in_addr_t x
= b
->ipv6
.sin6_addr
.s6_addr32
[3];
144 memcpy(&x
, b
->ipv6
.sin6_addr
.s6_addr
+12, sizeof(in_addr_t
));
146 return ((a
->ipv4
.sin_addr
.s_addr
& nm
) == (x
& nm
));
153 if (bits
> 128) bits
= 128;
154 if (b
->plain
.sa_family
== AF_INET6
) {
155 uint8_t *c
= (uint8_t *)&a
->ipv6
.sin6_addr
.s6_addr
[0];
156 uint8_t *d
= (uint8_t *)&b
->ipv6
.sin6_addr
.s6_addr
[0];
161 : (*c
>> (8 - bits
)) == (*d
>> (8 - bits
));
162 } while (match
&& (bits
-= 8) > 0);
165 else if (b
->plain
.sa_family
== AF_INET
166 && IN6_IS_ADDR_V4MAPPED(&a
->ipv6
.sin6_addr
)) {
167 uint32_t nm
= bits
< 128
168 ? htonl(~(~0u >> (bits
> 96 ? bits
- 96 : 0)))
171 in_addr_t x
= a
->ipv6
.sin6_addr
.s6_addr32
[3];
174 memcpy(&x
, a
->ipv6
.sin6_addr
.s6_addr
+12, sizeof(in_addr_t
));
176 return ((x
& nm
) == (b
->ipv4
.sin_addr
.s_addr
& nm
));
189 int sock_addr_assign (sock_addr
*saddr
, int family
, unsigned short nport
, const void *naddr
)
193 memset(&saddr
->ipv4
, 0, sizeof(struct sockaddr_in
));
194 saddr
->ipv4
.sin_family
= AF_INET
;
195 saddr
->ipv4
.sin_port
= nport
;
196 memcpy(&saddr
->ipv4
.sin_addr
, naddr
, 4);
200 memset(&saddr
->ipv6
, 0, sizeof(struct sockaddr_in6
));
201 saddr
->ipv6
.sin6_family
= AF_INET6
;
202 saddr
->ipv6
.sin6_port
= nport
;
203 memcpy(&saddr
->ipv6
.sin6_addr
, naddr
, 16);
209 size_t len
= strlen((char *)naddr
) + 1;
210 if (len
> sizeof(saddr
->un
.sun_path
)) {
211 errno
= ENAMETOOLONG
;
214 memset(&saddr
->un
, 0, sizeof(struct sockaddr_un
));
215 saddr
->un
.sun_family
= AF_UNIX
;
216 memcpy(saddr
->un
.sun_path
, naddr
, len
);
221 errno
= EAFNOSUPPORT
;
227 int sock_addr_inet_pton(sock_addr
*saddr
, const char *str
,
228 int family
, unsigned short port
)
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
));
238 return ((saddr
->ipv4
.sin_addr
.s_addr
= inet_addr(str
)) != INADDR_NONE
);
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
);
248 errno
= EAFNOSUPPORT
;
254 const char * sock_addr_inet_ntop(const sock_addr
*saddr
, char *buf
, socklen_t sz
)
256 switch (saddr
->plain
.sa_family
) {
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
);
265 return inet_ntop(AF_INET6
,(const void *)&saddr
->ipv6
.sin6_addr
,buf
,sz
);
269 return saddr
->un
.sun_path
;
272 errno
= EAFNOSUPPORT
;
278 int sock_addr_inet_ntop_copy_buffer(buffer
*b
, const sock_addr
*saddr
)
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
);
289 int sock_addr_inet_ntop_append_buffer(buffer
*b
, const sock_addr
*saddr
)
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
);
299 int sock_addr_stringify_append_buffer(buffer
*b
, const sock_addr
*saddr
)
301 switch (saddr
->plain
.sa_family
) {
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
));
309 buffer_append_string_len(b
, CONST_STR_LEN("["));
310 if (0 != sock_addr_inet_ntop_append_buffer(b
, saddr
)) {
311 buffer_string_set_length(b
, buffer_string_length(b
)-1);
314 buffer_append_string_len(b
, CONST_STR_LEN("]"));
315 buffer_append_string_len(b
, CONST_STR_LEN(":"));
316 buffer_append_int(b
, ntohs(saddr
->ipv6
.sin6_port
));
321 buffer_append_string(b
, saddr
->un
.sun_path
);
330 int sock_addr_nameinfo_append_buffer(server
*srv
, buffer
*b
, const sock_addr
*saddr
)
332 /*(this routine originates from
333 * http-header-glue.c:http_response_redirect_to_directory())*/
334 /*(note: name resolution here is *blocking*)*/
335 switch (saddr
->plain
.sa_family
) {
338 struct hostent
*he
= gethostbyaddr((char *)&saddr
->ipv4
.sin_addr
,
339 sizeof(struct in_addr
), AF_INET
);
341 log_error_write(srv
, __FILE__
, __LINE__
,
342 "SdS", "NOTICE: gethostbyaddr failed: ",
343 h_errno
, ", using ip-address instead");
345 sock_addr_inet_ntop_append_buffer(b
, saddr
);
347 buffer_append_string(b
, he
->h_name
);
355 if (0 != getnameinfo((const struct sockaddr
*)(&saddr
->ipv6
),
357 hbuf
, sizeof(hbuf
), NULL
, 0, 0)) {
358 log_error_write(srv
, __FILE__
, __LINE__
,
359 "SSS", "NOTICE: getnameinfo failed: ",
360 strerror(errno
), ", using ip-address instead");
362 buffer_append_string_len(b
, CONST_STR_LEN("["));
363 sock_addr_inet_ntop_append_buffer(b
, saddr
);
364 buffer_append_string_len(b
, CONST_STR_LEN("]"));
366 buffer_append_string(b
, hbuf
);
372 log_error_write(srv
, __FILE__
, __LINE__
,
373 "S", "ERROR: unsupported address-type");
379 int sock_addr_from_str_hints(server
*srv
, sock_addr
*saddr
, socklen_t
*len
, const char *str
, int family
, unsigned short port
)
381 /*(note: name resolution here is *blocking*)*/
384 if (0 == strcmp(str
, "localhost")) {
385 /*(special-case "localhost" to IPv4 127.0.0.1)*/
386 memset(saddr
, 0, sizeof(struct sockaddr_in
));
387 saddr
->ipv4
.sin_family
= AF_INET
;
388 saddr
->ipv4
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
389 saddr
->ipv4
.sin_port
= htons(port
);
390 *len
= sizeof(struct sockaddr_in
);
395 struct addrinfo hints
, *res
;
397 memset(&hints
, 0, sizeof(hints
));
398 hints
.ai_family
= AF_UNSPEC
;
399 hints
.ai_socktype
= SOCK_STREAM
;
400 hints
.ai_protocol
= IPPROTO_TCP
;
402 if (0 != (r
= getaddrinfo(str
, NULL
, &hints
, &res
))) {
403 log_error_write(srv
, __FILE__
, __LINE__
,
404 "sssss", "getaddrinfo failed: ",
405 gai_strerror(r
), "'", str
, "'");
409 memcpy(saddr
, res
->ai_addr
, res
->ai_addrlen
);
411 if (AF_INET6
== saddr
->plain
.sa_family
) {
412 saddr
->ipv6
.sin6_port
= htons(port
);
413 *len
= sizeof(struct sockaddr_in6
);
416 saddr
->ipv4
.sin_port
= htons(port
);
417 *len
= sizeof(struct sockaddr_in
);
426 memset(saddr
, 0, sizeof(struct sockaddr_in6
));
427 saddr
->ipv6
.sin6_family
= AF_INET6
;
428 if (0 == strcmp(str
, "::")) {
429 saddr
->ipv6
.sin6_addr
= in6addr_any
;
431 else if (0 == strcmp(str
, "::1")) {
432 saddr
->ipv6
.sin6_addr
= in6addr_loopback
;
435 struct addrinfo hints
, *res
;
438 memset(&hints
, 0, sizeof(hints
));
440 hints
.ai_family
= AF_INET6
;
441 hints
.ai_socktype
= SOCK_STREAM
;
442 hints
.ai_protocol
= IPPROTO_TCP
;
444 if (0 != (r
= getaddrinfo(str
, NULL
, &hints
, &res
))) {
445 hints
.ai_family
= AF_INET
;
447 #ifdef EAI_ADDRFAMILY
448 EAI_ADDRFAMILY
== r
&&
450 0 == getaddrinfo(str
, NULL
, &hints
, &res
)) {
451 memcpy(saddr
, res
->ai_addr
, res
->ai_addrlen
);
452 saddr
->ipv4
.sin_family
= AF_INET
;
453 saddr
->ipv4
.sin_port
= htons(port
);
454 *len
= sizeof(struct sockaddr_in
);
455 /*assert(*len == res->ai_addrlen);*/
460 log_error_write(srv
, __FILE__
, __LINE__
,
461 "sssss", "getaddrinfo failed: ",
462 gai_strerror(r
), "'", str
, "'");
467 memcpy(saddr
, res
->ai_addr
, res
->ai_addrlen
);
470 saddr
->ipv6
.sin6_port
= htons(port
);
471 *len
= sizeof(struct sockaddr_in6
);
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
);
480 else if (0 == strcmp(str
, "127.0.0.1")) {
481 saddr
->ipv4
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
484 #ifdef HAVE_INET_PTON
485 /*(reuse HAVE_INET_PTON for presence of getaddrinfo())*/
486 struct addrinfo hints
, *res
;
488 memset(&hints
, 0, sizeof(hints
));
489 hints
.ai_family
= AF_INET
;
490 hints
.ai_socktype
= SOCK_STREAM
;
491 hints
.ai_protocol
= IPPROTO_TCP
;
493 if (0 != (r
= getaddrinfo(str
, NULL
, &hints
, &res
))) {
494 log_error_write(srv
, __FILE__
, __LINE__
,
495 "sssss", "getaddrinfo failed: ",
496 gai_strerror(r
), "'", str
, "'");
500 memcpy(saddr
, res
->ai_addr
, res
->ai_addrlen
);
503 struct hostent
*he
= gethostbyname(str
);
505 log_error_write(srv
, __FILE__
, __LINE__
, "sds",
506 "gethostbyname failed:", h_errno
, str
);
510 if (he
->h_addrtype
!= AF_INET
) {
511 log_error_write(srv
, __FILE__
, __LINE__
, "sd",
512 "addr-type != AF_INET:", he
->h_addrtype
);
516 if (he
->h_length
!= sizeof(struct in_addr
)) {
517 log_error_write(srv
, __FILE__
, __LINE__
, "sd",
518 "addr-length != sizeof(in_addr):",he
->h_length
);
522 memcpy(&saddr
->ipv4
.sin_addr
.s_addr
,
523 he
->h_addr_list
[0], he
->h_length
);
526 saddr
->ipv4
.sin_port
= htons(port
);
527 *len
= sizeof(struct sockaddr_in
);
531 memset(saddr
, 0, sizeof(struct sockaddr_un
));
532 saddr
->un
.sun_family
= AF_UNIX
;
534 size_t hostlen
= strlen(str
) + 1;
535 if (hostlen
> sizeof(saddr
->un
.sun_path
)) {
536 log_error_write(srv
, __FILE__
, __LINE__
, "sS",
537 "unix socket filename too long:", str
);
538 /*errno = ENAMETOOLONG;*/
541 memcpy(saddr
->un
.sun_path
, str
, hostlen
);
543 *len
= SUN_LEN(&saddr
->un
);
546 *len
= hostlen
+ sizeof(saddr
->un
.sun_family
);
552 log_error_write(srv
, __FILE__
, __LINE__
, "s",
553 "unix domain sockets are not supported.");
557 log_error_write(srv
, __FILE__
, __LINE__
, "sd",
558 "address family unsupported:", family
);
559 /*errno = EAFNOSUPPORT;*/
565 int sock_addr_from_str_numeric(server
*srv
, sock_addr
*saddr
, const char *str
)
567 /*(note: does not handle port if getaddrinfo() is not available)*/
568 /*(note: getaddrinfo() is stricter than inet_aton() in what is accepted)*/
569 /*(this routine originates from mod_extforward.c:ipstr_to_sockaddr()*/
571 struct addrinfo hints
, *addrlist
= NULL
;
575 * quoting $ man getaddrinfo
578 * AI_ADDRCONFIG, AI_ALL, and AI_V4MAPPED are available since glibc 2.3.3.
579 * AI_NUMERICSERV is available since glibc 2.3.4.
581 #ifndef AI_NUMERICSERV
582 #define AI_NUMERICSERV 0
584 memset(&hints
, 0, sizeof(hints
));
585 hints
.ai_flags
= AI_NUMERICHOST
| AI_NUMERICSERV
;
588 result
= getaddrinfo(str
, NULL
, &hints
, &addrlist
);
591 log_error_write(srv
, __FILE__
, __LINE__
, "SSSs(S)",
592 "could not parse ip address ", str
, " because ",
593 gai_strerror(result
), strerror(errno
));
594 } else if (addrlist
== NULL
) {
595 log_error_write(srv
, __FILE__
, __LINE__
, "SSS",
596 "Problem in parsing ip address ", str
,
597 ": succeeded, but no information returned");
599 } else switch (addrlist
->ai_family
) {
601 memcpy(&saddr
->ipv4
, addrlist
->ai_addr
, sizeof(saddr
->ipv4
));
602 force_assert(AF_INET
== saddr
->plain
.sa_family
);
605 memcpy(&saddr
->ipv6
, addrlist
->ai_addr
, sizeof(saddr
->ipv6
));
606 force_assert(AF_INET6
== saddr
->plain
.sa_family
);
609 log_error_write(srv
, __FILE__
, __LINE__
, "SSS",
610 "Problem in parsing ip address ", str
,
611 ": succeeded, but unknown family");
616 freeaddrinfo(addrlist
);
617 return (0 == result
);
620 saddr
->ipv4
.sin_addr
.s_addr
= inet_addr(str
);
621 saddr
->plain
.sa_family
= AF_INET
;
622 return (saddr
->ipv4
.sin_addr
.s_addr
!= 0xFFFFFFFF);
627 int sock_addr_from_buffer_hints_numeric(server
*srv
, sock_addr
*saddr
, socklen_t
*len
, const buffer
*b
, int family
, unsigned short port
)
629 /*(this routine originates from mod_fastcgi.c and mod_scgi.c)*/
630 if (buffer_string_is_empty(b
)) {
631 /*(preserve existing behavior (for now))*/
632 /*(would be better if initialized default when reading config)*/
633 memset(&saddr
->ipv4
, 0, sizeof(struct sockaddr_in
));
634 saddr
->ipv4
.sin_family
= AF_INET
;
635 saddr
->ipv4
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
636 saddr
->ipv4
.sin_port
= htons(port
);
637 *len
= sizeof(struct sockaddr_in
);
640 else if (1 == sock_addr_inet_pton(saddr
, b
->ptr
, family
, port
)) {
641 *len
= (family
== AF_INET
)
642 ? sizeof(struct sockaddr_in
) /* family == AF_INET */
643 : sizeof(struct sockaddr_in6
); /* family == AF_INET6 */
646 #if defined(HAVE_IPV6) && defined(HAVE_INET_PTON)
647 else if (family
== AF_INET6
) {
648 log_error_write(srv
, __FILE__
, __LINE__
, "sb",
649 "invalid IPv6 address literal:", b
);
653 #ifndef HAVE_INET_PTON /*(preserve existing behavior (for now))*/
655 struct hostent
*he
= gethostbyname(b
->ptr
);
657 log_error_write(srv
, __FILE__
, __LINE__
, "sdb",
658 "gethostbyname failed:", h_errno
, b
);
662 if (he
->h_addrtype
!= AF_INET
) {
663 log_error_write(srv
, __FILE__
, __LINE__
, "sd",
664 "addr-type != AF_INET:", he
->h_addrtype
);
668 if (he
->h_length
!= sizeof(struct in_addr
)) {
669 log_error_write(srv
, __FILE__
, __LINE__
, "sd",
670 "addr-length != sizeof(in_addr):",he
->h_length
);
674 memset(&saddr
->ipv4
, 0, sizeof(struct sockaddr_in
));
675 memcpy(&saddr
->ipv4
.sin_addr
.s_addr
, he
->h_addr_list
[0], he
->h_length
);
676 saddr
->ipv4
.sin_family
= AF_INET
;
677 saddr
->ipv4
.sin_port
= htons(port
);
678 *len
= sizeof(struct sockaddr_in
);