Blame view

net/netfilter/nft_meta.c 16.3 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
96518518c   Patrick McHardy   netfilter: add nf...
2
  /*
ef1f7df91   Patrick McHardy   netfilter: nf_tab...
3
   * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
bd2bbdb49   Florian Westphal   netfilter: merge ...
4
5
   * Copyright (c) 2014 Intel Corporation
   * Author: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
96518518c   Patrick McHardy   netfilter: add nf...
6
   *
96518518c   Patrick McHardy   netfilter: add nf...
7
8
9
10
   * Development of this code funded by Astaro AG (http://www.astaro.com/)
   */
  
  #include <linux/kernel.h>
96518518c   Patrick McHardy   netfilter: add nf...
11
12
13
  #include <linux/netlink.h>
  #include <linux/netfilter.h>
  #include <linux/netfilter/nf_tables.h>
e2a093ff0   Ana Rey   netfilter: nft_me...
14
15
16
  #include <linux/in.h>
  #include <linux/ip.h>
  #include <linux/ipv6.h>
afc5be307   Ana Rey   netfilter: nft_me...
17
  #include <linux/smp.h>
e639f7ab0   Florian Westphal   netfilter: nf_tab...
18
  #include <linux/static_key.h>
96518518c   Patrick McHardy   netfilter: add nf...
19
20
21
22
  #include <net/dst.h>
  #include <net/sock.h>
  #include <net/tcp_states.h> /* for TCP_TIME_WAIT */
  #include <net/netfilter/nf_tables.h>
e639f7ab0   Florian Westphal   netfilter: nf_tab...
23
  #include <net/netfilter/nf_tables_core.h>
30e103fe2   wenxu   netfilter: nft_me...
24
  #include <net/netfilter/nft_meta.h>
c9626a2cb   Pablo Neira Ayuso   netfilter: nf_tab...
25
  #include <net/netfilter/nf_tables_offload.h>
96518518c   Patrick McHardy   netfilter: add nf...
26

b4aae759c   Florian Westphal   netfilter: meta: ...
27
  #include <uapi/linux/netfilter_bridge.h> /* NF_BR_PRE_ROUTING */
63d10e12b   Ander Juaristi   netfilter: nft_me...
28
29
30
31
  #define NFT_META_SECS_PER_MINUTE	60
  #define NFT_META_SECS_PER_HOUR		3600
  #define NFT_META_SECS_PER_DAY		86400
  #define NFT_META_DAYS_PER_WEEK		7
b07edbe1c   Florian Westphal   netfilter: meta: ...
32
  static DEFINE_PER_CPU(struct rnd_state, nft_prandom_state);
6408c40c3   Arnd Bergmann   netfilter: nft_me...
33
  static u8 nft_meta_weekday(time64_t secs)
63d10e12b   Ander Juaristi   netfilter: nft_me...
34
35
36
37
38
  {
  	unsigned int dse;
  	u8 wday;
  
  	secs -= NFT_META_SECS_PER_MINUTE * sys_tz.tz_minuteswest;
6408c40c3   Arnd Bergmann   netfilter: nft_me...
39
  	dse = div_u64(secs, NFT_META_SECS_PER_DAY);
63d10e12b   Ander Juaristi   netfilter: nft_me...
40
41
42
43
  	wday = (4 + dse) % NFT_META_DAYS_PER_WEEK;
  
  	return wday;
  }
6408c40c3   Arnd Bergmann   netfilter: nft_me...
44
  static u32 nft_meta_hour(time64_t secs)
63d10e12b   Ander Juaristi   netfilter: nft_me...
45
46
47
48
49
50
51
52
53
  {
  	struct tm tm;
  
  	time64_to_tm(secs, 0, &tm);
  
  	return tm.tm_hour * NFT_META_SECS_PER_HOUR
  		+ tm.tm_min * NFT_META_SECS_PER_MINUTE
  		+ tm.tm_sec;
  }
222440b4e   Florian Westphal   netfilter: nf_tab...
54
55
56
  void nft_meta_get_eval(const struct nft_expr *expr,
  		       struct nft_regs *regs,
  		       const struct nft_pktinfo *pkt)
