blob: 074067d4fc1eb16b048454f43e8b0f37a83e52a7 [file] [log] [blame]
Patrick McHardy96518512013-10-14 11:00:02 +02001/*
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
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>
Pablo Neira Ayusob5bc89b2013-10-10 16:49:19 +020022#include <net/netfilter/nf_log.h>
Patrick McHardy96518512013-10-14 11:00:02 +020023
Patrick McHardy01ef16c2015-03-03 20:10:04 +000024enum nft_trace {
25 NFT_TRACE_RULE,
26 NFT_TRACE_RETURN,
27 NFT_TRACE_POLICY,
28};
29
30static const char *const comments[] = {
31 [NFT_TRACE_RULE] = "rule",
32 [NFT_TRACE_RETURN] = "return",
33 [NFT_TRACE_POLICY] = "policy",
34};
35
36static struct nf_loginfo trace_loginfo = {
37 .type = NF_LOG_TYPE_LOG,
38 .u = {
39 .log = {
40 .level = 4,
41 .logflags = NF_LOG_MASK,
42 },
43 },
44};
45
46static void __nft_trace_packet(const struct nft_pktinfo *pkt,
47 const struct nft_chain *chain,
48 int rulenum, enum nft_trace type)
49{
50 struct net *net = dev_net(pkt->in ? pkt->in : pkt->out);
51
52 nf_log_packet(net, pkt->xt.family, pkt->ops->hooknum, pkt->skb, pkt->in,
53 pkt->out, &trace_loginfo, "TRACE: %s:%s:%s:%u ",
54 chain->table->name, chain->name, comments[type],
55 rulenum);
56}
57
58static inline void nft_trace_packet(const struct nft_pktinfo *pkt,
59 const struct nft_chain *chain,
60 int rulenum, enum nft_trace type)
61{
62 if (unlikely(pkt->skb->nf_trace))
63 __nft_trace_packet(pkt, chain, rulenum, type);
64}
65
Patrick McHardycb7dbfd2013-10-10 23:35:40 +020066static void nft_cmp_fast_eval(const struct nft_expr *expr,
67 struct nft_data data[NFT_REG_MAX + 1])
68{
69 const struct nft_cmp_fast_expr *priv = nft_expr_priv(expr);
Patrick McHardyb855d412014-04-12 13:17:57 +020070 u32 mask = nft_cmp_fast_mask(priv->len);
Patrick McHardycb7dbfd2013-10-10 23:35:40 +020071
Patrick McHardycb7dbfd2013-10-10 23:35:40 +020072 if ((data[priv->sreg].data[0] & mask) == priv->data)
73 return;
74 data[NFT_REG_VERDICT].verdict = NFT_BREAK;
75}
76
Patrick McHardyc29b72e2013-10-10 11:06:41 +020077static bool nft_payload_fast_eval(const struct nft_expr *expr,
78 struct nft_data data[NFT_REG_MAX + 1],
79 const struct nft_pktinfo *pkt)
80{
81 const struct nft_payload *priv = nft_expr_priv(expr);
82 const struct sk_buff *skb = pkt->skb;
83 struct nft_data *dest = &data[priv->dreg];
84 unsigned char *ptr;
85
86 if (priv->base == NFT_PAYLOAD_NETWORK_HEADER)
87 ptr = skb_network_header(skb);
88 else
Pablo Neira Ayusoc54032e2013-10-11 10:00:22 +020089 ptr = skb_network_header(skb) + pkt->xt.thoff;
Patrick McHardyc29b72e2013-10-10 11:06:41 +020090
91 ptr += priv->offset;
92
93 if (unlikely(ptr + priv->len >= skb_tail_pointer(skb)))
94 return false;
95
96 if (priv->len == 2)
97 *(u16 *)dest->data = *(u16 *)ptr;
98 else if (priv->len == 4)
99 *(u32 *)dest->data = *(u32 *)ptr;
100 else
101 *(u8 *)dest->data = *(u8 *)ptr;
102 return true;
103}
104
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200105struct nft_jumpstack {
106 const struct nft_chain *chain;
107 const struct nft_rule *rule;
Pablo Neira Ayusob5bc89b2013-10-10 16:49:19 +0200108 int rulenum;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200109};
110
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200111unsigned int
Patrick McHardy3876d222014-01-09 18:42:43 +0000112nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops)
Patrick McHardy96518512013-10-14 11:00:02 +0200113{
Pablo Neira Ayuso5467a512014-05-10 18:33:11 +0200114 const struct nft_chain *chain = ops->priv, *basechain = chain;
Patrick McHardy96518512013-10-14 11:00:02 +0200115 const struct nft_rule *rule;
116 const struct nft_expr *expr, *last;
117 struct nft_data data[NFT_REG_MAX + 1];
Patrick McHardy96518512013-10-14 11:00:02 +0200118 unsigned int stackptr = 0;
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200119 struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE];
Eric Dumazetce355e22014-07-09 15:14:06 +0200120 struct nft_stats *stats;
Pablo Neira Ayusod088be82014-05-10 13:39:21 +0200121 int rulenum;
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +0200122 /*
123 * Cache cursor to avoid problems in case that the cursor is updated
124 * while traversing the ruleset.
125 */
126 unsigned int gencursor = ACCESS_ONCE(chain->net->nft.gencursor);
Patrick McHardy96518512013-10-14 11:00:02 +0200127
128do_chain:
Pablo Neira Ayusod088be82014-05-10 13:39:21 +0200129 rulenum = 0;
Patrick McHardy96518512013-10-14 11:00:02 +0200130 rule = list_entry(&chain->rules, struct nft_rule, list);
131next_rule:
132 data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
133 list_for_each_entry_continue_rcu(rule, &chain->rules, list) {
Pablo Neira Ayuso0628b122013-10-14 11:05:33 +0200134
135 /* This rule is not active, skip. */
136 if (unlikely(rule->genmask & (1 << gencursor)))
137 continue;
138
Pablo Neira Ayusob5bc89b2013-10-10 16:49:19 +0200139 rulenum++;
140
Patrick McHardy96518512013-10-14 11:00:02 +0200141 nft_rule_for_each_expr(expr, last, rule) {
Patrick McHardycb7dbfd2013-10-10 23:35:40 +0200142 if (expr->ops == &nft_cmp_fast_ops)
143 nft_cmp_fast_eval(expr, data);
Patrick McHardyc29b72e2013-10-10 11:06:41 +0200144 else if (expr->ops != &nft_payload_fast_ops ||
Pablo Neira Ayuso0ca743a2013-10-14 00:06:06 +0200145 !nft_payload_fast_eval(expr, data, pkt))
146 expr->ops->eval(expr, data, pkt);
Patrick McHardycb7dbfd2013-10-10 23:35:40 +0200147
Patrick McHardy96518512013-10-14 11:00:02 +0200148 if (data[NFT_REG_VERDICT].verdict != NFT_CONTINUE)
149 break;
150 }
151
152 switch (data[NFT_REG_VERDICT].verdict) {
153 case NFT_BREAK:
154 data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
Pablo Neira Ayuso3b084e92014-05-15 17:18:26 +0200155 continue;
Patrick McHardy96518512013-10-14 11:00:02 +0200156 case NFT_CONTINUE:
Patrick McHardy01ef16c2015-03-03 20:10:04 +0000157 nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
Patrick McHardy96518512013-10-14 11:00:02 +0200158 continue;
159 }
160 break;
161 }
162
Eric Leblonde569bda2013-11-30 11:56:17 +0100163 switch (data[NFT_REG_VERDICT].verdict & NF_VERDICT_MASK) {
Patrick McHardy96518512013-10-14 11:00:02 +0200164 case NF_ACCEPT:
165 case NF_DROP:
166 case NF_QUEUE:
Patrick McHardy01ef16c2015-03-03 20:10:04 +0000167 nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
Patrick McHardy96518512013-10-14 11:00:02 +0200168 return data[NFT_REG_VERDICT].verdict;
Eric Leblonde569bda2013-11-30 11:56:17 +0100169 }
170
171 switch (data[NFT_REG_VERDICT].verdict) {
Patrick McHardy96518512013-10-14 11:00:02 +0200172 case NFT_JUMP:
Patrick McHardy01ef16c2015-03-03 20:10:04 +0000173 nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
Pablo Neira Ayusob5bc89b2013-10-10 16:49:19 +0200174
Patrick McHardy96518512013-10-14 11:00:02 +0200175 BUG_ON(stackptr >= NFT_JUMP_STACK_SIZE);
176 jumpstack[stackptr].chain = chain;
177 jumpstack[stackptr].rule = rule;
Pablo Neira Ayusob5bc89b2013-10-10 16:49:19 +0200178 jumpstack[stackptr].rulenum = rulenum;
Patrick McHardy96518512013-10-14 11:00:02 +0200179 stackptr++;
Pablo Neira Ayuso7b9d5ef2014-05-10 18:42:57 +0200180 chain = data[NFT_REG_VERDICT].chain;
181 goto do_chain;
Patrick McHardy96518512013-10-14 11:00:02 +0200182 case NFT_GOTO:
Patrick McHardy01ef16c2015-03-03 20:10:04 +0000183 nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
Pablo Neira Ayuso7b9d5ef2014-05-10 18:42:57 +0200184
Patrick McHardy96518512013-10-14 11:00:02 +0200185 chain = data[NFT_REG_VERDICT].chain;
186 goto do_chain;
187 case NFT_RETURN:
Patrick McHardy01ef16c2015-03-03 20:10:04 +0000188 nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RETURN);
Pablo Neira Ayuso7e9bc102014-05-11 17:14:49 +0200189 break;
Patrick McHardy96518512013-10-14 11:00:02 +0200190 case NFT_CONTINUE:
Patrick McHardy01ef16c2015-03-03 20:10:04 +0000191 nft_trace_packet(pkt, chain, ++rulenum, NFT_TRACE_RETURN);
Patrick McHardy96518512013-10-14 11:00:02 +0200192 break;
193 default:
194 WARN_ON(1);
195 }
196
197 if (stackptr > 0) {
198 stackptr--;
199 chain = jumpstack[stackptr].chain;
200 rule = jumpstack[stackptr].rule;
Pablo Neira Ayusob5bc89b2013-10-10 16:49:19 +0200201 rulenum = jumpstack[stackptr].rulenum;
Patrick McHardy96518512013-10-14 11:00:02 +0200202 goto next_rule;
203 }
204
Patrick McHardy01ef16c2015-03-03 20:10:04 +0000205 nft_trace_packet(pkt, basechain, -1, NFT_TRACE_POLICY);
Pablo Neira Ayusob5bc89b2013-10-10 16:49:19 +0200206
Pablo Neira Ayuso5467a512014-05-10 18:33:11 +0200207 rcu_read_lock_bh();
Eric Dumazetce355e22014-07-09 15:14:06 +0200208 stats = this_cpu_ptr(rcu_dereference(nft_base_chain(basechain)->stats));
209 u64_stats_update_begin(&stats->syncp);
210 stats->pkts++;
211 stats->bytes += pkt->skb->len;
212 u64_stats_update_end(&stats->syncp);
Pablo Neira Ayuso5467a512014-05-10 18:33:11 +0200213 rcu_read_unlock_bh();
214
215 return nft_base_chain(basechain)->policy;
Patrick McHardy96518512013-10-14 11:00:02 +0200216}
Patrick McHardy3876d222014-01-09 18:42:43 +0000217EXPORT_SYMBOL_GPL(nft_do_chain);
Patrick McHardy96518512013-10-14 11:00:02 +0200218
219int __init nf_tables_core_module_init(void)
220{
221 int err;
222
223 err = nft_immediate_module_init();
224 if (err < 0)
225 goto err1;
226
227 err = nft_cmp_module_init();
228 if (err < 0)
229 goto err2;
230
231 err = nft_lookup_module_init();
232 if (err < 0)
233 goto err3;
234
235 err = nft_bitwise_module_init();
236 if (err < 0)
237 goto err4;
238
239 err = nft_byteorder_module_init();
240 if (err < 0)
241 goto err5;
242
243 err = nft_payload_module_init();
244 if (err < 0)
245 goto err6;
246
247 return 0;
248
249err6:
250 nft_byteorder_module_exit();
251err5:
252 nft_bitwise_module_exit();
253err4:
254 nft_lookup_module_exit();
255err3:
256 nft_cmp_module_exit();
257err2:
258 nft_immediate_module_exit();
259err1:
260 return err;
261}
262
263void nf_tables_core_module_exit(void)
264{
265 nft_payload_module_exit();
266 nft_byteorder_module_exit();
267 nft_bitwise_module_exit();
268 nft_lookup_module_exit();
269 nft_cmp_module_exit();
270 nft_immediate_module_exit();
271}