Linux-libre 3.18.132-gnu
[librecmc/linux-libre.git] / net / bridge / netfilter / nft_reject_bridge.c
1 /*
2  * Copyright (c) 2014 Pablo Neira Ayuso <pablo@netfilter.org>
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
9 #include <linux/kernel.h>
10 #include <linux/init.h>
11 #include <linux/module.h>
12 #include <linux/netlink.h>
13 #include <linux/netfilter.h>
14 #include <linux/netfilter/nf_tables.h>
15 #include <net/netfilter/nf_tables.h>
16 #include <net/netfilter/nft_reject.h>
17 #include <net/netfilter/ipv4/nf_reject.h>
18 #include <net/netfilter/ipv6/nf_reject.h>
19 #include <linux/ip.h>
20 #include <net/ip.h>
21 #include <net/ip6_checksum.h>
22 #include <linux/netfilter_bridge.h>
23 #include "../br_private.h"
24
25 static void nft_reject_br_push_etherhdr(struct sk_buff *oldskb,
26                                         struct sk_buff *nskb)
27 {
28         struct ethhdr *eth;
29
30         eth = (struct ethhdr *)skb_push(nskb, ETH_HLEN);
31         skb_reset_mac_header(nskb);
32         ether_addr_copy(eth->h_source, eth_hdr(oldskb)->h_dest);
33         ether_addr_copy(eth->h_dest, eth_hdr(oldskb)->h_source);
34         eth->h_proto = eth_hdr(oldskb)->h_proto;
35         skb_pull(nskb, ETH_HLEN);
36 }
37
38 static int nft_reject_iphdr_validate(struct sk_buff *oldskb)
39 {
40         struct iphdr *iph;
41         u32 len;
42
43         if (!pskb_may_pull(oldskb, sizeof(struct iphdr)))
44                 return 0;
45
46         iph = ip_hdr(oldskb);
47         if (iph->ihl < 5 || iph->version != 4)
48                 return 0;
49
50         len = ntohs(iph->tot_len);
51         if (oldskb->len < len)
52                 return 0;
53         else if (len < (iph->ihl*4))
54                 return 0;
55
56         if (!pskb_may_pull(oldskb, iph->ihl*4))
57                 return 0;
58
59         return 1;
60 }
61
62 static void nft_reject_br_send_v4_tcp_reset(struct sk_buff *oldskb, int hook)
63 {
64         struct sk_buff *nskb;
65         struct iphdr *niph;
66         const struct tcphdr *oth;
67         struct tcphdr _oth;
68
69         if (!nft_reject_iphdr_validate(oldskb))
70                 return;
71
72         oth = nf_reject_ip_tcphdr_get(oldskb, &_oth, hook);
73         if (!oth)
74                 return;
75
76         nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) +
77                          LL_MAX_HEADER, GFP_ATOMIC);
78         if (!nskb)
79                 return;
80
81         skb_reserve(nskb, LL_MAX_HEADER);
82         niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_TCP,
83                                    sysctl_ip_default_ttl);
84         nf_reject_ip_tcphdr_put(nskb, oldskb, oth);
85         niph->ttl       = sysctl_ip_default_ttl;
86         niph->tot_len   = htons(nskb->len);
87         ip_send_check(niph);
88
89         nft_reject_br_push_etherhdr(oldskb, nskb);
90
91         br_deliver(br_port_get_rcu(oldskb->dev), nskb);
92 }
93
94 static void nft_reject_br_send_v4_unreach(struct sk_buff *oldskb, int hook,
95                                           u8 code)
96 {
97         struct sk_buff *nskb;
98         struct iphdr *niph;
99         struct icmphdr *icmph;
100         unsigned int len;
101         void *payload;
102         __wsum csum;
103
104         if (!nft_reject_iphdr_validate(oldskb))
105                 return;
106
107         /* IP header checks: fragment. */
108         if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET))
109                 return;
110
111         /* RFC says return as much as we can without exceeding 576 bytes. */
112         len = min_t(unsigned int, 536, oldskb->len);
113
114         if (!pskb_may_pull(oldskb, len))
115                 return;
116
117         if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), 0))
118                 return;
119
120         nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct icmphdr) +
121                          LL_MAX_HEADER + len, GFP_ATOMIC);
122         if (!nskb)
123                 return;
124
125         skb_reserve(nskb, LL_MAX_HEADER);
126         niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_ICMP,
127                                    sysctl_ip_default_ttl);
128
129         skb_reset_transport_header(nskb);
130         icmph = (struct icmphdr *)skb_put(nskb, sizeof(struct icmphdr));
131         memset(icmph, 0, sizeof(*icmph));
132         icmph->type     = ICMP_DEST_UNREACH;
133         icmph->code     = code;
134
135         payload = skb_put(nskb, len);
136         memcpy(payload, skb_network_header(oldskb), len);
137
138         csum = csum_partial((void *)icmph, len + sizeof(struct icmphdr), 0);
139         icmph->checksum = csum_fold(csum);
140
141         niph->tot_len   = htons(nskb->len);
142         ip_send_check(niph);
143
144         nft_reject_br_push_etherhdr(oldskb, nskb);
145
146         br_deliver(br_port_get_rcu(oldskb->dev), nskb);
147 }
148
149 static int nft_reject_ip6hdr_validate(struct sk_buff *oldskb)
150 {
151         struct ipv6hdr *hdr;
152         u32 pkt_len;
153
154         if (!pskb_may_pull(oldskb, sizeof(struct ipv6hdr)))
155                 return 0;
156
157         hdr = ipv6_hdr(oldskb);
158         if (hdr->version != 6)
159                 return 0;
160
161         pkt_len = ntohs(hdr->payload_len);
162         if (pkt_len + sizeof(struct ipv6hdr) > oldskb->len)
163                 return 0;
164
165         return 1;
166 }
167
168 static void nft_reject_br_send_v6_tcp_reset(struct net *net,
169                                             struct sk_buff *oldskb, int hook)
170 {
171         struct sk_buff *nskb;
172         const struct tcphdr *oth;
173         struct tcphdr _oth;
174         unsigned int otcplen;
175         struct ipv6hdr *nip6h;
176
177         if (!nft_reject_ip6hdr_validate(oldskb))
178                 return;
179
180         oth = nf_reject_ip6_tcphdr_get(oldskb, &_oth, &otcplen, hook);
181         if (!oth)
182                 return;
183
184         nskb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(struct tcphdr) +
185                          LL_MAX_HEADER, GFP_ATOMIC);
186         if (!nskb)
187                 return;
188
189         skb_reserve(nskb, LL_MAX_HEADER);
190         nip6h = nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_TCP,
191                                      net->ipv6.devconf_all->hop_limit);
192         nf_reject_ip6_tcphdr_put(nskb, oldskb, oth, otcplen);
193         nip6h->payload_len = htons(nskb->len - sizeof(struct ipv6hdr));
194
195         nft_reject_br_push_etherhdr(oldskb, nskb);
196
197         br_deliver(br_port_get_rcu(oldskb->dev), nskb);
198 }
199
200 static void nft_reject_br_send_v6_unreach(struct net *net,
201                                           struct sk_buff *oldskb, int hook,
202                                           u8 code)
203 {
204         struct sk_buff *nskb;
205         struct ipv6hdr *nip6h;
206         struct icmp6hdr *icmp6h;
207         unsigned int len;
208         void *payload;
209
210         if (!nft_reject_ip6hdr_validate(oldskb))
211                 return;
212
213         /* Include "As much of invoking packet as possible without the ICMPv6
214          * packet exceeding the minimum IPv6 MTU" in the ICMP payload.
215          */
216         len = min_t(unsigned int, 1220, oldskb->len);
217
218         if (!pskb_may_pull(oldskb, len))
219                 return;
220
221         nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct icmp6hdr) +
222                          LL_MAX_HEADER + len, GFP_ATOMIC);
223         if (!nskb)
224                 return;
225
226         skb_reserve(nskb, LL_MAX_HEADER);
227         nip6h = nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_ICMPV6,
228                                      net->ipv6.devconf_all->hop_limit);
229
230         skb_reset_transport_header(nskb);
231         icmp6h = (struct icmp6hdr *)skb_put(nskb, sizeof(struct icmp6hdr));
232         memset(icmp6h, 0, sizeof(*icmp6h));
233         icmp6h->icmp6_type = ICMPV6_DEST_UNREACH;
234         icmp6h->icmp6_code = code;
235
236         payload = skb_put(nskb, len);
237         memcpy(payload, skb_network_header(oldskb), len);
238         nip6h->payload_len = htons(nskb->len - sizeof(struct ipv6hdr));
239
240         icmp6h->icmp6_cksum =
241                 csum_ipv6_magic(&nip6h->saddr, &nip6h->daddr,
242                                 nskb->len - sizeof(struct ipv6hdr),
243                                 IPPROTO_ICMPV6,
244                                 csum_partial(icmp6h,
245                                              nskb->len - sizeof(struct ipv6hdr),
246                                              0));
247
248         nft_reject_br_push_etherhdr(oldskb, nskb);
249
250         br_deliver(br_port_get_rcu(oldskb->dev), nskb);
251 }
252
253 static void nft_reject_bridge_eval(const struct nft_expr *expr,
254                                  struct nft_data data[NFT_REG_MAX + 1],
255                                  const struct nft_pktinfo *pkt)
256 {
257         struct nft_reject *priv = nft_expr_priv(expr);
258         struct net *net = dev_net((pkt->in != NULL) ? pkt->in : pkt->out);
259         const unsigned char *dest = eth_hdr(pkt->skb)->h_dest;
260
261         if (is_broadcast_ether_addr(dest) ||
262             is_multicast_ether_addr(dest))
263                 goto out;
264
265         switch (eth_hdr(pkt->skb)->h_proto) {
266         case htons(ETH_P_IP):
267                 switch (priv->type) {
268                 case NFT_REJECT_ICMP_UNREACH:
269                         nft_reject_br_send_v4_unreach(pkt->skb,
270                                                       pkt->ops->hooknum,
271                                                       priv->icmp_code);
272                         break;
273                 case NFT_REJECT_TCP_RST:
274                         nft_reject_br_send_v4_tcp_reset(pkt->skb,
275                                                         pkt->ops->hooknum);
276                         break;
277                 case NFT_REJECT_ICMPX_UNREACH:
278                         nft_reject_br_send_v4_unreach(pkt->skb,
279                                                       pkt->ops->hooknum,
280                                                       nft_reject_icmp_code(priv->icmp_code));
281                         break;
282                 }
283                 break;
284         case htons(ETH_P_IPV6):
285                 switch (priv->type) {
286                 case NFT_REJECT_ICMP_UNREACH:
287                         nft_reject_br_send_v6_unreach(net, pkt->skb,
288                                                       pkt->ops->hooknum,
289                                                       priv->icmp_code);
290                         break;
291                 case NFT_REJECT_TCP_RST:
292                         nft_reject_br_send_v6_tcp_reset(net, pkt->skb,
293                                                         pkt->ops->hooknum);
294                         break;
295                 case NFT_REJECT_ICMPX_UNREACH:
296                         nft_reject_br_send_v6_unreach(net, pkt->skb,
297                                                       pkt->ops->hooknum,
298                                                       nft_reject_icmpv6_code(priv->icmp_code));
299                         break;
300                 }
301                 break;
302         default:
303                 /* No explicit way to reject this protocol, drop it. */
304                 break;
305         }
306 out:
307         data[NFT_REG_VERDICT].verdict = NF_DROP;
308 }
309
310 static int nft_reject_bridge_validate_hooks(const struct nft_chain *chain)
311 {
312         struct nft_base_chain *basechain;
313
314         if (chain->flags & NFT_BASE_CHAIN) {
315                 basechain = nft_base_chain(chain);
316
317                 switch (basechain->ops[0].hooknum) {
318                 case NF_BR_PRE_ROUTING:
319                 case NF_BR_LOCAL_IN:
320                         break;
321                 default:
322                         return -EOPNOTSUPP;
323                 }
324         }
325         return 0;
326 }
327
328 static int nft_reject_bridge_init(const struct nft_ctx *ctx,
329                                   const struct nft_expr *expr,
330                                   const struct nlattr * const tb[])
331 {
332         struct nft_reject *priv = nft_expr_priv(expr);
333         int icmp_code, err;
334
335         err = nft_reject_bridge_validate_hooks(ctx->chain);
336         if (err < 0)
337                 return err;
338
339         if (tb[NFTA_REJECT_TYPE] == NULL)
340                 return -EINVAL;
341
342         priv->type = ntohl(nla_get_be32(tb[NFTA_REJECT_TYPE]));
343         switch (priv->type) {
344         case NFT_REJECT_ICMP_UNREACH:
345         case NFT_REJECT_ICMPX_UNREACH:
346                 if (tb[NFTA_REJECT_ICMP_CODE] == NULL)
347                         return -EINVAL;
348
349                 icmp_code = nla_get_u8(tb[NFTA_REJECT_ICMP_CODE]);
350                 if (priv->type == NFT_REJECT_ICMPX_UNREACH &&
351                     icmp_code > NFT_REJECT_ICMPX_MAX)
352                         return -EINVAL;
353
354                 priv->icmp_code = icmp_code;
355                 break;
356         case NFT_REJECT_TCP_RST:
357                 break;
358         default:
359                 return -EINVAL;
360         }
361         return 0;
362 }
363
364 static int nft_reject_bridge_dump(struct sk_buff *skb,
365                                   const struct nft_expr *expr)
366 {
367         const struct nft_reject *priv = nft_expr_priv(expr);
368
369         if (nla_put_be32(skb, NFTA_REJECT_TYPE, htonl(priv->type)))
370                 goto nla_put_failure;
371
372         switch (priv->type) {
373         case NFT_REJECT_ICMP_UNREACH:
374         case NFT_REJECT_ICMPX_UNREACH:
375                 if (nla_put_u8(skb, NFTA_REJECT_ICMP_CODE, priv->icmp_code))
376                         goto nla_put_failure;
377                 break;
378         default:
379                 break;
380         }
381
382         return 0;
383
384 nla_put_failure:
385         return -1;
386 }
387
388 static int nft_reject_bridge_validate(const struct nft_ctx *ctx,
389                                       const struct nft_expr *expr,
390                                       const struct nft_data **data)
391 {
392         return nft_reject_bridge_validate_hooks(ctx->chain);
393 }
394
395 static struct nft_expr_type nft_reject_bridge_type;
396 static const struct nft_expr_ops nft_reject_bridge_ops = {
397         .type           = &nft_reject_bridge_type,
398         .size           = NFT_EXPR_SIZE(sizeof(struct nft_reject)),
399         .eval           = nft_reject_bridge_eval,
400         .init           = nft_reject_bridge_init,
401         .dump           = nft_reject_bridge_dump,
402         .validate       = nft_reject_bridge_validate,
403 };
404
405 static struct nft_expr_type nft_reject_bridge_type __read_mostly = {
406         .family         = NFPROTO_BRIDGE,
407         .name           = "reject",
408         .ops            = &nft_reject_bridge_ops,
409         .policy         = nft_reject_policy,
410         .maxattr        = NFTA_REJECT_MAX,
411         .owner          = THIS_MODULE,
412 };
413
414 static int __init nft_reject_bridge_module_init(void)
415 {
416         return nft_register_expr(&nft_reject_bridge_type);
417 }
418
419 static void __exit nft_reject_bridge_module_exit(void)
420 {
421         nft_unregister_expr(&nft_reject_bridge_type);
422 }
423
424 module_init(nft_reject_bridge_module_init);
425 module_exit(nft_reject_bridge_module_exit);
426
427 MODULE_LICENSE("GPL");
428 MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
429 MODULE_ALIAS_NFT_AF_EXPR(AF_BRIDGE, "reject");