nf_conntrack_helper.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* Helper handling for netfilter. */
  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. * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
  7. */
  8. #include <linux/types.h>
  9. #include <linux/netfilter.h>
  10. #include <linux/module.h>
  11. #include <linux/skbuff.h>
  12. #include <linux/vmalloc.h>
  13. #include <linux/stddef.h>
  14. #include <linux/random.h>
  15. #include <linux/err.h>
  16. #include <linux/kernel.h>
  17. #include <linux/netdevice.h>
  18. #include <linux/rculist.h>
  19. #include <linux/rtnetlink.h>
  20. #include <net/netfilter/nf_conntrack.h>
  21. #include <net/netfilter/nf_conntrack_core.h>
  22. #include <net/netfilter/nf_conntrack_ecache.h>
  23. #include <net/netfilter/nf_conntrack_extend.h>
  24. #include <net/netfilter/nf_conntrack_helper.h>
  25. #include <net/netfilter/nf_conntrack_l4proto.h>
  26. #include <net/netfilter/nf_log.h>
  27. static DEFINE_MUTEX(nf_ct_helper_mutex);
  28. struct hlist_head *nf_ct_helper_hash __read_mostly;
  29. EXPORT_SYMBOL_GPL(nf_ct_helper_hash);
  30. unsigned int nf_ct_helper_hsize __read_mostly;
  31. EXPORT_SYMBOL_GPL(nf_ct_helper_hsize);
  32. static unsigned int nf_ct_helper_count __read_mostly;
  33. static bool nf_ct_auto_assign_helper __read_mostly = false;
  34. module_param_named(nf_conntrack_helper, nf_ct_auto_assign_helper, bool, 0644);
  35. MODULE_PARM_DESC(nf_conntrack_helper,
  36. "Enable automatic conntrack helper assignment (default 0)");
  37. static DEFINE_MUTEX(nf_ct_nat_helpers_mutex);
  38. static struct list_head nf_ct_nat_helpers __read_mostly;
  39. /* Stupid hash, but collision free for the default registrations of the
  40. * helpers currently in the kernel. */
  41. static unsigned int helper_hash(const struct nf_conntrack_tuple *tuple)
  42. {
  43. return (((tuple->src.l3num << 8) | tuple->dst.protonum) ^
  44. (__force __u16)tuple->src.u.all) % nf_ct_helper_hsize;
  45. }
  46. static struct nf_conntrack_helper *
  47. __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple)
  48. {
  49. struct nf_conntrack_helper *helper;
  50. struct nf_conntrack_tuple_mask mask = { .src.u.all = htons(0xFFFF) };
  51. unsigned int h;
  52. if (!nf_ct_helper_count)
  53. return NULL;
  54. h = helper_hash(tuple);
  55. hlist_for_each_entry_rcu(helper, &nf_ct_helper_hash[h], hnode) {
  56. if (nf_ct_tuple_src_mask_cmp(tuple, &helper->tuple, &mask))
  57. return helper;
  58. }
  59. return NULL;
  60. }
  61. struct nf_conntrack_helper *
  62. __nf_conntrack_helper_find(const char *name, u16 l3num, u8 protonum)
  63. {
  64. struct nf_conntrack_helper *h;
  65. unsigned int i;
  66. for (i = 0; i < nf_ct_helper_hsize; i++) {
  67. hlist_for_each_entry_rcu(h, &nf_ct_helper_hash[i], hnode) {
  68. if (strcmp(h->name, name))
  69. continue;
  70. if (h->tuple.src.l3num != NFPROTO_UNSPEC &&
  71. h->tuple.src.l3num != l3num)
  72. continue;
  73. if (h->tuple.dst.protonum == protonum)
  74. return h;
  75. }
  76. }
  77. return NULL;
  78. }
  79. EXPORT_SYMBOL_GPL(__nf_conntrack_helper_find);
  80. struct nf_conntrack_helper *
  81. nf_conntrack_helper_try_module_get(const char *name, u16 l3num, u8 protonum)
  82. {
  83. struct nf_conntrack_helper *h;
  84. rcu_read_lock();
  85. h = __nf_conntrack_helper_find(name, l3num, protonum);
  86. #ifdef CONFIG_MODULES
  87. if (h == NULL) {
  88. rcu_read_unlock();
  89. if (request_module("nfct-helper-%s", name) == 0) {
  90. rcu_read_lock();
  91. h = __nf_conntrack_helper_find(name, l3num, protonum);
  92. } else {
  93. return h;
  94. }
  95. }
  96. #endif
  97. if (h != NULL && !try_module_get(h->me))
  98. h = NULL;
  99. if (h != NULL && !refcount_inc_not_zero(&h->refcnt)) {
  100. module_put(h->me);
  101. h = NULL;
  102. }
  103. rcu_read_unlock();
  104. return h;
  105. }
  106. EXPORT_SYMBOL_GPL(nf_conntrack_helper_try_module_get);
  107. void nf_conntrack_helper_put(struct nf_conntrack_helper *helper)
  108. {
  109. refcount_dec(&helper->refcnt);
  110. module_put(helper->me);
  111. }
  112. EXPORT_SYMBOL_GPL(nf_conntrack_helper_put);
  113. static struct nf_conntrack_nat_helper *
  114. nf_conntrack_nat_helper_find(const char *mod_name)
  115. {
  116. struct nf_conntrack_nat_helper *cur;
  117. bool found = false;
  118. list_for_each_entry_rcu(cur, &nf_ct_nat_helpers, list) {
  119. if (!strcmp(cur->mod_name, mod_name)) {
  120. found = true;
  121. break;
  122. }
  123. }
  124. return found ? cur : NULL;
  125. }
  126. int
  127. nf_nat_helper_try_module_get(const char *name, u16 l3num, u8 protonum)
  128. {
  129. struct nf_conntrack_helper *h;
  130. struct nf_conntrack_nat_helper *nat;
  131. char mod_name[NF_CT_HELPER_NAME_LEN];
  132. int ret = 0;
  133. rcu_read_lock();
  134. h = __nf_conntrack_helper_find(name, l3num, protonum);
  135. if (!h) {
  136. rcu_read_unlock();
  137. return -ENOENT;
  138. }
  139. nat = nf_conntrack_nat_helper_find(h->nat_mod_name);
  140. if (!nat) {
  141. snprintf(mod_name, sizeof(mod_name), "%s", h->nat_mod_name);
  142. rcu_read_unlock();
  143. request_module(mod_name);
  144. rcu_read_lock();
  145. nat = nf_conntrack_nat_helper_find(mod_name);
  146. if (!nat) {
  147. rcu_read_unlock();
  148. return -ENOENT;
  149. }
  150. }
  151. if (!try_module_get(nat->module))
  152. ret = -ENOENT;
  153. rcu_read_unlock();
  154. return ret;
  155. }
  156. EXPORT_SYMBOL_GPL(nf_nat_helper_try_module_get);
  157. void nf_nat_helper_put(struct nf_conntrack_helper *helper)
  158. {
  159. struct nf_conntrack_nat_helper *nat;
  160. nat = nf_conntrack_nat_helper_find(helper->nat_mod_name);
  161. if (WARN_ON_ONCE(!nat))
  162. return;
  163. module_put(nat->module);
  164. }
  165. EXPORT_SYMBOL_GPL(nf_nat_helper_put);
  166. struct nf_conn_help *
  167. nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp)
  168. {
  169. struct nf_conn_help *help;
  170. help = nf_ct_ext_add(ct, NF_CT_EXT_HELPER, gfp);
  171. if (help)
  172. INIT_HLIST_HEAD(&help->expectations);
  173. else
  174. pr_debug("failed to add helper extension area");
  175. return help;
  176. }
  177. EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add);
  178. static struct nf_conntrack_helper *
  179. nf_ct_lookup_helper(struct nf_conn *ct, struct net *net)
  180. {
  181. if (!net->ct.sysctl_auto_assign_helper) {
  182. if (net->ct.auto_assign_helper_warned)
  183. return NULL;
  184. if (!__nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple))
  185. return NULL;
  186. pr_info("nf_conntrack: default automatic helper assignment "
  187. "has been turned off for security reasons and CT-based "
  188. " firewall rule not found. Use the iptables CT target "
  189. "to attach helpers instead.\n");
  190. net->ct.auto_assign_helper_warned = 1;
  191. return NULL;
  192. }
  193. return __nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
  194. }
  195. int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
  196. gfp_t flags)
  197. {
  198. struct nf_conntrack_helper *helper = NULL;
  199. struct nf_conn_help *help;
  200. struct net *net = nf_ct_net(ct);
  201. /* We already got a helper explicitly attached. The function
  202. * nf_conntrack_alter_reply - in case NAT is in use - asks for looking
  203. * the helper up again. Since now the user is in full control of
  204. * making consistent helper configurations, skip this automatic
  205. * re-lookup, otherwise we'll lose the helper.
  206. */
  207. if (test_bit(IPS_HELPER_BIT, &ct->status))
  208. return 0;
  209. if (tmpl != NULL) {
  210. help = nfct_help(tmpl);
  211. if (help != NULL) {
  212. helper = help->helper;
  213. set_bit(IPS_HELPER_BIT, &ct->status);
  214. }
  215. }
  216. help = nfct_help(ct);
  217. if (helper == NULL) {
  218. helper = nf_ct_lookup_helper(ct, net);
  219. if (helper == NULL) {
  220. if (help)
  221. RCU_INIT_POINTER(help->helper, NULL);
  222. return 0;
  223. }
  224. }
  225. if (help == NULL) {
  226. help = nf_ct_helper_ext_add(ct, flags);
  227. if (help == NULL)
  228. return -ENOMEM;
  229. } else {
  230. /* We only allow helper re-assignment of the same sort since
  231. * we cannot reallocate the helper extension area.
  232. */
  233. struct nf_conntrack_helper *tmp = rcu_dereference(help->helper);
  234. if (tmp && tmp->help != helper->help) {
  235. RCU_INIT_POINTER(help->helper, NULL);
  236. return 0;
  237. }
  238. }
  239. rcu_assign_pointer(help->helper, helper);
  240. return 0;
  241. }
  242. EXPORT_SYMBOL_GPL(__nf_ct_try_assign_helper);
  243. /* appropriate ct lock protecting must be taken by caller */
  244. static int unhelp(struct nf_conn *ct, void *me)
  245. {
  246. struct nf_conn_help *help = nfct_help(ct);
  247. if (help && rcu_dereference_raw(help->helper) == me) {
  248. nf_conntrack_event(IPCT_HELPER, ct);
  249. RCU_INIT_POINTER(help->helper, NULL);
  250. }
  251. /* We are not intended to delete this conntrack. */
  252. return 0;
  253. }
  254. void nf_ct_helper_destroy(struct nf_conn *ct)
  255. {
  256. struct nf_conn_help *help = nfct_help(ct);
  257. struct nf_conntrack_helper *helper;
  258. if (help) {
  259. rcu_read_lock();
  260. helper = rcu_dereference(help->helper);
  261. if (helper && helper->destroy)
  262. helper->destroy(ct);
  263. rcu_read_unlock();
  264. }
  265. }
  266. static LIST_HEAD(nf_ct_helper_expectfn_list);
  267. void nf_ct_helper_expectfn_register(struct nf_ct_helper_expectfn *n)
  268. {
  269. spin_lock_bh(&nf_conntrack_expect_lock);
  270. list_add_rcu(&n->head, &nf_ct_helper_expectfn_list);
  271. spin_unlock_bh(&nf_conntrack_expect_lock);
  272. }
  273. EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_register);
  274. void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n)
  275. {
  276. spin_lock_bh(&nf_conntrack_expect_lock);
  277. list_del_rcu(&n->head);
  278. spin_unlock_bh(&nf_conntrack_expect_lock);
  279. }
  280. EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_unregister);
  281. /* Caller should hold the rcu lock */
  282. struct nf_ct_helper_expectfn *
  283. nf_ct_helper_expectfn_find_by_name(const char *name)
  284. {
  285. struct nf_ct_helper_expectfn *cur;
  286. bool found = false;
  287. list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) {
  288. if (!strcmp(cur->name, name)) {
  289. found = true;
  290. break;
  291. }
  292. }
  293. return found ? cur : NULL;
  294. }
  295. EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_name);
  296. /* Caller should hold the rcu lock */
  297. struct nf_ct_helper_expectfn *
  298. nf_ct_helper_expectfn_find_by_symbol(const void *symbol)
  299. {
  300. struct nf_ct_helper_expectfn *cur;
  301. bool found = false;
  302. list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) {
  303. if (cur->expectfn == symbol) {
  304. found = true;
  305. break;
  306. }
  307. }
  308. return found ? cur : NULL;
  309. }
  310. EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_symbol);
  311. __printf(3, 4)
  312. void nf_ct_helper_log(struct sk_buff *skb, const struct nf_conn *ct,
  313. const char *fmt, ...)
  314. {
  315. const struct nf_conn_help *help;
  316. const struct nf_conntrack_helper *helper;
  317. struct va_format vaf;
  318. va_list args;
  319. va_start(args, fmt);
  320. vaf.fmt = fmt;
  321. vaf.va = &args;
  322. /* Called from the helper function, this call never fails */
  323. help = nfct_help(ct);
  324. /* rcu_read_lock()ed by nf_hook_thresh */
  325. helper = rcu_dereference(help->helper);
  326. nf_log_packet(nf_ct_net(ct), nf_ct_l3num(ct), 0, skb, NULL, NULL, NULL,
  327. "nf_ct_%s: dropping packet: %pV ", helper->name, &vaf);
  328. va_end(args);
  329. }
  330. EXPORT_SYMBOL_GPL(nf_ct_helper_log);
  331. int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
  332. {
  333. struct nf_conntrack_tuple_mask mask = { .src.u.all = htons(0xFFFF) };
  334. unsigned int h = helper_hash(&me->tuple);
  335. struct nf_conntrack_helper *cur;
  336. int ret = 0, i;
  337. BUG_ON(me->expect_policy == NULL);
  338. BUG_ON(me->expect_class_max >= NF_CT_MAX_EXPECT_CLASSES);
  339. BUG_ON(strlen(me->name) > NF_CT_HELPER_NAME_LEN - 1);
  340. if (me->expect_policy->max_expected > NF_CT_EXPECT_MAX_CNT)
  341. return -EINVAL;
  342. mutex_lock(&nf_ct_helper_mutex);
  343. for (i = 0; i < nf_ct_helper_hsize; i++) {
  344. hlist_for_each_entry(cur, &nf_ct_helper_hash[i], hnode) {
  345. if (!strcmp(cur->name, me->name) &&
  346. (cur->tuple.src.l3num == NFPROTO_UNSPEC ||
  347. cur->tuple.src.l3num == me->tuple.src.l3num) &&
  348. cur->tuple.dst.protonum == me->tuple.dst.protonum) {
  349. ret = -EEXIST;
  350. goto out;
  351. }
  352. }
  353. }
  354. /* avoid unpredictable behaviour for auto_assign_helper */
  355. if (!(me->flags & NF_CT_HELPER_F_USERSPACE)) {
  356. hlist_for_each_entry(cur, &nf_ct_helper_hash[h], hnode) {
  357. if (nf_ct_tuple_src_mask_cmp(&cur->tuple, &me->tuple,
  358. &mask)) {
  359. ret = -EEXIST;
  360. goto out;
  361. }
  362. }
  363. }
  364. refcount_set(&me->refcnt, 1);
  365. hlist_add_head_rcu(&me->hnode, &nf_ct_helper_hash[h]);
  366. nf_ct_helper_count++;
  367. out:
  368. mutex_unlock(&nf_ct_helper_mutex);
  369. return ret;
  370. }
  371. EXPORT_SYMBOL_GPL(nf_conntrack_helper_register);
  372. static bool expect_iter_me(struct nf_conntrack_expect *exp, void *data)
  373. {
  374. struct nf_conn_help *help = nfct_help(exp->master);
  375. const struct nf_conntrack_helper *me = data;
  376. const struct nf_conntrack_helper *this;
  377. if (exp->helper == me)
  378. return true;
  379. this = rcu_dereference_protected(help->helper,
  380. lockdep_is_held(&nf_conntrack_expect_lock));
  381. return this == me;
  382. }
  383. void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
  384. {
  385. mutex_lock(&nf_ct_helper_mutex);
  386. hlist_del_rcu(&me->hnode);
  387. nf_ct_helper_count--;
  388. mutex_unlock(&nf_ct_helper_mutex);
  389. /* Make sure every nothing is still using the helper unless its a
  390. * connection in the hash.
  391. */
  392. synchronize_rcu();
  393. nf_ct_expect_iterate_destroy(expect_iter_me, NULL);
  394. nf_ct_iterate_destroy(unhelp, me);
  395. /* Maybe someone has gotten the helper already when unhelp above.
  396. * So need to wait it.
  397. */
  398. synchronize_rcu();
  399. }
  400. EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
  401. void nf_ct_helper_init(struct nf_conntrack_helper *helper,
  402. u16 l3num, u16 protonum, const char *name,
  403. u16 default_port, u16 spec_port, u32 id,
  404. const struct nf_conntrack_expect_policy *exp_pol,
  405. u32 expect_class_max,
  406. int (*help)(struct sk_buff *skb, unsigned int protoff,
  407. struct nf_conn *ct,
  408. enum ip_conntrack_info ctinfo),
  409. int (*from_nlattr)(struct nlattr *attr,
  410. struct nf_conn *ct),
  411. struct module *module)
  412. {
  413. helper->tuple.src.l3num = l3num;
  414. helper->tuple.dst.protonum = protonum;
  415. helper->tuple.src.u.all = htons(spec_port);
  416. helper->expect_policy = exp_pol;
  417. helper->expect_class_max = expect_class_max;
  418. helper->help = help;
  419. helper->from_nlattr = from_nlattr;
  420. helper->me = module;
  421. snprintf(helper->nat_mod_name, sizeof(helper->nat_mod_name),
  422. NF_NAT_HELPER_PREFIX "%s", name);
  423. if (spec_port == default_port)
  424. snprintf(helper->name, sizeof(helper->name), "%s", name);
  425. else
  426. snprintf(helper->name, sizeof(helper->name), "%s-%u", name, id);
  427. }
  428. EXPORT_SYMBOL_GPL(nf_ct_helper_init);
  429. int nf_conntrack_helpers_register(struct nf_conntrack_helper *helper,
  430. unsigned int n)
  431. {
  432. unsigned int i;
  433. int err = 0;
  434. for (i = 0; i < n; i++) {
  435. err = nf_conntrack_helper_register(&helper[i]);
  436. if (err < 0)
  437. goto err;
  438. }
  439. return err;
  440. err:
  441. if (i > 0)
  442. nf_conntrack_helpers_unregister(helper, i);
  443. return err;
  444. }
  445. EXPORT_SYMBOL_GPL(nf_conntrack_helpers_register);
  446. void nf_conntrack_helpers_unregister(struct nf_conntrack_helper *helper,
  447. unsigned int n)
  448. {
  449. while (n-- > 0)
  450. nf_conntrack_helper_unregister(&helper[n]);
  451. }
  452. EXPORT_SYMBOL_GPL(nf_conntrack_helpers_unregister);
  453. void nf_nat_helper_register(struct nf_conntrack_nat_helper *nat)
  454. {
  455. mutex_lock(&nf_ct_nat_helpers_mutex);
  456. list_add_rcu(&nat->list, &nf_ct_nat_helpers);
  457. mutex_unlock(&nf_ct_nat_helpers_mutex);
  458. }
  459. EXPORT_SYMBOL_GPL(nf_nat_helper_register);
  460. void nf_nat_helper_unregister(struct nf_conntrack_nat_helper *nat)
  461. {
  462. mutex_lock(&nf_ct_nat_helpers_mutex);
  463. list_del_rcu(&nat->list);
  464. mutex_unlock(&nf_ct_nat_helpers_mutex);
  465. }
  466. EXPORT_SYMBOL_GPL(nf_nat_helper_unregister);
  467. static const struct nf_ct_ext_type helper_extend = {
  468. .len = sizeof(struct nf_conn_help),
  469. .align = __alignof__(struct nf_conn_help),
  470. .id = NF_CT_EXT_HELPER,
  471. };
  472. void nf_conntrack_helper_pernet_init(struct net *net)
  473. {
  474. net->ct.auto_assign_helper_warned = false;
  475. net->ct.sysctl_auto_assign_helper = nf_ct_auto_assign_helper;
  476. }
  477. int nf_conntrack_helper_init(void)
  478. {
  479. int ret;
  480. nf_ct_helper_hsize = 1; /* gets rounded up to use one page */
  481. nf_ct_helper_hash =
  482. nf_ct_alloc_hashtable(&nf_ct_helper_hsize, 0);
  483. if (!nf_ct_helper_hash)
  484. return -ENOMEM;
  485. ret = nf_ct_extend_register(&helper_extend);
  486. if (ret < 0) {
  487. pr_err("nf_ct_helper: Unable to register helper extension.\n");
  488. goto out_extend;
  489. }
  490. INIT_LIST_HEAD(&nf_ct_nat_helpers);
  491. return 0;
  492. out_extend:
  493. kvfree(nf_ct_helper_hash);
  494. return ret;
  495. }
  496. void nf_conntrack_helper_fini(void)
  497. {
  498. nf_ct_extend_unregister(&helper_extend);
  499. kvfree(nf_ct_helper_hash);
  500. }