nft_reject_bridge.c 11.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
 * Copyright (c) 2014 Pablo Neira Ayuso <pablo@netfilter.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/netlink.h>
#include <linux/netfilter.h>
#include <linux/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables.h>
#include <net/netfilter/nft_reject.h>
17
18
#include <net/netfilter/ipv4/nf_reject.h>
#include <net/netfilter/ipv6/nf_reject.h>
19
20
#include <linux/ip.h>
#include <net/ip.h>
21
#include <net/ip6_checksum.h>
22
#include <linux/netfilter_bridge.h>
23
#include <linux/netfilter_ipv6.h>
24
25
26
27
28
29
30
#include "../br_private.h"

static void nft_reject_br_push_etherhdr(struct sk_buff *oldskb,
					struct sk_buff *nskb)
{
	struct ethhdr *eth;

31
	eth = skb_push(nskb, ETH_HLEN);
32
33
34
35
36
37
38
	skb_reset_mac_header(nskb);
	ether_addr_copy(eth->h_source, eth_hdr(oldskb)->h_dest);
	ether_addr_copy(eth->h_dest, eth_hdr(oldskb)->h_source);
	eth->h_proto = eth_hdr(oldskb)->h_proto;
	skb_pull(nskb, ETH_HLEN);
}

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
static int nft_bridge_iphdr_validate(struct sk_buff *skb)
{
	struct iphdr *iph;
	u32 len;

	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
		return 0;

	iph = ip_hdr(skb);
	if (iph->ihl < 5 || iph->version != 4)
		return 0;

	len = ntohs(iph->tot_len);
	if (skb->len < len)
		return 0;
	else if (len < (iph->ihl*4))
		return 0;

	if (!pskb_may_pull(skb, iph->ihl*4))
		return 0;

	return 1;
}

63
64
65
/* We cannot use oldskb->dev, it can be either bridge device (NF_BRIDGE INPUT)
 * or the bridge port (NF_BRIDGE PREROUTING).
 */
66
67
static void nft_reject_br_send_v4_tcp_reset(struct net *net,
					    struct sk_buff *oldskb,
68
69
					    const struct net_device *dev,
					    int hook)
70
71
72
73
74
75
{
	struct sk_buff *nskb;
	struct iphdr *niph;
	const struct tcphdr *oth;
	struct tcphdr _oth;

76
	if (!nft_bridge_iphdr_validate(oldskb))
77
78
79
80
81
82
83
84
85
86
87
88
89
		return;

	oth = nf_reject_ip_tcphdr_get(oldskb, &_oth, hook);
	if (!oth)
		return;

	nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) +
			 LL_MAX_HEADER, GFP_ATOMIC);
	if (!nskb)
		return;

	skb_reserve(nskb, LL_MAX_HEADER);
	niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_TCP,
90
				   net->ipv4.sysctl_ip_default_ttl);
91
	nf_reject_ip_tcphdr_put(nskb, oldskb, oth);
92
	niph->tot_len = htons(nskb->len);
93
94
95
96
	ip_send_check(niph);

	nft_reject_br_push_etherhdr(oldskb, nskb);

97
	br_forward(br_port_get_rcu(dev), nskb, false, true);
98
99
}

100
101
static void nft_reject_br_send_v4_unreach(struct net *net,
					  struct sk_buff *oldskb,
102
103
					  const struct net_device *dev,
					  int hook, u8 code)
104
105
106
107
108
109
{
	struct sk_buff *nskb;
	struct iphdr *niph;
	struct icmphdr *icmph;
	unsigned int len;
	__wsum csum;
110
	u8 proto;
111

112
	if (!nft_bridge_iphdr_validate(oldskb))
113
114
115
116
117
118
119
120
121
122
123
124
		return;

	/* IP header checks: fragment. */
	if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET))
		return;

	/* RFC says return as much as we can without exceeding 576 bytes. */
	len = min_t(unsigned int, 536, oldskb->len);

	if (!pskb_may_pull(oldskb, len))
		return;

125
	if (pskb_trim_rcsum(oldskb, ntohs(ip_hdr(oldskb)->tot_len)))
