diff --git a/internal/pmtud/errors.go b/internal/pmtud/errors.go index 5fc606fe..5f6eaa41 100644 --- a/internal/pmtud/errors.go +++ b/internal/pmtud/errors.go @@ -5,10 +5,12 @@ import ( "errors" "fmt" "net" + "strings" "time" ) var ( + ErrICMPNotPermitted = errors.New("ICMP not permitted") ErrICMPDestinationUnreachable = errors.New("ICMP destination unreachable") ErrICMPCommunicationAdministrativelyProhibited = errors.New("communication administratively prohibited") ErrICMPBodyUnsupported = errors.New("ICMP body type is not supported") @@ -16,6 +18,8 @@ var ( func wrapConnErr(err error, timedCtx context.Context, pingTimeout time.Duration) error { //nolint:revive switch { + case strings.HasSuffix(err.Error(), "sendto: operation not permitted"): + err = fmt.Errorf("%w", ErrICMPNotPermitted) case errors.Is(timedCtx.Err(), context.DeadlineExceeded): err = fmt.Errorf("%w (timed out after %s)", net.ErrClosed, pingTimeout) case timedCtx.Err() != nil: diff --git a/internal/pmtud/ipv4.go b/internal/pmtud/ipv4.go index e3850f86..77909e38 100644 --- a/internal/pmtud/ipv4.go +++ b/internal/pmtud/ipv4.go @@ -7,6 +7,7 @@ import ( "net" "net/netip" "runtime" + "strings" "syscall" "time" @@ -36,6 +37,9 @@ func listenICMPv4(ctx context.Context) (conn net.PacketConn, err error) { const listenAddress = "" packetConn, err := listenConfig.ListenPacket(ctx, "ip4:icmp", listenAddress) if err != nil { + if strings.HasSuffix(err.Error(), "socket: operation not permitted") { + err = fmt.Errorf("%w: you can try adding NET_RAW capability to resolve this", ErrICMPNotPermitted) + } return nil, fmt.Errorf("listening for ICMP packets: %w", err) } diff --git a/internal/pmtud/ipv6.go b/internal/pmtud/ipv6.go index b73ea09f..db793d4f 100644 --- a/internal/pmtud/ipv6.go +++ b/internal/pmtud/ipv6.go @@ -5,6 +5,7 @@ import ( "fmt" "net" "net/netip" + "strings" "time" "golang.org/x/net/icmp" @@ -21,6 +22,9 @@ func listenICMPv6(ctx context.Context) (conn net.PacketConn, err error) { const listenAddress = "" packetConn, err := listenConfig.ListenPacket(ctx, "ip6:ipv6-icmp", listenAddress) if err != nil { + if strings.HasSuffix(err.Error(), "socket: operation not permitted") { + err = fmt.Errorf("%w: you can try adding NET_RAW capability to resolve this", ErrICMPNotPermitted) + } return nil, fmt.Errorf("listening for ICMPv6 packets: %w", err) } return packetConn, nil diff --git a/internal/pmtud/pmtud.go b/internal/pmtud/pmtud.go index 56138f55..e9cab450 100644 --- a/internal/pmtud/pmtud.go +++ b/internal/pmtud/pmtud.go @@ -7,6 +7,7 @@ import ( "math" "net" "net/netip" + "strings" "time" "golang.org/x/net/icmp" @@ -87,6 +88,9 @@ func pmtudMultiSizes(ctx context.Context, ip netip.Addr, conn, err = listenICMPv6(ctx) } if err != nil { + if strings.HasSuffix(err.Error(), "socket: operation not permitted") { + err = fmt.Errorf("%w: you can try adding NET_RAW capability to resolve this", ErrICMPNotPermitted) + } return 0, fmt.Errorf("listening for ICMP packets: %w", err) } @@ -120,6 +124,9 @@ func pmtudMultiSizes(ctx context.Context, ip netip.Addr, _, err = conn.WriteTo(encodedMessage, &net.IPAddr{IP: ip.AsSlice()}) if err != nil { + if strings.HasSuffix(err.Error(), "sendto: operation not permitted") { + err = fmt.Errorf("%w", ErrICMPNotPermitted) + } return 0, fmt.Errorf("writing ICMP message: %w", err) } } diff --git a/internal/vpn/tunnelup.go b/internal/vpn/tunnelup.go index 3bba4dc0..4ae32b8e 100644 --- a/internal/vpn/tunnelup.go +++ b/internal/vpn/tunnelup.go @@ -120,10 +120,10 @@ func updateToMaxMTU(ctx context.Context, vpnInterface string, vpnLinkMTU, err = pmtud.PathMTUDiscover(ctx, vpnGatewayIP, vpnLinkMTU, pingTimeout, logger) switch { case err == nil: - logger.Infof("Setting VPN interface %s MTU to maximum valid MTU %d", vpnInterface, vpnLinkMTU) - case errors.Is(err, pmtud.ErrMTUNotFound): + logger.Infof("setting VPN interface %s MTU to maximum valid MTU %d", vpnInterface, vpnLinkMTU) + case errors.Is(err, pmtud.ErrMTUNotFound) || errors.Is(err, pmtud.ErrICMPNotPermitted): vpnLinkMTU = int(originalMTU) - logger.Infof("Reverting VPN interface %s MTU to %d (due to: %s)", + logger.Infof("reverting VPN interface %s MTU to %d (due to: %s)", vpnInterface, originalMTU, err) default: return fmt.Errorf("path MTU discovering: %w", err)