github.com/chwjbn/xclash@v0.2.0/component/dialer/bind_darwin.go (about)

     1  package dialer
     2  
     3  import (
     4  	"net"
     5  	"syscall"
     6  
     7  	"golang.org/x/sys/unix"
     8  
     9  	"github.com/chwjbn/xclash/component/iface"
    10  )
    11  
    12  type controlFn = func(network, address string, c syscall.RawConn) error
    13  
    14  func bindControl(ifaceIdx int, chain controlFn) controlFn {
    15  	return func(network, address string, c syscall.RawConn) (err error) {
    16  		defer func() {
    17  			if err == nil && chain != nil {
    18  				err = chain(network, address, c)
    19  			}
    20  		}()
    21  
    22  		ipStr, _, err := net.SplitHostPort(address)
    23  		if err == nil {
    24  			ip := net.ParseIP(ipStr)
    25  			if ip != nil && !ip.IsGlobalUnicast() {
    26  				return
    27  			}
    28  		}
    29  
    30  		var innerErr error
    31  		err = c.Control(func(fd uintptr) {
    32  			switch network {
    33  			case "tcp4", "udp4":
    34  				innerErr = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_BOUND_IF, ifaceIdx)
    35  			case "tcp6", "udp6":
    36  				innerErr = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_BOUND_IF, ifaceIdx)
    37  			}
    38  		})
    39  
    40  		if innerErr != nil {
    41  			err = innerErr
    42  		}
    43  
    44  		return
    45  	}
    46  }
    47  
    48  func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, _ string, _ net.IP) error {
    49  	ifaceObj, err := iface.ResolveInterface(ifaceName)
    50  	if err != nil {
    51  		return err
    52  	}
    53  
    54  	dialer.Control = bindControl(ifaceObj.Index, dialer.Control)
    55  	return nil
    56  }
    57  
    58  func bindIfaceToListenConfig(ifaceName string, lc *net.ListenConfig, _, address string) (string, error) {
    59  	ifaceObj, err := iface.ResolveInterface(ifaceName)
    60  	if err != nil {
    61  		return "", err
    62  	}
    63  
    64  	lc.Control = bindControl(ifaceObj.Index, lc.Control)
    65  	return address, nil
    66  }