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 }