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

     1  package control
     2  
     3  import (
     4  	"encoding/binary"
     5  	"os"
     6  	"syscall"
     7  	"unsafe"
     8  
     9  	M "github.com/sagernet/sing/common/metadata"
    10  )
    11  
    12  func bindToInterface(conn syscall.RawConn, network string, address string, finder InterfaceFinder, interfaceName string, interfaceIndex int, preferInterfaceName bool) error {
    13  	return Raw(conn, func(fd uintptr) error {
    14  		var err error
    15  		if interfaceIndex == -1 {
    16  			if finder == nil {
    17  				return os.ErrInvalid
    18  			}
    19  			interfaceIndex, err = finder.InterfaceIndexByName(interfaceName)
    20  			if err != nil {
    21  				return err
    22  			}
    23  		}
    24  		handle := syscall.Handle(fd)
    25  		if M.ParseSocksaddr(address).AddrString() == "" {
    26  			err = bind4(handle, interfaceIndex)
    27  			if err != nil {
    28  				return err
    29  			}
    30  			// try bind ipv6, if failed, ignore. it's a workaround for windows disable interface ipv6
    31  			bind6(handle, interfaceIndex)
    32  			return nil
    33  		}
    34  		switch network {
    35  		case "tcp4", "udp4", "ip4":
    36  			return bind4(handle, interfaceIndex)
    37  		default:
    38  			return bind6(handle, interfaceIndex)
    39  		}
    40  	})
    41  }
    42  
    43  const (
    44  	IP_UNICAST_IF   = 31
    45  	IPV6_UNICAST_IF = 31
    46  )
    47  
    48  func bind4(handle syscall.Handle, ifaceIdx int) error {
    49  	var bytes [4]byte
    50  	binary.BigEndian.PutUint32(bytes[:], uint32(ifaceIdx))
    51  	idx := *(*uint32)(unsafe.Pointer(&bytes[0]))
    52  	return syscall.SetsockoptInt(handle, syscall.IPPROTO_IP, IP_UNICAST_IF, int(idx))
    53  }
    54  
    55  func bind6(handle syscall.Handle, ifaceIdx int) error {
    56  	return syscall.SetsockoptInt(handle, syscall.IPPROTO_IPV6, IPV6_UNICAST_IF, ifaceIdx)
    57  }