0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/types.h>
0011 #include <linux/netfilter.h>
0012 #include <linux/module.h>
0013 #include <linux/skbuff.h>
0014 #include <linux/vmalloc.h>
0015 #include <linux/stddef.h>
0016 #include <linux/random.h>
0017 #include <linux/err.h>
0018 #include <linux/kernel.h>
0019 #include <linux/netdevice.h>
0020 #include <linux/rculist.h>
0021 #include <linux/rtnetlink.h>
0022
0023 #include <net/netfilter/nf_conntrack.h>
0024 #include <net/netfilter/nf_conntrack_core.h>
0025 #include <net/netfilter/nf_conntrack_ecache.h>
0026 #include <net/netfilter/nf_conntrack_extend.h>
0027 #include <net/netfilter/nf_conntrack_helper.h>
0028 #include <net/netfilter/nf_conntrack_l4proto.h>
0029 #include <net/netfilter/nf_log.h>
0030
0031 static DEFINE_MUTEX(nf_ct_helper_mutex);
0032 struct hlist_head *nf_ct_helper_hash __read_mostly;
0033 EXPORT_SYMBOL_GPL(nf_ct_helper_hash);
0034 unsigned int nf_ct_helper_hsize __read_mostly;
0035 EXPORT_SYMBOL_GPL(nf_ct_helper_hsize);
0036 static unsigned int nf_ct_helper_count __read_mostly;
0037
0038 static DEFINE_MUTEX(nf_ct_nat_helpers_mutex);
0039 static struct list_head nf_ct_nat_helpers __read_mostly;
0040
0041
0042
0043 static unsigned int helper_hash(const struct nf_conntrack_tuple *tuple)
0044 {
0045 return (((tuple->src.l3num << 8) | tuple->dst.protonum) ^
0046 (__force __u16)tuple->src.u.all) % nf_ct_helper_hsize;
0047 }
0048
0049 struct nf_conntrack_helper *
0050 __nf_conntrack_helper_find(const char *name, u16 l3num, u8 protonum)
0051 {
0052 struct nf_conntrack_helper *h;
0053 unsigned int i;
0054
0055 for (i = 0; i < nf_ct_helper_hsize; i++) {
0056 hlist_for_each_entry_rcu(h, &nf_ct_helper_hash[i], hnode) {
0057 if (strcmp(h->name, name))
0058 continue;
0059
0060 if (h->tuple.src.l3num != NFPROTO_UNSPEC &&
0061 h->tuple.src.l3num != l3num)
0062 continue;
0063
0064 if (h->tuple.dst.protonum == protonum)
0065 return h;
0066 }
0067 }
0068 return NULL;
0069 }
0070 EXPORT_SYMBOL_GPL(__nf_conntrack_helper_find);
0071
0072 struct nf_conntrack_helper *
0073 nf_conntrack_helper_try_module_get(const char *name, u16 l3num, u8 protonum)
0074 {
0075 struct nf_conntrack_helper *h;
0076
0077 rcu_read_lock();
0078
0079 h = __nf_conntrack_helper_find(name, l3num, protonum);
0080 #ifdef CONFIG_MODULES
0081 if (h == NULL) {
0082 rcu_read_unlock();
0083 if (request_module("nfct-helper-%s", name) == 0) {
0084 rcu_read_lock();
0085 h = __nf_conntrack_helper_find(name, l3num, protonum);
0086 } else {
0087 return h;
0088 }
0089 }
0090 #endif
0091 if (h != NULL && !try_module_get(h->me))
0092 h = NULL;
0093 if (h != NULL && !refcount_inc_not_zero(&h->refcnt)) {
0094 module_put(h->me);
0095 h = NULL;
0096 }
0097
0098 rcu_read_unlock();
0099
0100 return h;
0101 }
0102 EXPORT_SYMBOL_GPL(nf_conntrack_helper_try_module_get);
0103
0104 void nf_conntrack_helper_put(struct nf_conntrack_helper *helper)
0105 {
0106 refcount_dec(&helper->refcnt);
0107 module_put(helper->me);
0108 }
0109 EXPORT_SYMBOL_GPL(nf_conntrack_helper_put);
0110
0111 static struct nf_conntrack_nat_helper *
0112 nf_conntrack_nat_helper_find(const char *mod_name)
0113 {
0114 struct nf_conntrack_nat_helper *cur;
0115 bool found = false;
0116
0117 list_for_each_entry_rcu(cur, &nf_ct_nat_helpers, list) {
0118 if (!strcmp(cur->mod_name, mod_name)) {
0119 found = true;
0120 break;
0121 }
0122 }
0123 return found ? cur : NULL;
0124 }
0125
0126 int
0127 nf_nat_helper_try_module_get(const char *name, u16 l3num, u8 protonum)
0128 {
0129 struct nf_conntrack_helper *h;
0130 struct nf_conntrack_nat_helper *nat;
0131 char mod_name[NF_CT_HELPER_NAME_LEN];
0132 int ret = 0;
0133
0134 rcu_read_lock();
0135 h = __nf_conntrack_helper_find(name, l3num, protonum);
0136 if (!h) {
0137 rcu_read_unlock();
0138 return -ENOENT;
0139 }
0140
0141 nat = nf_conntrack_nat_helper_find(h->nat_mod_name);
0142 if (!nat) {
0143 snprintf(mod_name, sizeof(mod_name), "%s", h->nat_mod_name);
0144 rcu_read_unlock();
0145 request_module("%s", mod_name);
0146
0147 rcu_read_lock();
0148 nat = nf_conntrack_nat_helper_find(mod_name);
0149 if (!nat) {
0150 rcu_read_unlock();
0151 return -ENOENT;
0152 }
0153 }
0154
0155 if (!try_module_get(nat->module))
0156 ret = -ENOENT;
0157
0158 rcu_read_unlock();
0159 return ret;
0160 }
0161 EXPORT_SYMBOL_GPL(nf_nat_helper_try_module_get);
0162
0163 void nf_nat_helper_put(struct nf_conntrack_helper *helper)
0164 {
0165 struct nf_conntrack_nat_helper *nat;
0166
0167 nat = nf_conntrack_nat_helper_find(helper->nat_mod_name);
0168 if (WARN_ON_ONCE(!nat))
0169 return;
0170
0171 module_put(nat->module);
0172 }
0173 EXPORT_SYMBOL_GPL(nf_nat_helper_put);
0174
0175 struct nf_conn_help *
0176 nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp)
0177 {
0178 struct nf_conn_help *help;
0179
0180 help = nf_ct_ext_add(ct, NF_CT_EXT_HELPER, gfp);
0181 if (help)
0182 INIT_HLIST_HEAD(&help->expectations);
0183 else
0184 pr_debug("failed to add helper extension area");
0185 return help;
0186 }
0187 EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add);
0188
0189 int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
0190 gfp_t flags)
0191 {
0192 struct nf_conntrack_helper *helper = NULL;
0193 struct nf_conn_help *help;
0194
0195
0196
0197
0198
0199
0200
0201 if (test_bit(IPS_HELPER_BIT, &ct->status))
0202 return 0;
0203
0204 if (WARN_ON_ONCE(!tmpl))
0205 return 0;
0206
0207 help = nfct_help(tmpl);
0208 if (help != NULL) {
0209 helper = rcu_dereference(help->helper);
0210 set_bit(IPS_HELPER_BIT, &ct->status);
0211 }
0212
0213 help = nfct_help(ct);
0214
0215 if (helper == NULL) {
0216 if (help)
0217 RCU_INIT_POINTER(help->helper, NULL);
0218 return 0;
0219 }
0220
0221 if (help == NULL) {
0222 help = nf_ct_helper_ext_add(ct, flags);
0223 if (help == NULL)
0224 return -ENOMEM;
0225 } else {
0226
0227
0228
0229 struct nf_conntrack_helper *tmp = rcu_dereference(help->helper);
0230
0231 if (tmp && tmp->help != helper->help) {
0232 RCU_INIT_POINTER(help->helper, NULL);
0233 return 0;
0234 }
0235 }
0236
0237 rcu_assign_pointer(help->helper, helper);
0238
0239 return 0;
0240 }
0241 EXPORT_SYMBOL_GPL(__nf_ct_try_assign_helper);
0242
0243
0244 static int unhelp(struct nf_conn *ct, void *me)
0245 {
0246 struct nf_conn_help *help = nfct_help(ct);
0247
0248 if (help && rcu_dereference_raw(help->helper) == me) {
0249 nf_conntrack_event(IPCT_HELPER, ct);
0250 RCU_INIT_POINTER(help->helper, NULL);
0251 }
0252
0253
0254 return 0;
0255 }
0256
0257 void nf_ct_helper_destroy(struct nf_conn *ct)
0258 {
0259 struct nf_conn_help *help = nfct_help(ct);
0260 struct nf_conntrack_helper *helper;
0261
0262 if (help) {
0263 rcu_read_lock();
0264 helper = rcu_dereference(help->helper);
0265 if (helper && helper->destroy)
0266 helper->destroy(ct);
0267 rcu_read_unlock();
0268 }
0269 }
0270
0271 static LIST_HEAD(nf_ct_helper_expectfn_list);
0272
0273 void nf_ct_helper_expectfn_register(struct nf_ct_helper_expectfn *n)
0274 {
0275 spin_lock_bh(&nf_conntrack_expect_lock);
0276 list_add_rcu(&n->head, &nf_ct_helper_expectfn_list);
0277 spin_unlock_bh(&nf_conntrack_expect_lock);
0278 }
0279 EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_register);
0280
0281 void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n)
0282 {
0283 spin_lock_bh(&nf_conntrack_expect_lock);
0284 list_del_rcu(&n->head);
0285 spin_unlock_bh(&nf_conntrack_expect_lock);
0286 }
0287 EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_unregister);
0288
0289
0290 struct nf_ct_helper_expectfn *
0291 nf_ct_helper_expectfn_find_by_name(const char *name)
0292 {
0293 struct nf_ct_helper_expectfn *cur;
0294 bool found = false;
0295
0296 list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) {
0297 if (!strcmp(cur->name, name)) {
0298 found = true;
0299 break;
0300 }
0301 }
0302 return found ? cur : NULL;
0303 }
0304 EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_name);
0305
0306
0307 struct nf_ct_helper_expectfn *
0308 nf_ct_helper_expectfn_find_by_symbol(const void *symbol)
0309 {
0310 struct nf_ct_helper_expectfn *cur;
0311 bool found = false;
0312
0313 list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) {
0314 if (cur->expectfn == symbol) {
0315 found = true;
0316 break;
0317 }
0318 }
0319 return found ? cur : NULL;
0320 }
0321 EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_symbol);
0322
0323 __printf(3, 4)
0324 void nf_ct_helper_log(struct sk_buff *skb, const struct nf_conn *ct,
0325 const char *fmt, ...)
0326 {
0327 const struct nf_conn_help *help;
0328 const struct nf_conntrack_helper *helper;
0329 struct va_format vaf;
0330 va_list args;
0331
0332 va_start(args, fmt);
0333
0334 vaf.fmt = fmt;
0335 vaf.va = &args;
0336
0337
0338 help = nfct_help(ct);
0339
0340
0341 helper = rcu_dereference(help->helper);
0342
0343 nf_log_packet(nf_ct_net(ct), nf_ct_l3num(ct), 0, skb, NULL, NULL, NULL,
0344 "nf_ct_%s: dropping packet: %pV ", helper->name, &vaf);
0345
0346 va_end(args);
0347 }
0348 EXPORT_SYMBOL_GPL(nf_ct_helper_log);
0349
0350 int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
0351 {
0352 struct nf_conntrack_tuple_mask mask = { .src.u.all = htons(0xFFFF) };
0353 unsigned int h = helper_hash(&me->tuple);
0354 struct nf_conntrack_helper *cur;
0355 int ret = 0, i;
0356
0357 BUG_ON(me->expect_policy == NULL);
0358 BUG_ON(me->expect_class_max >= NF_CT_MAX_EXPECT_CLASSES);
0359 BUG_ON(strlen(me->name) > NF_CT_HELPER_NAME_LEN - 1);
0360
0361 if (me->expect_policy->max_expected > NF_CT_EXPECT_MAX_CNT)
0362 return -EINVAL;
0363
0364 mutex_lock(&nf_ct_helper_mutex);
0365 for (i = 0; i < nf_ct_helper_hsize; i++) {
0366 hlist_for_each_entry(cur, &nf_ct_helper_hash[i], hnode) {
0367 if (!strcmp(cur->name, me->name) &&
0368 (cur->tuple.src.l3num == NFPROTO_UNSPEC ||
0369 cur->tuple.src.l3num == me->tuple.src.l3num) &&
0370 cur->tuple.dst.protonum == me->tuple.dst.protonum) {
0371 ret = -EEXIST;
0372 goto out;
0373 }
0374 }
0375 }
0376
0377
0378 if (!(me->flags & NF_CT_HELPER_F_USERSPACE)) {
0379 hlist_for_each_entry(cur, &nf_ct_helper_hash[h], hnode) {
0380 if (nf_ct_tuple_src_mask_cmp(&cur->tuple, &me->tuple,
0381 &mask)) {
0382 ret = -EEXIST;
0383 goto out;
0384 }
0385 }
0386 }
0387 refcount_set(&me->refcnt, 1);
0388 hlist_add_head_rcu(&me->hnode, &nf_ct_helper_hash[h]);
0389 nf_ct_helper_count++;
0390 out:
0391 mutex_unlock(&nf_ct_helper_mutex);
0392 return ret;
0393 }
0394 EXPORT_SYMBOL_GPL(nf_conntrack_helper_register);
0395
0396 static bool expect_iter_me(struct nf_conntrack_expect *exp, void *data)
0397 {
0398 struct nf_conn_help *help = nfct_help(exp->master);
0399 const struct nf_conntrack_helper *me = data;
0400 const struct nf_conntrack_helper *this;
0401
0402 if (exp->helper == me)
0403 return true;
0404
0405 this = rcu_dereference_protected(help->helper,
0406 lockdep_is_held(&nf_conntrack_expect_lock));
0407 return this == me;
0408 }
0409
0410 void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
0411 {
0412 mutex_lock(&nf_ct_helper_mutex);
0413 hlist_del_rcu(&me->hnode);
0414 nf_ct_helper_count--;
0415 mutex_unlock(&nf_ct_helper_mutex);
0416
0417
0418
0419
0420 synchronize_rcu();
0421
0422 nf_ct_expect_iterate_destroy(expect_iter_me, NULL);
0423 nf_ct_iterate_destroy(unhelp, me);
0424 }
0425 EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
0426
0427 void nf_ct_helper_init(struct nf_conntrack_helper *helper,
0428 u16 l3num, u16 protonum, const char *name,
0429 u16 default_port, u16 spec_port, u32 id,
0430 const struct nf_conntrack_expect_policy *exp_pol,
0431 u32 expect_class_max,
0432 int (*help)(struct sk_buff *skb, unsigned int protoff,
0433 struct nf_conn *ct,
0434 enum ip_conntrack_info ctinfo),
0435 int (*from_nlattr)(struct nlattr *attr,
0436 struct nf_conn *ct),
0437 struct module *module)
0438 {
0439 helper->tuple.src.l3num = l3num;
0440 helper->tuple.dst.protonum = protonum;
0441 helper->tuple.src.u.all = htons(spec_port);
0442 helper->expect_policy = exp_pol;
0443 helper->expect_class_max = expect_class_max;
0444 helper->help = help;
0445 helper->from_nlattr = from_nlattr;
0446 helper->me = module;
0447 snprintf(helper->nat_mod_name, sizeof(helper->nat_mod_name),
0448 NF_NAT_HELPER_PREFIX "%s", name);
0449
0450 if (spec_port == default_port)
0451 snprintf(helper->name, sizeof(helper->name), "%s", name);
0452 else
0453 snprintf(helper->name, sizeof(helper->name), "%s-%u", name, id);
0454 }
0455 EXPORT_SYMBOL_GPL(nf_ct_helper_init);
0456
0457 int nf_conntrack_helpers_register(struct nf_conntrack_helper *helper,
0458 unsigned int n)
0459 {
0460 unsigned int i;
0461 int err = 0;
0462
0463 for (i = 0; i < n; i++) {
0464 err = nf_conntrack_helper_register(&helper[i]);
0465 if (err < 0)
0466 goto err;
0467 }
0468
0469 return err;
0470 err:
0471 if (i > 0)
0472 nf_conntrack_helpers_unregister(helper, i);
0473 return err;
0474 }
0475 EXPORT_SYMBOL_GPL(nf_conntrack_helpers_register);
0476
0477 void nf_conntrack_helpers_unregister(struct nf_conntrack_helper *helper,
0478 unsigned int n)
0479 {
0480 while (n-- > 0)
0481 nf_conntrack_helper_unregister(&helper[n]);
0482 }
0483 EXPORT_SYMBOL_GPL(nf_conntrack_helpers_unregister);
0484
0485 void nf_nat_helper_register(struct nf_conntrack_nat_helper *nat)
0486 {
0487 mutex_lock(&nf_ct_nat_helpers_mutex);
0488 list_add_rcu(&nat->list, &nf_ct_nat_helpers);
0489 mutex_unlock(&nf_ct_nat_helpers_mutex);
0490 }
0491 EXPORT_SYMBOL_GPL(nf_nat_helper_register);
0492
0493 void nf_nat_helper_unregister(struct nf_conntrack_nat_helper *nat)
0494 {
0495 mutex_lock(&nf_ct_nat_helpers_mutex);
0496 list_del_rcu(&nat->list);
0497 mutex_unlock(&nf_ct_nat_helpers_mutex);
0498 }
0499 EXPORT_SYMBOL_GPL(nf_nat_helper_unregister);
0500
0501 int nf_conntrack_helper_init(void)
0502 {
0503 nf_ct_helper_hsize = 1;
0504 nf_ct_helper_hash =
0505 nf_ct_alloc_hashtable(&nf_ct_helper_hsize, 0);
0506 if (!nf_ct_helper_hash)
0507 return -ENOMEM;
0508
0509 INIT_LIST_HEAD(&nf_ct_nat_helpers);
0510 return 0;
0511 }
0512
0513 void nf_conntrack_helper_fini(void)
0514 {
0515 kvfree(nf_ct_helper_hash);
0516 }