nf_conntrack_helper.c revision e2b7606cdb602a4f69c02cfc8bebe9c63b595e24
1/* Helper handling for netfilter. */ 2 3/* (C) 1999-2001 Paul `Rusty' Russell 4 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> 5 * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 12#include <linux/types.h> 13#include <linux/netfilter.h> 14#include <linux/module.h> 15#include <linux/skbuff.h> 16#include <linux/vmalloc.h> 17#include <linux/stddef.h> 18#include <linux/slab.h> 19#include <linux/random.h> 20#include <linux/err.h> 21#include <linux/kernel.h> 22#include <linux/netdevice.h> 23 24#define ASSERT_READ_LOCK(x) 25#define ASSERT_WRITE_LOCK(x) 26 27#include <net/netfilter/nf_conntrack.h> 28#include <net/netfilter/nf_conntrack_l3proto.h> 29#include <net/netfilter/nf_conntrack_protocol.h> 30#include <net/netfilter/nf_conntrack_helper.h> 31#include <net/netfilter/nf_conntrack_core.h> 32 33static __read_mostly LIST_HEAD(helpers); 34 35struct nf_conntrack_helper * 36__nf_ct_helper_find(const struct nf_conntrack_tuple *tuple) 37{ 38 struct nf_conntrack_helper *h; 39 40 list_for_each_entry(h, &helpers, list) { 41 if (nf_ct_tuple_mask_cmp(tuple, &h->tuple, &h->mask)) 42 return h; 43 } 44 return NULL; 45} 46 47struct nf_conntrack_helper * 48nf_ct_helper_find_get( const struct nf_conntrack_tuple *tuple) 49{ 50 struct nf_conntrack_helper *helper; 51 52 /* need nf_conntrack_lock to assure that helper exists until 53 * try_module_get() is called */ 54 read_lock_bh(&nf_conntrack_lock); 55 56 helper = __nf_ct_helper_find(tuple); 57 if (helper) { 58 /* need to increase module usage count to assure helper will 59 * not go away while the caller is e.g. busy putting a 60 * conntrack in the hash that uses the helper */ 61 if (!try_module_get(helper->me)) 62 helper = NULL; 63 } 64 65 read_unlock_bh(&nf_conntrack_lock); 66 67 return helper; 68} 69 70void nf_ct_helper_put(struct nf_conntrack_helper *helper) 71{ 72 module_put(helper->me); 73} 74 75struct nf_conntrack_helper * 76__nf_conntrack_helper_find_byname(const char *name) 77{ 78 struct nf_conntrack_helper *h; 79 80 list_for_each_entry(h, &helpers, list) { 81 if (!strcmp(h->name, name)) 82 return h; 83 } 84 85 return NULL; 86} 87 88static inline int unhelp(struct nf_conntrack_tuple_hash *i, 89 const struct nf_conntrack_helper *me) 90{ 91 struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(i); 92 struct nf_conn_help *help = nfct_help(ct); 93 94 if (help && help->helper == me) { 95 nf_conntrack_event(IPCT_HELPER, ct); 96 help->helper = NULL; 97 } 98 return 0; 99} 100 101int nf_conntrack_helper_register(struct nf_conntrack_helper *me) 102{ 103 int ret; 104 BUG_ON(me->timeout == 0); 105 106 ret = nf_conntrack_register_cache(NF_CT_F_HELP, "nf_conntrack:help", 107 sizeof(struct nf_conn) 108 + sizeof(struct nf_conn_help) 109 + __alignof__(struct nf_conn_help)); 110 if (ret < 0) { 111 printk(KERN_ERR "nf_conntrack_helper_register: Unable to create slab cache for conntracks\n"); 112 return ret; 113 } 114 write_lock_bh(&nf_conntrack_lock); 115 list_add(&me->list, &helpers); 116 write_unlock_bh(&nf_conntrack_lock); 117 118 return 0; 119} 120 121void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me) 122{ 123 unsigned int i; 124 struct nf_conntrack_tuple_hash *h; 125 struct nf_conntrack_expect *exp, *tmp; 126 127 /* Need write lock here, to delete helper. */ 128 write_lock_bh(&nf_conntrack_lock); 129 list_del(&me->list); 130 131 /* Get rid of expectations */ 132 list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, list) { 133 struct nf_conn_help *help = nfct_help(exp->master); 134 if (help->helper == me && del_timer(&exp->timeout)) { 135 nf_ct_unlink_expect(exp); 136 nf_conntrack_expect_put(exp); 137 } 138 } 139 140 /* Get rid of expecteds, set helpers to NULL. */ 141 list_for_each_entry(h, &unconfirmed, list) 142 unhelp(h, me); 143 for (i = 0; i < nf_conntrack_htable_size; i++) { 144 list_for_each_entry(h, &nf_conntrack_hash[i], list) 145 unhelp(h, me); 146 } 147 write_unlock_bh(&nf_conntrack_lock); 148 149 /* Someone could be still looking at the helper in a bh. */ 150 synchronize_net(); 151} 152