1// Copyright 2018 GoPacket Authors. 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 7package layers 8 9import ( 10 "encoding/binary" 11 "errors" 12 "fmt" 13 "math" 14 "net" 15 "time" 16 17 "github.com/google/gopacket" 18) 19 20// MLDv1Message represents the common structure of all MLDv1 messages 21type MLDv1Message struct { 22 BaseLayer 23 // 3.4. Maximum Response Delay 24 MaximumResponseDelay time.Duration 25 // 3.6. Multicast Address 26 // Zero in general query 27 // Specific IPv6 multicast address otherwise 28 MulticastAddress net.IP 29} 30 31// DecodeFromBytes decodes the given bytes into this layer. 32func (m *MLDv1Message) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { 33 if len(data) < 20 { 34 df.SetTruncated() 35 return errors.New("ICMP layer less than 20 bytes for Multicast Listener Query Message V1") 36 } 37 38 m.MaximumResponseDelay = time.Duration(binary.BigEndian.Uint16(data[0:2])) * time.Millisecond 39 // data[2:4] is reserved and not used in mldv1 40 m.MulticastAddress = data[4:20] 41 42 return nil 43} 44 45// NextLayerType returns the layer type contained by this DecodingLayer. 46func (*MLDv1Message) NextLayerType() gopacket.LayerType { 47 return gopacket.LayerTypeZero 48} 49 50// SerializeTo writes the serialized form of this layer into the 51// SerializationBuffer, implementing gopacket.SerializableLayer. 52// See the docs for gopacket.SerializableLayer for more info. 53func (m *MLDv1Message) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { 54 buf, err := b.PrependBytes(20) 55 if err != nil { 56 return err 57 } 58 59 if m.MaximumResponseDelay < 0 { 60 return errors.New("maximum response delay must not be negative") 61 } 62 dms := m.MaximumResponseDelay / time.Millisecond 63 if dms > math.MaxUint16 { 64 return fmt.Errorf("maximum response delay %dms is more than the allowed 65535ms", dms) 65 } 66 binary.BigEndian.PutUint16(buf[0:2], uint16(dms)) 67 68 copy(buf[2:4], []byte{0x0, 0x0}) 69 70 ma16 := m.MulticastAddress.To16() 71 if ma16 == nil { 72 return fmt.Errorf("invalid multicast address '%s'", m.MulticastAddress) 73 } 74 copy(buf[4:20], ma16) 75 76 return nil 77} 78 79// Sums this layer up nicely formatted 80func (m *MLDv1Message) String() string { 81 return fmt.Sprintf( 82 "Maximum Response Delay: %dms, Multicast Address: %s", 83 m.MaximumResponseDelay/time.Millisecond, 84 m.MulticastAddress) 85} 86 87// MLDv1MulticastListenerQueryMessage are sent by the router to determine 88// whether there are multicast listeners on the link. 89// https://tools.ietf.org/html/rfc2710 Page 5 90type MLDv1MulticastListenerQueryMessage struct { 91 MLDv1Message 92} 93 94// DecodeFromBytes decodes the given bytes into this layer. 95func (m *MLDv1MulticastListenerQueryMessage) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { 96 err := m.MLDv1Message.DecodeFromBytes(data, df) 97 if err != nil { 98 return err 99 } 100 101 if len(data) > 20 { 102 m.Payload = data[20:] 103 } 104 105 return nil 106} 107 108// LayerType returns LayerTypeMLDv1MulticastListenerQuery. 109func (*MLDv1MulticastListenerQueryMessage) LayerType() gopacket.LayerType { 110 return LayerTypeMLDv1MulticastListenerQuery 111} 112 113// CanDecode returns the set of layer types that this DecodingLayer can decode. 114func (*MLDv1MulticastListenerQueryMessage) CanDecode() gopacket.LayerClass { 115 return LayerTypeMLDv1MulticastListenerQuery 116} 117 118// IsGeneralQuery is true when this is a general query. 119// In a Query message, the Multicast Address field is set to zero when 120// sending a General Query. 121// https://tools.ietf.org/html/rfc2710#section-3.6 122func (m *MLDv1MulticastListenerQueryMessage) IsGeneralQuery() bool { 123 return net.IPv6zero.Equal(m.MulticastAddress) 124} 125 126// IsSpecificQuery is true when this is not a general query. 127// In a Query message, the Multicast Address field is set to a specific 128// IPv6 multicast address when sending a Multicast-Address-Specific Query. 129// https://tools.ietf.org/html/rfc2710#section-3.6 130func (m *MLDv1MulticastListenerQueryMessage) IsSpecificQuery() bool { 131 return !m.IsGeneralQuery() 132} 133 134// MLDv1MulticastListenerReportMessage is sent by a client listening on 135// a specific multicast address to indicate that it is (still) listening 136// on the specific multicast address. 137// https://tools.ietf.org/html/rfc2710 Page 6 138type MLDv1MulticastListenerReportMessage struct { 139 MLDv1Message 140} 141 142// LayerType returns LayerTypeMLDv1MulticastListenerReport. 143func (*MLDv1MulticastListenerReportMessage) LayerType() gopacket.LayerType { 144 return LayerTypeMLDv1MulticastListenerReport 145} 146 147// CanDecode returns the set of layer types that this DecodingLayer can decode. 148func (*MLDv1MulticastListenerReportMessage) CanDecode() gopacket.LayerClass { 149 return LayerTypeMLDv1MulticastListenerReport 150} 151 152// MLDv1MulticastListenerDoneMessage should be sent by a client when it ceases 153// to listen to a multicast address on an interface. 154// https://tools.ietf.org/html/rfc2710 Page 7 155type MLDv1MulticastListenerDoneMessage struct { 156 MLDv1Message 157} 158 159// LayerType returns LayerTypeMLDv1MulticastListenerDone. 160func (*MLDv1MulticastListenerDoneMessage) LayerType() gopacket.LayerType { 161 return LayerTypeMLDv1MulticastListenerDone 162} 163 164// CanDecode returns the set of layer types that this DecodingLayer can decode. 165func (*MLDv1MulticastListenerDoneMessage) CanDecode() gopacket.LayerClass { 166 return LayerTypeMLDv1MulticastListenerDone 167} 168 169func decodeMLDv1MulticastListenerReport(data []byte, p gopacket.PacketBuilder) error { 170 m := &MLDv1MulticastListenerReportMessage{} 171 return decodingLayerDecoder(m, data, p) 172} 173 174func decodeMLDv1MulticastListenerQuery(data []byte, p gopacket.PacketBuilder) error { 175 m := &MLDv1MulticastListenerQueryMessage{} 176 return decodingLayerDecoder(m, data, p) 177} 178 179func decodeMLDv1MulticastListenerDone(data []byte, p gopacket.PacketBuilder) error { 180 m := &MLDv1MulticastListenerDoneMessage{} 181 return decodingLayerDecoder(m, data, p) 182} 183