Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: nf_conntrack: nf_conntrack snmp helper

Adding support for SNMP broadcast connection tracking. The SNMP
broadcast requests are now paired with the SNMP responses.
Thus allowing using SNMP broadcasts with firewall enabled.

Please refer to the following conversation:
http://marc.info/?l=netfilter-devel&m=125992205006600&w=2

Patrick McHardy wrote:
> > The best solution would be to add generic broadcast tracking, the
> > use of expectations for this is a bit of abuse.
> > The second best choice I guess would be to move the help() function
> > to a shared module and generalize it so it can be used for both.
This patch implements the "second best choice".

Since the netbios-ns conntrack module uses the same helper
functionality as the snmp, only one helper function is added
for both snmp and netbios-ns modules into the new object -
nf_conntrack_broadcast.

Signed-off-by: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Patrick McHardy <kaber@trash.net>

authored by

Jiri Olsa and committed by
Patrick McHardy
93557f53 94d117a1

+211 -70
+9
include/linux/netfilter/nf_conntrack_snmp.h
··· 1 + #ifndef _NF_CONNTRACK_SNMP_H 2 + #define _NF_CONNTRACK_SNMP_H 3 + 4 + extern int (*nf_nat_snmp_hook)(struct sk_buff *skb, 5 + unsigned int protoff, 6 + struct nf_conn *ct, 7 + enum ip_conntrack_info ctinfo); 8 + 9 + #endif /* _NF_CONNTRACK_SNMP_H */
+6
include/net/netfilter/nf_conntrack_helper.h
··· 63 63 extern int nf_conntrack_helper_init(void); 64 64 extern void nf_conntrack_helper_fini(void); 65 65 66 + extern int nf_conntrack_broadcast_help(struct sk_buff *skb, 67 + unsigned int protoff, 68 + struct nf_conn *ct, 69 + enum ip_conntrack_info ctinfo, 70 + unsigned int timeout); 71 + 66 72 #endif /*_NF_CONNTRACK_HELPER_H*/
+2 -1
net/ipv4/netfilter/Kconfig
··· 206 206 207 207 config NF_NAT_SNMP_BASIC 208 208 tristate "Basic SNMP-ALG support" 209 - depends on NF_NAT 209 + depends on NF_CONNTRACK_SNMP && NF_NAT 210 210 depends on NETFILTER_ADVANCED 211 + default NF_NAT && NF_CONNTRACK_SNMP 211 212 ---help--- 212 213 213 214 This module implements an Application Layer Gateway (ALG) for
+5 -4
net/ipv4/netfilter/nf_nat_snmp_basic.c
··· 54 54 #include <net/netfilter/nf_conntrack_expect.h> 55 55 #include <net/netfilter/nf_conntrack_helper.h> 56 56 #include <net/netfilter/nf_nat_helper.h> 57 + #include <linux/netfilter/nf_conntrack_snmp.h> 57 58 58 59 MODULE_LICENSE("GPL"); 59 60 MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>"); ··· 1311 1310 { 1312 1311 int ret = 0; 1313 1312 1314 - ret = nf_conntrack_helper_register(&snmp_helper); 1315 - if (ret < 0) 1316 - return ret; 1313 + BUG_ON(nf_nat_snmp_hook != NULL); 1314 + rcu_assign_pointer(nf_nat_snmp_hook, help); 1315 + 1317 1316 ret = nf_conntrack_helper_register(&snmp_trap_helper); 1318 1317 if (ret < 0) { 1319 1318 nf_conntrack_helper_unregister(&snmp_helper); ··· 1324 1323 1325 1324 static void __exit nf_nat_snmp_basic_fini(void) 1326 1325 { 1327 - nf_conntrack_helper_unregister(&snmp_helper); 1326 + rcu_assign_pointer(nf_nat_snmp_hook, NULL); 1328 1327 nf_conntrack_helper_unregister(&snmp_trap_helper); 1329 1328 } 1330 1329
+19
net/netfilter/Kconfig
··· 185 185 186 186 To compile it as a module, choose M here. If unsure, say N. 187 187 188 + config NF_CONNTRACK_BROADCAST 189 + tristate 190 + 188 191 config NF_CONNTRACK_NETBIOS_NS 189 192 tristate "NetBIOS name service protocol support" 190 193 depends on NETFILTER_ADVANCED 194 + select NF_CONNTRACK_BROADCAST 191 195 help 192 196 NetBIOS name service requests are sent as broadcast messages from an 193 197 unprivileged port and responded to with unicast messages to the ··· 205 201 $ ip -4 address show eth0 206 202 4: eth0: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 1000 207 203 inet 172.16.2.252/24 brd 172.16.2.255 scope global eth0 204 + 205 + To compile it as a module, choose M here. If unsure, say N. 206 + 207 + config NF_CONNTRACK_SNMP 208 + tristate "SNMP service protocol support" 209 + depends on NETFILTER_ADVANCED 210 + select NF_CONNTRACK_BROADCAST 211 + help 212 + SNMP service requests are sent as broadcast messages from an 213 + unprivileged port and responded to with unicast messages to the 214 + same port. This make them hard to firewall properly because connection 215 + tracking doesn't deal with broadcasts. This helper tracks locally 216 + originating SNMP service requests and the corresponding 217 + responses. It relies on correct IP address configuration, specifically 218 + netmask and broadcast address. 208 219 209 220 To compile it as a module, choose M here. If unsure, say N. 210 221
+2
net/netfilter/Makefile
··· 28 28 obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o 29 29 obj-$(CONFIG_NF_CONNTRACK_H323) += nf_conntrack_h323.o 30 30 obj-$(CONFIG_NF_CONNTRACK_IRC) += nf_conntrack_irc.o 31 + obj-$(CONFIG_NF_CONNTRACK_BROADCAST) += nf_conntrack_broadcast.o 31 32 obj-$(CONFIG_NF_CONNTRACK_NETBIOS_NS) += nf_conntrack_netbios_ns.o 33 + obj-$(CONFIG_NF_CONNTRACK_SNMP) += nf_conntrack_snmp.o 32 34 obj-$(CONFIG_NF_CONNTRACK_PPTP) += nf_conntrack_pptp.o 33 35 obj-$(CONFIG_NF_CONNTRACK_SANE) += nf_conntrack_sane.o 34 36 obj-$(CONFIG_NF_CONNTRACK_SIP) += nf_conntrack_sip.o
+82
net/netfilter/nf_conntrack_broadcast.c
··· 1 + /* 2 + * broadcast connection tracking helper 3 + * 4 + * (c) 2005 Patrick McHardy <kaber@trash.net> 5 + * 6 + * This program is free software; you can redistribute it and/or 7 + * modify it under the terms of the GNU General Public License 8 + * as published by the Free Software Foundation; either version 9 + * 2 of the License, or (at your option) any later version. 10 + */ 11 + 12 + #include <linux/module.h> 13 + #include <linux/ip.h> 14 + #include <net/route.h> 15 + #include <linux/inetdevice.h> 16 + #include <linux/skbuff.h> 17 + 18 + #include <net/netfilter/nf_conntrack.h> 19 + #include <net/netfilter/nf_conntrack_helper.h> 20 + #include <net/netfilter/nf_conntrack_expect.h> 21 + 22 + int nf_conntrack_broadcast_help(struct sk_buff *skb, 23 + unsigned int protoff, 24 + struct nf_conn *ct, 25 + enum ip_conntrack_info ctinfo, 26 + unsigned int timeout) 27 + { 28 + struct nf_conntrack_expect *exp; 29 + struct iphdr *iph = ip_hdr(skb); 30 + struct rtable *rt = skb_rtable(skb); 31 + struct in_device *in_dev; 32 + struct nf_conn_help *help = nfct_help(ct); 33 + __be32 mask = 0; 34 + 35 + /* we're only interested in locally generated packets */ 36 + if (skb->sk == NULL) 37 + goto out; 38 + if (rt == NULL || !(rt->rt_flags & RTCF_BROADCAST)) 39 + goto out; 40 + if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL) 41 + goto out; 42 + 43 + rcu_read_lock(); 44 + in_dev = __in_dev_get_rcu(rt->dst.dev); 45 + if (in_dev != NULL) { 46 + for_primary_ifa(in_dev) { 47 + if (ifa->ifa_broadcast == iph->daddr) { 48 + mask = ifa->ifa_mask; 49 + break; 50 + } 51 + } endfor_ifa(in_dev); 52 + } 53 + rcu_read_unlock(); 54 + 55 + if (mask == 0) 56 + goto out; 57 + 58 + exp = nf_ct_expect_alloc(ct); 59 + if (exp == NULL) 60 + goto out; 61 + 62 + exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple; 63 + exp->tuple.src.u.udp.port = help->helper->tuple.src.u.udp.port; 64 + 65 + exp->mask.src.u3.ip = mask; 66 + exp->mask.src.u.udp.port = htons(0xFFFF); 67 + 68 + exp->expectfn = NULL; 69 + exp->flags = NF_CT_EXPECT_PERMANENT; 70 + exp->class = NF_CT_EXPECT_CLASS_DEFAULT; 71 + exp->helper = NULL; 72 + 73 + nf_ct_expect_related(exp); 74 + nf_ct_expect_put(exp); 75 + 76 + nf_ct_refresh(ct, skb, timeout * HZ); 77 + out: 78 + return NF_ACCEPT; 79 + } 80 + EXPORT_SYMBOL_GPL(nf_conntrack_broadcast_help); 81 + 82 + MODULE_LICENSE("GPL");
+9 -65
net/netfilter/nf_conntrack_netbios_ns.c
··· 18 18 #include <linux/kernel.h> 19 19 #include <linux/module.h> 20 20 #include <linux/init.h> 21 - #include <linux/skbuff.h> 22 - #include <linux/netdevice.h> 23 - #include <linux/inetdevice.h> 24 - #include <linux/if_addr.h> 25 21 #include <linux/in.h> 26 - #include <linux/ip.h> 27 - #include <linux/netfilter.h> 28 - #include <net/route.h> 29 22 30 23 #include <net/netfilter/nf_conntrack.h> 31 24 #include <net/netfilter/nf_conntrack_helper.h> ··· 33 40 MODULE_ALIAS_NFCT_HELPER("netbios_ns"); 34 41 35 42 static unsigned int timeout __read_mostly = 3; 36 - module_param(timeout, uint, 0400); 43 + module_param(timeout, uint, S_IRUSR); 37 44 MODULE_PARM_DESC(timeout, "timeout for master connection/replies in seconds"); 38 - 39 - static int help(struct sk_buff *skb, unsigned int protoff, 40 - struct nf_conn *ct, enum ip_conntrack_info ctinfo) 41 - { 42 - struct nf_conntrack_expect *exp; 43 - struct iphdr *iph = ip_hdr(skb); 44 - struct rtable *rt = skb_rtable(skb); 45 - struct in_device *in_dev; 46 - __be32 mask = 0; 47 - 48 - /* we're only interested in locally generated packets */ 49 - if (skb->sk == NULL) 50 - goto out; 51 - if (rt == NULL || !(rt->rt_flags & RTCF_BROADCAST)) 52 - goto out; 53 - if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL) 54 - goto out; 55 - 56 - rcu_read_lock(); 57 - in_dev = __in_dev_get_rcu(rt->dst.dev); 58 - if (in_dev != NULL) { 59 - for_primary_ifa(in_dev) { 60 - if (ifa->ifa_broadcast == iph->daddr) { 61 - mask = ifa->ifa_mask; 62 - break; 63 - } 64 - } endfor_ifa(in_dev); 65 - } 66 - rcu_read_unlock(); 67 - 68 - if (mask == 0) 69 - goto out; 70 - 71 - exp = nf_ct_expect_alloc(ct); 72 - if (exp == NULL) 73 - goto out; 74 - 75 - exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple; 76 - exp->tuple.src.u.udp.port = htons(NMBD_PORT); 77 - 78 - exp->mask.src.u3.ip = mask; 79 - exp->mask.src.u.udp.port = htons(0xFFFF); 80 - 81 - exp->expectfn = NULL; 82 - exp->flags = NF_CT_EXPECT_PERMANENT; 83 - exp->class = NF_CT_EXPECT_CLASS_DEFAULT; 84 - exp->helper = NULL; 85 - 86 - nf_ct_expect_related(exp); 87 - nf_ct_expect_put(exp); 88 - 89 - nf_ct_refresh(ct, skb, timeout * HZ); 90 - out: 91 - return NF_ACCEPT; 92 - } 93 45 94 46 static struct nf_conntrack_expect_policy exp_policy = { 95 47 .max_expected = 1, 96 48 }; 97 49 50 + static int netbios_ns_help(struct sk_buff *skb, unsigned int protoff, 51 + struct nf_conn *ct, enum ip_conntrack_info ctinfo) 52 + { 53 + return nf_conntrack_broadcast_help(skb, protoff, ct, ctinfo, timeout); 54 + } 55 + 98 56 static struct nf_conntrack_helper helper __read_mostly = { 99 57 .name = "netbios-ns", 100 - .tuple.src.l3num = AF_INET, 58 + .tuple.src.l3num = NFPROTO_IPV4, 101 59 .tuple.src.u.udp.port = cpu_to_be16(NMBD_PORT), 102 60 .tuple.dst.protonum = IPPROTO_UDP, 103 61 .me = THIS_MODULE, 104 - .help = help, 62 + .help = netbios_ns_help, 105 63 .expect_policy = &exp_policy, 106 64 }; 107 65
+77
net/netfilter/nf_conntrack_snmp.c
··· 1 + /* 2 + * SNMP service broadcast connection tracking helper 3 + * 4 + * (c) 2011 Jiri Olsa <jolsa@redhat.com> 5 + * 6 + * This program is free software; you can redistribute it and/or 7 + * modify it under the terms of the GNU General Public License 8 + * as published by the Free Software Foundation; either version 9 + * 2 of the License, or (at your option) any later version. 10 + */ 11 + #include <linux/kernel.h> 12 + #include <linux/module.h> 13 + #include <linux/init.h> 14 + #include <linux/in.h> 15 + 16 + #include <net/netfilter/nf_conntrack.h> 17 + #include <net/netfilter/nf_conntrack_helper.h> 18 + #include <net/netfilter/nf_conntrack_expect.h> 19 + 20 + #define SNMP_PORT 161 21 + 22 + MODULE_AUTHOR("Jiri Olsa <jolsa@redhat.com>"); 23 + MODULE_DESCRIPTION("SNMP service broadcast connection tracking helper"); 24 + MODULE_LICENSE("GPL"); 25 + MODULE_ALIAS_NFCT_HELPER("snmp"); 26 + 27 + static unsigned int timeout __read_mostly = 30; 28 + module_param(timeout, uint, S_IRUSR); 29 + MODULE_PARM_DESC(timeout, "timeout for master connection/replies in seconds"); 30 + 31 + int (*nf_nat_snmp_hook)(struct sk_buff *skb, 32 + unsigned int protoff, 33 + struct nf_conn *ct, 34 + enum ip_conntrack_info ctinfo); 35 + EXPORT_SYMBOL_GPL(nf_nat_snmp_hook); 36 + 37 + static int snmp_conntrack_help(struct sk_buff *skb, unsigned int protoff, 38 + struct nf_conn *ct, enum ip_conntrack_info ctinfo) 39 + { 40 + typeof(nf_nat_snmp_hook) nf_nat_snmp; 41 + 42 + nf_conntrack_broadcast_help(skb, protoff, ct, ctinfo, timeout); 43 + 44 + nf_nat_snmp = rcu_dereference(nf_nat_snmp_hook); 45 + if (nf_nat_snmp && ct->status & IPS_NAT_MASK) 46 + return nf_nat_snmp(skb, protoff, ct, ctinfo); 47 + 48 + return NF_ACCEPT; 49 + } 50 + 51 + static struct nf_conntrack_expect_policy exp_policy = { 52 + .max_expected = 1, 53 + }; 54 + 55 + static struct nf_conntrack_helper helper __read_mostly = { 56 + .name = "snmp", 57 + .tuple.src.l3num = NFPROTO_IPV4, 58 + .tuple.src.u.udp.port = cpu_to_be16(SNMP_PORT), 59 + .tuple.dst.protonum = IPPROTO_UDP, 60 + .me = THIS_MODULE, 61 + .help = snmp_conntrack_help, 62 + .expect_policy = &exp_policy, 63 + }; 64 + 65 + static int __init nf_conntrack_snmp_init(void) 66 + { 67 + exp_policy.timeout = timeout; 68 + return nf_conntrack_helper_register(&helper); 69 + } 70 + 71 + static void __exit nf_conntrack_snmp_fini(void) 72 + { 73 + nf_conntrack_helper_unregister(&helper); 74 + } 75 + 76 + module_init(nf_conntrack_snmp_init); 77 + module_exit(nf_conntrack_snmp_fini);