1// SPDX-License-Identifier: GPL-2.0-only
2/* (C) 1999-2001 Paul `Rusty' Russell
3 * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
4 */
5
6#include <linux/module.h>
7#include <net/ipv6.h>
8#include <net/ip6_route.h>
9#include <net/ip6_fib.h>
10#include <net/ip6_checksum.h>
11#include <net/netfilter/ipv6/nf_reject.h>
12#include <linux/netfilter_ipv6.h>
13#include <linux/netfilter_bridge.h>
14
15static struct ipv6hdr *
16nf_reject_ip6hdr_put(struct sk_buff *nskb,
17 const struct sk_buff *oldskb,
18 __u8 protocol, int hoplimit);
19static void
20nf_reject_ip6_tcphdr_put(struct sk_buff *nskb,
21 const struct sk_buff *oldskb,
22 const struct tcphdr *oth, unsigned int otcplen);
23static const struct tcphdr *
24nf_reject_ip6_tcphdr_get(struct sk_buff *oldskb,
25 struct tcphdr *otcph,
26 unsigned int *otcplen, int hook);
27
28static bool nf_reject_v6_csum_ok(struct sk_buff *skb, int hook)
29{
30 const struct ipv6hdr *ip6h = ipv6_hdr(skb);
31 int thoff;
32 __be16 fo;
33 u8 proto = ip6h->nexthdr;
34
35 if (skb_csum_unnecessary(skb))
36 return true;
37
38 if (ip6h->payload_len &&
39 pskb_trim_rcsum(skb, ntohs(ip6h->payload_len) + sizeof(*ip6h)))
40 return false;
41
42 ip6h = ipv6_hdr(skb);
43 thoff = ipv6_skip_exthdr(skb, start: ((u8*)(ip6h+1) - skb->data), nexthdrp: &proto, frag_offp: &fo);
44 if (thoff < 0 || thoff >= skb->len || (fo & htons(~0x7)) != 0)
45 return false;
46
47 if (!nf_reject_verify_csum(skb, dataoff: thoff, proto))
48 return true;
49
50 return nf_ip6_checksum(skb, hook, dataoff: thoff, protocol: proto) == 0;
51}
52
53static int nf_reject_ip6hdr_validate(struct sk_buff *skb)
54{
55 struct ipv6hdr *hdr;
56 u32 pkt_len;
57
58 if (!pskb_may_pull(skb, len: sizeof(struct ipv6hdr)))
59 return 0;
60
61 hdr = ipv6_hdr(skb);
62 if (hdr->version != 6)
63 return 0;
64
65 pkt_len = ntohs(hdr->payload_len);
66 if (pkt_len + sizeof(struct ipv6hdr) > skb->len)
67 return 0;
68
69 return 1;
70}
71
72struct sk_buff *nf_reject_skb_v6_tcp_reset(struct net *net,
73 struct sk_buff *oldskb,
74 const struct net_device *dev,
75 int hook)
76{
77 struct sk_buff *nskb;
78 const struct tcphdr *oth;
79 struct tcphdr _oth;
80 unsigned int otcplen;
81 struct ipv6hdr *nip6h;
82
83 if (!nf_reject_ip6hdr_validate(skb: oldskb))
84 return NULL;
85
86 oth = nf_reject_ip6_tcphdr_get(oldskb, otcph: &_oth, otcplen: &otcplen, hook);
87 if (!oth)
88 return NULL;
89
90 nskb = alloc_skb(size: sizeof(struct ipv6hdr) + sizeof(struct tcphdr) +
91 LL_MAX_HEADER, GFP_ATOMIC);
92 if (!nskb)
93 return NULL;
94
95 nskb->dev = (struct net_device *)dev;
96
97 skb_reserve(skb: nskb, LL_MAX_HEADER);
98 nip6h = nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_TCP,
99 READ_ONCE(net->ipv6.devconf_all->hop_limit));
100 nf_reject_ip6_tcphdr_put(nskb, oldskb, oth, otcplen);
101 nip6h->payload_len = htons(nskb->len - sizeof(struct ipv6hdr));
102
103 return nskb;
104}
105EXPORT_SYMBOL_GPL(nf_reject_skb_v6_tcp_reset);
106
107static bool nf_skb_is_icmp6_unreach(const struct sk_buff *skb)
108{
109 const struct ipv6hdr *ip6h = ipv6_hdr(skb);
110 u8 proto = ip6h->nexthdr;
111 u8 _type, *tp;
112 int thoff;
113 __be16 fo;
114
115 thoff = ipv6_skip_exthdr(skb, start: ((u8 *)(ip6h + 1) - skb->data), nexthdrp: &proto, frag_offp: &fo);
116
117 if (thoff < 0 || thoff >= skb->len || fo != 0)
118 return false;
119
120 if (proto != IPPROTO_ICMPV6)
121 return false;
122
123 tp = skb_header_pointer(skb,
124 offset: thoff + offsetof(struct icmp6hdr, icmp6_type),
125 len: sizeof(_type), buffer: &_type);
126
127 if (!tp)
128 return false;
129
130 return *tp == ICMPV6_DEST_UNREACH;
131}
132
133struct sk_buff *nf_reject_skb_v6_unreach(struct net *net,
134 struct sk_buff *oldskb,
135 const struct net_device *dev,
136 int hook, u8 code)
137{
138 struct sk_buff *nskb;
139 struct ipv6hdr *nip6h;
140 struct icmp6hdr *icmp6h;
141 unsigned int len;
142
143 if (!nf_reject_ip6hdr_validate(skb: oldskb))
144 return NULL;
145
146 /* Don't reply to ICMPV6_DEST_UNREACH with ICMPV6_DEST_UNREACH */
147 if (nf_skb_is_icmp6_unreach(skb: oldskb))
148 return NULL;
149
150 /* Include "As much of invoking packet as possible without the ICMPv6
151 * packet exceeding the minimum IPv6 MTU" in the ICMP payload.
152 */
153 len = min_t(unsigned int, 1220, oldskb->len);
154
155 if (!pskb_may_pull(skb: oldskb, len))
156 return NULL;
157
158 if (!nf_reject_v6_csum_ok(skb: oldskb, hook))
159 return NULL;
160
161 nskb = alloc_skb(size: sizeof(struct ipv6hdr) + sizeof(struct icmp6hdr) +
162 LL_MAX_HEADER + len, GFP_ATOMIC);
163 if (!nskb)
164 return NULL;
165
166 nskb->dev = (struct net_device *)dev;
167
168 skb_reserve(skb: nskb, LL_MAX_HEADER);
169 nip6h = nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_ICMPV6,
170 READ_ONCE(net->ipv6.devconf_all->hop_limit));
171
172 skb_reset_transport_header(skb: nskb);
173 icmp6h = skb_put_zero(skb: nskb, len: sizeof(struct icmp6hdr));
174 icmp6h->icmp6_type = ICMPV6_DEST_UNREACH;
175 icmp6h->icmp6_code = code;
176
177 skb_put_data(skb: nskb, data: skb_network_header(skb: oldskb), len);
178 nip6h->payload_len = htons(nskb->len - sizeof(struct ipv6hdr));
179
180 icmp6h->icmp6_cksum =
181 csum_ipv6_magic(saddr: &nip6h->saddr, daddr: &nip6h->daddr,
182 len: nskb->len - sizeof(struct ipv6hdr),
183 IPPROTO_ICMPV6,
184 sum: csum_partial(buff: icmp6h,
185 len: nskb->len - sizeof(struct ipv6hdr),
186 sum: 0));
187
188 return nskb;
189}
190EXPORT_SYMBOL_GPL(nf_reject_skb_v6_unreach);
191
192static const struct tcphdr *
193nf_reject_ip6_tcphdr_get(struct sk_buff *oldskb,
194 struct tcphdr *otcph,
195 unsigned int *otcplen, int hook)
196{
197 const struct ipv6hdr *oip6h = ipv6_hdr(skb: oldskb);
198 u8 proto;
199 __be16 frag_off;
200 int tcphoff;
201
202 proto = oip6h->nexthdr;
203 tcphoff = ipv6_skip_exthdr(oldskb, start: ((u8 *)(oip6h + 1) - oldskb->data),
204 nexthdrp: &proto, frag_offp: &frag_off);
205
206 if ((tcphoff < 0) || (tcphoff > oldskb->len)) {
207 pr_debug("Cannot get TCP header.\n");
208 return NULL;
209 }
210
211 *otcplen = oldskb->len - tcphoff;
212
213 /* IP header checks: fragment, too short. */
214 if (proto != IPPROTO_TCP || *otcplen < sizeof(struct tcphdr)) {
215 pr_debug("proto(%d) != IPPROTO_TCP or too short (len = %d)\n",
216 proto, *otcplen);
217 return NULL;
218 }
219
220 otcph = skb_header_pointer(skb: oldskb, offset: tcphoff, len: sizeof(struct tcphdr),
221 buffer: otcph);
222 if (otcph == NULL)
223 return NULL;
224
225 /* No RST for RST. */
226 if (otcph->rst) {
227 pr_debug("RST is set\n");
228 return NULL;
229 }
230
231 /* Check checksum. */
232 if (nf_ip6_checksum(skb: oldskb, hook, dataoff: tcphoff, IPPROTO_TCP)) {
233 pr_debug("TCP checksum is invalid\n");
234 return NULL;
235 }
236
237 return otcph;
238}
239
240static struct ipv6hdr *
241nf_reject_ip6hdr_put(struct sk_buff *nskb,
242 const struct sk_buff *oldskb,
243 __u8 protocol, int hoplimit)
244{
245 struct ipv6hdr *ip6h;
246 const struct ipv6hdr *oip6h = ipv6_hdr(skb: oldskb);
247#define DEFAULT_TOS_VALUE 0x0U
248 const __u8 tclass = DEFAULT_TOS_VALUE;
249
250 skb_put(skb: nskb, len: sizeof(struct ipv6hdr));
251 skb_reset_network_header(skb: nskb);
252 ip6h = ipv6_hdr(skb: nskb);
253 ip6_flow_hdr(hdr: ip6h, tclass, flowlabel: 0);
254 ip6h->hop_limit = hoplimit;
255 ip6h->nexthdr = protocol;
256 ip6h->saddr = oip6h->daddr;
257 ip6h->daddr = oip6h->saddr;
258
259 nskb->protocol = htons(ETH_P_IPV6);
260
261 return ip6h;
262}
263
264static void
265nf_reject_ip6_tcphdr_put(struct sk_buff *nskb,
266 const struct sk_buff *oldskb,
267 const struct tcphdr *oth, unsigned int otcplen)
268{
269 struct tcphdr *tcph;
270
271 skb_reset_transport_header(skb: nskb);
272 tcph = skb_put_zero(skb: nskb, len: sizeof(struct tcphdr));
273 /* Truncate to length (no data) */
274 tcph->doff = sizeof(struct tcphdr)/4;
275 tcph->source = oth->dest;
276 tcph->dest = oth->source;
277
278 if (oth->ack) {
279 tcph->seq = oth->ack_seq;
280 } else {
281 tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin +
282 otcplen - (oth->doff<<2));
283 tcph->ack = 1;
284 }
285
286 tcph->rst = 1;
287
288 /* Adjust TCP checksum */
289 tcph->check = csum_ipv6_magic(saddr: &ipv6_hdr(skb: nskb)->saddr,
290 daddr: &ipv6_hdr(skb: nskb)->daddr,
291 len: sizeof(struct tcphdr), IPPROTO_TCP,
292 sum: csum_partial(buff: tcph,
293 len: sizeof(struct tcphdr), sum: 0));
294}
295
296static int nf_reject6_fill_skb_dst(struct sk_buff *skb_in)
297{
298 struct dst_entry *dst = NULL;
299 struct flowi fl;
300
301 memset(s: &fl, c: 0, n: sizeof(struct flowi));
302 fl.u.ip6.daddr = ipv6_hdr(skb: skb_in)->saddr;
303 nf_ip6_route(net: dev_net(dev: skb_in->dev), dst: &dst, fl: &fl, strict: false);
304 if (!dst)
305 return -1;
306
307 skb_dst_set(skb: skb_in, dst);
308 return 0;
309}
310
311void nf_send_reset6(struct net *net, struct sock *sk, struct sk_buff *oldskb,
312 int hook)
313{
314 const struct ipv6hdr *oip6h = ipv6_hdr(skb: oldskb);
315 struct dst_entry *dst = NULL;
316 const struct tcphdr *otcph;
317 struct sk_buff *nskb;
318 struct tcphdr _otcph;
319 unsigned int otcplen;
320 struct flowi6 fl6;
321
322 if ((!(ipv6_addr_type(addr: &oip6h->saddr) & IPV6_ADDR_UNICAST)) ||
323 (!(ipv6_addr_type(addr: &oip6h->daddr) & IPV6_ADDR_UNICAST))) {
324 pr_debug("addr is not unicast.\n");
325 return;
326 }
327
328 otcph = nf_reject_ip6_tcphdr_get(oldskb, otcph: &_otcph, otcplen: &otcplen, hook);
329 if (!otcph)
330 return;
331
332 memset(s: &fl6, c: 0, n: sizeof(fl6));
333 fl6.flowi6_proto = IPPROTO_TCP;
334 fl6.saddr = oip6h->daddr;
335 fl6.daddr = oip6h->saddr;
336 fl6.fl6_sport = otcph->dest;
337 fl6.fl6_dport = otcph->source;
338
339 if (!skb_dst(skb: oldskb)) {
340 nf_ip6_route(net, dst: &dst, fl: flowi6_to_flowi(fl6: &fl6), strict: false);
341 if (!dst)
342 return;
343 skb_dst_set(skb: oldskb, dst);
344 }
345
346 fl6.flowi6_oif = l3mdev_master_ifindex(dev: skb_dst_dev(skb: oldskb));
347 fl6.flowi6_mark = IP6_REPLY_MARK(net, oldskb->mark);
348 security_skb_classify_flow(skb: oldskb, flic: flowi6_to_flowi_common(fl6: &fl6));
349 dst = ip6_route_output(net, NULL, fl6: &fl6);
350 if (dst->error) {
351 dst_release(dst);
352 return;
353 }
354 dst = xfrm_lookup(net, dst_orig: dst, fl: flowi6_to_flowi(fl6: &fl6), NULL, flags: 0);
355 if (IS_ERR(ptr: dst))
356 return;
357
358 nskb = alloc_skb(LL_MAX_HEADER + sizeof(struct ipv6hdr) +
359 sizeof(struct tcphdr) + dst->trailer_len,
360 GFP_ATOMIC);
361
362 if (!nskb) {
363 net_dbg_ratelimited("cannot alloc skb\n");
364 dst_release(dst);
365 return;
366 }
367
368 skb_dst_set(skb: nskb, dst);
369
370 nskb->mark = fl6.flowi6_mark;
371
372 skb_reserve(skb: nskb, LL_MAX_HEADER);
373 nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_TCP, hoplimit: ip6_dst_hoplimit(dst));
374 nf_reject_ip6_tcphdr_put(nskb, oldskb, oth: otcph, otcplen);
375
376 nf_ct_attach(nskb, oldskb);
377 nf_ct_set_closing(nfct: skb_nfct(skb: oldskb));
378
379#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
380 /* If we use ip6_local_out for bridged traffic, the MAC source on
381 * the RST will be ours, instead of the destination's. This confuses
382 * some routers/firewalls, and they drop the packet. So we need to
383 * build the eth header using the original destination's MAC as the
384 * source, and send the RST packet directly.
385 */
386 if (nf_bridge_info_exists(oldskb)) {
387 struct ethhdr *oeth = eth_hdr(oldskb);
388 struct ipv6hdr *ip6h = ipv6_hdr(nskb);
389 struct net_device *br_indev;
390
391 br_indev = nf_bridge_get_physindev(oldskb, net);
392 if (!br_indev) {
393 kfree_skb(nskb);
394 return;
395 }
396
397 nskb->dev = br_indev;
398 nskb->protocol = htons(ETH_P_IPV6);
399 ip6h->payload_len = htons(sizeof(struct tcphdr));
400 if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol),
401 oeth->h_source, oeth->h_dest, nskb->len) < 0) {
402 kfree_skb(nskb);
403 return;
404 }
405 dev_queue_xmit(nskb);
406 } else
407#endif
408 ip6_local_out(net, sk, skb: nskb);
409}
410EXPORT_SYMBOL_GPL(nf_send_reset6);
411
412static bool reject6_csum_ok(struct sk_buff *skb, int hook)
413{
414 const struct ipv6hdr *ip6h = ipv6_hdr(skb);
415 int thoff;
416 __be16 fo;
417 u8 proto;
418
419 if (skb_csum_unnecessary(skb))
420 return true;
421
422 proto = ip6h->nexthdr;
423 thoff = ipv6_skip_exthdr(skb, start: ((u8 *)(ip6h + 1) - skb->data), nexthdrp: &proto, frag_offp: &fo);
424
425 if (thoff < 0 || thoff >= skb->len || (fo & htons(~0x7)) != 0)
426 return false;
427
428 if (!nf_reject_verify_csum(skb, dataoff: thoff, proto))
429 return true;
430
431 return nf_ip6_checksum(skb, hook, dataoff: thoff, protocol: proto) == 0;
432}
433
434void nf_send_unreach6(struct net *net, struct sk_buff *skb_in,
435 unsigned char code, unsigned int hooknum)
436{
437 if (!reject6_csum_ok(skb: skb_in, hook: hooknum))
438 return;
439
440 if (hooknum == NF_INET_LOCAL_OUT && skb_in->dev == NULL)
441 skb_in->dev = net->loopback_dev;
442
443 if (!skb_dst(skb: skb_in) && nf_reject6_fill_skb_dst(skb_in) < 0)
444 return;
445
446 icmpv6_send(skb: skb_in, ICMPV6_DEST_UNREACH, code, info: 0);
447}
448EXPORT_SYMBOL_GPL(nf_send_unreach6);
449
450MODULE_LICENSE("GPL");
451MODULE_DESCRIPTION("IPv6 packet rejection core");
452