nft_compat.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. /*
  2. * (C) 2012-2013 by 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.
  7. *
  8. * This software has been sponsored by Sophos Astaro <http://www.sophos.com>
  9. */
  10. #include <linux/kernel.h>
  11. #include <linux/init.h>
  12. #include <linux/module.h>
  13. #include <linux/netlink.h>
  14. #include <linux/netfilter.h>
  15. #include <linux/netfilter/nfnetlink.h>
  16. #include <linux/netfilter/nf_tables.h>
  17. #include <linux/netfilter/nf_tables_compat.h>
  18. #include <linux/netfilter/x_tables.h>
  19. #include <linux/netfilter_ipv4/ip_tables.h>
  20. #include <linux/netfilter_ipv6/ip6_tables.h>
  21. #include <net/netfilter/nf_tables.h>
  22. static int nft_compat_chain_validate_dependency(const char *tablename,
  23. const struct nft_chain *chain)
  24. {
  25. const struct nft_base_chain *basechain;
  26. if (!tablename || !(chain->flags & NFT_BASE_CHAIN))
  27. return 0;
  28. basechain = nft_base_chain(chain);
  29. if (strcmp(tablename, "nat") == 0 &&
  30. basechain->type->type != NFT_CHAIN_T_NAT)
  31. return -EINVAL;
  32. return 0;
  33. }
  34. union nft_entry {
  35. struct ipt_entry e4;
  36. struct ip6t_entry e6;
  37. };
  38. static inline void
  39. nft_compat_set_par(struct xt_action_param *par, void *xt, const void *xt_info)
  40. {
  41. par->target = xt;
  42. par->targinfo = xt_info;
  43. par->hotdrop = false;
  44. }
  45. static void nft_target_eval(const struct nft_expr *expr,
  46. struct nft_data data[NFT_REG_MAX + 1],
  47. const struct nft_pktinfo *pkt)
  48. {
  49. void *info = nft_expr_priv(expr);
  50. struct xt_target *target = expr->ops->data;
  51. struct sk_buff *skb = pkt->skb;
  52. int ret;
  53. nft_compat_set_par((struct xt_action_param *)&pkt->xt, target, info);
  54. ret = target->target(skb, &pkt->xt);
  55. if (pkt->xt.hotdrop)
  56. ret = NF_DROP;
  57. switch(ret) {
  58. case XT_CONTINUE:
  59. data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
  60. break;
  61. default:
  62. data[NFT_REG_VERDICT].verdict = ret;
  63. break;
  64. }
  65. return;
  66. }
  67. static const struct nla_policy nft_target_policy[NFTA_TARGET_MAX + 1] = {
  68. [NFTA_TARGET_NAME] = { .type = NLA_NUL_STRING },
  69. [NFTA_TARGET_REV] = { .type = NLA_U32 },
  70. [NFTA_TARGET_INFO] = { .type = NLA_BINARY },
  71. };
  72. static void
  73. nft_target_set_tgchk_param(struct xt_tgchk_param *par,
  74. const struct nft_ctx *ctx,
  75. struct xt_target *target, void *info,
  76. union nft_entry *entry, u8 proto, bool inv)
  77. {
  78. par->net = ctx->net;
  79. par->table = ctx->table->name;
  80. switch (ctx->afi->family) {
  81. case AF_INET:
  82. entry->e4.ip.proto = proto;
  83. entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0;
  84. break;
  85. case AF_INET6:
  86. if (proto)
  87. entry->e6.ipv6.flags |= IP6T_F_PROTO;
  88. entry->e6.ipv6.proto = proto;
  89. entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0;
  90. break;
  91. }
  92. par->entryinfo = entry;
  93. par->target = target;
  94. par->targinfo = info;
  95. if (ctx->chain->flags & NFT_BASE_CHAIN) {
  96. const struct nft_base_chain *basechain =
  97. nft_base_chain(ctx->chain);
  98. const struct nf_hook_ops *ops = &basechain->ops[0];
  99. par->hook_mask = 1 << ops->hooknum;
  100. } else {
  101. par->hook_mask = 0;
  102. }
  103. par->family = ctx->afi->family;
  104. }
  105. static void target_compat_from_user(struct xt_target *t, void *in, void *out)
  106. {
  107. int pad;
  108. memcpy(out, in, t->targetsize);
  109. pad = XT_ALIGN(t->targetsize) - t->targetsize;
  110. if (pad > 0)
  111. memset(out + t->targetsize, 0, pad);
  112. }
  113. static const struct nla_policy nft_rule_compat_policy[NFTA_RULE_COMPAT_MAX + 1] = {
  114. [NFTA_RULE_COMPAT_PROTO] = { .type = NLA_U32 },
  115. [NFTA_RULE_COMPAT_FLAGS] = { .type = NLA_U32 },
  116. };
  117. static int nft_parse_compat(const struct nlattr *attr, u8 *proto, bool *inv)
  118. {
  119. struct nlattr *tb[NFTA_RULE_COMPAT_MAX+1];
  120. u32 flags;
  121. int err;
  122. err = nla_parse_nested(tb, NFTA_RULE_COMPAT_MAX, attr,
  123. nft_rule_compat_policy);
  124. if (err < 0)
  125. return err;
  126. if (!tb[NFTA_RULE_COMPAT_PROTO] || !tb[NFTA_RULE_COMPAT_FLAGS])
  127. return -EINVAL;
  128. flags = ntohl(nla_get_be32(tb[NFTA_RULE_COMPAT_FLAGS]));
  129. if (flags & ~NFT_RULE_COMPAT_F_MASK)
  130. return -EINVAL;
  131. if (flags & NFT_RULE_COMPAT_F_INV)
  132. *inv = true;
  133. *proto = ntohl(nla_get_be32(tb[NFTA_RULE_COMPAT_PROTO]));
  134. return 0;
  135. }
  136. static int
  137. nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
  138. const struct nlattr * const tb[])
  139. {
  140. void *info = nft_expr_priv(expr);
  141. struct xt_target *target = expr->ops->data;
  142. struct xt_tgchk_param par;
  143. size_t size = XT_ALIGN(nla_len(tb[NFTA_TARGET_INFO]));
  144. u8 proto = 0;
  145. bool inv = false;
  146. union nft_entry e = {};
  147. int ret;
  148. ret = nft_compat_chain_validate_dependency(target->table, ctx->chain);
  149. if (ret < 0)
  150. goto err;
  151. target_compat_from_user(target, nla_data(tb[NFTA_TARGET_INFO]), info);
  152. if (ctx->nla[NFTA_RULE_COMPAT]) {
  153. ret = nft_parse_compat(ctx->nla[NFTA_RULE_COMPAT], &proto, &inv);
  154. if (ret < 0)
  155. goto err;
  156. }
  157. nft_target_set_tgchk_param(&par, ctx, target, info, &e, proto, inv);
  158. ret = xt_check_target(&par, size, proto, inv);
  159. if (ret < 0)
  160. goto err;
  161. /* The standard target cannot be used */
  162. if (target->target == NULL) {
  163. ret = -EINVAL;
  164. goto err;
  165. }
  166. return 0;
  167. err:
  168. module_put(target->me);
  169. return ret;
  170. }
  171. static void
  172. nft_target_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
  173. {
  174. struct xt_target *target = expr->ops->data;
  175. void *info = nft_expr_priv(expr);
  176. struct xt_tgdtor_param par;
  177. par.net = ctx->net;
  178. par.target = target;
  179. par.targinfo = info;
  180. par.family = ctx->afi->family;
  181. if (par.target->destroy != NULL)
  182. par.target->destroy(&par);
  183. module_put(target->me);
  184. }
  185. static int nft_target_dump(struct sk_buff *skb, const struct nft_expr *expr)
  186. {
  187. const struct xt_target *target = expr->ops->data;
  188. void *info = nft_expr_priv(expr);
  189. if (nla_put_string(skb, NFTA_TARGET_NAME, target->name) ||
  190. nla_put_be32(skb, NFTA_TARGET_REV, htonl(target->revision)) ||
  191. nla_put(skb, NFTA_TARGET_INFO, XT_ALIGN(target->targetsize), info))
  192. goto nla_put_failure;
  193. return 0;
  194. nla_put_failure:
  195. return -1;
  196. }
  197. static int nft_target_validate(const struct nft_ctx *ctx,
  198. const struct nft_expr *expr,
  199. const struct nft_data **data)
  200. {
  201. struct xt_target *target = expr->ops->data;
  202. unsigned int hook_mask = 0;
  203. int ret;
  204. if (ctx->chain->flags & NFT_BASE_CHAIN) {
  205. const struct nft_base_chain *basechain =
  206. nft_base_chain(ctx->chain);
  207. const struct nf_hook_ops *ops = &basechain->ops[0];
  208. hook_mask = 1 << ops->hooknum;
  209. if (!(hook_mask & target->hooks))
  210. return -EINVAL;
  211. ret = nft_compat_chain_validate_dependency(target->table,
  212. ctx->chain);
  213. if (ret < 0)
  214. return ret;
  215. }
  216. return 0;
  217. }
  218. static void nft_match_eval(const struct nft_expr *expr,
  219. struct nft_data data[NFT_REG_MAX + 1],
  220. const struct nft_pktinfo *pkt)
  221. {
  222. void *info = nft_expr_priv(expr);
  223. struct xt_match *match = expr->ops->data;
  224. struct sk_buff *skb = pkt->skb;
  225. bool ret;
  226. nft_compat_set_par((struct xt_action_param *)&pkt->xt, match, info);
  227. ret = match->match(skb, (struct xt_action_param *)&pkt->xt);
  228. if (pkt->xt.hotdrop) {
  229. data[NFT_REG_VERDICT].verdict = NF_DROP;
  230. return;
  231. }
  232. switch(ret) {
  233. case true:
  234. data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
  235. break;
  236. case false:
  237. data[NFT_REG_VERDICT].verdict = NFT_BREAK;
  238. break;
  239. }
  240. }
  241. static const struct nla_policy nft_match_policy[NFTA_MATCH_MAX + 1] = {
  242. [NFTA_MATCH_NAME] = { .type = NLA_NUL_STRING },
  243. [NFTA_MATCH_REV] = { .type = NLA_U32 },
  244. [NFTA_MATCH_INFO] = { .type = NLA_BINARY },
  245. };
  246. /* struct xt_mtchk_param and xt_tgchk_param look very similar */
  247. static void
  248. nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx,
  249. struct xt_match *match, void *info,
  250. union nft_entry *entry, u8 proto, bool inv)
  251. {
  252. par->net = ctx->net;
  253. par->table = ctx->table->name;
  254. switch (ctx->afi->family) {
  255. case AF_INET:
  256. entry->e4.ip.proto = proto;
  257. entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0;
  258. break;
  259. case AF_INET6:
  260. if (proto)
  261. entry->e6.ipv6.flags |= IP6T_F_PROTO;
  262. entry->e6.ipv6.proto = proto;
  263. entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0;
  264. break;
  265. }
  266. par->entryinfo = entry;
  267. par->match = match;
  268. par->matchinfo = info;
  269. if (ctx->chain->flags & NFT_BASE_CHAIN) {
  270. const struct nft_base_chain *basechain =
  271. nft_base_chain(ctx->chain);
  272. const struct nf_hook_ops *ops = &basechain->ops[0];
  273. par->hook_mask = 1 << ops->hooknum;
  274. } else {
  275. par->hook_mask = 0;
  276. }
  277. par->family = ctx->afi->family;
  278. }
  279. static void match_compat_from_user(struct xt_match *m, void *in, void *out)
  280. {
  281. int pad;
  282. memcpy(out, in, m->matchsize);
  283. pad = XT_ALIGN(m->matchsize) - m->matchsize;
  284. if (pad > 0)
  285. memset(out + m->matchsize, 0, pad);
  286. }
  287. static int
  288. nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
  289. const struct nlattr * const tb[])
  290. {
  291. void *info = nft_expr_priv(expr);
  292. struct xt_match *match = expr->ops->data;
  293. struct xt_mtchk_param par;
  294. size_t size = XT_ALIGN(nla_len(tb[NFTA_MATCH_INFO]));
  295. u8 proto = 0;
  296. bool inv = false;
  297. union nft_entry e = {};
  298. int ret;
  299. ret = nft_compat_chain_validate_dependency(match->table, ctx->chain);
  300. if (ret < 0)
  301. goto err;
  302. match_compat_from_user(match, nla_data(tb[NFTA_MATCH_INFO]), info);
  303. if (ctx->nla[NFTA_RULE_COMPAT]) {
  304. ret = nft_parse_compat(ctx->nla[NFTA_RULE_COMPAT], &proto, &inv);
  305. if (ret < 0)
  306. goto err;
  307. }
  308. nft_match_set_mtchk_param(&par, ctx, match, info, &e, proto, inv);
  309. ret = xt_check_match(&par, size, proto, inv);
  310. if (ret < 0)
  311. goto err;
  312. return 0;
  313. err:
  314. module_put(match->me);
  315. return ret;
  316. }
  317. static void
  318. nft_match_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
  319. {
  320. struct xt_match *match = expr->ops->data;
  321. void *info = nft_expr_priv(expr);
  322. struct xt_mtdtor_param par;
  323. par.net = ctx->net;
  324. par.match = match;
  325. par.matchinfo = info;
  326. par.family = ctx->afi->family;
  327. if (par.match->destroy != NULL)
  328. par.match->destroy(&par);
  329. module_put(match->me);
  330. }
  331. static int nft_match_dump(struct sk_buff *skb, const struct nft_expr *expr)
  332. {
  333. void *info = nft_expr_priv(expr);
  334. struct xt_match *match = expr->ops->data;
  335. if (nla_put_string(skb, NFTA_MATCH_NAME, match->name) ||
  336. nla_put_be32(skb, NFTA_MATCH_REV, htonl(match->revision)) ||
  337. nla_put(skb, NFTA_MATCH_INFO, XT_ALIGN(match->matchsize), info))
  338. goto nla_put_failure;
  339. return 0;
  340. nla_put_failure:
  341. return -1;
  342. }
  343. static int nft_match_validate(const struct nft_ctx *ctx,
  344. const struct nft_expr *expr,
  345. const struct nft_data **data)
  346. {
  347. struct xt_match *match = expr->ops->data;
  348. unsigned int hook_mask = 0;
  349. int ret;
  350. if (ctx->chain->flags & NFT_BASE_CHAIN) {
  351. const struct nft_base_chain *basechain =
  352. nft_base_chain(ctx->chain);
  353. const struct nf_hook_ops *ops = &basechain->ops[0];
  354. hook_mask = 1 << ops->hooknum;
  355. if (!(hook_mask & match->hooks))
  356. return -EINVAL;
  357. ret = nft_compat_chain_validate_dependency(match->table,
  358. ctx->chain);
  359. if (ret < 0)
  360. return ret;
  361. }
  362. return 0;
  363. }
  364. static int
  365. nfnl_compat_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
  366. int event, u16 family, const char *name,
  367. int rev, int target)
  368. {
  369. struct nlmsghdr *nlh;
  370. struct nfgenmsg *nfmsg;
  371. unsigned int flags = portid ? NLM_F_MULTI : 0;
  372. event |= NFNL_SUBSYS_NFT_COMPAT << 8;
  373. nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
  374. if (nlh == NULL)
  375. goto nlmsg_failure;
  376. nfmsg = nlmsg_data(nlh);
  377. nfmsg->nfgen_family = family;
  378. nfmsg->version = NFNETLINK_V0;
  379. nfmsg->res_id = 0;
  380. if (nla_put_string(skb, NFTA_COMPAT_NAME, name) ||
  381. nla_put_be32(skb, NFTA_COMPAT_REV, htonl(rev)) ||
  382. nla_put_be32(skb, NFTA_COMPAT_TYPE, htonl(target)))
  383. goto nla_put_failure;
  384. nlmsg_end(skb, nlh);
  385. return skb->len;
  386. nlmsg_failure:
  387. nla_put_failure:
  388. nlmsg_cancel(skb, nlh);
  389. return -1;
  390. }
  391. static int
  392. nfnl_compat_get(struct sock *nfnl, struct sk_buff *skb,
  393. const struct nlmsghdr *nlh, const struct nlattr * const tb[])
  394. {
  395. int ret = 0, target;
  396. struct nfgenmsg *nfmsg;
  397. const char *fmt;
  398. const char *name;
  399. u32 rev;
  400. struct sk_buff *skb2;
  401. if (tb[NFTA_COMPAT_NAME] == NULL ||
  402. tb[NFTA_COMPAT_REV] == NULL ||
  403. tb[NFTA_COMPAT_TYPE] == NULL)
  404. return -EINVAL;
  405. name = nla_data(tb[NFTA_COMPAT_NAME]);
  406. rev = ntohl(nla_get_be32(tb[NFTA_COMPAT_REV]));
  407. target = ntohl(nla_get_be32(tb[NFTA_COMPAT_TYPE]));
  408. nfmsg = nlmsg_data(nlh);
  409. switch(nfmsg->nfgen_family) {
  410. case AF_INET:
  411. fmt = "ipt_%s";
  412. break;
  413. case AF_INET6:
  414. fmt = "ip6t_%s";
  415. break;
  416. default:
  417. pr_err("nft_compat: unsupported protocol %d\n",
  418. nfmsg->nfgen_family);
  419. return -EINVAL;
  420. }
  421. try_then_request_module(xt_find_revision(nfmsg->nfgen_family, name,
  422. rev, target, &ret),
  423. fmt, name);
  424. if (ret < 0)
  425. return ret;
  426. skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  427. if (skb2 == NULL)
  428. return -ENOMEM;
  429. /* include the best revision for this extension in the message */
  430. if (nfnl_compat_fill_info(skb2, NETLINK_CB(skb).portid,
  431. nlh->nlmsg_seq,
  432. NFNL_MSG_TYPE(nlh->nlmsg_type),
  433. NFNL_MSG_COMPAT_GET,
  434. nfmsg->nfgen_family,
  435. name, ret, target) <= 0) {
  436. kfree_skb(skb2);
  437. return -ENOSPC;
  438. }
  439. ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid,
  440. MSG_DONTWAIT);
  441. if (ret > 0)
  442. ret = 0;
  443. return ret == -EAGAIN ? -ENOBUFS : ret;
  444. }
  445. static const struct nla_policy nfnl_compat_policy_get[NFTA_COMPAT_MAX+1] = {
  446. [NFTA_COMPAT_NAME] = { .type = NLA_NUL_STRING,
  447. .len = NFT_COMPAT_NAME_MAX-1 },
  448. [NFTA_COMPAT_REV] = { .type = NLA_U32 },
  449. [NFTA_COMPAT_TYPE] = { .type = NLA_U32 },
  450. };
  451. static const struct nfnl_callback nfnl_nft_compat_cb[NFNL_MSG_COMPAT_MAX] = {
  452. [NFNL_MSG_COMPAT_GET] = { .call = nfnl_compat_get,
  453. .attr_count = NFTA_COMPAT_MAX,
  454. .policy = nfnl_compat_policy_get },
  455. };
  456. static const struct nfnetlink_subsystem nfnl_compat_subsys = {
  457. .name = "nft-compat",
  458. .subsys_id = NFNL_SUBSYS_NFT_COMPAT,
  459. .cb_count = NFNL_MSG_COMPAT_MAX,
  460. .cb = nfnl_nft_compat_cb,
  461. };
  462. static LIST_HEAD(nft_match_list);
  463. struct nft_xt {
  464. struct list_head head;
  465. struct nft_expr_ops ops;
  466. };
  467. static struct nft_expr_type nft_match_type;
  468. static const struct nft_expr_ops *
  469. nft_match_select_ops(const struct nft_ctx *ctx,
  470. const struct nlattr * const tb[])
  471. {
  472. struct nft_xt *nft_match;
  473. struct xt_match *match;
  474. char *mt_name;
  475. __u32 rev, family;
  476. if (tb[NFTA_MATCH_NAME] == NULL ||
  477. tb[NFTA_MATCH_REV] == NULL ||
  478. tb[NFTA_MATCH_INFO] == NULL)
  479. return ERR_PTR(-EINVAL);
  480. mt_name = nla_data(tb[NFTA_MATCH_NAME]);
  481. rev = ntohl(nla_get_be32(tb[NFTA_MATCH_REV]));
  482. family = ctx->afi->family;
  483. /* Re-use the existing match if it's already loaded. */
  484. list_for_each_entry(nft_match, &nft_match_list, head) {
  485. struct xt_match *match = nft_match->ops.data;
  486. if (strcmp(match->name, mt_name) == 0 &&
  487. match->revision == rev && match->family == family)
  488. return &nft_match->ops;
  489. }
  490. match = xt_request_find_match(family, mt_name, rev);
  491. if (IS_ERR(match))
  492. return ERR_PTR(-ENOENT);
  493. /* This is the first time we use this match, allocate operations */
  494. nft_match = kzalloc(sizeof(struct nft_xt), GFP_KERNEL);
  495. if (nft_match == NULL)
  496. return ERR_PTR(-ENOMEM);
  497. nft_match->ops.type = &nft_match_type;
  498. nft_match->ops.size = NFT_EXPR_SIZE(XT_ALIGN(match->matchsize));
  499. nft_match->ops.eval = nft_match_eval;
  500. nft_match->ops.init = nft_match_init;
  501. nft_match->ops.destroy = nft_match_destroy;
  502. nft_match->ops.dump = nft_match_dump;
  503. nft_match->ops.validate = nft_match_validate;
  504. nft_match->ops.data = match;
  505. list_add(&nft_match->head, &nft_match_list);
  506. return &nft_match->ops;
  507. }
  508. static void nft_match_release(void)
  509. {
  510. struct nft_xt *nft_match, *tmp;
  511. list_for_each_entry_safe(nft_match, tmp, &nft_match_list, head)
  512. kfree(nft_match);
  513. }
  514. static struct nft_expr_type nft_match_type __read_mostly = {
  515. .name = "match",
  516. .select_ops = nft_match_select_ops,
  517. .policy = nft_match_policy,
  518. .maxattr = NFTA_MATCH_MAX,
  519. .owner = THIS_MODULE,
  520. };
  521. static LIST_HEAD(nft_target_list);
  522. static struct nft_expr_type nft_target_type;
  523. static const struct nft_expr_ops *
  524. nft_target_select_ops(const struct nft_ctx *ctx,
  525. const struct nlattr * const tb[])
  526. {
  527. struct nft_xt *nft_target;
  528. struct xt_target *target;
  529. char *tg_name;
  530. __u32 rev, family;
  531. if (tb[NFTA_TARGET_NAME] == NULL ||
  532. tb[NFTA_TARGET_REV] == NULL ||
  533. tb[NFTA_TARGET_INFO] == NULL)
  534. return ERR_PTR(-EINVAL);
  535. tg_name = nla_data(tb[NFTA_TARGET_NAME]);
  536. rev = ntohl(nla_get_be32(tb[NFTA_TARGET_REV]));
  537. family = ctx->afi->family;
  538. /* Re-use the existing target if it's already loaded. */
  539. list_for_each_entry(nft_target, &nft_target_list, head) {
  540. struct xt_target *target = nft_target->ops.data;
  541. if (strcmp(target->name, tg_name) == 0 &&
  542. target->revision == rev && target->family == family)
  543. return &nft_target->ops;
  544. }
  545. target = xt_request_find_target(family, tg_name, rev);
  546. if (IS_ERR(target))
  547. return ERR_PTR(-ENOENT);
  548. /* This is the first time we use this target, allocate operations */
  549. nft_target = kzalloc(sizeof(struct nft_xt), GFP_KERNEL);
  550. if (nft_target == NULL)
  551. return ERR_PTR(-ENOMEM);
  552. nft_target->ops.type = &nft_target_type;
  553. nft_target->ops.size = NFT_EXPR_SIZE(XT_ALIGN(target->targetsize));
  554. nft_target->ops.eval = nft_target_eval;
  555. nft_target->ops.init = nft_target_init;
  556. nft_target->ops.destroy = nft_target_destroy;
  557. nft_target->ops.dump = nft_target_dump;
  558. nft_target->ops.validate = nft_target_validate;
  559. nft_target->ops.data = target;
  560. list_add(&nft_target->head, &nft_target_list);
  561. return &nft_target->ops;
  562. }
  563. static void nft_target_release(void)
  564. {
  565. struct nft_xt *nft_target, *tmp;
  566. list_for_each_entry_safe(nft_target, tmp, &nft_target_list, head)
  567. kfree(nft_target);
  568. }
  569. static struct nft_expr_type nft_target_type __read_mostly = {
  570. .name = "target",
  571. .select_ops = nft_target_select_ops,
  572. .policy = nft_target_policy,
  573. .maxattr = NFTA_TARGET_MAX,
  574. .owner = THIS_MODULE,
  575. };
  576. static int __init nft_compat_module_init(void)
  577. {
  578. int ret;
  579. ret = nft_register_expr(&nft_match_type);
  580. if (ret < 0)
  581. return ret;
  582. ret = nft_register_expr(&nft_target_type);
  583. if (ret < 0)
  584. goto err_match;
  585. ret = nfnetlink_subsys_register(&nfnl_compat_subsys);
  586. if (ret < 0) {
  587. pr_err("nft_compat: cannot register with nfnetlink.\n");
  588. goto err_target;
  589. }
  590. pr_info("nf_tables_compat: (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org>\n");
  591. return ret;
  592. err_target:
  593. nft_unregister_expr(&nft_target_type);
  594. err_match:
  595. nft_unregister_expr(&nft_match_type);
  596. return ret;
  597. }
  598. static void __exit nft_compat_module_exit(void)
  599. {
  600. nfnetlink_subsys_unregister(&nfnl_compat_subsys);
  601. nft_unregister_expr(&nft_target_type);
  602. nft_unregister_expr(&nft_match_type);
  603. nft_match_release();
  604. nft_target_release();
  605. }
  606. MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFT_COMPAT);
  607. module_init(nft_compat_module_init);
  608. module_exit(nft_compat_module_exit);
  609. MODULE_LICENSE("GPL");
  610. MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
  611. MODULE_ALIAS_NFT_EXPR("match");
  612. MODULE_ALIAS_NFT_EXPR("target");