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