Klaus Demo nginx / 3d87688
Geo: IPv6 support. The "ranges" mode is still limited to IPv4 only. Ruslan Ermilov 9 years ago
3 changed file(s) with 453 addition(s) and 90 deletion(s). Raw diff Collapse all Expand all
262262 }
263263
264264
265 #if (NGX_HAVE_INET6)
266
267 ngx_int_t
268 ngx_radix128tree_insert(ngx_radix_tree_t *tree, u_char *key, u_char *mask,
269 uintptr_t value)
270 {
271 u_char bit;
272 ngx_uint_t i;
273 ngx_radix_node_t *node, *next;
274
275 i = 0;
276 bit = 0x80;
277
278 node = tree->root;
279 next = tree->root;
280
281 while (bit & mask[i]) {
282 if (key[i] & bit) {
283 next = node->right;
284
285 } else {
286 next = node->left;
287 }
288
289 if (next == NULL) {
290 break;
291 }
292
293 bit >>= 1;
294 node = next;
295
296 if (bit == 0) {
297 if (++i == 16) {
298 break;
299 }
300
301 bit = 0x80;
302 }
303 }
304
305 if (next) {
306 if (node->value != NGX_RADIX_NO_VALUE) {
307 return NGX_BUSY;
308 }
309
310 node->value = value;
311 return NGX_OK;
312 }
313
314 while (bit & mask[i]) {
315 next = ngx_radix_alloc(tree);
316 if (next == NULL) {
317 return NGX_ERROR;
318 }
319
320 next->right = NULL;
321 next->left = NULL;
322 next->parent = node;
323 next->value = NGX_RADIX_NO_VALUE;
324
325 if (key[i] & bit) {
326 node->right = next;
327
328 } else {
329 node->left = next;
330 }
331
332 bit >>= 1;
333 node = next;
334
335 if (bit == 0) {
336 if (++i == 16) {
337 break;
338 }
339
340 bit = 0x80;
341 }
342 }
343
344 node->value = value;
345
346 return NGX_OK;
347 }
348
349
350 ngx_int_t
351 ngx_radix128tree_delete(ngx_radix_tree_t *tree, u_char *key, u_char *mask)
352 {
353 u_char bit;
354 ngx_uint_t i;
355 ngx_radix_node_t *node;
356
357 i = 0;
358 bit = 0x80;
359 node = tree->root;
360
361 while (node && (bit & mask[i])) {
362 if (key[i] & bit) {
363 node = node->right;
364
365 } else {
366 node = node->left;
367 }
368
369 bit >>= 1;
370
371 if (bit == 0) {
372 if (++i == 16) {
373 break;
374 }
375
376 bit = 0x80;
377 }
378 }
379
380 if (node == NULL) {
381 return NGX_ERROR;
382 }
383
384 if (node->right || node->left) {
385 if (node->value != NGX_RADIX_NO_VALUE) {
386 node->value = NGX_RADIX_NO_VALUE;
387 return NGX_OK;
388 }
389
390 return NGX_ERROR;
391 }
392
393 for ( ;; ) {
394 if (node->parent->right == node) {
395 node->parent->right = NULL;
396
397 } else {
398 node->parent->left = NULL;
399 }
400
401 node->right = tree->free;
402 tree->free = node;
403
404 node = node->parent;
405
406 if (node->right || node->left) {
407 break;
408 }
409
410 if (node->value != NGX_RADIX_NO_VALUE) {
411 break;
412 }
413
414 if (node->parent == NULL) {
415 break;
416 }
417 }
418
419 return NGX_OK;
420 }
421
422
423 uintptr_t
424 ngx_radix128tree_find(ngx_radix_tree_t *tree, u_char *key)
425 {
426 u_char bit;
427 uintptr_t value;
428 ngx_uint_t i;
429 ngx_radix_node_t *node;
430
431 i = 0;
432 bit = 0x80;
433 value = NGX_RADIX_NO_VALUE;
434 node = tree->root;
435
436 while (node) {
437 if (node->value != NGX_RADIX_NO_VALUE) {
438 value = node->value;
439 }
440
441 if (key[i] & bit) {
442 node = node->right;
443
444 } else {
445 node = node->left;
446 }
447
448 bit >>= 1;
449
450 if (bit == 0) {
451 i++;
452 bit = 0x80;
453 }
454 }
455
456 return value;
457 }
458
459 #endif
460
461
265462 static ngx_radix_node_t *
266463 ngx_radix_alloc(ngx_radix_tree_t *tree)
267464 {
3535
3636 ngx_radix_tree_t *ngx_radix_tree_create(ngx_pool_t *pool,
3737 ngx_int_t preallocate);
38
3839 ngx_int_t ngx_radix32tree_insert(ngx_radix_tree_t *tree,
3940 uint32_t key, uint32_t mask, uintptr_t value);
4041 ngx_int_t ngx_radix32tree_delete(ngx_radix_tree_t *tree,
4142 uint32_t key, uint32_t mask);
4243 uintptr_t ngx_radix32tree_find(ngx_radix_tree_t *tree, uint32_t key);
4344
45 #if (NGX_HAVE_INET6)
46 ngx_int_t ngx_radix128tree_insert(ngx_radix_tree_t *tree,
47 u_char *key, u_char *mask, uintptr_t value);
48 ngx_int_t ngx_radix128tree_delete(ngx_radix_tree_t *tree,
49 u_char *key, u_char *mask);
50 uintptr_t ngx_radix128tree_find(ngx_radix_tree_t *tree, u_char *key);
51 #endif
52
4453
4554 #endif /* _NGX_RADIX_TREE_H_INCLUDED_ */
1717
1818
1919 typedef struct {
20 ngx_radix_tree_t *tree;
21 #if (NGX_HAVE_INET6)
22 ngx_radix_tree_t *tree6;
23 #endif
24 } ngx_http_geo_trees_t;
25
26
27 typedef struct {
2028 ngx_http_geo_range_t **low;
2129 ngx_http_variable_value_t *default_value;
2230 } ngx_http_geo_high_ranges_t;
3442 ngx_str_t *net;
3543 ngx_http_geo_high_ranges_t high;
3644 ngx_radix_tree_t *tree;
45 #if (NGX_HAVE_INET6)
46 ngx_radix_tree_t *tree6;
47 #endif
3748 ngx_rbtree_t rbtree;
3849 ngx_rbtree_node_t sentinel;
3950 ngx_array_t *proxies;
5667
5768 typedef struct {
5869 union {
59 ngx_radix_tree_t *tree;
70 ngx_http_geo_trees_t trees;
6071 ngx_http_geo_high_ranges_t high;
6172 } u;
6273
6778 } ngx_http_geo_ctx_t;
6879
6980
70 static in_addr_t ngx_http_geo_addr(ngx_http_request_t *r,
71 ngx_http_geo_ctx_t *ctx);
81 static ngx_int_t ngx_http_geo_addr(ngx_http_request_t *r,
82 ngx_http_geo_ctx_t *ctx, ngx_addr_t *addr);
7283 static ngx_int_t ngx_http_geo_real_addr(ngx_http_request_t *r,
7384 ngx_http_geo_ctx_t *ctx, ngx_addr_t *addr);
7485 static char *ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
154165 };
155166
156167
157 /* AF_INET only */
168 /* geo range is AF_INET only */
158169
159170 static ngx_int_t
160171 ngx_http_geo_cidr_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
162173 {
163174 ngx_http_geo_ctx_t *ctx = (ngx_http_geo_ctx_t *) data;
164175
176 in_addr_t inaddr;
177 ngx_addr_t addr;
178 struct sockaddr_in *sin;
165179 ngx_http_variable_value_t *vv;
166
167 vv = (ngx_http_variable_value_t *)
168 ngx_radix32tree_find(ctx->u.tree, ngx_http_geo_addr(r, ctx));
180 #if (NGX_HAVE_INET6)
181 u_char *p;
182 struct in6_addr *inaddr6;
183 #endif
184
185 if (ngx_http_geo_addr(r, ctx, &addr) != NGX_OK) {
186 vv = (ngx_http_variable_value_t *)
187 ngx_radix32tree_find(ctx->u.trees.tree, INADDR_NONE);
188 goto done;
189 }
190
191 switch (addr.sockaddr->sa_family) {
192
193 #if (NGX_HAVE_INET6)
194 case AF_INET6:
195 inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr;
196 p = inaddr6->s6_addr;
197
198 if (IN6_IS_ADDR_V4MAPPED(inaddr6)) {
199 inaddr = p[12] << 24;
200 inaddr += p[13] << 16;
201 inaddr += p[14] << 8;
202 inaddr += p[15];
203
204 vv = (ngx_http_variable_value_t *)
205 ngx_radix32tree_find(ctx->u.trees.tree, inaddr);
206
207 } else {
208 vv = (ngx_http_variable_value_t *)
209 ngx_radix128tree_find(ctx->u.trees.tree6, p);
210 }
211
212 break;
213 #endif
214
215 default: /* AF_INET */
216 sin = (struct sockaddr_in *) addr.sockaddr;
217 inaddr = ntohl(sin->sin_addr.s_addr);
218
219 vv = (ngx_http_variable_value_t *)
220 ngx_radix32tree_find(ctx->u.trees.tree, inaddr);
221
222 break;
223 }
224
225 done:
169226
170227 *v = *vv;
171228
182239 {
183240 ngx_http_geo_ctx_t *ctx = (ngx_http_geo_ctx_t *) data;
184241
185 in_addr_t addr;
242 in_addr_t inaddr;
243 ngx_addr_t addr;
186244 ngx_uint_t n;
245 struct sockaddr_in *sin;
187246 ngx_http_geo_range_t *range;
247 #if (NGX_HAVE_INET6)
248 u_char *p;
249 struct in6_addr *inaddr6;
250 #endif
188251
189252 *v = *ctx->u.high.default_value;
190253
254 if (ngx_http_geo_addr(r, ctx, &addr) == NGX_OK) {
255
256 switch (addr.sockaddr->sa_family) {
257
258 #if (NGX_HAVE_INET6)
259 case AF_INET6:
260 inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr;
261
262 if (IN6_IS_ADDR_V4MAPPED(inaddr6)) {
263 p = inaddr6->s6_addr;
264
265 inaddr = p[12] << 24;
266 inaddr += p[13] << 16;
267 inaddr += p[14] << 8;
268 inaddr += p[15];
269
270 } else {
271 inaddr = INADDR_NONE;
272 }
273
274 break;
275 #endif
276
277 default: /* AF_INET */
278 sin = (struct sockaddr_in *) addr.sockaddr;
279 inaddr = ntohl(sin->sin_addr.s_addr);
280 break;
281 }
282
283 } else {
284 inaddr = INADDR_NONE;
285 }
286
191287 if (ctx->u.high.low) {
192 addr = ngx_http_geo_addr(r, ctx);
193
194 range = ctx->u.high.low[addr >> 16];
288 range = ctx->u.high.low[inaddr >> 16];
195289
196290 if (range) {
197 n = addr & 0xffff;
291 n = inaddr & 0xffff;
198292 do {
199293 if (n >= (ngx_uint_t) range->start
200294 && n <= (ngx_uint_t) range->end)
213307 }
214308
215309
216 static in_addr_t
217 ngx_http_geo_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx)
310 static ngx_int_t
311 ngx_http_geo_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx,
312 ngx_addr_t *addr)
218313 {
219 ngx_addr_t addr;
220 ngx_table_elt_t *xfwd;
221 struct sockaddr_in *sin;
222
223 if (ngx_http_geo_real_addr(r, ctx, &addr) != NGX_OK) {
224 return INADDR_NONE;
314 ngx_table_elt_t *xfwd;
315
316 if (ngx_http_geo_real_addr(r, ctx, addr) != NGX_OK) {
317 return NGX_ERROR;
225318 }
226319
227320 xfwd = r->headers_in.x_forwarded_for;
228321
229322 if (xfwd != NULL && ctx->proxies != NULL) {
230 (void) ngx_http_get_forwarded_addr(r, &addr, xfwd->value.data,
323 (void) ngx_http_get_forwarded_addr(r, addr, xfwd->value.data,
231324 xfwd->value.len, ctx->proxies,
232325 ctx->proxy_recursive);
233326 }
234327
235 #if (NGX_HAVE_INET6)
236
237 if (addr.sockaddr->sa_family == AF_INET6) {
238 u_char *p;
239 in_addr_t inaddr;
240 struct in6_addr *inaddr6;
241
242 inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr;
243
244 if (IN6_IS_ADDR_V4MAPPED(inaddr6)) {
245 p = inaddr6->s6_addr;
246
247 inaddr = p[12] << 24;
248 inaddr += p[13] << 16;
249 inaddr += p[14] << 8;
250 inaddr += p[15];
251
252 return inaddr;
253 }
254 }
255
256 #endif
257
258 if (addr.sockaddr->sa_family != AF_INET) {
259 return INADDR_NONE;
260 }
261
262 sin = (struct sockaddr_in *) addr.sockaddr;
263 return ntohl(sin->sin_addr.s_addr);
328 return NGX_OK;
264329 }
265330
266331
314379 ngx_http_variable_t *var;
315380 ngx_http_geo_ctx_t *geo;
316381 ngx_http_geo_conf_ctx_t ctx;
382 #if (NGX_HAVE_INET6)
383 static struct in6_addr zero;
384 #endif
317385
318386 value = cf->args->elts;
319387
444512 }
445513 }
446514
447 geo->u.tree = ctx.tree;
515 geo->u.trees.tree = ctx.tree;
516
517 #if (NGX_HAVE_INET6)
518 if (ctx.tree6 == NULL) {
519 ctx.tree6 = ngx_radix_tree_create(cf->pool, -1);
520 if (ctx.tree6 == NULL) {
521 return NGX_CONF_ERROR;
522 }
523 }
524
525 geo->u.trees.tree6 = ctx.tree6;
526 #endif
448527
449528 var->get_handler = ngx_http_geo_cidr_variable;
450529 var->data = (uintptr_t) geo;
460539 }
461540
462541 /* NGX_BUSY is okay (default was set explicitly) */
542
543 #if (NGX_HAVE_INET6)
544 if (ngx_radix128tree_insert(ctx.tree6, zero.s6_addr, zero.s6_addr,
545 (uintptr_t) &ngx_http_variable_null_value)
546 == NGX_ERROR)
547 {
548 return NGX_CONF_ERROR;
549 }
550 #endif
463551 }
464552
465553 return rv;
482570
483571 if (ngx_strcmp(value[0].data, "ranges") == 0) {
484572
485 if (ctx->tree) {
573 if (ctx->tree
574 #if (NGX_HAVE_INET6)
575 || ctx->tree6
576 #endif
577 )
578 {
486579 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
487580 "the \"ranges\" directive must be "
488581 "the first directive inside \"geo\" block");
9331026 }
9341027 }
9351028
1029 #if (NGX_HAVE_INET6)
1030 if (ctx->tree6 == NULL) {
1031 ctx->tree6 = ngx_radix_tree_create(ctx->pool, -1);
1032 if (ctx->tree6 == NULL) {
1033 return NGX_CONF_ERROR;
1034 }
1035 }
1036 #endif
1037
9361038 if (ngx_strcmp(value[0].data, "default") == 0) {
9371039 /* cidr.family = AF_INET; */
9381040 cidr.u.in.addr = 0;
9531055 return NGX_CONF_ERROR;
9541056 }
9551057
956 if (cidr.family != AF_INET) {
957 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
958 "\"geo\" supports IPv4 only");
959 return NGX_CONF_ERROR;
960 }
961
962 cidr.u.in.addr = ntohl(cidr.u.in.addr);
963 cidr.u.in.mask = ntohl(cidr.u.in.mask);
1058 if (cidr.family == AF_INET) {
1059 cidr.u.in.addr = ntohl(cidr.u.in.addr);
1060 cidr.u.in.mask = ntohl(cidr.u.in.mask);
1061 }
9641062
9651063 if (del) {
966 if (ngx_radix32tree_delete(ctx->tree, cidr.u.in.addr,
967 cidr.u.in.mask)
968 != NGX_OK)
969 {
1064 switch (cidr.family) {
1065
1066 #if (NGX_HAVE_INET6)
1067 case AF_INET6:
1068 rc = ngx_radix128tree_delete(ctx->tree6,
1069 cidr.u.in6.addr.s6_addr,
1070 cidr.u.in6.mask.s6_addr);
1071 break;
1072 #endif
1073
1074 default: /* AF_INET */
1075 rc = ngx_radix32tree_delete(ctx->tree, cidr.u.in.addr,
1076 cidr.u.in.mask);
1077 break;
1078 }
1079
1080 if (rc != NGX_OK) {
9701081 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
9711082 "no network \"%V\" to delete", net);
9721083 }
9811092 return NGX_CONF_ERROR;
9821093 }
9831094
984 for (i = 2; i; i--) {
985 rc = ngx_radix32tree_insert(ctx->tree, cidr.u.in.addr, cidr.u.in.mask,
986 (uintptr_t) val);
987 if (rc == NGX_OK) {
988 return NGX_CONF_OK;
989 }
990
991 if (rc == NGX_ERROR) {
992 return NGX_CONF_ERROR;
993 }
994
995 /* rc == NGX_BUSY */
996
997 old = (ngx_http_variable_value_t *)
998 ngx_radix32tree_find(ctx->tree, cidr.u.in.addr);
999
1000 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
1001 "duplicate network \"%V\", value: \"%v\", old value: \"%v\"",
1002 net, val, old);
1003
1004 rc = ngx_radix32tree_delete(ctx->tree, cidr.u.in.addr, cidr.u.in.mask);
1005
1006 if (rc == NGX_ERROR) {
1007 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid radix tree");
1008 return NGX_CONF_ERROR;
1009 }
1095 switch (cidr.family) {
1096
1097 #if (NGX_HAVE_INET6)
1098 case AF_INET6:
1099 for (i = 2; i; i--) {
1100 rc = ngx_radix128tree_insert(ctx->tree6, cidr.u.in6.addr.s6_addr,
1101 cidr.u.in6.mask.s6_addr,
1102 (uintptr_t) val);
1103
1104 if (rc == NGX_OK) {
1105 return NGX_CONF_OK;
1106 }
1107
1108 if (rc == NGX_ERROR) {
1109 return NGX_CONF_ERROR;
1110 }
1111
1112 /* rc == NGX_BUSY */
1113
1114 old = (ngx_http_variable_value_t *)
1115 ngx_radix128tree_find(ctx->tree6,
1116 cidr.u.in6.addr.s6_addr);
1117
1118 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
1119 "duplicate network \"%V\", value: \"%v\", old value: \"%v\"",
1120 net, val, old);
1121
1122 rc = ngx_radix128tree_delete(ctx->tree6,
1123 cidr.u.in6.addr.s6_addr,
1124 cidr.u.in6.mask.s6_addr);
1125
1126 if (rc == NGX_ERROR) {
1127 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid radix tree");
1128 return NGX_CONF_ERROR;
1129 }
1130 }
1131
1132 break;
1133 #endif
1134
1135 default: /* AF_INET */
1136 for (i = 2; i; i--) {
1137 rc = ngx_radix32tree_insert(ctx->tree, cidr.u.in.addr,
1138 cidr.u.in.mask, (uintptr_t) val);
1139
1140 if (rc == NGX_OK) {
1141 return NGX_CONF_OK;
1142 }
1143
1144 if (rc == NGX_ERROR) {
1145 return NGX_CONF_ERROR;
1146 }
1147
1148 /* rc == NGX_BUSY */
1149
1150 old = (ngx_http_variable_value_t *)
1151 ngx_radix32tree_find(ctx->tree, cidr.u.in.addr);
1152
1153 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
1154 "duplicate network \"%V\", value: \"%v\", old value: \"%v\"",
1155 net, val, old);
1156
1157 rc = ngx_radix32tree_delete(ctx->tree,
1158 cidr.u.in.addr, cidr.u.in.mask);
1159
1160 if (rc == NGX_ERROR) {
1161 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid radix tree");
1162 return NGX_CONF_ERROR;
1163 }
1164 }
1165
1166 break;
10101167 }
10111168
10121169 return NGX_CONF_ERROR;