diff --git a/configure.in b/configure.in index 179f944..68d4d31 100644 --- a/configure.in +++ b/configure.in @@ -1215,7 +1215,7 @@ AC_FUNC_SETPGRP AC_TYPE_SIGNAL dnl uncommenting does not work for swa. suse linux dnl AC_FUNC_STAT -AC_CHECK_FUNCS([access atexit getcwd gethostbyaddr gethostbyaddr_r gethostbyname gethostbyname_r gettimeofday inet_ntoa localtime_r memchr memmove memset putenv random regcomp select setlocale snprintf socket strchr strdup strerror strftime strlcat strlcpy strptime strstr strtoul timegm tzset]) +AC_CHECK_FUNCS([access atexit getaddrinfo getcwd gethostbyaddr gethostbyaddr_r gethostbyname gethostbyname_r getnameinfo gettimeofday inet_ntoa localtime_r memchr memmove memset putenv random regcomp select setlocale snprintf socket strchr strdup strerror strftime strlcat strlcpy strptime strstr strtoul timegm tzset]) dnl ================================================================= diff --git a/filters.c b/filters.c index 96e2a55..6b03dbd 100644 --- a/filters.c +++ b/filters.c @@ -647,6 +647,11 @@ const char filters_rcs[] = "$Id: filters.c,v 1.108 2008/05/21 15:35:08 fabiankei #include #include +#ifdef HAVE_GETADDRINFO +#include +#include +#endif /* def HAVE_GETADDRINFO */ + #ifndef _WIN32 #ifndef __OS2__ #include @@ -694,6 +699,152 @@ static jb_err remove_chunked_transfer_coding(char *buffer, size_t *size); static jb_err prepare_for_filtering(struct client_state *csp); #ifdef FEATURE_ACL +#ifdef HAVE_GETADDRINFO +/********************************************************************* + * + * Function : sockaddr_storage_to_ip + * + * Description : Access internal structure of sockaddr_storage + * + * Parameters : + * 1 : addr = socket address + * 2 : ip = IP address as array of octets in network order + * (it points into addr) + * 3 : len = length of IP address in octets + * 4 : port = port number in network order; + * + * Returns : 0 = no errror; otherwise + * + *********************************************************************/ +int sockaddr_storage_to_ip(const struct sockaddr_storage *addr, uint8_t **ip, + unsigned int *len, in_port_t **port) +{ + if (!addr) + { + return(-1); + } + + switch (addr->ss_family) + { + case AF_INET: + if (len) + { + *len = 4; + } + if (ip) + { + *ip = (uint8_t *) + &(( (struct sockaddr_in *) addr)->sin_addr.s_addr); + } + if (port) + { + *port = &((struct sockaddr_in *) addr)->sin_port; + } + break; + + case AF_INET6: + if (len) + { + *len = 16; + } + if (ip) + { + *ip = (uint8_t *) + &(( (struct sockaddr_in6 *) addr)->sin6_addr.in6_u); + } + if (port) + { + *port = &((struct sockaddr_in6 *) addr)->sin6_port; + } + break; + + default: + /* Unsupported address family */ + return(-1); + } + + return(0); +} + + +/********************************************************************* + * + * Function : match_sockaddr + * + * Description : Check whether address matches network (IP address and port) + * + * Parameters : + * 1 : network = socket address of subnework + * 3 : netmask = network mask as socket address + * 2 : address = checked socket address against given network + * + * Returns : 0 = doesn't match; 1 = does match + * + *********************************************************************/ +int match_sockaddr(const struct sockaddr_storage *network, + const struct sockaddr_storage *netmask, + const struct sockaddr_storage *address) +{ + uint8_t *network_addr, *netmask_addr, *address_addr; + unsigned int addr_len; + in_port_t *network_port, *netmask_port, *address_port; + int i; + + if (network->ss_family != netmask->ss_family) + { + /* This should never happen */ + log_error(LOG_LEVEL_ERROR, + "Internal error at %s:%llu: network and netmask differ in family", + __FILE__, __LINE__); + return 0; + } + + sockaddr_storage_to_ip(network, &network_addr, &addr_len, &network_port); + sockaddr_storage_to_ip(netmask, &netmask_addr, NULL, &netmask_port); + sockaddr_storage_to_ip(address, &address_addr, NULL, &address_port); + + /* Check for family */ + if (network->ss_family == AF_INET && address->ss_family == AF_INET6 && + IN6_IS_ADDR_V4MAPPED(address_addr)) + { + /* Map AF_INET6 V4MAPPED address into AF_INET */ + address_addr += 12; + addr_len = 4; + } + else if (network->ss_family == AF_INET6 && address->ss_family == AF_INET && + IN6_IS_ADDR_V4MAPPED(network_addr)) + { + /* Map AF_INET6 V4MAPPED network into AF_INET */ + network_addr += 12; + netmask_addr += 12; + addr_len = 4; + } + else if (network->ss_family != address->ss_family) + { + return 0; + } + + /* XXX: Port check is signaled in netmask */ + if (*netmask_port && *network_port != *address_port) + { + return 0; + } + + /* TODO: Optimize by checking by words insted of octets */ + for (i=0; i < addr_len && netmask_addr[i]; i++) + { + if ( (network_addr[i] & netmask_addr[i]) != + (address_addr[i] & netmask_addr[i]) ) + { + return 0; + } + } + + return 1; +} +#endif /* def HAVE_GETADDRINFO */ + + /********************************************************************* * * Function : block_acl @@ -723,7 +874,13 @@ int block_acl(const struct access_control_addr *dst, const struct client_state * /* search the list */ while (acl != NULL) { - if ((csp->ip_addr_long & acl->src->mask) == acl->src->addr) + if ( +#ifdef HAVE_GETADDRINFO + match_sockaddr(&acl->src->addr, &acl->src->mask, &csp->tcp_addr) +#else + (csp->ip_addr_long & acl->src->mask) == acl->src->addr +#endif + ) { if (dst == NULL) { @@ -733,8 +890,23 @@ int block_acl(const struct access_control_addr *dst, const struct client_state * return(0); } } - else if ( ((dst->addr & acl->dst->mask) == acl->dst->addr) - && ((dst->port == acl->dst->port) || (acl->dst->port == 0))) + else if ( +#ifdef HAVE_GETADDRINFO + /* XXX: Undefined acl->dst is full of zeros and should be + * considered as wildcard address. + * sockaddr_storage_to_ip() failes on such dst because of + * uknown sa_familly on glibc. However this test is not + * portable. + * + * So, we signal the acl->dst is wildcard in wildcard_dst. + */ + acl->wildcard_dst || + match_sockaddr(&acl->dst->addr, &acl->dst->mask, &dst->addr) +#else + ((dst->addr & acl->dst->mask) == acl->dst->addr) + && ((dst->port == acl->dst->port) || (acl->dst->port == 0)) +#endif + ) { if (acl->action == ACL_PERMIT) { @@ -770,12 +942,24 @@ int block_acl(const struct access_control_addr *dst, const struct client_state * int acl_addr(const char *aspec, struct access_control_addr *aca) { int i, masklength; +#ifdef HAVE_GETADDRINFO + struct addrinfo hints, *result; + uint8_t *mask_data; + in_port_t *mask_port; + unsigned int addr_len; +#else long port; +#endif /* def HAVE_GETADDRINFO */ char *p; char *acl_spec = NULL; +#ifdef HAVE_GETADDRINFO + /* FIXME: Depend on ai_family */ + masklength = 128; +#else masklength = 32; port = 0; +#endif /* * Use a temporary acl spec copy so we can log @@ -799,13 +983,53 @@ int acl_addr(const char *aspec, struct access_control_addr *aca) masklength = atoi(p); } - if ((masklength < 0) || (masklength > 32)) + if ((masklength < 0) || +#ifdef HAVE_GETADDRINFO + (masklength > 128) +#else + (masklength > 32) +#endif + ) { freez(acl_spec); return(-1); } - if ((p = strchr(acl_spec, ':')) != NULL) + if (*acl_spec == '[' && NULL != (p = strchr(acl_spec, ']'))) + { + *p = '\0'; + memmove(acl_spec, acl_spec + 1, (size_t) (p - acl_spec)); + + if (*++p != ':') + { + p = NULL; + } + } + else + { + p = strchr(acl_spec, ':'); + } + +#ifdef HAVE_GETADDRINFO + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + i = getaddrinfo(acl_spec, (p) ? ++p : NULL, &hints, &result); + freez(acl_spec); + + if (i != 0) + { + log_error(LOG_LEVEL_ERROR, "Can not resolve [%s]:%s: %s", acl_spec, p, + gai_strerror(i)); + return(-1); + } + + /* TODO: Allow multihomed hostnames */ + memcpy(&(aca->addr), result->ai_addr, sizeof(aca->addr)); + freeaddrinfo(result); +#else + if (p != NULL) { char *endptr; @@ -829,8 +1053,49 @@ int acl_addr(const char *aspec, struct access_control_addr *aca) /* XXX: This will be logged as parse error. */ return(-1); } +#endif /* def HAVE_GETADDRINFO */ /* build the netmask */ +#ifdef HAVE_GETADDRINFO + /* Clip masklength according current family */ + if (aca->addr.ss_family == AF_INET && masklength > 32) + { + masklength = 32; + } + + aca->mask.ss_family = aca->addr.ss_family; + if (sockaddr_storage_to_ip(&aca->mask, &mask_data, &addr_len, &mask_port)) + { + return(-1); + } + + if (p) + { + /* Port number in ACL has been specified, check ports in future */ + *mask_port = 1; + } + + /* XXX: This could be optimized to operate on whole words instead of octets + * (128-bit CPU could do it in one iteration). */ + /* Octets after prefix can be ommitted because of previous initialization + * to zeros. */ + for (i=0; i < addr_len && masklength; i++) + { + if (masklength >= 8) + { + mask_data[i] = 0xFF; + masklength -= 8; + } + else + { + /* XXX: This assumes MSB of octet is on the left site. This should be + * true for all architectures or solved on link layer of OSI model. */ + mask_data[i] = ~((1 << (8 - masklength)) - 1); + masklength = 0; + } + } + +#else aca->mask = 0; for (i=1; i <= masklength ; i++) { @@ -841,6 +1106,7 @@ int acl_addr(const char *aspec, struct access_control_addr *aca) * (i.e. save on the network portion of the address). */ aca->addr = aca->addr & aca->mask; +#endif /* def HAVE_GETADDRINFO */ return(0); @@ -2685,4 +2951,6 @@ int content_filters_enabled(const struct current_action_spec *action) Local Variables: tab-width: 3 end: + + vim:softtabstop=3 shiftwidth=3 */ diff --git a/jbsockets.c b/jbsockets.c index 91832f8..9467c3f 100644 --- a/jbsockets.c +++ b/jbsockets.c @@ -345,19 +345,52 @@ const char jbsockets_h_rcs[] = JBSOCKETS_H_VERSION; *********************************************************************/ jb_socket connect_to(const char *host, int portnum, struct client_state *csp) { +#ifdef HAVE_GETADDRINFO + struct addrinfo hints, *result, *rp; + char service[6]; + int retval; +#else struct sockaddr_in inaddr; - jb_socket fd; int addr; +#endif /* def HAVE_GETADDRINFO */ + jb_socket fd; fd_set wfds; struct timeval tv[1]; #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) int flags; #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) */ + int connect_failed; #ifdef FEATURE_ACL struct access_control_addr dst[1]; #endif /* def FEATURE_ACL */ +#ifdef HAVE_GETADDRINFO + retval = snprintf(service, sizeof(service), "%d", portnum); + if (-1 == retval || sizeof(service) <= retval) + { + log_error(LOG_LEVEL_ERROR, + "Port number (%d) ASCII decimal representation doesn't fit into 6 bytes", + portnum); + csp->http->host_ip_addr_str = strdup("unknown"); + return(JB_INVALID_SOCKET); + } + + memset((char *)&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV; /* avoid service look-up */ + if ((retval = getaddrinfo(host, service, &hints, &result))) + { + log_error(LOG_LEVEL_INFO, + "Can not resolve %s: %s", host, gai_strerror(retval)); + csp->http->host_ip_addr_str = strdup("unknown"); + return(JB_INVALID_SOCKET); + } + + for (rp = result; rp != NULL; rp = rp->ai_next) + { +#else memset((char *)&inaddr, 0, sizeof inaddr); if ((addr = resolve_hostname_to_ip(host)) == INADDR_NONE) @@ -365,10 +398,15 @@ jb_socket connect_to(const char *host, int portnum, struct client_state *csp) csp->http->host_ip_addr_str = strdup("unknown"); return(JB_INVALID_SOCKET); } +#endif /* def HAVE_GETADDRINFO */ #ifdef FEATURE_ACL +#ifdef HAVE_GETADDRINFO + memcpy(&dst->addr, rp->ai_addr, sizeof(dst->addr)); +#else dst->addr = ntohl((unsigned long) addr); dst->port = portnum; +#endif /* def HAVE_GETADDRINFO */ if (block_acl(dst, csp)) { @@ -377,14 +415,43 @@ jb_socket connect_to(const char *host, int portnum, struct client_state *csp) #else errno = EPERM; #endif +#ifdef HAVE_GETADDRINFO + continue; +#else return(JB_INVALID_SOCKET); +#endif /* def HAVE_GETADDRINFO */ } #endif /* def FEATURE_ACL */ +#ifdef HAVE_GETNAMEINFO + csp->http->host_ip_addr_str = malloc(NI_MAXHOST); + retval = getnameinfo(rp->ai_addr, rp->ai_addrlen, + csp->http->host_ip_addr_str, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); + if (!csp->http->host_ip_addr_str || retval) + { + log_error(LOG_LEVEL_ERROR, "Can not save csp->http->host_ip_addr_str: %s", + (csp->http->host_ip_addr_str) ? gai_strerror(retval) : + "Insufficient memory"); + freez(csp->http->host_ip_addr_str); + continue; + } +#else inaddr.sin_addr.s_addr = addr; inaddr.sin_family = AF_INET; csp->http->host_ip_addr_str = strdup(inet_ntoa(inaddr.sin_addr)); +#endif /* def HAVE_GETNAMERINFO */ +#ifdef HAVE_GETADDRINFO +#ifdef _WIN32 + if ((fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == + JB_INVALID_SOCKET) +#else + if ((fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) < 0) +#endif + { + continue; + } +#else #ifndef _WIN32 if (sizeof(inaddr.sin_port) == sizeof(short)) #endif /* ndef _WIN32 */ @@ -406,6 +473,7 @@ jb_socket connect_to(const char *host, int portnum, struct client_state *csp) { return(JB_INVALID_SOCKET); } +#endif /* HAVE_GETADDRINFO */ #ifdef TCP_NODELAY { /* turn off TCP coalescence */ @@ -422,7 +490,12 @@ jb_socket connect_to(const char *host, int portnum, struct client_state *csp) } #endif /* !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) */ + connect_failed = 0; +#ifdef HAVE_GETADDRINFO + while (connect(fd, rp->ai_addr, rp->ai_addrlen) == JB_INVALID_SOCKET) +#else while (connect(fd, (struct sockaddr *) & inaddr, sizeof inaddr) == JB_INVALID_SOCKET) +#endif /* HAVE_GETADDRINFO */ { #ifdef _WIN32 if (errno == WSAEINPROGRESS) @@ -442,9 +515,18 @@ jb_socket connect_to(const char *host, int portnum, struct client_state *csp) #endif /* __OS2__ */ { close_socket(fd); - return(JB_INVALID_SOCKET); + connect_failed = 1; + break; } } + if (connect_failed) + { +#ifdef HAVE_GETADDRINFO + continue; +#else + return(JB_INVALID_SOCKET); +#endif + } #if !defined(_WIN32) && !defined(__BEOS__) && !defined(AMIGA) && !defined(__OS2__) if (flags != -1) @@ -465,8 +547,32 @@ jb_socket connect_to(const char *host, int portnum, struct client_state *csp) if (select((int)fd + 1, NULL, &wfds, NULL, tv) <= 0) { close_socket(fd); +#ifdef HAVE_GETADDRINFO + continue; +#else + return(JB_INVALID_SOCKET); +#endif + } + +#ifdef HAVE_GETADDRINFO + break; /* for */ + } + + freeaddrinfo(result); + if (!rp) + { + log_error(LOG_LEVEL_INFO, "Could not connect to TCP/[%s]:%s", host, service); return(JB_INVALID_SOCKET); } + /* XXX: Current connection verification (EINPROGRESS && select() for + * writing) is not sufficient. E.g. on my Linux-2.6.27 with glibc-2.6 + * select returns socket ready for writing, however subsequential write(2) + * fails with ENOCONNECT. Read Linux connect(2) man page about non-blocking + * sockets. + * Thus we can not log here the socket is connected. */ + /*log_error(LOG_LEVEL_INFO, "Connected to TCP/[%s]:%s", host, service);*/ +#endif + return(fd); } @@ -625,7 +731,16 @@ void close_socket(jb_socket fd) *********************************************************************/ int bind_port(const char *hostnam, int portnum, jb_socket *pfd) { +#ifdef HAVE_GETADDRINFO + struct addrinfo hints; + struct addrinfo *result, *rp; + /* TODO: portnum shuld be string to allow symbolic service names in + * configuration and to avoid following int2string */ + char servnam[6]; + int retval; +#else struct sockaddr_in inaddr; +#endif /* def HAVE_GETADDRINFO */ jb_socket fd; #ifndef _WIN32 int one = 1; @@ -633,6 +748,32 @@ int bind_port(const char *hostnam, int portnum, jb_socket *pfd) *pfd = JB_INVALID_SOCKET; +#ifdef HAVE_GETADDRINFO + retval = snprintf(servnam, sizeof(servnam), "%d", portnum); + if (-1 == retval || sizeof(servnam) <= retval) + { + log_error(LOG_LEVEL_ERROR, + "Port number (%d) ASCII decimal representation doesn't fit into 6 bytes", + portnum); + return -1; + } + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family=AF_UNSPEC; + hints.ai_socktype=SOCK_STREAM; + hints.ai_flags=AI_PASSIVE|AI_ADDRCONFIG; + hints.ai_protocol=0; /* Realy any stream protocol or TCP only */ + hints.ai_canonname=NULL; + hints.ai_addr=NULL; + hints.ai_next=NULL; + + if ((retval = getaddrinfo(hostnam, servnam, &hints, &result))) + { + log_error(LOG_LEVEL_ERROR, + "Can not resolve %s: %s", hostnam, gai_strerror(retval)); + return -2; + } +#else memset((char *)&inaddr, '\0', sizeof inaddr); inaddr.sin_family = AF_INET; @@ -655,8 +796,15 @@ int bind_port(const char *hostnam, int portnum, jb_socket *pfd) inaddr.sin_port = htonl((unsigned long) portnum); } #endif /* ndef _WIN32 */ +#endif /* def HAVE_GETADDRINFO */ +#ifdef HAVE_GETADDRINFO + for (rp = result; rp != NULL; rp = rp->ai_next) + { + fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); +#else fd = socket(AF_INET, SOCK_STREAM, 0); +#endif /* def HAVE_GETADDRINFO */ #ifdef _WIN32 if (fd == JB_INVALID_SOCKET) @@ -664,7 +812,11 @@ int bind_port(const char *hostnam, int portnum, jb_socket *pfd) if (fd < 0) #endif { +#ifdef HAVE_GETADDRINFO + continue; +#else return(-1); +#endif } #ifndef _WIN32 @@ -683,7 +835,11 @@ int bind_port(const char *hostnam, int portnum, jb_socket *pfd) setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)); #endif /* ndef _WIN32 */ +#ifdef HAVE_GETADDRINFO + if (bind(fd, rp->ai_addr, rp->ai_addrlen) < 0) +#else if (bind(fd, (struct sockaddr *)&inaddr, sizeof(inaddr)) < 0) +#endif { #ifdef _WIN32 errno = WSAGetLastError(); @@ -692,15 +848,36 @@ int bind_port(const char *hostnam, int portnum, jb_socket *pfd) if (errno == EADDRINUSE) #endif { +#ifdef HAVE_GETADDRINFO + freeaddrinfo(result); +#endif close_socket(fd); return(-3); } else { close_socket(fd); +#ifndef HAVE_GETADDRINFO return(-1); } } +#else + } + } + else + /* bind() succeeded, escape from for-loop */ + /* TODO: Support multiple listening sockets (e.g. localhost resolves to + * AF_INET and AF_INET6, but only fist address is used */ + break; + } + + freeaddrinfo(result); + if (rp == NULL) + { + /* All bind()s failed */ + return(-1); + } +#endif /* ndef HAVE_GETADDRINFO */ while (listen(fd, MAX_LISTEN_BACKLOG) == -1) { @@ -740,14 +917,20 @@ int bind_port(const char *hostnam, int portnum, jb_socket *pfd) *********************************************************************/ void get_host_information(jb_socket afd, char **ip_address, char **hostname) { +#ifdef HAVE_GETNAMEINFO + struct sockaddr_storage server; + int retval; +#else struct sockaddr_in server; struct hostent *host = NULL; +#endif /* HAVE_GETNAMEINFO */ #if defined(_WIN32) || defined(__OS2__) || defined(__APPLE_CC__) || defined(AMIGA) /* according to accept_connection() this fixes a warning. */ - int s_length; + int s_length, s_length_provided; #else - socklen_t s_length; + socklen_t s_length, s_length_provided; #endif +#ifndef HAVE_GETNAMEINFO #if defined(HAVE_GETHOSTBYADDR_R_8_ARGS) || defined(HAVE_GETHOSTBYADDR_R_7_ARGS) || defined(HAVE_GETHOSTBYADDR_R_5_ARGS) struct hostent result; #if defined(HAVE_GETHOSTBYADDR_R_5_ARGS) @@ -757,7 +940,8 @@ void get_host_information(jb_socket afd, char **ip_address, char **hostname) int thd_err; #endif /* def HAVE_GETHOSTBYADDR_R_5_ARGS */ #endif /* def HAVE_GETHOSTBYADDR_R_(8|7|5)_ARGS */ - s_length = sizeof(server); +#endif /* ifndef HAVE_GETNAMEINFO */ + s_length = s_length_provided = sizeof(server); if (NULL != hostname) { @@ -767,8 +951,23 @@ void get_host_information(jb_socket afd, char **ip_address, char **hostname) if (!getsockname(afd, (struct sockaddr *) &server, &s_length)) { + if (s_length > s_length_provided) + { + log_error(LOG_LEVEL_ERROR, "getsockname() truncated server address"); + return; + } +#ifdef HAVE_GETNAMEINFO + *ip_address = malloc(NI_MAXHOST); + if ((retval = getnameinfo((struct sockaddr *) &server, s_length, + *ip_address, NI_MAXHOST, NULL, 0, NI_NUMERICHOST))) { + log_error(LOG_LEVEL_ERROR, "Unable to print my own IP address: %s", + gai_strerror(retval)); + freez(*ip_address); + return; + } +#else *ip_address = strdup(inet_ntoa(server.sin_addr)); - +#endif /* HAVE_GETNAMEINFO */ if (NULL == hostname) { /* @@ -777,6 +976,16 @@ void get_host_information(jb_socket afd, char **ip_address, char **hostname) */ return; } + +#ifdef HAVE_GETNAMEINFO + *hostname = malloc(NI_MAXHOST); + if ((retval = getnameinfo((struct sockaddr *) &server, s_length, + *hostname, NI_MAXHOST, NULL, 0, NI_NAMEREQD))) { + log_error(LOG_LEVEL_ERROR, "Unable to resolve my own IP address: %s", + gai_strerror(retval)); + freez(*hostname); + } +#else #if defined(HAVE_GETHOSTBYADDR_R_8_ARGS) gethostbyaddr_r((const char *)&server.sin_addr, sizeof(server.sin_addr), AF_INET, @@ -814,6 +1023,7 @@ void get_host_information(jb_socket afd, char **ip_address, char **hostname) { *hostname = strdup(host->h_name); } +#endif /* else def HAVE_GETNAMEINFO */ } return; @@ -838,7 +1048,13 @@ void get_host_information(jb_socket afd, char **ip_address, char **hostname) *********************************************************************/ int accept_connection(struct client_state * csp, jb_socket fd) { +#ifdef HAVE_GETNAMEINFO + /* XXX: client is stored directly into csp->tcp_addr */ +#define client (csp->tcp_addr) + int retval; +#else struct sockaddr_in client; +#endif jb_socket afd; #if defined(_WIN32) || defined(__OS2__) || defined(__APPLE_CC__) || defined(AMIGA) /* Wierdness - fix a warning. */ @@ -867,8 +1083,21 @@ int accept_connection(struct client_state * csp, jb_socket fd) #endif csp->cfd = afd; +#ifdef HAVE_GETNAMEINFO + csp->ip_addr_str = malloc(NI_MAXHOST); + retval = getnameinfo((struct sockaddr *) &client, c_length, + csp->ip_addr_str, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); + if (!csp->ip_addr_str || retval) + { + log_error(LOG_LEVEL_ERROR, "Can not save csp->ip_addr_str: %s", + (csp->ip_addr_str) ? gai_strerror(retval) : "Insuffcient memory"); + freez(csp->ip_addr_str); + } +#undef client +#else csp->ip_addr_str = strdup(inet_ntoa(client.sin_addr)); csp->ip_addr_long = ntohl(client.sin_addr.s_addr); +#endif /* def HAVE_GETNAMEINFO */ return 1; @@ -999,4 +1228,6 @@ unsigned long resolve_hostname_to_ip(const char *host) Local Variables: tab-width: 3 end: + + vim:softtabstop=3 shiftwidth=3 */ diff --git a/jcc.c b/jcc.c index 0fb7cfd..2800869 100644 --- a/jcc.c +++ b/jcc.c @@ -2320,7 +2320,7 @@ static void chat(struct client_state *csp) if (fwd->forward_host) { - log_error(LOG_LEVEL_CONNECT, "via %s:%d to: %s", + log_error(LOG_LEVEL_CONNECT, "via [%s]:%d to: %s", fwd->forward_host, fwd->forward_port, http->hostport); } else @@ -3899,4 +3899,6 @@ static void listen_loop(void) Local Variables: tab-width: 3 end: + + vim:softtabstop=3 shiftwidth=3 */ diff --git a/loadcfg.c b/loadcfg.c index 69cce44..8088cfc 100644 --- a/loadcfg.c +++ b/loadcfg.c @@ -985,6 +985,12 @@ struct configuration_spec * load_config(void) continue; } } +#ifdef HAVE_GETADDRINFO + else + { + cur_acl->wildcard_dst = 1; + } +#endif /* def HAVE_GETADDRINFO */ /* * Add it to the list. Note we reverse the list to get the @@ -1133,7 +1139,18 @@ struct configuration_spec * load_config(void) { cur_fwd->forward_host = strdup(p); - if (NULL != (p = strchr(cur_fwd->forward_host, ':'))) + if (*cur_fwd->forward_host == '[' && + NULL != (p = strchr(cur_fwd->forward_host, ']'))) + { + *p++ = '\0'; + memmove(cur_fwd->forward_host, cur_fwd->forward_host + 1, + (size_t) (p - cur_fwd->forward_host)); + if (*p == ':') + { + cur_fwd->forward_port = atoi(++p); + } + } + else if (NULL != (p = strchr(cur_fwd->forward_host, ':'))) { *p++ = '\0'; cur_fwd->forward_port = atoi(p); @@ -1196,11 +1213,23 @@ struct configuration_spec * load_config(void) { cur_fwd->gateway_host = strdup(p); - if (NULL != (p = strchr(cur_fwd->gateway_host, ':'))) + if (*cur_fwd->gateway_host == '[' && + NULL != (p = strchr(cur_fwd->gateway_host, ']'))) + { + *p++ = '\0'; + memmove(cur_fwd->gateway_host, cur_fwd->gateway_host + 1, + (size_t) (p - cur_fwd->gateway_host)); + if (*p == ':') + { + cur_fwd->gateway_port = atoi(++p); + } + } + else if (NULL != (p = strchr(cur_fwd->gateway_host, ':'))) { *p++ = '\0'; cur_fwd->gateway_port = atoi(p); } + if (cur_fwd->gateway_port <= 0) { cur_fwd->gateway_port = 1080; @@ -1214,7 +1243,18 @@ struct configuration_spec * load_config(void) { cur_fwd->forward_host = strdup(p); - if (NULL != (p = strchr(cur_fwd->forward_host, ':'))) + if (*cur_fwd->forward_host == '[' && + NULL != (p = strchr(cur_fwd->forward_host, ']'))) + { + *p++ = '\0'; + memmove(cur_fwd->forward_host, cur_fwd->forward_host + 1, + (size_t) (p - cur_fwd->forward_host)); + if (*p == ':') + { + cur_fwd->forward_port = atoi(++p); + } + } + else if (NULL != (p = strchr(cur_fwd->forward_host, ':'))) { *p++ = '\0'; cur_fwd->forward_port = atoi(p); @@ -1283,11 +1323,23 @@ struct configuration_spec * load_config(void) cur_fwd->gateway_host = strdup(p); - if (NULL != (p = strchr(cur_fwd->gateway_host, ':'))) + if (*cur_fwd->gateway_host == '[' && + NULL != (p = strchr(cur_fwd->gateway_host, ']'))) + { + *p++ = '\0'; + memmove(cur_fwd->gateway_host, cur_fwd->gateway_host + 1, + (size_t) (p - cur_fwd->gateway_host)); + if (*p == ':') + { + cur_fwd->gateway_port = atoi(++p); + } + } + else if (NULL != (p = strchr(cur_fwd->gateway_host, ':'))) { *p++ = '\0'; cur_fwd->gateway_port = atoi(p); } + if (cur_fwd->gateway_port <= 0) { cur_fwd->gateway_port = 1080; @@ -1300,7 +1352,18 @@ struct configuration_spec * load_config(void) { cur_fwd->forward_host = strdup(p); - if (NULL != (p = strchr(cur_fwd->forward_host, ':'))) + if (*cur_fwd->forward_host == '[' && + NULL != (p = strchr(cur_fwd->forward_host, ']'))) + { + *p++ = '\0'; + memmove(cur_fwd->forward_host, cur_fwd->forward_host + 1, + (size_t) (p - cur_fwd->forward_host)); + if (*p == ':') + { + cur_fwd->forward_port = atoi(++p); + } + } + else if (NULL != (p = strchr(cur_fwd->forward_host, ':'))) { *p++ = '\0'; cur_fwd->forward_port = atoi(p); @@ -1439,6 +1502,12 @@ struct configuration_spec * load_config(void) continue; } } +#ifdef HAVE_GETADDRINFO + else + { + cur_acl->wildcard_dst = 1; + } +#endif /* def HAVE_GETADDRINFO */ /* * Add it to the list. Note we reverse the list to get the @@ -1735,18 +1804,20 @@ struct configuration_spec * load_config(void) if ( NULL != config->haddr ) { - if (NULL != (p = strchr(config->haddr, ':'))) + if (*config->haddr == '[' && NULL != (p = strchr(config->haddr, ']')) && + p[1] == ':' && 0 < (config->hport = atoi(p + 2))) { - *p++ = '\0'; - if (*p) - { - config->hport = atoi(p); - } + *p='\0'; + memmove((void *) config->haddr, config->haddr + 1, + (size_t) (p - config->haddr)); } - - if (config->hport <= 0) + else if (NULL != (p = strchr(config->haddr, ':')) && + 0 < (config->hport = atoi(p + 1))) + { + *p = '\0'; + } + else { - *--p = ':'; log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr); /* Never get here - LOG_LEVEL_FATAL causes program exit */ } @@ -1922,4 +1993,6 @@ static void savearg(char *command, char *argument, struct configuration_spec * c Local Variables: tab-width: 3 end: + + vim:softtabstop=3 shiftwidth=3 */ diff --git a/project.h b/project.h index 4dbe236..61b6be7 100644 --- a/project.h +++ b/project.h @@ -657,6 +657,12 @@ /* Needed for pcre choice */ #include "config.h" +#ifdef HAVE_GETADDRINFO +/* Need for struct sockaddr_storage */ +#include +#endif + + /* * Include appropriate regular expression libraries. * Note that pcrs and pcre (native) are needed for cgi @@ -1349,9 +1355,15 @@ struct client_state /** Client PC's IP address, as reported by the accept() function. As a string. */ char *ip_addr_str; +#ifdef HAVE_GETADDRINFO + /** Client PC's TCP address, as reported by the accept() function. + As a sockaddr. */ + struct sockaddr_storage tcp_addr; +#else /** Client PC's IP address, as reported by the accept() function. As a number. */ long ip_addr_long; +#endif /* def HAVE_GETADDRINFO */ /** The URL that was requested */ struct http_request http[1]; @@ -1577,9 +1589,14 @@ struct re_filterfile_spec */ struct access_control_addr { +#ifdef HAVE_GETADDRINFO + struct sockaddr_storage addr; /*