mirror of
https://github.com/coredns/coredns.git
synced 2026-10-17 07:45:42 -04:00
38 lines
1.2 KiB
Go
38 lines
1.2 KiB
Go
|
|
//go:build linux
|
||
|
|
|
||
|
|
package proxy
|
||
|
|
|
||
|
|
import (
|
||
|
|
"syscall"
|
||
|
|
|
||
|
|
"github.com/coredns/coredns/plugin/pkg/log"
|
||
|
|
|
||
|
|
"golang.org/x/sys/unix"
|
||
|
|
)
|
||
|
|
|
||
|
|
// recvErr is a net.Dialer Control function that sets IP_RECVERR or IPV6_RECVERR
|
||
|
|
// on UDP sockets. Without it Linux passes only some ICMP errors, such as port
|
||
|
|
// unreachable, to a connected UDP socket, and drops net and host unreachable
|
||
|
|
// (net/ipv4/udp.c, __udp4_lib_err). A read from an upstream behind an
|
||
|
|
// unreachable route then waits out its timeout. With it, the read fails as soon
|
||
|
|
// as the ICMP error arrives. Other networks are left alone.
|
||
|
|
func recvErr(network, _ string, c syscall.RawConn) error {
|
||
|
|
if network != "udp4" && network != "udp6" {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
return c.Control(func(fd uintptr) {
|
||
|
|
const maxInt = int(^uint(0) >> 1)
|
||
|
|
if fd > uintptr(maxInt) {
|
||
|
|
log.Warningf("Failed to set IP_RECVERR on socket: invalid file descriptor %d", fd)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
level, opt := unix.SOL_IP, unix.IP_RECVERR
|
||
|
|
if network == "udp6" {
|
||
|
|
level, opt = unix.SOL_IPV6, unix.IPV6_RECVERR
|
||
|
|
}
|
||
|
|
if err := unix.SetsockoptInt(int(fd), level, opt, 1); err != nil { // #nosec G115 -- fd is range-checked above
|
||
|
|
log.Warningf("Failed to set IP_RECVERR on socket: %s", err)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|