126
127
128
129
130
131
132
133
134
135
		return;

	if (ip_hdr(oldskb)->protocol == IPPROTO_TCP ||
	    ip_hdr(oldskb)->protocol == IPPROTO_UDP)
		proto = ip_hdr(oldskb)->protocol;
	else
		proto = 0;

	if (!skb_csum_unnecessary(oldskb) &&
	    nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), proto))
136
137
138
139
140
141
142
143
144
		return;

	nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct icmphdr) +
			 LL_MAX_HEADER + len, GFP_ATOMIC);
	if (!nskb)
		return;

	skb_reserve(nskb, LL_MAX_HEADER);
	niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_ICMP,
145
				   net->ipv4.sysctl_ip_default_ttl);
146
147

	skb_reset_transport_header(nskb);
148
	icmph = skb_put_zero(nskb, sizeof(struct icmphdr));
149
150
151
	icmph->type     = ICMP_DEST_UNREACH;
	icmph->code	= code;

152
	skb_put_data(nskb, skb_network_header(oldskb), len);
153
154
155
156
157
158
159
160
161

	csum = csum_partial((void *)icmph, len + sizeof(struct icmphdr), 0);
	icmph->checksum = csum_fold(csum);

	niph->tot_len	= htons(nskb->len);
	ip_send_check(niph);

	nft_reject_br_push_etherhdr(oldskb, nskb);

162
	br_forward(br_port_get_rcu(dev), nskb, false, true);
163
164
}

165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
static int nft_bridge_ip6hdr_validate(struct sk_buff *skb)
{
	struct ipv6hdr *hdr;
	u32 pkt_len;

	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
		return 0;

	hdr = ipv6_hdr(skb);
	if (hdr->version != 6)
		return 0;

	pkt_len = ntohs(hdr->payload_len);
	if (pkt_len + sizeof(struct ipv6hdr) > skb->len)
		return 0;

	return 1;
}

184
static void nft_reject_br_send_v6_tcp_reset(struct net *net,
185
186
187
					    struct sk_buff *oldskb,
					    const struct net_device *dev,
					    int hook)
188
189
190
191
192
193
194
{
	struct sk_buff *nskb;
	const struct tcphdr *oth;
	struct tcphdr _oth;
	unsigned int otcplen;
	struct ipv6hdr *nip6h;

195
	if (!nft_bridge_ip6hdr_validate(oldskb))
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
		return;

	oth = nf_reject_ip6_tcphdr_get(oldskb, &_oth, &otcplen, hook);
	if (!oth)
		return;

	nskb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(struct tcphdr) +
			 LL_MAX_HEADER, GFP_ATOMIC);
	if (!nskb)
		return;

	skb_reserve(nskb, LL_MAX_HEADER);
	nip6h = nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_TCP,
				     net->ipv6.devconf_all->hop_limit);
	nf_reject_ip6_tcphdr_put(nskb, oldskb, oth, otcplen);
	nip6h->payload_len = htons(nskb->len - sizeof(struct ipv6hdr));

	nft_reject_br_push_etherhdr(oldskb, nskb);

215
	br_forward(br_port_get_rcu(dev), nskb, false, true);
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
}

static bool reject6_br_csum_ok(struct sk_buff *skb, int hook)
{
	const struct ipv6hdr *ip6h = ipv6_hdr(skb);
	int thoff;
	__be16 fo;
	u8 proto = ip6h->nexthdr;

	if (skb_csum_unnecessary(skb))
		return true;

	if (ip6h->payload_len &&
	    pskb_trim_rcsum(skb, ntohs(ip6h->payload_len) + sizeof(*ip6h)))
		return false;

232
	ip6h = ipv6_hdr(skb);
233
234
235
236
237
	thoff = ipv6_skip_exthdr(skb, ((u8*)(ip6h+1) - skb->data), &proto, &fo);
	if (thoff < 0 || thoff >= skb->len || (fo & htons(~0x7)) != 0)
		return false;

	return nf_ip6_checksum(skb, hook, thoff, proto) == 0;
238
239
240
}

static void nft_reject_br_send_v6_unreach(struct net *net,
241
242
243
					  struct sk_buff *oldskb,
					  const struct net_device *dev,
					  int hook, u8 code)
