github.com/sagernet/sing@v0.4.0-beta.19.0.20240518125136-f67a0988a636/common/control/bind_linux.go (about)

     1  package control
     2  
     3  import (
     4  	"os"
     5  	"syscall"
     6  
     7  	"github.com/sagernet/sing/common/atomic"
     8  	E "github.com/sagernet/sing/common/exceptions"
     9  
    10  	"golang.org/x/sys/unix"
    11  )
    12  
    13  var ifIndexDisabled atomic.Bool
    14  
    15  func bindToInterface(conn syscall.RawConn, network string, address string, finder InterfaceFinder, interfaceName string, interfaceIndex int, preferInterfaceName bool) error {
    16  	return Raw(conn, func(fd uintptr) error {
    17  		if !preferInterfaceName && !ifIndexDisabled.Load() {
    18  			if interfaceIndex == -1 {
    19  				if interfaceName == "" {
    20  					return os.ErrInvalid
    21  				}
    22  				var err error
    23  				interfaceIndex, err = finder.InterfaceIndexByName(interfaceName)
    24  				if err != nil {
    25  					return err
    26  				}
    27  			}
    28  			err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_BINDTOIFINDEX, interfaceIndex)
    29  			if err == nil {
    30  				return nil
    31  			} else if E.IsMulti(err, unix.ENOPROTOOPT, unix.EINVAL) {
    32  				ifIndexDisabled.Store(true)
    33  			} else {
    34  				return err
    35  			}
    36  		}
    37  		if interfaceName == "" {
    38  			return os.ErrInvalid
    39  		}
    40  		return unix.BindToDevice(int(fd), interfaceName)
    41  	})
    42  }