github.com/igoogolx/clash@v1.19.8/component/dialer/bind_linux.go (about)

     1  package dialer
     2  
     3  import (
     4  	"net"
     5  	"syscall"
     6  
     7  	"golang.org/x/sys/unix"
     8  )
     9  
    10  type controlFn = func(network, address string, c syscall.RawConn) error
    11  
    12  func bindControl(ifaceName string, chain controlFn) controlFn {
    13  	return func(network, address string, c syscall.RawConn) (err error) {
    14  		defer func() {
    15  			if err == nil && chain != nil {
    16  				err = chain(network, address, c)
    17  			}
    18  		}()
    19  
    20  		ipStr, _, err := net.SplitHostPort(address)
    21  		if err == nil {
    22  			ip := net.ParseIP(ipStr)
    23  			if ip != nil && !ip.IsGlobalUnicast() {
    24  				return
    25  			}
    26  		}
    27  
    28  		var innerErr error
    29  		err = c.Control(func(fd uintptr) {
    30  			innerErr = unix.BindToDevice(int(fd), ifaceName)
    31  		})
    32  
    33  		if innerErr != nil {
    34  			err = innerErr
    35  		}
    36  
    37  		return
    38  	}
    39  }
    40  
    41  func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, _ string, _ net.IP) error {
    42  	dialer.Control = bindControl(ifaceName, dialer.Control)
    43  
    44  	return nil
    45  }
    46  
    47  func bindIfaceToListenConfig(ifaceName string, lc *net.ListenConfig, _, address string) (string, error) {
    48  	lc.Control = bindControl(ifaceName, lc.Control)
    49  
    50  	return address, nil
    51  }