244
245
246
247
248
249
{
	struct sk_buff *nskb;
	struct ipv6hdr *nip6h;
	struct icmp6hdr *icmp6h;
	unsigned int len;

250
	if (!nft_bridge_ip6hdr_validate(oldskb))
251
252
253
254
255
256
257
258
259
260
		return;

	/* Include "As much of invoking packet as possible without the ICMPv6
	 * packet exceeding the minimum IPv6 MTU" in the ICMP payload.
	 */
	len = min_t(unsigned int, 1220, oldskb->len);

	if (!pskb_may_pull(oldskb, len))
		return;

261
262
263
	if (!reject6_br_csum_ok(oldskb, hook))
		return;

264
	nskb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(struct icmp6hdr) +
265
266
267
268
269
270
271
272
273
			 LL_MAX_HEADER + len, GFP_ATOMIC);
	if (!nskb)
		return;

	skb_reserve(nskb, LL_MAX_HEADER);
	nip6h = nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_ICMPV6,
				     net->ipv6.devconf_all->hop_limit);

	skb_reset_transport_header(nskb);
274
	icmp6h = skb_put_zero(nskb, sizeof(struct icmp6hdr));
275
276
277
	icmp6h->icmp6_type = ICMPV6_DEST_UNREACH;
	icmp6h->icmp6_code = code;

278
	skb_put_data(nskb, skb_network_header(oldskb), len);
279
280
281
282
283
284
285
286
287
288
289
290
	nip6h->payload_len = htons(nskb->len - sizeof(struct ipv6hdr));

	icmp6h->icmp6_cksum =
		csum_ipv6_magic(&nip6h->saddr, &nip6h->daddr,
				nskb->len - sizeof(struct ipv6hdr),
				IPPROTO_ICMPV6,
				csum_partial(icmp6h,
					     nskb->len - sizeof(struct ipv6hdr),
					     0));

	nft_reject_br_push_etherhdr(oldskb, nskb);

291
	br_forward(br_port_get_rcu(dev), nskb, false, true);
292
}
293
294

static void nft_reject_bridge_eval(const struct nft_expr *expr,
295
296
				   struct nft_regs *regs,
				   const struct nft_pktinfo *pkt)
297
{
298
	struct nft_reject *priv = nft_expr_priv(expr);
299
300
301
302
303
	const unsigned char *dest = eth_hdr(pkt->skb)->h_dest;

	if (is_broadcast_ether_addr(dest) ||
	    is_multicast_ether_addr(dest))
		goto out;
304

305
306
	switch (eth_hdr(pkt->skb)->h_proto) {
	case htons(ETH_P_IP):
307
308
		switch (priv->type) {
		case NFT_REJECT_ICMP_UNREACH:
309
310
311
			nft_reject_br_send_v4_unreach(nft_net(pkt), pkt->skb,
						      nft_in(pkt),
						      nft_hook(pkt),
312
						      priv->icmp_code);
313
314
			break;
		case NFT_REJECT_TCP_RST:
315
316
317
			nft_reject_br_send_v4_tcp_reset(nft_net(pkt), pkt->skb,
							nft_in(pkt),
							nft_hook(pkt));
318
319
			break;
		case NFT_REJECT_ICMPX_UNREACH:
320
321
322
			nft_reject_br_send_v4_unreach(nft_net(pkt), pkt->skb,
						      nft_in(pkt),
						      nft_hook(pkt),
323
						      nft_reject_icmp_code(priv->icmp_code));
324
325
326
			break;
		}
		break;
327
	case htons(ETH_P_IPV6):
328
329
		switch (priv->type) {
		case NFT_REJECT_ICMP_UNREACH:
330
331
332
			nft_reject_br_send_v6_unreach(nft_net(pkt), pkt->skb,
						      nft_in(pkt),
						      nft_hook(pkt),
333
						      priv->icmp_code);
334
335
			break;
		case NFT_REJECT_TCP_RST:
336
337
338
			nft_reject_br_send_v6_tcp_reset(nft_net(pkt), pkt->skb,
							nft_in(pkt),
							nft_hook(pkt));
339
340
			break;
		case NFT_REJECT_ICMPX_UNREACH:
341
342
343
			nft_reject_br_send_v6_unreach(nft_net(pkt), pkt->skb,
						      nft_in(pkt),
						      nft_hook(pkt),
344
						      nft_reject_icmpv6_code(priv->icmp_code));
345
346
347
			break;
		}
		break;
348
349
350
351
	default:
		/* No explicit way to reject this protocol, drop it. */
		break;
	}
352
out:
353
	regs->verdict.code = NF_DROP;
354
355
}

