nf_tables_core.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /*
  2. * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
  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. * Development of this code funded by Astaro AG (http://www.astaro.com/)
  9. */
  10. #include <linux/kernel.h>
  11. #include <linux/module.h>
  12. #include <linux/init.h>
  13. #include <linux/list.h>
  14. #include <linux/rculist.h>
  15. #include <linux/skbuff.h>
  16. #include <linux/netlink.h>
  17. #include <linux/netfilter.h>
  18. #include <linux/netfilter/nfnetlink.h>
  19. #include <linux/netfilter/nf_tables.h>
  20. #include <net/netfilter/nf_tables_core.h>
  21. #include <net/netfilter/nf_tables.h>
  22. #include <net/netfilter/nf_log.h>
  23. enum nft_trace {
  24. NFT_TRACE_RULE,
  25. NFT_TRACE_RETURN,
  26. NFT_TRACE_POLICY,
  27. };
  28. static const char *const comments[] = {
  29. [NFT_TRACE_RULE] = "rule",
  30. [NFT_TRACE_RETURN] = "return",
  31. [NFT_TRACE_POLICY] = "policy",
  32. };
  33. static struct nf_loginfo trace_loginfo = {
  34. .type = NF_LOG_TYPE_LOG,
  35. .u = {
  36. .log = {
  37. .level = LOGLEVEL_WARNING,
  38. .logflags = NF_LOG_MASK,
  39. },
  40. },
  41. };
  42. static void __nft_trace_packet(const struct nft_pktinfo *pkt,
  43. const struct nft_chain *chain,
  44. int rulenum, enum nft_trace type)
  45. {
  46. nf_log_trace(pkt->net, pkt->pf, pkt->hook, pkt->skb, pkt->in,
  47. pkt->out, &trace_loginfo, "TRACE: %s:%s:%s:%u ",
  48. chain->table->name, chain->name, comments[type],
  49. rulenum);
  50. }
  51. static inline void nft_trace_packet(const struct nft_pktinfo *pkt,
  52. const struct nft_chain *chain,
  53. int rulenum, enum nft_trace type)
  54. {
  55. if (unlikely(pkt->skb->nf_trace))
  56. __nft_trace_packet(pkt, chain, rulenum, type);
  57. }
  58. static void nft_cmp_fast_eval(const struct nft_expr *expr,
  59. struct nft_regs *regs)
  60. {
  61. const struct nft_cmp_fast_expr *priv = nft_expr_priv(expr);
  62. u32 mask = nft_cmp_fast_mask(priv->len);
  63. if ((regs->data[priv->sreg] & mask) == priv->data)
  64. return;
  65. regs->verdict.code = NFT_BREAK;
  66. }
  67. static bool nft_payload_fast_eval(const struct nft_expr *expr,
  68. struct nft_regs *regs,
  69. const struct nft_pktinfo *pkt)
  70. {
  71. const struct nft_payload *priv = nft_expr_priv(expr);
  72. const struct sk_buff *skb = pkt->skb;
  73. u32 *dest = &regs->data[priv->dreg];
  74. unsigned char *ptr;
  75. if (priv->base == NFT_PAYLOAD_NETWORK_HEADER)
  76. ptr = skb_network_header(skb);
  77. else
  78. ptr = skb_network_header(skb) + pkt->xt.thoff;
  79. ptr += priv->offset;
  80. if (unlikely(ptr + priv->len >= skb_tail_pointer(skb)))
  81. return false;
  82. *dest = 0;
  83. if (priv->len == 2)
  84. *(u16 *)dest = *(u16 *)ptr;
  85. else if (priv->len == 4)
  86. *(u32 *)dest = *(u32 *)ptr;
  87. else
  88. *(u8 *)dest = *(u8 *)ptr;
  89. return true;
  90. }
  91. struct nft_jumpstack {
  92. const struct nft_chain *chain;
  93. const struct nft_rule *rule;
  94. int rulenum;
  95. };
  96. unsigned int
  97. nft_do_chain(struct nft_pktinfo *pkt, void *priv)
  98. {
  99. const struct nft_chain *chain = priv, *basechain = chain;
  100. const struct net *net = pkt->net;
  101. const struct nft_rule *rule;
  102. const struct nft_expr *expr, *last;
  103. struct nft_regs regs;
  104. unsigned int stackptr = 0;
  105. struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE];
  106. struct nft_stats *stats;
  107. int rulenum;
  108. unsigned int gencursor = nft_genmask_cur(net);
  109. do_chain:
  110. rulenum = 0;
  111. rule = list_entry(&chain->rules, struct nft_rule, list);
  112. next_rule:
  113. regs.verdict.code = NFT_CONTINUE;
  114. list_for_each_entry_continue_rcu(rule, &chain->rules, list) {
  115. /* This rule is not active, skip. */
  116. if (unlikely(rule->genmask & (1 << gencursor)))
  117. continue;
  118. rulenum++;
  119. nft_rule_for_each_expr(expr, last, rule) {
  120. if (expr->ops == &nft_cmp_fast_ops)
  121. nft_cmp_fast_eval(expr, &regs);
  122. else if (expr->ops != &nft_payload_fast_ops ||
  123. !nft_payload_fast_eval(expr, &regs, pkt))
  124. expr->ops->eval(expr, &regs, pkt);
  125. if (regs.verdict.code != NFT_CONTINUE)
  126. break;
  127. }
  128. switch (regs.verdict.code) {
  129. case NFT_BREAK:
  130. regs.verdict.code = NFT_CONTINUE;
  131. continue;
  132. case NFT_CONTINUE:
  133. nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
  134. continue;
  135. }
  136. break;
  137. }
  138. switch (regs.verdict.code & NF_VERDICT_MASK) {
  139. case NF_ACCEPT:
  140. case NF_DROP:
  141. case NF_QUEUE:
  142. nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
  143. return regs.verdict.code;
  144. }
  145. switch (regs.verdict.code) {
  146. case NFT_JUMP:
  147. if (WARN_ON_ONCE(stackptr >= NFT_JUMP_STACK_SIZE))
  148. return NF_DROP;
  149. jumpstack[stackptr].chain = chain;
  150. jumpstack[stackptr].rule = rule;
  151. jumpstack[stackptr].rulenum = rulenum;
  152. stackptr++;
  153. /* fall through */
  154. case NFT_GOTO:
  155. nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
  156. chain = regs.verdict.chain;
  157. goto do_chain;
  158. case NFT_CONTINUE:
  159. rulenum++;
  160. /* fall through */
  161. case NFT_RETURN:
  162. nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RETURN);
  163. break;
  164. default:
  165. WARN_ON(1);
  166. }
  167. if (stackptr > 0) {
  168. stackptr--;
  169. chain = jumpstack[stackptr].chain;
  170. rule = jumpstack[stackptr].rule;
  171. rulenum = jumpstack[stackptr].rulenum;
  172. goto next_rule;
  173. }
  174. nft_trace_packet(pkt, basechain, -1, NFT_TRACE_POLICY);
  175. rcu_read_lock_bh();
  176. stats = this_cpu_ptr(rcu_dereference(nft_base_chain(basechain)->stats));
  177. u64_stats_update_begin(&stats->syncp);
  178. stats->pkts++;
  179. stats->bytes += pkt->skb->len;
  180. u64_stats_update_end(&stats->syncp);
  181. rcu_read_unlock_bh();
  182. return nft_base_chain(basechain)->policy;
  183. }
  184. EXPORT_SYMBOL_GPL(nft_do_chain);
  185. int __init nf_tables_core_module_init(void)
  186. {
  187. int err;
  188. err = nft_immediate_module_init();
  189. if (err < 0)
  190. goto err1;
  191. err = nft_cmp_module_init();
  192. if (err < 0)
  193. goto err2;
  194. err = nft_lookup_module_init();
  195. if (err < 0)
  196. goto err3;
  197. err = nft_bitwise_module_init();
  198. if (err < 0)
  199. goto err4;
  200. err = nft_byteorder_module_init();
  201. if (err < 0)
  202. goto err5;
  203. err = nft_payload_module_init();
  204. if (err < 0)
  205. goto err6;
  206. err = nft_dynset_module_init();
  207. if (err < 0)
  208. goto err7;
  209. return 0;
  210. err7:
  211. nft_payload_module_exit();
  212. err6:
  213. nft_byteorder_module_exit();
  214. err5:
  215. nft_bitwise_module_exit();
  216. err4:
  217. nft_lookup_module_exit();
  218. err3:
  219. nft_cmp_module_exit();
  220. err2:
  221. nft_immediate_module_exit();
  222. err1:
  223. return err;
  224. }
  225. void nf_tables_core_module_exit(void)
  226. {
  227. nft_dynset_module_exit();
  228. nft_payload_module_exit();
  229. nft_byteorder_module_exit();
  230. nft_bitwise_module_exit();
  231. nft_lookup_module_exit();
  232. nft_cmp_module_exit();
  233. nft_immediate_module_exit();
  234. }