96518518c   Patrick McHardy   netfilter: add nf...
57
58
59
  {
  	const struct nft_meta *priv = nft_expr_priv(expr);
  	const struct sk_buff *skb = pkt->skb;
0e5a1c7eb   Pablo Neira Ayuso   netfilter: nf_tab...
60
  	const struct net_device *in = nft_in(pkt), *out = nft_out(pkt);
3aed82259   Eric Dumazet   netfilter: nft_me...
61
  	struct sock *sk;
49499c3e6   Patrick McHardy   netfilter: nf_tab...
62
  	u32 *dest = &regs->data[priv->dreg];
96518518c   Patrick McHardy   netfilter: add nf...
63
64
65
  
  	switch (priv->key) {
  	case NFT_META_LEN:
fad136ea0   Patrick McHardy   netfilter: nf_tab...
66
  		*dest = skb->len;
96518518c   Patrick McHardy   netfilter: add nf...
67
68
  		break;
  	case NFT_META_PROTOCOL:
10596608c   Liping Zhang   netfilter: nf_tab...
69
  		nft_reg_store16(dest, (__force u16)skb->protocol);
96518518c   Patrick McHardy   netfilter: add nf...
70
  		break;
124edfa9e   Patrick McHardy   netfilter: nf_tab...
71
  	case NFT_META_NFPROTO:
10596608c   Liping Zhang   netfilter: nf_tab...
72
  		nft_reg_store8(dest, nft_pf(pkt));
124edfa9e   Patrick McHardy   netfilter: nf_tab...
73
  		break;
4566bf270   Patrick McHardy   netfilter: nft_me...
74
  	case NFT_META_L4PROTO:
beac5afa2   Pablo Neira Ayuso   netfilter: nf_tab...
75
76
  		if (!pkt->tprot_set)
  			goto err;
10596608c   Liping Zhang   netfilter: nf_tab...
77
  		nft_reg_store8(dest, pkt->tprot);
4566bf270   Patrick McHardy   netfilter: nft_me...
78
  		break;
96518518c   Patrick McHardy   netfilter: add nf...
79
  	case NFT_META_PRIORITY:
fad136ea0   Patrick McHardy   netfilter: nf_tab...
80
  		*dest = skb->priority;
96518518c   Patrick McHardy   netfilter: add nf...
81
82
  		break;
  	case NFT_META_MARK:
fad136ea0   Patrick McHardy   netfilter: nf_tab...
83
  		*dest = skb->mark;
96518518c   Patrick McHardy   netfilter: add nf...
84
85
  		break;
  	case NFT_META_IIF:
cb81572e8   Phil Sutter   netfilter: nf_tab...
86
  		*dest = in ? in->ifindex : 0;
96518518c   Patrick McHardy   netfilter: add nf...
87
88
  		break;
  	case NFT_META_OIF:
cb81572e8   Phil Sutter   netfilter: nf_tab...
89
  		*dest = out ? out->ifindex : 0;
96518518c   Patrick McHardy   netfilter: add nf...
90
91
  		break;
  	case NFT_META_IIFNAME:
cb81572e8   Phil Sutter   netfilter: nf_tab...
92
  		strncpy((char *)dest, in ? in->name : "", IFNAMSIZ);
96518518c   Patrick McHardy   netfilter: add nf...
93
94
  		break;
  	case NFT_META_OIFNAME:
cb81572e8   Phil Sutter   netfilter: nf_tab...
95
  		strncpy((char *)dest, out ? out->name : "", IFNAMSIZ);
96518518c   Patrick McHardy   netfilter: add nf...
96
97
98
99
  		break;
  	case NFT_META_IIFTYPE:
  		if (in == NULL)
  			goto err;
10596608c   Liping Zhang   netfilter: nf_tab...
100
  		nft_reg_store16(dest, in->type);
96518518c   Patrick McHardy   netfilter: add nf...
101
102
103
104
  		break;
  	case NFT_META_OIFTYPE:
  		if (out == NULL)
  			goto err;
10596608c   Liping Zhang   netfilter: nf_tab...
105
  		nft_reg_store16(dest, out->type);
96518518c   Patrick McHardy   netfilter: add nf...
106
107
  		break;
  	case NFT_META_SKUID:
3aed82259   Eric Dumazet   netfilter: nft_me...
108
  		sk = skb_to_full_sk(skb);
f56465010   Flavio Leitner   netfilter: check ...
109
110
  		if (!sk || !sk_fullsock(sk) ||
  		    !net_eq(nft_net(pkt), sock_net(sk)))
96518518c   Patrick McHardy   netfilter: add nf...
111
  			goto err;
3aed82259   Eric Dumazet   netfilter: nft_me...
112
113
114
115
  		read_lock_bh(&sk->sk_callback_lock);
  		if (sk->sk_socket == NULL ||
  		    sk->sk_socket->file == NULL) {
  			read_unlock_bh(&sk->sk_callback_lock);
96518518c   Patrick McHardy   netfilter: add nf...
116
117
  			goto err;
  		}
fad136ea0   Patrick McHardy   netfilter: nf_tab...
118
  		*dest =	from_kuid_munged(&init_user_ns,
3aed82259   Eric Dumazet   netfilter: nft_me...
119
120
  				sk->sk_socket->file->f_cred->fsuid);
  		read_unlock_bh(&sk->sk_callback_lock);
96518518c   Patrick McHardy   netfilter: add nf...
121
122
  		break;
  	case NFT_META_SKGID:
3aed82259   Eric Dumazet   netfilter: nft_me...
123
  		sk = skb_to_full_sk(skb);
f56465010   Flavio Leitner   netfilter: check ...
124
125
  		if (!sk || !sk_fullsock(sk) ||
  		    !net_eq(nft_net(pkt), sock_net(sk)))
96518518c   Patrick McHardy   netfilter: add nf...
126
  			goto err;
3aed82259   Eric Dumazet   netfilter: nft_me...
127
128
129
130
  		read_lock_bh(&sk->sk_callback_lock);
  		if (sk->sk_socket == NULL ||
  		    sk->sk_socket->file == NULL) {
  			read_unlock_bh(&sk->sk_callback_lock);
96518518c   Patrick McHardy   netfilter: add nf...
131
132
  			goto err;
  		}
fad136ea0   Patrick McHardy   netfilter: nf_tab...
133
  		*dest =	from_kgid_munged(&init_user_ns,
3aed82259   Eric Dumazet   netfilter: nft_me...
134
135
  				 sk->sk_socket->file->f_cred->fsgid);
  		read_unlock_bh(&sk->sk_callback_lock);
96518518c   Patrick McHardy   netfilter: add nf...
136
  		break;
06efbd6d5   Paul Bolle   netfilter: nft_me...
137
  #ifdef CONFIG_IP_ROUTE_CLASSID
96518518c   Patrick McHardy   netfilter: add nf...
138
139
140
141
142
  	case NFT_META_RTCLASSID: {
  		const struct dst_entry *dst = skb_dst(skb);
  
  		if (dst == NULL)
  			goto err;
fad136ea0   Patrick McHardy   netfilter: nf_tab...
143
  		*dest = dst->tclassid;
96518518c   Patrick McHardy   netfilter: add nf...
144
145
146
147
148
  		break;
  	}
  #endif
  #ifdef CONFIG_NETWORK_SECMARK
  	case NFT_META_SECMARK:
fad136ea0   Patrick McHardy   netfilter: nf_tab...
149
  		*dest = skb->secmark;
96518518c   Patrick McHardy   netfilter: add nf...
150
151
  		break;
  #endif
e2a093ff0   Ana Rey   netfilter: nft_me...
152
153
  	case NFT_META_PKTTYPE:
  		if (skb->pkt_type != PACKET_LOOPBACK) {
10596608c   Liping Zhang   netfilter: nf_tab...
154
  			nft_reg_store8(dest, skb->pkt_type);
e2a093ff0   Ana Rey   netfilter: nft_me...
155
156
  			break;
  		}
0e5a1c7eb   Pablo Neira Ayuso   netfilter: nf_tab...
157
  		switch (nft_pf(pkt)) {
e2a093ff0   Ana Rey   netfilter: nft_me...
158
159
  		case NFPROTO_IPV4:
  			if (ipv4_is_multicast(ip_hdr(skb)->daddr))
10596608c   Liping Zhang   netfilter: nf_tab...
160
  				nft_reg_store8(dest, PACKET_MULTICAST);
e2a093ff0   Ana Rey   netfilter: nft_me...
161
  			else
10596608c   Liping Zhang   netfilter: nf_tab...
162
  				nft_reg_store8(dest, PACKET_BROADCAST);
e2a093ff0   Ana Rey   netfilter: nft_me...
163
164
  			break;
  		case NFPROTO_IPV6:
10596608c   Liping Zhang   netfilter: nf_tab...
165
  			nft_reg_store8(dest, PACKET_MULTICAST);
e2a093ff0   Ana Rey   netfilter: nft_me...
166
  			break;
f169fd695   Liping Zhang   netfilter: nft_me...
167
168
169
170
171
172
173
174
175
176
177
178
  		case NFPROTO_NETDEV:
  			switch (skb->protocol) {
  			case htons(ETH_P_IP): {
  				int noff = skb_network_offset(skb);
  				struct iphdr *iph, _iph;
  
  				iph = skb_header_pointer(skb, noff,
  							 sizeof(_iph), &_iph);
  				if (!iph)
  					goto err;
  
  				if (ipv4_is_multicast(iph->daddr))
10596608c   Liping Zhang   netfilter: nf_tab...
179
  					nft_reg_store8(dest, PACKET_MULTICAST);
f169fd695   Liping Zhang   netfilter: nft_me...
180
  				else
10596608c   Liping Zhang   netfilter: nf_tab...
181
  					nft_reg_store8(dest, PACKET_BROADCAST);
f169fd695   Liping Zhang   netfilter: nft_me...
182
183
184
185
  
  				break;
  			}
  			case htons(ETH_P_IPV6):
10596608c   Liping Zhang   netfilter: nf_tab...
186
  				nft_reg_store8(dest, PACKET_MULTICAST);
f169fd695   Liping Zhang   netfilter: nft_me...
187
188
189
190
191
192
  				break;
  			default:
  				WARN_ON_ONCE(1);
  				goto err;
  			}
  			break;
e2a093ff0   Ana Rey   netfilter: nft_me...
193
  		default:
f169fd695   Liping Zhang   netfilter: nft_me...
194
  			WARN_ON_ONCE(1);
e2a093ff0   Ana Rey   netfilter: nft_me...
195
196
197
  			goto err;
  		}
  		break;
afc5be307   Ana Rey   netfilter: nft_me...
198
  	case NFT_META_CPU:
fad136ea0   Patrick McHardy   netfilter: nf_tab...
199
  		*dest = raw_smp_processor_id();
afc5be307   Ana Rey   netfilter: nft_me...
200
  		break;
3045d7607   Ana Rey   netfilter: nf_tab...
201
202
203
  	case NFT_META_IIFGROUP:
  		if (in == NULL)
  			goto err;
fad136ea0   Patrick McHardy   netfilter: nf_tab...
204
  		*dest = in->group;
3045d7607   Ana Rey   netfilter: nf_tab...
205
206
207
208
  		break;
  	case NFT_META_OIFGROUP:
  		if (out == NULL)
  			goto err;
fad136ea0   Patrick McHardy   netfilter: nf_tab...
209
  		*dest = out->group;
3045d7607   Ana Rey   netfilter: nf_tab...
210
  		break;
e181a5430   Mathias Krause   net: #ifdefify sk...
211
  #ifdef CONFIG_CGROUP_NET_CLASSID
ce674173e   Ana Rey   netfilter: nft_me...
212
  	case NFT_META_CGROUP:
3aed82259   Eric Dumazet   netfilter: nft_me...
213
  		sk = skb_to_full_sk(skb);
f56465010   Flavio Leitner   netfilter: check ...
214
215
  		if (!sk || !sk_fullsock(sk) ||
  		    !net_eq(nft_net(pkt), sock_net(sk)))
c5035c77f   Pablo Neira Ayuso   netfilter: nft_me...
216
  			goto err;
2a56a1fec   Tejun Heo   net: wrap sock->s...
217
  		*dest = sock_cgroup_classid(&sk->sk_cgrp_data);
ce674173e   Ana Rey   netfilter: nft_me...
218
  		break;
e181a5430   Mathias Krause   net: #ifdefify sk...
219
  #endif
b07edbe1c   Florian Westphal   netfilter: meta: ...
220
221
222
223
224
  	case NFT_META_PRANDOM: {
  		struct rnd_state *state = this_cpu_ptr(&nft_prandom_state);
  		*dest = prandom_u32_state(state);
  		break;
  	}
f6931f5f5   Florian Westphal   netfilter: meta: ...
225
226
  #ifdef CONFIG_XFRM
  	case NFT_META_SECPATH:
7af8f4ca3   Florian Westphal   net: move secpath...
227
  		nft_reg_store8(dest, secpath_exists(skb));
f6931f5f5   Florian Westphal   netfilter: meta: ...
228
229
  		break;
  #endif
0fb4d2195   wenxu   netfilter: nft_me...
230
231
232
233
234
235
236
237
238
239
  	case NFT_META_IIFKIND:
  		if (in == NULL || in->rtnl_link_ops == NULL)
  			goto err;
  		strncpy((char *)dest, in->rtnl_link_ops->kind, IFNAMSIZ);
  		break;
  	case NFT_META_OIFKIND:
  		if (out == NULL || out->rtnl_link_ops == NULL)
  			goto err;
  		strncpy((char *)dest, out->rtnl_link_ops->kind, IFNAMSIZ);
  		break;
63d10e12b   Ander Juaristi   netfilter: nft_me...
240
241
242
243
  	case NFT_META_TIME_NS:
  		nft_reg_store64(dest, ktime_get_real_ns());
  		break;
  	case NFT_META_TIME_DAY:
6408c40c3   Arnd Bergmann   netfilter: nft_me...
244
  		nft_reg_store8(dest, nft_meta_weekday(ktime_get_real_seconds()));
63d10e12b   Ander Juaristi   netfilter: nft_me...
245
246
  		break;
  	case NFT_META_TIME_HOUR:
6408c40c3   Arnd Bergmann   netfilter: nft_me...
247
  		*dest = nft_meta_hour(ktime_get_real_seconds());
63d10e12b   Ander Juaristi   netfilter: nft_me...
248
  		break;
96518518c   Patrick McHardy   netfilter: add nf...
249
250
251
252
253
254
255
  	default:
  		WARN_ON(1);
  		goto err;
  	}
  	return;
  
  err:
a55e22e92   Patrick McHardy   netfilter: nf_tab...
256
  	regs->verdict.code = NFT_BREAK;
96518518c   Patrick McHardy   netfilter: add nf...
257
  }
