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