aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDenys Fedoryshchenko <denys@visp.net.lb>2012-05-17 16:08:57 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2012-06-07 08:58:42 -0400
commitefdedd5426a94b00d23483a1bcb4af3a91c894db (patch)
treefdcf05bb970caa499a8dc86c058a167d8eb098b3
parent1da6dd07989869fa4f8ec1f47d610d12f96eb04d (diff)
netfilter: xt_recent: add address masking option
The mask option allows you put all address belonging that mask into the same recent slot. This can be useful in case that recent is used to detect attacks from the same network segment. Tested for backward compatibility. Signed-off-by: Denys Fedoryshchenko <denys@visp.net.lb> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r--Documentation/feature-removal-schedule.txt7
-rw-r--r--include/linux/netfilter.h10
-rw-r--r--include/linux/netfilter/xt_recent.h10
-rw-r--r--net/netfilter/xt_recent.c62
4 files changed, 80 insertions, 9 deletions
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 24ac00f4ae4..bc4b9c6eb80 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -574,6 +574,13 @@ Why: Remount currently allows changing bound subsystems and
574 574
575---------------------------- 575----------------------------
576 576
577What: xt_recent rev 0
578When: 2013
579Who: Pablo Neira Ayuso <pablo@netfilter.org>
580Files: net/netfilter/xt_recent.c
581
582----------------------------
583
577What: KVM debugfs statistics 584What: KVM debugfs statistics
578When: 2013 585When: 2013
579Why: KVM tracepoints provide mostly equivalent information in a much more 586Why: KVM tracepoints provide mostly equivalent information in a much more
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index ff9c84c29b2..4541f33dbfc 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -94,6 +94,16 @@ static inline int nf_inet_addr_cmp(const union nf_inet_addr *a1,
94 a1->all[3] == a2->all[3]; 94 a1->all[3] == a2->all[3];
95} 95}
96 96
97static inline void nf_inet_addr_mask(const union nf_inet_addr *a1,
98 union nf_inet_addr *result,
99 const union nf_inet_addr *mask)
100{
101 result->all[0] = a1->all[0] & mask->all[0];
102 result->all[1] = a1->all[1] & mask->all[1];
103 result->all[2] = a1->all[2] & mask->all[2];
104 result->all[3] = a1->all[3] & mask->all[3];
105}
106
97extern void netfilter_init(void); 107extern void netfilter_init(void);
98 108
99/* Largest hook number + 1 */ 109/* Largest hook number + 1 */
diff --git a/include/linux/netfilter/xt_recent.h b/include/linux/netfilter/xt_recent.h
index 83318e01425..6ef36c113e8 100644
--- a/include/linux/netfilter/xt_recent.h
+++ b/include/linux/netfilter/xt_recent.h
@@ -32,4 +32,14 @@ struct xt_recent_mtinfo {
32 __u8 side; 32 __u8 side;
33}; 33};
34 34
35struct xt_recent_mtinfo_v1 {
36 __u32 seconds;
37 __u32 hit_count;
38 __u8 check_set;
39 __u8 invert;
40 char name[XT_RECENT_NAME_LEN];
41 __u8 side;
42 union nf_inet_addr mask;
43};
44
35#endif /* _LINUX_NETFILTER_XT_RECENT_H */ 45#endif /* _LINUX_NETFILTER_XT_RECENT_H */
diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c
index fc0d6dbe5d1..ae2ad1eec8d 100644
--- a/net/netfilter/xt_recent.c
+++ b/net/netfilter/xt_recent.c
@@ -75,6 +75,7 @@ struct recent_entry {
75struct recent_table { 75struct recent_table {
76 struct list_head list; 76 struct list_head list;
77 char name[XT_RECENT_NAME_LEN]; 77 char name[XT_RECENT_NAME_LEN];
78 union nf_inet_addr mask;
78 unsigned int refcnt; 79 unsigned int refcnt;
79 unsigned int entries; 80 unsigned int entries;
80 struct list_head lru_list; 81 struct list_head lru_list;
@@ -228,10 +229,10 @@ recent_mt(const struct sk_buff *skb, struct xt_action_param *par)
228{ 229{
229 struct net *net = dev_net(par->in ? par->in : par->out); 230 struct net *net = dev_net(par->in ? par->in : par->out);
230 struct recent_net *recent_net = recent_pernet(net); 231 struct recent_net *recent_net = recent_pernet(net);
231 const struct xt_recent_mtinfo *info = par->matchinfo; 232 const struct xt_recent_mtinfo_v1 *info = par->matchinfo;
232 struct recent_table *t; 233 struct recent_table *t;
233 struct recent_entry *e; 234 struct recent_entry *e;
234 union nf_inet_addr addr = {}; 235 union nf_inet_addr addr = {}, addr_mask;
235 u_int8_t ttl; 236 u_int8_t ttl;
236 bool ret = info->invert; 237 bool ret = info->invert;
237 238
@@ -261,12 +262,15 @@ recent_mt(const struct sk_buff *skb, struct xt_action_param *par)
261 262
262 spin_lock_bh(&recent_lock); 263 spin_lock_bh(&recent_lock);
263 t = recent_table_lookup(recent_net, info->name); 264 t = recent_table_lookup(recent_net, info->name);
264 e = recent_entry_lookup(t, &addr, par->family, 265
266 nf_inet_addr_mask(&addr, &addr_mask, &t->mask);
267
268 e = recent_entry_lookup(t, &addr_mask, par->family,
265 (info->check_set & XT_RECENT_TTL) ? ttl : 0); 269 (info->check_set & XT_RECENT_TTL) ? ttl : 0);
266 if (e == NULL) { 270 if (e == NULL) {
267 if (!(info->check_set & XT_RECENT_SET)) 271 if (!(info->check_set & XT_RECENT_SET))
268 goto out; 272 goto out;
269 e = recent_entry_init(t, &addr, par->family, ttl); 273 e = recent_entry_init(t, &addr_mask, par->family, ttl);
270 if (e == NULL) 274 if (e == NULL)
271 par->hotdrop = true; 275 par->hotdrop = true;
272 ret = !ret; 276 ret = !ret;
@@ -306,10 +310,10 @@ out:
306 return ret; 310 return ret;
307} 311}
308 312
309static int recent_mt_check(const struct xt_mtchk_param *par) 313static int recent_mt_check(const struct xt_mtchk_param *par,
314 const struct xt_recent_mtinfo_v1 *info)
310{ 315{
311 struct recent_net *recent_net = recent_pernet(par->net); 316 struct recent_net *recent_net = recent_pernet(par->net);
312 const struct xt_recent_mtinfo *info = par->matchinfo;
313 struct recent_table *t; 317 struct recent_table *t;
314#ifdef CONFIG_PROC_FS 318#ifdef CONFIG_PROC_FS
315 struct proc_dir_entry *pde; 319 struct proc_dir_entry *pde;
@@ -361,6 +365,8 @@ static int recent_mt_check(const struct xt_mtchk_param *par)
361 goto out; 365 goto out;
362 } 366 }
363 t->refcnt = 1; 367 t->refcnt = 1;
368
369 memcpy(&t->mask, &info->mask, sizeof(t->mask));
364 strcpy(t->name, info->name); 370 strcpy(t->name, info->name);
365 INIT_LIST_HEAD(&t->lru_list); 371 INIT_LIST_HEAD(&t->lru_list);
366 for (i = 0; i < ip_list_hash_size; i++) 372 for (i = 0; i < ip_list_hash_size; i++)
@@ -385,10 +391,28 @@ out:
385 return ret; 391 return ret;
386} 392}
387 393
394static int recent_mt_check_v0(const struct xt_mtchk_param *par)
395{
396 const struct xt_recent_mtinfo_v0 *info_v0 = par->matchinfo;
397 struct xt_recent_mtinfo_v1 info_v1;
398
399 /* Copy revision 0 structure to revision 1 */
400 memcpy(&info_v1, info_v0, sizeof(struct xt_recent_mtinfo));
401 /* Set default mask to ensure backward compatible behaviour */
402 memset(info_v1.mask.all, 0xFF, sizeof(info_v1.mask.all));
403
404 return recent_mt_check(par, &info_v1);
405}
406
407static int recent_mt_check_v1(const struct xt_mtchk_param *par)
408{
409 return recent_mt_check(par, par->matchinfo);
410}
411
388static void recent_mt_destroy(const struct xt_mtdtor_param *par) 412static void recent_mt_destroy(const struct xt_mtdtor_param *par)
389{ 413{
390 struct recent_net *recent_net = recent_pernet(par->net); 414 struct recent_net *recent_net = recent_pernet(par->net);
391 const struct xt_recent_mtinfo *info = par->matchinfo; 415 const struct xt_recent_mtinfo_v1 *info = par->matchinfo;
392 struct recent_table *t; 416 struct recent_table *t;
393 417
394 mutex_lock(&recent_mutex); 418 mutex_lock(&recent_mutex);
@@ -625,7 +649,7 @@ static struct xt_match recent_mt_reg[] __read_mostly = {
625 .family = NFPROTO_IPV4, 649 .family = NFPROTO_IPV4,
626 .match = recent_mt, 650 .match = recent_mt,
627 .matchsize = sizeof(struct xt_recent_mtinfo), 651 .matchsize = sizeof(struct xt_recent_mtinfo),
628 .checkentry = recent_mt_check, 652 .checkentry = recent_mt_check_v0,
629 .destroy = recent_mt_destroy, 653 .destroy = recent_mt_destroy,
630 .me = THIS_MODULE, 654 .me = THIS_MODULE,
631 }, 655 },
@@ -635,10 +659,30 @@ static struct xt_match recent_mt_reg[] __read_mostly = {
635 .family = NFPROTO_IPV6, 659 .family = NFPROTO_IPV6,
636 .match = recent_mt, 660 .match = recent_mt,
637 .matchsize = sizeof(struct xt_recent_mtinfo), 661 .matchsize = sizeof(struct xt_recent_mtinfo),
638 .checkentry = recent_mt_check, 662 .checkentry = recent_mt_check_v0,
663 .destroy = recent_mt_destroy,
664 .me = THIS_MODULE,
665 },
666 {
667 .name = "recent",
668 .revision = 1,
669 .family = NFPROTO_IPV4,
670 .match = recent_mt,
671 .matchsize = sizeof(struct xt_recent_mtinfo_v1),
672 .checkentry = recent_mt_check_v1,
639 .destroy = recent_mt_destroy, 673 .destroy = recent_mt_destroy,
640 .me = THIS_MODULE, 674 .me = THIS_MODULE,
641 }, 675 },
676 {
677 .name = "recent",
678 .revision = 1,
679 .family = NFPROTO_IPV6,
680 .match = recent_mt,
681 .matchsize = sizeof(struct xt_recent_mtinfo_v1),
682 .checkentry = recent_mt_check_v1,
683 .destroy = recent_mt_destroy,
684 .me = THIS_MODULE,
685 }
642}; 686};
643 687
644static int __init recent_mt_init(void) 688static int __init recent_mt_init(void)