--- lighttpd-1.4.35/src/configfile-glue.c.orig 2014-03-06 15:08:00.000000000 +0100 +++ lighttpd-1.4.35/src/configfile-glue.c 2015-11-26 11:39:23.000000000 +0100 @@ -8,6 +8,10 @@ #include #include +#include +#ifndef __WIN32 +#include +#endif /** * like all glue code this file contains functions which @@ -336,12 +340,22 @@ static cond_result_t config_check_cond_n if ((dc->cond == CONFIG_COND_EQ || dc->cond == CONFIG_COND_NE) && - (con->dst_addr.plain.sa_family == AF_INET) && (NULL != (nm_slash = strchr(dc->string->ptr, '/')))) { int nm_bits; - long nm; char *err; struct in_addr val_inp; + struct in6_addr val_inp6; + int val_af; + uint8_t *a, *b; + int result_match, result_nomatch; + + if (dc->cond == CONFIG_COND_EQ) { + result_match = COND_RESULT_TRUE; + result_nomatch = COND_RESULT_FALSE; + } else { + result_match = COND_RESULT_FALSE; + result_nomatch = COND_RESULT_TRUE; + } if (*(nm_slash+1) == '\0') { log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: no number after / ", dc->string); @@ -356,10 +370,16 @@ static cond_result_t config_check_cond_n return COND_RESULT_FALSE; } + if (nm_bits < 0) { + log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: negative netmask:", dc->string, err); + + return COND_RESULT_FALSE; + } /* take IP convert to the native */ buffer_copy_string_len(srv->cond_check_buf, dc->string->ptr, nm_slash - dc->string->ptr); #ifdef __WIN32 + val_af = AF_INET; if (INADDR_NONE == (val_inp.s_addr = inet_addr(srv->cond_check_buf->ptr))) { log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf); @@ -367,21 +387,54 @@ static cond_result_t config_check_cond_n } #else - if (0 == inet_aton(srv->cond_check_buf->ptr, &val_inp)) { + if (1 == inet_pton(AF_INET, srv->cond_check_buf->ptr, &val_inp)) { + val_af = AF_INET; + } else if (1 == inet_pton(AF_INET6, srv->cond_check_buf->ptr, &val_inp6)) { + val_af = AF_INET6; + } else { log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf); return COND_RESULT_FALSE; } #endif - /* build netmask */ - nm = htonl(~((1 << (32 - nm_bits)) - 1)); + if (val_af == AF_INET) { + if (nm_bits > 32) { + log_error_write(srv, __FILE__, __LINE__, "sd", "ERROR: ipv4 netmask too large:", nm_bits); - if ((val_inp.s_addr & nm) == (con->dst_addr.ipv4.sin_addr.s_addr & nm)) { - return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE; + return COND_RESULT_FALSE; + } + a = (uint8_t *)&val_inp; + if (con->dst_addr.plain.sa_family == AF_INET) { + b = (uint8_t *)&con->dst_addr.ipv4.sin_addr.s_addr; + } else if (IN6_IS_ADDR_V4MAPPED(&con->dst_addr.ipv6.sin6_addr)) { + b = (uint8_t *)&con->dst_addr.ipv6.sin6_addr.s6_addr[12]; + } else { + return result_nomatch; + } } else { - return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_FALSE : COND_RESULT_TRUE; + if (nm_bits > 128) { + log_error_write(srv, __FILE__, __LINE__, "sd", "ERROR: ipv6 netmask too large:", nm_bits); + + return COND_RESULT_FALSE; + } + a = (uint8_t *)&val_inp6; + if (con->dst_addr.plain.sa_family == AF_INET) { + return result_nomatch; + } else { + b = (uint8_t *)&con->dst_addr.ipv6.sin6_addr.s6_addr[0]; + } + } + while (nm_bits) { + if (nm_bits >= 8) { + if (*a++ != *b++) return result_nomatch; + nm_bits -= 8; + } else { + if (*a >> (8 - nm_bits) != *b >> (8 - nm_bits)) return result_nomatch; + nm_bits = 0; + } } + return result_match; } else { l = con->dst_addr_buf; }