igmp.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. // Copyright 2012 Google, Inc. All rights reserved.
  2. // Copyright 2009-2011 Andreas Krennmair. All rights reserved.
  3. //
  4. // Use of this source code is governed by a BSD-style license
  5. // that can be found in the LICENSE file in the root of the source
  6. // tree.
  7. package layers
  8. import (
  9. "encoding/binary"
  10. "errors"
  11. "net"
  12. "time"
  13. "github.com/google/gopacket"
  14. )
  15. type IGMPType uint8
  16. const (
  17. IGMPMembershipQuery IGMPType = 0x11 // General or group specific query
  18. IGMPMembershipReportV1 IGMPType = 0x12 // Version 1 Membership Report
  19. IGMPMembershipReportV2 IGMPType = 0x16 // Version 2 Membership Report
  20. IGMPLeaveGroup IGMPType = 0x17 // Leave Group
  21. IGMPMembershipReportV3 IGMPType = 0x22 // Version 3 Membership Report
  22. )
  23. // String conversions for IGMP message types
  24. func (i IGMPType) String() string {
  25. switch i {
  26. case IGMPMembershipQuery:
  27. return "IGMP Membership Query"
  28. case IGMPMembershipReportV1:
  29. return "IGMPv1 Membership Report"
  30. case IGMPMembershipReportV2:
  31. return "IGMPv2 Membership Report"
  32. case IGMPMembershipReportV3:
  33. return "IGMPv3 Membership Report"
  34. case IGMPLeaveGroup:
  35. return "Leave Group"
  36. default:
  37. return ""
  38. }
  39. }
  40. type IGMPv3GroupRecordType uint8
  41. const (
  42. IGMPIsIn IGMPv3GroupRecordType = 0x01 // Type MODE_IS_INCLUDE, source addresses x
  43. IGMPIsEx IGMPv3GroupRecordType = 0x02 // Type MODE_IS_EXCLUDE, source addresses x
  44. IGMPToIn IGMPv3GroupRecordType = 0x03 // Type CHANGE_TO_INCLUDE_MODE, source addresses x
  45. IGMPToEx IGMPv3GroupRecordType = 0x04 // Type CHANGE_TO_EXCLUDE_MODE, source addresses x
  46. IGMPAllow IGMPv3GroupRecordType = 0x05 // Type ALLOW_NEW_SOURCES, source addresses x
  47. IGMPBlock IGMPv3GroupRecordType = 0x06 // Type BLOCK_OLD_SOURCES, source addresses x
  48. )
  49. func (i IGMPv3GroupRecordType) String() string {
  50. switch i {
  51. case IGMPIsIn:
  52. return "MODE_IS_INCLUDE"
  53. case IGMPIsEx:
  54. return "MODE_IS_EXCLUDE"
  55. case IGMPToIn:
  56. return "CHANGE_TO_INCLUDE_MODE"
  57. case IGMPToEx:
  58. return "CHANGE_TO_EXCLUDE_MODE"
  59. case IGMPAllow:
  60. return "ALLOW_NEW_SOURCES"
  61. case IGMPBlock:
  62. return "BLOCK_OLD_SOURCES"
  63. default:
  64. return ""
  65. }
  66. }
  67. // IGMP represents an IGMPv3 message.
  68. type IGMP struct {
  69. BaseLayer
  70. Type IGMPType
  71. MaxResponseTime time.Duration
  72. Checksum uint16
  73. GroupAddress net.IP
  74. SupressRouterProcessing bool
  75. RobustnessValue uint8
  76. IntervalTime time.Duration
  77. SourceAddresses []net.IP
  78. NumberOfGroupRecords uint16
  79. NumberOfSources uint16
  80. GroupRecords []IGMPv3GroupRecord
  81. Version uint8 // IGMP protocol version
  82. }
  83. // IGMPv1or2 stores header details for an IGMPv1 or IGMPv2 packet.
  84. //
  85. // 0 1 2 3
  86. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  87. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  88. // | Type | Max Resp Time | Checksum |
  89. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  90. // | Group Address |
  91. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  92. type IGMPv1or2 struct {
  93. BaseLayer
  94. Type IGMPType // IGMP message type
  95. MaxResponseTime time.Duration // meaningful only in Membership Query messages
  96. Checksum uint16 // 16-bit checksum of entire ip payload
  97. GroupAddress net.IP // either 0 or an IP multicast address
  98. Version uint8
  99. }
  100. // decodeResponse dissects IGMPv1 or IGMPv2 packet.
  101. func (i *IGMPv1or2) decodeResponse(data []byte) error {
  102. if len(data) < 8 {
  103. return errors.New("IGMP packet too small")
  104. }
  105. i.MaxResponseTime = igmpTimeDecode(data[1])
  106. i.Checksum = binary.BigEndian.Uint16(data[2:4])
  107. i.GroupAddress = net.IP(data[4:8])
  108. return nil
  109. }
  110. // 0 1 2 3
  111. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  112. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  113. // | Type = 0x22 | Reserved | Checksum |
  114. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  115. // | Reserved | Number of Group Records (M) |
  116. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  117. // | |
  118. // . Group Record [1] .
  119. // | |
  120. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  121. // | |
  122. // . Group Record [2] .
  123. // | |
  124. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  125. // | |
  126. // . Group Record [M] .
  127. // | |
  128. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  129. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  130. // | Record Type | Aux Data Len | Number of Sources (N) |
  131. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  132. // | Multicast Address |
  133. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  134. // | Source Address [1] |
  135. // +- -+
  136. // | Source Address [2] |
  137. // +- -+
  138. // | Source Address [N] |
  139. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  140. // | |
  141. // . Auxiliary Data .
  142. // | |
  143. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  144. // IGMPv3GroupRecord stores individual group records for a V3 Membership Report message.
  145. type IGMPv3GroupRecord struct {
  146. Type IGMPv3GroupRecordType
  147. AuxDataLen uint8 // this should always be 0 as per IGMPv3 spec.
  148. NumberOfSources uint16
  149. MulticastAddress net.IP
  150. SourceAddresses []net.IP
  151. AuxData uint32 // NOT USED
  152. }
  153. func (i *IGMP) decodeIGMPv3MembershipReport(data []byte) error {
  154. if len(data) < 8 {
  155. return errors.New("IGMPv3 Membership Report too small #1")
  156. }
  157. i.Checksum = binary.BigEndian.Uint16(data[2:4])
  158. i.NumberOfGroupRecords = binary.BigEndian.Uint16(data[6:8])
  159. recordOffset := 8
  160. for j := 0; j < int(i.NumberOfGroupRecords); j++ {
  161. if len(data) < recordOffset+8 {
  162. return errors.New("IGMPv3 Membership Report too small #2")
  163. }
  164. var gr IGMPv3GroupRecord
  165. gr.Type = IGMPv3GroupRecordType(data[recordOffset])
  166. gr.AuxDataLen = data[recordOffset+1]
  167. gr.NumberOfSources = binary.BigEndian.Uint16(data[recordOffset+2 : recordOffset+4])
  168. gr.MulticastAddress = net.IP(data[recordOffset+4 : recordOffset+8])
  169. if len(data) < recordOffset+8+int(gr.NumberOfSources)*4 {
  170. return errors.New("IGMPv3 Membership Report too small #3")
  171. }
  172. // append source address records.
  173. for i := 0; i < int(gr.NumberOfSources); i++ {
  174. sourceAddr := net.IP(data[recordOffset+8+i*4 : recordOffset+12+i*4])
  175. gr.SourceAddresses = append(gr.SourceAddresses, sourceAddr)
  176. }
  177. i.GroupRecords = append(i.GroupRecords, gr)
  178. recordOffset += 8 + 4*int(gr.NumberOfSources)
  179. }
  180. return nil
  181. }
  182. // 0 1 2 3
  183. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  184. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  185. // | Type = 0x11 | Max Resp Code | Checksum |
  186. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  187. // | Group Address |
  188. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  189. // | Resv |S| QRV | QQIC | Number of Sources (N) |
  190. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  191. // | Source Address [1] |
  192. // +- -+
  193. // | Source Address [2] |
  194. // +- . -+
  195. // | Source Address [N] |
  196. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  197. //
  198. // decodeIGMPv3MembershipQuery parses the IGMPv3 message of type 0x11
  199. func (i *IGMP) decodeIGMPv3MembershipQuery(data []byte) error {
  200. if len(data) < 12 {
  201. return errors.New("IGMPv3 Membership Query too small #1")
  202. }
  203. i.MaxResponseTime = igmpTimeDecode(data[1])
  204. i.Checksum = binary.BigEndian.Uint16(data[2:4])
  205. i.SupressRouterProcessing = data[8]&0x8 != 0
  206. i.GroupAddress = net.IP(data[4:8])
  207. i.RobustnessValue = data[8] & 0x7
  208. i.IntervalTime = igmpTimeDecode(data[9])
  209. i.NumberOfSources = binary.BigEndian.Uint16(data[10:12])
  210. if len(data) < 12+int(i.NumberOfSources)*4 {
  211. return errors.New("IGMPv3 Membership Query too small #2")
  212. }
  213. for j := 0; j < int(i.NumberOfSources); j++ {
  214. i.SourceAddresses = append(i.SourceAddresses, net.IP(data[12+j*4:16+j*4]))
  215. }
  216. return nil
  217. }
  218. // igmpTimeDecode decodes the duration created by the given byte, using the
  219. // algorithm in http://www.rfc-base.org/txt/rfc-3376.txt section 4.1.1.
  220. func igmpTimeDecode(t uint8) time.Duration {
  221. if t&0x80 == 0 {
  222. return time.Millisecond * 100 * time.Duration(t)
  223. }
  224. mant := (t & 0x70) >> 4
  225. exp := t & 0x0F
  226. return time.Millisecond * 100 * time.Duration((mant|0x10)<<(exp+3))
  227. }
  228. // LayerType returns LayerTypeIGMP for the V1,2,3 message protocol formats.
  229. func (i *IGMP) LayerType() gopacket.LayerType { return LayerTypeIGMP }
  230. func (i *IGMPv1or2) LayerType() gopacket.LayerType { return LayerTypeIGMP }
  231. func (i *IGMPv1or2) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
  232. if len(data) < 8 {
  233. return errors.New("IGMP Packet too small")
  234. }
  235. i.Type = IGMPType(data[0])
  236. i.MaxResponseTime = igmpTimeDecode(data[1])
  237. i.Checksum = binary.BigEndian.Uint16(data[2:4])
  238. i.GroupAddress = net.IP(data[4:8])
  239. return nil
  240. }
  241. func (i *IGMPv1or2) NextLayerType() gopacket.LayerType {
  242. return gopacket.LayerTypeZero
  243. }
  244. func (i *IGMPv1or2) CanDecode() gopacket.LayerClass {
  245. return LayerTypeIGMP
  246. }
  247. // DecodeFromBytes decodes the given bytes into this layer.
  248. func (i *IGMP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
  249. if len(data) < 1 {
  250. return errors.New("IGMP packet is too small")
  251. }
  252. // common IGMP header values between versions 1..3 of IGMP specification..
  253. i.Type = IGMPType(data[0])
  254. switch i.Type {
  255. case IGMPMembershipQuery:
  256. i.decodeIGMPv3MembershipQuery(data)
  257. case IGMPMembershipReportV3:
  258. i.decodeIGMPv3MembershipReport(data)
  259. default:
  260. return errors.New("unsupported IGMP type")
  261. }
  262. return nil
  263. }
  264. // CanDecode returns the set of layer types that this DecodingLayer can decode.
  265. func (i *IGMP) CanDecode() gopacket.LayerClass {
  266. return LayerTypeIGMP
  267. }
  268. // NextLayerType returns the layer type contained by this DecodingLayer.
  269. func (i *IGMP) NextLayerType() gopacket.LayerType {
  270. return gopacket.LayerTypeZero
  271. }
  272. // decodeIGMP will parse IGMP v1,2 or 3 protocols. Checks against the
  273. // IGMP type are performed against byte[0], logic then iniitalizes and
  274. // passes the appropriate struct (IGMP or IGMPv1or2) to
  275. // decodingLayerDecoder.
  276. func decodeIGMP(data []byte, p gopacket.PacketBuilder) error {
  277. if len(data) < 1 {
  278. return errors.New("IGMP packet is too small")
  279. }
  280. // byte 0 contains IGMP message type.
  281. switch IGMPType(data[0]) {
  282. case IGMPMembershipQuery:
  283. // IGMPv3 Membership Query payload is >= 12
  284. if len(data) >= 12 {
  285. i := &IGMP{Version: 3}
  286. return decodingLayerDecoder(i, data, p)
  287. } else if len(data) == 8 {
  288. i := &IGMPv1or2{}
  289. if data[1] == 0x00 {
  290. i.Version = 1 // IGMPv1 has a query length of 8 and MaxResp = 0
  291. } else {
  292. i.Version = 2 // IGMPv2 has a query length of 8 and MaxResp != 0
  293. }
  294. return decodingLayerDecoder(i, data, p)
  295. }
  296. case IGMPMembershipReportV3:
  297. i := &IGMP{Version: 3}
  298. return decodingLayerDecoder(i, data, p)
  299. case IGMPMembershipReportV1:
  300. i := &IGMPv1or2{Version: 1}
  301. return decodingLayerDecoder(i, data, p)
  302. case IGMPLeaveGroup, IGMPMembershipReportV2:
  303. // leave group and Query Report v2 used in IGMPv2 only.
  304. i := &IGMPv1or2{Version: 2}
  305. return decodingLayerDecoder(i, data, p)
  306. default:
  307. }
  308. return errors.New("Unable to determine IGMP type.")
  309. }