nft_objref.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /*
  2. * Copyright (c) 2012-2016 Pablo Neira Ayuso <pablo@netfilter.org>
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms and conditions of the GNU General Public License,
  6. * version 2, as published by the Free Software Foundation.
  7. */
  8. #include <linux/init.h>
  9. #include <linux/module.h>
  10. #include <linux/skbuff.h>
  11. #include <linux/netlink.h>
  12. #include <linux/netfilter.h>
  13. #include <linux/netfilter/nf_tables.h>
  14. #include <net/netfilter/nf_tables.h>
  15. #define nft_objref_priv(expr) *((struct nft_object **)nft_expr_priv(expr))
  16. static void nft_objref_eval(const struct nft_expr *expr,
  17. struct nft_regs *regs,
  18. const struct nft_pktinfo *pkt)
  19. {
  20. struct nft_object *obj = nft_objref_priv(expr);
  21. obj->ops->eval(obj, regs, pkt);
  22. }
  23. static int nft_objref_init(const struct nft_ctx *ctx,
  24. const struct nft_expr *expr,
  25. const struct nlattr * const tb[])
  26. {
  27. struct nft_object *obj = nft_objref_priv(expr);
  28. u8 genmask = nft_genmask_next(ctx->net);
  29. u32 objtype;
  30. if (!tb[NFTA_OBJREF_IMM_NAME] ||
  31. !tb[NFTA_OBJREF_IMM_TYPE])
  32. return -EINVAL;
  33. objtype = ntohl(nla_get_be32(tb[NFTA_OBJREF_IMM_TYPE]));
  34. obj = nft_obj_lookup(ctx->table, tb[NFTA_OBJREF_IMM_NAME], objtype,
  35. genmask);
  36. if (IS_ERR(obj))
  37. return -ENOENT;
  38. nft_objref_priv(expr) = obj;
  39. obj->use++;
  40. return 0;
  41. }
  42. static int nft_objref_dump(struct sk_buff *skb, const struct nft_expr *expr)
  43. {
  44. const struct nft_object *obj = nft_objref_priv(expr);
  45. if (nla_put_string(skb, NFTA_OBJREF_IMM_NAME, obj->name) ||
  46. nla_put_be32(skb, NFTA_OBJREF_IMM_TYPE,
  47. htonl(obj->ops->type->type)))
  48. goto nla_put_failure;
  49. return 0;
  50. nla_put_failure:
  51. return -1;
  52. }
  53. static void nft_objref_deactivate(const struct nft_ctx *ctx,
  54. const struct nft_expr *expr,
  55. enum nft_trans_phase phase)
  56. {
  57. struct nft_object *obj = nft_objref_priv(expr);
  58. if (phase == NFT_TRANS_COMMIT)
  59. return;
  60. obj->use--;
  61. }
  62. static void nft_objref_activate(const struct nft_ctx *ctx,
  63. const struct nft_expr *expr)
  64. {
  65. struct nft_object *obj = nft_objref_priv(expr);
  66. obj->use++;
  67. }
  68. static struct nft_expr_type nft_objref_type;
  69. static const struct nft_expr_ops nft_objref_ops = {
  70. .type = &nft_objref_type,
  71. .size = NFT_EXPR_SIZE(sizeof(struct nft_object *)),
  72. .eval = nft_objref_eval,
  73. .init = nft_objref_init,
  74. .activate = nft_objref_activate,
  75. .deactivate = nft_objref_deactivate,
  76. .dump = nft_objref_dump,
  77. };
  78. struct nft_objref_map {
  79. struct nft_set *set;
  80. enum nft_registers sreg:8;
  81. struct nft_set_binding binding;
  82. };
  83. static void nft_objref_map_eval(const struct nft_expr *expr,
  84. struct nft_regs *regs,
  85. const struct nft_pktinfo *pkt)
  86. {
  87. struct nft_objref_map *priv = nft_expr_priv(expr);
  88. const struct nft_set *set = priv->set;
  89. const struct nft_set_ext *ext;
  90. struct nft_object *obj;
  91. bool found;
  92. found = set->ops->lookup(nft_net(pkt), set, &regs->data[priv->sreg],
  93. &ext);
  94. if (!found) {
  95. regs->verdict.code = NFT_BREAK;
  96. return;
  97. }
  98. obj = *nft_set_ext_obj(ext);
  99. obj->ops->eval(obj, regs, pkt);
  100. }
  101. static int nft_objref_map_init(const struct nft_ctx *ctx,
  102. const struct nft_expr *expr,
  103. const struct nlattr * const tb[])
  104. {
  105. struct nft_objref_map *priv = nft_expr_priv(expr);
  106. u8 genmask = nft_genmask_next(ctx->net);
  107. struct nft_set *set;
  108. int err;
  109. set = nft_set_lookup_global(ctx->net, ctx->table,
  110. tb[NFTA_OBJREF_SET_NAME],
  111. tb[NFTA_OBJREF_SET_ID], genmask);
  112. if (IS_ERR(set))
  113. return PTR_ERR(set);
  114. if (!(set->flags & NFT_SET_OBJECT))
  115. return -EINVAL;
  116. priv->sreg = nft_parse_register(tb[NFTA_OBJREF_SET_SREG]);
  117. err = nft_validate_register_load(priv->sreg, set->klen);
  118. if (err < 0)
  119. return err;
  120. priv->binding.flags = set->flags & NFT_SET_OBJECT;
  121. err = nf_tables_bind_set(ctx, set, &priv->binding);
  122. if (err < 0)
  123. return err;
  124. priv->set = set;
  125. return 0;
  126. }
  127. static int nft_objref_map_dump(struct sk_buff *skb, const struct nft_expr *expr)
  128. {
  129. const struct nft_objref_map *priv = nft_expr_priv(expr);
  130. if (nft_dump_register(skb, NFTA_OBJREF_SET_SREG, priv->sreg) ||
  131. nla_put_string(skb, NFTA_OBJREF_SET_NAME, priv->set->name))
  132. goto nla_put_failure;
  133. return 0;
  134. nla_put_failure:
  135. return -1;
  136. }
  137. static void nft_objref_map_deactivate(const struct nft_ctx *ctx,
  138. const struct nft_expr *expr,
  139. enum nft_trans_phase phase)
  140. {
  141. struct nft_objref_map *priv = nft_expr_priv(expr);
  142. nf_tables_deactivate_set(ctx, priv->set, &priv->binding, phase);
  143. }
  144. static void nft_objref_map_activate(const struct nft_ctx *ctx,
  145. const struct nft_expr *expr)
  146. {
  147. struct nft_objref_map *priv = nft_expr_priv(expr);
  148. priv->set->use++;
  149. }
  150. static void nft_objref_map_destroy(const struct nft_ctx *ctx,
  151. const struct nft_expr *expr)
  152. {
  153. struct nft_objref_map *priv = nft_expr_priv(expr);
  154. nf_tables_destroy_set(ctx, priv->set);
  155. }
  156. static struct nft_expr_type nft_objref_type;
  157. static const struct nft_expr_ops nft_objref_map_ops = {
  158. .type = &nft_objref_type,
  159. .size = NFT_EXPR_SIZE(sizeof(struct nft_objref_map)),
  160. .eval = nft_objref_map_eval,
  161. .init = nft_objref_map_init,
  162. .activate = nft_objref_map_activate,
  163. .deactivate = nft_objref_map_deactivate,
  164. .destroy = nft_objref_map_destroy,
  165. .dump = nft_objref_map_dump,
  166. };
  167. static const struct nft_expr_ops *
  168. nft_objref_select_ops(const struct nft_ctx *ctx,
  169. const struct nlattr * const tb[])
  170. {
  171. if (tb[NFTA_OBJREF_SET_SREG] &&
  172. (tb[NFTA_OBJREF_SET_NAME] ||
  173. tb[NFTA_OBJREF_SET_ID]))
  174. return &nft_objref_map_ops;
  175. else if (tb[NFTA_OBJREF_IMM_NAME] &&
  176. tb[NFTA_OBJREF_IMM_TYPE])
  177. return &nft_objref_ops;
  178. return ERR_PTR(-EOPNOTSUPP);
  179. }
  180. static const struct nla_policy nft_objref_policy[NFTA_OBJREF_MAX + 1] = {
  181. [NFTA_OBJREF_IMM_NAME] = { .type = NLA_STRING,
  182. .len = NFT_OBJ_MAXNAMELEN - 1 },
  183. [NFTA_OBJREF_IMM_TYPE] = { .type = NLA_U32 },
  184. [NFTA_OBJREF_SET_SREG] = { .type = NLA_U32 },
  185. [NFTA_OBJREF_SET_NAME] = { .type = NLA_STRING,
  186. .len = NFT_SET_MAXNAMELEN - 1 },
  187. [NFTA_OBJREF_SET_ID] = { .type = NLA_U32 },
  188. };
  189. static struct nft_expr_type nft_objref_type __read_mostly = {
  190. .name = "objref",
  191. .select_ops = nft_objref_select_ops,
  192. .policy = nft_objref_policy,
  193. .maxattr = NFTA_OBJREF_MAX,
  194. .owner = THIS_MODULE,
  195. };
  196. static int __init nft_objref_module_init(void)
  197. {
  198. return nft_register_expr(&nft_objref_type);
  199. }
  200. static void __exit nft_objref_module_exit(void)
  201. {
  202. nft_unregister_expr(&nft_objref_type);
  203. }
  204. module_init(nft_objref_module_init);
  205. module_exit(nft_objref_module_exit);
  206. MODULE_LICENSE("GPL");
  207. MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
  208. MODULE_ALIAS_NFT_EXPR("objref");