diff options
author | Jan Engelhardt <jengelh@computergmbh.de> | 2008-01-31 07:48:13 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-31 22:28:04 -0500 |
commit | 09e410def6432458c7d7e771a1807b157f4c2577 (patch) | |
tree | 409cb903573639d08b3dbe0418477a0ac6e87eee /net | |
parent | d33b7c06bd721e21534c120d1c4a5944dc3eb9ce (diff) |
[NETFILTER]: xt_hashlimit match, revision 1
Introduces the xt_hashlimit match revision 1. It adds support for
kernel-level inversion and grouping source and/or destination IP
addresses, allowing to limit on a per-subnet basis. While this would
technically obsolete xt_limit, xt_hashlimit is a more expensive due
to the hashbucketing.
Kernel-level inversion: Previously you had to do user-level inversion:
iptables -N foo
iptables -A foo -m hashlimit --hashlimit(-upto) 5/s -j RETURN
iptables -A foo -j DROP
iptables -A INPUT -j foo
now it is simpler:
iptables -A INPUT -m hashlimit --hashlimit-over 5/s -j DROP
Signed-off-by: Jan Engelhardt <jengelh@computergmbh.de>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/netfilter/xt_hashlimit.c | 322 |
1 files changed, 286 insertions, 36 deletions
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index b224b8f719a4..54aaf5bac2d7 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c | |||
@@ -1,9 +1,9 @@ | |||
1 | /* iptables match extension to limit the number of packets per second | 1 | /* |
2 | * seperately for each hashbucket (sourceip/sourceport/dstip/dstport) | 2 | * xt_hashlimit - Netfilter module to limit the number of packets per time |
3 | * seperately for each hashbucket (sourceip/sourceport/dstip/dstport) | ||
3 | * | 4 | * |
4 | * (C) 2003-2004 by Harald Welte <laforge@netfilter.org> | 5 | * (C) 2003-2004 by Harald Welte <laforge@netfilter.org> |
5 | * | 6 | * Copyright © CC Computer Consultants GmbH, 2007 - 2008 |
6 | * $Id: ipt_hashlimit.c 3244 2004-10-20 16:24:29Z laforge@netfilter.org $ | ||
7 | * | 7 | * |
8 | * Development of this code was funded by Astaro AG, http://www.astaro.com/ | 8 | * Development of this code was funded by Astaro AG, http://www.astaro.com/ |
9 | */ | 9 | */ |
@@ -35,6 +35,7 @@ | |||
35 | 35 | ||
36 | MODULE_LICENSE("GPL"); | 36 | MODULE_LICENSE("GPL"); |
37 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | 37 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); |
38 | MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>"); | ||
38 | MODULE_DESCRIPTION("Xtables: per hash-bucket rate-limit match"); | 39 | MODULE_DESCRIPTION("Xtables: per hash-bucket rate-limit match"); |
39 | MODULE_ALIAS("ipt_hashlimit"); | 40 | MODULE_ALIAS("ipt_hashlimit"); |
40 | MODULE_ALIAS("ip6t_hashlimit"); | 41 | MODULE_ALIAS("ip6t_hashlimit"); |
@@ -57,7 +58,7 @@ struct dsthash_dst { | |||
57 | __be32 dst[4]; | 58 | __be32 dst[4]; |
58 | } ip6; | 59 | } ip6; |
59 | #endif | 60 | #endif |
60 | } addr; | 61 | }; |
61 | __be16 src_port; | 62 | __be16 src_port; |
62 | __be16 dst_port; | 63 | __be16 dst_port; |
63 | }; | 64 | }; |
@@ -81,7 +82,7 @@ struct xt_hashlimit_htable { | |||
81 | atomic_t use; | 82 | atomic_t use; |
82 | int family; | 83 | int family; |
83 | 84 | ||
84 | struct hashlimit_cfg cfg; /* config */ | 85 | struct hashlimit_cfg1 cfg; /* config */ |
85 | 86 | ||
86 | /* used internally */ | 87 | /* used internally */ |
87 | spinlock_t lock; /* lock for list_head */ | 88 | spinlock_t lock; /* lock for list_head */ |
@@ -184,7 +185,7 @@ dsthash_free(struct xt_hashlimit_htable *ht, struct dsthash_ent *ent) | |||
184 | } | 185 | } |
185 | static void htable_gc(unsigned long htlong); | 186 | static void htable_gc(unsigned long htlong); |
186 | 187 | ||
187 | static int htable_create(struct xt_hashlimit_info *minfo, int family) | 188 | static int htable_create_v0(struct xt_hashlimit_info *minfo, int family) |
188 | { | 189 | { |
189 | struct xt_hashlimit_htable *hinfo; | 190 | struct xt_hashlimit_htable *hinfo; |
190 | unsigned int size; | 191 | unsigned int size; |
@@ -210,7 +211,18 @@ static int htable_create(struct xt_hashlimit_info *minfo, int family) | |||
210 | minfo->hinfo = hinfo; | 211 | minfo->hinfo = hinfo; |
211 | 212 | ||
212 | /* copy match config into hashtable config */ | 213 | /* copy match config into hashtable config */ |
213 | memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg)); | 214 | hinfo->cfg.mode = minfo->cfg.mode; |
215 | hinfo->cfg.avg = minfo->cfg.avg; | ||
216 | hinfo->cfg.burst = minfo->cfg.burst; | ||
217 | hinfo->cfg.max = minfo->cfg.max; | ||
218 | hinfo->cfg.gc_interval = minfo->cfg.gc_interval; | ||
219 | hinfo->cfg.expire = minfo->cfg.expire; | ||
220 | |||
221 | if (family == AF_INET) | ||
222 | hinfo->cfg.srcmask = hinfo->cfg.dstmask = 32; | ||
223 | else | ||
224 | hinfo->cfg.srcmask = hinfo->cfg.dstmask = 128; | ||
225 | |||
214 | hinfo->cfg.size = size; | 226 | hinfo->cfg.size = size; |
215 | if (!hinfo->cfg.max) | 227 | if (!hinfo->cfg.max) |
216 | hinfo->cfg.max = 8 * hinfo->cfg.size; | 228 | hinfo->cfg.max = 8 * hinfo->cfg.size; |
@@ -246,6 +258,70 @@ static int htable_create(struct xt_hashlimit_info *minfo, int family) | |||
246 | return 0; | 258 | return 0; |
247 | } | 259 | } |
248 | 260 | ||
261 | static int htable_create(struct xt_hashlimit_mtinfo1 *minfo, | ||
262 | unsigned int family) | ||
263 | { | ||
264 | struct xt_hashlimit_htable *hinfo; | ||
265 | unsigned int size; | ||
266 | unsigned int i; | ||
267 | |||
268 | if (minfo->cfg.size) { | ||
269 | size = minfo->cfg.size; | ||
270 | } else { | ||
271 | size = (num_physpages << PAGE_SHIFT) / 16384 / | ||
272 | sizeof(struct list_head); | ||
273 | if (num_physpages > 1024 * 1024 * 1024 / PAGE_SIZE) | ||
274 | size = 8192; | ||
275 | if (size < 16) | ||
276 | size = 16; | ||
277 | } | ||
278 | /* FIXME: don't use vmalloc() here or anywhere else -HW */ | ||
279 | hinfo = vmalloc(sizeof(struct xt_hashlimit_htable) + | ||
280 | sizeof(struct list_head) * size); | ||
281 | if (hinfo == NULL) { | ||
282 | printk(KERN_ERR "xt_hashlimit: unable to create hashtable\n"); | ||
283 | return -1; | ||
284 | } | ||
285 | minfo->hinfo = hinfo; | ||
286 | |||
287 | /* copy match config into hashtable config */ | ||
288 | memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg)); | ||
289 | hinfo->cfg.size = size; | ||
290 | if (hinfo->cfg.max == 0) | ||
291 | hinfo->cfg.max = 8 * hinfo->cfg.size; | ||
292 | else if (hinfo->cfg.max < hinfo->cfg.size) | ||
293 | hinfo->cfg.max = hinfo->cfg.size; | ||
294 | |||
295 | for (i = 0; i < hinfo->cfg.size; i++) | ||
296 | INIT_HLIST_HEAD(&hinfo->hash[i]); | ||
297 | |||
298 | atomic_set(&hinfo->use, 1); | ||
299 | hinfo->count = 0; | ||
300 | hinfo->family = family; | ||
301 | hinfo->rnd_initialized = 0; | ||
302 | spin_lock_init(&hinfo->lock); | ||
303 | |||
304 | hinfo->pde = create_proc_entry(minfo->name, 0, | ||
305 | family == AF_INET ? hashlimit_procdir4 : | ||
306 | hashlimit_procdir6); | ||
307 | if (hinfo->pde == NULL) { | ||
308 | vfree(hinfo); | ||
309 | return -1; | ||
310 | } | ||
311 | hinfo->pde->proc_fops = &dl_file_ops; | ||
312 | hinfo->pde->data = hinfo; | ||
313 | |||
314 | setup_timer(&hinfo->timer, htable_gc, (unsigned long)hinfo); | ||
315 | hinfo->timer.expires = jiffies + msecs_to_jiffies(hinfo->cfg.gc_interval); | ||
316 | add_timer(&hinfo->timer); | ||
317 | |||
318 | spin_lock_bh(&hashlimit_lock); | ||
319 | hlist_add_head(&hinfo->node, &hashlimit_htables); | ||
320 | spin_unlock_bh(&hashlimit_lock); | ||
321 | |||
322 | return 0; | ||
323 | } | ||
324 | |||
249 | static bool select_all(const struct xt_hashlimit_htable *ht, | 325 | static bool select_all(const struct xt_hashlimit_htable *ht, |
250 | const struct dsthash_ent *he) | 326 | const struct dsthash_ent *he) |
251 | { | 327 | { |
@@ -388,6 +464,46 @@ static inline void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now) | |||
388 | dh->rateinfo.prev = now; | 464 | dh->rateinfo.prev = now; |
389 | } | 465 | } |
390 | 466 | ||
467 | static inline __be32 maskl(__be32 a, unsigned int l) | ||
468 | { | ||
469 | return htonl(ntohl(a) & ~(~(u_int32_t)0 >> l)); | ||
470 | } | ||
471 | |||
472 | static void hashlimit_ipv6_mask(__be32 *i, unsigned int p) | ||
473 | { | ||
474 | switch (p) { | ||
475 | case 0: | ||
476 | i[0] = i[1] = 0; | ||
477 | i[2] = i[3] = 0; | ||
478 | break; | ||
479 | case 1 ... 31: | ||
480 | i[0] = maskl(i[0], p); | ||
481 | i[1] = i[2] = i[3] = 0; | ||
482 | break; | ||
483 | case 32: | ||
484 | i[1] = i[2] = i[3] = 0; | ||
485 | break; | ||
486 | case 33 ... 63: | ||
487 | i[1] = maskl(i[1], p - 32); | ||
488 | i[2] = i[3] = 0; | ||
489 | break; | ||
490 | case 64: | ||
491 | i[2] = i[3] = 0; | ||
492 | break; | ||
493 | case 65 ... 95: | ||
494 | i[2] = maskl(i[2], p - 64); | ||
495 | i[3] = 0; | ||
496 | case 96: | ||
497 | i[3] = 0; | ||
498 | break; | ||
499 | case 97 ... 127: | ||
500 | i[3] = maskl(i[3], p - 96); | ||
501 | break; | ||
502 | case 128: | ||
503 | break; | ||
504 | } | ||
505 | } | ||
506 | |||
391 | static int | 507 | static int |
392 | hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo, | 508 | hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo, |
393 | struct dsthash_dst *dst, | 509 | struct dsthash_dst *dst, |
@@ -401,9 +517,11 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo, | |||
401 | switch (hinfo->family) { | 517 | switch (hinfo->family) { |
402 | case AF_INET: | 518 | case AF_INET: |
403 | if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DIP) | 519 | if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DIP) |
404 | dst->addr.ip.dst = ip_hdr(skb)->daddr; | 520 | dst->ip.dst = maskl(ip_hdr(skb)->daddr, |
521 | hinfo->cfg.dstmask); | ||
405 | if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_SIP) | 522 | if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_SIP) |
406 | dst->addr.ip.src = ip_hdr(skb)->saddr; | 523 | dst->ip.src = maskl(ip_hdr(skb)->saddr, |
524 | hinfo->cfg.srcmask); | ||
407 | 525 | ||
408 | if (!(hinfo->cfg.mode & | 526 | if (!(hinfo->cfg.mode & |
409 | (XT_HASHLIMIT_HASH_DPT | XT_HASHLIMIT_HASH_SPT))) | 527 | (XT_HASHLIMIT_HASH_DPT | XT_HASHLIMIT_HASH_SPT))) |
@@ -412,12 +530,16 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo, | |||
412 | break; | 530 | break; |
413 | #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) | 531 | #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) |
414 | case AF_INET6: | 532 | case AF_INET6: |
415 | if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DIP) | 533 | if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DIP) { |
416 | memcpy(&dst->addr.ip6.dst, &ipv6_hdr(skb)->daddr, | 534 | memcpy(&dst->ip6.dst, &ipv6_hdr(skb)->daddr, |
417 | sizeof(dst->addr.ip6.dst)); | 535 | sizeof(dst->ip6.dst)); |
418 | if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_SIP) | 536 | hashlimit_ipv6_mask(dst->ip6.dst, hinfo->cfg.dstmask); |
419 | memcpy(&dst->addr.ip6.src, &ipv6_hdr(skb)->saddr, | 537 | } |
420 | sizeof(dst->addr.ip6.src)); | 538 | if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_SIP) { |
539 | memcpy(&dst->ip6.src, &ipv6_hdr(skb)->saddr, | ||
540 | sizeof(dst->ip6.src)); | ||
541 | hashlimit_ipv6_mask(dst->ip6.src, hinfo->cfg.srcmask); | ||
542 | } | ||
421 | 543 | ||
422 | if (!(hinfo->cfg.mode & | 544 | if (!(hinfo->cfg.mode & |
423 | (XT_HASHLIMIT_HASH_DPT | XT_HASHLIMIT_HASH_SPT))) | 545 | (XT_HASHLIMIT_HASH_DPT | XT_HASHLIMIT_HASH_SPT))) |
@@ -457,10 +579,10 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo, | |||
457 | } | 579 | } |
458 | 580 | ||
459 | static bool | 581 | static bool |
460 | hashlimit_mt(const struct sk_buff *skb, const struct net_device *in, | 582 | hashlimit_mt_v0(const struct sk_buff *skb, const struct net_device *in, |
461 | const struct net_device *out, const struct xt_match *match, | 583 | const struct net_device *out, const struct xt_match *match, |
462 | const void *matchinfo, int offset, unsigned int protoff, | 584 | const void *matchinfo, int offset, unsigned int protoff, |
463 | bool *hotdrop) | 585 | bool *hotdrop) |
464 | { | 586 | { |
465 | const struct xt_hashlimit_info *r = | 587 | const struct xt_hashlimit_info *r = |
466 | ((const struct xt_hashlimit_info *)matchinfo)->u.master; | 588 | ((const struct xt_hashlimit_info *)matchinfo)->u.master; |
@@ -512,9 +634,62 @@ hotdrop: | |||
512 | } | 634 | } |
513 | 635 | ||
514 | static bool | 636 | static bool |
515 | hashlimit_mt_check(const char *tablename, const void *inf, | 637 | hashlimit_mt(const struct sk_buff *skb, const struct net_device *in, |
516 | const struct xt_match *match, void *matchinfo, | 638 | const struct net_device *out, const struct xt_match *match, |
517 | unsigned int hook_mask) | 639 | const void *matchinfo, int offset, unsigned int protoff, |
640 | bool *hotdrop) | ||
641 | { | ||
642 | const struct xt_hashlimit_mtinfo1 *info = matchinfo; | ||
643 | struct xt_hashlimit_htable *hinfo = info->hinfo; | ||
644 | unsigned long now = jiffies; | ||
645 | struct dsthash_ent *dh; | ||
646 | struct dsthash_dst dst; | ||
647 | |||
648 | if (hashlimit_init_dst(hinfo, &dst, skb, protoff) < 0) | ||
649 | goto hotdrop; | ||
650 | |||
651 | spin_lock_bh(&hinfo->lock); | ||
652 | dh = dsthash_find(hinfo, &dst); | ||
653 | if (dh == NULL) { | ||
654 | dh = dsthash_alloc_init(hinfo, &dst); | ||
655 | if (dh == NULL) { | ||
656 | spin_unlock_bh(&hinfo->lock); | ||
657 | goto hotdrop; | ||
658 | } | ||
659 | |||
660 | dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire); | ||
661 | dh->rateinfo.prev = jiffies; | ||
662 | dh->rateinfo.credit = user2credits(hinfo->cfg.avg * | ||
663 | hinfo->cfg.burst); | ||
664 | dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg * | ||
665 | hinfo->cfg.burst); | ||
666 | dh->rateinfo.cost = user2credits(hinfo->cfg.avg); | ||
667 | } else { | ||
668 | /* update expiration timeout */ | ||
669 | dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire); | ||
670 | rateinfo_recalc(dh, now); | ||
671 | } | ||
672 | |||
673 | if (dh->rateinfo.credit >= dh->rateinfo.cost) { | ||
674 | /* below the limit */ | ||
675 | dh->rateinfo.credit -= dh->rateinfo.cost; | ||
676 | spin_unlock_bh(&hinfo->lock); | ||
677 | return !(info->cfg.mode & XT_HASHLIMIT_INVERT); | ||
678 | } | ||
679 | |||
680 | spin_unlock_bh(&hinfo->lock); | ||
681 | /* default match is underlimit - so over the limit, we need to invert */ | ||
682 | return info->cfg.mode & XT_HASHLIMIT_INVERT; | ||
683 | |||
684 | hotdrop: | ||
685 | *hotdrop = true; | ||
686 | return false; | ||
687 | } | ||
688 | |||
689 | static bool | ||
690 | hashlimit_mt_check_v0(const char *tablename, const void *inf, | ||
691 | const struct xt_match *match, void *matchinfo, | ||
692 | unsigned int hook_mask) | ||
518 | { | 693 | { |
519 | struct xt_hashlimit_info *r = matchinfo; | 694 | struct xt_hashlimit_info *r = matchinfo; |
520 | 695 | ||
@@ -546,7 +721,7 @@ hashlimit_mt_check(const char *tablename, const void *inf, | |||
546 | * create duplicate proc files. -HW */ | 721 | * create duplicate proc files. -HW */ |
547 | mutex_lock(&hlimit_mutex); | 722 | mutex_lock(&hlimit_mutex); |
548 | r->hinfo = htable_find_get(r->name, match->family); | 723 | r->hinfo = htable_find_get(r->name, match->family); |
549 | if (!r->hinfo && htable_create(r, match->family) != 0) { | 724 | if (!r->hinfo && htable_create_v0(r, match->family) != 0) { |
550 | mutex_unlock(&hlimit_mutex); | 725 | mutex_unlock(&hlimit_mutex); |
551 | return false; | 726 | return false; |
552 | } | 727 | } |
@@ -557,14 +732,68 @@ hashlimit_mt_check(const char *tablename, const void *inf, | |||
557 | return true; | 732 | return true; |
558 | } | 733 | } |
559 | 734 | ||
735 | static bool | ||
736 | hashlimit_mt_check(const char *tablename, const void *inf, | ||
737 | const struct xt_match *match, void *matchinfo, | ||
738 | unsigned int hook_mask) | ||
739 | { | ||
740 | struct xt_hashlimit_mtinfo1 *info = matchinfo; | ||
741 | |||
742 | /* Check for overflow. */ | ||
743 | if (info->cfg.burst == 0 || | ||
744 | user2credits(info->cfg.avg * info->cfg.burst) < | ||
745 | user2credits(info->cfg.avg)) { | ||
746 | printk(KERN_ERR "xt_hashlimit: overflow, try lower: %u/%u\n", | ||
747 | info->cfg.avg, info->cfg.burst); | ||
748 | return false; | ||
749 | } | ||
750 | if (info->cfg.gc_interval == 0 || info->cfg.expire == 0) | ||
751 | return false; | ||
752 | if (info->name[sizeof(info->name)-1] != '\0') | ||
753 | return false; | ||
754 | if (match->family == AF_INET) { | ||
755 | if (info->cfg.srcmask > 32 || info->cfg.dstmask > 32) | ||
756 | return false; | ||
757 | } else { | ||
758 | if (info->cfg.srcmask > 128 || info->cfg.dstmask > 128) | ||
759 | return false; | ||
760 | } | ||
761 | |||
762 | /* This is the best we've got: We cannot release and re-grab lock, | ||
763 | * since checkentry() is called before x_tables.c grabs xt_mutex. | ||
764 | * We also cannot grab the hashtable spinlock, since htable_create will | ||
765 | * call vmalloc, and that can sleep. And we cannot just re-search | ||
766 | * the list of htable's in htable_create(), since then we would | ||
767 | * create duplicate proc files. -HW */ | ||
768 | mutex_lock(&hlimit_mutex); | ||
769 | info->hinfo = htable_find_get(info->name, match->family); | ||
770 | if (!info->hinfo && htable_create(info, match->family) != 0) { | ||
771 | mutex_unlock(&hlimit_mutex); | ||
772 | return false; | ||
773 | } | ||
774 | mutex_unlock(&hlimit_mutex); | ||
775 | |||
776 | /* Ugly hack: For SMP, we only want to use one set */ | ||
777 | info->master = info; | ||
778 | return true; | ||
779 | } | ||
780 | |||
560 | static void | 781 | static void |
561 | hashlimit_mt_destroy(const struct xt_match *match, void *matchinfo) | 782 | hashlimit_mt_destroy_v0(const struct xt_match *match, void *matchinfo) |
562 | { | 783 | { |
563 | const struct xt_hashlimit_info *r = matchinfo; | 784 | const struct xt_hashlimit_info *r = matchinfo; |
564 | 785 | ||
565 | htable_put(r->hinfo); | 786 | htable_put(r->hinfo); |
566 | } | 787 | } |
567 | 788 | ||
789 | static void | ||
790 | hashlimit_mt_destroy(const struct xt_match *match, void *matchinfo) | ||
791 | { | ||
792 | const struct xt_hashlimit_mtinfo1 *info = matchinfo; | ||
793 | |||
794 | htable_put(info->hinfo); | ||
795 | } | ||
796 | |||
568 | #ifdef CONFIG_COMPAT | 797 | #ifdef CONFIG_COMPAT |
569 | struct compat_xt_hashlimit_info { | 798 | struct compat_xt_hashlimit_info { |
570 | char name[IFNAMSIZ]; | 799 | char name[IFNAMSIZ]; |
@@ -592,33 +821,54 @@ static int hashlimit_mt_compat_to_user(void __user *dst, void *src) | |||
592 | static struct xt_match hashlimit_mt_reg[] __read_mostly = { | 821 | static struct xt_match hashlimit_mt_reg[] __read_mostly = { |
593 | { | 822 | { |
594 | .name = "hashlimit", | 823 | .name = "hashlimit", |
824 | .revision = 0, | ||
595 | .family = AF_INET, | 825 | .family = AF_INET, |
596 | .match = hashlimit_mt, | 826 | .match = hashlimit_mt_v0, |
597 | .matchsize = sizeof(struct xt_hashlimit_info), | 827 | .matchsize = sizeof(struct xt_hashlimit_info), |
598 | #ifdef CONFIG_COMPAT | 828 | #ifdef CONFIG_COMPAT |
599 | .compatsize = sizeof(struct compat_xt_hashlimit_info), | 829 | .compatsize = sizeof(struct compat_xt_hashlimit_info), |
600 | .compat_from_user = hashlimit_mt_compat_from_user, | 830 | .compat_from_user = hashlimit_mt_compat_from_user, |
601 | .compat_to_user = hashlimit_mt_compat_to_user, | 831 | .compat_to_user = hashlimit_mt_compat_to_user, |
602 | #endif | 832 | #endif |
603 | .checkentry = hashlimit_mt_check, | 833 | .checkentry = hashlimit_mt_check_v0, |
604 | .destroy = hashlimit_mt_destroy, | 834 | .destroy = hashlimit_mt_destroy_v0, |
605 | .me = THIS_MODULE | 835 | .me = THIS_MODULE |
606 | }, | 836 | }, |
837 | { | ||
838 | .name = "hashlimit", | ||
839 | .revision = 1, | ||
840 | .family = AF_INET, | ||
841 | .match = hashlimit_mt, | ||
842 | .matchsize = sizeof(struct xt_hashlimit_mtinfo1), | ||
843 | .checkentry = hashlimit_mt_check, | ||
844 | .destroy = hashlimit_mt_destroy, | ||
845 | .me = THIS_MODULE, | ||
846 | }, | ||
607 | #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) | 847 | #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) |
608 | { | 848 | { |
609 | .name = "hashlimit", | 849 | .name = "hashlimit", |
610 | .family = AF_INET6, | 850 | .family = AF_INET6, |
611 | .match = hashlimit_mt, | 851 | .match = hashlimit_mt_v0, |
612 | .matchsize = sizeof(struct xt_hashlimit_info), | 852 | .matchsize = sizeof(struct xt_hashlimit_info), |
613 | #ifdef CONFIG_COMPAT | 853 | #ifdef CONFIG_COMPAT |
614 | .compatsize = sizeof(struct compat_xt_hashlimit_info), | 854 | .compatsize = sizeof(struct compat_xt_hashlimit_info), |
615 | .compat_from_user = hashlimit_mt_compat_from_user, | 855 | .compat_from_user = hashlimit_mt_compat_from_user, |
616 | .compat_to_user = hashlimit_mt_compat_to_user, | 856 | .compat_to_user = hashlimit_mt_compat_to_user, |
617 | #endif | 857 | #endif |
618 | .checkentry = hashlimit_mt_check, | 858 | .checkentry = hashlimit_mt_check_v0, |
619 | .destroy = hashlimit_mt_destroy, | 859 | .destroy = hashlimit_mt_destroy_v0, |
620 | .me = THIS_MODULE | 860 | .me = THIS_MODULE |
621 | }, | 861 | }, |
862 | { | ||
863 | .name = "hashlimit", | ||
864 | .revision = 1, | ||
865 | .family = AF_INET6, | ||
866 | .match = hashlimit_mt, | ||
867 | .matchsize = sizeof(struct xt_hashlimit_mtinfo1), | ||
868 | .checkentry = hashlimit_mt_check, | ||
869 | .destroy = hashlimit_mt_destroy, | ||
870 | .me = THIS_MODULE, | ||
871 | }, | ||
622 | #endif | 872 | #endif |
623 | }; | 873 | }; |
624 | 874 | ||
@@ -678,9 +928,9 @@ static int dl_seq_real_show(struct dsthash_ent *ent, int family, | |||
678 | return seq_printf(s, "%ld %u.%u.%u.%u:%u->" | 928 | return seq_printf(s, "%ld %u.%u.%u.%u:%u->" |
679 | "%u.%u.%u.%u:%u %u %u %u\n", | 929 | "%u.%u.%u.%u:%u %u %u %u\n", |
680 | (long)(ent->expires - jiffies)/HZ, | 930 | (long)(ent->expires - jiffies)/HZ, |
681 | NIPQUAD(ent->dst.addr.ip.src), | 931 | NIPQUAD(ent->dst.ip.src), |
682 | ntohs(ent->dst.src_port), | 932 | ntohs(ent->dst.src_port), |
683 | NIPQUAD(ent->dst.addr.ip.dst), | 933 | NIPQUAD(ent->dst.ip.dst), |
684 | ntohs(ent->dst.dst_port), | 934 | ntohs(ent->dst.dst_port), |
685 | ent->rateinfo.credit, ent->rateinfo.credit_cap, | 935 | ent->rateinfo.credit, ent->rateinfo.credit_cap, |
686 | ent->rateinfo.cost); | 936 | ent->rateinfo.cost); |
@@ -689,9 +939,9 @@ static int dl_seq_real_show(struct dsthash_ent *ent, int family, | |||
689 | return seq_printf(s, "%ld " NIP6_FMT ":%u->" | 939 | return seq_printf(s, "%ld " NIP6_FMT ":%u->" |
690 | NIP6_FMT ":%u %u %u %u\n", | 940 | NIP6_FMT ":%u %u %u %u\n", |
691 | (long)(ent->expires - jiffies)/HZ, | 941 | (long)(ent->expires - jiffies)/HZ, |
692 | NIP6(*(struct in6_addr *)&ent->dst.addr.ip6.src), | 942 | NIP6(*(struct in6_addr *)&ent->dst.ip6.src), |
693 | ntohs(ent->dst.src_port), | 943 | ntohs(ent->dst.src_port), |
694 | NIP6(*(struct in6_addr *)&ent->dst.addr.ip6.dst), | 944 | NIP6(*(struct in6_addr *)&ent->dst.ip6.dst), |
695 | ntohs(ent->dst.dst_port), | 945 | ntohs(ent->dst.dst_port), |
696 | ent->rateinfo.credit, ent->rateinfo.credit_cap, | 946 | ent->rateinfo.credit, ent->rateinfo.credit_cap, |
697 | ent->rateinfo.cost); | 947 | ent->rateinfo.cost); |