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
nxt_http_route_addr_pattern_parse(nxt_mp_t * mp,nxt_http_route_addr_pattern_t * pattern,nxt_conf_value_t * cv)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
442161Salx.manpages@gmail.com if (nxt_str_eq(&addr, "unix", 4)) {
452161Salx.manpages@gmail.com #if (NXT_HAVE_UNIX_DOMAIN)
462161Salx.manpages@gmail.com base->addr_family = AF_UNIX;
472161Salx.manpages@gmail.com
482161Salx.manpages@gmail.com return NXT_OK;
492161Salx.manpages@gmail.com #else
502161Salx.manpages@gmail.com return NXT_ADDR_PATTERN_NO_UNIX_ERROR;
512161Salx.manpages@gmail.com #endif
522161Salx.manpages@gmail.com }
532161Salx.manpages@gmail.com
541324Saxel.duch@nginx.com if (nxt_slow_path(addr.length < 2)) {
551324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_LENGTH_ERROR;
561324Saxel.duch@nginx.com }
571324Saxel.duch@nginx.com
581324Saxel.duch@nginx.com nxt_str_null(&port);
591324Saxel.duch@nginx.com
601324Saxel.duch@nginx.com if (addr.start[0] == '*' && addr.start[1] == ':') {
611324Saxel.duch@nginx.com port.start = addr.start + 2;
621324Saxel.duch@nginx.com port.length = addr.length - 2;
631324Saxel.duch@nginx.com base->addr_family = AF_UNSPEC;
641324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_ANY;
651324Saxel.duch@nginx.com
661324Saxel.duch@nginx.com goto parse_port;
671324Saxel.duch@nginx.com }
681324Saxel.duch@nginx.com
691935So.canty@f5.com if (nxt_inet6_probe(&addr)) {
701324Saxel.duch@nginx.com #if (NXT_INET6)
711343Saxel.duch@nginx.com u_char *end;
721324Saxel.duch@nginx.com uint8_t i;
731324Saxel.duch@nginx.com nxt_int_t len;
741324Saxel.duch@nginx.com nxt_http_route_in6_addr_range_t *inet6;
751324Saxel.duch@nginx.com
761324Saxel.duch@nginx.com base->addr_family = AF_INET6;
771324Saxel.duch@nginx.com
781324Saxel.duch@nginx.com if (addr.start[0] == '[') {
791324Saxel.duch@nginx.com addr.start++;
801324Saxel.duch@nginx.com addr.length--;
811324Saxel.duch@nginx.com
821324Saxel.duch@nginx.com end = addr.start + addr.length;
831324Saxel.duch@nginx.com
841324Saxel.duch@nginx.com port.start = nxt_rmemstrn(addr.start, end, "]:", 2);
851324Saxel.duch@nginx.com if (nxt_slow_path(port.start == NULL)) {
861324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR;
871324Saxel.duch@nginx.com }
881324Saxel.duch@nginx.com
891324Saxel.duch@nginx.com addr.length = port.start - addr.start;
901324Saxel.duch@nginx.com port.start += nxt_length("]:");
911324Saxel.duch@nginx.com port.length = end - port.start;
921324Saxel.duch@nginx.com }
931324Saxel.duch@nginx.com
941324Saxel.duch@nginx.com inet6 = &pattern->addr.v6;
951324Saxel.duch@nginx.com
96*2232Salx@nginx.com delim = memchr(addr.start, '-', addr.length);
971324Saxel.duch@nginx.com if (delim != NULL) {
981324Saxel.duch@nginx.com len = delim - addr.start;
991324Saxel.duch@nginx.com if (nxt_slow_path(!nxt_valid_ipv6_blocks(addr.start, 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->start, addr.start, 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 len = addr.start + addr.length - delim - 1;
1091324Saxel.duch@nginx.com if (nxt_slow_path(!nxt_valid_ipv6_blocks(delim + 1, len))) {
1101324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR;
1111324Saxel.duch@nginx.com }
1121324Saxel.duch@nginx.com
1131324Saxel.duch@nginx.com ret = nxt_inet6_addr(&inet6->end, delim + 1, len);
1141324Saxel.duch@nginx.com if (nxt_slow_path(ret != NXT_OK)) {
1151324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR;
1161324Saxel.duch@nginx.com }
1171324Saxel.duch@nginx.com
1182231Salx@nginx.com if (nxt_slow_path(memcmp(&inet6->start, &inet6->end,
1191324Saxel.duch@nginx.com sizeof(struct in6_addr)) > 0))
1201324Saxel.duch@nginx.com {
1211324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_RANGE_OVERLAP_ERROR;
1221324Saxel.duch@nginx.com }
1231324Saxel.duch@nginx.com
1241324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_RANGE;
1251324Saxel.duch@nginx.com
1261324Saxel.duch@nginx.com goto parse_port;
1271324Saxel.duch@nginx.com }
1281324Saxel.duch@nginx.com
129*2232Salx@nginx.com delim = memchr(addr.start, '/', addr.length);
1301324Saxel.duch@nginx.com if (delim != NULL) {
1311324Saxel.duch@nginx.com cidr_prefix = nxt_int_parse(delim + 1,
1321324Saxel.duch@nginx.com addr.start + addr.length - (delim + 1));
1331324Saxel.duch@nginx.com if (nxt_slow_path(cidr_prefix < 0 || cidr_prefix > 128)) {
1341324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_CIDR_ERROR;
1351324Saxel.duch@nginx.com }
1361324Saxel.duch@nginx.com
1371324Saxel.duch@nginx.com addr.length = delim - addr.start;
1381324Saxel.duch@nginx.com if (nxt_slow_path(!nxt_valid_ipv6_blocks(addr.start,
1391324Saxel.duch@nginx.com addr.length)))
1401324Saxel.duch@nginx.com {
1411324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR;
1421324Saxel.duch@nginx.com }
1431324Saxel.duch@nginx.com
1441324Saxel.duch@nginx.com ret = nxt_inet6_addr(&inet6->start, addr.start, addr.length);
1451324Saxel.duch@nginx.com if (nxt_slow_path(ret != NXT_OK)) {
1461324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR;
1471324Saxel.duch@nginx.com }
1481324Saxel.duch@nginx.com
1491324Saxel.duch@nginx.com if (nxt_slow_path(cidr_prefix == 0)) {
1501324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_ANY;
1511324Saxel.duch@nginx.com
1521324Saxel.duch@nginx.com goto parse_port;
1531324Saxel.duch@nginx.com }
1541324Saxel.duch@nginx.com
1551324Saxel.duch@nginx.com if (nxt_slow_path(cidr_prefix == 128)) {
1561324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_EXACT;
1571324Saxel.duch@nginx.com
1581324Saxel.duch@nginx.com goto parse_port;
1591324Saxel.duch@nginx.com }
1601324Saxel.duch@nginx.com
1611324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_CIDR;
1621324Saxel.duch@nginx.com
1631324Saxel.duch@nginx.com for (i = 0; i < sizeof(struct in6_addr); i++) {
1641324Saxel.duch@nginx.com if (cidr_prefix >= 8) {
1651324Saxel.duch@nginx.com inet6->end.s6_addr[i] = 0xFF;
1661324Saxel.duch@nginx.com cidr_prefix -= 8;
1671324Saxel.duch@nginx.com
1681324Saxel.duch@nginx.com continue;
1691324Saxel.duch@nginx.com }
1701324Saxel.duch@nginx.com
1711324Saxel.duch@nginx.com if (cidr_prefix > 0) {
1721324Saxel.duch@nginx.com inet6->end.s6_addr[i] = 0xFF & (0xFF << (8 - cidr_prefix));
1731324Saxel.duch@nginx.com inet6->start.s6_addr[i] &= inet6->end.s6_addr[i];
1741324Saxel.duch@nginx.com cidr_prefix = 0;
1751324Saxel.duch@nginx.com
1761324Saxel.duch@nginx.com continue;
1771324Saxel.duch@nginx.com }
1781324Saxel.duch@nginx.com
1791324Saxel.duch@nginx.com inet6->start.s6_addr[i] = 0;
1801324Saxel.duch@nginx.com inet6->end.s6_addr[i] = 0;
1811324Saxel.duch@nginx.com }
1821324Saxel.duch@nginx.com
1831324Saxel.duch@nginx.com goto parse_port;
1841324Saxel.duch@nginx.com }
1851324Saxel.duch@nginx.com
1861324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_EXACT;
1871324Saxel.duch@nginx.com
1881324Saxel.duch@nginx.com if (nxt_slow_path(!nxt_valid_ipv6_blocks(addr.start, addr.length))) {
1891324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR;
1901324Saxel.duch@nginx.com }
1911324Saxel.duch@nginx.com
1921343Saxel.duch@nginx.com ret = nxt_inet6_addr(&inet6->start, addr.start, addr.length);
1931343Saxel.duch@nginx.com if (nxt_slow_path(ret != NXT_OK)) {
1941343Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR;
1951343Saxel.duch@nginx.com }
1961324Saxel.duch@nginx.com
1971324Saxel.duch@nginx.com goto parse_port;
1981324Saxel.duch@nginx.com #endif
1991324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_NO_IPv6_ERROR;
2001324Saxel.duch@nginx.com }
2011324Saxel.duch@nginx.com
2021324Saxel.duch@nginx.com base->addr_family = AF_INET;
2031324Saxel.duch@nginx.com
204*2232Salx@nginx.com delim = memchr(addr.start, ':', addr.length);
2051324Saxel.duch@nginx.com if (delim != NULL) {
2061324Saxel.duch@nginx.com port.start = delim + 1;
2071324Saxel.duch@nginx.com port.length = addr.start + addr.length - port.start;
2081324Saxel.duch@nginx.com addr.length = delim - addr.start;
2091324Saxel.duch@nginx.com }
2101324Saxel.duch@nginx.com
2111324Saxel.duch@nginx.com inet = &pattern->addr.v4;
2121324Saxel.duch@nginx.com
213*2232Salx@nginx.com delim = memchr(addr.start, '-', addr.length);
2141324Saxel.duch@nginx.com if (delim != NULL) {
2151324Saxel.duch@nginx.com inet->start = nxt_inet_addr(addr.start, delim - addr.start);
2161324Saxel.duch@nginx.com if (nxt_slow_path(inet->start == INADDR_NONE)) {
2171324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR;
2181324Saxel.duch@nginx.com }
2191324Saxel.duch@nginx.com
2201324Saxel.duch@nginx.com inet->end = nxt_inet_addr(delim + 1,
2211324Saxel.duch@nginx.com addr.start + addr.length - (delim + 1));
2221324Saxel.duch@nginx.com if (nxt_slow_path(inet->end == INADDR_NONE)) {
2231324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR;
2241324Saxel.duch@nginx.com }
2251324Saxel.duch@nginx.com
2262231Salx@nginx.com if (nxt_slow_path(memcmp(&inet->start, &inet->end,
2271324Saxel.duch@nginx.com sizeof(struct in_addr)) > 0))
2281324Saxel.duch@nginx.com {
2291324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_RANGE_OVERLAP_ERROR;
2301324Saxel.duch@nginx.com }
2311324Saxel.duch@nginx.com
2321324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_RANGE;
2331324Saxel.duch@nginx.com
2341324Saxel.duch@nginx.com goto parse_port;
2351324Saxel.duch@nginx.com }
2361324Saxel.duch@nginx.com
237*2232Salx@nginx.com delim = memchr(addr.start, '/', addr.length);
2381324Saxel.duch@nginx.com if (delim != NULL) {
2391324Saxel.duch@nginx.com cidr_prefix = nxt_int_parse(delim + 1,
2401324Saxel.duch@nginx.com addr.start + addr.length - (delim + 1));
2411324Saxel.duch@nginx.com if (nxt_slow_path(cidr_prefix < 0 || cidr_prefix > 32)) {
2421324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_CIDR_ERROR;
2431324Saxel.duch@nginx.com }
2441324Saxel.duch@nginx.com
2451324Saxel.duch@nginx.com addr.length = delim - addr.start;
2462160Sandrew@digital-domain.net inet->end = htonl(0xFFFFFFFF & (0xFFFFFFFFULL << (32 - cidr_prefix)));
2471324Saxel.duch@nginx.com
2481324Saxel.duch@nginx.com inet->start = nxt_inet_addr(addr.start, addr.length) & inet->end;
2491324Saxel.duch@nginx.com if (nxt_slow_path(inet->start == INADDR_NONE)) {
2501324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR;
2511324Saxel.duch@nginx.com }
2521324Saxel.duch@nginx.com
2531324Saxel.duch@nginx.com if (cidr_prefix == 0) {
2541324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_ANY;
2551324Saxel.duch@nginx.com
2561324Saxel.duch@nginx.com goto parse_port;
2571324Saxel.duch@nginx.com }
2581324Saxel.duch@nginx.com
2591324Saxel.duch@nginx.com if (cidr_prefix < 32) {
2601324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_CIDR;
2611324Saxel.duch@nginx.com
2621324Saxel.duch@nginx.com goto parse_port;
2631324Saxel.duch@nginx.com }
2641324Saxel.duch@nginx.com }
2651324Saxel.duch@nginx.com
2661324Saxel.duch@nginx.com inet->start = nxt_inet_addr(addr.start, addr.length);
2671324Saxel.duch@nginx.com if (nxt_slow_path(inet->start == INADDR_NONE)) {
2681324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR;
2691324Saxel.duch@nginx.com }
2701324Saxel.duch@nginx.com
2711324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_EXACT;
2721324Saxel.duch@nginx.com
2731324Saxel.duch@nginx.com parse_port:
2741324Saxel.duch@nginx.com
2751324Saxel.duch@nginx.com if (port.length == 0) {
2761324Saxel.duch@nginx.com if (nxt_slow_path(port.start != NULL)) {
2771324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR;
2781324Saxel.duch@nginx.com }
2791324Saxel.duch@nginx.com
2801324Saxel.duch@nginx.com base->port.start = 0;
2811324Saxel.duch@nginx.com base->port.end = 65535;
2821324Saxel.duch@nginx.com
2831324Saxel.duch@nginx.com return NXT_OK;
2841324Saxel.duch@nginx.com }
2851324Saxel.duch@nginx.com
286*2232Salx@nginx.com delim = memchr(port.start, '-', port.length - 1);
2871324Saxel.duch@nginx.com if (delim != NULL) {
2881324Saxel.duch@nginx.com ret = nxt_int_parse(port.start, delim - port.start);
2891324Saxel.duch@nginx.com if (nxt_slow_path(ret < 0 || ret > 65535)) {
2901324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_PORT_ERROR;
2911324Saxel.duch@nginx.com }
2921324Saxel.duch@nginx.com
2931324Saxel.duch@nginx.com base->port.start = ret;
2941324Saxel.duch@nginx.com
2951324Saxel.duch@nginx.com ret = nxt_int_parse(delim + 1, port.start + port.length - (delim + 1));
2961324Saxel.duch@nginx.com if (nxt_slow_path(ret < base->port.start || ret > 65535)) {
2971324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_PORT_ERROR;
2981324Saxel.duch@nginx.com }
2991324Saxel.duch@nginx.com
3001324Saxel.duch@nginx.com base->port.end = ret;
3011324Saxel.duch@nginx.com
3021324Saxel.duch@nginx.com } else {
3031324Saxel.duch@nginx.com ret = nxt_int_parse(port.start, port.length);
3041324Saxel.duch@nginx.com if (nxt_slow_path(ret < 0 || ret > 65535)) {
3051324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_PORT_ERROR;
3061324Saxel.duch@nginx.com }
3071324Saxel.duch@nginx.com
3081324Saxel.duch@nginx.com base->port.start = ret;
3091324Saxel.duch@nginx.com base->port.end = ret;
3101324Saxel.duch@nginx.com }
3111324Saxel.duch@nginx.com
3121324Saxel.duch@nginx.com return NXT_OK;
3131324Saxel.duch@nginx.com }
3141324Saxel.duch@nginx.com
3151324Saxel.duch@nginx.com
3161324Saxel.duch@nginx.com #if (NXT_INET6)
3171324Saxel.duch@nginx.com
3181324Saxel.duch@nginx.com static nxt_bool_t
nxt_valid_ipv6_blocks(u_char * c,size_t len)3191324Saxel.duch@nginx.com nxt_valid_ipv6_blocks(u_char *c, size_t len)
3201324Saxel.duch@nginx.com {
3211324Saxel.duch@nginx.com u_char *end;
3221324Saxel.duch@nginx.com nxt_uint_t colon_gap;
3231324Saxel.duch@nginx.com
3241324Saxel.duch@nginx.com end = c + len;
3251324Saxel.duch@nginx.com colon_gap = 0;
3261324Saxel.duch@nginx.com
3271324Saxel.duch@nginx.com while (c != end) {
3281324Saxel.duch@nginx.com if (*c == ':') {
3291324Saxel.duch@nginx.com colon_gap = 0;
3301324Saxel.duch@nginx.com c++;
3311324Saxel.duch@nginx.com
3321324Saxel.duch@nginx.com continue;
3331324Saxel.duch@nginx.com }
3341324Saxel.duch@nginx.com
3351324Saxel.duch@nginx.com colon_gap++;
3361324Saxel.duch@nginx.com c++;
3371324Saxel.duch@nginx.com
3381324Saxel.duch@nginx.com if (nxt_slow_path(colon_gap > 4)) {
3391324Saxel.duch@nginx.com return 0;
3401324Saxel.duch@nginx.com }
3411324Saxel.duch@nginx.com }
3421324Saxel.duch@nginx.com
3431324Saxel.duch@nginx.com return 1;
3441324Saxel.duch@nginx.com }
3451324Saxel.duch@nginx.com
3461324Saxel.duch@nginx.com #endif
347