flows.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. // Copyright 2012 Google, Inc. All rights reserved.
  2. //
  3. // Use of this source code is governed by a BSD-style license
  4. // that can be found in the LICENSE file in the root of the source
  5. // tree.
  6. package gopacket
  7. import (
  8. "bytes"
  9. "fmt"
  10. "strconv"
  11. )
  12. // MaxEndpointSize determines the maximum size in bytes of an endpoint address.
  13. //
  14. // Endpoints/Flows have a problem: They need to be hashable. Therefore, they
  15. // can't use a byte slice. The two obvious choices are to use a string or a
  16. // byte array. Strings work great, but string creation requires memory
  17. // allocation, which can be slow. Arrays work great, but have a fixed size. We
  18. // originally used the former, now we've switched to the latter. Use of a fixed
  19. // byte-array doubles the speed of constructing a flow (due to not needing to
  20. // allocate). This is a huge increase... too much for us to pass up.
  21. //
  22. // The end result of this, though, is that an endpoint/flow can't be created
  23. // using more than MaxEndpointSize bytes per address.
  24. const MaxEndpointSize = 16
  25. // Endpoint is the set of bytes used to address packets at various layers.
  26. // See LinkLayer, NetworkLayer, and TransportLayer specifications.
  27. // Endpoints are usable as map keys.
  28. type Endpoint struct {
  29. typ EndpointType
  30. len int
  31. raw [MaxEndpointSize]byte
  32. }
  33. // EndpointType returns the endpoint type associated with this endpoint.
  34. func (a Endpoint) EndpointType() EndpointType { return a.typ }
  35. // Raw returns the raw bytes of this endpoint. These aren't human-readable
  36. // most of the time, but they are faster than calling String.
  37. func (a Endpoint) Raw() []byte { return a.raw[:a.len] }
  38. // LessThan provides a stable ordering for all endpoints. It sorts first based
  39. // on the EndpointType of an endpoint, then based on the raw bytes of that
  40. // endpoint.
  41. //
  42. // For some endpoints, the actual comparison may not make sense, however this
  43. // ordering does provide useful information for most Endpoint types.
  44. // Ordering is based first on endpoint type, then on raw endpoint bytes.
  45. // Endpoint bytes are sorted lexigraphically.
  46. func (a Endpoint) LessThan(b Endpoint) bool {
  47. return a.typ < b.typ || (a.typ == b.typ && bytes.Compare(a.raw[:a.len], b.raw[:b.len]) < 0)
  48. }
  49. // fnvHash is used by our FastHash functions, and implements the FNV hash
  50. // created by Glenn Fowler, Landon Curt Noll, and Phong Vo.
  51. // See http://isthe.com/chongo/tech/comp/fnv/.
  52. func fnvHash(s []byte) (h uint64) {
  53. h = fnvBasis
  54. for i := 0; i < len(s); i++ {
  55. h ^= uint64(s[i])
  56. h *= fnvPrime
  57. }
  58. return
  59. }
  60. const fnvBasis = 14695981039346656037
  61. const fnvPrime = 1099511628211
  62. // FastHash provides a quick hashing function for an endpoint, useful if you'd
  63. // like to split up endpoints by modulos or other load-balancing techniques.
  64. // It uses a variant of Fowler-Noll-Vo hashing.
  65. //
  66. // The output of FastHash is not guaranteed to remain the same through future
  67. // code revisions, so should not be used to key values in persistent storage.
  68. func (a Endpoint) FastHash() (h uint64) {
  69. h = fnvHash(a.raw[:a.len])
  70. h ^= uint64(a.typ)
  71. h *= fnvPrime
  72. return
  73. }
  74. // NewEndpoint creates a new Endpoint object.
  75. //
  76. // The size of raw must be less than MaxEndpointSize, otherwise this function
  77. // will panic.
  78. func NewEndpoint(typ EndpointType, raw []byte) (e Endpoint) {
  79. e.len = len(raw)
  80. if e.len > MaxEndpointSize {
  81. panic("raw byte length greater than MaxEndpointSize")
  82. }
  83. e.typ = typ
  84. copy(e.raw[:], raw)
  85. return
  86. }
  87. // EndpointTypeMetadata is used to register a new endpoint type.
  88. type EndpointTypeMetadata struct {
  89. // Name is the string returned by an EndpointType's String function.
  90. Name string
  91. // Formatter is called from an Endpoint's String function to format the raw
  92. // bytes in an Endpoint into a human-readable string.
  93. Formatter func([]byte) string
  94. }
  95. // EndpointType is the type of a gopacket Endpoint. This type determines how
  96. // the bytes stored in the endpoint should be interpreted.
  97. type EndpointType int64
  98. var endpointTypes = map[EndpointType]EndpointTypeMetadata{}
  99. // RegisterEndpointType creates a new EndpointType and registers it globally.
  100. // It MUST be passed a unique number, or it will panic. Numbers 0-999 are
  101. // reserved for gopacket's use.
  102. func RegisterEndpointType(num int, meta EndpointTypeMetadata) EndpointType {
  103. t := EndpointType(num)
  104. if _, ok := endpointTypes[t]; ok {
  105. panic("Endpoint type number already in use")
  106. }
  107. endpointTypes[t] = meta
  108. return t
  109. }
  110. func (e EndpointType) String() string {
  111. if t, ok := endpointTypes[e]; ok {
  112. return t.Name
  113. }
  114. return strconv.Itoa(int(e))
  115. }
  116. func (a Endpoint) String() string {
  117. if t, ok := endpointTypes[a.typ]; ok && t.Formatter != nil {
  118. return t.Formatter(a.raw[:a.len])
  119. }
  120. return fmt.Sprintf("%v:%v", a.typ, a.raw)
  121. }
  122. // Flow represents the direction of traffic for a packet layer, as a source and destination Endpoint.
  123. // Flows are usable as map keys.
  124. type Flow struct {
  125. typ EndpointType
  126. slen, dlen int
  127. src, dst [MaxEndpointSize]byte
  128. }
  129. // FlowFromEndpoints creates a new flow by pasting together two endpoints.
  130. // The endpoints must have the same EndpointType, or this function will return
  131. // an error.
  132. func FlowFromEndpoints(src, dst Endpoint) (_ Flow, err error) {
  133. if src.typ != dst.typ {
  134. err = fmt.Errorf("Mismatched endpoint types: %v->%v", src.typ, dst.typ)
  135. return
  136. }
  137. return Flow{src.typ, src.len, dst.len, src.raw, dst.raw}, nil
  138. }
  139. // FastHash provides a quick hashing function for a flow, useful if you'd
  140. // like to split up flows by modulos or other load-balancing techniques.
  141. // It uses a variant of Fowler-Noll-Vo hashing, and is guaranteed to collide
  142. // with its reverse flow. IE: the flow A->B will have the same hash as the flow
  143. // B->A.
  144. //
  145. // The output of FastHash is not guaranteed to remain the same through future
  146. // code revisions, so should not be used to key values in persistent storage.
  147. func (f Flow) FastHash() (h uint64) {
  148. // This combination must be commutative. We don't use ^, since that would
  149. // give the same hash for all A->A flows.
  150. h = fnvHash(f.src[:f.slen]) + fnvHash(f.dst[:f.dlen])
  151. h ^= uint64(f.typ)
  152. h *= fnvPrime
  153. return
  154. }
  155. // String returns a human-readable representation of this flow, in the form
  156. // "Src->Dst"
  157. func (f Flow) String() string {
  158. s, d := f.Endpoints()
  159. return fmt.Sprintf("%v->%v", s, d)
  160. }
  161. // EndpointType returns the EndpointType for this Flow.
  162. func (f Flow) EndpointType() EndpointType {
  163. return f.typ
  164. }
  165. // Endpoints returns the two Endpoints for this flow.
  166. func (f Flow) Endpoints() (src, dst Endpoint) {
  167. return Endpoint{f.typ, f.slen, f.src}, Endpoint{f.typ, f.dlen, f.dst}
  168. }
  169. // Src returns the source Endpoint for this flow.
  170. func (f Flow) Src() (src Endpoint) {
  171. src, _ = f.Endpoints()
  172. return
  173. }
  174. // Dst returns the destination Endpoint for this flow.
  175. func (f Flow) Dst() (dst Endpoint) {
  176. _, dst = f.Endpoints()
  177. return
  178. }
  179. // Reverse returns a new flow with endpoints reversed.
  180. func (f Flow) Reverse() Flow {
  181. return Flow{f.typ, f.dlen, f.slen, f.dst, f.src}
  182. }
  183. // NewFlow creates a new flow.
  184. //
  185. // src and dst must have length <= MaxEndpointSize, otherwise NewFlow will
  186. // panic.
  187. func NewFlow(t EndpointType, src, dst []byte) (f Flow) {
  188. f.slen = len(src)
  189. f.dlen = len(dst)
  190. if f.slen > MaxEndpointSize || f.dlen > MaxEndpointSize {
  191. panic("flow raw byte length greater than MaxEndpointSize")
  192. }
  193. f.typ = t
  194. copy(f.src[:], src)
  195. copy(f.dst[:], dst)
  196. return
  197. }
  198. // EndpointInvalid is an endpoint type used for invalid endpoints, IE endpoints
  199. // that are specified incorrectly during creation.
  200. var EndpointInvalid = RegisterEndpointType(0, EndpointTypeMetadata{Name: "invalid", Formatter: func(b []byte) string {
  201. return fmt.Sprintf("%v", b)
  202. }})
  203. // InvalidEndpoint is a singleton Endpoint of type EndpointInvalid.
  204. var InvalidEndpoint = NewEndpoint(EndpointInvalid, nil)
  205. // InvalidFlow is a singleton Flow of type EndpointInvalid.
  206. var InvalidFlow = NewFlow(EndpointInvalid, nil, nil)