ethernet.go 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. // Package ethernet implements marshaling and unmarshaling of IEEE 802.3
  2. // Ethernet II frames and IEEE 802.1Q VLAN tags.
  3. package ethernet
  4. import (
  5. "encoding/binary"
  6. "errors"
  7. "fmt"
  8. "hash/crc32"
  9. "io"
  10. "net"
  11. )
  12. //go:generate stringer -output=string.go -type=EtherType
  13. const (
  14. // minPayload is the minimum payload size for an Ethernet frame, assuming
  15. // that no 802.1Q VLAN tags are present.
  16. minPayload = 46
  17. )
  18. var (
  19. // Broadcast is a special hardware address which indicates a Frame should
  20. // be sent to every device on a given LAN segment.
  21. Broadcast = net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
  22. )
  23. var (
  24. // ErrInvalidFCS is returned when Frame.UnmarshalFCS detects an incorrect
  25. // Ethernet frame check sequence in a byte slice for a Frame.
  26. ErrInvalidFCS = errors.New("invalid frame check sequence")
  27. )
  28. // An EtherType is a value used to identify an upper layer protocol
  29. // encapsulated in a Frame.
  30. //
  31. // A list of IANA-assigned EtherType values may be found here:
  32. // http://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml.
  33. type EtherType uint16
  34. // Common EtherType values frequently used in a Frame.
  35. const (
  36. EtherTypeIPv4 EtherType = 0x0800
  37. EtherTypeARP EtherType = 0x0806
  38. EtherTypeIPv6 EtherType = 0x86DD
  39. // EtherTypeVLAN and EtherTypeServiceVLAN are used as 802.1Q Tag Protocol
  40. // Identifiers (TPIDs).
  41. EtherTypeVLAN EtherType = 0x8100
  42. EtherTypeServiceVLAN EtherType = 0x88a8
  43. )
  44. // A Frame is an IEEE 802.3 Ethernet II frame. A Frame contains information
  45. // such as source and destination hardware addresses, zero or more optional
  46. // 802.1Q VLAN tags, an EtherType, and payload data.
  47. type Frame struct {
  48. // Destination specifies the destination hardware address for this Frame.
  49. //
  50. // If this address is set to Broadcast, the Frame will be sent to every
  51. // device on a given LAN segment.
  52. Destination net.HardwareAddr
  53. // Source specifies the source hardware address for this Frame.
  54. //
  55. // Typically, this is the hardware address of the network interface used to
  56. // send this Frame.
  57. Source net.HardwareAddr
  58. // ServiceVLAN specifies an optional 802.1Q service VLAN tag, for use with
  59. // 802.1ad double tagging, or "Q-in-Q". If ServiceVLAN is not nil, VLAN must
  60. // not be nil as well.
  61. //
  62. // Most users should leave this field set to nil and use VLAN instead.
  63. ServiceVLAN *VLAN
  64. // VLAN specifies an optional 802.1Q customer VLAN tag, which may or may
  65. // not be present in a Frame. It is important to note that the operating
  66. // system may automatically strip VLAN tags before they can be parsed.
  67. VLAN *VLAN
  68. // EtherType is a value used to identify an upper layer protocol
  69. // encapsulated in this Frame.
  70. EtherType EtherType
  71. // Payload is a variable length data payload encapsulated by this Frame.
  72. Payload []byte
  73. }
  74. // MarshalBinary allocates a byte slice and marshals a Frame into binary form.
  75. func (f *Frame) MarshalBinary() ([]byte, error) {
  76. b := make([]byte, f.length())
  77. _, err := f.read(b)
  78. return b, err
  79. }
  80. // MarshalFCS allocates a byte slice, marshals a Frame into binary form, and
  81. // finally calculates and places a 4-byte IEEE CRC32 frame check sequence at
  82. // the end of the slice.
  83. //
  84. // Most users should use MarshalBinary instead. MarshalFCS is provided as a
  85. // convenience for rare occasions when the operating system cannot
  86. // automatically generate a frame check sequence for an Ethernet frame.
  87. func (f *Frame) MarshalFCS() ([]byte, error) {
  88. // Frame length with 4 extra bytes for frame check sequence
  89. b := make([]byte, f.length()+4)
  90. if _, err := f.read(b); err != nil {
  91. return nil, err
  92. }
  93. // Compute IEEE CRC32 checksum of frame bytes and place it directly
  94. // in the last four bytes of the slice
  95. binary.BigEndian.PutUint32(b[len(b)-4:], crc32.ChecksumIEEE(b[0:len(b)-4]))
  96. return b, nil
  97. }
  98. // read reads data from a Frame into b. read is used to marshal a Frame
  99. // into binary form, but does not allocate on its own.
  100. func (f *Frame) read(b []byte) (int, error) {
  101. // S-VLAN must also have accompanying C-VLAN.
  102. if f.ServiceVLAN != nil && f.VLAN == nil {
  103. return 0, ErrInvalidVLAN
  104. }
  105. copy(b[0:6], f.Destination)
  106. copy(b[6:12], f.Source)
  107. // Marshal each non-nil VLAN tag into bytes, inserting the appropriate
  108. // EtherType/TPID before each, so devices know that one or more VLANs
  109. // are present.
  110. vlans := []struct {
  111. vlan *VLAN
  112. tpid EtherType
  113. }{
  114. {vlan: f.ServiceVLAN, tpid: EtherTypeServiceVLAN},
  115. {vlan: f.VLAN, tpid: EtherTypeVLAN},
  116. }
  117. n := 12
  118. for _, vt := range vlans {
  119. if vt.vlan == nil {
  120. continue
  121. }
  122. // Add VLAN EtherType and VLAN bytes.
  123. binary.BigEndian.PutUint16(b[n:n+2], uint16(vt.tpid))
  124. if _, err := vt.vlan.read(b[n+2 : n+4]); err != nil {
  125. return 0, err
  126. }
  127. n += 4
  128. }
  129. // Marshal actual EtherType after any VLANs, copy payload into
  130. // output bytes.
  131. binary.BigEndian.PutUint16(b[n:n+2], uint16(f.EtherType))
  132. copy(b[n+2:], f.Payload)
  133. return len(b), nil
  134. }
  135. // UnmarshalBinary unmarshals a byte slice into a Frame.
  136. func (f *Frame) UnmarshalBinary(b []byte) error {
  137. // Verify that both hardware addresses and a single EtherType are present
  138. if len(b) < 14 {
  139. return io.ErrUnexpectedEOF
  140. }
  141. // Track offset in packet for reading data
  142. n := 14
  143. // Continue looping and parsing VLAN tags until no more VLAN EtherType
  144. // values are detected
  145. et := EtherType(binary.BigEndian.Uint16(b[n-2 : n]))
  146. switch et {
  147. case EtherTypeServiceVLAN, EtherTypeVLAN:
  148. // VLAN type is hinted for further parsing. An index is returned which
  149. // indicates how many bytes were consumed by VLAN tags.
  150. nn, err := f.unmarshalVLANs(et, b[n:])
  151. if err != nil {
  152. return err
  153. }
  154. n += nn
  155. default:
  156. // No VLANs detected.
  157. f.EtherType = et
  158. }
  159. // Allocate single byte slice to store destination and source hardware
  160. // addresses, and payload
  161. bb := make([]byte, 6+6+len(b[n:]))
  162. copy(bb[0:6], b[0:6])
  163. f.Destination = bb[0:6]
  164. copy(bb[6:12], b[6:12])
  165. f.Source = bb[6:12]
  166. // There used to be a minimum payload length restriction here, but as
  167. // long as two hardware addresses and an EtherType are present, it
  168. // doesn't really matter what is contained in the payload. We will
  169. // follow the "robustness principle".
  170. copy(bb[12:], b[n:])
  171. f.Payload = bb[12:]
  172. return nil
  173. }
  174. // UnmarshalFCS computes the IEEE CRC32 frame check sequence of a Frame,
  175. // verifies it against the checksum present in the byte slice, and finally,
  176. // unmarshals a byte slice into a Frame.
  177. //
  178. // Most users should use UnmarshalBinary instead. UnmarshalFCS is provided as
  179. // a convenience for rare occasions when the operating system cannot
  180. // automatically verify a frame check sequence for an Ethernet frame.
  181. func (f *Frame) UnmarshalFCS(b []byte) error {
  182. // Must contain enough data for FCS, to avoid panics
  183. if len(b) < 4 {
  184. return io.ErrUnexpectedEOF
  185. }
  186. // Verify checksum in slice versus newly computed checksum
  187. want := binary.BigEndian.Uint32(b[len(b)-4:])
  188. got := crc32.ChecksumIEEE(b[0 : len(b)-4])
  189. if want != got {
  190. return ErrInvalidFCS
  191. }
  192. return f.UnmarshalBinary(b[0 : len(b)-4])
  193. }
  194. // length calculates the number of bytes required to store a Frame.
  195. func (f *Frame) length() int {
  196. // If payload is less than the required minimum length, we zero-pad up to
  197. // the required minimum length
  198. pl := len(f.Payload)
  199. if pl < minPayload {
  200. pl = minPayload
  201. }
  202. // Add additional length if VLAN tags are needed.
  203. var vlanLen int
  204. switch {
  205. case f.ServiceVLAN != nil && f.VLAN != nil:
  206. vlanLen = 8
  207. case f.VLAN != nil:
  208. vlanLen = 4
  209. }
  210. // 6 bytes: destination hardware address
  211. // 6 bytes: source hardware address
  212. // N bytes: VLAN tags (if present)
  213. // 2 bytes: EtherType
  214. // N bytes: payload length (may be padded)
  215. return 6 + 6 + vlanLen + 2 + pl
  216. }
  217. // unmarshalVLANs unmarshals S/C-VLAN tags. It is assumed that tpid
  218. // is a valid S/C-VLAN TPID.
  219. func (f *Frame) unmarshalVLANs(tpid EtherType, b []byte) (int, error) {
  220. // 4 or more bytes must remain for valid S/C-VLAN tag and EtherType.
  221. if len(b) < 4 {
  222. return 0, io.ErrUnexpectedEOF
  223. }
  224. // Track how many bytes are consumed by VLAN tags.
  225. var n int
  226. switch tpid {
  227. case EtherTypeServiceVLAN:
  228. vlan := new(VLAN)
  229. if err := vlan.UnmarshalBinary(b[n : n+2]); err != nil {
  230. return 0, err
  231. }
  232. f.ServiceVLAN = vlan
  233. // Assume that a C-VLAN immediately trails an S-VLAN.
  234. if EtherType(binary.BigEndian.Uint16(b[n+2:n+4])) != EtherTypeVLAN {
  235. return 0, ErrInvalidVLAN
  236. }
  237. // 4 or more bytes must remain for valid C-VLAN tag and EtherType.
  238. n += 4
  239. if len(b[n:]) < 4 {
  240. return 0, io.ErrUnexpectedEOF
  241. }
  242. // Continue to parse the C-VLAN.
  243. fallthrough
  244. case EtherTypeVLAN:
  245. vlan := new(VLAN)
  246. if err := vlan.UnmarshalBinary(b[n : n+2]); err != nil {
  247. return 0, err
  248. }
  249. f.VLAN = vlan
  250. f.EtherType = EtherType(binary.BigEndian.Uint16(b[n+2 : n+4]))
  251. n += 4
  252. default:
  253. panic(fmt.Sprintf("unknown VLAN TPID: %04x", tpid))
  254. }
  255. return n, nil
  256. }