aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/google/gopacket/layers/igmp.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/google/gopacket/layers/igmp.go')
-rw-r--r--vendor/github.com/google/gopacket/layers/igmp.go355
1 files changed, 355 insertions, 0 deletions
diff --git a/vendor/github.com/google/gopacket/layers/igmp.go b/vendor/github.com/google/gopacket/layers/igmp.go
new file mode 100644
index 0000000..d008415
--- /dev/null
+++ b/vendor/github.com/google/gopacket/layers/igmp.go
@@ -0,0 +1,355 @@
+// Copyright 2012 Google, Inc. All rights reserved.
+// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file in the root of the source
+// tree.
+
+package layers
+
+import (
+ "encoding/binary"
+ "errors"
+ "net"
+ "time"
+
+ "github.com/google/gopacket"
+)
+
+type IGMPType uint8
+
+const (
+ IGMPMembershipQuery IGMPType = 0x11 // General or group specific query
+ IGMPMembershipReportV1 IGMPType = 0x12 // Version 1 Membership Report
+ IGMPMembershipReportV2 IGMPType = 0x16 // Version 2 Membership Report
+ IGMPLeaveGroup IGMPType = 0x17 // Leave Group
+ IGMPMembershipReportV3 IGMPType = 0x22 // Version 3 Membership Report
+)
+
+// String conversions for IGMP message types
+func (i IGMPType) String() string {
+ switch i {
+ case IGMPMembershipQuery:
+ return "IGMP Membership Query"
+ case IGMPMembershipReportV1:
+ return "IGMPv1 Membership Report"
+ case IGMPMembershipReportV2:
+ return "IGMPv2 Membership Report"
+ case IGMPMembershipReportV3:
+ return "IGMPv3 Membership Report"
+ case IGMPLeaveGroup:
+ return "Leave Group"
+ default:
+ return ""
+ }
+}
+
+type IGMPv3GroupRecordType uint8
+
+const (
+ IGMPIsIn IGMPv3GroupRecordType = 0x01 // Type MODE_IS_INCLUDE, source addresses x
+ IGMPIsEx IGMPv3GroupRecordType = 0x02 // Type MODE_IS_EXCLUDE, source addresses x
+ IGMPToIn IGMPv3GroupRecordType = 0x03 // Type CHANGE_TO_INCLUDE_MODE, source addresses x
+ IGMPToEx IGMPv3GroupRecordType = 0x04 // Type CHANGE_TO_EXCLUDE_MODE, source addresses x
+ IGMPAllow IGMPv3GroupRecordType = 0x05 // Type ALLOW_NEW_SOURCES, source addresses x
+ IGMPBlock IGMPv3GroupRecordType = 0x06 // Type BLOCK_OLD_SOURCES, source addresses x
+)
+
+func (i IGMPv3GroupRecordType) String() string {
+ switch i {
+ case IGMPIsIn:
+ return "MODE_IS_INCLUDE"
+ case IGMPIsEx:
+ return "MODE_IS_EXCLUDE"
+ case IGMPToIn:
+ return "CHANGE_TO_INCLUDE_MODE"
+ case IGMPToEx:
+ return "CHANGE_TO_EXCLUDE_MODE"
+ case IGMPAllow:
+ return "ALLOW_NEW_SOURCES"
+ case IGMPBlock:
+ return "BLOCK_OLD_SOURCES"
+ default:
+ return ""
+ }
+}
+
+// IGMP represents an IGMPv3 message.
+type IGMP struct {
+ BaseLayer
+ Type IGMPType
+ MaxResponseTime time.Duration
+ Checksum uint16
+ GroupAddress net.IP
+ SupressRouterProcessing bool
+ RobustnessValue uint8
+ IntervalTime time.Duration
+ SourceAddresses []net.IP
+ NumberOfGroupRecords uint16
+ NumberOfSources uint16
+ GroupRecords []IGMPv3GroupRecord
+ Version uint8 // IGMP protocol version
+}
+
+// IGMPv1or2 stores header details for an IGMPv1 or IGMPv2 packet.
+//
+// 0 1 2 3
+// 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
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Type | Max Resp Time | Checksum |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Group Address |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+type IGMPv1or2 struct {
+ BaseLayer
+ Type IGMPType // IGMP message type
+ MaxResponseTime time.Duration // meaningful only in Membership Query messages
+ Checksum uint16 // 16-bit checksum of entire ip payload
+ GroupAddress net.IP // either 0 or an IP multicast address
+ Version uint8
+}
+
+// decodeResponse dissects IGMPv1 or IGMPv2 packet.
+func (i *IGMPv1or2) decodeResponse(data []byte) error {
+ if len(data) < 8 {
+ return errors.New("IGMP packet too small")
+ }
+
+ i.MaxResponseTime = igmpTimeDecode(data[1])
+ i.Checksum = binary.BigEndian.Uint16(data[2:4])
+ i.GroupAddress = net.IP(data[4:8])
+
+ return nil
+}
+
+// 0 1 2 3
+// 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
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Type = 0x22 | Reserved | Checksum |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Reserved | Number of Group Records (M) |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | |
+// . Group Record [1] .
+// | |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | |
+// . Group Record [2] .
+// | |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | |
+// . Group Record [M] .
+// | |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Record Type | Aux Data Len | Number of Sources (N) |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Multicast Address |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Source Address [1] |
+// +- -+
+// | Source Address [2] |
+// +- -+
+// | Source Address [N] |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | |
+// . Auxiliary Data .
+// | |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+// IGMPv3GroupRecord stores individual group records for a V3 Membership Report message.
+type IGMPv3GroupRecord struct {
+ Type IGMPv3GroupRecordType
+ AuxDataLen uint8 // this should always be 0 as per IGMPv3 spec.
+ NumberOfSources uint16
+ MulticastAddress net.IP
+ SourceAddresses []net.IP
+ AuxData uint32 // NOT USED
+}
+
+func (i *IGMP) decodeIGMPv3MembershipReport(data []byte) error {
+ if len(data) < 8 {
+ return errors.New("IGMPv3 Membership Report too small #1")
+ }
+
+ i.Checksum = binary.BigEndian.Uint16(data[2:4])
+ i.NumberOfGroupRecords = binary.BigEndian.Uint16(data[6:8])
+
+ recordOffset := 8
+ for j := 0; j < int(i.NumberOfGroupRecords); j++ {
+ if len(data) < recordOffset+8 {
+ return errors.New("IGMPv3 Membership Report too small #2")
+ }
+
+ var gr IGMPv3GroupRecord
+ gr.Type = IGMPv3GroupRecordType(data[recordOffset])
+ gr.AuxDataLen = data[recordOffset+1]
+ gr.NumberOfSources = binary.BigEndian.Uint16(data[recordOffset+2 : recordOffset+4])
+ gr.MulticastAddress = net.IP(data[recordOffset+4 : recordOffset+8])
+
+ if len(data) < recordOffset+8+int(gr.NumberOfSources)*4 {
+ return errors.New("IGMPv3 Membership Report too small #3")
+ }
+
+ // append source address records.
+ for i := 0; i < int(gr.NumberOfSources); i++ {
+ sourceAddr := net.IP(data[recordOffset+8+i*4 : recordOffset+12+i*4])
+ gr.SourceAddresses = append(gr.SourceAddresses, sourceAddr)
+ }
+
+ i.GroupRecords = append(i.GroupRecords, gr)
+ recordOffset += 8 + 4*int(gr.NumberOfSources)
+ }
+ return nil
+}
+
+// 0 1 2 3
+// 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
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Type = 0x11 | Max Resp Code | Checksum |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Group Address |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Resv |S| QRV | QQIC | Number of Sources (N) |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Source Address [1] |
+// +- -+
+// | Source Address [2] |
+// +- . -+
+// | Source Address [N] |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+// decodeIGMPv3MembershipQuery parses the IGMPv3 message of type 0x11
+func (i *IGMP) decodeIGMPv3MembershipQuery(data []byte) error {
+ if len(data) < 12 {
+ return errors.New("IGMPv3 Membership Query too small #1")
+ }
+
+ i.MaxResponseTime = igmpTimeDecode(data[1])
+ i.Checksum = binary.BigEndian.Uint16(data[2:4])
+ i.SupressRouterProcessing = data[8]&0x8 != 0
+ i.GroupAddress = net.IP(data[4:8])
+ i.RobustnessValue = data[8] & 0x7
+ i.IntervalTime = igmpTimeDecode(data[9])
+ i.NumberOfSources = binary.BigEndian.Uint16(data[10:12])
+
+ if len(data) < 12+int(i.NumberOfSources)*4 {
+ return errors.New("IGMPv3 Membership Query too small #2")
+ }
+
+ for j := 0; j < int(i.NumberOfSources); j++ {
+ i.SourceAddresses = append(i.SourceAddresses, net.IP(data[12+j*4:16+j*4]))
+ }
+
+ return nil
+}
+
+// igmpTimeDecode decodes the duration created by the given byte, using the
+// algorithm in http://www.rfc-base.org/txt/rfc-3376.txt section 4.1.1.
+func igmpTimeDecode(t uint8) time.Duration {
+ if t&0x80 == 0 {
+ return time.Millisecond * 100 * time.Duration(t)
+ }
+ mant := (t & 0x70) >> 4
+ exp := t & 0x0F
+ return time.Millisecond * 100 * time.Duration((mant|0x10)<<(exp+3))
+}
+
+// LayerType returns LayerTypeIGMP for the V1,2,3 message protocol formats.
+func (i *IGMP) LayerType() gopacket.LayerType { return LayerTypeIGMP }
+func (i *IGMPv1or2) LayerType() gopacket.LayerType { return LayerTypeIGMP }
+
+func (i *IGMPv1or2) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
+ if len(data) < 8 {
+ return errors.New("IGMP Packet too small")
+ }
+
+ i.Type = IGMPType(data[0])
+ i.MaxResponseTime = igmpTimeDecode(data[1])
+ i.Checksum = binary.BigEndian.Uint16(data[2:4])
+ i.GroupAddress = net.IP(data[4:8])
+
+ return nil
+}
+
+func (i *IGMPv1or2) NextLayerType() gopacket.LayerType {
+ return gopacket.LayerTypeZero
+}
+
+func (i *IGMPv1or2) CanDecode() gopacket.LayerClass {
+ return LayerTypeIGMP
+}
+
+// DecodeFromBytes decodes the given bytes into this layer.
+func (i *IGMP) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
+ if len(data) < 1 {
+ return errors.New("IGMP packet is too small")
+ }
+
+ // common IGMP header values between versions 1..3 of IGMP specification..
+ i.Type = IGMPType(data[0])
+
+ switch i.Type {
+ case IGMPMembershipQuery:
+ i.decodeIGMPv3MembershipQuery(data)
+ case IGMPMembershipReportV3:
+ i.decodeIGMPv3MembershipReport(data)
+ default:
+ return errors.New("unsupported IGMP type")
+ }
+
+ return nil
+}
+
+// CanDecode returns the set of layer types that this DecodingLayer can decode.
+func (i *IGMP) CanDecode() gopacket.LayerClass {
+ return LayerTypeIGMP
+}
+
+// NextLayerType returns the layer type contained by this DecodingLayer.
+func (i *IGMP) NextLayerType() gopacket.LayerType {
+ return gopacket.LayerTypeZero
+}
+
+// decodeIGMP will parse IGMP v1,2 or 3 protocols. Checks against the
+// IGMP type are performed against byte[0], logic then iniitalizes and
+// passes the appropriate struct (IGMP or IGMPv1or2) to
+// decodingLayerDecoder.
+func decodeIGMP(data []byte, p gopacket.PacketBuilder) error {
+ if len(data) < 1 {
+ return errors.New("IGMP packet is too small")
+ }
+
+ // byte 0 contains IGMP message type.
+ switch IGMPType(data[0]) {
+ case IGMPMembershipQuery:
+ // IGMPv3 Membership Query payload is >= 12
+ if len(data) >= 12 {
+ i := &IGMP{Version: 3}
+ return decodingLayerDecoder(i, data, p)
+ } else if len(data) == 8 {
+ i := &IGMPv1or2{}
+ if data[1] == 0x00 {
+ i.Version = 1 // IGMPv1 has a query length of 8 and MaxResp = 0
+ } else {
+ i.Version = 2 // IGMPv2 has a query length of 8 and MaxResp != 0
+ }
+
+ return decodingLayerDecoder(i, data, p)
+ }
+ case IGMPMembershipReportV3:
+ i := &IGMP{Version: 3}
+ return decodingLayerDecoder(i, data, p)
+ case IGMPMembershipReportV1:
+ i := &IGMPv1or2{Version: 1}
+ return decodingLayerDecoder(i, data, p)
+ case IGMPLeaveGroup, IGMPMembershipReportV2:
+ // leave group and Query Report v2 used in IGMPv2 only.
+ i := &IGMPv1or2{Version: 2}
+ return decodingLayerDecoder(i, data, p)
+ default:
+ }
+
+ return errors.New("Unable to determine IGMP type.")
+}