-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathpacket.go
241 lines (198 loc) · 6.92 KB
/
packet.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
package packet
import (
"net"
"syscall"
"time"
"golang.org/x/net/bpf"
)
const (
// network is the network reported in net.OpError.
network = "packet"
// Operation names which may be returned in net.OpError.
opClose = "close"
opGetsockopt = "getsockopt"
opListen = "listen"
opRawControl = "raw-control"
opRawRead = "raw-read"
opRawWrite = "raw-write"
opRead = "read"
opSet = "set"
opSetsockopt = "setsockopt"
opSyscallConn = "syscall-conn"
opWrite = "write"
)
// Config contains options for a Conn.
type Config struct {
// Filter is an optional assembled BPF filter which can be applied to the
// Conn before bind(2) is called.
//
// The Conn.SetBPF method serves the same purpose once a Conn has already
// been opened, but setting Filter applies the BPF filter before the Conn is
// bound. This ensures that unexpected packets will not be captured before
// the Conn is opened.
Filter []bpf.RawInstruction
}
// Type is a socket type used when creating a Conn with Listen.
//enumcheck:exhaustive
type Type int
// Possible Type values. Note that the zero value is not valid: callers must
// always specify one of Raw or Datagram when calling Listen.
const (
_ Type = iota
Raw
Datagram
)
// Listen opens a packet sockets connection on the specified interface, using
// the given socket type and protocol values.
//
// The socket type must be one of the Type constants: Raw or Datagram.
//
// The Config specifies optional configuration for the Conn. A nil *Config
// applies the default configuration.
func Listen(ifi *net.Interface, socketType Type, protocol int, cfg *Config) (*Conn, error) {
l, err := listen(ifi, socketType, protocol, cfg)
if err != nil {
return nil, opError(opListen, err, &Addr{HardwareAddr: ifi.HardwareAddr})
}
return l, nil
}
// TODO(mdlayher): we want to support FileConn for advanced use cases, but this
// library would also need a big endian protocol value and an interface index.
// For now we won't bother, but reconsider in the future.
var (
_ net.PacketConn = &Conn{}
_ syscall.Conn = &Conn{}
_ bpf.Setter = &Conn{}
)
// A Conn is an Linux packet sockets (AF_PACKET) implementation of a
// net.PacketConn.
type Conn struct {
c *conn
// Metadata about the local connection.
addr *Addr
ifIndex int
protocol uint16
}
// Close closes the connection.
func (c *Conn) Close() error {
return c.opError(opClose, c.c.Close())
}
// LocalAddr returns the local network address. The Addr returned is shared by
// all invocations of LocalAddr, so do not modify it.
func (c *Conn) LocalAddr() net.Addr { return c.addr }
// ReadFrom implements the net.PacketConn ReadFrom method.
func (c *Conn) ReadFrom(b []byte) (int, net.Addr, error) {
return c.readFrom(b)
}
// WriteTo implements the net.PacketConn WriteTo method.
func (c *Conn) WriteTo(b []byte, addr net.Addr) (int, error) {
return c.writeTo(b, addr)
}
// SetDeadline implements the net.PacketConn SetDeadline method.
func (c *Conn) SetDeadline(t time.Time) error {
return c.opError(opSet, c.c.SetDeadline(t))
}
// SetReadDeadline implements the net.PacketConn SetReadDeadline method.
func (c *Conn) SetReadDeadline(t time.Time) error {
return c.opError(opSet, c.c.SetReadDeadline(t))
}
// SetWriteDeadline implements the net.PacketConn SetWriteDeadline method.
func (c *Conn) SetWriteDeadline(t time.Time) error {
return c.opError(opSet, c.c.SetWriteDeadline(t))
}
// SetBPF attaches an assembled BPF program to the Conn.
func (c *Conn) SetBPF(filter []bpf.RawInstruction) error {
return c.opError(opSetsockopt, c.c.SetBPF(filter))
}
// SetPromiscuous enables or disables promiscuous mode on the Conn, allowing it
// to receive traffic that is not addressed to the Conn's network interface.
func (c *Conn) SetPromiscuous(enable bool) error {
return c.setPromiscuous(enable)
}
// Stats contains statistics about a Conn reported by the Linux kernel.
type Stats struct {
// The total number of packets received.
Packets uint32
// The number of packets dropped.
Drops uint32
// The total number of times that a receive queue is frozen. May be zero if
// the Linux kernel is not new enough to support TPACKET_V3 statistics.
FreezeQueueCount uint32
}
// Stats retrieves statistics about the Conn from the Linux kernel.
//
// Note that calling Stats will reset the kernel's internal counters for this
// Conn. If you want to maintain cumulative statistics by polling Stats over
// time, you must do so in your calling code.
func (c *Conn) Stats() (*Stats, error) { return c.stats() }
// SyscallConn returns a raw network connection. This implements the
// syscall.Conn interface.
func (c *Conn) SyscallConn() (syscall.RawConn, error) {
rc, err := c.c.SyscallConn()
if err != nil {
return nil, c.opError(opSyscallConn, err)
}
return &rawConn{
rc: rc,
addr: c.addr,
}, nil
}
// opError is a convenience for the function opError that also passes the local
// and remote addresses of the Conn.
func (c *Conn) opError(op string, err error) error {
return opError(op, err, c.addr)
}
// TODO(mdlayher): see if we can port smarter net.OpError logic into
// socket.Conn's SyscallConn type to avoid the need for this wrapper.
var _ syscall.RawConn = &rawConn{}
// A rawConn is a syscall.RawConn that wraps an internal syscall.RawConn in order
// to produce net.OpError error values.
type rawConn struct {
rc syscall.RawConn
addr *Addr
}
// Control implements the syscall.RawConn Control method.
func (rc *rawConn) Control(fn func(fd uintptr)) error {
return rc.opError(opRawControl, rc.rc.Control(fn))
}
// Control implements the syscall.RawConn Read method.
func (rc *rawConn) Read(fn func(fd uintptr) (done bool)) error {
return rc.opError(opRawRead, rc.rc.Read(fn))
}
// Control implements the syscall.RawConn Write method.
func (rc *rawConn) Write(fn func(fd uintptr) (done bool)) error {
return rc.opError(opRawWrite, rc.rc.Write(fn))
}
// opError is a convenience for the function opError that also passes the
// address of the rawConn.
func (rc *rawConn) opError(op string, err error) error {
return opError(op, err, rc.addr)
}
var _ net.Addr = &Addr{}
// TODO(mdlayher): expose sll_hatype and sll_pkttype on receive Addr only.
// An Addr is a physical-layer address.
type Addr struct {
HardwareAddr net.HardwareAddr
}
// Network returns the address's network name, "packet".
func (a *Addr) Network() string { return network }
// String returns the string representation of an Addr.
func (a *Addr) String() string {
return a.HardwareAddr.String()
}
// opError unpacks err if possible, producing a net.OpError with the input
// parameters in order to implement net.PacketConn. As a convenience, opError
// returns nil if the input error is nil.
func opError(op string, err error, local net.Addr) error {
if err == nil {
return nil
}
// TODO(mdlayher): try to comply with net.PacketConn as best as we can; land
// a nettest.TestPacketConn API upstream.
return &net.OpError{
Op: op,
Net: network,
Addr: local,
Err: err,
}
}