Holger Hildebrandt | fa07499 | 2020-03-27 15:42:06 +0000 | [diff] [blame] | 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 | |
| 7 | package layers |
| 8 | |
| 9 | import ( |
| 10 | "encoding/binary" |
| 11 | "errors" |
| 12 | "fmt" |
| 13 | "math" |
| 14 | "net" |
| 15 | "time" |
| 16 | |
| 17 | "github.com/google/gopacket" |
| 18 | ) |
| 19 | |
| 20 | const ( |
| 21 | // S Flag bit is 1 |
| 22 | mldv2STrue uint8 = 0x8 |
| 23 | |
| 24 | // S Flag value mask |
| 25 | // mldv2STrue & mldv2SMask == mldv2STrue // true |
| 26 | // 0x1 & mldv2SMask == mldv2STrue // true |
| 27 | // 0x0 & mldv2SMask == mldv2STrue // false |
| 28 | mldv2SMask uint8 = 0x8 |
| 29 | |
| 30 | // QRV value mask |
| 31 | mldv2QRVMask uint8 = 0x7 |
| 32 | ) |
| 33 | |
| 34 | // MLDv2MulticastListenerQueryMessage are sent by multicast routers to query the |
| 35 | // multicast listening state of neighboring interfaces. |
| 36 | // https://tools.ietf.org/html/rfc3810#section-5.1 |
| 37 | // |
| 38 | // Some information, like Maximum Response Code and Multicast Address are in the |
| 39 | // previous layer LayerTypeMLDv1MulticastListenerQuery |
| 40 | type MLDv2MulticastListenerQueryMessage struct { |
| 41 | BaseLayer |
| 42 | // 5.1.3. Maximum Response Delay COde |
| 43 | MaximumResponseCode uint16 |
| 44 | // 5.1.5. Multicast Address |
| 45 | // Zero in general query |
| 46 | // Specific IPv6 multicast address otherwise |
| 47 | MulticastAddress net.IP |
| 48 | // 5.1.7. S Flag (Suppress Router-Side Processing) |
| 49 | SuppressRoutersideProcessing bool |
| 50 | // 5.1.8. QRV (Querier's Robustness Variable) |
| 51 | QueriersRobustnessVariable uint8 |
| 52 | // 5.1.9. QQIC (Querier's Query Interval Code) |
| 53 | QueriersQueryIntervalCode uint8 |
| 54 | // 5.1.10. Number of Sources (N) |
| 55 | NumberOfSources uint16 |
| 56 | // 5.1.11 Source Address [i] |
| 57 | SourceAddresses []net.IP |
| 58 | } |
| 59 | |
| 60 | // DecodeFromBytes decodes the given bytes into this layer. |
| 61 | func (m *MLDv2MulticastListenerQueryMessage) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { |
| 62 | if len(data) < 24 { |
| 63 | df.SetTruncated() |
| 64 | return errors.New("ICMP layer less than 24 bytes for Multicast Listener Query Message V2") |
| 65 | } |
| 66 | |
| 67 | m.MaximumResponseCode = binary.BigEndian.Uint16(data[0:2]) |
| 68 | // ignore data[2:4] as per https://tools.ietf.org/html/rfc3810#section-5.1.4 |
| 69 | m.MulticastAddress = data[4:20] |
| 70 | m.SuppressRoutersideProcessing = (data[20] & mldv2SMask) == mldv2STrue |
| 71 | m.QueriersRobustnessVariable = data[20] & mldv2QRVMask |
| 72 | m.QueriersQueryIntervalCode = data[21] |
| 73 | |
| 74 | m.NumberOfSources = binary.BigEndian.Uint16(data[22:24]) |
| 75 | |
| 76 | var end int |
| 77 | for i := uint16(0); i < m.NumberOfSources; i++ { |
| 78 | begin := 24 + (int(i) * 16) |
| 79 | end = begin + 16 |
| 80 | |
| 81 | if end > len(data) { |
| 82 | df.SetTruncated() |
| 83 | return fmt.Errorf("ICMP layer less than %d bytes for Multicast Listener Query Message V2", end) |
| 84 | } |
| 85 | |
| 86 | m.SourceAddresses = append(m.SourceAddresses, data[begin:end]) |
| 87 | } |
| 88 | |
| 89 | return nil |
| 90 | } |
| 91 | |
| 92 | // NextLayerType returns the layer type contained by this DecodingLayer. |
| 93 | func (*MLDv2MulticastListenerQueryMessage) NextLayerType() gopacket.LayerType { |
| 94 | return gopacket.LayerTypeZero |
| 95 | } |
| 96 | |
| 97 | // SerializeTo writes the serialized form of this layer into the |
| 98 | // SerializationBuffer, implementing gopacket.SerializableLayer. |
| 99 | // See the docs for gopacket.SerializableLayer for more info. |
| 100 | func (m *MLDv2MulticastListenerQueryMessage) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { |
| 101 | if err := m.serializeSourceAddressesTo(b, opts); err != nil { |
| 102 | return err |
| 103 | } |
| 104 | |
| 105 | buf, err := b.PrependBytes(24) |
| 106 | if err != nil { |
| 107 | return err |
| 108 | } |
| 109 | |
| 110 | binary.BigEndian.PutUint16(buf[0:2], m.MaximumResponseCode) |
| 111 | copy(buf[2:4], []byte{0x00, 0x00}) // set reserved bytes to zero |
| 112 | |
| 113 | ma16 := m.MulticastAddress.To16() |
| 114 | if ma16 == nil { |
| 115 | return fmt.Errorf("invalid MulticastAddress '%s'", m.MulticastAddress) |
| 116 | } |
| 117 | copy(buf[4:20], ma16) |
| 118 | |
| 119 | byte20 := m.QueriersRobustnessVariable & mldv2QRVMask |
| 120 | if m.SuppressRoutersideProcessing { |
| 121 | byte20 |= mldv2STrue |
| 122 | } else { |
| 123 | byte20 &= ^mldv2STrue // the complement of mldv2STrue |
| 124 | } |
| 125 | byte20 &= 0x0F // set reserved bits to zero |
| 126 | buf[20] = byte20 |
| 127 | |
| 128 | binary.BigEndian.PutUint16(buf[22:24], m.NumberOfSources) |
| 129 | buf[21] = m.QueriersQueryIntervalCode |
| 130 | |
| 131 | return nil |
| 132 | } |
| 133 | |
| 134 | // writes each source address to the buffer preserving the order |
| 135 | func (m *MLDv2MulticastListenerQueryMessage) serializeSourceAddressesTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { |
| 136 | numberOfSourceAddresses := len(m.SourceAddresses) |
| 137 | if numberOfSourceAddresses > math.MaxUint16 { |
| 138 | return fmt.Errorf( |
| 139 | "there are more than %d source addresses, but 65535 is the maximum number of supported addresses", |
| 140 | numberOfSourceAddresses) |
| 141 | } |
| 142 | |
| 143 | if opts.FixLengths { |
| 144 | m.NumberOfSources = uint16(numberOfSourceAddresses) |
| 145 | } |
| 146 | |
| 147 | lastSAIdx := numberOfSourceAddresses - 1 |
| 148 | for k := range m.SourceAddresses { |
| 149 | i := lastSAIdx - k // reverse order |
| 150 | |
| 151 | buf, err := b.PrependBytes(16) |
| 152 | if err != nil { |
| 153 | return err |
| 154 | } |
| 155 | |
| 156 | sa16 := m.SourceAddresses[i].To16() |
| 157 | if sa16 == nil { |
| 158 | return fmt.Errorf("invalid source address [%d] '%s'", i, m.SourceAddresses[i]) |
| 159 | } |
| 160 | copy(buf[0:16], sa16) |
| 161 | } |
| 162 | |
| 163 | return nil |
| 164 | } |
| 165 | |
| 166 | // String sums this layer up nicely formatted |
| 167 | func (m *MLDv2MulticastListenerQueryMessage) String() string { |
| 168 | return fmt.Sprintf( |
| 169 | "Maximum Response Code: %#x (%dms), Multicast Address: %s, Suppress Routerside Processing: %t, QRV: %#x, QQIC: %#x (%ds), Number of Source Address: %d (actual: %d), Source Addresses: %s", |
| 170 | m.MaximumResponseCode, |
| 171 | m.MaximumResponseDelay(), |
| 172 | m.MulticastAddress, |
| 173 | m.SuppressRoutersideProcessing, |
| 174 | m.QueriersRobustnessVariable, |
| 175 | m.QueriersQueryIntervalCode, |
| 176 | m.QQI()/time.Second, |
| 177 | m.NumberOfSources, |
| 178 | len(m.SourceAddresses), |
| 179 | m.SourceAddresses) |
| 180 | } |
| 181 | |
| 182 | // LayerType returns LayerTypeMLDv2MulticastListenerQuery. |
| 183 | func (*MLDv2MulticastListenerQueryMessage) LayerType() gopacket.LayerType { |
| 184 | return LayerTypeMLDv2MulticastListenerQuery |
| 185 | } |
| 186 | |
| 187 | // CanDecode returns the set of layer types that this DecodingLayer can decode. |
| 188 | func (*MLDv2MulticastListenerQueryMessage) CanDecode() gopacket.LayerClass { |
| 189 | return LayerTypeMLDv2MulticastListenerQuery |
| 190 | } |
| 191 | |
| 192 | // QQI calculates the Querier's Query Interval based on the QQIC |
| 193 | // according to https://tools.ietf.org/html/rfc3810#section-5.1.9 |
| 194 | func (m *MLDv2MulticastListenerQueryMessage) QQI() time.Duration { |
| 195 | data := m.QueriersQueryIntervalCode |
| 196 | if data < 128 { |
| 197 | return time.Second * time.Duration(data) |
| 198 | } |
| 199 | |
| 200 | exp := uint16(data) & 0x70 >> 4 |
| 201 | mant := uint16(data) & 0x0F |
| 202 | return time.Second * time.Duration(mant|0x1000<<(exp+3)) |
| 203 | } |
| 204 | |
| 205 | // SetQQI calculates and updates the Querier's Query Interval Code (QQIC) |
| 206 | // according to https://tools.ietf.org/html/rfc3810#section-5.1.9 |
| 207 | func (m *MLDv2MulticastListenerQueryMessage) SetQQI(d time.Duration) error { |
| 208 | if d < 0 { |
| 209 | m.QueriersQueryIntervalCode = 0 |
| 210 | return errors.New("QQI duration is negative") |
| 211 | } |
| 212 | |
| 213 | if d == 0 { |
| 214 | m.QueriersQueryIntervalCode = 0 |
| 215 | return nil |
| 216 | } |
| 217 | |
| 218 | dms := d / time.Second |
| 219 | if dms < 128 { |
| 220 | m.QueriersQueryIntervalCode = uint8(dms) |
| 221 | } |
| 222 | |
| 223 | if dms > 31744 { // mant=0xF, exp=0x7 |
| 224 | m.QueriersQueryIntervalCode = 0xFF |
| 225 | return fmt.Errorf("QQI duration %ds is, maximum allowed is 31744s", dms) |
| 226 | } |
| 227 | |
| 228 | value := uint16(dms) // ok, because 31744 < math.MaxUint16 |
| 229 | exp := uint8(7) |
| 230 | for mask := uint16(0x4000); exp > 0; exp-- { |
| 231 | if mask&value != 0 { |
| 232 | break |
| 233 | } |
| 234 | |
| 235 | mask >>= 1 |
| 236 | } |
| 237 | |
| 238 | mant := uint8(0x000F & (value >> (exp + 3))) |
| 239 | sig := uint8(0x10) |
| 240 | m.QueriersQueryIntervalCode = sig | exp<<4 | mant |
| 241 | |
| 242 | return nil |
| 243 | } |
| 244 | |
| 245 | // MaximumResponseDelay returns the Maximum Response Delay based on the |
| 246 | // Maximum Response Code according to |
| 247 | // https://tools.ietf.org/html/rfc3810#section-5.1.3 |
| 248 | func (m *MLDv2MulticastListenerQueryMessage) MaximumResponseDelay() time.Duration { |
| 249 | if m.MaximumResponseCode < 0x8000 { |
| 250 | return time.Duration(m.MaximumResponseCode) |
| 251 | } |
| 252 | |
| 253 | exp := m.MaximumResponseCode & 0x7000 >> 12 |
| 254 | mant := m.MaximumResponseCode & 0x0FFF |
| 255 | |
| 256 | return time.Millisecond * time.Duration(mant|0x1000<<(exp+3)) |
| 257 | } |
| 258 | |
| 259 | // SetMLDv2MaximumResponseDelay updates the Maximum Response Code according to |
| 260 | // https://tools.ietf.org/html/rfc3810#section-5.1.3 |
| 261 | func (m *MLDv2MulticastListenerQueryMessage) SetMLDv2MaximumResponseDelay(d time.Duration) error { |
| 262 | if d == 0 { |
| 263 | m.MaximumResponseCode = 0 |
| 264 | return nil |
| 265 | } |
| 266 | |
| 267 | if d < 0 { |
| 268 | return errors.New("maximum response delay must not be negative") |
| 269 | } |
| 270 | |
| 271 | dms := d / time.Millisecond |
| 272 | |
| 273 | if dms < 32768 { |
| 274 | m.MaximumResponseCode = uint16(dms) |
| 275 | } |
| 276 | |
| 277 | if dms > 4193280 { // mant=0xFFF, exp=0x7 |
| 278 | return fmt.Errorf("maximum response delay %dms is bigger the than maximum of 4193280ms", dms) |
| 279 | } |
| 280 | |
| 281 | value := uint32(dms) // ok, because 4193280 < math.MaxUint32 |
| 282 | exp := uint8(7) |
| 283 | for mask := uint32(0x40000000); exp > 0; exp-- { |
| 284 | if mask&value != 0 { |
| 285 | break |
| 286 | } |
| 287 | |
| 288 | mask >>= 1 |
| 289 | } |
| 290 | |
| 291 | mant := uint16(0x00000FFF & (value >> (exp + 3))) |
| 292 | sig := uint16(0x1000) |
| 293 | m.MaximumResponseCode = sig | uint16(exp)<<12 | mant |
| 294 | return nil |
| 295 | } |
| 296 | |
| 297 | // MLDv2MulticastListenerReportMessage is sent by an IP node to report the |
| 298 | // current multicast listening state, or changes therein. |
| 299 | // https://tools.ietf.org/html/rfc3810#section-5.2 |
| 300 | type MLDv2MulticastListenerReportMessage struct { |
| 301 | BaseLayer |
| 302 | // 5.2.3. Nr of Mcast Address Records |
| 303 | NumberOfMulticastAddressRecords uint16 |
| 304 | // 5.2.4. Multicast Address Record [i] |
| 305 | MulticastAddressRecords []MLDv2MulticastAddressRecord |
| 306 | } |
| 307 | |
| 308 | // DecodeFromBytes decodes the given bytes into this layer. |
| 309 | func (m *MLDv2MulticastListenerReportMessage) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { |
| 310 | if len(data) < 4 { |
| 311 | df.SetTruncated() |
| 312 | return errors.New("ICMP layer less than 4 bytes for Multicast Listener Report Message V2") |
| 313 | } |
| 314 | |
| 315 | // ignore data[0:2] as per RFC |
| 316 | // https://tools.ietf.org/html/rfc3810#section-5.2.1 |
| 317 | m.NumberOfMulticastAddressRecords = binary.BigEndian.Uint16(data[2:4]) |
| 318 | |
| 319 | begin := 4 |
| 320 | for i := uint16(0); i < m.NumberOfMulticastAddressRecords; i++ { |
| 321 | mar := MLDv2MulticastAddressRecord{} |
| 322 | read, err := mar.decode(data[begin:], df) |
| 323 | if err != nil { |
| 324 | return err |
| 325 | } |
| 326 | |
| 327 | m.MulticastAddressRecords = append(m.MulticastAddressRecords, mar) |
| 328 | |
| 329 | begin += read |
| 330 | } |
| 331 | |
| 332 | return nil |
| 333 | } |
| 334 | |
| 335 | // SerializeTo writes the serialized form of this layer into the |
| 336 | // SerializationBuffer, implementing gopacket.SerializableLayer. |
| 337 | // See the docs for gopacket.SerializableLayer for more info. |
| 338 | func (m *MLDv2MulticastListenerReportMessage) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { |
| 339 | lastItemIdx := len(m.MulticastAddressRecords) - 1 |
| 340 | for k := range m.MulticastAddressRecords { |
| 341 | i := lastItemIdx - k // reverse order |
| 342 | |
| 343 | err := m.MulticastAddressRecords[i].serializeTo(b, opts) |
| 344 | if err != nil { |
| 345 | return err |
| 346 | } |
| 347 | } |
| 348 | |
| 349 | if opts.FixLengths { |
| 350 | numberOfMAR := len(m.MulticastAddressRecords) |
| 351 | if numberOfMAR > math.MaxUint16 { |
| 352 | return fmt.Errorf( |
| 353 | "%d multicast address records added, but the maximum is 65535", |
| 354 | numberOfMAR) |
| 355 | } |
| 356 | |
| 357 | m.NumberOfMulticastAddressRecords = uint16(numberOfMAR) |
| 358 | } |
| 359 | |
| 360 | buf, err := b.PrependBytes(4) |
| 361 | if err != nil { |
| 362 | return err |
| 363 | } |
| 364 | |
| 365 | copy(buf[0:2], []byte{0x0, 0x0}) |
| 366 | binary.BigEndian.PutUint16(buf[2:4], m.NumberOfMulticastAddressRecords) |
| 367 | return nil |
| 368 | } |
| 369 | |
| 370 | // Sums this layer up nicely formatted |
| 371 | func (m *MLDv2MulticastListenerReportMessage) String() string { |
| 372 | return fmt.Sprintf( |
| 373 | "Number of Mcast Addr Records: %d (actual %d), Multicast Address Records: %+v", |
| 374 | m.NumberOfMulticastAddressRecords, |
| 375 | len(m.MulticastAddressRecords), |
| 376 | m.MulticastAddressRecords) |
| 377 | } |
| 378 | |
| 379 | // LayerType returns LayerTypeMLDv2MulticastListenerQuery. |
| 380 | func (*MLDv2MulticastListenerReportMessage) LayerType() gopacket.LayerType { |
| 381 | return LayerTypeMLDv2MulticastListenerReport |
| 382 | } |
| 383 | |
| 384 | // CanDecode returns the set of layer types that this DecodingLayer can decode. |
| 385 | func (*MLDv2MulticastListenerReportMessage) CanDecode() gopacket.LayerClass { |
| 386 | return LayerTypeMLDv2MulticastListenerReport |
| 387 | } |
| 388 | |
| 389 | // NextLayerType returns the layer type contained by this DecodingLayer. |
| 390 | func (*MLDv2MulticastListenerReportMessage) NextLayerType() gopacket.LayerType { |
| 391 | return gopacket.LayerTypePayload |
| 392 | } |
| 393 | |
| 394 | // MLDv2MulticastAddressRecordType holds the type of a |
| 395 | // Multicast Address Record, according to |
| 396 | // https://tools.ietf.org/html/rfc3810#section-5.2.5 and |
| 397 | // https://tools.ietf.org/html/rfc3810#section-5.2.12 |
| 398 | type MLDv2MulticastAddressRecordType uint8 |
| 399 | |
| 400 | const ( |
| 401 | // MLDv2MulticastAddressRecordTypeModeIsIncluded stands for |
| 402 | // MODE_IS_INCLUDE - indicates that the interface has a filter |
| 403 | // mode of INCLUDE for the specified multicast address. |
| 404 | MLDv2MulticastAddressRecordTypeModeIsIncluded MLDv2MulticastAddressRecordType = 1 |
| 405 | // MLDv2MulticastAddressRecordTypeModeIsExcluded stands for |
| 406 | // MODE_IS_EXCLUDE - indicates that the interface has a filter |
| 407 | // mode of EXCLUDE for the specified multicast address. |
| 408 | MLDv2MulticastAddressRecordTypeModeIsExcluded MLDv2MulticastAddressRecordType = 2 |
| 409 | // MLDv2MulticastAddressRecordTypeChangeToIncludeMode stands for |
| 410 | // CHANGE_TO_INCLUDE_MODE - indicates that the interface has |
| 411 | // changed to INCLUDE filter mode for the specified multicast |
| 412 | // address. |
| 413 | MLDv2MulticastAddressRecordTypeChangeToIncludeMode MLDv2MulticastAddressRecordType = 3 |
| 414 | // MLDv2MulticastAddressRecordTypeChangeToExcludeMode stands for |
| 415 | // CHANGE_TO_EXCLUDE_MODE - indicates that the interface has |
| 416 | // changed to EXCLUDE filter mode for the specified multicast |
| 417 | // address |
| 418 | MLDv2MulticastAddressRecordTypeChangeToExcludeMode MLDv2MulticastAddressRecordType = 4 |
| 419 | // MLDv2MulticastAddressRecordTypeAllowNewSources stands for |
| 420 | // ALLOW_NEW_SOURCES - indicates that the Source Address [i] |
| 421 | // fields in this Multicast Address Record contain a list of |
| 422 | // the additional sources that the node wishes to listen to, |
| 423 | // for packets sent to the specified multicast address. |
| 424 | MLDv2MulticastAddressRecordTypeAllowNewSources MLDv2MulticastAddressRecordType = 5 |
| 425 | // MLDv2MulticastAddressRecordTypeBlockOldSources stands for |
| 426 | // BLOCK_OLD_SOURCES - indicates that the Source Address [i] |
| 427 | // fields in this Multicast Address Record contain a list of |
| 428 | // the sources that the node no longer wishes to listen to, |
| 429 | // for packets sent to the specified multicast address. |
| 430 | MLDv2MulticastAddressRecordTypeBlockOldSources MLDv2MulticastAddressRecordType = 6 |
| 431 | ) |
| 432 | |
| 433 | // Human readable record types |
| 434 | // Naming follows https://tools.ietf.org/html/rfc3810#section-5.2.12 |
| 435 | func (m MLDv2MulticastAddressRecordType) String() string { |
| 436 | switch m { |
| 437 | case MLDv2MulticastAddressRecordTypeModeIsIncluded: |
| 438 | return "MODE_IS_INCLUDE" |
| 439 | case MLDv2MulticastAddressRecordTypeModeIsExcluded: |
| 440 | return "MODE_IS_EXCLUDE" |
| 441 | case MLDv2MulticastAddressRecordTypeChangeToIncludeMode: |
| 442 | return "CHANGE_TO_INCLUDE_MODE" |
| 443 | case MLDv2MulticastAddressRecordTypeChangeToExcludeMode: |
| 444 | return "CHANGE_TO_EXCLUDE_MODE" |
| 445 | case MLDv2MulticastAddressRecordTypeAllowNewSources: |
| 446 | return "ALLOW_NEW_SOURCES" |
| 447 | case MLDv2MulticastAddressRecordTypeBlockOldSources: |
| 448 | return "BLOCK_OLD_SOURCES" |
| 449 | default: |
| 450 | return fmt.Sprintf("UNKNOWN(%d)", m) |
| 451 | } |
| 452 | } |
| 453 | |
| 454 | // MLDv2MulticastAddressRecord contains information on the sender listening to a |
| 455 | // single multicast address on the interface the report is sent. |
| 456 | // https://tools.ietf.org/html/rfc3810#section-5.2.4 |
| 457 | type MLDv2MulticastAddressRecord struct { |
| 458 | // 5.2.5. Record Type |
| 459 | RecordType MLDv2MulticastAddressRecordType |
| 460 | // 5.2.6. Auxiliary Data Length (number of 32-bit words) |
| 461 | AuxDataLen uint8 |
| 462 | // 5.2.7. Number Of Sources (N) |
| 463 | N uint16 |
| 464 | // 5.2.8. Multicast Address |
| 465 | MulticastAddress net.IP |
| 466 | // 5.2.9 Source Address [i] |
| 467 | SourceAddresses []net.IP |
| 468 | // 5.2.10 Auxiliary Data |
| 469 | AuxiliaryData []byte |
| 470 | } |
| 471 | |
| 472 | // decodes a multicast address record from bytes |
| 473 | func (m *MLDv2MulticastAddressRecord) decode(data []byte, df gopacket.DecodeFeedback) (int, error) { |
| 474 | if len(data) < 4 { |
| 475 | df.SetTruncated() |
| 476 | return 0, errors.New( |
| 477 | "Multicast Listener Report Message V2 layer less than 4 bytes for Multicast Address Record") |
| 478 | } |
| 479 | |
| 480 | m.RecordType = MLDv2MulticastAddressRecordType(data[0]) |
| 481 | m.AuxDataLen = data[1] |
| 482 | m.N = binary.BigEndian.Uint16(data[2:4]) |
| 483 | m.MulticastAddress = data[4:20] |
| 484 | |
| 485 | for i := uint16(0); i < m.N; i++ { |
| 486 | begin := 20 + (int(i) * 16) |
| 487 | end := begin + 16 |
| 488 | |
| 489 | if len(data) < end { |
| 490 | df.SetTruncated() |
| 491 | return begin, fmt.Errorf( |
| 492 | "Multicast Listener Report Message V2 layer less than %d bytes for Multicast Address Record", end) |
| 493 | } |
| 494 | |
| 495 | m.SourceAddresses = append(m.SourceAddresses, data[begin:end]) |
| 496 | } |
| 497 | |
| 498 | expectedLengthWithouAuxData := 20 + (int(m.N) * 16) |
| 499 | expectedTotalLength := (int(m.AuxDataLen) * 4) + expectedLengthWithouAuxData // *4 because AuxDataLen are 32bit words |
| 500 | if len(data) < expectedTotalLength { |
| 501 | return expectedLengthWithouAuxData, fmt.Errorf( |
| 502 | "Multicast Listener Report Message V2 layer less than %d bytes for Multicast Address Record", |
| 503 | expectedLengthWithouAuxData) |
| 504 | } |
| 505 | |
| 506 | m.AuxiliaryData = data[expectedLengthWithouAuxData:expectedTotalLength] |
| 507 | |
| 508 | return expectedTotalLength, nil |
| 509 | } |
| 510 | |
| 511 | // String sums this layer up nicely formatted |
| 512 | func (m *MLDv2MulticastAddressRecord) String() string { |
| 513 | return fmt.Sprintf( |
| 514 | "RecordType: %d (%s), AuxDataLen: %d [32-bit words], N: %d, Multicast Address: %s, SourceAddresses: %s, Auxiliary Data: %#x", |
| 515 | m.RecordType, |
| 516 | m.RecordType.String(), |
| 517 | m.AuxDataLen, |
| 518 | m.N, |
| 519 | m.MulticastAddress.To16(), |
| 520 | m.SourceAddresses, |
| 521 | m.AuxiliaryData) |
| 522 | } |
| 523 | |
| 524 | // serializes a multicast address record |
| 525 | func (m *MLDv2MulticastAddressRecord) serializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { |
| 526 | if err := m.serializeAuxiliaryDataTo(b, opts); err != nil { |
| 527 | return err |
| 528 | } |
| 529 | |
| 530 | if err := m.serializeSourceAddressesTo(b, opts); err != nil { |
| 531 | return err |
| 532 | } |
| 533 | |
| 534 | buf, err := b.PrependBytes(20) |
| 535 | if err != nil { |
| 536 | return err |
| 537 | } |
| 538 | |
| 539 | buf[0] = uint8(m.RecordType) |
| 540 | buf[1] = m.AuxDataLen |
| 541 | binary.BigEndian.PutUint16(buf[2:4], m.N) |
| 542 | |
| 543 | ma16 := m.MulticastAddress.To16() |
| 544 | if ma16 == nil { |
| 545 | return fmt.Errorf("invalid multicast address '%s'", m.MulticastAddress) |
| 546 | } |
| 547 | copy(buf[4:20], ma16) |
| 548 | |
| 549 | return nil |
| 550 | } |
| 551 | |
| 552 | // serializes the auxiliary data of a multicast address record |
| 553 | func (m *MLDv2MulticastAddressRecord) serializeAuxiliaryDataTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { |
| 554 | if remainder := len(m.AuxiliaryData) % 4; remainder != 0 { |
| 555 | zeroWord := []byte{0x0, 0x0, 0x0, 0x0} |
| 556 | m.AuxiliaryData = append(m.AuxiliaryData, zeroWord[:remainder]...) |
| 557 | } |
| 558 | |
| 559 | if opts.FixLengths { |
| 560 | auxDataLen := len(m.AuxiliaryData) / 4 |
| 561 | |
| 562 | if auxDataLen > math.MaxUint8 { |
| 563 | return fmt.Errorf("auxilary data is %d 32-bit words, but the maximum is 255 32-bit words", auxDataLen) |
| 564 | } |
| 565 | |
| 566 | m.AuxDataLen = uint8(auxDataLen) |
| 567 | } |
| 568 | |
| 569 | buf, err := b.PrependBytes(len(m.AuxiliaryData)) |
| 570 | if err != nil { |
| 571 | return err |
| 572 | } |
| 573 | |
| 574 | copy(buf, m.AuxiliaryData) |
| 575 | return nil |
| 576 | } |
| 577 | |
| 578 | // serializes the source addresses of a multicast address record preserving the order |
| 579 | func (m *MLDv2MulticastAddressRecord) serializeSourceAddressesTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { |
| 580 | if opts.FixLengths { |
| 581 | numberOfSourceAddresses := len(m.SourceAddresses) |
| 582 | |
| 583 | if numberOfSourceAddresses > math.MaxUint16 { |
| 584 | return fmt.Errorf( |
| 585 | "%d source addresses added, but the maximum is 65535", |
| 586 | numberOfSourceAddresses) |
| 587 | } |
| 588 | |
| 589 | m.N = uint16(numberOfSourceAddresses) |
| 590 | } |
| 591 | |
| 592 | lastItemIdx := len(m.SourceAddresses) - 1 |
| 593 | for k := range m.SourceAddresses { |
| 594 | i := lastItemIdx - k // reverse order |
| 595 | |
| 596 | buf, err := b.PrependBytes(16) |
| 597 | if err != nil { |
| 598 | return err |
| 599 | } |
| 600 | |
| 601 | sa16 := m.SourceAddresses[i].To16() |
| 602 | if sa16 == nil { |
| 603 | return fmt.Errorf("invalid source address [%d] '%s'", i, m.SourceAddresses[i]) |
| 604 | } |
| 605 | copy(buf, sa16) |
| 606 | } |
| 607 | |
| 608 | return nil |
| 609 | } |
| 610 | |
| 611 | func decodeMLDv2MulticastListenerReport(data []byte, p gopacket.PacketBuilder) error { |
| 612 | m := &MLDv2MulticastListenerReportMessage{} |
| 613 | return decodingLayerDecoder(m, data, p) |
| 614 | } |
| 615 | |
| 616 | func decodeMLDv2MulticastListenerQuery(data []byte, p gopacket.PacketBuilder) error { |
| 617 | m := &MLDv2MulticastListenerQueryMessage{} |
| 618 | return decodingLayerDecoder(m, data, p) |
| 619 | } |