-
-
Notifications
You must be signed in to change notification settings - Fork 278
/
tables.go
263 lines (215 loc) Β· 6.66 KB
/
tables.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
// +build windows
package iphelper
import (
"encoding/binary"
"errors"
"fmt"
"net"
"unsafe"
"golang.org/x/sys/windows"
)
const (
iphelper_TCP_TABLE_OWNER_PID_ALL uintptr = 5
iphelper_UDP_TABLE_OWNER_PID uintptr = 1
iphelper_TCP_STATE_LISTEN uint32 = 2
)
type connectionEntry struct {
localIP net.IP
remoteIP net.IP
localPort uint16
remotePort uint16
pid int
}
func (entry *connectionEntry) String() string {
return fmt.Sprintf("PID=%d %s:%d <> %s:%d", entry.pid, entry.localIP, entry.localPort, entry.remoteIP, entry.remotePort)
}
type iphelperTcpTable struct {
// docs: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366921(v=vs.85).aspx
numEntries uint32
table [4096]iphelperTcpRow
}
type iphelperTcpRow struct {
// docs: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366913(v=vs.85).aspx
state uint32
localAddr uint32
localPort uint32
remoteAddr uint32
remotePort uint32
owningPid uint32
}
type iphelperTcp6Table struct {
// docs: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366905(v=vs.85).aspx
numEntries uint32
table [4096]iphelperTcp6Row
}
type iphelperTcp6Row struct {
// docs: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366896(v=vs.85).aspx
localAddr [16]byte
localScopeId uint32
localPort uint32
remoteAddr [16]byte
remoteScopeId uint32
remotePort uint32
state uint32
owningPid uint32
}
type iphelperUdpTable struct {
// docs: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366932(v=vs.85).aspx
numEntries uint32
table [4096]iphelperUdpRow
}
type iphelperUdpRow struct {
// docs: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366928(v=vs.85).aspx
localAddr uint32
localPort uint32
owningPid uint32
}
type iphelperUdp6Table struct {
// docs: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366925(v=vs.85).aspx
numEntries uint32
table [4096]iphelperUdp6Row
}
type iphelperUdp6Row struct {
// docs: https://msdn.microsoft.com/en-us/library/windows/desktop/aa366923(v=vs.85).aspx
localAddr [16]byte
localScopeId uint32
localPort uint32
owningPid uint32
}
const (
IPv4 uint8 = 4
IPv6 uint8 = 6
TCP uint8 = 6
UDP uint8 = 17
)
func (ipHelper *IPHelper) GetTables(protocol uint8, ipVersion uint8) (connections []*connectionEntry, listeners []*connectionEntry, err error) {
// docs: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365928(v=vs.85).aspx
if !ipHelper.valid.IsSet() {
return nil, nil, errInvalid
}
var afClass int
switch ipVersion {
case IPv4:
afClass = windows.AF_INET
case IPv6:
afClass = windows.AF_INET6
default:
return nil, nil, errors.New("invalid protocol")
}
bufSize := 4096
buf := make([]byte, bufSize)
var r1 uintptr
switch protocol {
case TCP:
r1, _, err = ipHelper.getExtendedTcpTable.Call(
uintptr(unsafe.Pointer(&buf[0])), // _Out_ PVOID pTcpTable
uintptr(unsafe.Pointer(&bufSize)), // _Inout_ PDWORD pdwSize
0, // _In_ BOOL bOrder
uintptr(afClass), // _In_ ULONG ulAf
iphelper_TCP_TABLE_OWNER_PID_ALL, // _In_ TCP_TABLE_CLASS TableClass
0, // _In_ ULONG Reserved
)
case UDP:
r1, _, err = ipHelper.getExtendedUdpTable.Call(
uintptr(unsafe.Pointer(&buf[0])), // _Out_ PVOID pUdpTable,
uintptr(unsafe.Pointer(&bufSize)), // _Inout_ PDWORD pdwSize,
0, // _In_ BOOL bOrder,
uintptr(afClass), // _In_ ULONG ulAf,
iphelper_UDP_TABLE_OWNER_PID, // _In_ UDP_TABLE_CLASS TableClass,
0, // _In_ ULONG Reserved
)
}
switch r1 {
// case windows.ERROR_INSUFFICIENT_BUFFER:
// return nil, fmt.Errorf("insufficient buffer error: %s", err)
// case windows.ERROR_INVALID_PARAMETER:
// return nil, fmt.Errorf("invalid parameter: %s", err)
case windows.NO_ERROR:
default:
return nil, nil, fmt.Errorf("unexpected error: %s", err)
}
// parse output
switch {
case protocol == TCP && ipVersion == IPv4:
tcpTable := (*iphelperTcpTable)(unsafe.Pointer(&buf[0]))
table := tcpTable.table[:tcpTable.numEntries]
for _, row := range table {
new := &connectionEntry{}
// PID
new.pid = int(row.owningPid)
// local
new.localIP = make([]byte, 4)
binary.LittleEndian.PutUint32(new.localIP, row.localAddr)
new.localPort = uint16(row.localPort>>8 | row.localPort<<8)
// remote
if row.state == iphelper_TCP_STATE_LISTEN {
if new.localIP.Equal(net.IPv4zero) {
new.localIP = nil
}
listeners = append(listeners, new)
} else {
new.remoteIP = make([]byte, 4)
binary.LittleEndian.PutUint32(new.remoteIP, row.remoteAddr)
new.remotePort = uint16(row.remotePort>>8 | row.remotePort<<8)
connections = append(connections, new)
}
}
case protocol == TCP && ipVersion == IPv6:
tcpTable := (*iphelperTcp6Table)(unsafe.Pointer(&buf[0]))
table := tcpTable.table[:tcpTable.numEntries]
for _, row := range table {
new := &connectionEntry{}
// PID
new.pid = int(row.owningPid)
// local
new.localIP = net.IP(row.localAddr[:])
new.localPort = uint16(row.localPort>>8 | row.localPort<<8)
// remote
if row.state == iphelper_TCP_STATE_LISTEN {
if new.localIP.Equal(net.IPv6zero) {
new.localIP = nil
}
listeners = append(listeners, new)
} else {
new.remoteIP = net.IP(row.remoteAddr[:])
new.remotePort = uint16(row.remotePort>>8 | row.remotePort<<8)
connections = append(connections, new)
}
}
case protocol == UDP && ipVersion == IPv4:
udpTable := (*iphelperUdpTable)(unsafe.Pointer(&buf[0]))
table := udpTable.table[:udpTable.numEntries]
for _, row := range table {
new := &connectionEntry{}
// PID
new.pid = int(row.owningPid)
// local
new.localPort = uint16(row.localPort>>8 | row.localPort<<8)
if row.localAddr == 0 {
listeners = append(listeners, new)
} else {
new.localIP = make([]byte, 4)
binary.LittleEndian.PutUint32(new.localIP, row.localAddr)
connections = append(connections, new)
}
}
case protocol == UDP && ipVersion == IPv6:
udpTable := (*iphelperUdp6Table)(unsafe.Pointer(&buf[0]))
table := udpTable.table[:udpTable.numEntries]
for _, row := range table {
new := &connectionEntry{}
// PID
new.pid = int(row.owningPid)
// local
new.localIP = net.IP(row.localAddr[:])
new.localPort = uint16(row.localPort>>8 | row.localPort<<8)
if new.localIP.Equal(net.IPv6zero) {
new.localIP = nil
listeners = append(listeners, new)
} else {
connections = append(connections, new)
}
}
}
return connections, listeners, nil
}