forked from libp2p/go-netroute
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sockaddr_windows.go
130 lines (116 loc) · 3.13 KB
/
sockaddr_windows.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//go:build windows
package netroute
import (
"net"
"strconv"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
// socklen is a type for the length of a sockaddr.
type socklen uint
// ipAndZoneToSockaddr converts a net.IP (with optional IPv6 Zone) to a Sockaddr
// Returns nil if conversion fails.
func ipAndZoneToSockaddr(ip net.IP, zone string) windows.Sockaddr {
// Unspecified?
if ip == nil {
if zone != "" {
return &windows.SockaddrInet6{ZoneId: uint32(ip6ZoneToInt(zone))}
}
return new(windows.SockaddrInet4)
}
// Valid IPv4?
if ip4 := ip.To4(); ip4 != nil && zone == "" {
var buf [4]byte
copy(buf[:], ip4) // last 4 bytes
return &windows.SockaddrInet4{Addr: buf}
}
// Valid IPv6 address?
if ip6 := ip.To16(); ip6 != nil {
var buf [16]byte
copy(buf[:], ip6)
return &windows.SockaddrInet6{Addr: buf, ZoneId: uint32(ip6ZoneToInt(zone))}
}
return nil
}
// sockaddrToIPAndZone converts a Sockaddr to a net.IP (with optional IPv6 Zone)
// Returns nil if conversion fails.
func sockaddrToIPAndZone(sa windows.Sockaddr) (net.IP, string) {
switch sa := sa.(type) {
case *windows.SockaddrInet4:
ip := make([]byte, 16)
// V4InV6Prefix
ip[10] = 0xff
ip[11] = 0xff
copy(ip[12:16], sa.Addr[:])
return ip, ""
case *windows.SockaddrInet6:
ip := make([]byte, 16)
copy(ip, sa.Addr[:])
return ip, ip6ZoneToString(int(sa.ZoneId))
}
return nil, ""
}
func sockaddrToAny(sa windows.Sockaddr) (*windows.RawSockaddrAny, socklen, error) {
if sa == nil {
return nil, 0, syscall.EINVAL
}
switch sa := sa.(type) {
case *windows.SockaddrInet4:
if sa.Port < 0 || sa.Port > 0xFFFF {
return nil, 0, syscall.EINVAL
}
raw := new(windows.RawSockaddrAny)
raw.Addr.Family = windows.AF_INET
raw4 := (*windows.RawSockaddrInet4)(unsafe.Pointer(raw))
p := (*[2]byte)(unsafe.Pointer(&raw4.Port))
p[0] = byte(sa.Port >> 8)
p[1] = byte(sa.Port)
for i := 0; i < len(sa.Addr); i++ {
raw4.Addr[i] = sa.Addr[i]
}
return raw, socklen(unsafe.Sizeof(*raw4)), nil
case *windows.SockaddrInet6:
if sa.Port < 0 || sa.Port > 0xFFFF {
return nil, 0, syscall.EINVAL
}
raw := new(windows.RawSockaddrAny)
raw.Addr.Family = windows.AF_INET6
raw6 := (*windows.RawSockaddrInet6)(unsafe.Pointer(raw))
p := (*[2]byte)(unsafe.Pointer(&raw6.Port))
p[0] = byte(sa.Port >> 8)
p[1] = byte(sa.Port)
raw6.Scope_id = sa.ZoneId
for i := 0; i < len(sa.Addr); i++ {
raw6.Addr[i] = sa.Addr[i]
}
return raw, socklen(unsafe.Sizeof(*raw6)), nil
case *windows.SockaddrUnix:
return nil, 0, syscall.EWINDOWS
}
return nil, 0, syscall.EAFNOSUPPORT
}
// from: go/src/pkg/net/ipsock.go
// ip6ZoneToString converts an IP6 Zone unix int to a net string
// returns "" if zone is 0
func ip6ZoneToString(zone int) string {
if zone == 0 {
return ""
}
if ifi, err := net.InterfaceByIndex(zone); err == nil {
return ifi.Name
}
return strconv.Itoa(zone)
}
// ip6ZoneToInt converts an IP6 Zone net string to a unix int
// returns 0 if zone is ""
func ip6ZoneToInt(zone string) int {
if zone == "" {
return 0
}
if ifi, err := net.InterfaceByName(zone); err == nil {
return ifi.Index
}
n, _ := strconv.ParseInt(zone, 10, 32)
return int(n)
}