1*1324Saxel.duch@nginx.com 2*1324Saxel.duch@nginx.com /* 3*1324Saxel.duch@nginx.com * Copyright (C) Axel Duch 4*1324Saxel.duch@nginx.com * Copyright (C) NGINX, Inc. 5*1324Saxel.duch@nginx.com */ 6*1324Saxel.duch@nginx.com 7*1324Saxel.duch@nginx.com #include <nxt_main.h> 8*1324Saxel.duch@nginx.com #include <nxt_http_route_addr.h> 9*1324Saxel.duch@nginx.com 10*1324Saxel.duch@nginx.com 11*1324Saxel.duch@nginx.com static nxt_bool_t nxt_str_looks_like_ipv6(const nxt_str_t *str); 12*1324Saxel.duch@nginx.com #if (NXT_INET6) 13*1324Saxel.duch@nginx.com static nxt_bool_t nxt_valid_ipv6_blocks(u_char *c, size_t len); 14*1324Saxel.duch@nginx.com #endif 15*1324Saxel.duch@nginx.com 16*1324Saxel.duch@nginx.com 17*1324Saxel.duch@nginx.com nxt_int_t 18*1324Saxel.duch@nginx.com nxt_http_route_addr_pattern_parse(nxt_mp_t *mp, 19*1324Saxel.duch@nginx.com nxt_http_route_addr_pattern_t *pattern, nxt_conf_value_t *cv) 20*1324Saxel.duch@nginx.com { 21*1324Saxel.duch@nginx.com u_char *delim, *end; 22*1324Saxel.duch@nginx.com nxt_int_t ret, cidr_prefix; 23*1324Saxel.duch@nginx.com nxt_str_t addr, port; 24*1324Saxel.duch@nginx.com nxt_http_route_addr_base_t *base; 25*1324Saxel.duch@nginx.com nxt_http_route_addr_range_t *inet; 26*1324Saxel.duch@nginx.com 27*1324Saxel.duch@nginx.com if (nxt_conf_type(cv) != NXT_CONF_STRING) { 28*1324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_CV_TYPE_ERROR; 29*1324Saxel.duch@nginx.com } 30*1324Saxel.duch@nginx.com 31*1324Saxel.duch@nginx.com nxt_conf_get_string(cv, &addr); 32*1324Saxel.duch@nginx.com 33*1324Saxel.duch@nginx.com base = &pattern->base; 34*1324Saxel.duch@nginx.com 35*1324Saxel.duch@nginx.com if (addr.length > 0 && addr.start[0] == '!') { 36*1324Saxel.duch@nginx.com addr.start++; 37*1324Saxel.duch@nginx.com addr.length--; 38*1324Saxel.duch@nginx.com 39*1324Saxel.duch@nginx.com base->negative = 1; 40*1324Saxel.duch@nginx.com 41*1324Saxel.duch@nginx.com } else { 42*1324Saxel.duch@nginx.com base->negative = 0; 43*1324Saxel.duch@nginx.com } 44*1324Saxel.duch@nginx.com 45*1324Saxel.duch@nginx.com if (nxt_slow_path(addr.length < 2)) { 46*1324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_LENGTH_ERROR; 47*1324Saxel.duch@nginx.com } 48*1324Saxel.duch@nginx.com 49*1324Saxel.duch@nginx.com nxt_str_null(&port); 50*1324Saxel.duch@nginx.com 51*1324Saxel.duch@nginx.com if (addr.start[0] == '*' && addr.start[1] == ':') { 52*1324Saxel.duch@nginx.com port.start = addr.start + 2; 53*1324Saxel.duch@nginx.com port.length = addr.length - 2; 54*1324Saxel.duch@nginx.com base->addr_family = AF_UNSPEC; 55*1324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_ANY; 56*1324Saxel.duch@nginx.com 57*1324Saxel.duch@nginx.com goto parse_port; 58*1324Saxel.duch@nginx.com } 59*1324Saxel.duch@nginx.com 60*1324Saxel.duch@nginx.com if (nxt_str_looks_like_ipv6(&addr)) { 61*1324Saxel.duch@nginx.com #if (NXT_INET6) 62*1324Saxel.duch@nginx.com uint8_t i; 63*1324Saxel.duch@nginx.com nxt_int_t len; 64*1324Saxel.duch@nginx.com nxt_http_route_in6_addr_range_t *inet6; 65*1324Saxel.duch@nginx.com 66*1324Saxel.duch@nginx.com base->addr_family = AF_INET6; 67*1324Saxel.duch@nginx.com 68*1324Saxel.duch@nginx.com if (addr.start[0] == '[') { 69*1324Saxel.duch@nginx.com addr.start++; 70*1324Saxel.duch@nginx.com addr.length--; 71*1324Saxel.duch@nginx.com 72*1324Saxel.duch@nginx.com end = addr.start + addr.length; 73*1324Saxel.duch@nginx.com 74*1324Saxel.duch@nginx.com port.start = nxt_rmemstrn(addr.start, end, "]:", 2); 75*1324Saxel.duch@nginx.com if (nxt_slow_path(port.start == NULL)) { 76*1324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 77*1324Saxel.duch@nginx.com } 78*1324Saxel.duch@nginx.com 79*1324Saxel.duch@nginx.com addr.length = port.start - addr.start; 80*1324Saxel.duch@nginx.com port.start += nxt_length("]:"); 81*1324Saxel.duch@nginx.com port.length = end - port.start; 82*1324Saxel.duch@nginx.com } 83*1324Saxel.duch@nginx.com 84*1324Saxel.duch@nginx.com inet6 = &pattern->addr.v6; 85*1324Saxel.duch@nginx.com 86*1324Saxel.duch@nginx.com delim = nxt_memchr(addr.start, '-', addr.length); 87*1324Saxel.duch@nginx.com if (delim != NULL) { 88*1324Saxel.duch@nginx.com len = delim - addr.start; 89*1324Saxel.duch@nginx.com if (nxt_slow_path(!nxt_valid_ipv6_blocks(addr.start, len))) { 90*1324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 91*1324Saxel.duch@nginx.com } 92*1324Saxel.duch@nginx.com 93*1324Saxel.duch@nginx.com ret = nxt_inet6_addr(&inet6->start, addr.start, len); 94*1324Saxel.duch@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 95*1324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 96*1324Saxel.duch@nginx.com } 97*1324Saxel.duch@nginx.com 98*1324Saxel.duch@nginx.com len = addr.start + addr.length - delim - 1; 99*1324Saxel.duch@nginx.com if (nxt_slow_path(!nxt_valid_ipv6_blocks(delim + 1, len))) { 100*1324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 101*1324Saxel.duch@nginx.com } 102*1324Saxel.duch@nginx.com 103*1324Saxel.duch@nginx.com ret = nxt_inet6_addr(&inet6->end, delim + 1, len); 104*1324Saxel.duch@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 105*1324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 106*1324Saxel.duch@nginx.com } 107*1324Saxel.duch@nginx.com 108*1324Saxel.duch@nginx.com if (nxt_slow_path(nxt_memcmp(&inet6->start, &inet6->end, 109*1324Saxel.duch@nginx.com sizeof(struct in6_addr)) > 0)) 110*1324Saxel.duch@nginx.com { 111*1324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_RANGE_OVERLAP_ERROR; 112*1324Saxel.duch@nginx.com } 113*1324Saxel.duch@nginx.com 114*1324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_RANGE; 115*1324Saxel.duch@nginx.com 116*1324Saxel.duch@nginx.com goto parse_port; 117*1324Saxel.duch@nginx.com } 118*1324Saxel.duch@nginx.com 119*1324Saxel.duch@nginx.com delim = nxt_memchr(addr.start, '/', addr.length); 120*1324Saxel.duch@nginx.com if (delim != NULL) { 121*1324Saxel.duch@nginx.com cidr_prefix = nxt_int_parse(delim + 1, 122*1324Saxel.duch@nginx.com addr.start + addr.length - (delim + 1)); 123*1324Saxel.duch@nginx.com if (nxt_slow_path(cidr_prefix < 0 || cidr_prefix > 128)) { 124*1324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_CIDR_ERROR; 125*1324Saxel.duch@nginx.com } 126*1324Saxel.duch@nginx.com 127*1324Saxel.duch@nginx.com addr.length = delim - addr.start; 128*1324Saxel.duch@nginx.com if (nxt_slow_path(!nxt_valid_ipv6_blocks(addr.start, 129*1324Saxel.duch@nginx.com addr.length))) 130*1324Saxel.duch@nginx.com { 131*1324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 132*1324Saxel.duch@nginx.com } 133*1324Saxel.duch@nginx.com 134*1324Saxel.duch@nginx.com ret = nxt_inet6_addr(&inet6->start, addr.start, addr.length); 135*1324Saxel.duch@nginx.com if (nxt_slow_path(ret != NXT_OK)) { 136*1324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 137*1324Saxel.duch@nginx.com } 138*1324Saxel.duch@nginx.com 139*1324Saxel.duch@nginx.com if (nxt_slow_path(cidr_prefix == 0)) { 140*1324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_ANY; 141*1324Saxel.duch@nginx.com 142*1324Saxel.duch@nginx.com goto parse_port; 143*1324Saxel.duch@nginx.com } 144*1324Saxel.duch@nginx.com 145*1324Saxel.duch@nginx.com if (nxt_slow_path(cidr_prefix == 128)) { 146*1324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_EXACT; 147*1324Saxel.duch@nginx.com 148*1324Saxel.duch@nginx.com goto parse_port; 149*1324Saxel.duch@nginx.com } 150*1324Saxel.duch@nginx.com 151*1324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_CIDR; 152*1324Saxel.duch@nginx.com 153*1324Saxel.duch@nginx.com for (i = 0; i < sizeof(struct in6_addr); i++) { 154*1324Saxel.duch@nginx.com if (cidr_prefix >= 8) { 155*1324Saxel.duch@nginx.com inet6->end.s6_addr[i] = 0xFF; 156*1324Saxel.duch@nginx.com cidr_prefix -= 8; 157*1324Saxel.duch@nginx.com 158*1324Saxel.duch@nginx.com continue; 159*1324Saxel.duch@nginx.com } 160*1324Saxel.duch@nginx.com 161*1324Saxel.duch@nginx.com if (cidr_prefix > 0) { 162*1324Saxel.duch@nginx.com inet6->end.s6_addr[i] = 0xFF & (0xFF << (8 - cidr_prefix)); 163*1324Saxel.duch@nginx.com inet6->start.s6_addr[i] &= inet6->end.s6_addr[i]; 164*1324Saxel.duch@nginx.com cidr_prefix = 0; 165*1324Saxel.duch@nginx.com 166*1324Saxel.duch@nginx.com continue; 167*1324Saxel.duch@nginx.com } 168*1324Saxel.duch@nginx.com 169*1324Saxel.duch@nginx.com inet6->start.s6_addr[i] = 0; 170*1324Saxel.duch@nginx.com inet6->end.s6_addr[i] = 0; 171*1324Saxel.duch@nginx.com } 172*1324Saxel.duch@nginx.com 173*1324Saxel.duch@nginx.com goto parse_port; 174*1324Saxel.duch@nginx.com } 175*1324Saxel.duch@nginx.com 176*1324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_EXACT; 177*1324Saxel.duch@nginx.com 178*1324Saxel.duch@nginx.com if (nxt_slow_path(!nxt_valid_ipv6_blocks(addr.start, addr.length))) { 179*1324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 180*1324Saxel.duch@nginx.com } 181*1324Saxel.duch@nginx.com 182*1324Saxel.duch@nginx.com nxt_inet6_addr(&inet6->start, addr.start, addr.length); 183*1324Saxel.duch@nginx.com 184*1324Saxel.duch@nginx.com goto parse_port; 185*1324Saxel.duch@nginx.com #endif 186*1324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_NO_IPv6_ERROR; 187*1324Saxel.duch@nginx.com } 188*1324Saxel.duch@nginx.com 189*1324Saxel.duch@nginx.com base->addr_family = AF_INET; 190*1324Saxel.duch@nginx.com 191*1324Saxel.duch@nginx.com delim = nxt_memchr(addr.start, ':', addr.length); 192*1324Saxel.duch@nginx.com if (delim != NULL) { 193*1324Saxel.duch@nginx.com port.start = delim + 1; 194*1324Saxel.duch@nginx.com port.length = addr.start + addr.length - port.start; 195*1324Saxel.duch@nginx.com addr.length = delim - addr.start; 196*1324Saxel.duch@nginx.com } 197*1324Saxel.duch@nginx.com 198*1324Saxel.duch@nginx.com inet = &pattern->addr.v4; 199*1324Saxel.duch@nginx.com 200*1324Saxel.duch@nginx.com delim = nxt_memchr(addr.start, '-', addr.length); 201*1324Saxel.duch@nginx.com if (delim != NULL) { 202*1324Saxel.duch@nginx.com inet->start = nxt_inet_addr(addr.start, delim - addr.start); 203*1324Saxel.duch@nginx.com if (nxt_slow_path(inet->start == INADDR_NONE)) { 204*1324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 205*1324Saxel.duch@nginx.com } 206*1324Saxel.duch@nginx.com 207*1324Saxel.duch@nginx.com inet->end = nxt_inet_addr(delim + 1, 208*1324Saxel.duch@nginx.com addr.start + addr.length - (delim + 1)); 209*1324Saxel.duch@nginx.com if (nxt_slow_path(inet->end == INADDR_NONE)) { 210*1324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 211*1324Saxel.duch@nginx.com } 212*1324Saxel.duch@nginx.com 213*1324Saxel.duch@nginx.com if (nxt_slow_path(nxt_memcmp(&inet->start, &inet->end, 214*1324Saxel.duch@nginx.com sizeof(struct in_addr)) > 0)) 215*1324Saxel.duch@nginx.com { 216*1324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_RANGE_OVERLAP_ERROR; 217*1324Saxel.duch@nginx.com } 218*1324Saxel.duch@nginx.com 219*1324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_RANGE; 220*1324Saxel.duch@nginx.com 221*1324Saxel.duch@nginx.com goto parse_port; 222*1324Saxel.duch@nginx.com } 223*1324Saxel.duch@nginx.com 224*1324Saxel.duch@nginx.com delim = nxt_memchr(addr.start, '/', addr.length); 225*1324Saxel.duch@nginx.com if (delim != NULL) { 226*1324Saxel.duch@nginx.com cidr_prefix = nxt_int_parse(delim + 1, 227*1324Saxel.duch@nginx.com addr.start + addr.length - (delim + 1)); 228*1324Saxel.duch@nginx.com if (nxt_slow_path(cidr_prefix < 0 || cidr_prefix > 32)) { 229*1324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_CIDR_ERROR; 230*1324Saxel.duch@nginx.com } 231*1324Saxel.duch@nginx.com 232*1324Saxel.duch@nginx.com addr.length = delim - addr.start; 233*1324Saxel.duch@nginx.com inet->end = htonl(0xFFFFFFFF & (0xFFFFFFFF << (32 - cidr_prefix))); 234*1324Saxel.duch@nginx.com 235*1324Saxel.duch@nginx.com inet->start = nxt_inet_addr(addr.start, addr.length) & inet->end; 236*1324Saxel.duch@nginx.com if (nxt_slow_path(inet->start == INADDR_NONE)) { 237*1324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 238*1324Saxel.duch@nginx.com } 239*1324Saxel.duch@nginx.com 240*1324Saxel.duch@nginx.com if (cidr_prefix == 0) { 241*1324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_ANY; 242*1324Saxel.duch@nginx.com 243*1324Saxel.duch@nginx.com goto parse_port; 244*1324Saxel.duch@nginx.com } 245*1324Saxel.duch@nginx.com 246*1324Saxel.duch@nginx.com if (cidr_prefix < 32) { 247*1324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_CIDR; 248*1324Saxel.duch@nginx.com 249*1324Saxel.duch@nginx.com goto parse_port; 250*1324Saxel.duch@nginx.com } 251*1324Saxel.duch@nginx.com } 252*1324Saxel.duch@nginx.com 253*1324Saxel.duch@nginx.com inet->start = nxt_inet_addr(addr.start, addr.length); 254*1324Saxel.duch@nginx.com if (nxt_slow_path(inet->start == INADDR_NONE)) { 255*1324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 256*1324Saxel.duch@nginx.com } 257*1324Saxel.duch@nginx.com 258*1324Saxel.duch@nginx.com base->match_type = NXT_HTTP_ROUTE_ADDR_EXACT; 259*1324Saxel.duch@nginx.com 260*1324Saxel.duch@nginx.com parse_port: 261*1324Saxel.duch@nginx.com 262*1324Saxel.duch@nginx.com if (port.length == 0) { 263*1324Saxel.duch@nginx.com if (nxt_slow_path(port.start != NULL)) { 264*1324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_FORMAT_ERROR; 265*1324Saxel.duch@nginx.com } 266*1324Saxel.duch@nginx.com 267*1324Saxel.duch@nginx.com base->port.start = 0; 268*1324Saxel.duch@nginx.com base->port.end = 65535; 269*1324Saxel.duch@nginx.com 270*1324Saxel.duch@nginx.com return NXT_OK; 271*1324Saxel.duch@nginx.com } 272*1324Saxel.duch@nginx.com 273*1324Saxel.duch@nginx.com delim = nxt_memchr(port.start, '-', port.length - 1); 274*1324Saxel.duch@nginx.com if (delim != NULL) { 275*1324Saxel.duch@nginx.com ret = nxt_int_parse(port.start, delim - port.start); 276*1324Saxel.duch@nginx.com if (nxt_slow_path(ret < 0 || ret > 65535)) { 277*1324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_PORT_ERROR; 278*1324Saxel.duch@nginx.com } 279*1324Saxel.duch@nginx.com 280*1324Saxel.duch@nginx.com base->port.start = ret; 281*1324Saxel.duch@nginx.com 282*1324Saxel.duch@nginx.com ret = nxt_int_parse(delim + 1, port.start + port.length - (delim + 1)); 283*1324Saxel.duch@nginx.com if (nxt_slow_path(ret < base->port.start || ret > 65535)) { 284*1324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_PORT_ERROR; 285*1324Saxel.duch@nginx.com } 286*1324Saxel.duch@nginx.com 287*1324Saxel.duch@nginx.com base->port.end = ret; 288*1324Saxel.duch@nginx.com 289*1324Saxel.duch@nginx.com } else { 290*1324Saxel.duch@nginx.com ret = nxt_int_parse(port.start, port.length); 291*1324Saxel.duch@nginx.com if (nxt_slow_path(ret < 0 || ret > 65535)) { 292*1324Saxel.duch@nginx.com return NXT_ADDR_PATTERN_PORT_ERROR; 293*1324Saxel.duch@nginx.com } 294*1324Saxel.duch@nginx.com 295*1324Saxel.duch@nginx.com base->port.start = ret; 296*1324Saxel.duch@nginx.com base->port.end = ret; 297*1324Saxel.duch@nginx.com } 298*1324Saxel.duch@nginx.com 299*1324Saxel.duch@nginx.com return NXT_OK; 300*1324Saxel.duch@nginx.com } 301*1324Saxel.duch@nginx.com 302*1324Saxel.duch@nginx.com 303*1324Saxel.duch@nginx.com static nxt_bool_t 304*1324Saxel.duch@nginx.com nxt_str_looks_like_ipv6(const nxt_str_t *str) 305*1324Saxel.duch@nginx.com { 306*1324Saxel.duch@nginx.com u_char *colon, *end; 307*1324Saxel.duch@nginx.com 308*1324Saxel.duch@nginx.com colon = nxt_memchr(str->start, ':', str->length); 309*1324Saxel.duch@nginx.com 310*1324Saxel.duch@nginx.com if (colon != NULL) { 311*1324Saxel.duch@nginx.com end = str->start + str->length; 312*1324Saxel.duch@nginx.com colon = nxt_memchr(colon + 1, ':', end - (colon + 1)); 313*1324Saxel.duch@nginx.com } 314*1324Saxel.duch@nginx.com 315*1324Saxel.duch@nginx.com return (colon != NULL); 316*1324Saxel.duch@nginx.com } 317*1324Saxel.duch@nginx.com 318*1324Saxel.duch@nginx.com 319*1324Saxel.duch@nginx.com #if (NXT_INET6) 320*1324Saxel.duch@nginx.com 321*1324Saxel.duch@nginx.com static nxt_bool_t 322*1324Saxel.duch@nginx.com nxt_valid_ipv6_blocks(u_char *c, size_t len) 323*1324Saxel.duch@nginx.com { 324*1324Saxel.duch@nginx.com u_char *end; 325*1324Saxel.duch@nginx.com nxt_uint_t colon_gap; 326*1324Saxel.duch@nginx.com 327*1324Saxel.duch@nginx.com end = c + len; 328*1324Saxel.duch@nginx.com colon_gap = 0; 329*1324Saxel.duch@nginx.com 330*1324Saxel.duch@nginx.com while (c != end) { 331*1324Saxel.duch@nginx.com if (*c == ':') { 332*1324Saxel.duch@nginx.com colon_gap = 0; 333*1324Saxel.duch@nginx.com c++; 334*1324Saxel.duch@nginx.com 335*1324Saxel.duch@nginx.com continue; 336*1324Saxel.duch@nginx.com } 337*1324Saxel.duch@nginx.com 338*1324Saxel.duch@nginx.com colon_gap++; 339*1324Saxel.duch@nginx.com c++; 340*1324Saxel.duch@nginx.com 341*1324Saxel.duch@nginx.com if (nxt_slow_path(colon_gap > 4)) { 342*1324Saxel.duch@nginx.com return 0; 343*1324Saxel.duch@nginx.com } 344*1324Saxel.duch@nginx.com } 345*1324Saxel.duch@nginx.com 346*1324Saxel.duch@nginx.com return 1; 347*1324Saxel.duch@nginx.com } 348*1324Saxel.duch@nginx.com 349*1324Saxel.duch@nginx.com #endif 350