1 package arp
2
3 import (
4 "errors"
5 "net"
6 "net/netip"
7 "time"
8
9 "github.com/mdlayher/ethernet"
10 "github.com/mdlayher/packet"
11 )
12
13
14
15 var errNoIPv4Addr = errors.New("no IPv4 address available for interface")
16
17
18
19 const protocolARP = 0x0806
20
21
22
23 type Client struct {
24 ifi *net.Interface
25 ip netip.Addr
26 p net.PacketConn
27 }
28
29
30
31
32 func Dial(ifi *net.Interface) (*Client, error) {
33
34
35 p, err := packet.Listen(ifi, packet.Raw, protocolARP, nil)
36 if err != nil {
37 return nil, err
38 }
39 return New(ifi, p)
40 }
41
42
43
44
45
46
47 func New(ifi *net.Interface, p net.PacketConn) (*Client, error) {
48
49 addrs, err := ifi.Addrs()
50 if err != nil {
51 return nil, err
52 }
53
54 ipaddrs := make([]netip.Addr, len(addrs))
55 for i, a := range addrs {
56 ipPrefix, err := netip.ParsePrefix(a.String())
57 if err != nil {
58 return nil, err
59 }
60 ipaddrs[i] = ipPrefix.Addr()
61 }
62
63 return newClient(ifi, p, ipaddrs)
64 }
65
66
67
68
69 func newClient(ifi *net.Interface, p net.PacketConn, addrs []netip.Addr) (*Client, error) {
70 ip, err := firstIPv4Addr(addrs)
71 if err != nil {
72 return nil, err
73 }
74
75 return &Client{
76 ifi: ifi,
77 ip: ip,
78 p: p,
79 }, nil
80 }
81
82
83
84 func (c *Client) Close() error {
85 return c.p.Close()
86 }
87
88
89
90
91
92
93
94
95 func (c *Client) Request(ip netip.Addr) error {
96 if !c.ip.IsValid() {
97 return errNoIPv4Addr
98 }
99
100
101
102 arp, err := NewPacket(OperationRequest, c.ifi.HardwareAddr, c.ip, ethernet.Broadcast, ip)
103 if err != nil {
104 return err
105 }
106 return c.WriteTo(arp, ethernet.Broadcast)
107 }
108
109
110
111
112
113
114 func (c *Client) Resolve(ip netip.Addr) (net.HardwareAddr, error) {
115 err := c.Request(ip)
116 if err != nil {
117 return nil, err
118 }
119
120
121 for {
122 arp, _, err := c.Read()
123 if err != nil {
124 return nil, err
125 }
126
127 if arp.Operation != OperationReply || arp.SenderIP != ip {
128 continue
129 }
130
131 return arp.SenderHardwareAddr, nil
132 }
133 }
134
135
136
137 func (c *Client) Read() (*Packet, *ethernet.Frame, error) {
138 buf := make([]byte, 128)
139 for {
140 n, _, err := c.p.ReadFrom(buf)
141 if err != nil {
142 return nil, nil, err
143 }
144
145 p, eth, err := parsePacket(buf[:n])
146 if err != nil {
147 if err == errInvalidARPPacket {
148 continue
149 }
150 return nil, nil, err
151 }
152 return p, eth, nil
153 }
154 }
155
156
157
158
159 func (c *Client) WriteTo(p *Packet, addr net.HardwareAddr) error {
160 pb, err := p.MarshalBinary()
161 if err != nil {
162 return err
163 }
164
165 f := ðernet.Frame{
166 Destination: addr,
167 Source: p.SenderHardwareAddr,
168 EtherType: ethernet.EtherTypeARP,
169 Payload: pb,
170 }
171
172 fb, err := f.MarshalBinary()
173 if err != nil {
174 return err
175 }
176
177 _, err = c.p.WriteTo(fb, &packet.Addr{HardwareAddr: addr})
178 return err
179 }
180
181
182
183
184
185
186
187
188 func (c *Client) Reply(req *Packet, hwAddr net.HardwareAddr, ip netip.Addr) error {
189 p, err := NewPacket(OperationReply, hwAddr, ip, req.SenderHardwareAddr, req.SenderIP)
190 if err != nil {
191 return err
192 }
193 return c.WriteTo(p, req.SenderHardwareAddr)
194 }
195
196
197
198
199
200
201
202
203
204
205
206 func (c *Client) SetDeadline(t time.Time) error {
207 return c.p.SetDeadline(t)
208 }
209
210
211
212
213
214 func (c *Client) SetReadDeadline(t time.Time) error {
215 return c.p.SetReadDeadline(t)
216 }
217
218
219
220
221
222
223
224 func (c *Client) SetWriteDeadline(t time.Time) error {
225 return c.p.SetWriteDeadline(t)
226 }
227
228
229
230 func (c Client) HardwareAddr() net.HardwareAddr {
231 return c.ifi.HardwareAddr
232 }
233
234
235
236 func firstIPv4Addr(addrs []netip.Addr) (netip.Addr, error) {
237 for _, a := range addrs {
238 if a.Is4() {
239 return a, nil
240 }
241 }
242 return netip.Addr{}, errNoIPv4Addr
243 }
244
View as plain text