30e103fe2   wenxu   netfilter: nft_me...
258
  EXPORT_SYMBOL_GPL(nft_meta_get_eval);
96518518c   Patrick McHardy   netfilter: add nf...
259

30e103fe2   wenxu   netfilter: nft_me...
260
261
262
  void nft_meta_set_eval(const struct nft_expr *expr,
  		       struct nft_regs *regs,
  		       const struct nft_pktinfo *pkt)
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
263
264
265
  {
  	const struct nft_meta *meta = nft_expr_priv(expr);
  	struct sk_buff *skb = pkt->skb;
10596608c   Liping Zhang   netfilter: nf_tab...
266
267
  	u32 *sreg = &regs->data[meta->sreg];
  	u32 value = *sreg;
97a0549b1   Taehee Yoo   netfilter: nft_me...
268
  	u8 value8;
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
269
270
271
272
273
274
275
276
  
  	switch (meta->key) {
  	case NFT_META_MARK:
  		skb->mark = value;
  		break;
  	case NFT_META_PRIORITY:
  		skb->priority = value;
  		break;
b4aae759c   Florian Westphal   netfilter: meta: ...
277
  	case NFT_META_PKTTYPE:
97a0549b1   Taehee Yoo   netfilter: nft_me...
278
  		value8 = nft_reg_load8(sreg);
10596608c   Liping Zhang   netfilter: nf_tab...
279

97a0549b1   Taehee Yoo   netfilter: nft_me...
280
281
  		if (skb->pkt_type != value8 &&
  		    skb_pkt_type_ok(value8) &&
10596608c   Liping Zhang   netfilter: nf_tab...
282
  		    skb_pkt_type_ok(skb->pkt_type))
97a0549b1   Taehee Yoo   netfilter: nft_me...
283
  			skb->pkt_type = value8;
b4aae759c   Florian Westphal   netfilter: meta: ...
284
  		break;
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
285
  	case NFT_META_NFTRACE:
97a0549b1   Taehee Yoo   netfilter: nft_me...
286
287
288
  		value8 = nft_reg_load8(sreg);
  
  		skb->nf_trace = !!value8;
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
289
  		break;
b473a1f5d   Christian Göttsche   netfilter: nf_tab...
290
291
292
293
294
  #ifdef CONFIG_NETWORK_SECMARK
  	case NFT_META_SECMARK:
  		skb->secmark = value;
  		break;
  #endif
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
295
296
297
298
  	default:
  		WARN_ON(1);
  	}
  }
