1
2
3
4 package packet
5
6 import (
7 "context"
8 "encoding/binary"
9 "errors"
10 "math"
11 "net"
12 "os"
13
14 "github.com/josharian/native"
15 "github.com/mdlayher/socket"
16 "golang.org/x/sys/unix"
17 )
18
19
20
21 type conn = socket.Conn
22
23
24 func (c *Conn) readFrom(b []byte) (int, net.Addr, error) {
25
26
27
28
29
30
31
32
33 n, sa, err := c.c.Recvfrom(context.Background(), b, 0)
34 return n, fromSockaddr(sa), c.opError(opRead, err)
35 }
36
37
38 func (c *Conn) writeTo(b []byte, addr net.Addr) (int, error) {
39 sa, err := c.toSockaddr("sendto", addr)
40 if err != nil {
41 return 0, c.opError(opWrite, err)
42 }
43
44
45
46 if err := c.c.Sendto(context.Background(), b, 0, sa); err != nil {
47 return 0, c.opError(opWrite, err)
48 }
49
50 return len(b), nil
51 }
52
53
54 func (c *Conn) setPromiscuous(enable bool) error {
55 mreq := unix.PacketMreq{
56 Ifindex: int32(c.ifIndex),
57 Type: unix.PACKET_MR_PROMISC,
58 }
59
60 membership := unix.PACKET_DROP_MEMBERSHIP
61 if enable {
62 membership = unix.PACKET_ADD_MEMBERSHIP
63 }
64
65 return c.opError(
66 opSetsockopt,
67 c.c.SetsockoptPacketMreq(unix.SOL_PACKET, membership, &mreq),
68 )
69 }
70
71
72 func (c *Conn) stats() (*Stats, error) {
73 const (
74 level = unix.SOL_PACKET
75 name = unix.PACKET_STATISTICS
76 )
77
78
79 if stats, err := c.c.GetsockoptTpacketStatsV3(level, name); err == nil {
80 return &Stats{
81 Packets: stats.Packets,
82 Drops: stats.Drops,
83 FreezeQueueCount: stats.Freeze_q_cnt,
84 }, nil
85 }
86
87
88 stats, err := c.c.GetsockoptTpacketStats(level, name)
89 if err != nil {
90 return nil, c.opError(opGetsockopt, err)
91 }
92
93 return &Stats{
94 Packets: stats.Packets,
95 Drops: stats.Drops,
96
97 }, nil
98 }
99
100
101 func listen(ifi *net.Interface, socketType Type, protocol int, cfg *Config) (*Conn, error) {
102 if cfg == nil {
103
104 cfg = &Config{}
105 }
106
107
108 var typ int
109 switch socketType {
110 case Raw:
111 typ = unix.SOCK_RAW
112 case Datagram:
113 typ = unix.SOCK_DGRAM
114 default:
115 return nil, errors.New("packet: invalid Type value")
116 }
117
118
119
120
121 c, err := socket.Socket(unix.AF_PACKET, typ, 0, network, nil)
122 if err != nil {
123 return nil, err
124 }
125
126 conn, err := bind(c, ifi.Index, protocol, cfg)
127 if err != nil {
128 _ = c.Close()
129 return nil, err
130 }
131
132 return conn, nil
133 }
134
135
136 func bind(c *socket.Conn, ifIndex, protocol int, cfg *Config) (*Conn, error) {
137 if len(cfg.Filter) > 0 {
138
139 if err := c.SetBPF(cfg.Filter); err != nil {
140 return nil, err
141 }
142 }
143
144
145 pnet, err := htons(protocol)
146 if err != nil {
147 return nil, err
148 }
149
150
151
152 err = c.Bind(&unix.SockaddrLinklayer{
153 Protocol: pnet,
154 Ifindex: ifIndex,
155 })
156 if err != nil {
157 return nil, err
158 }
159
160 lsa, err := c.Getsockname()
161 if err != nil {
162 return nil, err
163 }
164
165
166
167 lsall := lsa.(*unix.SockaddrLinklayer)
168 addr := make(net.HardwareAddr, lsall.Halen)
169 copy(addr, lsall.Addr[:])
170
171 return &Conn{
172 c: c,
173
174 addr: &Addr{HardwareAddr: addr},
175 ifIndex: ifIndex,
176 protocol: pnet,
177 }, nil
178 }
179
180
181
182 func fromSockaddr(sa unix.Sockaddr) *Addr {
183 if sa == nil {
184 return nil
185 }
186
187 sall := sa.(*unix.SockaddrLinklayer)
188
189 return &Addr{
190
191
192 HardwareAddr: net.HardwareAddr(sall.Addr[:sall.Halen]),
193 }
194 }
195
196
197
198 func (c *Conn) toSockaddr(
199 op string,
200 addr net.Addr,
201 ) (unix.Sockaddr, error) {
202
203
204
205
206
207
208 a, ok := addr.(*Addr)
209 if !ok || a.HardwareAddr == nil {
210 return nil, os.NewSyscallError(op, unix.EINVAL)
211 }
212
213
214
215
216
217
218
219
220 sa := unix.SockaddrLinklayer{
221 Ifindex: c.ifIndex,
222 Protocol: c.protocol,
223 }
224
225
226
227 if len(a.HardwareAddr) > len(sa.Addr) {
228 return nil, os.NewSyscallError(op, unix.EINVAL)
229 }
230
231 sa.Halen = uint8(len(a.HardwareAddr))
232 copy(sa.Addr[:], a.HardwareAddr)
233
234 return &sa, nil
235 }
236
237
238 func htons(i int) (uint16, error) {
239 if i < 0 || i > math.MaxUint16 {
240 return 0, errors.New("packet: protocol value out of range")
241 }
242
243
244 var b [2]byte
245 binary.BigEndian.PutUint16(b[:], uint16(i))
246
247 return native.Endian.Uint16(b[:]), nil
248 }
249
View as plain text