356
357
358
static int nft_reject_bridge_validate(const struct nft_ctx *ctx,
				      const struct nft_expr *expr,
				      const struct nft_data **data)
359
{
360
361
	return nft_chain_validate_hooks(ctx->chain, (1 << NF_BR_PRE_ROUTING) |
						    (1 << NF_BR_LOCAL_IN));
362
363
}

364
365
366
367
368
static int nft_reject_bridge_init(const struct nft_ctx *ctx,
				  const struct nft_expr *expr,
				  const struct nlattr * const tb[])
{
	struct nft_reject *priv = nft_expr_priv(expr);
369
	int icmp_code;
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409

	if (tb[NFTA_REJECT_TYPE] == NULL)
		return -EINVAL;

	priv->type = ntohl(nla_get_be32(tb[NFTA_REJECT_TYPE]));
	switch (priv->type) {
	case NFT_REJECT_ICMP_UNREACH:
	case NFT_REJECT_ICMPX_UNREACH:
		if (tb[NFTA_REJECT_ICMP_CODE] == NULL)
			return -EINVAL;

		icmp_code = nla_get_u8(tb[NFTA_REJECT_ICMP_CODE]);
		if (priv->type == NFT_REJECT_ICMPX_UNREACH &&
		    icmp_code > NFT_REJECT_ICMPX_MAX)
			return -EINVAL;

		priv->icmp_code = icmp_code;
		break;
	case NFT_REJECT_TCP_RST:
		break;
	default:
		return -EINVAL;
	}
	return 0;
}

static int nft_reject_bridge_dump(struct sk_buff *skb,
				  const struct nft_expr *expr)
{
	const struct nft_reject *priv = nft_expr_priv(expr);

	if (nla_put_be32(skb, NFTA_REJECT_TYPE, htonl(priv->type)))
		goto nla_put_failure;

	switch (priv->type) {
	case NFT_REJECT_ICMP_UNREACH:
	case NFT_REJECT_ICMPX_UNREACH:
		if (nla_put_u8(skb, NFTA_REJECT_ICMP_CODE, priv->icmp_code))
			goto nla_put_failure;
		break;
410
411
	default:
		break;
412
413
414
415
416
417
	}

	return 0;

nla_put_failure:
	return -1;
418
419
420
421
422
423
424
}

static struct nft_expr_type nft_reject_bridge_type;
static const struct nft_expr_ops nft_reject_bridge_ops = {
	.type		= &nft_reject_bridge_type,
	.size		= NFT_EXPR_SIZE(sizeof(struct nft_reject)),
	.eval		= nft_reject_bridge_eval,
425
426
	.init		= nft_reject_bridge_init,
	.dump		= nft_reject_bridge_dump,
427
	.validate	= nft_reject_bridge_validate,
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
};

static struct nft_expr_type nft_reject_bridge_type __read_mostly = {
	.family		= NFPROTO_BRIDGE,
	.name		= "reject",
	.ops		= &nft_reject_bridge_ops,
	.policy		= nft_reject_policy,
	.maxattr	= NFTA_REJECT_MAX,
	.owner		= THIS_MODULE,
};

static int __init nft_reject_bridge_module_init(void)
{
	return nft_register_expr(&nft_reject_bridge_type);
}

static void __exit nft_reject_bridge_module_exit(void)
{
	nft_unregister_expr(&nft_reject_bridge_type);
}

module_init(nft_reject_bridge_module_init);
module_exit(nft_reject_bridge_module_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
MODULE_ALIAS_NFT_AF_EXPR(AF_BRIDGE, "reject");