30e103fe2   wenxu   netfilter: nft_me...
299
  EXPORT_SYMBOL_GPL(nft_meta_set_eval);
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
300

30e103fe2   wenxu   netfilter: nft_me...
301
  const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = {
96518518c   Patrick McHardy   netfilter: add nf...
302
303
  	[NFTA_META_DREG]	= { .type = NLA_U32 },
  	[NFTA_META_KEY]		= { .type = NLA_U32 },
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
304
  	[NFTA_META_SREG]	= { .type = NLA_U32 },
96518518c   Patrick McHardy   netfilter: add nf...
305
  };
30e103fe2   wenxu   netfilter: nft_me...
306
  EXPORT_SYMBOL_GPL(nft_meta_policy);
96518518c   Patrick McHardy   netfilter: add nf...
307

30e103fe2   wenxu   netfilter: nft_me...
308
309
310
  int nft_meta_get_init(const struct nft_ctx *ctx,
  		      const struct nft_expr *expr,
  		      const struct nlattr * const tb[])
96518518c   Patrick McHardy   netfilter: add nf...
311
  {
d2caa696a   Patrick McHardy   netfilter: nft_me...
312
  	struct nft_meta *priv = nft_expr_priv(expr);
45d9bcda2   Patrick McHardy   netfilter: nf_tab...
313
  	unsigned int len;
96518518c   Patrick McHardy   netfilter: add nf...
314

d2caa696a   Patrick McHardy   netfilter: nft_me...
315
316
  	priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
  	switch (priv->key) {
96518518c   Patrick McHardy   netfilter: add nf...
317
  	case NFT_META_PROTOCOL:
45d9bcda2   Patrick McHardy   netfilter: nf_tab...
318
319
320
321
  	case NFT_META_IIFTYPE:
  	case NFT_META_OIFTYPE:
  		len = sizeof(u16);
  		break;
124edfa9e   Patrick McHardy   netfilter: nf_tab...
322
  	case NFT_META_NFPROTO:
4566bf270   Patrick McHardy   netfilter: nft_me...
323
  	case NFT_META_L4PROTO:
45d9bcda2   Patrick McHardy   netfilter: nf_tab...
324
  	case NFT_META_LEN:
96518518c   Patrick McHardy   netfilter: add nf...
325
326
327
328
  	case NFT_META_PRIORITY:
  	case NFT_META_MARK:
  	case NFT_META_IIF:
  	case NFT_META_OIF:
96518518c   Patrick McHardy   netfilter: add nf...
329
330
  	case NFT_META_SKUID:
  	case NFT_META_SKGID:
06efbd6d5   Paul Bolle   netfilter: nft_me...
331
  #ifdef CONFIG_IP_ROUTE_CLASSID
96518518c   Patrick McHardy   netfilter: add nf...
332
333
334
335
336
  	case NFT_META_RTCLASSID:
  #endif
  #ifdef CONFIG_NETWORK_SECMARK
  	case NFT_META_SECMARK:
  #endif
e2a093ff0   Ana Rey   netfilter: nft_me...
337
  	case NFT_META_PKTTYPE:
afc5be307   Ana Rey   netfilter: nft_me...
338
  	case NFT_META_CPU:
3045d7607   Ana Rey   netfilter: nf_tab...
339
340
  	case NFT_META_IIFGROUP:
  	case NFT_META_OIFGROUP:
e181a5430   Mathias Krause   net: #ifdefify sk...
341
  #ifdef CONFIG_CGROUP_NET_CLASSID
ce674173e   Ana Rey   netfilter: nft_me...
342
  	case NFT_META_CGROUP:
e181a5430   Mathias Krause   net: #ifdefify sk...
343
  #endif
45d9bcda2   Patrick McHardy   netfilter: nf_tab...
344
345
346
347
  		len = sizeof(u32);
  		break;
  	case NFT_META_IIFNAME:
  	case NFT_META_OIFNAME:
0fb4d2195   wenxu   netfilter: nft_me...
348
349
  	case NFT_META_IIFKIND:
  	case NFT_META_OIFKIND:
45d9bcda2   Patrick McHardy   netfilter: nf_tab...
350
  		len = IFNAMSIZ;
d2caa696a   Patrick McHardy   netfilter: nft_me...
351
  		break;
b07edbe1c   Florian Westphal   netfilter: meta: ...
352
353
354
355
  	case NFT_META_PRANDOM:
  		prandom_init_once(&nft_prandom_state);
  		len = sizeof(u32);
  		break;
f6931f5f5   Florian Westphal   netfilter: meta: ...
356
357
358
359
360
  #ifdef CONFIG_XFRM
  	case NFT_META_SECPATH:
  		len = sizeof(u8);
  		break;
  #endif
63d10e12b   Ander Juaristi   netfilter: nft_me...
361
362
363
364
365
366
367
368
369
  	case NFT_META_TIME_NS:
  		len = sizeof(u64);
  		break;
  	case NFT_META_TIME_DAY:
  		len = sizeof(u8);
  		break;
  	case NFT_META_TIME_HOUR:
  		len = sizeof(u32);
  		break;
96518518c   Patrick McHardy   netfilter: add nf...
370
371
372
  	default:
  		return -EOPNOTSUPP;
  	}
b1c96ed37   Patrick McHardy   netfilter: nf_tab...
373
  	priv->dreg = nft_parse_register(tb[NFTA_META_DREG]);
27e6d2017   Patrick McHardy   netfilter: nf_tab...
374
375
  	return nft_validate_register_store(ctx, priv->dreg, NULL,
  					   NFT_DATA_VALUE, len);
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
376
  }
