11324Saxel.duch@nginx.com 21324Saxel.duch@nginx.com /* 31324Saxel.duch@nginx.com * Copyright (C) Axel Duch 41324Saxel.duch@nginx.com * Copyright (C) NGINX, Inc. 51324Saxel.duch@nginx.com */ 61324Saxel.duch@nginx.com 71324Saxel.duch@nginx.com #include <nxt_main.h> 81324Saxel.duch@nginx.com #include <nxt_http_route_addr.h> 91324Saxel.duch@nginx.com 101324Saxel.duch@nginx.com 111324Saxel.duch@nginx.com #if (NXT_INET6) 121324Saxel.duch@nginx.com static nxt_bool_t nxt_valid_ipv6_blocks(u_char *c, size_t len); 131324Saxel.duch@nginx.com #endif 141324Saxel.duch@nginx.com 151324Saxel.duch@nginx.com 161324Saxel.duch@nginx.com nxt_int_t 171324Saxel.duch@nginx.com nxt_http_route_addr_pattern_parse(nxt_mp_t *mp, 181324Saxel.duch@nginx.com nxt_http_route_addr_pattern_t *pattern, nxt_conf_value_t *cv) 191324Saxel.duch@nginx.com { 201343Saxel.duch@nginx.com u_char *delim; 211324Saxel.duch@nginx.com nxt_int_t ret, cidr_prefix; 221324Saxel.duch@nginx.com nxt_str_t addr, port; 231324Saxel.duch@nginx.com nxt_http_route_addr_base_t *base; 241324Saxel.duch@nginx.com nxt_http_route_addr_range_t *inet; 251324Saxel.duch@nginx.com 261324Saxel.duch@nginx.com if (nxt_conf_type(cv) != NXT_CONF_STRING) { 271324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_CV_TYPE_ERROR; 281324Saxel.duch@nginx.com } 291324Saxel.duch@nginx.com 301324Saxel.duch@nginx.com nxt_conf_get_string(cv, &addr); 311324Saxel.duch@nginx.com 321324Saxel.duch@nginx.com base = &pattern->base; 331324Saxel.duch@nginx.com 341324Saxel.duch@nginx.com if (addr.length > 0 && addr.start[0] == '!') { 351324Saxel.duch@nginx.com addr.start++; 361324Saxel.duch@nginx.com addr.length--; 371324Saxel.duch@nginx.com 381324Saxel.duch@nginx.com base->negative = 1; 391324Saxel.duch@nginx.com 401324Saxel.duch@nginx.com } else { 411324Saxel.duch@nginx.com base->negative = 0; 421324Saxel.duch@nginx.com } 431324Saxel.duch@nginx.com 441324Saxel.duch@nginx.com if (nxt_slow_path(addr.length < 2)) { 451324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_LENGTH_ERROR; 461324Saxel.duch@nginx.com } 471324Saxel.duch@nginx.com 481324Saxel.duch@nginx.com nxt_str_null(&port); 491324Saxel.duch@nginx.com 501324Saxel.duch@nginx.com if (addr.start[0] == '*' && addr.start[1] == ':') { 511324Saxel.duch@nginx.com port.start = addr.start + 2; 521324Saxel.duch@nginx.com port.length = addr.length - 2; 531324Saxel.duch@nginx.com base->addr_family = AF_UNSPEC; 541324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_ANY; 551324Saxel.duch@nginx.com 561324Saxel.duch@nginx.com goto parse_port; 571324Saxel.duch@nginx.com } 581324Saxel.duch@nginx.com 59*1935So.canty@f5.com if (nxt_inet6_probe(&addr)) { 601324Saxel.duch@nginx.com #if (NXT_INET6) 611343Saxel.duch@nginx.com u_char *end; 621324Saxel.duch@nginx.com uint8_t i; 631324Saxel.duch@nginx.com nxt_int_t len; 641324Saxel.duch@nginx.com nxt_http_route_in6_addr_range_t *inet6; 651324Saxel.duch@nginx.com 661324Saxel.duch@nginx.com base->addr_family = AF_INET6; 671324Saxel.duch@nginx.com 681324Saxel.duch@nginx.com if (addr.start[0] == '[') { 691324Saxel.duch@nginx.com addr.start++; 701324Saxel.duch@nginx.com addr.length--; 711324Saxel.duch@nginx.com 721324Saxel.duch@nginx.com end = addr.start + addr.length; 731324Saxel.duch@nginx.com 741324Saxel.duch@nginx.com port.start = nxt_rmemstrn(addr.start, end, "]:", 2); 751324Saxel.duch@nginx.com if (nxt_slow_path(port.start == NULL)) { 761324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 771324Saxel.duch@nginx.com } 781324Saxel.duch@nginx.com 791324Saxel.duch@nginx.com addr.length = port.start - addr.start; 801324Saxel.duch@nginx.com port.start += nxt_length("]:"); 811324Saxel.duch@nginx.com port.length = end - port.start; 821324Saxel.duch@nginx.com } 831324Saxel.duch@nginx.com 841324Saxel.duch@nginx.com inet6 = &pattern->addr.v6; 851324Saxel.duch@nginx.com 861324Saxel.duch@nginx.com delim = nxt_memchr(addr.start, '-', addr.length); 871324Saxel.duch@nginx.com if (delim != NULL) { 881324Saxel.duch@nginx.com len = delim - addr.start; 891324Saxel.duch@nginx.com if (nxt_slow_path(!nxt_valid_ipv6_blocks(addr.start, len))) { 901324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 911324Saxel.duch@nginx.com } 921324Saxel.duch@nginx.com 931324Saxel.duch@nginx.com ret = nxt_inet6_addr(&inet6->start, addr.start, len); 941324Saxel.duch@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 951324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 961324Saxel.duch@nginx.com } 971324Saxel.duch@nginx.com 981324Saxel.duch@nginx.com len = addr.start + addr.length - delim - 1; 991324Saxel.duch@nginx.com if (nxt_slow_path(!nxt_valid_ipv6_blocks(delim + 1, len))) { 1001324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 1011324Saxel.duch@nginx.com } 1021324Saxel.duch@nginx.com 1031324Saxel.duch@nginx.com ret = nxt_inet6_addr(&inet6->end, delim + 1, len); 1041324Saxel.duch@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 1051324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 1061324Saxel.duch@nginx.com } 1071324Saxel.duch@nginx.com 1081324Saxel.duch@nginx.com if (nxt_slow_path(nxt_memcmp(&inet6->start, &inet6->end, 1091324Saxel.duch@nginx.com sizeof(struct in6_addr)) > 0)) 1101324Saxel.duch@nginx.com { 1111324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_RANGE_OVERLAP_ERROR; 1121324Saxel.duch@nginx.com } 1131324Saxel.duch@nginx.com 1141324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_RANGE; 1151324Saxel.duch@nginx.com 1161324Saxel.duch@nginx.com goto parse_port; 1171324Saxel.duch@nginx.com } 1181324Saxel.duch@nginx.com 1191324Saxel.duch@nginx.com delim = nxt_memchr(addr.start, '/', addr.length); 1201324Saxel.duch@nginx.com if (delim != NULL) { 1211324Saxel.duch@nginx.com cidr_prefix = nxt_int_parse(delim + 1, 1221324Saxel.duch@nginx.com addr.start + addr.length - (delim + 1)); 1231324Saxel.duch@nginx.com if (nxt_slow_path(cidr_prefix < 0 || cidr_prefix > 128)) { 1241324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_CIDR_ERROR; 1251324Saxel.duch@nginx.com } 1261324Saxel.duch@nginx.com 1271324Saxel.duch@nginx.com addr.length = delim - addr.start; 1281324Saxel.duch@nginx.com if (nxt_slow_path(!nxt_valid_ipv6_blocks(addr.start, 1291324Saxel.duch@nginx.com addr.length))) 1301324Saxel.duch@nginx.com { 1311324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 1321324Saxel.duch@nginx.com } 1331324Saxel.duch@nginx.com 1341324Saxel.duch@nginx.com ret = nxt_inet6_addr(&inet6->start, addr.start, addr.length); 1351324Saxel.duch@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 1361324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 1371324Saxel.duch@nginx.com } 1381324Saxel.duch@nginx.com 1391324Saxel.duch@nginx.com if (nxt_slow_path(cidr_prefix == 0)) { 1401324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_ANY; 1411324Saxel.duch@nginx.com 1421324Saxel.duch@nginx.com goto parse_port; 1431324Saxel.duch@nginx.com } 1441324Saxel.duch@nginx.com 1451324Saxel.duch@nginx.com if (nxt_slow_path(cidr_prefix == 128)) { 1461324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_EXACT; 1471324Saxel.duch@nginx.com 1481324Saxel.duch@nginx.com goto parse_port; 1491324Saxel.duch@nginx.com } 1501324Saxel.duch@nginx.com 1511324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_CIDR; 1521324Saxel.duch@nginx.com 1531324Saxel.duch@nginx.com for (i = 0; i < sizeof(struct in6_addr); i++) { 1541324Saxel.duch@nginx.com if (cidr_prefix >= 8) { 1551324Saxel.duch@nginx.com inet6->end.s6_addr[i] = 0xFF; 1561324Saxel.duch@nginx.com cidr_prefix -= 8; 1571324Saxel.duch@nginx.com 1581324Saxel.duch@nginx.com continue; 1591324Saxel.duch@nginx.com } 1601324Saxel.duch@nginx.com 1611324Saxel.duch@nginx.com if (cidr_prefix > 0) { 1621324Saxel.duch@nginx.com inet6->end.s6_addr[i] = 0xFF & (0xFF << (8 - cidr_prefix)); 1631324Saxel.duch@nginx.com inet6->start.s6_addr[i] &= inet6->end.s6_addr[i]; 1641324Saxel.duch@nginx.com cidr_prefix = 0; 1651324Saxel.duch@nginx.com 1661324Saxel.duch@nginx.com continue; 1671324Saxel.duch@nginx.com } 1681324Saxel.duch@nginx.com 1691324Saxel.duch@nginx.com inet6->start.s6_addr[i] = 0; 1701324Saxel.duch@nginx.com inet6->end.s6_addr[i] = 0; 1711324Saxel.duch@nginx.com } 1721324Saxel.duch@nginx.com 1731324Saxel.duch@nginx.com goto parse_port; 1741324Saxel.duch@nginx.com } 1751324Saxel.duch@nginx.com 1761324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_EXACT; 1771324Saxel.duch@nginx.com 1781324Saxel.duch@nginx.com if (nxt_slow_path(!nxt_valid_ipv6_blocks(addr.start, addr.length))) { 1791324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 1801324Saxel.duch@nginx.com } 1811324Saxel.duch@nginx.com 1821343Saxel.duch@nginx.com ret = nxt_inet6_addr(&inet6->start, addr.start, addr.length); 1831343Saxel.duch@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 1841343Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 1851343Saxel.duch@nginx.com } 1861324Saxel.duch@nginx.com 1871324Saxel.duch@nginx.com goto parse_port; 1881324Saxel.duch@nginx.com #endif 1891324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_NO_IPv6_ERROR; 1901324Saxel.duch@nginx.com } 1911324Saxel.duch@nginx.com 1921324Saxel.duch@nginx.com base->addr_family = AF_INET; 1931324Saxel.duch@nginx.com 1941324Saxel.duch@nginx.com delim = nxt_memchr(addr.start, ':', addr.length); 1951324Saxel.duch@nginx.com if (delim != NULL) { 1961324Saxel.duch@nginx.com port.start = delim + 1; 1971324Saxel.duch@nginx.com port.length = addr.start + addr.length - port.start; 1981324Saxel.duch@nginx.com addr.length = delim - addr.start; 1991324Saxel.duch@nginx.com } 2001324Saxel.duch@nginx.com 2011324Saxel.duch@nginx.com inet = &pattern->addr.v4; 2021324Saxel.duch@nginx.com 2031324Saxel.duch@nginx.com delim = nxt_memchr(addr.start, '-', addr.length); 2041324Saxel.duch@nginx.com if (delim != NULL) { 2051324Saxel.duch@nginx.com inet->start = nxt_inet_addr(addr.start, delim - addr.start); 2061324Saxel.duch@nginx.com if (nxt_slow_path(inet->start == INADDR_NONE)) { 2071324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 2081324Saxel.duch@nginx.com } 2091324Saxel.duch@nginx.com 2101324Saxel.duch@nginx.com inet->end = nxt_inet_addr(delim + 1, 2111324Saxel.duch@nginx.com addr.start + addr.length - (delim + 1)); 2121324Saxel.duch@nginx.com if (nxt_slow_path(inet->end == INADDR_NONE)) { 2131324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 2141324Saxel.duch@nginx.com } 2151324Saxel.duch@nginx.com 2161324Saxel.duch@nginx.com if (nxt_slow_path(nxt_memcmp(&inet->start, &inet->end, 2171324Saxel.duch@nginx.com sizeof(struct in_addr)) > 0)) 2181324Saxel.duch@nginx.com { 2191324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_RANGE_OVERLAP_ERROR; 2201324Saxel.duch@nginx.com } 2211324Saxel.duch@nginx.com 2221324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_RANGE; 2231324Saxel.duch@nginx.com 2241324Saxel.duch@nginx.com goto parse_port; 2251324Saxel.duch@nginx.com } 2261324Saxel.duch@nginx.com 2271324Saxel.duch@nginx.com delim = nxt_memchr(addr.start, '/', addr.length); 2281324Saxel.duch@nginx.com if (delim != NULL) { 2291324Saxel.duch@nginx.com cidr_prefix = nxt_int_parse(delim + 1, 2301324Saxel.duch@nginx.com addr.start + addr.length - (delim + 1)); 2311324Saxel.duch@nginx.com if (nxt_slow_path(cidr_prefix < 0 || cidr_prefix > 32)) { 2321324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_CIDR_ERROR; 2331324Saxel.duch@nginx.com } 2341324Saxel.duch@nginx.com 2351324Saxel.duch@nginx.com addr.length = delim - addr.start; 2361324Saxel.duch@nginx.com inet->end = htonl(0xFFFFFFFF & (0xFFFFFFFF << (32 - cidr_prefix))); 2371324Saxel.duch@nginx.com 2381324Saxel.duch@nginx.com inet->start = nxt_inet_addr(addr.start, addr.length) & inet->end; 2391324Saxel.duch@nginx.com if (nxt_slow_path(inet->start == INADDR_NONE)) { 2401324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 2411324Saxel.duch@nginx.com } 2421324Saxel.duch@nginx.com 2431324Saxel.duch@nginx.com if (cidr_prefix == 0) { 2441324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_ANY; 2451324Saxel.duch@nginx.com 2461324Saxel.duch@nginx.com goto parse_port; 2471324Saxel.duch@nginx.com } 2481324Saxel.duch@nginx.com 2491324Saxel.duch@nginx.com if (cidr_prefix < 32) { 2501324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_CIDR; 2511324Saxel.duch@nginx.com 2521324Saxel.duch@nginx.com goto parse_port; 2531324Saxel.duch@nginx.com } 2541324Saxel.duch@nginx.com } 2551324Saxel.duch@nginx.com 2561324Saxel.duch@nginx.com inet->start = nxt_inet_addr(addr.start, addr.length); 2571324Saxel.duch@nginx.com if (nxt_slow_path(inet->start == INADDR_NONE)) { 2581324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 2591324Saxel.duch@nginx.com } 2601324Saxel.duch@nginx.com 2611324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_EXACT; 2621324Saxel.duch@nginx.com 2631324Saxel.duch@nginx.com parse_port: 2641324Saxel.duch@nginx.com 2651324Saxel.duch@nginx.com if (port.length == 0) { 2661324Saxel.duch@nginx.com if (nxt_slow_path(port.start != NULL)) { 2671324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 2681324Saxel.duch@nginx.com } 2691324Saxel.duch@nginx.com 2701324Saxel.duch@nginx.com base->port.start = 0; 2711324Saxel.duch@nginx.com base->port.end = 65535; 2721324Saxel.duch@nginx.com 2731324Saxel.duch@nginx.com return NXT_OK; 2741324Saxel.duch@nginx.com } 2751324Saxel.duch@nginx.com 2761324Saxel.duch@nginx.com delim = nxt_memchr(port.start, '-', port.length - 1); 2771324Saxel.duch@nginx.com if (delim != NULL) { 2781324Saxel.duch@nginx.com ret = nxt_int_parse(port.start, delim - port.start); 2791324Saxel.duch@nginx.com if (nxt_slow_path(ret < 0 || ret > 65535)) { 2801324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_PORT_ERROR; 2811324Saxel.duch@nginx.com } 2821324Saxel.duch@nginx.com 2831324Saxel.duch@nginx.com base->port.start = ret; 2841324Saxel.duch@nginx.com 2851324Saxel.duch@nginx.com ret = nxt_int_parse(delim + 1, port.start + port.length - (delim + 1)); 2861324Saxel.duch@nginx.com if (nxt_slow_path(ret < base->port.start || ret > 65535)) { 2871324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_PORT_ERROR; 2881324Saxel.duch@nginx.com } 2891324Saxel.duch@nginx.com 2901324Saxel.duch@nginx.com base->port.end = ret; 2911324Saxel.duch@nginx.com 2921324Saxel.duch@nginx.com } else { 2931324Saxel.duch@nginx.com ret = nxt_int_parse(port.start, port.length); 2941324Saxel.duch@nginx.com if (nxt_slow_path(ret < 0 || ret > 65535)) { 2951324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_PORT_ERROR; 2961324Saxel.duch@nginx.com } 2971324Saxel.duch@nginx.com 2981324Saxel.duch@nginx.com base->port.start = ret; 2991324Saxel.duch@nginx.com base->port.end = ret; 3001324Saxel.duch@nginx.com } 3011324Saxel.duch@nginx.com 3021324Saxel.duch@nginx.com return NXT_OK; 3031324Saxel.duch@nginx.com } 3041324Saxel.duch@nginx.com 3051324Saxel.duch@nginx.com 3061324Saxel.duch@nginx.com #if (NXT_INET6) 3071324Saxel.duch@nginx.com 3081324Saxel.duch@nginx.com static nxt_bool_t 3091324Saxel.duch@nginx.com nxt_valid_ipv6_blocks(u_char *c, size_t len) 3101324Saxel.duch@nginx.com { 3111324Saxel.duch@nginx.com u_char *end; 3121324Saxel.duch@nginx.com nxt_uint_t colon_gap; 3131324Saxel.duch@nginx.com 3141324Saxel.duch@nginx.com end = c + len; 3151324Saxel.duch@nginx.com colon_gap = 0; 3161324Saxel.duch@nginx.com 3171324Saxel.duch@nginx.com while (c != end) { 3181324Saxel.duch@nginx.com if (*c == ':') { 3191324Saxel.duch@nginx.com colon_gap = 0; 3201324Saxel.duch@nginx.com c++; 3211324Saxel.duch@nginx.com 3221324Saxel.duch@nginx.com continue; 3231324Saxel.duch@nginx.com } 3241324Saxel.duch@nginx.com 3251324Saxel.duch@nginx.com colon_gap++; 3261324Saxel.duch@nginx.com c++; 3271324Saxel.duch@nginx.com 3281324Saxel.duch@nginx.com if (nxt_slow_path(colon_gap > 4)) { 3291324Saxel.duch@nginx.com return 0; 3301324Saxel.duch@nginx.com } 3311324Saxel.duch@nginx.com } 3321324Saxel.duch@nginx.com 3331324Saxel.duch@nginx.com return 1; 3341324Saxel.duch@nginx.com } 3351324Saxel.duch@nginx.com 3361324Saxel.duch@nginx.com #endif 337