Files
tun2socks/component/dialer/sockopt_darwin.go
2022-03-29 13:39:18 +08:00

62 lines
1.3 KiB
Go

package dialer
import (
"net"
"syscall"
"time"
"github.com/xjasonlyu/tun2socks/v2/common/singledo"
"golang.org/x/sys/unix"
)
var interfaces = singledo.NewSingle(30 * time.Second)
func resolveInterfaceByName(name string) (*net.Interface, error) {
value, err, _ := interfaces.Do(func() (any, error) {
return net.InterfaceByName(name)
})
if err != nil {
return nil, err
}
return value.(*net.Interface), nil
}
func setSocketOptions(network, address string, c syscall.RawConn, opts *Options) (err error) {
if !isTCPSocket(network) && !isUDPSocket(network) {
return
}
var innerErr error
err = c.Control(func(fd uintptr) {
// must be GlobalUnicast.
host, _, _ := net.SplitHostPort(address)
if ip := net.ParseIP(host); ip != nil && !ip.IsGlobalUnicast() {
return
}
if opts.InterfaceName != "" {
var iface *net.Interface
iface, innerErr = resolveInterfaceByName(opts.InterfaceName)
if innerErr != nil {
return
}
switch network {
case "tcp4", "udp4":
innerErr = unix.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_BOUND_IF, iface.Index)
case "tcp6", "udp6":
innerErr = unix.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IPV6_BOUND_IF, iface.Index)
}
if innerErr != nil {
return
}
}
})
if innerErr != nil {
err = innerErr
}
return
}