mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-04-11 16:14:11 +00:00
Sockopt: Fix Darwin (macOS, iOS...) UDP interface
bind (#4530)
Fixes https://github.com/XTLS/Xray-core/issues/4007
This commit is contained in:
parent
8284a0ef8f
commit
63eb0539b3
@ -1,7 +1,7 @@
|
|||||||
package internet
|
package internet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
network "net"
|
gonet "net"
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
@ -108,13 +108,58 @@ func applyOutboundSocketOptions(network string, address string, fd uintptr, conf
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if config.Interface != "" {
|
|
||||||
InterfaceIndex := getInterfaceIndexByName(config.Interface)
|
if config.TcpKeepAliveIdle > 0 || config.TcpKeepAliveInterval > 0 {
|
||||||
if InterfaceIndex != 0 {
|
if config.TcpKeepAliveIdle > 0 {
|
||||||
if err := unix.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BOUND_IF, InterfaceIndex); err != nil {
|
if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_TCP, unix.TCP_KEEPALIVE, int(config.TcpKeepAliveInterval)); err != nil {
|
||||||
return errors.New("failed to set Interface").Base(err)
|
return errors.New("failed to set TCP_KEEPINTVL", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if config.TcpKeepAliveInterval > 0 {
|
||||||
|
if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_TCP, sysTCP_KEEPINTVL, int(config.TcpKeepAliveIdle)); err != nil {
|
||||||
|
return errors.New("failed to set TCP_KEEPIDLE", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_KEEPALIVE, 1); err != nil {
|
||||||
|
return errors.New("failed to set SO_KEEPALIVE", err)
|
||||||
|
}
|
||||||
|
} else if config.TcpKeepAliveInterval < 0 || config.TcpKeepAliveIdle < 0 {
|
||||||
|
if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_KEEPALIVE, 0); err != nil {
|
||||||
|
return errors.New("failed to unset SO_KEEPALIVE", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Interface != "" {
|
||||||
|
iface, err := gonet.InterfaceByName(config.Interface)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("failed to get interface ", config.Interface).Base(err)
|
||||||
|
}
|
||||||
|
if network == "tcp6" || network == "udp6" {
|
||||||
|
if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_BOUND_IF, iface.Index); err != nil {
|
||||||
|
return errors.New("failed to set IPV6_BOUND_IF").Base(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_BOUND_IF, iface.Index); err != nil {
|
||||||
|
return errors.New("failed to set IP_BOUND_IF").Base(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig) error {
|
||||||
|
if isTCPSocket(network) {
|
||||||
|
tfo := config.ParseTFOValue()
|
||||||
|
if tfo > 0 {
|
||||||
|
tfo = TCP_FASTOPEN_SERVER
|
||||||
|
}
|
||||||
|
if tfo >= 0 {
|
||||||
|
if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_TCP, unix.TCP_FASTOPEN, tfo); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.TcpKeepAliveIdle > 0 || config.TcpKeepAliveInterval > 0 {
|
if config.TcpKeepAliveIdle > 0 || config.TcpKeepAliveInterval > 0 {
|
||||||
@ -138,46 +183,19 @@ func applyOutboundSocketOptions(network string, address string, fd uintptr, conf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
if config.Interface != "" {
|
||||||
}
|
iface, err := gonet.InterfaceByName(config.Interface)
|
||||||
|
|
||||||
func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig) error {
|
if err != nil {
|
||||||
if isTCPSocket(network) {
|
return errors.New("failed to get interface ", config.Interface).Base(err)
|
||||||
tfo := config.ParseTFOValue()
|
|
||||||
if tfo > 0 {
|
|
||||||
tfo = TCP_FASTOPEN_SERVER
|
|
||||||
}
|
}
|
||||||
if tfo >= 0 {
|
if network == "tcp6" || network == "udp6" {
|
||||||
if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_TCP, unix.TCP_FASTOPEN, tfo); err != nil {
|
if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_BOUND_IF, iface.Index); err != nil {
|
||||||
return err
|
return errors.New("failed to set IPV6_BOUND_IF").Base(err)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
if config.Interface != "" {
|
if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_BOUND_IF, iface.Index); err != nil {
|
||||||
InterfaceIndex := getInterfaceIndexByName(config.Interface)
|
return errors.New("failed to set IP_BOUND_IF").Base(err)
|
||||||
if InterfaceIndex != 0 {
|
|
||||||
if err := unix.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BOUND_IF, InterfaceIndex); err != nil {
|
|
||||||
return errors.New("failed to set Interface").Base(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.TcpKeepAliveIdle > 0 || config.TcpKeepAliveInterval > 0 {
|
|
||||||
if config.TcpKeepAliveIdle > 0 {
|
|
||||||
if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_TCP, unix.TCP_KEEPALIVE, int(config.TcpKeepAliveInterval)); err != nil {
|
|
||||||
return errors.New("failed to set TCP_KEEPINTVL", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if config.TcpKeepAliveInterval > 0 {
|
|
||||||
if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_TCP, sysTCP_KEEPINTVL, int(config.TcpKeepAliveIdle)); err != nil {
|
|
||||||
return errors.New("failed to set TCP_KEEPIDLE", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_KEEPALIVE, 1); err != nil {
|
|
||||||
return errors.New("failed to set SO_KEEPALIVE", err)
|
|
||||||
}
|
|
||||||
} else if config.TcpKeepAliveInterval < 0 || config.TcpKeepAliveIdle < 0 {
|
|
||||||
if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_KEEPALIVE, 0); err != nil {
|
|
||||||
return errors.New("failed to unset SO_KEEPALIVE", err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -224,24 +242,3 @@ func setReusePort(fd uintptr) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func getInterfaceIndexByName(name string) int {
|
|
||||||
ifaces, err := network.Interfaces()
|
|
||||||
if err == nil {
|
|
||||||
for _, iface := range ifaces {
|
|
||||||
if (iface.Flags&network.FlagUp == network.FlagUp) && (iface.Flags&network.FlagLoopback != network.FlagLoopback) {
|
|
||||||
addrs, _ := iface.Addrs()
|
|
||||||
for _, addr := range addrs {
|
|
||||||
if ipnet, ok := addr.(*network.IPNet); ok && !ipnet.IP.IsLoopback() {
|
|
||||||
if ipnet.IP.To4() != nil {
|
|
||||||
if iface.Name == name {
|
|
||||||
return iface.Index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user