diff options
Diffstat (limited to 'net/ipv6/udp.c')
-rw-r--r-- | net/ipv6/udp.c | 89 |
1 files changed, 78 insertions, 11 deletions
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index c55698d19d68..1216c920f945 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -462,6 +462,61 @@ csum_copy_err: | |||
462 | goto try_again; | 462 | goto try_again; |
463 | } | 463 | } |
464 | 464 | ||
465 | DEFINE_STATIC_KEY_FALSE(udpv6_encap_needed_key); | ||
466 | void udpv6_encap_enable(void) | ||
467 | { | ||
468 | static_branch_enable(&udpv6_encap_needed_key); | ||
469 | } | ||
470 | EXPORT_SYMBOL(udpv6_encap_enable); | ||
471 | |||
472 | /* Try to match ICMP errors to UDP tunnels by looking up a socket without | ||
473 | * reversing source and destination port: this will match tunnels that force the | ||
474 | * same destination port on both endpoints (e.g. VXLAN, GENEVE). Note that | ||
475 | * lwtunnels might actually break this assumption by being configured with | ||
476 | * different destination ports on endpoints, in this case we won't be able to | ||
477 | * trace ICMP messages back to them. | ||
478 | * | ||
479 | * Then ask the tunnel implementation to match the error against a valid | ||
480 | * association. | ||
481 | * | ||
482 | * Return the socket if we have a match. | ||
483 | */ | ||
484 | static struct sock *__udp6_lib_err_encap(struct net *net, | ||
485 | const struct ipv6hdr *hdr, int offset, | ||
486 | struct udphdr *uh, | ||
487 | struct udp_table *udptable, | ||
488 | struct sk_buff *skb) | ||
489 | { | ||
490 | int (*lookup)(struct sock *sk, struct sk_buff *skb); | ||
491 | int network_offset, transport_offset; | ||
492 | struct udp_sock *up; | ||
493 | struct sock *sk; | ||
494 | |||
495 | sk = __udp6_lib_lookup(net, &hdr->daddr, uh->source, | ||
496 | &hdr->saddr, uh->dest, | ||
497 | inet6_iif(skb), 0, udptable, skb); | ||
498 | if (!sk) | ||
499 | return NULL; | ||
500 | |||
501 | network_offset = skb_network_offset(skb); | ||
502 | transport_offset = skb_transport_offset(skb); | ||
503 | |||
504 | /* Network header needs to point to the outer IPv6 header inside ICMP */ | ||
505 | skb_reset_network_header(skb); | ||
506 | |||
507 | /* Transport header needs to point to the UDP header */ | ||
508 | skb_set_transport_header(skb, offset); | ||
509 | |||
510 | up = udp_sk(sk); | ||
511 | lookup = READ_ONCE(up->encap_err_lookup); | ||
512 | if (!lookup || lookup(sk, skb)) | ||
513 | sk = NULL; | ||
514 | |||
515 | skb_set_transport_header(skb, transport_offset); | ||
516 | skb_set_network_header(skb, network_offset); | ||
517 | return sk; | ||
518 | } | ||
519 | |||
465 | void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | 520 | void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, |
466 | u8 type, u8 code, int offset, __be32 info, | 521 | u8 type, u8 code, int offset, __be32 info, |
467 | struct udp_table *udptable) | 522 | struct udp_table *udptable) |
@@ -471,6 +526,7 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
471 | const struct in6_addr *saddr = &hdr->saddr; | 526 | const struct in6_addr *saddr = &hdr->saddr; |
472 | const struct in6_addr *daddr = &hdr->daddr; | 527 | const struct in6_addr *daddr = &hdr->daddr; |
473 | struct udphdr *uh = (struct udphdr *)(skb->data+offset); | 528 | struct udphdr *uh = (struct udphdr *)(skb->data+offset); |
529 | bool tunnel = false; | ||
474 | struct sock *sk; | 530 | struct sock *sk; |
475 | int harderr; | 531 | int harderr; |
476 | int err; | 532 | int err; |
@@ -479,9 +535,18 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
479 | sk = __udp6_lib_lookup(net, daddr, uh->dest, saddr, uh->source, | 535 | sk = __udp6_lib_lookup(net, daddr, uh->dest, saddr, uh->source, |
480 | inet6_iif(skb), inet6_sdif(skb), udptable, skb); | 536 | inet6_iif(skb), inet6_sdif(skb), udptable, skb); |
481 | if (!sk) { | 537 | if (!sk) { |
482 | __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), | 538 | /* No socket for error: try tunnels before discarding */ |
483 | ICMP6_MIB_INERRORS); | 539 | if (static_branch_unlikely(&udpv6_encap_needed_key)) { |
484 | return; | 540 | sk = __udp6_lib_err_encap(net, hdr, offset, uh, |
541 | udptable, skb); | ||
542 | } | ||
543 | |||
544 | if (!sk) { | ||
545 | __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), | ||
546 | ICMP6_MIB_INERRORS); | ||
547 | return; | ||
548 | } | ||
549 | tunnel = true; | ||
485 | } | 550 | } |
486 | 551 | ||
487 | harderr = icmpv6_err_convert(type, code, &err); | 552 | harderr = icmpv6_err_convert(type, code, &err); |
@@ -495,10 +560,19 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
495 | harderr = 1; | 560 | harderr = 1; |
496 | } | 561 | } |
497 | if (type == NDISC_REDIRECT) { | 562 | if (type == NDISC_REDIRECT) { |
498 | ip6_sk_redirect(skb, sk); | 563 | if (tunnel) { |
564 | ip6_redirect(skb, sock_net(sk), inet6_iif(skb), | ||
565 | sk->sk_mark, sk->sk_uid); | ||
566 | } else { | ||
567 | ip6_sk_redirect(skb, sk); | ||
568 | } | ||
499 | goto out; | 569 | goto out; |
500 | } | 570 | } |
501 | 571 | ||
572 | /* Tunnels don't have an application socket: don't pass errors back */ | ||
573 | if (tunnel) | ||
574 | goto out; | ||
575 | |||
502 | if (!np->recverr) { | 576 | if (!np->recverr) { |
503 | if (!harderr || sk->sk_state != TCP_ESTABLISHED) | 577 | if (!harderr || sk->sk_state != TCP_ESTABLISHED) |
504 | goto out; | 578 | goto out; |
@@ -547,13 +621,6 @@ static __inline__ void udpv6_err(struct sk_buff *skb, | |||
547 | __udp6_lib_err(skb, opt, type, code, offset, info, &udp_table); | 621 | __udp6_lib_err(skb, opt, type, code, offset, info, &udp_table); |
548 | } | 622 | } |
549 | 623 | ||
550 | DEFINE_STATIC_KEY_FALSE(udpv6_encap_needed_key); | ||
551 | void udpv6_encap_enable(void) | ||
552 | { | ||
553 | static_branch_enable(&udpv6_encap_needed_key); | ||
554 | } | ||
555 | EXPORT_SYMBOL(udpv6_encap_enable); | ||
556 | |||
557 | static int udpv6_queue_rcv_one_skb(struct sock *sk, struct sk_buff *skb) | 624 | static int udpv6_queue_rcv_one_skb(struct sock *sk, struct sk_buff *skb) |
558 | { | 625 | { |
559 | struct udp_sock *up = udp_sk(sk); | 626 | struct udp_sock *up = udp_sk(sk); |