30e103fe2   wenxu   netfilter: nft_me...
377
  EXPORT_SYMBOL_GPL(nft_meta_get_init);
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
378

f6931f5f5   Florian Westphal   netfilter: meta: ...
379
380
381
382
383
384
385
386
387
388
  static int nft_meta_get_validate(const struct nft_ctx *ctx,
  				 const struct nft_expr *expr,
  				 const struct nft_data **data)
  {
  #ifdef CONFIG_XFRM
  	const struct nft_meta *priv = nft_expr_priv(expr);
  	unsigned int hooks;
  
  	if (priv->key != NFT_META_SECPATH)
  		return 0;
36596dadf   Pablo Neira Ayuso   netfilter: nf_tab...
389
  	switch (ctx->family) {
f6931f5f5   Florian Westphal   netfilter: meta: ...
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
  	case NFPROTO_NETDEV:
  		hooks = 1 << NF_NETDEV_INGRESS;
  		break;
  	case NFPROTO_IPV4:
  	case NFPROTO_IPV6:
  	case NFPROTO_INET:
  		hooks = (1 << NF_INET_PRE_ROUTING) |
  			(1 << NF_INET_LOCAL_IN) |
  			(1 << NF_INET_FORWARD);
  		break;
  	default:
  		return -EOPNOTSUPP;
  	}
  
  	return nft_chain_validate_hooks(ctx->chain, hooks);
  #else
  	return 0;
  #endif
  }
