github.com/quic-go/quic-go@v0.44.0/sys_conn_df_darwin.go (about) 1 //go:build darwin 2 3 package quic 4 5 import ( 6 "errors" 7 "strconv" 8 "strings" 9 "syscall" 10 11 "golang.org/x/sys/unix" 12 13 "github.com/quic-go/quic-go/internal/utils" 14 ) 15 16 func setDF(rawConn syscall.RawConn) (bool, error) { 17 // Setting DF bit is only supported from macOS11 18 // https://github.com/chromium/chromium/blob/117.0.5881.2/net/socket/udp_socket_posix.cc#L555 19 if supportsDF, err := isAtLeastMacOS11(); !supportsDF || err != nil { 20 return false, err 21 } 22 23 // Enabling IP_DONTFRAG will force the kernel to return "sendto: message too long" 24 // and the datagram will not be fragmented 25 var errDFIPv4, errDFIPv6 error 26 if err := rawConn.Control(func(fd uintptr) { 27 errDFIPv4 = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_DONTFRAG, 1) 28 errDFIPv6 = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_DONTFRAG, 1) 29 }); err != nil { 30 return false, err 31 } 32 switch { 33 case errDFIPv4 == nil && errDFIPv6 == nil: 34 utils.DefaultLogger.Debugf("Setting DF for IPv4 and IPv6.") 35 case errDFIPv4 == nil && errDFIPv6 != nil: 36 utils.DefaultLogger.Debugf("Setting DF for IPv4.") 37 case errDFIPv4 != nil && errDFIPv6 == nil: 38 utils.DefaultLogger.Debugf("Setting DF for IPv6.") 39 // On macOS, the syscall for setting DF bit for IPv4 fails on dual-stack listeners. 40 // Treat the connection as not having DF enabled, even though the DF bit will be set 41 // when used for IPv6. 42 // See https://github.com/quic-go/quic-go/issues/3793 for details. 43 return false, nil 44 case errDFIPv4 != nil && errDFIPv6 != nil: 45 return false, errors.New("setting DF failed for both IPv4 and IPv6") 46 } 47 return true, nil 48 } 49 50 func isSendMsgSizeErr(err error) bool { 51 return errors.Is(err, unix.EMSGSIZE) 52 } 53 54 func isRecvMsgSizeErr(error) bool { return false } 55 56 func isAtLeastMacOS11() (bool, error) { 57 uname := &unix.Utsname{} 58 err := unix.Uname(uname) 59 if err != nil { 60 return false, err 61 } 62 63 release := string(uname.Release[:]) 64 if idx := strings.Index(release, "."); idx != -1 { 65 version, err := strconv.Atoi(release[:idx]) 66 if err != nil { 67 return false, err 68 } 69 // Darwin version 20 is macOS version 11 70 // https://en.wikipedia.org/wiki/Darwin_(operating_system)#Darwin_20_onwards 71 return version >= 20, nil 72 } 73 return false, nil 74 }