From patchwork Thu Mar 1 20:48:55 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Denys Fedoryshchenko X-Patchwork-Id: 144114 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 4FE491007D5 for ; Fri, 2 Mar 2012 07:58:54 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932550Ab2CAU6w (ORCPT ); Thu, 1 Mar 2012 15:58:52 -0500 Received: from hosting.visp.net.lb ([194.146.153.11]:57472 "EHLO hosting.visp.net.lb" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932534Ab2CAU6v (ORCPT ); Thu, 1 Mar 2012 15:58:51 -0500 X-Greylist: delayed 539 seconds by postgrey-1.27 at vger.kernel.org; Thu, 01 Mar 2012 15:58:51 EST Received: by hosting.visp.net.lb (Postfix, from userid 65534) id BCF282EC069; Thu, 1 Mar 2012 22:49:03 +0200 (EET) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on vmail X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_FILL_THIS_FORM_SHORT, UNPARSEABLE_RELAY autolearn=disabled version=3.3.1 Received: from webmail.visp.net.lb (localhost [127.0.0.1]) by hosting.visp.net.lb (Postfix) with ESMTP id C44A72EC069; Thu, 1 Mar 2012 22:48:55 +0200 (EET) Received: from 2DETQgoGbtyn2SB6QoHom6+cm0Tt/ZqLzclhHyZE/3k= (sh05/cv/CpJHhKOBBTAHaP3VaIDmUB2e) by webmail.visp.net.lb with HTTP (HTTP/1.1 POST); Thu, 01 Mar 2012 22:48:55 +0200 MIME-Version: 1.0 Date: Thu, 01 Mar 2012 22:48:55 +0200 From: Denys Fedoryshchenko To: , , Subject: iptables recent mask option, request for comments Message-ID: X-Sender: denys@visp.net.lb User-Agent: VISP Webmail/0.7.1 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Dear All I just wrote patch for recent module, to add option --mask. Please dont hit me hard, since i am newbie for this stuff :) Use case for this feature: 1)In some occasions i need to allow,block,match whole /24 subnet or other mask. 2)I can use recent as a trigger, e.g.: iptables -I OUTPUT -p icmp -d 8.8.8.8/32 -m recent --name X --set --mask 0.0.0.0 -j ACCEPT iptables -I OUTPUT -p icmp -d 2.2.2.10 -m recent --name X --rcheck --mask 0.0.0.0 -j REJECT vm ~ # ping 2.2.2.10 -c 2 -i 1;ping -c 1 8.8.8.8;ping -i 1 -c15 2.2.2.10 PING 2.2.2.10 (2.2.2.10) 56(84) bytes of data. 64 bytes from 2.2.2.10: icmp_req=1 ttl=62 time=0.733 ms 64 bytes from 2.2.2.10: icmp_req=2 ttl=62 time=0.768 ms --- 2.2.2.10 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1000ms rtt min/avg/max/mdev = 0.733/0.750/0.768/0.032 ms PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data. 64 bytes from 8.8.8.8: icmp_req=1 ttl=48 time=139 ms --- 8.8.8.8 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 139.251/139.251/139.251/0.000 ms PING 2.2.2.10 (2.2.2.10) 56(84) bytes of data. From 192.168.122.150: icmp_seq=1 Destination Port Unreachable From 192.168.122.150: icmp_seq=1 Destination Port Unreachable From 192.168.122.150: icmp_seq=1 Destination Port Unreachable From 192.168.122.150: icmp_seq=1 Destination Port Unreachable From 192.168.122.150: icmp_seq=1 Destination Port Unreachable From 192.168.122.150: icmp_seq=1 Destination Port Unreachable From 192.168.122.150: icmp_seq=1 Destination Port Unreachable From 192.168.122.150: icmp_seq=1 Destination Port Unreachable From 192.168.122.150: icmp_seq=1 Destination Port Unreachable From 192.168.122.150: icmp_seq=1 Destination Port Unreachable From 192.168.122.150: icmp_seq=1 Destination Port Unreachable From 192.168.122.150: icmp_seq=1 Destination Port Unreachable From 192.168.122.150: icmp_seq=1 Destination Port Unreachable From 192.168.122.150: icmp_seq=1 Destination Port Unreachable From 192.168.122.150: icmp_seq=1 Destination Port Unreachable --- 2.2.2.10 ping statistics --- 0 packets transmitted, 0 received, +15 errors Tested for backward compatibility: old iptables, new kernel old kernel, new iptables new kernel, new iptables Patches attached diff -Naur linux-3.2.9/include/linux/netfilter/xt_recent.h linux-3.2.9-custom/include/linux/netfilter/xt_recent.h --- linux-3.2.9/include/linux/netfilter/xt_recent.h 2012-03-01 02:32:49.000000000 +0200 +++ linux-3.2.9-custom/include/linux/netfilter/xt_recent.h 2012-03-01 19:39:10.674001660 +0200 @@ -32,4 +32,14 @@ __u8 side; }; +struct xt_recent_mtinfo_v1 { + __u32 seconds; + __u32 hit_count; + __u8 check_set; + __u8 invert; + char name[XT_RECENT_NAME_LEN]; + __u8 side; + union nf_inet_addr mask; +}; + #endif /* _LINUX_NETFILTER_XT_RECENT_H */ diff -Naur linux-3.2.9/include/linux/netfilter.h linux-3.2.9-custom/include/linux/netfilter.h --- linux-3.2.9/include/linux/netfilter.h 2012-03-01 02:32:49.000000000 +0200 +++ linux-3.2.9-custom/include/linux/netfilter.h 2012-03-01 12:41:23.000000000 +0200 @@ -85,6 +85,17 @@ return -(verdict >> NF_VERDICT_QBITS); } + +static inline void nf_inet_addr_mask(const union nf_inet_addr *a1, + union nf_inet_addr *result, + const union nf_inet_addr *mask) +{ + result->all[0] = a1->all[0] & mask->all[0]; + result->all[1] = a1->all[1] & mask->all[1]; + result->all[2] = a1->all[2] & mask->all[2]; + result->all[3] = a1->all[3] & mask->all[3]; +} + static inline int nf_inet_addr_cmp(const union nf_inet_addr *a1, const union nf_inet_addr *a2) { diff -Naur linux-3.2.9/net/netfilter/xt_recent.c linux-3.2.9-custom/net/netfilter/xt_recent.c --- linux-3.2.9/net/netfilter/xt_recent.c 2012-03-01 02:32:49.000000000 +0200 +++ linux-3.2.9-custom/net/netfilter/xt_recent.c 2012-03-01 22:23:33.969742684 +0200 @@ -75,6 +75,7 @@ struct recent_table { struct list_head list; char name[XT_RECENT_NAME_LEN]; + union nf_inet_addr mask; unsigned int refcnt; unsigned int entries; struct list_head lru_list; @@ -228,10 +229,11 @@ { struct net *net = dev_net(par->in ? par->in : par->out); struct recent_net *recent_net = recent_pernet(net); - const struct xt_recent_mtinfo *info = par->matchinfo; + const struct xt_recent_mtinfo_v1 *info = par->matchinfo; struct recent_table *t; struct recent_entry *e; union nf_inet_addr addr = {}; + union nf_inet_addr addr_masked; u_int8_t ttl; bool ret = info->invert; @@ -261,12 +263,15 @@ spin_lock_bh(&recent_lock); t = recent_table_lookup(recent_net, info->name); - e = recent_entry_lookup(t, &addr, par->family, + + nf_inet_addr_mask(&addr,&addr_masked,&t->mask); + + e = recent_entry_lookup(t, &addr_masked, par->family, (info->check_set & XT_RECENT_TTL) ? ttl : 0); if (e == NULL) { if (!(info->check_set & XT_RECENT_SET)) goto out; - e = recent_entry_init(t, &addr, par->family, ttl); + e = recent_entry_init(t, &addr_masked, par->family, ttl); if (e == NULL) par->hotdrop = true; ret = !ret; @@ -306,10 +311,10 @@ return ret; } -static int recent_mt_check(const struct xt_mtchk_param *par) +static int recent_mt_check(const struct xt_mtchk_param *par, const struct xt_recent_mtinfo_v1 *info) { struct recent_net *recent_net = recent_pernet(par->net); - const struct xt_recent_mtinfo *info = par->matchinfo; +// const struct xt_recent_mtinfo_v1 *info = par->matchinfo; struct recent_table *t; #ifdef CONFIG_PROC_FS struct proc_dir_entry *pde; @@ -361,6 +366,8 @@ goto out; } t->refcnt = 1; + + memcpy(&t->mask,&info->mask,sizeof(t->mask)); strcpy(t->name, info->name); INIT_LIST_HEAD(&t->lru_list); for (i = 0; i < ip_list_hash_size; i++) @@ -385,10 +392,37 @@ return ret; } +static int recent_mt_check_v0(const struct xt_mtchk_param *par) +{ + const struct xt_recent_mtinfo_v0 *info_v0 = par->matchinfo; + struct xt_recent_mtinfo_v1 *info_v1 = par->matchinfo; + int ret; + + info_v1 = kzalloc(sizeof(struct xt_recent_mtinfo_v1), + GFP_KERNEL); + if (info_v1 == NULL) { + return -ENOMEM; + } + + /* Copy old data */ + memcpy(info_v1,info_v0,sizeof(struct xt_recent_mtinfo)); + /* Default mask will make same behavior as old recent */ + memset(info_v1->mask.all,0xFF,sizeof(info_v1->mask.all)); + ret = recent_mt_check(par,info_v1); + + kfree(info_v1); + return(ret); +} + +static int recent_mt_check_v1(const struct xt_mtchk_param *par) +{ + return(recent_mt_check(par,par->matchinfo)); +} + static void recent_mt_destroy(const struct xt_mtdtor_param *par) { struct recent_net *recent_net = recent_pernet(par->net); - const struct xt_recent_mtinfo *info = par->matchinfo; + const struct xt_recent_mtinfo_v1 *info = par->matchinfo; struct recent_table *t; mutex_lock(&recent_mutex); @@ -625,7 +659,7 @@ .family = NFPROTO_IPV4, .match = recent_mt, .matchsize = sizeof(struct xt_recent_mtinfo), - .checkentry = recent_mt_check, + .checkentry = recent_mt_check_v0, .destroy = recent_mt_destroy, .me = THIS_MODULE, }, @@ -635,10 +669,30 @@ .family = NFPROTO_IPV6, .match = recent_mt, .matchsize = sizeof(struct xt_recent_mtinfo), - .checkentry = recent_mt_check, + .checkentry = recent_mt_check_v0, .destroy = recent_mt_destroy, .me = THIS_MODULE, }, + { + .name = "recent", + .revision = 1, + .family = NFPROTO_IPV4, + .match = recent_mt, + .matchsize = sizeof(struct xt_recent_mtinfo_v1), + .checkentry = recent_mt_check_v1, + .destroy = recent_mt_destroy, + .me = THIS_MODULE, + }, + { + .name = "recent", + .revision = 1, + .family = NFPROTO_IPV6, + .match = recent_mt, + .matchsize = sizeof(struct xt_recent_mtinfo_v1), + .checkentry = recent_mt_check_v1, + .destroy = recent_mt_destroy, + .me = THIS_MODULE, + } }; static int __init recent_mt_init(void)