30e103fe2   wenxu   netfilter: nft_me...
409
410
411
  int nft_meta_set_validate(const struct nft_ctx *ctx,
  			  const struct nft_expr *expr,
  			  const struct nft_data **data)
b4aae759c   Florian Westphal   netfilter: meta: ...
412
  {
960fa72f6   Liping Zhang   netfilter: nft_me...
413
  	struct nft_meta *priv = nft_expr_priv(expr);
b4aae759c   Florian Westphal   netfilter: meta: ...
414
  	unsigned int hooks;
960fa72f6   Liping Zhang   netfilter: nft_me...
415
416
  	if (priv->key != NFT_META_PKTTYPE)
  		return 0;
36596dadf   Pablo Neira Ayuso   netfilter: nf_tab...
417
  	switch (ctx->family) {
b4aae759c   Florian Westphal   netfilter: meta: ...
418
419
420
421
422
423
  	case NFPROTO_BRIDGE:
  		hooks = 1 << NF_BR_PRE_ROUTING;
  		break;
  	case NFPROTO_NETDEV:
  		hooks = 1 << NF_NETDEV_INGRESS;
  		break;
96d9f2a72   Liping Zhang   netfilter: nft_me...
424
425
426
427
428
  	case NFPROTO_IPV4:
  	case NFPROTO_IPV6:
  	case NFPROTO_INET:
  		hooks = 1 << NF_INET_PRE_ROUTING;
  		break;
b4aae759c   Florian Westphal   netfilter: meta: ...
429
430
431
432
433
434
  	default:
  		return -EOPNOTSUPP;
  	}
  
  	return nft_chain_validate_hooks(ctx->chain, hooks);
  }
30e103fe2   wenxu   netfilter: nft_me...
435
  EXPORT_SYMBOL_GPL(nft_meta_set_validate);
b4aae759c   Florian Westphal   netfilter: meta: ...
436

30e103fe2   wenxu   netfilter: nft_me...
437
438
439
  int nft_meta_set_init(const struct nft_ctx *ctx,
  		      const struct nft_expr *expr,
  		      const struct nlattr * const tb[])
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
440
441
  {
  	struct nft_meta *priv = nft_expr_priv(expr);
d07db9884   Patrick McHardy   netfilter: nf_tab...
442
  	unsigned int len;
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
443
444
445
  	int err;
  
  	priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
d2caa696a   Patrick McHardy   netfilter: nft_me...
446
447
448
  	switch (priv->key) {
  	case NFT_META_MARK:
  	case NFT_META_PRIORITY:
b473a1f5d   Christian Göttsche   netfilter: nf_tab...
449
450
451
  #ifdef CONFIG_NETWORK_SECMARK
  	case NFT_META_SECMARK:
  #endif
d07db9884   Patrick McHardy   netfilter: nf_tab...
452
453
  		len = sizeof(u32);
  		break;
d2caa696a   Patrick McHardy   netfilter: nft_me...
454
  	case NFT_META_NFTRACE:
d07db9884   Patrick McHardy   netfilter: nf_tab...
455
  		len = sizeof(u8);
d2caa696a   Patrick McHardy   netfilter: nft_me...
456
  		break;
b4aae759c   Florian Westphal   netfilter: meta: ...
457
  	case NFT_META_PKTTYPE:
b4aae759c   Florian Westphal   netfilter: meta: ...
458
459
  		len = sizeof(u8);
  		break;
d2caa696a   Patrick McHardy   netfilter: nft_me...
460
461
  	default:
  		return -EOPNOTSUPP;
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
462
  	}
b1c96ed37   Patrick McHardy   netfilter: nf_tab...
463
  	priv->sreg = nft_parse_register(tb[NFTA_META_SREG]);
d07db9884   Patrick McHardy   netfilter: nf_tab...
464
  	err = nft_validate_register_load(priv->sreg, len);
b38895c57   Pablo Neira Ayuso   netfilter: nft_me...
465
466
  	if (err < 0)
  		return err;
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
467

e639f7ab0   Florian Westphal   netfilter: nf_tab...
468
469
  	if (priv->key == NFT_META_NFTRACE)
  		static_branch_inc(&nft_trace_enabled);
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
470
  	return 0;
96518518c   Patrick McHardy   netfilter: add nf...
471
  }
30e103fe2   wenxu   netfilter: nft_me...
472
  EXPORT_SYMBOL_GPL(nft_meta_set_init);
96518518c   Patrick McHardy   netfilter: add nf...
473

30e103fe2   wenxu   netfilter: nft_me...
474
475
  int nft_meta_get_dump(struct sk_buff *skb,
  		      const struct nft_expr *expr)
