diff options
-rw-r--r-- | include/uapi/linux/netfilter/xt_hashlimit.h | 23 | ||||
-rw-r--r-- | net/netfilter/xt_hashlimit.c | 330 |
2 files changed, 285 insertions, 68 deletions
diff --git a/include/uapi/linux/netfilter/xt_hashlimit.h b/include/uapi/linux/netfilter/xt_hashlimit.h index 6db90372f09c..3efc0ca18345 100644 --- a/include/uapi/linux/netfilter/xt_hashlimit.h +++ b/include/uapi/linux/netfilter/xt_hashlimit.h | |||
@@ -6,6 +6,7 @@ | |||
6 | 6 | ||
7 | /* timings are in milliseconds. */ | 7 | /* timings are in milliseconds. */ |
8 | #define XT_HASHLIMIT_SCALE 10000 | 8 | #define XT_HASHLIMIT_SCALE 10000 |
9 | #define XT_HASHLIMIT_SCALE_v2 1000000llu | ||
9 | /* 1/10,000 sec period => max of 10,000/sec. Min rate is then 429490 | 10 | /* 1/10,000 sec period => max of 10,000/sec. Min rate is then 429490 |
10 | * seconds, or one packet every 59 hours. | 11 | * seconds, or one packet every 59 hours. |
11 | */ | 12 | */ |
@@ -63,6 +64,20 @@ struct hashlimit_cfg1 { | |||
63 | __u8 srcmask, dstmask; | 64 | __u8 srcmask, dstmask; |
64 | }; | 65 | }; |
65 | 66 | ||
67 | struct hashlimit_cfg2 { | ||
68 | __u64 avg; /* Average secs between packets * scale */ | ||
69 | __u64 burst; /* Period multiplier for upper limit. */ | ||
70 | __u32 mode; /* bitmask of XT_HASHLIMIT_HASH_* */ | ||
71 | |||
72 | /* user specified */ | ||
73 | __u32 size; /* how many buckets */ | ||
74 | __u32 max; /* max number of entries */ | ||
75 | __u32 gc_interval; /* gc interval */ | ||
76 | __u32 expire; /* when do entries expire? */ | ||
77 | |||
78 | __u8 srcmask, dstmask; | ||
79 | }; | ||
80 | |||
66 | struct xt_hashlimit_mtinfo1 { | 81 | struct xt_hashlimit_mtinfo1 { |
67 | char name[IFNAMSIZ]; | 82 | char name[IFNAMSIZ]; |
68 | struct hashlimit_cfg1 cfg; | 83 | struct hashlimit_cfg1 cfg; |
@@ -71,4 +86,12 @@ struct xt_hashlimit_mtinfo1 { | |||
71 | struct xt_hashlimit_htable *hinfo __attribute__((aligned(8))); | 86 | struct xt_hashlimit_htable *hinfo __attribute__((aligned(8))); |
72 | }; | 87 | }; |
73 | 88 | ||
89 | struct xt_hashlimit_mtinfo2 { | ||
90 | char name[NAME_MAX]; | ||
91 | struct hashlimit_cfg2 cfg; | ||
92 | |||
93 | /* Used internally by the kernel */ | ||
94 | struct xt_hashlimit_htable *hinfo __attribute__((aligned(8))); | ||
95 | }; | ||
96 | |||
74 | #endif /* _UAPI_XT_HASHLIMIT_H */ | 97 | #endif /* _UAPI_XT_HASHLIMIT_H */ |
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index e93d9e0a3f35..44a095ecc7b7 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c | |||
@@ -57,6 +57,7 @@ static inline struct hashlimit_net *hashlimit_pernet(struct net *net) | |||
57 | 57 | ||
58 | /* need to declare this at the top */ | 58 | /* need to declare this at the top */ |
59 | static const struct file_operations dl_file_ops_v1; | 59 | static const struct file_operations dl_file_ops_v1; |
60 | static const struct file_operations dl_file_ops; | ||
60 | 61 | ||
61 | /* hash table crap */ | 62 | /* hash table crap */ |
62 | struct dsthash_dst { | 63 | struct dsthash_dst { |
@@ -86,8 +87,8 @@ struct dsthash_ent { | |||
86 | unsigned long expires; /* precalculated expiry time */ | 87 | unsigned long expires; /* precalculated expiry time */ |
87 | struct { | 88 | struct { |
88 | unsigned long prev; /* last modification */ | 89 | unsigned long prev; /* last modification */ |
89 | u_int32_t credit; | 90 | u_int64_t credit; |
90 | u_int32_t credit_cap, cost; | 91 | u_int64_t credit_cap, cost; |
91 | } rateinfo; | 92 | } rateinfo; |
92 | struct rcu_head rcu; | 93 | struct rcu_head rcu; |
93 | }; | 94 | }; |
@@ -98,7 +99,7 @@ struct xt_hashlimit_htable { | |||
98 | u_int8_t family; | 99 | u_int8_t family; |
99 | bool rnd_initialized; | 100 | bool rnd_initialized; |
100 | 101 | ||
101 | struct hashlimit_cfg1 cfg; /* config */ | 102 | struct hashlimit_cfg2 cfg; /* config */ |
102 | 103 | ||
103 | /* used internally */ | 104 | /* used internally */ |
104 | spinlock_t lock; /* lock for list_head */ | 105 | spinlock_t lock; /* lock for list_head */ |
@@ -114,6 +115,30 @@ struct xt_hashlimit_htable { | |||
114 | struct hlist_head hash[0]; /* hashtable itself */ | 115 | struct hlist_head hash[0]; /* hashtable itself */ |
115 | }; | 116 | }; |
116 | 117 | ||
118 | static int | ||
119 | cfg_copy(struct hashlimit_cfg2 *to, void *from, int revision) | ||
120 | { | ||
121 | if (revision == 1) { | ||
122 | struct hashlimit_cfg1 *cfg = (struct hashlimit_cfg1 *)from; | ||
123 | |||
124 | to->mode = cfg->mode; | ||
125 | to->avg = cfg->avg; | ||
126 | to->burst = cfg->burst; | ||
127 | to->size = cfg->size; | ||
128 | to->max = cfg->max; | ||
129 | to->gc_interval = cfg->gc_interval; | ||
130 | to->expire = cfg->expire; | ||
131 | to->srcmask = cfg->srcmask; | ||
132 | to->dstmask = cfg->dstmask; | ||
133 | } else if (revision == 2) { | ||
134 | memcpy(to, from, sizeof(struct hashlimit_cfg2)); | ||
135 | } else { | ||
136 | return -EINVAL; | ||
137 | } | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
117 | static DEFINE_MUTEX(hashlimit_mutex); /* protects htables list */ | 142 | static DEFINE_MUTEX(hashlimit_mutex); /* protects htables list */ |
118 | static struct kmem_cache *hashlimit_cachep __read_mostly; | 143 | static struct kmem_cache *hashlimit_cachep __read_mostly; |
119 | 144 | ||
@@ -215,16 +240,18 @@ dsthash_free(struct xt_hashlimit_htable *ht, struct dsthash_ent *ent) | |||
215 | } | 240 | } |
216 | static void htable_gc(struct work_struct *work); | 241 | static void htable_gc(struct work_struct *work); |
217 | 242 | ||
218 | static int htable_create_v1(struct net *net, struct xt_hashlimit_mtinfo1 *minfo, | 243 | static int htable_create(struct net *net, struct hashlimit_cfg2 *cfg, |
219 | u_int8_t family) | 244 | const char *name, u_int8_t family, |
245 | struct xt_hashlimit_htable **out_hinfo, | ||
246 | int revision) | ||
220 | { | 247 | { |
221 | struct hashlimit_net *hashlimit_net = hashlimit_pernet(net); | 248 | struct hashlimit_net *hashlimit_net = hashlimit_pernet(net); |
222 | struct xt_hashlimit_htable *hinfo; | 249 | struct xt_hashlimit_htable *hinfo; |
223 | unsigned int size; | 250 | unsigned int size, i; |
224 | unsigned int i; | 251 | int ret; |
225 | 252 | ||
226 | if (minfo->cfg.size) { | 253 | if (cfg->size) { |
227 | size = minfo->cfg.size; | 254 | size = cfg->size; |
228 | } else { | 255 | } else { |
229 | size = (totalram_pages << PAGE_SHIFT) / 16384 / | 256 | size = (totalram_pages << PAGE_SHIFT) / 16384 / |
230 | sizeof(struct list_head); | 257 | sizeof(struct list_head); |
@@ -238,10 +265,14 @@ static int htable_create_v1(struct net *net, struct xt_hashlimit_mtinfo1 *minfo, | |||
238 | sizeof(struct list_head) * size); | 265 | sizeof(struct list_head) * size); |
239 | if (hinfo == NULL) | 266 | if (hinfo == NULL) |
240 | return -ENOMEM; | 267 | return -ENOMEM; |
241 | minfo->hinfo = hinfo; | 268 | *out_hinfo = hinfo; |
242 | 269 | ||
243 | /* copy match config into hashtable config */ | 270 | /* copy match config into hashtable config */ |
244 | memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg)); | 271 | ret = cfg_copy(&hinfo->cfg, (void *)cfg, 2); |
272 | |||
273 | if (ret) | ||
274 | return ret; | ||
275 | |||
245 | hinfo->cfg.size = size; | 276 | hinfo->cfg.size = size; |
246 | if (hinfo->cfg.max == 0) | 277 | if (hinfo->cfg.max == 0) |
247 | hinfo->cfg.max = 8 * hinfo->cfg.size; | 278 | hinfo->cfg.max = 8 * hinfo->cfg.size; |
@@ -255,17 +286,18 @@ static int htable_create_v1(struct net *net, struct xt_hashlimit_mtinfo1 *minfo, | |||
255 | hinfo->count = 0; | 286 | hinfo->count = 0; |
256 | hinfo->family = family; | 287 | hinfo->family = family; |
257 | hinfo->rnd_initialized = false; | 288 | hinfo->rnd_initialized = false; |
258 | hinfo->name = kstrdup(minfo->name, GFP_KERNEL); | 289 | hinfo->name = kstrdup(name, GFP_KERNEL); |
259 | if (!hinfo->name) { | 290 | if (!hinfo->name) { |
260 | vfree(hinfo); | 291 | vfree(hinfo); |
261 | return -ENOMEM; | 292 | return -ENOMEM; |
262 | } | 293 | } |
263 | spin_lock_init(&hinfo->lock); | 294 | spin_lock_init(&hinfo->lock); |
264 | 295 | ||
265 | hinfo->pde = proc_create_data(minfo->name, 0, | 296 | hinfo->pde = proc_create_data(name, 0, |
266 | (family == NFPROTO_IPV4) ? | 297 | (family == NFPROTO_IPV4) ? |
267 | hashlimit_net->ipt_hashlimit : hashlimit_net->ip6t_hashlimit, | 298 | hashlimit_net->ipt_hashlimit : hashlimit_net->ip6t_hashlimit, |
268 | &dl_file_ops_v1, hinfo); | 299 | (revision == 1) ? &dl_file_ops_v1 : &dl_file_ops, |
300 | hinfo); | ||
269 | if (hinfo->pde == NULL) { | 301 | if (hinfo->pde == NULL) { |
270 | kfree(hinfo->name); | 302 | kfree(hinfo->name); |
271 | vfree(hinfo); | 303 | vfree(hinfo); |
@@ -399,6 +431,7 @@ static void htable_put(struct xt_hashlimit_htable *hinfo) | |||
399 | CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32 ie. | 431 | CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32 ie. |
400 | */ | 432 | */ |
401 | #define MAX_CPJ_v1 (0xFFFFFFFF / (HZ*60*60*24)) | 433 | #define MAX_CPJ_v1 (0xFFFFFFFF / (HZ*60*60*24)) |
434 | #define MAX_CPJ (0xFFFFFFFFFFFFFFFF / (HZ*60*60*24)) | ||
402 | 435 | ||
403 | /* Repeated shift and or gives us all 1s, final shift and add 1 gives | 436 | /* Repeated shift and or gives us all 1s, final shift and add 1 gives |
404 | * us the power of 2 below the theoretical max, so GCC simply does a | 437 | * us the power of 2 below the theoretical max, so GCC simply does a |
@@ -408,8 +441,11 @@ static void htable_put(struct xt_hashlimit_htable *hinfo) | |||
408 | #define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4)) | 441 | #define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4)) |
409 | #define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8)) | 442 | #define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8)) |
410 | #define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16)) | 443 | #define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16)) |
444 | #define _POW2_BELOW64(x) (_POW2_BELOW32(x)|_POW2_BELOW32((x)>>32)) | ||
411 | #define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1) | 445 | #define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1) |
446 | #define POW2_BELOW64(x) ((_POW2_BELOW64(x)>>1) + 1) | ||
412 | 447 | ||
448 | #define CREDITS_PER_JIFFY POW2_BELOW64(MAX_CPJ) | ||
413 | #define CREDITS_PER_JIFFY_v1 POW2_BELOW32(MAX_CPJ_v1) | 449 | #define CREDITS_PER_JIFFY_v1 POW2_BELOW32(MAX_CPJ_v1) |
414 | 450 | ||
415 | /* in byte mode, the lowest possible rate is one packet/second. | 451 | /* in byte mode, the lowest possible rate is one packet/second. |
@@ -425,15 +461,24 @@ static u32 xt_hashlimit_len_to_chunks(u32 len) | |||
425 | } | 461 | } |
426 | 462 | ||
427 | /* Precision saver. */ | 463 | /* Precision saver. */ |
428 | static u32 user2credits(u32 user) | 464 | static u64 user2credits(u64 user, int revision) |
429 | { | 465 | { |
430 | /* If multiplying would overflow... */ | 466 | if (revision == 1) { |
431 | if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY_v1)) | 467 | /* If multiplying would overflow... */ |
432 | /* Divide first. */ | 468 | if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY_v1)) |
433 | return (user / XT_HASHLIMIT_SCALE) *\ | 469 | /* Divide first. */ |
434 | HZ * CREDITS_PER_JIFFY_v1; | 470 | return (user / XT_HASHLIMIT_SCALE) *\ |
471 | HZ * CREDITS_PER_JIFFY_v1; | ||
472 | |||
473 | return (user * HZ * CREDITS_PER_JIFFY_v1) \ | ||
474 | / XT_HASHLIMIT_SCALE; | ||
475 | } else { | ||
476 | if (user > 0xFFFFFFFFFFFFFFFF / (HZ*CREDITS_PER_JIFFY)) | ||
477 | return (user / XT_HASHLIMIT_SCALE_v2) *\ | ||
478 | HZ * CREDITS_PER_JIFFY; | ||
435 | 479 | ||
436 | return (user * HZ * CREDITS_PER_JIFFY_v1) / XT_HASHLIMIT_SCALE; | 480 | return (user * HZ * CREDITS_PER_JIFFY) / XT_HASHLIMIT_SCALE_v2; |
481 | } | ||
437 | } | 482 | } |
438 | 483 | ||
439 | static u32 user2credits_byte(u32 user) | 484 | static u32 user2credits_byte(u32 user) |
@@ -443,10 +488,11 @@ static u32 user2credits_byte(u32 user) | |||
443 | return (u32) (us >> 32); | 488 | return (u32) (us >> 32); |
444 | } | 489 | } |
445 | 490 | ||
446 | static void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now, u32 mode) | 491 | static void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now, |
492 | u32 mode, int revision) | ||
447 | { | 493 | { |
448 | unsigned long delta = now - dh->rateinfo.prev; | 494 | unsigned long delta = now - dh->rateinfo.prev; |
449 | u32 cap; | 495 | u64 cap, cpj; |
450 | 496 | ||
451 | if (delta == 0) | 497 | if (delta == 0) |
452 | return; | 498 | return; |
@@ -454,7 +500,7 @@ static void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now, u32 mode) | |||
454 | dh->rateinfo.prev = now; | 500 | dh->rateinfo.prev = now; |
455 | 501 | ||
456 | if (mode & XT_HASHLIMIT_BYTES) { | 502 | if (mode & XT_HASHLIMIT_BYTES) { |
457 | u32 tmp = dh->rateinfo.credit; | 503 | u64 tmp = dh->rateinfo.credit; |
458 | dh->rateinfo.credit += CREDITS_PER_JIFFY_BYTES * delta; | 504 | dh->rateinfo.credit += CREDITS_PER_JIFFY_BYTES * delta; |
459 | cap = CREDITS_PER_JIFFY_BYTES * HZ; | 505 | cap = CREDITS_PER_JIFFY_BYTES * HZ; |
460 | if (tmp >= dh->rateinfo.credit) {/* overflow */ | 506 | if (tmp >= dh->rateinfo.credit) {/* overflow */ |
@@ -462,7 +508,9 @@ static void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now, u32 mode) | |||
462 | return; | 508 | return; |
463 | } | 509 | } |
464 | } else { | 510 | } else { |
465 | dh->rateinfo.credit += delta * CREDITS_PER_JIFFY_v1; | 511 | cpj = (revision == 1) ? |
512 | CREDITS_PER_JIFFY_v1 : CREDITS_PER_JIFFY; | ||
513 | dh->rateinfo.credit += delta * cpj; | ||
466 | cap = dh->rateinfo.credit_cap; | 514 | cap = dh->rateinfo.credit_cap; |
467 | } | 515 | } |
468 | if (dh->rateinfo.credit > cap) | 516 | if (dh->rateinfo.credit > cap) |
@@ -470,7 +518,7 @@ static void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now, u32 mode) | |||
470 | } | 518 | } |
471 | 519 | ||
472 | static void rateinfo_init(struct dsthash_ent *dh, | 520 | static void rateinfo_init(struct dsthash_ent *dh, |
473 | struct xt_hashlimit_htable *hinfo) | 521 | struct xt_hashlimit_htable *hinfo, int revision) |
474 | { | 522 | { |
475 | dh->rateinfo.prev = jiffies; | 523 | dh->rateinfo.prev = jiffies; |
476 | if (hinfo->cfg.mode & XT_HASHLIMIT_BYTES) { | 524 | if (hinfo->cfg.mode & XT_HASHLIMIT_BYTES) { |
@@ -479,8 +527,8 @@ static void rateinfo_init(struct dsthash_ent *dh, | |||
479 | dh->rateinfo.credit_cap = hinfo->cfg.burst; | 527 | dh->rateinfo.credit_cap = hinfo->cfg.burst; |
480 | } else { | 528 | } else { |
481 | dh->rateinfo.credit = user2credits(hinfo->cfg.avg * | 529 | dh->rateinfo.credit = user2credits(hinfo->cfg.avg * |
482 | hinfo->cfg.burst); | 530 | hinfo->cfg.burst, revision); |
483 | dh->rateinfo.cost = user2credits(hinfo->cfg.avg); | 531 | dh->rateinfo.cost = user2credits(hinfo->cfg.avg, revision); |
484 | dh->rateinfo.credit_cap = dh->rateinfo.credit; | 532 | dh->rateinfo.credit_cap = dh->rateinfo.credit; |
485 | } | 533 | } |
486 | } | 534 | } |
@@ -604,15 +652,15 @@ static u32 hashlimit_byte_cost(unsigned int len, struct dsthash_ent *dh) | |||
604 | } | 652 | } |
605 | 653 | ||
606 | static bool | 654 | static bool |
607 | hashlimit_mt_v1(const struct sk_buff *skb, struct xt_action_param *par) | 655 | hashlimit_mt_common(const struct sk_buff *skb, struct xt_action_param *par, |
656 | struct xt_hashlimit_htable *hinfo, | ||
657 | const struct hashlimit_cfg2 *cfg, int revision) | ||
608 | { | 658 | { |
609 | const struct xt_hashlimit_mtinfo1 *info = par->matchinfo; | ||
610 | struct xt_hashlimit_htable *hinfo = info->hinfo; | ||
611 | unsigned long now = jiffies; | 659 | unsigned long now = jiffies; |
612 | struct dsthash_ent *dh; | 660 | struct dsthash_ent *dh; |
613 | struct dsthash_dst dst; | 661 | struct dsthash_dst dst; |
614 | bool race = false; | 662 | bool race = false; |
615 | u32 cost; | 663 | u64 cost; |
616 | 664 | ||
617 | if (hashlimit_init_dst(hinfo, &dst, skb, par->thoff) < 0) | 665 | if (hashlimit_init_dst(hinfo, &dst, skb, par->thoff) < 0) |
618 | goto hotdrop; | 666 | goto hotdrop; |
@@ -627,18 +675,18 @@ hashlimit_mt_v1(const struct sk_buff *skb, struct xt_action_param *par) | |||
627 | } else if (race) { | 675 | } else if (race) { |
628 | /* Already got an entry, update expiration timeout */ | 676 | /* Already got an entry, update expiration timeout */ |
629 | dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire); | 677 | dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire); |
630 | rateinfo_recalc(dh, now, hinfo->cfg.mode); | 678 | rateinfo_recalc(dh, now, hinfo->cfg.mode, revision); |
631 | } else { | 679 | } else { |
632 | dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire); | 680 | dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire); |
633 | rateinfo_init(dh, hinfo); | 681 | rateinfo_init(dh, hinfo, revision); |
634 | } | 682 | } |
635 | } else { | 683 | } else { |
636 | /* update expiration timeout */ | 684 | /* update expiration timeout */ |
637 | dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire); | 685 | dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire); |
638 | rateinfo_recalc(dh, now, hinfo->cfg.mode); | 686 | rateinfo_recalc(dh, now, hinfo->cfg.mode, revision); |
639 | } | 687 | } |
640 | 688 | ||
641 | if (info->cfg.mode & XT_HASHLIMIT_BYTES) | 689 | if (cfg->mode & XT_HASHLIMIT_BYTES) |
642 | cost = hashlimit_byte_cost(skb->len, dh); | 690 | cost = hashlimit_byte_cost(skb->len, dh); |
643 | else | 691 | else |
644 | cost = dh->rateinfo.cost; | 692 | cost = dh->rateinfo.cost; |
@@ -648,70 +696,126 @@ hashlimit_mt_v1(const struct sk_buff *skb, struct xt_action_param *par) | |||
648 | dh->rateinfo.credit -= cost; | 696 | dh->rateinfo.credit -= cost; |
649 | spin_unlock(&dh->lock); | 697 | spin_unlock(&dh->lock); |
650 | rcu_read_unlock_bh(); | 698 | rcu_read_unlock_bh(); |
651 | return !(info->cfg.mode & XT_HASHLIMIT_INVERT); | 699 | return !(cfg->mode & XT_HASHLIMIT_INVERT); |
652 | } | 700 | } |
653 | 701 | ||
654 | spin_unlock(&dh->lock); | 702 | spin_unlock(&dh->lock); |
655 | rcu_read_unlock_bh(); | 703 | rcu_read_unlock_bh(); |
656 | /* default match is underlimit - so over the limit, we need to invert */ | 704 | /* default match is underlimit - so over the limit, we need to invert */ |
657 | return info->cfg.mode & XT_HASHLIMIT_INVERT; | 705 | return cfg->mode & XT_HASHLIMIT_INVERT; |
658 | 706 | ||
659 | hotdrop: | 707 | hotdrop: |
660 | par->hotdrop = true; | 708 | par->hotdrop = true; |
661 | return false; | 709 | return false; |
662 | } | 710 | } |
663 | 711 | ||
664 | static int hashlimit_mt_check_v1(const struct xt_mtchk_param *par) | 712 | static bool |
713 | hashlimit_mt_v1(const struct sk_buff *skb, struct xt_action_param *par) | ||
714 | { | ||
715 | const struct xt_hashlimit_mtinfo1 *info = par->matchinfo; | ||
716 | struct xt_hashlimit_htable *hinfo = info->hinfo; | ||
717 | struct hashlimit_cfg2 cfg = {}; | ||
718 | int ret; | ||
719 | |||
720 | ret = cfg_copy(&cfg, (void *)&info->cfg, 1); | ||
721 | |||
722 | if (ret) | ||
723 | return ret; | ||
724 | |||
725 | return hashlimit_mt_common(skb, par, hinfo, &cfg, 1); | ||
726 | } | ||
727 | |||
728 | static bool | ||
729 | hashlimit_mt(const struct sk_buff *skb, struct xt_action_param *par) | ||
730 | { | ||
731 | const struct xt_hashlimit_mtinfo2 *info = par->matchinfo; | ||
732 | struct xt_hashlimit_htable *hinfo = info->hinfo; | ||
733 | |||
734 | return hashlimit_mt_common(skb, par, hinfo, &info->cfg, 2); | ||
735 | } | ||
736 | |||
737 | static int hashlimit_mt_check_common(const struct xt_mtchk_param *par, | ||
738 | struct xt_hashlimit_htable **hinfo, | ||
739 | struct hashlimit_cfg2 *cfg, | ||
740 | const char *name, int revision) | ||
665 | { | 741 | { |
666 | struct net *net = par->net; | 742 | struct net *net = par->net; |
667 | struct xt_hashlimit_mtinfo1 *info = par->matchinfo; | ||
668 | int ret; | 743 | int ret; |
669 | 744 | ||
670 | if (info->cfg.gc_interval == 0 || info->cfg.expire == 0) | 745 | if (cfg->gc_interval == 0 || cfg->expire == 0) |
671 | return -EINVAL; | ||
672 | if (info->name[sizeof(info->name)-1] != '\0') | ||
673 | return -EINVAL; | 746 | return -EINVAL; |
674 | if (par->family == NFPROTO_IPV4) { | 747 | if (par->family == NFPROTO_IPV4) { |
675 | if (info->cfg.srcmask > 32 || info->cfg.dstmask > 32) | 748 | if (cfg->srcmask > 32 || cfg->dstmask > 32) |
676 | return -EINVAL; | 749 | return -EINVAL; |
677 | } else { | 750 | } else { |
678 | if (info->cfg.srcmask > 128 || info->cfg.dstmask > 128) | 751 | if (cfg->srcmask > 128 || cfg->dstmask > 128) |
679 | return -EINVAL; | 752 | return -EINVAL; |
680 | } | 753 | } |
681 | 754 | ||
682 | if (info->cfg.mode & ~XT_HASHLIMIT_ALL) { | 755 | if (cfg->mode & ~XT_HASHLIMIT_ALL) { |
683 | pr_info("Unknown mode mask %X, kernel too old?\n", | 756 | pr_info("Unknown mode mask %X, kernel too old?\n", |
684 | info->cfg.mode); | 757 | cfg->mode); |
685 | return -EINVAL; | 758 | return -EINVAL; |
686 | } | 759 | } |
687 | 760 | ||
688 | /* Check for overflow. */ | 761 | /* Check for overflow. */ |
689 | if (info->cfg.mode & XT_HASHLIMIT_BYTES) { | 762 | if (cfg->mode & XT_HASHLIMIT_BYTES) { |
690 | if (user2credits_byte(info->cfg.avg) == 0) { | 763 | if (user2credits_byte(cfg->avg) == 0) { |
691 | pr_info("overflow, rate too high: %u\n", info->cfg.avg); | 764 | pr_info("overflow, rate too high: %llu\n", cfg->avg); |
692 | return -EINVAL; | 765 | return -EINVAL; |
693 | } | 766 | } |
694 | } else if (info->cfg.burst == 0 || | 767 | } else if (cfg->burst == 0 || |
695 | user2credits(info->cfg.avg * info->cfg.burst) < | 768 | user2credits(cfg->avg * cfg->burst, revision) < |
696 | user2credits(info->cfg.avg)) { | 769 | user2credits(cfg->avg, revision)) { |
697 | pr_info("overflow, try lower: %u/%u\n", | 770 | pr_info("overflow, try lower: %llu/%llu\n", |
698 | info->cfg.avg, info->cfg.burst); | 771 | cfg->avg, cfg->burst); |
699 | return -ERANGE; | 772 | return -ERANGE; |
700 | } | 773 | } |
701 | 774 | ||
702 | mutex_lock(&hashlimit_mutex); | 775 | mutex_lock(&hashlimit_mutex); |
703 | info->hinfo = htable_find_get(net, info->name, par->family); | 776 | *hinfo = htable_find_get(net, name, par->family); |
704 | if (info->hinfo == NULL) { | 777 | if (*hinfo == NULL) { |
705 | ret = htable_create_v1(net, info, par->family); | 778 | ret = htable_create(net, cfg, name, par->family, |
779 | hinfo, revision); | ||
706 | if (ret < 0) { | 780 | if (ret < 0) { |
707 | mutex_unlock(&hashlimit_mutex); | 781 | mutex_unlock(&hashlimit_mutex); |
708 | return ret; | 782 | return ret; |
709 | } | 783 | } |
710 | } | 784 | } |
711 | mutex_unlock(&hashlimit_mutex); | 785 | mutex_unlock(&hashlimit_mutex); |
786 | |||
712 | return 0; | 787 | return 0; |
713 | } | 788 | } |
714 | 789 | ||
790 | static int hashlimit_mt_check_v1(const struct xt_mtchk_param *par) | ||
791 | { | ||
792 | struct xt_hashlimit_mtinfo1 *info = par->matchinfo; | ||
793 | struct hashlimit_cfg2 cfg = {}; | ||
794 | int ret; | ||
795 | |||
796 | if (info->name[sizeof(info->name) - 1] != '\0') | ||
797 | return -EINVAL; | ||
798 | |||
799 | ret = cfg_copy(&cfg, (void *)&info->cfg, 1); | ||
800 | |||
801 | if (ret) | ||
802 | return ret; | ||
803 | |||
804 | return hashlimit_mt_check_common(par, &info->hinfo, | ||
805 | &cfg, info->name, 1); | ||
806 | } | ||
807 | |||
808 | static int hashlimit_mt_check(const struct xt_mtchk_param *par) | ||
809 | { | ||
810 | struct xt_hashlimit_mtinfo2 *info = par->matchinfo; | ||
811 | |||
812 | if (info->name[sizeof(info->name) - 1] != '\0') | ||
813 | return -EINVAL; | ||
814 | |||
815 | return hashlimit_mt_check_common(par, &info->hinfo, &info->cfg, | ||
816 | info->name, 2); | ||
817 | } | ||
818 | |||
715 | static void hashlimit_mt_destroy_v1(const struct xt_mtdtor_param *par) | 819 | static void hashlimit_mt_destroy_v1(const struct xt_mtdtor_param *par) |
716 | { | 820 | { |
717 | const struct xt_hashlimit_mtinfo1 *info = par->matchinfo; | 821 | const struct xt_hashlimit_mtinfo1 *info = par->matchinfo; |
@@ -719,6 +823,13 @@ static void hashlimit_mt_destroy_v1(const struct xt_mtdtor_param *par) | |||
719 | htable_put(info->hinfo); | 823 | htable_put(info->hinfo); |
720 | } | 824 | } |
721 | 825 | ||
826 | static void hashlimit_mt_destroy(const struct xt_mtdtor_param *par) | ||
827 | { | ||
828 | const struct xt_hashlimit_mtinfo2 *info = par->matchinfo; | ||
829 | |||
830 | htable_put(info->hinfo); | ||
831 | } | ||
832 | |||
722 | static struct xt_match hashlimit_mt_reg[] __read_mostly = { | 833 | static struct xt_match hashlimit_mt_reg[] __read_mostly = { |
723 | { | 834 | { |
724 | .name = "hashlimit", | 835 | .name = "hashlimit", |
@@ -730,6 +841,16 @@ static struct xt_match hashlimit_mt_reg[] __read_mostly = { | |||
730 | .destroy = hashlimit_mt_destroy_v1, | 841 | .destroy = hashlimit_mt_destroy_v1, |
731 | .me = THIS_MODULE, | 842 | .me = THIS_MODULE, |
732 | }, | 843 | }, |
844 | { | ||
845 | .name = "hashlimit", | ||
846 | .revision = 2, | ||
847 | .family = NFPROTO_IPV4, | ||
848 | .match = hashlimit_mt, | ||
849 | .matchsize = sizeof(struct xt_hashlimit_mtinfo2), | ||
850 | .checkentry = hashlimit_mt_check, | ||
851 | .destroy = hashlimit_mt_destroy, | ||
852 | .me = THIS_MODULE, | ||
853 | }, | ||
733 | #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) | 854 | #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) |
734 | { | 855 | { |
735 | .name = "hashlimit", | 856 | .name = "hashlimit", |
@@ -741,6 +862,16 @@ static struct xt_match hashlimit_mt_reg[] __read_mostly = { | |||
741 | .destroy = hashlimit_mt_destroy_v1, | 862 | .destroy = hashlimit_mt_destroy_v1, |
742 | .me = THIS_MODULE, | 863 | .me = THIS_MODULE, |
743 | }, | 864 | }, |
865 | { | ||
866 | .name = "hashlimit", | ||
867 | .revision = 2, | ||
868 | .family = NFPROTO_IPV6, | ||
869 | .match = hashlimit_mt, | ||
870 | .matchsize = sizeof(struct xt_hashlimit_mtinfo2), | ||
871 | .checkentry = hashlimit_mt_check, | ||
872 | .destroy = hashlimit_mt_destroy, | ||
873 | .me = THIS_MODULE, | ||
874 | }, | ||
744 | #endif | 875 | #endif |
745 | }; | 876 | }; |
746 | 877 | ||
@@ -787,18 +918,12 @@ static void dl_seq_stop(struct seq_file *s, void *v) | |||
787 | spin_unlock_bh(&htable->lock); | 918 | spin_unlock_bh(&htable->lock); |
788 | } | 919 | } |
789 | 920 | ||
790 | static int dl_seq_real_show_v1(struct dsthash_ent *ent, u_int8_t family, | 921 | static void dl_seq_print(struct dsthash_ent *ent, u_int8_t family, |
791 | struct seq_file *s) | 922 | struct seq_file *s) |
792 | { | 923 | { |
793 | const struct xt_hashlimit_htable *ht = s->private; | ||
794 | |||
795 | spin_lock(&ent->lock); | ||
796 | /* recalculate to show accurate numbers */ | ||
797 | rateinfo_recalc(ent, jiffies, ht->cfg.mode); | ||
798 | |||
799 | switch (family) { | 924 | switch (family) { |
800 | case NFPROTO_IPV4: | 925 | case NFPROTO_IPV4: |
801 | seq_printf(s, "%ld %pI4:%u->%pI4:%u %u %u %u\n", | 926 | seq_printf(s, "%ld %pI4:%u->%pI4:%u %llu %llu %llu\n", |
802 | (long)(ent->expires - jiffies)/HZ, | 927 | (long)(ent->expires - jiffies)/HZ, |
803 | &ent->dst.ip.src, | 928 | &ent->dst.ip.src, |
804 | ntohs(ent->dst.src_port), | 929 | ntohs(ent->dst.src_port), |
@@ -809,7 +934,7 @@ static int dl_seq_real_show_v1(struct dsthash_ent *ent, u_int8_t family, | |||
809 | break; | 934 | break; |
810 | #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) | 935 | #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) |
811 | case NFPROTO_IPV6: | 936 | case NFPROTO_IPV6: |
812 | seq_printf(s, "%ld %pI6:%u->%pI6:%u %u %u %u\n", | 937 | seq_printf(s, "%ld %pI6:%u->%pI6:%u %llu %llu %llu\n", |
813 | (long)(ent->expires - jiffies)/HZ, | 938 | (long)(ent->expires - jiffies)/HZ, |
814 | &ent->dst.ip6.src, | 939 | &ent->dst.ip6.src, |
815 | ntohs(ent->dst.src_port), | 940 | ntohs(ent->dst.src_port), |
@@ -822,6 +947,34 @@ static int dl_seq_real_show_v1(struct dsthash_ent *ent, u_int8_t family, | |||
822 | default: | 947 | default: |
823 | BUG(); | 948 | BUG(); |
824 | } | 949 | } |
950 | } | ||
951 | |||
952 | static int dl_seq_real_show_v1(struct dsthash_ent *ent, u_int8_t family, | ||
953 | struct seq_file *s) | ||
954 | { | ||
955 | const struct xt_hashlimit_htable *ht = s->private; | ||
956 | |||
957 | spin_lock(&ent->lock); | ||
958 | /* recalculate to show accurate numbers */ | ||
959 | rateinfo_recalc(ent, jiffies, ht->cfg.mode, 1); | ||
960 | |||
961 | dl_seq_print(ent, family, s); | ||
962 | |||
963 | spin_unlock(&ent->lock); | ||
964 | return seq_has_overflowed(s); | ||
965 | } | ||
966 | |||
967 | static int dl_seq_real_show(struct dsthash_ent *ent, u_int8_t family, | ||
968 | struct seq_file *s) | ||
969 | { | ||
970 | const struct xt_hashlimit_htable *ht = s->private; | ||
971 | |||
972 | spin_lock(&ent->lock); | ||
973 | /* recalculate to show accurate numbers */ | ||
974 | rateinfo_recalc(ent, jiffies, ht->cfg.mode, 2); | ||
975 | |||
976 | dl_seq_print(ent, family, s); | ||
977 | |||
825 | spin_unlock(&ent->lock); | 978 | spin_unlock(&ent->lock); |
826 | return seq_has_overflowed(s); | 979 | return seq_has_overflowed(s); |
827 | } | 980 | } |
@@ -840,6 +993,20 @@ static int dl_seq_show_v1(struct seq_file *s, void *v) | |||
840 | return 0; | 993 | return 0; |
841 | } | 994 | } |
842 | 995 | ||
996 | static int dl_seq_show(struct seq_file *s, void *v) | ||
997 | { | ||
998 | struct xt_hashlimit_htable *htable = s->private; | ||
999 | unsigned int *bucket = (unsigned int *)v; | ||
1000 | struct dsthash_ent *ent; | ||
1001 | |||
1002 | if (!hlist_empty(&htable->hash[*bucket])) { | ||
1003 | hlist_for_each_entry(ent, &htable->hash[*bucket], node) | ||
1004 | if (dl_seq_real_show(ent, htable->family, s)) | ||
1005 | return -1; | ||
1006 | } | ||
1007 | return 0; | ||
1008 | } | ||
1009 | |||
843 | static const struct seq_operations dl_seq_ops_v1 = { | 1010 | static const struct seq_operations dl_seq_ops_v1 = { |
844 | .start = dl_seq_start, | 1011 | .start = dl_seq_start, |
845 | .next = dl_seq_next, | 1012 | .next = dl_seq_next, |
@@ -847,6 +1014,13 @@ static const struct seq_operations dl_seq_ops_v1 = { | |||
847 | .show = dl_seq_show_v1 | 1014 | .show = dl_seq_show_v1 |
848 | }; | 1015 | }; |
849 | 1016 | ||
1017 | static const struct seq_operations dl_seq_ops = { | ||
1018 | .start = dl_seq_start, | ||
1019 | .next = dl_seq_next, | ||
1020 | .stop = dl_seq_stop, | ||
1021 | .show = dl_seq_show | ||
1022 | }; | ||
1023 | |||
850 | static int dl_proc_open_v1(struct inode *inode, struct file *file) | 1024 | static int dl_proc_open_v1(struct inode *inode, struct file *file) |
851 | { | 1025 | { |
852 | int ret = seq_open(file, &dl_seq_ops_v1); | 1026 | int ret = seq_open(file, &dl_seq_ops_v1); |
@@ -858,6 +1032,18 @@ static int dl_proc_open_v1(struct inode *inode, struct file *file) | |||
858 | return ret; | 1032 | return ret; |
859 | } | 1033 | } |
860 | 1034 | ||
1035 | static int dl_proc_open(struct inode *inode, struct file *file) | ||
1036 | { | ||
1037 | int ret = seq_open(file, &dl_seq_ops); | ||
1038 | |||
1039 | if (!ret) { | ||
1040 | struct seq_file *sf = file->private_data; | ||
1041 | |||
1042 | sf->private = PDE_DATA(inode); | ||
1043 | } | ||
1044 | return ret; | ||
1045 | } | ||
1046 | |||
861 | static const struct file_operations dl_file_ops_v1 = { | 1047 | static const struct file_operations dl_file_ops_v1 = { |
862 | .owner = THIS_MODULE, | 1048 | .owner = THIS_MODULE, |
863 | .open = dl_proc_open_v1, | 1049 | .open = dl_proc_open_v1, |
@@ -866,6 +1052,14 @@ static const struct file_operations dl_file_ops_v1 = { | |||
866 | .release = seq_release | 1052 | .release = seq_release |
867 | }; | 1053 | }; |
868 | 1054 | ||
1055 | static const struct file_operations dl_file_ops = { | ||
1056 | .owner = THIS_MODULE, | ||
1057 | .open = dl_proc_open, | ||
1058 | .read = seq_read, | ||
1059 | .llseek = seq_lseek, | ||
1060 | .release = seq_release | ||
1061 | }; | ||
1062 | |||
869 | static int __net_init hashlimit_proc_net_init(struct net *net) | 1063 | static int __net_init hashlimit_proc_net_init(struct net *net) |
870 | { | 1064 | { |
871 | struct hashlimit_net *hashlimit_net = hashlimit_pernet(net); | 1065 | struct hashlimit_net *hashlimit_net = hashlimit_pernet(net); |