-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsocket_extra.go
166 lines (149 loc) · 3.52 KB
/
socket_extra.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
package main
import (
"encoding/binary"
"errors"
"net"
"github.com/vishvananda/netlink"
"github.com/vishvananda/netlink/nl"
"golang.org/x/sys/unix"
)
const (
sizeofSocketID = 0x30
sizeofSocketRequest = sizeofSocketID + 0x8
sizeofSocket = sizeofSocketID + 0x18
)
const (
TCP_ESTABLISHED = iota + 1
TCP_SYN_SENT
TCP_SYN_RECV
TCP_FIN_WAIT1
TCP_FIN_WAIT2
TCP_TIME_WAIT
TCP_CLOSE
TCP_CLOSE_WAIT
TCP_LAST_ACK
TCP_LISTEN
TCP_CLOSING /* Now a valid state */
TCP_NEW_SYN_RECV
TCP_MAX_STATES /* Leave at the end! */
)
var (
native = nl.NativeEndian()
networkOrder = binary.BigEndian
)
type socketRequest struct {
Family uint8
Protocol uint8
Ext uint8
pad uint8
States uint32
ID netlink.SocketID
}
type writeBuffer struct {
Bytes []byte
pos int
}
func (b *writeBuffer) Write(c byte) {
b.Bytes[b.pos] = c
b.pos++
}
func (b *writeBuffer) Next(n int) []byte {
s := b.Bytes[b.pos : b.pos+n]
b.pos += n
return s
}
func (r *socketRequest) Serialize() []byte {
b := writeBuffer{Bytes: make([]byte, sizeofSocketRequest)}
b.Write(r.Family)
b.Write(r.Protocol)
b.Write(r.Ext)
b.Write(r.pad)
native.PutUint32(b.Next(4), r.States)
networkOrder.PutUint16(b.Next(2), r.ID.SourcePort)
networkOrder.PutUint16(b.Next(2), r.ID.DestinationPort)
copy(b.Next(4), r.ID.Source.To4())
b.Next(12)
copy(b.Next(4), r.ID.Destination.To4())
b.Next(12)
native.PutUint32(b.Next(4), r.ID.Interface)
native.PutUint32(b.Next(4), r.ID.Cookie[0])
native.PutUint32(b.Next(4), r.ID.Cookie[1])
return b.Bytes
}
func (r *socketRequest) Len() int { return sizeofSocketRequest }
// GetListenersOnPort returns the Socket identified by its local and remote addresses.
func HasListenersOnPort4(port uint16) (bool, error) {
s, err := nl.Subscribe(unix.NETLINK_INET_DIAG)
if err != nil {
return false, err
}
defer s.Close()
req := nl.NewNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
req.AddData(&socketRequest{
Family: unix.AF_INET,
Protocol: unix.IPPROTO_TCP,
States: 1 << TCP_LISTEN,
ID: netlink.SocketID{
SourcePort: port,
DestinationPort: 0,
Source: net.IP{0, 0, 0, 0},
Destination: net.IP{0, 0, 0, 0},
Cookie: [2]uint32{0, 0},
},
})
s.Send(req)
msgs, err := s.Receive()
if err != nil {
return false, err
}
if len(msgs) == 0 {
return false, errors.New("no message nor error from netlink")
}
if len(msgs) > 2 {
return true, nil
}
return len(msgs[0].Data) >= sizeofSocket, nil
}
func HasListenersOnPort6(port uint16) (bool, error) {
s, err := nl.Subscribe(unix.NETLINK_INET_DIAG)
if err != nil {
return false, err
}
defer s.Close()
req := nl.NewNetlinkRequest(nl.SOCK_DIAG_BY_FAMILY, unix.NLM_F_DUMP)
req.AddData(&socketRequest{
Family: unix.AF_INET6,
Protocol: unix.IPPROTO_TCP,
States: 1 << TCP_LISTEN,
ID: netlink.SocketID{
SourcePort: port,
DestinationPort: 0,
Source: net.IP{0, 0, 0, 0, 0, 0, 0, 0},
Destination: net.IP{0, 0, 0, 0, 0, 0, 0, 0},
Cookie: [2]uint32{0, 0},
},
})
s.Send(req)
msgs, err := s.Receive()
if err != nil {
return false, err
}
if len(msgs) == 0 {
return false, errors.New("no message nor error from netlink")
}
if len(msgs) > 2 {
return true, nil
}
return len(msgs[0].Data) >= sizeofSocket, nil
}
func HasListenersOnPortSimple(port uint16) bool {
hasListeners4, err := HasListenersOnPort4(port)
if err != nil {
return false
}
hasListeners6, err := HasListenersOnPort6(port)
if err != nil {
return false
}
return hasListeners4 || hasListeners6
}