96518518c   Patrick McHardy   netfilter: add nf...
476
477
  {
  	const struct nft_meta *priv = nft_expr_priv(expr);
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
478
479
  	if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key)))
  		goto nla_put_failure;
b1c96ed37   Patrick McHardy   netfilter: nf_tab...
480
  	if (nft_dump_register(skb, NFTA_META_DREG, priv->dreg))
96518518c   Patrick McHardy   netfilter: add nf...
481
  		goto nla_put_failure;
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
482
483
484
485
486
  	return 0;
  
  nla_put_failure:
  	return -1;
  }
30e103fe2   wenxu   netfilter: nft_me...
487
  EXPORT_SYMBOL_GPL(nft_meta_get_dump);
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
488

30e103fe2   wenxu   netfilter: nft_me...
489
  int nft_meta_set_dump(struct sk_buff *skb, const struct nft_expr *expr)
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
490
491
  {
  	const struct nft_meta *priv = nft_expr_priv(expr);
96518518c   Patrick McHardy   netfilter: add nf...
492
493
  	if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key)))
  		goto nla_put_failure;
b1c96ed37   Patrick McHardy   netfilter: nf_tab...
494
  	if (nft_dump_register(skb, NFTA_META_SREG, priv->sreg))
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
495
  		goto nla_put_failure;
96518518c   Patrick McHardy   netfilter: add nf...
496
497
498
499
500
  	return 0;
  
  nla_put_failure:
  	return -1;
  }
30e103fe2   wenxu   netfilter: nft_me...
501
  EXPORT_SYMBOL_GPL(nft_meta_set_dump);
96518518c   Patrick McHardy   netfilter: add nf...
502

30e103fe2   wenxu   netfilter: nft_me...
503
504
  void nft_meta_set_destroy(const struct nft_ctx *ctx,
  			  const struct nft_expr *expr)
e639f7ab0   Florian Westphal   netfilter: nf_tab...
505
506
507
508
509
510
  {
  	const struct nft_meta *priv = nft_expr_priv(expr);
  
  	if (priv->key == NFT_META_NFTRACE)
  		static_branch_dec(&nft_trace_enabled);
  }
30e103fe2   wenxu   netfilter: nft_me...
511
  EXPORT_SYMBOL_GPL(nft_meta_set_destroy);
e639f7ab0   Florian Westphal   netfilter: nf_tab...
512

c9626a2cb   Pablo Neira Ayuso   netfilter: nf_tab...
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
  static int nft_meta_get_offload(struct nft_offload_ctx *ctx,
  				struct nft_flow_rule *flow,
  				const struct nft_expr *expr)
  {
  	const struct nft_meta *priv = nft_expr_priv(expr);
  	struct nft_offload_reg *reg = &ctx->regs[priv->dreg];
  
  	switch (priv->key) {
  	case NFT_META_PROTOCOL:
  		NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_BASIC, basic, n_proto,
  				  sizeof(__u16), reg);
  		nft_offload_set_dependency(ctx, NFT_OFFLOAD_DEP_NETWORK);
  		break;
  	case NFT_META_L4PROTO:
  		NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_BASIC, basic, ip_proto,
  				  sizeof(__u8), reg);
  		nft_offload_set_dependency(ctx, NFT_OFFLOAD_DEP_TRANSPORT);
  		break;
25da5eb32   Pablo Neira Ayuso   netfilter: nft_me...
531
532
533
534
  	case NFT_META_IIF:
  		NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_META, meta,
  				  ingress_ifindex, sizeof(__u32), reg);
  		break;
8819efc94   Pablo Neira Ayuso   netfilter: nf_tab...
535
536
537
538
  	case NFT_META_IIFTYPE:
  		NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_META, meta,
  				  ingress_iftype, sizeof(__u16), reg);
  		break;
c9626a2cb   Pablo Neira Ayuso   netfilter: nf_tab...
539
540
541
542
543
544
  	default:
  		return -EOPNOTSUPP;
  	}
  
  	return 0;
  }
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
545
  static const struct nft_expr_ops nft_meta_get_ops = {
ef1f7df91   Patrick McHardy   netfilter: nf_tab...
546
  	.type		= &nft_meta_type,
96518518c   Patrick McHardy   netfilter: add nf...
547
  	.size		= NFT_EXPR_SIZE(sizeof(struct nft_meta)),
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
548
  	.eval		= nft_meta_get_eval,
d2caa696a   Patrick McHardy   netfilter: nft_me...
549
  	.init		= nft_meta_get_init,
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
550
  	.dump		= nft_meta_get_dump,
f6931f5f5   Florian Westphal   netfilter: meta: ...
551
  	.validate	= nft_meta_get_validate,
c9626a2cb   Pablo Neira Ayuso   netfilter: nf_tab...
552
  	.offload	= nft_meta_get_offload,
ef1f7df91   Patrick McHardy   netfilter: nf_tab...
553
  };
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
554
555
556
557
  static const struct nft_expr_ops nft_meta_set_ops = {
  	.type		= &nft_meta_type,
  	.size		= NFT_EXPR_SIZE(sizeof(struct nft_meta)),
  	.eval		= nft_meta_set_eval,
d2caa696a   Patrick McHardy   netfilter: nft_me...
558
  	.init		= nft_meta_set_init,
e639f7ab0   Florian Westphal   netfilter: nf_tab...
559
  	.destroy	= nft_meta_set_destroy,
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
560
  	.dump		= nft_meta_set_dump,
960fa72f6   Liping Zhang   netfilter: nft_me...
561
  	.validate	= nft_meta_set_validate,
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
562
563
564
565
566
567
568
569
570
571
572
  };
  
  static const struct nft_expr_ops *
  nft_meta_select_ops(const struct nft_ctx *ctx,
  		    const struct nlattr * const tb[])
  {
  	if (tb[NFTA_META_KEY] == NULL)
  		return ERR_PTR(-EINVAL);
  
  	if (tb[NFTA_META_DREG] && tb[NFTA_META_SREG])
  		return ERR_PTR(-EINVAL);
dfee0e99b   Arnd Bergmann   netfilter: bridge...
573
  #if IS_ENABLED(CONFIG_NF_TABLES_BRIDGE) && IS_MODULE(CONFIG_NFT_BRIDGE_META)
0ef1efd13   Pablo Neira Ayuso   netfilter: nf_tab...
574
575
576
  	if (ctx->family == NFPROTO_BRIDGE)
  		return ERR_PTR(-EAGAIN);
  #endif
e035b77ac   Arturo Borrero Gonzalez   netfilter: nf_tab...
577
578
579
580
581
582
583
584
  	if (tb[NFTA_META_DREG])
  		return &nft_meta_get_ops;
  
  	if (tb[NFTA_META_SREG])
  		return &nft_meta_set_ops;
  
  	return ERR_PTR(-EINVAL);
  }
