/
adapters.go
139 lines (126 loc) · 4.07 KB
/
adapters.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
131
132
133
134
135
136
137
138
139
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2018-present Datadog, Inc.
//go:build windows
package iphelper
import (
"C"
"fmt"
"net"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
var (
procGetAdaptersAddresses = modiphelper.NewProc("GetAdaptersAddresses")
)
// IPAdapterUnicastAddress is a Go approximation of IP_ADAPTER_UNICAST_ADDRESS_LH
//
// https://learn.microsoft.com/en-us/windows/win32/api/iptypes/ns-iptypes-ip_adapter_unicast_address_lh
type IPAdapterUnicastAddress struct {
Flags uint32
Address net.IP
}
type sockaddr struct {
family int16
port uint16
// if it's ipv4, the address is the first 4 bytes
// if it's ipv6, the address is bytes 4->20
addressBase uintptr
}
type socketAddress struct {
lpSockaddr *sockaddr
iSockaddrLength int32
}
type ipAdapterUnicastAddress struct {
length uint32
flags uint32
next *ipAdapterUnicastAddress
address socketAddress
}
// IPAdapterAddressesLh is a go adaptation of the C structure IP_ADAPTER_ADDRESSES_LH
// it is a go adaptation, rather than a matching structure, because the real structure
// is difficult to approximate in Go.
//
// https://learn.microsoft.com/en-us/windows/win32/api/iptypes/ns-iptypes-ip_adapter_addresses_lh
type IPAdapterAddressesLh struct {
Index uint32
AdapterName string
UnicastAddresses []IPAdapterUnicastAddress
}
type ipAdapterAddresses struct {
length uint32
ifIndex uint32
next *ipAdapterAddresses
adapterName unsafe.Pointer // pointer to character buffer
firstUnicastAddress *ipAdapterUnicastAddress
}
// GetAdaptersAddresses returns a map of all of the adapters, indexed by
// interface index
func GetAdaptersAddresses() (table map[uint32]IPAdapterAddressesLh, err error) {
size := uint32(15 * 1024)
rawbuf := make([]byte, size)
r, _, _ := procGetAdaptersAddresses.Call(uintptr(syscall.AF_INET),
uintptr(0), // flags == 0 for now
uintptr(0), // reserved, always zero
uintptr(unsafe.Pointer(&rawbuf[0])),
uintptr(unsafe.Pointer(&size)))
if r != 0 {
if r != uintptr(windows.ERROR_BUFFER_OVERFLOW) {
err = fmt.Errorf("Error getting address list %v", r)
return
}
rawbuf = make([]byte, size)
r, _, _ := procGetAdaptersAddresses.Call(uintptr(syscall.AF_INET),
uintptr(0), // flags == 0 for now
uintptr(0), // reserved, always zero
uintptr(unsafe.Pointer(&rawbuf[0])),
uintptr(unsafe.Pointer(&size)))
if r != 0 {
err = fmt.Errorf("Error getting address list %v", r)
return
}
}
// need to walk the list. The list is a C style list. The `Next` pointer
// is not the first element. The C structure is as follows
/*
typedef struct _IP_ADAPTER_ADDRESSES_LH {
union {
ULONGLONG Alignment;
struct {
ULONG Length;
IF_INDEX IfIndex;
};
};
struct _IP_ADAPTER_ADDRESSES_LH *Next;
PCHAR AdapterName;
PIP_ADAPTER_UNICAST_ADDRESS_LH FirstUnicastAddress;
// more fields follow which we're not using
*/
var addr *ipAdapterAddresses
table = make(map[uint32]IPAdapterAddressesLh)
addr = (*ipAdapterAddresses)(unsafe.Pointer(&rawbuf[0]))
for addr != nil {
var entry IPAdapterAddressesLh
entry.Index = addr.ifIndex
entry.AdapterName = C.GoString((*C.char)(addr.adapterName))
unicast := addr.firstUnicastAddress
for unicast != nil {
if unicast.address.lpSockaddr.family == syscall.AF_INET {
// ipv4 address
var uni IPAdapterUnicastAddress
uni.Address = (*[1 << 29]byte)(unsafe.Pointer(unicast.address.lpSockaddr))[4:8:8]
entry.UnicastAddresses = append(entry.UnicastAddresses, uni)
} else if unicast.address.lpSockaddr.family == syscall.AF_INET6 {
var uni IPAdapterUnicastAddress
uni.Address = (*[1 << 29]byte)(unsafe.Pointer(&(unicast.address.lpSockaddr.addressBase)))[:16:16]
entry.UnicastAddresses = append(entry.UnicastAddresses, uni)
}
unicast = unicast.next
}
table[entry.Index] = entry
addr = addr.next
}
return
}