aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2011-07-21 06:06:18 -0400
committerPatrick McHardy <kaber@trash.net>2011-07-21 06:06:18 -0400
commit89dc79b787d20e4b6c4077dcee1c5b1be4ab55b8 (patch)
tree24ebd4da0fe7e239e45cbc5a4ec599ee1abba94d /include
parenta6a7b759ba62e62542308e091f7fc9cfac4f978e (diff)
netfilter: ipset: hash:net,iface fixed to handle overlapping nets behind different interfaces
If overlapping networks with different interfaces was added to the set, the type did not handle it properly. Example ipset create test hash:net,iface ipset add test 192.168.0.0/16,eth0 ipset add test 192.168.0.0/24,eth1 Now, if a packet was sent from 192.168.0.0/24,eth0, the type returned a match. In the patch the algorithm is fixed in order to correctly handle overlapping networks. Limitation: the same network cannot be stored with more than 64 different interfaces in a single set. Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'include')
-rw-r--r--include/linux/netfilter/ipset/ip_set_ahash.h92
1 files changed, 61 insertions, 31 deletions
diff --git a/include/linux/netfilter/ipset/ip_set_ahash.h b/include/linux/netfilter/ipset/ip_set_ahash.h
index 42b7d25a1b2e..1e7f7594cd02 100644
--- a/include/linux/netfilter/ipset/ip_set_ahash.h
+++ b/include/linux/netfilter/ipset/ip_set_ahash.h
@@ -28,7 +28,32 @@
28/* Number of elements to store in an initial array block */ 28/* Number of elements to store in an initial array block */
29#define AHASH_INIT_SIZE 4 29#define AHASH_INIT_SIZE 4
30/* Max number of elements to store in an array block */ 30/* Max number of elements to store in an array block */
31#define AHASH_MAX_SIZE (3*4) 31#define AHASH_MAX_SIZE (3*AHASH_INIT_SIZE)
32
33/* Max number of elements can be tuned */
34#ifdef IP_SET_HASH_WITH_MULTI
35#define AHASH_MAX(h) ((h)->ahash_max)
36
37static inline u8
38tune_ahash_max(u8 curr, u32 multi)
39{
40 u32 n;
41
42 if (multi < curr)
43 return curr;
44
45 n = curr + AHASH_INIT_SIZE;
46 /* Currently, at listing one hash bucket must fit into a message.
47 * Therefore we have a hard limit here.
48 */
49 return n > curr && n <= 64 ? n : curr;
50}
51#define TUNE_AHASH_MAX(h, multi) \
52 ((h)->ahash_max = tune_ahash_max((h)->ahash_max, multi))
53#else
54#define AHASH_MAX(h) AHASH_MAX_SIZE
55#define TUNE_AHASH_MAX(h, multi)
56#endif
32 57
33/* A hash bucket */ 58/* A hash bucket */
34struct hbucket { 59struct hbucket {
@@ -60,6 +85,9 @@ struct ip_set_hash {
60 u32 timeout; /* timeout value, if enabled */ 85 u32 timeout; /* timeout value, if enabled */
61 struct timer_list gc; /* garbage collection when timeout enabled */ 86 struct timer_list gc; /* garbage collection when timeout enabled */
62 struct type_pf_next next; /* temporary storage for uadd */ 87 struct type_pf_next next; /* temporary storage for uadd */
88#ifdef IP_SET_HASH_WITH_MULTI
89 u8 ahash_max; /* max elements in an array block */
90#endif
63#ifdef IP_SET_HASH_WITH_NETMASK 91#ifdef IP_SET_HASH_WITH_NETMASK
64 u8 netmask; /* netmask value for subnets to store */ 92 u8 netmask; /* netmask value for subnets to store */
65#endif 93#endif
@@ -279,12 +307,13 @@ ip_set_hash_destroy(struct ip_set *set)
279/* Add an element to the hash table when resizing the set: 307/* Add an element to the hash table when resizing the set:
280 * we spare the maintenance of the internal counters. */ 308 * we spare the maintenance of the internal counters. */
281static int 309static int
282type_pf_elem_add(struct hbucket *n, const struct type_pf_elem *value) 310type_pf_elem_add(struct hbucket *n, const struct type_pf_elem *value,
311 u8 ahash_max)
283{ 312{
284 if (n->pos >= n->size) { 313 if (n->pos >= n->size) {
285 void *tmp; 314 void *tmp;
286 315
287 if (n->size >= AHASH_MAX_SIZE) 316 if (n->size >= ahash_max)
288 /* Trigger rehashing */ 317 /* Trigger rehashing */
289 return -EAGAIN; 318 return -EAGAIN;
290 319
@@ -339,7 +368,7 @@ retry:
339 for (j = 0; j < n->pos; j++) { 368 for (j = 0; j < n->pos; j++) {
340 data = ahash_data(n, j); 369 data = ahash_data(n, j);
341 m = hbucket(t, HKEY(data, h->initval, htable_bits)); 370 m = hbucket(t, HKEY(data, h->initval, htable_bits));
342 ret = type_pf_elem_add(m, data); 371 ret = type_pf_elem_add(m, data, AHASH_MAX(h));
343 if (ret < 0) { 372 if (ret < 0) {
344 read_unlock_bh(&set->lock); 373 read_unlock_bh(&set->lock);
345 ahash_destroy(t); 374 ahash_destroy(t);
@@ -376,7 +405,7 @@ type_pf_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
376 const struct type_pf_elem *d = value; 405 const struct type_pf_elem *d = value;
377 struct hbucket *n; 406 struct hbucket *n;
378 int i, ret = 0; 407 int i, ret = 0;
379 u32 key; 408 u32 key, multi = 0;
380 409
381 if (h->elements >= h->maxelem) 410 if (h->elements >= h->maxelem)
382 return -IPSET_ERR_HASH_FULL; 411 return -IPSET_ERR_HASH_FULL;
@@ -386,12 +415,12 @@ type_pf_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
386 key = HKEY(value, h->initval, t->htable_bits); 415 key = HKEY(value, h->initval, t->htable_bits);
387 n = hbucket(t, key); 416 n = hbucket(t, key);
388 for (i = 0; i < n->pos; i++) 417 for (i = 0; i < n->pos; i++)
389 if (type_pf_data_equal(ahash_data(n, i), d)) { 418 if (type_pf_data_equal(ahash_data(n, i), d, &multi)) {
390 ret = -IPSET_ERR_EXIST; 419 ret = -IPSET_ERR_EXIST;
391 goto out; 420 goto out;
392 } 421 }
393 422 TUNE_AHASH_MAX(h, multi);
394 ret = type_pf_elem_add(n, value); 423 ret = type_pf_elem_add(n, value, AHASH_MAX(h));
395 if (ret != 0) { 424 if (ret != 0) {
396 if (ret == -EAGAIN) 425 if (ret == -EAGAIN)
397 type_pf_data_next(h, d); 426 type_pf_data_next(h, d);
@@ -419,13 +448,13 @@ type_pf_del(struct ip_set *set, void *value, u32 timeout, u32 flags)
419 struct hbucket *n; 448 struct hbucket *n;
420 int i; 449 int i;
421 struct type_pf_elem *data; 450 struct type_pf_elem *data;
422 u32 key; 451 u32 key, multi = 0;
423 452
424 key = HKEY(value, h->initval, t->htable_bits); 453 key = HKEY(value, h->initval, t->htable_bits);
425 n = hbucket(t, key); 454 n = hbucket(t, key);
426 for (i = 0; i < n->pos; i++) { 455 for (i = 0; i < n->pos; i++) {
427 data = ahash_data(n, i); 456 data = ahash_data(n, i);
428 if (!type_pf_data_equal(data, d)) 457 if (!type_pf_data_equal(data, d, &multi))
429 continue; 458 continue;
430 if (i != n->pos - 1) 459 if (i != n->pos - 1)
431 /* Not last one */ 460 /* Not last one */
@@ -466,17 +495,17 @@ type_pf_test_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout)
466 struct hbucket *n; 495 struct hbucket *n;
467 const struct type_pf_elem *data; 496 const struct type_pf_elem *data;
468 int i, j = 0; 497 int i, j = 0;
469 u32 key; 498 u32 key, multi = 0;
470 u8 host_mask = SET_HOST_MASK(set->family); 499 u8 host_mask = SET_HOST_MASK(set->family);
471 500
472 pr_debug("test by nets\n"); 501 pr_debug("test by nets\n");
473 for (; j < host_mask && h->nets[j].cidr; j++) { 502 for (; j < host_mask && h->nets[j].cidr && !multi; j++) {
474 type_pf_data_netmask(d, h->nets[j].cidr); 503 type_pf_data_netmask(d, h->nets[j].cidr);
475 key = HKEY(d, h->initval, t->htable_bits); 504 key = HKEY(d, h->initval, t->htable_bits);
476 n = hbucket(t, key); 505 n = hbucket(t, key);
477 for (i = 0; i < n->pos; i++) { 506 for (i = 0; i < n->pos; i++) {
478 data = ahash_data(n, i); 507 data = ahash_data(n, i);
479 if (type_pf_data_equal(data, d)) 508 if (type_pf_data_equal(data, d, &multi))
480 return 1; 509 return 1;
481 } 510 }
482 } 511 }
@@ -494,7 +523,7 @@ type_pf_test(struct ip_set *set, void *value, u32 timeout, u32 flags)
494 struct hbucket *n; 523 struct hbucket *n;
495 const struct type_pf_elem *data; 524 const struct type_pf_elem *data;
496 int i; 525 int i;
497 u32 key; 526 u32 key, multi = 0;
498 527
499#ifdef IP_SET_HASH_WITH_NETS 528#ifdef IP_SET_HASH_WITH_NETS
500 /* If we test an IP address and not a network address, 529 /* If we test an IP address and not a network address,
@@ -507,7 +536,7 @@ type_pf_test(struct ip_set *set, void *value, u32 timeout, u32 flags)
507 n = hbucket(t, key); 536 n = hbucket(t, key);
508 for (i = 0; i < n->pos; i++) { 537 for (i = 0; i < n->pos; i++) {
509 data = ahash_data(n, i); 538 data = ahash_data(n, i);
510 if (type_pf_data_equal(data, d)) 539 if (type_pf_data_equal(data, d, &multi))
511 return 1; 540 return 1;
512 } 541 }
513 return 0; 542 return 0;
@@ -664,14 +693,14 @@ type_pf_data_timeout_set(struct type_pf_elem *data, u32 timeout)
664 693
665static int 694static int
666type_pf_elem_tadd(struct hbucket *n, const struct type_pf_elem *value, 695type_pf_elem_tadd(struct hbucket *n, const struct type_pf_elem *value,
667 u32 timeout) 696 u8 ahash_max, u32 timeout)
668{ 697{
669 struct type_pf_elem *data; 698 struct type_pf_elem *data;
670 699
671 if (n->pos >= n->size) { 700 if (n->pos >= n->size) {
672 void *tmp; 701 void *tmp;
673 702
674 if (n->size >= AHASH_MAX_SIZE) 703 if (n->size >= ahash_max)
675 /* Trigger rehashing */ 704 /* Trigger rehashing */
676 return -EAGAIN; 705 return -EAGAIN;
677 706
@@ -776,7 +805,7 @@ retry:
776 for (j = 0; j < n->pos; j++) { 805 for (j = 0; j < n->pos; j++) {
777 data = ahash_tdata(n, j); 806 data = ahash_tdata(n, j);
778 m = hbucket(t, HKEY(data, h->initval, htable_bits)); 807 m = hbucket(t, HKEY(data, h->initval, htable_bits));
779 ret = type_pf_elem_tadd(m, data, 808 ret = type_pf_elem_tadd(m, data, AHASH_MAX(h),
780 type_pf_data_timeout(data)); 809 type_pf_data_timeout(data));
781 if (ret < 0) { 810 if (ret < 0) {
782 read_unlock_bh(&set->lock); 811 read_unlock_bh(&set->lock);
@@ -807,9 +836,9 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
807 const struct type_pf_elem *d = value; 836 const struct type_pf_elem *d = value;
808 struct hbucket *n; 837 struct hbucket *n;
809 struct type_pf_elem *data; 838 struct type_pf_elem *data;
810 int ret = 0, i, j = AHASH_MAX_SIZE + 1; 839 int ret = 0, i, j = AHASH_MAX(h) + 1;
811 bool flag_exist = flags & IPSET_FLAG_EXIST; 840 bool flag_exist = flags & IPSET_FLAG_EXIST;
812 u32 key; 841 u32 key, multi = 0;
813 842
814 if (h->elements >= h->maxelem) 843 if (h->elements >= h->maxelem)
815 /* FIXME: when set is full, we slow down here */ 844 /* FIXME: when set is full, we slow down here */
@@ -823,18 +852,18 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
823 n = hbucket(t, key); 852 n = hbucket(t, key);
824 for (i = 0; i < n->pos; i++) { 853 for (i = 0; i < n->pos; i++) {
825 data = ahash_tdata(n, i); 854 data = ahash_tdata(n, i);
826 if (type_pf_data_equal(data, d)) { 855 if (type_pf_data_equal(data, d, &multi)) {
827 if (type_pf_data_expired(data) || flag_exist) 856 if (type_pf_data_expired(data) || flag_exist)
828 j = i; 857 j = i;
829 else { 858 else {
830 ret = -IPSET_ERR_EXIST; 859 ret = -IPSET_ERR_EXIST;
831 goto out; 860 goto out;
832 } 861 }
833 } else if (j == AHASH_MAX_SIZE + 1 && 862 } else if (j == AHASH_MAX(h) + 1 &&
834 type_pf_data_expired(data)) 863 type_pf_data_expired(data))
835 j = i; 864 j = i;
836 } 865 }
837 if (j != AHASH_MAX_SIZE + 1) { 866 if (j != AHASH_MAX(h) + 1) {
838 data = ahash_tdata(n, j); 867 data = ahash_tdata(n, j);
839#ifdef IP_SET_HASH_WITH_NETS 868#ifdef IP_SET_HASH_WITH_NETS
840 del_cidr(h, data->cidr, HOST_MASK); 869 del_cidr(h, data->cidr, HOST_MASK);
@@ -844,7 +873,8 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
844 type_pf_data_timeout_set(data, timeout); 873 type_pf_data_timeout_set(data, timeout);
845 goto out; 874 goto out;
846 } 875 }
847 ret = type_pf_elem_tadd(n, d, timeout); 876 TUNE_AHASH_MAX(h, multi);
877 ret = type_pf_elem_tadd(n, d, AHASH_MAX(h), timeout);
848 if (ret != 0) { 878 if (ret != 0) {
849 if (ret == -EAGAIN) 879 if (ret == -EAGAIN)
850 type_pf_data_next(h, d); 880 type_pf_data_next(h, d);
@@ -869,13 +899,13 @@ type_pf_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
869 struct hbucket *n; 899 struct hbucket *n;
870 int i; 900 int i;
871 struct type_pf_elem *data; 901 struct type_pf_elem *data;
872 u32 key; 902 u32 key, multi = 0;
873 903
874 key = HKEY(value, h->initval, t->htable_bits); 904 key = HKEY(value, h->initval, t->htable_bits);
875 n = hbucket(t, key); 905 n = hbucket(t, key);
876 for (i = 0; i < n->pos; i++) { 906 for (i = 0; i < n->pos; i++) {
877 data = ahash_tdata(n, i); 907 data = ahash_tdata(n, i);
878 if (!type_pf_data_equal(data, d)) 908 if (!type_pf_data_equal(data, d, &multi))
879 continue; 909 continue;
880 if (type_pf_data_expired(data)) 910 if (type_pf_data_expired(data))
881 return -IPSET_ERR_EXIST; 911 return -IPSET_ERR_EXIST;
@@ -915,16 +945,16 @@ type_pf_ttest_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout)
915 struct type_pf_elem *data; 945 struct type_pf_elem *data;
916 struct hbucket *n; 946 struct hbucket *n;
917 int i, j = 0; 947 int i, j = 0;
918 u32 key; 948 u32 key, multi = 0;
919 u8 host_mask = SET_HOST_MASK(set->family); 949 u8 host_mask = SET_HOST_MASK(set->family);
920 950
921 for (; j < host_mask && h->nets[j].cidr; j++) { 951 for (; j < host_mask && h->nets[j].cidr && !multi; j++) {
922 type_pf_data_netmask(d, h->nets[j].cidr); 952 type_pf_data_netmask(d, h->nets[j].cidr);
923 key = HKEY(d, h->initval, t->htable_bits); 953 key = HKEY(d, h->initval, t->htable_bits);
924 n = hbucket(t, key); 954 n = hbucket(t, key);
925 for (i = 0; i < n->pos; i++) { 955 for (i = 0; i < n->pos; i++) {
926 data = ahash_tdata(n, i); 956 data = ahash_tdata(n, i);
927 if (type_pf_data_equal(data, d)) 957 if (type_pf_data_equal(data, d, &multi))
928 return !type_pf_data_expired(data); 958 return !type_pf_data_expired(data);
929 } 959 }
930 } 960 }
@@ -940,7 +970,7 @@ type_pf_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags)
940 struct type_pf_elem *data, *d = value; 970 struct type_pf_elem *data, *d = value;
941 struct hbucket *n; 971 struct hbucket *n;
942 int i; 972 int i;
943 u32 key; 973 u32 key, multi = 0;
944 974
945#ifdef IP_SET_HASH_WITH_NETS 975#ifdef IP_SET_HASH_WITH_NETS
946 if (d->cidr == SET_HOST_MASK(set->family)) 976 if (d->cidr == SET_HOST_MASK(set->family))
@@ -950,7 +980,7 @@ type_pf_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags)
950 n = hbucket(t, key); 980 n = hbucket(t, key);
951 for (i = 0; i < n->pos; i++) { 981 for (i = 0; i < n->pos; i++) {
952 data = ahash_tdata(n, i); 982 data = ahash_tdata(n, i);
953 if (type_pf_data_equal(data, d)) 983 if (type_pf_data_equal(data, d, &multi))
954 return !type_pf_data_expired(data); 984 return !type_pf_data_expired(data);
955 } 985 }
956 return 0; 986 return 0;