8a22543c8   Florian Westphal   netfilter: nf_tab...
585
  struct nft_expr_type nft_meta_type __read_mostly = {
ef1f7df91   Patrick McHardy   netfilter: nf_tab...
586
  	.name		= "meta",
d4ef38354   Arushi Singhal   netfilter: Remove...
587
  	.select_ops	= nft_meta_select_ops,
96518518c   Patrick McHardy   netfilter: add nf...
588
589
  	.policy		= nft_meta_policy,
  	.maxattr	= NFTA_META_MAX,
ef1f7df91   Patrick McHardy   netfilter: nf_tab...
590
  	.owner		= THIS_MODULE,
96518518c   Patrick McHardy   netfilter: add nf...
591
  };
fb9619454   Christian Göttsche   netfilter: nf_tab...
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
  
  #ifdef CONFIG_NETWORK_SECMARK
  struct nft_secmark {
  	u32 secid;
  	char *ctx;
  };
  
  static const struct nla_policy nft_secmark_policy[NFTA_SECMARK_MAX + 1] = {
  	[NFTA_SECMARK_CTX]     = { .type = NLA_STRING, .len = NFT_SECMARK_CTX_MAXLEN },
  };
  
  static int nft_secmark_compute_secid(struct nft_secmark *priv)
  {
  	u32 tmp_secid = 0;
  	int err;
  
  	err = security_secctx_to_secid(priv->ctx, strlen(priv->ctx), &tmp_secid);
  	if (err)
  		return err;
  
  	if (!tmp_secid)
  		return -ENOENT;
  
  	err = security_secmark_relabel_packet(tmp_secid);
  	if (err)
  		return err;
  
  	priv->secid = tmp_secid;
  	return 0;
  }
  
  static void nft_secmark_obj_eval(struct nft_object *obj, struct nft_regs *regs,
  				 const struct nft_pktinfo *pkt)
  {
  	const struct nft_secmark *priv = nft_obj_data(obj);
  	struct sk_buff *skb = pkt->skb;
  
  	skb->secmark = priv->secid;
  }
  
  static int nft_secmark_obj_init(const struct nft_ctx *ctx,
  				const struct nlattr * const tb[],
  				struct nft_object *obj)
  {
  	struct nft_secmark *priv = nft_obj_data(obj);
  	int err;
  
  	if (tb[NFTA_SECMARK_CTX] == NULL)
  		return -EINVAL;
  
  	priv->ctx = nla_strdup(tb[NFTA_SECMARK_CTX], GFP_KERNEL);
  	if (!priv->ctx)
  		return -ENOMEM;
  
  	err = nft_secmark_compute_secid(priv);
  	if (err) {
  		kfree(priv->ctx);
  		return err;
  	}
  
  	security_secmark_refcount_inc();
  
  	return 0;
  }
  
  static int nft_secmark_obj_dump(struct sk_buff *skb, struct nft_object *obj,
  				bool reset)
  {
  	struct nft_secmark *priv = nft_obj_data(obj);
  	int err;
  
  	if (nla_put_string(skb, NFTA_SECMARK_CTX, priv->ctx))
  		return -1;
  
  	if (reset) {
  		err = nft_secmark_compute_secid(priv);
  		if (err)
  			return err;
  	}
  
  	return 0;
  }
  
  static void nft_secmark_obj_destroy(const struct nft_ctx *ctx, struct nft_object *obj)
  {
  	struct nft_secmark *priv = nft_obj_data(obj);
  
  	security_secmark_refcount_dec();
  
  	kfree(priv->ctx);
  }
  
  static const struct nft_object_ops nft_secmark_obj_ops = {
  	.type		= &nft_secmark_obj_type,
  	.size		= sizeof(struct nft_secmark),
  	.init		= nft_secmark_obj_init,
  	.eval		= nft_secmark_obj_eval,
  	.dump		= nft_secmark_obj_dump,
  	.destroy	= nft_secmark_obj_destroy,
  };
  struct nft_object_type nft_secmark_obj_type __read_mostly = {
  	.type		= NFT_OBJECT_SECMARK,
  	.ops		= &nft_secmark_obj_ops,
  	.maxattr	= NFTA_SECMARK_MAX,
  	.policy		= nft_secmark_policy,
  	.owner		= THIS_MODULE,
  };
  #endif /* CONFIG_NETWORK_SECMARK */