Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* Helper handling for netfilter. */
0003 
0004 /* (C) 1999-2001 Paul `Rusty' Russell
0005  * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
0006  * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
0007  * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
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 /* Stupid hash, but collision free for the default registrations of the
0042  * helpers currently in the kernel. */
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     /* We already got a helper explicitly attached. The function
0196      * nf_conntrack_alter_reply - in case NAT is in use - asks for looking
0197      * the helper up again. Since now the user is in full control of
0198      * making consistent helper configurations, skip this automatic
0199      * re-lookup, otherwise we'll lose the helper.
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         /* We only allow helper re-assignment of the same sort since
0227          * we cannot reallocate the helper extension area.
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 /* appropriate ct lock protecting must be taken by caller */
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     /* We are not intended to delete this conntrack. */
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 /* Caller should hold the rcu lock */
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 /* Caller should hold the rcu lock */
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     /* Called from the helper function, this call never fails */
0338     help = nfct_help(ct);
0339 
0340     /* rcu_read_lock()ed by nf_hook_thresh */
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     /* avoid unpredictable behaviour for auto_assign_helper */
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     /* Make sure every nothing is still using the helper unless its a
0418      * connection in the hash.
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; /* gets rounded up to use one page */
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 }