github.com/sagernet/sing@v0.2.6/common/control/bind_windows.go (about)

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