forked from mdlayher/arp
/
server.go
161 lines (136 loc) · 3.91 KB
/
server.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
package arp
import (
"io"
"net"
"github.com/mdlayher/ethernet"
"github.com/mdlayher/raw"
)
// A Server is an ARP server, and is used to configure an ARP server's
// behavior.
type Server struct {
// Iface is the the network interface on which this server should
// listen.
Iface *net.Interface
// Handler is the handler to use while serving ARP requests. If this
// value is nil, DefaultServeMux will be used in place of Handler.
Handler Handler
}
// ListenAndServe listens for ARP requests using a raw ethernet socket on
// the specified interface, using the default Server configuration and
// specified handler to handle ARP requests. If the handler is nil,
// DefaultServeMux is used instead.
func ListenAndServe(iface string, handler Handler) error {
// Verify network interface exists
ifi, err := net.InterfaceByName(iface)
if err != nil {
return err
}
return (&Server{
Iface: ifi,
Handler: handler,
}).ListenAndServe()
}
// ListenAndServe listens for ARP requests using a raw ethernet socket on the
// network interface specified by s.Iface. Serve is called to handle serving
// traffic once ListenAndServe opens a raw ethernet socket.
func (s *Server) ListenAndServe() error {
p, err := raw.ListenPacket(s.Iface, raw.ProtocolARP)
if err != nil {
return err
}
return s.Serve(p)
}
// Serve accepts incoming connections ARP requests on net.PacketConn p,
// creating a new goroutine for each.
//
// The service goroutine reads requests, generates the appropriate Request and
// ResponseSender values, then calls s.Handler to handle the request.
func (s *Server) Serve(p net.PacketConn) error {
defer p.Close()
// Loop and read requests until exit
buf := make([]byte, 128)
for {
n, addr, err := p.ReadFrom(buf)
if err != nil {
// Treat EOF as an exit signal
if err == io.EOF {
return nil
}
return err
}
c := s.newConn(p, addr.(*raw.Addr), n, buf)
go c.serve()
}
}
// A conn is an in-flight ARP request which contains information about a
// request to the server.
type conn struct {
p net.PacketConn
remoteAddr *raw.Addr
server *Server
buf []byte
}
// newConn creates a new conn using information received in a single ARP
// request. newConn makes a copy of the input buffer for use in handling
// a single connection.
func (s *Server) newConn(p net.PacketConn, addr *raw.Addr, n int, buf []byte) *conn {
c := &conn{
p: p,
remoteAddr: addr,
server: s,
buf: make([]byte, n),
}
copy(c.buf, buf[:n])
return c
}
// serve handles serving an individual ARP request, and is invoked in a
// goroutine.
func (c *conn) serve() {
// Parese ethernet frame and ARP packet to create Request for client
// consumption
r, err := parseRequest(c.buf)
if err != nil {
// Ethernet frames with non-ARP EtherType are ignored
if err == errInvalidARPPacket {
return
}
return
}
// Set up response to send data back to client
w := &response{
p: c.p,
remoteAddr: c.remoteAddr,
}
// If set, invoke ARP handler using request and response
// Default to DefaultServeMux if handler is not available
handler := c.server.Handler
if handler == nil {
handler = DefaultServeMux
}
handler.ServeARP(w, r)
}
// response represents an ARP response, and implements ResponseSender so that
// outbound Packets can be appropriately created and sent to a client.
type response struct {
p net.PacketConn
remoteAddr *raw.Addr
}
// Send marshals an input Packet to binary form, wraps it in an ethernet frame,
// and sends it to the hardware address specified by r.remoteAddr.
func (r *response) Send(p *Packet) (int, error) {
pb, err := p.MarshalBinary()
if err != nil {
return 0, err
}
f := ðernet.Frame{
Destination: p.TargetHardwareAddr,
Source: p.SenderHardwareAddr,
EtherType: ethernet.EtherTypeARP,
Payload: pb,
}
fb, err := f.MarshalBinary()
if err != nil {
return 0, err
}
return r.p.WriteTo(fb, r.remoteAddr)
}