packet.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. package arp
  2. import (
  3. "encoding/binary"
  4. "errors"
  5. "io"
  6. "net"
  7. "github.com/mdlayher/ethernet"
  8. )
  9. var (
  10. // ErrInvalidHardwareAddr is returned when one or more invalid hardware
  11. // addresses are passed to NewPacket.
  12. ErrInvalidHardwareAddr = errors.New("invalid hardware address")
  13. // ErrInvalidIP is returned when one or more invalid IPv4 addresses are
  14. // passed to NewPacket.
  15. ErrInvalidIP = errors.New("invalid IPv4 address")
  16. // errInvalidARPPacket is returned when an ethernet frame does not
  17. // indicate that an ARP packet is contained in its payload.
  18. errInvalidARPPacket = errors.New("invalid ARP packet")
  19. )
  20. //go:generate stringer -output=string.go -type=Operation
  21. // An Operation is an ARP operation, such as request or reply.
  22. type Operation uint16
  23. // Operation constants which indicate an ARP request or reply.
  24. const (
  25. OperationRequest Operation = 1
  26. OperationReply Operation = 2
  27. )
  28. // A Packet is a raw ARP packet, as described in RFC 826.
  29. type Packet struct {
  30. // HardwareType specifies an IANA-assigned hardware type, as described
  31. // in RFC 826.
  32. HardwareType uint16
  33. // ProtocolType specifies the internetwork protocol for which the ARP
  34. // request is intended. Typically, this is the IPv4 EtherType.
  35. ProtocolType uint16
  36. // HardwareAddrLength specifies the length of the sender and target
  37. // hardware addresses included in a Packet.
  38. HardwareAddrLength uint8
  39. // IPLength specifies the length of the sender and target IPv4 addresses
  40. // included in a Packet.
  41. IPLength uint8
  42. // Operation specifies the ARP operation being performed, such as request
  43. // or reply.
  44. Operation Operation
  45. // SenderHardwareAddr specifies the hardware address of the sender of this
  46. // Packet.
  47. SenderHardwareAddr net.HardwareAddr
  48. // SenderIP specifies the IPv4 address of the sender of this Packet.
  49. SenderIP net.IP
  50. // TargetHardwareAddr specifies the hardware address of the target of this
  51. // Packet.
  52. TargetHardwareAddr net.HardwareAddr
  53. // TargetIP specifies the IPv4 address of the target of this Packet.
  54. TargetIP net.IP
  55. }
  56. // NewPacket creates a new Packet from an input Operation and hardware/IPv4
  57. // address values for both a sender and target.
  58. //
  59. // If either hardware address is less than 6 bytes in length, or there is a
  60. // length mismatch between the two, ErrInvalidHardwareAddr is returned.
  61. //
  62. // If either IP address is not an IPv4 address, or there is a length mismatch
  63. // between the two, ErrInvalidIP is returned.
  64. func NewPacket(op Operation, srcHW net.HardwareAddr, srcIP net.IP, dstHW net.HardwareAddr, dstIP net.IP) (*Packet, error) {
  65. // Validate hardware addresses for minimum length, and matching length
  66. if len(srcHW) < 6 {
  67. return nil, ErrInvalidHardwareAddr
  68. }
  69. if len(dstHW) < 6 {
  70. return nil, ErrInvalidHardwareAddr
  71. }
  72. if len(srcHW) != len(dstHW) {
  73. return nil, ErrInvalidHardwareAddr
  74. }
  75. // Validate IP addresses to ensure they are IPv4 addresses, and
  76. // correct length
  77. srcIP = srcIP.To4()
  78. if srcIP == nil {
  79. return nil, ErrInvalidIP
  80. }
  81. dstIP = dstIP.To4()
  82. if dstIP == nil {
  83. return nil, ErrInvalidIP
  84. }
  85. return &Packet{
  86. // There is no Go-native way to detect hardware type of a network
  87. // interface, so default to 1 (ethernet 10Mb) for now
  88. HardwareType: 1,
  89. // Default to EtherType for IPv4
  90. ProtocolType: uint16(ethernet.EtherTypeIPv4),
  91. // Populate other fields using input data
  92. HardwareAddrLength: uint8(len(srcHW)),
  93. IPLength: uint8(len(srcIP)),
  94. Operation: op,
  95. SenderHardwareAddr: srcHW,
  96. SenderIP: srcIP,
  97. TargetHardwareAddr: dstHW,
  98. TargetIP: dstIP,
  99. }, nil
  100. }
  101. // MarshalBinary allocates a byte slice containing the data from a Packet.
  102. //
  103. // MarshalBinary never returns an error.
  104. func (p *Packet) MarshalBinary() ([]byte, error) {
  105. // 2 bytes: hardware type
  106. // 2 bytes: protocol type
  107. // 1 byte : hardware address length
  108. // 1 byte : protocol length
  109. // 2 bytes: operation
  110. // N bytes: source hardware address
  111. // N bytes: source protocol address
  112. // N bytes: target hardware address
  113. // N bytes: target protocol address
  114. // Though an IPv4 address should always 4 bytes, go-fuzz
  115. // very quickly created several crasher scenarios which
  116. // indicated that these values can lie.
  117. b := make([]byte, 2+2+1+1+2+(p.IPLength*2)+(p.HardwareAddrLength*2))
  118. // Marshal fixed length data
  119. binary.BigEndian.PutUint16(b[0:2], p.HardwareType)
  120. binary.BigEndian.PutUint16(b[2:4], p.ProtocolType)
  121. b[4] = p.HardwareAddrLength
  122. b[5] = p.IPLength
  123. binary.BigEndian.PutUint16(b[6:8], uint16(p.Operation))
  124. // Marshal variable length data at correct offset using lengths
  125. // defined in p
  126. n := 8
  127. hal := int(p.HardwareAddrLength)
  128. pl := int(p.IPLength)
  129. copy(b[n:n+hal], p.SenderHardwareAddr)
  130. n += hal
  131. copy(b[n:n+pl], p.SenderIP)
  132. n += pl
  133. copy(b[n:n+hal], p.TargetHardwareAddr)
  134. n += hal
  135. copy(b[n:n+pl], p.TargetIP)
  136. return b, nil
  137. }
  138. // UnmarshalBinary unmarshals a raw byte slice into a Packet.
  139. func (p *Packet) UnmarshalBinary(b []byte) error {
  140. // Must have enough room to retrieve hardware address and IP lengths
  141. if len(b) < 8 {
  142. return io.ErrUnexpectedEOF
  143. }
  144. // Retrieve fixed length data
  145. p.HardwareType = binary.BigEndian.Uint16(b[0:2])
  146. p.ProtocolType = binary.BigEndian.Uint16(b[2:4])
  147. p.HardwareAddrLength = b[4]
  148. p.IPLength = b[5]
  149. p.Operation = Operation(binary.BigEndian.Uint16(b[6:8]))
  150. // Unmarshal variable length data at correct offset using lengths
  151. // defined by ml and il
  152. //
  153. // These variables are meant to improve readability of offset calculations
  154. // for the code below
  155. n := 8
  156. ml := int(p.HardwareAddrLength)
  157. ml2 := ml * 2
  158. il := int(p.IPLength)
  159. il2 := il * 2
  160. // Must have enough room to retrieve both hardware address and IP addresses
  161. addrl := n + ml2 + il2
  162. if len(b) < addrl {
  163. return io.ErrUnexpectedEOF
  164. }
  165. // Allocate single byte slice to store address information, which
  166. // is resliced into fields
  167. bb := make([]byte, addrl-n)
  168. // Sender hardware address
  169. copy(bb[0:ml], b[n:n+ml])
  170. p.SenderHardwareAddr = bb[0:ml]
  171. n += ml
  172. // Sender IP address
  173. copy(bb[ml:ml+il], b[n:n+il])
  174. p.SenderIP = bb[ml : ml+il]
  175. n += il
  176. // Target hardware address
  177. copy(bb[ml+il:ml2+il], b[n:n+ml])
  178. p.TargetHardwareAddr = bb[ml+il : ml2+il]
  179. n += ml
  180. // Target IP address
  181. copy(bb[ml2+il:ml2+il2], b[n:n+il])
  182. p.TargetIP = bb[ml2+il : ml2+il2]
  183. return nil
  184. }
  185. func parsePacket(buf []byte) (*Packet, *ethernet.Frame, error) {
  186. f := new(ethernet.Frame)
  187. if err := f.UnmarshalBinary(buf); err != nil {
  188. return nil, nil, err
  189. }
  190. // Ignore frames which do not have ARP EtherType
  191. if f.EtherType != ethernet.EtherTypeARP {
  192. return nil, nil, errInvalidARPPacket
  193. }
  194. p := new(Packet)
  195. if err := p.UnmarshalBinary(f.Payload); err != nil {
  196. return nil, nil, err
  197. }
  198. return p, f, nil
  199. }