github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/tcpip/header/mldv2.go (about)

     1  // Copyright 2022 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package header
    16  
    17  import (
    18  	"bytes"
    19  	"encoding/binary"
    20  	"fmt"
    21  	"time"
    22  
    23  	"github.com/nicocha30/gvisor-ligolo/pkg/tcpip"
    24  )
    25  
    26  const (
    27  	// MLDv2QueryMinimumSize is the minimum size for an MLDv2 message.
    28  	MLDv2QueryMinimumSize = 24
    29  
    30  	mldv2QueryMaximumResponseCodeOffset = 0
    31  	mldv2QueryResvSQRVOffset            = 20
    32  	mldv2QueryQRVMask                   = 0b111
    33  	mldv2QueryQQICOffset                = 21
    34  	// mldv2QueryNumberOfSourcesOffset is the offset to the Number of Sources
    35  	// field within MLDv2Query.
    36  	mldv2QueryNumberOfSourcesOffset = 22
    37  
    38  	// MLDv2ReportMinimumSize is the minimum size of an MLDv2 report.
    39  	MLDv2ReportMinimumSize = 24
    40  
    41  	// mldv2QuerySourcesOffset is the offset to the Sources field within
    42  	// MLDv2Query.
    43  	mldv2QuerySourcesOffset = 24
    44  )
    45  
    46  var (
    47  	// MLDv2RoutersAddress is the address to send MLDv2 reports to.
    48  	//
    49  	// As per RFC 3810 section 5.2.14,
    50  	//
    51  	//   Version 2 Multicast Listener Reports are sent with an IP destination
    52  	//   address of FF02:0:0:0:0:0:0:16, to which all MLDv2-capable multicast
    53  	//   routers listen (see section 11 for IANA considerations related to
    54  	//   this special destination address).
    55  	MLDv2RoutersAddress = tcpip.AddrFrom16([16]byte{0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16})
    56  )
    57  
    58  // MLDv2Query is a Multicast Listener Discovery Version 2 Query message in an
    59  // ICMPv6 packet.
    60  //
    61  // MLDv2Query will only contain the body of an ICMPv6 packet.
    62  //
    63  // As per RFC 3810 section 5.1, MLDv2 Query messages have the following format
    64  // (MLDv2Query only holds the bytes after the first four bytes in the diagram
    65  // below):
    66  //
    67  //	 0                   1                   2                   3
    68  //	 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
    69  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    70  //	|  Type = 130   |      Code     |           Checksum            |
    71  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    72  //	|    Maximum Response Code      |           Reserved            |
    73  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    74  //	|                                                               |
    75  //	*                                                               *
    76  //	|                                                               |
    77  //	*                       Multicast Address                       *
    78  //	|                                                               |
    79  //	*                                                               *
    80  //	|                                                               |
    81  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    82  //	| Resv  |S| QRV |     QQIC      |     Number of Sources (N)     |
    83  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    84  //	|                                                               |
    85  //	*                                                               *
    86  //	|                                                               |
    87  //	*                       Source Address [1]                      *
    88  //	|                                                               |
    89  //	*                                                               *
    90  //	|                                                               |
    91  //	+-                                                             -+
    92  //	|                                                               |
    93  //	*                                                               *
    94  //	|                                                               |
    95  //	*                       Source Address [2]                      *
    96  //	|                                                               |
    97  //	*                                                               *
    98  //	|                                                               |
    99  //	+-                              .                              -+
   100  //	.                               .                               .
   101  //	.                               .                               .
   102  //	+-                                                             -+
   103  //	|                                                               |
   104  //	*                                                               *
   105  //	|                                                               |
   106  //	*                       Source Address [N]                      *
   107  //	|                                                               |
   108  //	*                                                               *
   109  //	|                                                               |
   110  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   111  type MLDv2Query MLD
   112  
   113  // MaximumResponseCode returns the Maximum Response Code
   114  func (m MLDv2Query) MaximumResponseCode() uint16 {
   115  	return binary.BigEndian.Uint16(m[mldv2QueryMaximumResponseCodeOffset:])
   116  }
   117  
   118  // MLDv2MaximumResponseDelay returns the Maximum Response Delay in an MLDv2
   119  // Maximum Response Code.
   120  //
   121  // As per RFC 3810 section 5.1.3,
   122  //
   123  //	The Maximum Response Code field specifies the maximum time allowed
   124  //	before sending a responding Report.  The actual time allowed, called
   125  //	the Maximum Response Delay, is represented in units of milliseconds,
   126  //	and is derived from the Maximum Response Code as follows:
   127  //
   128  //	If Maximum Response Code < 32768,
   129  //	   Maximum Response Delay = Maximum Response Code
   130  //
   131  //	If Maximum Response Code >=32768, Maximum Response Code represents a
   132  //	floating-point value as follows:
   133  //
   134  //	    0 1 2 3 4 5 6 7 8 9 A B C D E F
   135  //	   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   136  //	   |1| exp |          mant         |
   137  //	   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   138  //
   139  //	Maximum Response Delay = (mant | 0x1000) << (exp+3)
   140  //
   141  //	Small values of Maximum Response Delay allow MLDv2 routers to tune
   142  //	the "leave latency" (the time between the moment the last node on a
   143  //	link ceases to listen to a specific multicast address and the moment
   144  //	the routing protocol is notified that there are no more listeners for
   145  //	that address).  Larger values, especially in the exponential range,
   146  //	allow the tuning of the burstiness of MLD traffic on a link.
   147  func MLDv2MaximumResponseDelay(codeRaw uint16) time.Duration {
   148  	code := time.Duration(codeRaw)
   149  	if code < 32768 {
   150  		return code * time.Millisecond
   151  	}
   152  
   153  	const mantBits = 12
   154  	const expMask = 0b111
   155  	exp := (code >> mantBits) & expMask
   156  	mant := code & ((1 << mantBits) - 1)
   157  	return (mant | 0x1000) << (exp + 3) * time.Millisecond
   158  }
   159  
   160  // MulticastAddress returns the Multicast Address.
   161  func (m MLDv2Query) MulticastAddress() tcpip.Address {
   162  	// As per RFC 2710 section 3.5:
   163  	//
   164  	//   In a Query message, the Multicast Address field is set to zero when
   165  	//   sending a General Query, and set to a specific IPv6 multicast address
   166  	//   when sending a Multicast-Address-Specific Query.
   167  	//
   168  	//   In a Report or Done message, the Multicast Address field holds a
   169  	//   specific IPv6 multicast address to which the message sender is
   170  	//   listening or is ceasing to listen, respectively.
   171  	return tcpip.AddrFrom16([16]byte(m[mldMulticastAddressOffset:][:IPv6AddressSize]))
   172  }
   173  
   174  // QuerierRobustnessVariable returns the querier's robustness variable.
   175  func (m MLDv2Query) QuerierRobustnessVariable() uint8 {
   176  	return m[mldv2QueryResvSQRVOffset] & mldv2QueryQRVMask
   177  }
   178  
   179  // QuerierQueryInterval returns the querier's query interval.
   180  func (m MLDv2Query) QuerierQueryInterval() time.Duration {
   181  	return mldv2AndIGMPv3QuerierQueryCodeToInterval(m[mldv2QueryQQICOffset])
   182  }
   183  
   184  // Sources returns an iterator over source addresses in the query.
   185  //
   186  // Returns false if the message cannot hold the expected number of sources.
   187  func (m MLDv2Query) Sources() (AddressIterator, bool) {
   188  	return makeAddressIterator(
   189  		m[mldv2QuerySourcesOffset:],
   190  		binary.BigEndian.Uint16(m[mldv2QueryNumberOfSourcesOffset:]),
   191  		IPv6AddressSize,
   192  	)
   193  }
   194  
   195  // MLDv2ReportRecordType is the type of an MLDv2 multicast address record
   196  // found in an MLDv2 report, as per RFC 3810 section 5.2.12.
   197  type MLDv2ReportRecordType int
   198  
   199  // MLDv2 multicast address record types, as per RFC 3810 section 5.2.12.
   200  const (
   201  	MLDv2ReportRecordModeIsInclude       MLDv2ReportRecordType = 1
   202  	MLDv2ReportRecordModeIsExclude       MLDv2ReportRecordType = 2
   203  	MLDv2ReportRecordChangeToIncludeMode MLDv2ReportRecordType = 3
   204  	MLDv2ReportRecordChangeToExcludeMode MLDv2ReportRecordType = 4
   205  	MLDv2ReportRecordAllowNewSources     MLDv2ReportRecordType = 5
   206  	MLDv2ReportRecordBlockOldSources     MLDv2ReportRecordType = 6
   207  )
   208  
   209  const (
   210  	mldv2ReportMulticastAddressRecordMinimumSize            = 20
   211  	mldv2ReportMulticastAddressRecordTypeOffset             = 0
   212  	mldv2ReportMulticastAddressRecordAuxDataLenOffset       = 1
   213  	mldv2ReportMulticastAddressRecordAuxDataLenUnits        = 4
   214  	mldv2ReportMulticastAddressRecordNumberOfSourcesOffset  = 2
   215  	mldv2ReportMulticastAddressRecordMulticastAddressOffset = 4
   216  	mldv2ReportMulticastAddressRecordSourcesOffset          = 20
   217  )
   218  
   219  // MLDv2ReportMulticastAddressRecordSerializer is an MLDv2 Multicast Address
   220  // Record serializer.
   221  //
   222  // As per RFC 3810 section 5.2, a Multicast Address Record has the following
   223  // internal format:
   224  //
   225  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   226  //	|  Record Type  |  Aux Data Len |     Number of Sources (N)     |
   227  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   228  //	|                                                               |
   229  //	*                                                               *
   230  //	|                                                               |
   231  //	*                       Multicast Address                       *
   232  //	|                                                               |
   233  //	*                                                               *
   234  //	|                                                               |
   235  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   236  //	|                                                               |
   237  //	*                                                               *
   238  //	|                                                               |
   239  //	*                       Source Address [1]                      *
   240  //	|                                                               |
   241  //	*                                                               *
   242  //	|                                                               |
   243  //	+-                                                             -+
   244  //	|                                                               |
   245  //	*                                                               *
   246  //	|                                                               |
   247  //	*                       Source Address [2]                      *
   248  //	|                                                               |
   249  //	*                                                               *
   250  //	|                                                               |
   251  //	+-                                                             -+
   252  //	.                               .                               .
   253  //	.                               .                               .
   254  //	.                               .                               .
   255  //	+-                                                             -+
   256  //	|                                                               |
   257  //	*                                                               *
   258  //	|                                                               |
   259  //	*                       Source Address [N]                      *
   260  //	|                                                               |
   261  //	*                                                               *
   262  //	|                                                               |
   263  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   264  //	|                                                               |
   265  //	.                                                               .
   266  //	.                         Auxiliary Data                        .
   267  //	.                                                               .
   268  //	|                                                               |
   269  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   270  type MLDv2ReportMulticastAddressRecordSerializer struct {
   271  	RecordType       MLDv2ReportRecordType
   272  	MulticastAddress tcpip.Address
   273  	Sources          []tcpip.Address
   274  }
   275  
   276  // Length returns the number of bytes this serializer would occupy.
   277  func (s *MLDv2ReportMulticastAddressRecordSerializer) Length() int {
   278  	return mldv2ReportMulticastAddressRecordSourcesOffset + len(s.Sources)*IPv6AddressSize
   279  }
   280  
   281  func copyIPv6Address(dst []byte, src tcpip.Address) {
   282  	if n := copy(dst, src.AsSlice()); n != IPv6AddressSize {
   283  		panic(fmt.Sprintf("got copy(...) = %d, want = %d", n, IPv6AddressSize))
   284  	}
   285  }
   286  
   287  // SerializeInto serializes the record into the buffer.
   288  //
   289  // Panics if the buffer does not have enough space to fit the record.
   290  func (s *MLDv2ReportMulticastAddressRecordSerializer) SerializeInto(b []byte) {
   291  	b[mldv2ReportMulticastAddressRecordTypeOffset] = byte(s.RecordType)
   292  	b[mldv2ReportMulticastAddressRecordAuxDataLenOffset] = 0
   293  	binary.BigEndian.PutUint16(b[mldv2ReportMulticastAddressRecordNumberOfSourcesOffset:], uint16(len(s.Sources)))
   294  	copyIPv6Address(b[mldv2ReportMulticastAddressRecordMulticastAddressOffset:], s.MulticastAddress)
   295  	b = b[mldv2ReportMulticastAddressRecordSourcesOffset:]
   296  	for _, source := range s.Sources {
   297  		copyIPv6Address(b, source)
   298  		b = b[IPv6AddressSize:]
   299  	}
   300  }
   301  
   302  const (
   303  	mldv2ReportReservedOffset                        = 0
   304  	mldv2ReportNumberOfMulticastAddressRecordsOffset = 2
   305  	mldv2ReportMulticastAddressRecordsOffset         = 4
   306  )
   307  
   308  // MLDv2ReportSerializer is an MLD Version 2 Report serializer.
   309  //
   310  // As per RFC 3810 section 5.2,
   311  //
   312  //	 0                   1                   2                   3
   313  //	 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
   314  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   315  //	|  Type = 143   |    Reserved   |           Checksum            |
   316  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   317  //	|           Reserved            |Nr of Mcast Address Records (M)|
   318  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   319  //	|                                                               |
   320  //	.                                                               .
   321  //	.                  Multicast Address Record [1]                 .
   322  //	.                                                               .
   323  //	|                                                               |
   324  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   325  //	|                                                               |
   326  //	.                                                               .
   327  //	.                  Multicast Address Record [2]                 .
   328  //	.                                                               .
   329  //	|                                                               |
   330  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   331  //	|                               .                               |
   332  //	.                               .                               .
   333  //	|                               .                               |
   334  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   335  //	|                                                               |
   336  //	.                                                               .
   337  //	.                  Multicast Address Record [M]                 .
   338  //	.                                                               .
   339  //	|                                                               |
   340  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   341  type MLDv2ReportSerializer struct {
   342  	Records []MLDv2ReportMulticastAddressRecordSerializer
   343  }
   344  
   345  // Length returns the number of bytes this serializer would occupy.
   346  func (s *MLDv2ReportSerializer) Length() int {
   347  	ret := mldv2ReportMulticastAddressRecordsOffset
   348  	for _, record := range s.Records {
   349  		ret += record.Length()
   350  	}
   351  	return ret
   352  }
   353  
   354  // SerializeInto serializes the report into the buffer.
   355  //
   356  // Panics if the buffer does not have enough space to fit the report.
   357  func (s *MLDv2ReportSerializer) SerializeInto(b []byte) {
   358  	binary.BigEndian.PutUint16(b[mldv2ReportReservedOffset:], 0)
   359  	binary.BigEndian.PutUint16(b[mldv2ReportNumberOfMulticastAddressRecordsOffset:], uint16(len(s.Records)))
   360  	b = b[mldv2ReportMulticastAddressRecordsOffset:]
   361  	for _, record := range s.Records {
   362  		len := record.Length()
   363  		record.SerializeInto(b[:len])
   364  		b = b[len:]
   365  	}
   366  }
   367  
   368  // MLDv2ReportMulticastAddressRecord is an MLDv2 record.
   369  //
   370  // As per RFC 3810 section 5.2, a Multicast Address Record has the following
   371  // internal format:
   372  //
   373  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   374  //	|  Record Type  |  Aux Data Len |     Number of Sources (N)     |
   375  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   376  //	|                                                               |
   377  //	*                                                               *
   378  //	|                                                               |
   379  //	*                       Multicast Address                       *
   380  //	|                                                               |
   381  //	*                                                               *
   382  //	|                                                               |
   383  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   384  //	|                                                               |
   385  //	*                                                               *
   386  //	|                                                               |
   387  //	*                       Source Address [1]                      *
   388  //	|                                                               |
   389  //	*                                                               *
   390  //	|                                                               |
   391  //	+-                                                             -+
   392  //	|                                                               |
   393  //	*                                                               *
   394  //	|                                                               |
   395  //	*                       Source Address [2]                      *
   396  //	|                                                               |
   397  //	*                                                               *
   398  //	|                                                               |
   399  //	+-                                                             -+
   400  //	.                               .                               .
   401  //	.                               .                               .
   402  //	.                               .                               .
   403  //	+-                                                             -+
   404  //	|                                                               |
   405  //	*                                                               *
   406  //	|                                                               |
   407  //	*                       Source Address [N]                      *
   408  //	|                                                               |
   409  //	*                                                               *
   410  //	|                                                               |
   411  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   412  //	|                                                               |
   413  //	.                                                               .
   414  //	.                         Auxiliary Data                        .
   415  //	.                                                               .
   416  //	|                                                               |
   417  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   418  type MLDv2ReportMulticastAddressRecord []byte
   419  
   420  // RecordType returns the type of this record.
   421  func (r MLDv2ReportMulticastAddressRecord) RecordType() MLDv2ReportRecordType {
   422  	return MLDv2ReportRecordType(r[mldv2ReportMulticastAddressRecordTypeOffset])
   423  }
   424  
   425  // AuxDataLen returns the length of the auxillary data in this record.
   426  func (r MLDv2ReportMulticastAddressRecord) AuxDataLen() int {
   427  	return int(r[mldv2ReportMulticastAddressRecordAuxDataLenOffset]) * mldv2ReportMulticastAddressRecordAuxDataLenUnits
   428  }
   429  
   430  // numberOfSources returns the number of sources in this record.
   431  func (r MLDv2ReportMulticastAddressRecord) numberOfSources() uint16 {
   432  	return binary.BigEndian.Uint16(r[mldv2ReportMulticastAddressRecordNumberOfSourcesOffset:])
   433  }
   434  
   435  // MulticastAddress returns the multicast address this record targets.
   436  func (r MLDv2ReportMulticastAddressRecord) MulticastAddress() tcpip.Address {
   437  	return tcpip.AddrFrom16([16]byte(r[mldv2ReportMulticastAddressRecordMulticastAddressOffset:][:IPv6AddressSize]))
   438  }
   439  
   440  // Sources returns an iterator over source addresses in the query.
   441  //
   442  // Returns false if the message cannot hold the expected number of sources.
   443  func (r MLDv2ReportMulticastAddressRecord) Sources() (AddressIterator, bool) {
   444  	expectedLen := int(r.numberOfSources()) * IPv6AddressSize
   445  	b := r[mldv2ReportMulticastAddressRecordSourcesOffset:]
   446  	if len(b) < expectedLen {
   447  		return AddressIterator{}, false
   448  	}
   449  	return AddressIterator{addressSize: IPv6AddressSize, buf: bytes.NewBuffer(b[:expectedLen])}, true
   450  }
   451  
   452  // MLDv2Report is an MLDv2 Report.
   453  //
   454  // As per RFC 3810 section 5.2,
   455  //
   456  //	 0                   1                   2                   3
   457  //	 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
   458  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   459  //	|  Type = 143   |    Reserved   |           Checksum            |
   460  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   461  //	|           Reserved            |Nr of Mcast Address Records (M)|
   462  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   463  //	|                                                               |
   464  //	.                                                               .
   465  //	.                  Multicast Address Record [1]                 .
   466  //	.                                                               .
   467  //	|                                                               |
   468  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   469  //	|                                                               |
   470  //	.                                                               .
   471  //	.                  Multicast Address Record [2]                 .
   472  //	.                                                               .
   473  //	|                                                               |
   474  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   475  //	|                               .                               |
   476  //	.                               .                               .
   477  //	|                               .                               |
   478  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   479  //	|                                                               |
   480  //	.                                                               .
   481  //	.                  Multicast Address Record [M]                 .
   482  //	.                                                               .
   483  //	|                                                               |
   484  //	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   485  type MLDv2Report []byte
   486  
   487  // MLDv2ReportMulticastAddressRecordIterator is an iterator over MLDv2 Multicast
   488  // Address Records.
   489  type MLDv2ReportMulticastAddressRecordIterator struct {
   490  	recordsLeft uint16
   491  	buf         *bytes.Buffer
   492  }
   493  
   494  // MLDv2ReportMulticastAddressRecordIteratorNextDisposition is the possible
   495  // return values from MLDv2ReportMulticastAddressRecordIterator.Next.
   496  type MLDv2ReportMulticastAddressRecordIteratorNextDisposition int
   497  
   498  const (
   499  	// MLDv2ReportMulticastAddressRecordIteratorNextOk indicates that a multicast
   500  	// address record was yielded.
   501  	MLDv2ReportMulticastAddressRecordIteratorNextOk MLDv2ReportMulticastAddressRecordIteratorNextDisposition = iota
   502  
   503  	// MLDv2ReportMulticastAddressRecordIteratorNextDone indicates that the iterator
   504  	// has been exhausted.
   505  	MLDv2ReportMulticastAddressRecordIteratorNextDone
   506  
   507  	// MLDv2ReportMulticastAddressRecordIteratorNextErrBufferTooShort indicates
   508  	// that the iterator expected another record, but the buffer ended
   509  	// prematurely.
   510  	MLDv2ReportMulticastAddressRecordIteratorNextErrBufferTooShort
   511  )
   512  
   513  // Next returns the next MLDv2 Multicast Address Record.
   514  func (it *MLDv2ReportMulticastAddressRecordIterator) Next() (MLDv2ReportMulticastAddressRecord, MLDv2ReportMulticastAddressRecordIteratorNextDisposition) {
   515  	if it.recordsLeft == 0 {
   516  		return MLDv2ReportMulticastAddressRecord{}, MLDv2ReportMulticastAddressRecordIteratorNextDone
   517  	}
   518  	if it.buf.Len() < mldv2ReportMulticastAddressRecordMinimumSize {
   519  		return MLDv2ReportMulticastAddressRecord{}, MLDv2ReportMulticastAddressRecordIteratorNextErrBufferTooShort
   520  	}
   521  
   522  	hdr := MLDv2ReportMulticastAddressRecord(it.buf.Bytes())
   523  	expectedLen := mldv2ReportMulticastAddressRecordMinimumSize +
   524  		int(hdr.AuxDataLen()) + int(hdr.numberOfSources())*IPv6AddressSize
   525  
   526  	bytes := it.buf.Next(expectedLen)
   527  	if len(bytes) < expectedLen {
   528  		return MLDv2ReportMulticastAddressRecord{}, MLDv2ReportMulticastAddressRecordIteratorNextErrBufferTooShort
   529  	}
   530  	it.recordsLeft--
   531  	return MLDv2ReportMulticastAddressRecord(bytes), MLDv2ReportMulticastAddressRecordIteratorNextOk
   532  }
   533  
   534  // MulticastAddressRecords returns an iterator of MLDv2 Multicast Address
   535  // Records.
   536  func (m MLDv2Report) MulticastAddressRecords() MLDv2ReportMulticastAddressRecordIterator {
   537  	return MLDv2ReportMulticastAddressRecordIterator{
   538  		recordsLeft: binary.BigEndian.Uint16(m[mldv2ReportNumberOfMulticastAddressRecordsOffset:]),
   539  		buf:         bytes.NewBuffer(m[mldv2ReportMulticastAddressRecordsOffset:]),
   540  	}
   541  }