xref: /unit/src/nxt_http_route_addr.c (revision 2232:1fb2182a4d03)
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