nfnetlink_cthelper.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. /*
  2. * (C) 2012 Pablo Neira Ayuso <pablo@netfilter.org>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License version 2 as
  6. * published by the Free Software Foundation (or any later at your option).
  7. *
  8. * This software has been sponsored by Vyatta Inc. <http://www.vyatta.com>
  9. */
  10. #include <linux/init.h>
  11. #include <linux/module.h>
  12. #include <linux/kernel.h>
  13. #include <linux/skbuff.h>
  14. #include <linux/netlink.h>
  15. #include <linux/rculist.h>
  16. #include <linux/slab.h>
  17. #include <linux/types.h>
  18. #include <linux/list.h>
  19. #include <linux/errno.h>
  20. #include <net/netlink.h>
  21. #include <net/sock.h>
  22. #include <net/netfilter/nf_conntrack_helper.h>
  23. #include <net/netfilter/nf_conntrack_expect.h>
  24. #include <net/netfilter/nf_conntrack_ecache.h>
  25. #include <linux/netfilter/nfnetlink.h>
  26. #include <linux/netfilter/nfnetlink_conntrack.h>
  27. #include <linux/netfilter/nfnetlink_cthelper.h>
  28. MODULE_LICENSE("GPL");
  29. MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
  30. MODULE_DESCRIPTION("nfnl_cthelper: User-space connection tracking helpers");
  31. static int
  32. nfnl_userspace_cthelper(struct sk_buff *skb, unsigned int protoff,
  33. struct nf_conn *ct, enum ip_conntrack_info ctinfo)
  34. {
  35. const struct nf_conn_help *help;
  36. struct nf_conntrack_helper *helper;
  37. help = nfct_help(ct);
  38. if (help == NULL)
  39. return NF_DROP;
  40. /* rcu_read_lock()ed by nf_hook_slow */
  41. helper = rcu_dereference(help->helper);
  42. if (helper == NULL)
  43. return NF_DROP;
  44. /* This is an user-space helper not yet configured, skip. */
  45. if ((helper->flags &
  46. (NF_CT_HELPER_F_USERSPACE | NF_CT_HELPER_F_CONFIGURED)) ==
  47. NF_CT_HELPER_F_USERSPACE)
  48. return NF_ACCEPT;
  49. /* If the user-space helper is not available, don't block traffic. */
  50. return NF_QUEUE_NR(helper->queue_num) | NF_VERDICT_FLAG_QUEUE_BYPASS;
  51. }
  52. static const struct nla_policy nfnl_cthelper_tuple_pol[NFCTH_TUPLE_MAX+1] = {
  53. [NFCTH_TUPLE_L3PROTONUM] = { .type = NLA_U16, },
  54. [NFCTH_TUPLE_L4PROTONUM] = { .type = NLA_U8, },
  55. };
  56. static int
  57. nfnl_cthelper_parse_tuple(struct nf_conntrack_tuple *tuple,
  58. const struct nlattr *attr)
  59. {
  60. int err;
  61. struct nlattr *tb[NFCTH_TUPLE_MAX+1];
  62. err = nla_parse_nested(tb, NFCTH_TUPLE_MAX, attr, nfnl_cthelper_tuple_pol);
  63. if (err < 0)
  64. return err;
  65. if (!tb[NFCTH_TUPLE_L3PROTONUM] || !tb[NFCTH_TUPLE_L4PROTONUM])
  66. return -EINVAL;
  67. /* Not all fields are initialized so first zero the tuple */
  68. memset(tuple, 0, sizeof(struct nf_conntrack_tuple));
  69. tuple->src.l3num = ntohs(nla_get_be16(tb[NFCTH_TUPLE_L3PROTONUM]));
  70. tuple->dst.protonum = nla_get_u8(tb[NFCTH_TUPLE_L4PROTONUM]);
  71. return 0;
  72. }
  73. static int
  74. nfnl_cthelper_from_nlattr(struct nlattr *attr, struct nf_conn *ct)
  75. {
  76. struct nf_conn_help *help = nfct_help(ct);
  77. if (attr == NULL)
  78. return -EINVAL;
  79. if (help->helper->data_len == 0)
  80. return -EINVAL;
  81. memcpy(help->data, nla_data(attr), help->helper->data_len);
  82. return 0;
  83. }
  84. static int
  85. nfnl_cthelper_to_nlattr(struct sk_buff *skb, const struct nf_conn *ct)
  86. {
  87. const struct nf_conn_help *help = nfct_help(ct);
  88. if (help->helper->data_len &&
  89. nla_put(skb, CTA_HELP_INFO, help->helper->data_len, &help->data))
  90. goto nla_put_failure;
  91. return 0;
  92. nla_put_failure:
  93. return -ENOSPC;
  94. }
  95. static const struct nla_policy nfnl_cthelper_expect_pol[NFCTH_POLICY_MAX+1] = {
  96. [NFCTH_POLICY_NAME] = { .type = NLA_NUL_STRING,
  97. .len = NF_CT_HELPER_NAME_LEN-1 },
  98. [NFCTH_POLICY_EXPECT_MAX] = { .type = NLA_U32, },
  99. [NFCTH_POLICY_EXPECT_TIMEOUT] = { .type = NLA_U32, },
  100. };
  101. static int
  102. nfnl_cthelper_expect_policy(struct nf_conntrack_expect_policy *expect_policy,
  103. const struct nlattr *attr)
  104. {
  105. int err;
  106. struct nlattr *tb[NFCTH_POLICY_MAX+1];
  107. err = nla_parse_nested(tb, NFCTH_POLICY_MAX, attr, nfnl_cthelper_expect_pol);
  108. if (err < 0)
  109. return err;
  110. if (!tb[NFCTH_POLICY_NAME] ||
  111. !tb[NFCTH_POLICY_EXPECT_MAX] ||
  112. !tb[NFCTH_POLICY_EXPECT_TIMEOUT])
  113. return -EINVAL;
  114. strncpy(expect_policy->name,
  115. nla_data(tb[NFCTH_POLICY_NAME]), NF_CT_HELPER_NAME_LEN);
  116. expect_policy->max_expected =
  117. ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_MAX]));
  118. expect_policy->timeout =
  119. ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_TIMEOUT]));
  120. return 0;
  121. }
  122. static const struct nla_policy
  123. nfnl_cthelper_expect_policy_set[NFCTH_POLICY_SET_MAX+1] = {
  124. [NFCTH_POLICY_SET_NUM] = { .type = NLA_U32, },
  125. };
  126. static int
  127. nfnl_cthelper_parse_expect_policy(struct nf_conntrack_helper *helper,
  128. const struct nlattr *attr)
  129. {
  130. int i, ret;
  131. struct nf_conntrack_expect_policy *expect_policy;
  132. struct nlattr *tb[NFCTH_POLICY_SET_MAX+1];
  133. ret = nla_parse_nested(tb, NFCTH_POLICY_SET_MAX, attr,
  134. nfnl_cthelper_expect_policy_set);
  135. if (ret < 0)
  136. return ret;
  137. if (!tb[NFCTH_POLICY_SET_NUM])
  138. return -EINVAL;
  139. helper->expect_class_max =
  140. ntohl(nla_get_be32(tb[NFCTH_POLICY_SET_NUM]));
  141. if (helper->expect_class_max != 0 &&
  142. helper->expect_class_max > NF_CT_MAX_EXPECT_CLASSES)
  143. return -EOVERFLOW;
  144. expect_policy = kzalloc(sizeof(struct nf_conntrack_expect_policy) *
  145. helper->expect_class_max, GFP_KERNEL);
  146. if (expect_policy == NULL)
  147. return -ENOMEM;
  148. for (i=0; i<helper->expect_class_max; i++) {
  149. if (!tb[NFCTH_POLICY_SET+i])
  150. goto err;
  151. ret = nfnl_cthelper_expect_policy(&expect_policy[i],
  152. tb[NFCTH_POLICY_SET+i]);
  153. if (ret < 0)
  154. goto err;
  155. }
  156. helper->expect_policy = expect_policy;
  157. return 0;
  158. err:
  159. kfree(expect_policy);
  160. return -EINVAL;
  161. }
  162. static int
  163. nfnl_cthelper_create(const struct nlattr * const tb[],
  164. struct nf_conntrack_tuple *tuple)
  165. {
  166. struct nf_conntrack_helper *helper;
  167. int ret;
  168. if (!tb[NFCTH_TUPLE] || !tb[NFCTH_POLICY] || !tb[NFCTH_PRIV_DATA_LEN])
  169. return -EINVAL;
  170. helper = kzalloc(sizeof(struct nf_conntrack_helper), GFP_KERNEL);
  171. if (helper == NULL)
  172. return -ENOMEM;
  173. ret = nfnl_cthelper_parse_expect_policy(helper, tb[NFCTH_POLICY]);
  174. if (ret < 0)
  175. goto err;
  176. strncpy(helper->name, nla_data(tb[NFCTH_NAME]), NF_CT_HELPER_NAME_LEN);
  177. helper->data_len = ntohl(nla_get_be32(tb[NFCTH_PRIV_DATA_LEN]));
  178. helper->flags |= NF_CT_HELPER_F_USERSPACE;
  179. memcpy(&helper->tuple, tuple, sizeof(struct nf_conntrack_tuple));
  180. helper->me = THIS_MODULE;
  181. helper->help = nfnl_userspace_cthelper;
  182. helper->from_nlattr = nfnl_cthelper_from_nlattr;
  183. helper->to_nlattr = nfnl_cthelper_to_nlattr;
  184. /* Default to queue number zero, this can be updated at any time. */
  185. if (tb[NFCTH_QUEUE_NUM])
  186. helper->queue_num = ntohl(nla_get_be32(tb[NFCTH_QUEUE_NUM]));
  187. if (tb[NFCTH_STATUS]) {
  188. int status = ntohl(nla_get_be32(tb[NFCTH_STATUS]));
  189. switch(status) {
  190. case NFCT_HELPER_STATUS_ENABLED:
  191. helper->flags |= NF_CT_HELPER_F_CONFIGURED;
  192. break;
  193. case NFCT_HELPER_STATUS_DISABLED:
  194. helper->flags &= ~NF_CT_HELPER_F_CONFIGURED;
  195. break;
  196. }
  197. }
  198. ret = nf_conntrack_helper_register(helper);
  199. if (ret < 0)
  200. goto err;
  201. return 0;
  202. err:
  203. kfree(helper);
  204. return ret;
  205. }
  206. static int
  207. nfnl_cthelper_update(const struct nlattr * const tb[],
  208. struct nf_conntrack_helper *helper)
  209. {
  210. int ret;
  211. if (tb[NFCTH_PRIV_DATA_LEN])
  212. return -EBUSY;
  213. if (tb[NFCTH_POLICY]) {
  214. ret = nfnl_cthelper_parse_expect_policy(helper,
  215. tb[NFCTH_POLICY]);
  216. if (ret < 0)
  217. return ret;
  218. }
  219. if (tb[NFCTH_QUEUE_NUM])
  220. helper->queue_num = ntohl(nla_get_be32(tb[NFCTH_QUEUE_NUM]));
  221. if (tb[NFCTH_STATUS]) {
  222. int status = ntohl(nla_get_be32(tb[NFCTH_STATUS]));
  223. switch(status) {
  224. case NFCT_HELPER_STATUS_ENABLED:
  225. helper->flags |= NF_CT_HELPER_F_CONFIGURED;
  226. break;
  227. case NFCT_HELPER_STATUS_DISABLED:
  228. helper->flags &= ~NF_CT_HELPER_F_CONFIGURED;
  229. break;
  230. }
  231. }
  232. return 0;
  233. }
  234. static int
  235. nfnl_cthelper_new(struct sock *nfnl, struct sk_buff *skb,
  236. const struct nlmsghdr *nlh, const struct nlattr * const tb[])
  237. {
  238. const char *helper_name;
  239. struct nf_conntrack_helper *cur, *helper = NULL;
  240. struct nf_conntrack_tuple tuple;
  241. int ret = 0, i;
  242. if (!tb[NFCTH_NAME] || !tb[NFCTH_TUPLE])
  243. return -EINVAL;
  244. helper_name = nla_data(tb[NFCTH_NAME]);
  245. ret = nfnl_cthelper_parse_tuple(&tuple, tb[NFCTH_TUPLE]);
  246. if (ret < 0)
  247. return ret;
  248. rcu_read_lock();
  249. for (i = 0; i < nf_ct_helper_hsize && !helper; i++) {
  250. hlist_for_each_entry_rcu(cur, &nf_ct_helper_hash[i], hnode) {
  251. /* skip non-userspace conntrack helpers. */
  252. if (!(cur->flags & NF_CT_HELPER_F_USERSPACE))
  253. continue;
  254. if (strncmp(cur->name, helper_name,
  255. NF_CT_HELPER_NAME_LEN) != 0)
  256. continue;
  257. if ((tuple.src.l3num != cur->tuple.src.l3num ||
  258. tuple.dst.protonum != cur->tuple.dst.protonum))
  259. continue;
  260. if (nlh->nlmsg_flags & NLM_F_EXCL) {
  261. ret = -EEXIST;
  262. goto err;
  263. }
  264. helper = cur;
  265. break;
  266. }
  267. }
  268. rcu_read_unlock();
  269. if (helper == NULL)
  270. ret = nfnl_cthelper_create(tb, &tuple);
  271. else
  272. ret = nfnl_cthelper_update(tb, helper);
  273. return ret;
  274. err:
  275. rcu_read_unlock();
  276. return ret;
  277. }
  278. static int
  279. nfnl_cthelper_dump_tuple(struct sk_buff *skb,
  280. struct nf_conntrack_helper *helper)
  281. {
  282. struct nlattr *nest_parms;
  283. nest_parms = nla_nest_start(skb, NFCTH_TUPLE | NLA_F_NESTED);
  284. if (nest_parms == NULL)
  285. goto nla_put_failure;
  286. if (nla_put_be16(skb, NFCTH_TUPLE_L3PROTONUM,
  287. htons(helper->tuple.src.l3num)))
  288. goto nla_put_failure;
  289. if (nla_put_u8(skb, NFCTH_TUPLE_L4PROTONUM, helper->tuple.dst.protonum))
  290. goto nla_put_failure;
  291. nla_nest_end(skb, nest_parms);
  292. return 0;
  293. nla_put_failure:
  294. return -1;
  295. }
  296. static int
  297. nfnl_cthelper_dump_policy(struct sk_buff *skb,
  298. struct nf_conntrack_helper *helper)
  299. {
  300. int i;
  301. struct nlattr *nest_parms1, *nest_parms2;
  302. nest_parms1 = nla_nest_start(skb, NFCTH_POLICY | NLA_F_NESTED);
  303. if (nest_parms1 == NULL)
  304. goto nla_put_failure;
  305. if (nla_put_be32(skb, NFCTH_POLICY_SET_NUM,
  306. htonl(helper->expect_class_max)))
  307. goto nla_put_failure;
  308. for (i=0; i<helper->expect_class_max; i++) {
  309. nest_parms2 = nla_nest_start(skb,
  310. (NFCTH_POLICY_SET+i) | NLA_F_NESTED);
  311. if (nest_parms2 == NULL)
  312. goto nla_put_failure;
  313. if (nla_put_string(skb, NFCTH_POLICY_NAME,
  314. helper->expect_policy[i].name))
  315. goto nla_put_failure;
  316. if (nla_put_be32(skb, NFCTH_POLICY_EXPECT_MAX,
  317. htonl(helper->expect_policy[i].max_expected)))
  318. goto nla_put_failure;
  319. if (nla_put_be32(skb, NFCTH_POLICY_EXPECT_TIMEOUT,
  320. htonl(helper->expect_policy[i].timeout)))
  321. goto nla_put_failure;
  322. nla_nest_end(skb, nest_parms2);
  323. }
  324. nla_nest_end(skb, nest_parms1);
  325. return 0;
  326. nla_put_failure:
  327. return -1;
  328. }
  329. static int
  330. nfnl_cthelper_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
  331. int event, struct nf_conntrack_helper *helper)
  332. {
  333. struct nlmsghdr *nlh;
  334. struct nfgenmsg *nfmsg;
  335. unsigned int flags = portid ? NLM_F_MULTI : 0;
  336. int status;
  337. event |= NFNL_SUBSYS_CTHELPER << 8;
  338. nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
  339. if (nlh == NULL)
  340. goto nlmsg_failure;
  341. nfmsg = nlmsg_data(nlh);
  342. nfmsg->nfgen_family = AF_UNSPEC;
  343. nfmsg->version = NFNETLINK_V0;
  344. nfmsg->res_id = 0;
  345. if (nla_put_string(skb, NFCTH_NAME, helper->name))
  346. goto nla_put_failure;
  347. if (nla_put_be32(skb, NFCTH_QUEUE_NUM, htonl(helper->queue_num)))
  348. goto nla_put_failure;
  349. if (nfnl_cthelper_dump_tuple(skb, helper) < 0)
  350. goto nla_put_failure;
  351. if (nfnl_cthelper_dump_policy(skb, helper) < 0)
  352. goto nla_put_failure;
  353. if (nla_put_be32(skb, NFCTH_PRIV_DATA_LEN, htonl(helper->data_len)))
  354. goto nla_put_failure;
  355. if (helper->flags & NF_CT_HELPER_F_CONFIGURED)
  356. status = NFCT_HELPER_STATUS_ENABLED;
  357. else
  358. status = NFCT_HELPER_STATUS_DISABLED;
  359. if (nla_put_be32(skb, NFCTH_STATUS, htonl(status)))
  360. goto nla_put_failure;
  361. nlmsg_end(skb, nlh);
  362. return skb->len;
  363. nlmsg_failure:
  364. nla_put_failure:
  365. nlmsg_cancel(skb, nlh);
  366. return -1;
  367. }
  368. static int
  369. nfnl_cthelper_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
  370. {
  371. struct nf_conntrack_helper *cur, *last;
  372. rcu_read_lock();
  373. last = (struct nf_conntrack_helper *)cb->args[1];
  374. for (; cb->args[0] < nf_ct_helper_hsize; cb->args[0]++) {
  375. restart:
  376. hlist_for_each_entry_rcu(cur,
  377. &nf_ct_helper_hash[cb->args[0]], hnode) {
  378. /* skip non-userspace conntrack helpers. */
  379. if (!(cur->flags & NF_CT_HELPER_F_USERSPACE))
  380. continue;
  381. if (cb->args[1]) {
  382. if (cur != last)
  383. continue;
  384. cb->args[1] = 0;
  385. }
  386. if (nfnl_cthelper_fill_info(skb,
  387. NETLINK_CB(cb->skb).portid,
  388. cb->nlh->nlmsg_seq,
  389. NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
  390. NFNL_MSG_CTHELPER_NEW, cur) < 0) {
  391. cb->args[1] = (unsigned long)cur;
  392. goto out;
  393. }
  394. }
  395. }
  396. if (cb->args[1]) {
  397. cb->args[1] = 0;
  398. goto restart;
  399. }
  400. out:
  401. rcu_read_unlock();
  402. return skb->len;
  403. }
  404. static int
  405. nfnl_cthelper_get(struct sock *nfnl, struct sk_buff *skb,
  406. const struct nlmsghdr *nlh, const struct nlattr * const tb[])
  407. {
  408. int ret = -ENOENT, i;
  409. struct nf_conntrack_helper *cur;
  410. struct sk_buff *skb2;
  411. char *helper_name = NULL;
  412. struct nf_conntrack_tuple tuple;
  413. bool tuple_set = false;
  414. if (nlh->nlmsg_flags & NLM_F_DUMP) {
  415. struct netlink_dump_control c = {
  416. .dump = nfnl_cthelper_dump_table,
  417. };
  418. return netlink_dump_start(nfnl, skb, nlh, &c);
  419. }
  420. if (tb[NFCTH_NAME])
  421. helper_name = nla_data(tb[NFCTH_NAME]);
  422. if (tb[NFCTH_TUPLE]) {
  423. ret = nfnl_cthelper_parse_tuple(&tuple, tb[NFCTH_TUPLE]);
  424. if (ret < 0)
  425. return ret;
  426. tuple_set = true;
  427. }
  428. for (i = 0; i < nf_ct_helper_hsize; i++) {
  429. hlist_for_each_entry_rcu(cur, &nf_ct_helper_hash[i], hnode) {
  430. /* skip non-userspace conntrack helpers. */
  431. if (!(cur->flags & NF_CT_HELPER_F_USERSPACE))
  432. continue;
  433. if (helper_name && strncmp(cur->name, helper_name,
  434. NF_CT_HELPER_NAME_LEN) != 0) {
  435. continue;
  436. }
  437. if (tuple_set &&
  438. (tuple.src.l3num != cur->tuple.src.l3num ||
  439. tuple.dst.protonum != cur->tuple.dst.protonum))
  440. continue;
  441. skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  442. if (skb2 == NULL) {
  443. ret = -ENOMEM;
  444. break;
  445. }
  446. ret = nfnl_cthelper_fill_info(skb2, NETLINK_CB(skb).portid,
  447. nlh->nlmsg_seq,
  448. NFNL_MSG_TYPE(nlh->nlmsg_type),
  449. NFNL_MSG_CTHELPER_NEW, cur);
  450. if (ret <= 0) {
  451. kfree_skb(skb2);
  452. break;
  453. }
  454. ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid,
  455. MSG_DONTWAIT);
  456. if (ret > 0)
  457. ret = 0;
  458. /* this avoids a loop in nfnetlink. */
  459. return ret == -EAGAIN ? -ENOBUFS : ret;
  460. }
  461. }
  462. return ret;
  463. }
  464. static int
  465. nfnl_cthelper_del(struct sock *nfnl, struct sk_buff *skb,
  466. const struct nlmsghdr *nlh, const struct nlattr * const tb[])
  467. {
  468. char *helper_name = NULL;
  469. struct nf_conntrack_helper *cur;
  470. struct hlist_node *tmp;
  471. struct nf_conntrack_tuple tuple;
  472. bool tuple_set = false, found = false;
  473. int i, j = 0, ret;
  474. if (tb[NFCTH_NAME])
  475. helper_name = nla_data(tb[NFCTH_NAME]);
  476. if (tb[NFCTH_TUPLE]) {
  477. ret = nfnl_cthelper_parse_tuple(&tuple, tb[NFCTH_TUPLE]);
  478. if (ret < 0)
  479. return ret;
  480. tuple_set = true;
  481. }
  482. for (i = 0; i < nf_ct_helper_hsize; i++) {
  483. hlist_for_each_entry_safe(cur, tmp, &nf_ct_helper_hash[i],
  484. hnode) {
  485. /* skip non-userspace conntrack helpers. */
  486. if (!(cur->flags & NF_CT_HELPER_F_USERSPACE))
  487. continue;
  488. j++;
  489. if (helper_name && strncmp(cur->name, helper_name,
  490. NF_CT_HELPER_NAME_LEN) != 0) {
  491. continue;
  492. }
  493. if (tuple_set &&
  494. (tuple.src.l3num != cur->tuple.src.l3num ||
  495. tuple.dst.protonum != cur->tuple.dst.protonum))
  496. continue;
  497. found = true;
  498. nf_conntrack_helper_unregister(cur);
  499. }
  500. }
  501. /* Make sure we return success if we flush and there is no helpers */
  502. return (found || j == 0) ? 0 : -ENOENT;
  503. }
  504. static const struct nla_policy nfnl_cthelper_policy[NFCTH_MAX+1] = {
  505. [NFCTH_NAME] = { .type = NLA_NUL_STRING,
  506. .len = NF_CT_HELPER_NAME_LEN-1 },
  507. [NFCTH_QUEUE_NUM] = { .type = NLA_U32, },
  508. };
  509. static const struct nfnl_callback nfnl_cthelper_cb[NFNL_MSG_CTHELPER_MAX] = {
  510. [NFNL_MSG_CTHELPER_NEW] = { .call = nfnl_cthelper_new,
  511. .attr_count = NFCTH_MAX,
  512. .policy = nfnl_cthelper_policy },
  513. [NFNL_MSG_CTHELPER_GET] = { .call = nfnl_cthelper_get,
  514. .attr_count = NFCTH_MAX,
  515. .policy = nfnl_cthelper_policy },
  516. [NFNL_MSG_CTHELPER_DEL] = { .call = nfnl_cthelper_del,
  517. .attr_count = NFCTH_MAX,
  518. .policy = nfnl_cthelper_policy },
  519. };
  520. static const struct nfnetlink_subsystem nfnl_cthelper_subsys = {
  521. .name = "cthelper",
  522. .subsys_id = NFNL_SUBSYS_CTHELPER,
  523. .cb_count = NFNL_MSG_CTHELPER_MAX,
  524. .cb = nfnl_cthelper_cb,
  525. };
  526. MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTHELPER);
  527. static int __init nfnl_cthelper_init(void)
  528. {
  529. int ret;
  530. ret = nfnetlink_subsys_register(&nfnl_cthelper_subsys);
  531. if (ret < 0) {
  532. pr_err("nfnl_cthelper: cannot register with nfnetlink.\n");
  533. goto err_out;
  534. }
  535. return 0;
  536. err_out:
  537. return ret;
  538. }
  539. static void __exit nfnl_cthelper_exit(void)
  540. {
  541. struct nf_conntrack_helper *cur;
  542. struct hlist_node *tmp;
  543. int i;
  544. nfnetlink_subsys_unregister(&nfnl_cthelper_subsys);
  545. for (i=0; i<nf_ct_helper_hsize; i++) {
  546. hlist_for_each_entry_safe(cur, tmp, &nf_ct_helper_hash[i],
  547. hnode) {
  548. /* skip non-userspace conntrack helpers. */
  549. if (!(cur->flags & NF_CT_HELPER_F_USERSPACE))
  550. continue;
  551. nf_conntrack_helper_unregister(cur);
  552. }
  553. }
  554. }
  555. module_init(nfnl_cthelper_init);
  556. module_exit(nfnl_cthelper_exit);