client.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. package arp
  2. import (
  3. "errors"
  4. "net"
  5. "time"
  6. "github.com/mdlayher/ethernet"
  7. "github.com/mdlayher/raw"
  8. )
  9. var (
  10. // errNoIPv4Addr is returned when an interface does not have an IPv4
  11. // address.
  12. errNoIPv4Addr = errors.New("no IPv4 address available for interface")
  13. )
  14. // protocolARP is the uint16 EtherType representation of ARP (Address
  15. // Resolution Protocol, RFC 826).
  16. const protocolARP = 0x0806
  17. // A Client is an ARP client, which can be used to send and receive
  18. // ARP packets.
  19. type Client struct {
  20. ifi *net.Interface
  21. ip net.IP
  22. p net.PacketConn
  23. }
  24. // Dial creates a new Client using the specified network interface.
  25. // Dial retrieves the IPv4 address of the interface and binds a raw socket
  26. // to send and receive ARP packets.
  27. func Dial(ifi *net.Interface) (*Client, error) {
  28. // Open raw socket to send and receive ARP packets using ethernet frames
  29. // we build ourselves.
  30. p, err := raw.ListenPacket(ifi, protocolARP, nil)
  31. if err != nil {
  32. return nil, err
  33. }
  34. return New(ifi, p)
  35. }
  36. // New creates a new Client using the specified network interface
  37. // and net.PacketConn. This allows the caller to define exactly how they bind to the
  38. // net.PacketConn. This is most useful to define what protocol to pass to socket(7).
  39. //
  40. // In most cases, callers would be better off calling Dial.
  41. func New(ifi *net.Interface, p net.PacketConn) (*Client, error) {
  42. // Check for usable IPv4 addresses for the Client
  43. addrs, err := ifi.Addrs()
  44. if err != nil {
  45. return nil, err
  46. }
  47. return newClient(ifi, p, addrs)
  48. }
  49. // newClient is the internal, generic implementation of newClient. It is used
  50. // to allow an arbitrary net.PacketConn to be used in a Client, so testing
  51. // is easier to accomplish.
  52. func newClient(ifi *net.Interface, p net.PacketConn, addrs []net.Addr) (*Client, error) {
  53. ip, err := firstIPv4Addr(addrs)
  54. if err != nil {
  55. return nil, err
  56. }
  57. return &Client{
  58. ifi: ifi,
  59. ip: ip,
  60. p: p,
  61. }, nil
  62. }
  63. // Close closes the Client's raw socket and stops sending and receiving
  64. // ARP packets.
  65. func (c *Client) Close() error {
  66. return c.p.Close()
  67. }
  68. // Request sends an ARP request, asking for the hardware address
  69. // associated with an IPv4 address. The response, if any, can be read
  70. // with the Read method.
  71. //
  72. // Unlike Resolve, which provides an easier interface for getting the
  73. // hardware address, Request allows sending many requests in a row,
  74. // retrieving the responses afterwards.
  75. func (c *Client) Request(ip net.IP) error {
  76. if c.ip == nil {
  77. return errNoIPv4Addr
  78. }
  79. // Create ARP packet for broadcast address to attempt to find the
  80. // hardware address of the input IP address
  81. arp, err := NewPacket(OperationRequest, c.ifi.HardwareAddr, c.ip, ethernet.Broadcast, ip)
  82. if err != nil {
  83. return err
  84. }
  85. return c.WriteTo(arp, ethernet.Broadcast)
  86. }
  87. // Resolve performs an ARP request, attempting to retrieve the
  88. // hardware address of a machine using its IPv4 address. Resolve must not
  89. // be used concurrently with Read. If you're using Read (usually in a
  90. // loop), you need to use Request instead. Resolve may read more than
  91. // one message if it receives messages unrelated to the request.
  92. func (c *Client) Resolve(ip net.IP) (net.HardwareAddr, error) {
  93. err := c.Request(ip)
  94. if err != nil {
  95. return nil, err
  96. }
  97. // Loop and wait for replies
  98. for {
  99. arp, _, err := c.Read()
  100. if err != nil {
  101. return nil, err
  102. }
  103. if arp.Operation != OperationReply || !arp.SenderIP.Equal(ip) {
  104. continue
  105. }
  106. return arp.SenderHardwareAddr, nil
  107. }
  108. }
  109. // Read reads a single ARP packet and returns it, together with its
  110. // ethernet frame.
  111. func (c *Client) Read() (*Packet, *ethernet.Frame, error) {
  112. buf := make([]byte, 128)
  113. for {
  114. n, _, err := c.p.ReadFrom(buf)
  115. if err != nil {
  116. return nil, nil, err
  117. }
  118. p, eth, err := parsePacket(buf[:n])
  119. if err != nil {
  120. if err == errInvalidARPPacket {
  121. continue
  122. }
  123. return nil, nil, err
  124. }
  125. return p, eth, nil
  126. }
  127. }
  128. // WriteTo writes a single ARP packet to addr. Note that addr should,
  129. // but doesn't have to, match the target hardware address of the ARP
  130. // packet.
  131. func (c *Client) WriteTo(p *Packet, addr net.HardwareAddr) error {
  132. pb, err := p.MarshalBinary()
  133. if err != nil {
  134. return err
  135. }
  136. f := &ethernet.Frame{
  137. Destination: p.TargetHardwareAddr,
  138. Source: p.SenderHardwareAddr,
  139. EtherType: ethernet.EtherTypeARP,
  140. Payload: pb,
  141. }
  142. fb, err := f.MarshalBinary()
  143. if err != nil {
  144. return err
  145. }
  146. _, err = c.p.WriteTo(fb, &raw.Addr{HardwareAddr: addr})
  147. return err
  148. }
  149. // Reply constructs and sends a reply to an ARP request. On the ARP
  150. // layer, it will be addressed to the sender address of the packet. On
  151. // the ethernet layer, it will be sent to the actual remote address
  152. // from which the request was received.
  153. //
  154. // For more fine-grained control, use WriteTo to write a custom
  155. // response.
  156. func (c *Client) Reply(req *Packet, hwAddr net.HardwareAddr, ip net.IP) error {
  157. p, err := NewPacket(OperationReply, hwAddr, ip, req.SenderHardwareAddr, req.SenderIP)
  158. if err != nil {
  159. return err
  160. }
  161. return c.WriteTo(p, req.SenderHardwareAddr)
  162. }
  163. // Copyright (c) 2012 The Go Authors. All rights reserved.
  164. // Source code in this file is based on src/net/interface_linux.go,
  165. // from the Go standard library. The Go license can be found here:
  166. // https://golang.org/LICENSE.
  167. // Documentation taken from net.PacketConn interface. Thanks:
  168. // http://golang.org/pkg/net/#PacketConn.
  169. // SetDeadline sets the read and write deadlines associated with the
  170. // connection.
  171. func (c *Client) SetDeadline(t time.Time) error {
  172. return c.p.SetDeadline(t)
  173. }
  174. // SetReadDeadline sets the deadline for future raw socket read calls.
  175. // If the deadline is reached, a raw socket read will fail with a timeout
  176. // (see type net.Error) instead of blocking.
  177. // A zero value for t means a raw socket read will not time out.
  178. func (c *Client) SetReadDeadline(t time.Time) error {
  179. return c.p.SetReadDeadline(t)
  180. }
  181. // SetWriteDeadline sets the deadline for future raw socket write calls.
  182. // If the deadline is reached, a raw socket write will fail with a timeout
  183. // (see type net.Error) instead of blocking.
  184. // A zero value for t means a raw socket write will not time out.
  185. // Even if a write times out, it may return n > 0, indicating that
  186. // some of the data was successfully written.
  187. func (c *Client) SetWriteDeadline(t time.Time) error {
  188. return c.p.SetWriteDeadline(t)
  189. }
  190. // HardwareAddr fetches the hardware address for the interface associated
  191. // with the connection.
  192. func (c Client) HardwareAddr() net.HardwareAddr {
  193. return c.ifi.HardwareAddr
  194. }
  195. // firstIPv4Addr attempts to retrieve the first detected IPv4 address from an
  196. // input slice of network addresses.
  197. func firstIPv4Addr(addrs []net.Addr) (net.IP, error) {
  198. for _, a := range addrs {
  199. if a.Network() != "ip+net" {
  200. continue
  201. }
  202. ip, _, err := net.ParseCIDR(a.String())
  203. if err != nil {
  204. return nil, err
  205. }
  206. // "If ip is not an IPv4 address, To4 returns nil."
  207. // Reference: http://golang.org/pkg/net/#IP.To4
  208. if ip4 := ip.To4(); ip4 != nil {
  209. return ip4, nil
  210. }
  211. }
  212. return nil, nil
  213. }