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