// Copyright 2018 GoPacket Authors. 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" "fmt" "math" "net" "time" "github.com/google/gopacket" ) // MLDv1Message represents the common structure of all MLDv1 messages type MLDv1Message struct { BaseLayer // 3.4. Maximum Response Delay MaximumResponseDelay time.Duration // 3.6. Multicast Address // Zero in general query // Specific IPv6 multicast address otherwise MulticastAddress net.IP } // DecodeFromBytes decodes the given bytes into this layer. func (m *MLDv1Message) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { if len(data) < 20 { df.SetTruncated() return errors.New("ICMP layer less than 20 bytes for Multicast Listener Query Message V1") } m.MaximumResponseDelay = time.Duration(binary.BigEndian.Uint16(data[0:2])) * time.Millisecond // data[2:4] is reserved and not used in mldv1 m.MulticastAddress = data[4:20] return nil } // NextLayerType returns the layer type contained by this DecodingLayer. func (*MLDv1Message) NextLayerType() gopacket.LayerType { return gopacket.LayerTypeZero } // SerializeTo writes the serialized form of this layer into the // SerializationBuffer, implementing gopacket.SerializableLayer. // See the docs for gopacket.SerializableLayer for more info. func (m *MLDv1Message) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { buf, err := b.PrependBytes(20) if err != nil { return err } if m.MaximumResponseDelay < 0 { return errors.New("maximum response delay must not be negative") } dms := m.MaximumResponseDelay / time.Millisecond if dms > math.MaxUint16 { return fmt.Errorf("maximum response delay %dms is more than the allowed 65535ms", dms) } binary.BigEndian.PutUint16(buf[0:2], uint16(dms)) copy(buf[2:4], []byte{0x0, 0x0}) ma16 := m.MulticastAddress.To16() if ma16 == nil { return fmt.Errorf("invalid multicast address '%s'", m.MulticastAddress) } copy(buf[4:20], ma16) return nil } // Sums this layer up nicely formatted func (m *MLDv1Message) String() string { return fmt.Sprintf( "Maximum Response Delay: %dms, Multicast Address: %s", m.MaximumResponseDelay/time.Millisecond, m.MulticastAddress) } // MLDv1MulticastListenerQueryMessage are sent by the router to determine // whether there are multicast listeners on the link. // https://tools.ietf.org/html/rfc2710 Page 5 type MLDv1MulticastListenerQueryMessage struct { MLDv1Message } // DecodeFromBytes decodes the given bytes into this layer. func (m *MLDv1MulticastListenerQueryMessage) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { err := m.MLDv1Message.DecodeFromBytes(data, df) if err != nil { return err } if len(data) > 20 { m.Payload = data[20:] } return nil } // LayerType returns LayerTypeMLDv1MulticastListenerQuery. func (*MLDv1MulticastListenerQueryMessage) LayerType() gopacket.LayerType { return LayerTypeMLDv1MulticastListenerQuery } // CanDecode returns the set of layer types that this DecodingLayer can decode. func (*MLDv1MulticastListenerQueryMessage) CanDecode() gopacket.LayerClass { return LayerTypeMLDv1MulticastListenerQuery } // IsGeneralQuery is true when this is a general query. // In a Query message, the Multicast Address field is set to zero when // sending a General Query. // https://tools.ietf.org/html/rfc2710#section-3.6 func (m *MLDv1MulticastListenerQueryMessage) IsGeneralQuery() bool { return net.IPv6zero.Equal(m.MulticastAddress) } // IsSpecificQuery is true when this is not a general query. // In a Query message, the Multicast Address field is set to a specific // IPv6 multicast address when sending a Multicast-Address-Specific Query. // https://tools.ietf.org/html/rfc2710#section-3.6 func (m *MLDv1MulticastListenerQueryMessage) IsSpecificQuery() bool { return !m.IsGeneralQuery() } // MLDv1MulticastListenerReportMessage is sent by a client listening on // a specific multicast address to indicate that it is (still) listening // on the specific multicast address. // https://tools.ietf.org/html/rfc2710 Page 6 type MLDv1MulticastListenerReportMessage struct { MLDv1Message } // LayerType returns LayerTypeMLDv1MulticastListenerReport. func (*MLDv1MulticastListenerReportMessage) LayerType() gopacket.LayerType { return LayerTypeMLDv1MulticastListenerReport } // CanDecode returns the set of layer types that this DecodingLayer can decode. func (*MLDv1MulticastListenerReportMessage) CanDecode() gopacket.LayerClass { return LayerTypeMLDv1MulticastListenerReport } // MLDv1MulticastListenerDoneMessage should be sent by a client when it ceases // to listen to a multicast address on an interface. // https://tools.ietf.org/html/rfc2710 Page 7 type MLDv1MulticastListenerDoneMessage struct { MLDv1Message } // LayerType returns LayerTypeMLDv1MulticastListenerDone. func (*MLDv1MulticastListenerDoneMessage) LayerType() gopacket.LayerType { return LayerTypeMLDv1MulticastListenerDone } // CanDecode returns the set of layer types that this DecodingLayer can decode. func (*MLDv1MulticastListenerDoneMessage) CanDecode() gopacket.LayerClass { return LayerTypeMLDv1MulticastListenerDone } func decodeMLDv1MulticastListenerReport(data []byte, p gopacket.PacketBuilder) error { m := &MLDv1MulticastListenerReportMessage{} return decodingLayerDecoder(m, data, p) } func decodeMLDv1MulticastListenerQuery(data []byte, p gopacket.PacketBuilder) error { m := &MLDv1MulticastListenerQueryMessage{} return decodingLayerDecoder(m, data, p) } func decodeMLDv1MulticastListenerDone(data []byte, p gopacket.PacketBuilder) error { m := &MLDv1MulticastListenerDoneMessage{} return decodingLayerDecoder(m, data, p) }