github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/tcpip/network/internal/ip/generic_multicast_protocol.go (about) 1 // Copyright 2020 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 ip 16 17 import ( 18 "fmt" 19 "math/rand" 20 "time" 21 22 "github.com/SagerNet/gvisor/pkg/sync" 23 "github.com/SagerNet/gvisor/pkg/tcpip" 24 ) 25 26 // hostState is the state a host may be in for a multicast group. 27 type hostState int 28 29 // The states below are generic across IGMPv2 (RFC 2236 section 6) and MLDv1 30 // (RFC 2710 section 5). Even though the states are generic across both IGMPv2 31 // and MLDv1, IGMPv2 terminology will be used. 32 // 33 // ______________receive query______________ 34 // | | 35 // | _____send or receive report_____ | 36 // | | | | 37 // V | V | 38 // +-------+ +-----------+ +------------+ +-------------------+ +--------+ | 39 // | Non-M | | Pending-M | | Delaying-M | | Queued Delaying-M | | Idle-M | - 40 // +-------+ +-----------+ +------------+ +-------------------+ +--------+ 41 // | ^ | ^ | ^ | ^ 42 // | | | | | | | | 43 // ---------- ------- ---------- ------------- 44 // initialize new send inital fail to send send or receive 45 // group membership report delayed report report 46 // 47 // Not shown in the diagram above, but any state may transition into the non 48 // member state when a group is left. 49 const ( 50 // nonMember is the "'Non-Member' state, when the host does not belong to the 51 // group on the interface. This is the initial state for all memberships on 52 // all network interfaces; it requires no storage in the host." 53 // 54 // 'Non-Listener' is the MLDv1 term used to describe this state. 55 // 56 // This state is used to keep track of groups that have been joined locally, 57 // but without advertising the membership to the network. 58 nonMember hostState = iota 59 60 // pendingMember is a newly joined member that is waiting to successfully send 61 // the initial set of reports. 62 // 63 // This is not an RFC defined state; it is an implementation specific state to 64 // track that the initial report needs to be sent. 65 // 66 // MAY NOT transition to the idle member state from this state. 67 pendingMember 68 69 // delayingMember is the "'Delaying Member' state, when the host belongs to 70 // the group on the interface and has a report delay timer running for that 71 // membership." 72 // 73 // 'Delaying Listener' is the MLDv1 term used to describe this state. 74 delayingMember 75 76 // queuedDelayingMember is a delayingMember that failed to send a report after 77 // its delayed report timer fired. Hosts in this state are waiting to attempt 78 // retransmission of the delayed report. 79 // 80 // This is not an RFC defined state; it is an implementation specific state to 81 // track that the delayed report needs to be sent. 82 // 83 // May transition to idle member if a report is received for a group. 84 queuedDelayingMember 85 86 // idleMember is the "Idle Member" state, when the host belongs to the group 87 // on the interface and does not have a report delay timer running for that 88 // membership. 89 // 90 // 'Idle Listener' is the MLDv1 term used to describe this state. 91 idleMember 92 ) 93 94 func (s hostState) isDelayingMember() bool { 95 switch s { 96 case nonMember, pendingMember, idleMember: 97 return false 98 case delayingMember, queuedDelayingMember: 99 return true 100 default: 101 panic(fmt.Sprintf("unrecognized host state = %d", s)) 102 } 103 } 104 105 // multicastGroupState holds the Generic Multicast Protocol state for a 106 // multicast group. 107 type multicastGroupState struct { 108 // joins is the number of times the group has been joined. 109 joins uint64 110 111 // state holds the host's state for the group. 112 state hostState 113 114 // lastToSendReport is true if we sent the last report for the group. It is 115 // used to track whether there are other hosts on the subnet that are also 116 // members of the group. 117 // 118 // Defined in RFC 2236 section 6 page 9 for IGMPv2 and RFC 2710 section 5 page 119 // 8 for MLDv1. 120 lastToSendReport bool 121 122 // delayedReportJob is used to delay sending responses to membership report 123 // messages in order to reduce duplicate reports from multiple hosts on the 124 // interface. 125 // 126 // Must not be nil. 127 delayedReportJob *tcpip.Job 128 129 // delyedReportJobFiresAt is the time when the delayed report job will fire. 130 // 131 // A zero value indicates that the job is not scheduled. 132 delayedReportJobFiresAt time.Time 133 } 134 135 func (m *multicastGroupState) cancelDelayedReportJob() { 136 m.delayedReportJob.Cancel() 137 m.delayedReportJobFiresAt = time.Time{} 138 } 139 140 // GenericMulticastProtocolOptions holds options for the generic multicast 141 // protocol. 142 type GenericMulticastProtocolOptions struct { 143 // Rand is the source of random numbers. 144 Rand *rand.Rand 145 146 // Clock is the clock used to create timers. 147 Clock tcpip.Clock 148 149 // Protocol is the implementation of the variant of multicast group protocol 150 // in use. 151 Protocol MulticastGroupProtocol 152 153 // MaxUnsolicitedReportDelay is the maximum amount of time to wait between 154 // transmitting unsolicited reports. 155 // 156 // Unsolicited reports are transmitted when a group is newly joined. 157 MaxUnsolicitedReportDelay time.Duration 158 } 159 160 // MulticastGroupProtocol is a multicast group protocol whose core state machine 161 // can be represented by GenericMulticastProtocolState. 162 type MulticastGroupProtocol interface { 163 // Enabled indicates whether the generic multicast protocol will be 164 // performed. 165 // 166 // When enabled, the protocol may transmit report and leave messages when 167 // joining and leaving multicast groups respectively, and handle incoming 168 // packets. 169 // 170 // When disabled, the protocol will still keep track of locally joined groups, 171 // it just won't transmit and handle packets, or update groups' state. 172 Enabled() bool 173 174 // SendReport sends a multicast report for the specified group address. 175 // 176 // Returns false if the caller should queue the report to be sent later. Note, 177 // returning false does not mean that the receiver hit an error. 178 SendReport(groupAddress tcpip.Address) (sent bool, err tcpip.Error) 179 180 // SendLeave sends a multicast leave for the specified group address. 181 SendLeave(groupAddress tcpip.Address) tcpip.Error 182 183 // ShouldPerformProtocol returns true iff the protocol should be performed for 184 // the specified group. 185 ShouldPerformProtocol(tcpip.Address) bool 186 } 187 188 // GenericMulticastProtocolState is the per interface generic multicast protocol 189 // state. 190 // 191 // There is actually no protocol named "Generic Multicast Protocol". Instead, 192 // the term used to refer to a generic multicast protocol that applies to both 193 // IPv4 and IPv6. Specifically, Generic Multicast Protocol is the core state 194 // machine of IGMPv2 as defined by RFC 2236 and MLDv1 as defined by RFC 2710. 195 // 196 // Callers must synchronize accesses to the generic multicast protocol state; 197 // GenericMulticastProtocolState obtains no locks in any of its methods. The 198 // only exception to this is GenericMulticastProtocolState's timer/job callbacks 199 // which will obtain the lock provided to the GenericMulticastProtocolState when 200 // it is initialized. 201 // 202 // GenericMulticastProtocolState.Init MUST be called before calling any of 203 // the methods on GenericMulticastProtocolState. 204 // 205 // GenericMulticastProtocolState.MakeAllNonMemberLocked MUST be called when the 206 // multicast group protocol is disabled so that leave messages may be sent. 207 type GenericMulticastProtocolState struct { 208 // Do not allow overwriting this state. 209 _ sync.NoCopy 210 211 opts GenericMulticastProtocolOptions 212 213 // memberships holds group addresses and their associated state. 214 memberships map[tcpip.Address]multicastGroupState 215 216 // protocolMU is the mutex used to protect the protocol. 217 protocolMU *sync.RWMutex 218 } 219 220 // Init initializes the Generic Multicast Protocol state. 221 // 222 // Must only be called once for the lifetime of g; Init will panic if it is 223 // called twice. 224 // 225 // The GenericMulticastProtocolState will only grab the lock when timers/jobs 226 // fire. 227 // 228 // Note: the methods on opts.Protocol will always be called while protocolMU is 229 // held. 230 func (g *GenericMulticastProtocolState) Init(protocolMU *sync.RWMutex, opts GenericMulticastProtocolOptions) { 231 if g.memberships != nil { 232 panic("attempted to initialize generic membership protocol state twice") 233 } 234 235 *g = GenericMulticastProtocolState{ 236 opts: opts, 237 memberships: make(map[tcpip.Address]multicastGroupState), 238 protocolMU: protocolMU, 239 } 240 } 241 242 // MakeAllNonMemberLocked transitions all groups to the non-member state. 243 // 244 // The groups will still be considered joined locally. 245 // 246 // MUST be called when the multicast group protocol is disabled. 247 // 248 // Precondition: g.protocolMU must be locked. 249 func (g *GenericMulticastProtocolState) MakeAllNonMemberLocked() { 250 if !g.opts.Protocol.Enabled() { 251 return 252 } 253 254 for groupAddress, info := range g.memberships { 255 g.transitionToNonMemberLocked(groupAddress, &info) 256 g.memberships[groupAddress] = info 257 } 258 } 259 260 // InitializeGroupsLocked initializes each group, as if they were newly joined 261 // but without affecting the groups' join count. 262 // 263 // Must only be called after calling MakeAllNonMember as a group should not be 264 // initialized while it is not in the non-member state. 265 // 266 // Precondition: g.protocolMU must be locked. 267 func (g *GenericMulticastProtocolState) InitializeGroupsLocked() { 268 if !g.opts.Protocol.Enabled() { 269 return 270 } 271 272 for groupAddress, info := range g.memberships { 273 g.initializeNewMemberLocked(groupAddress, &info) 274 g.memberships[groupAddress] = info 275 } 276 } 277 278 // SendQueuedReportsLocked attempts to send reports for groups that failed to 279 // send reports during their last attempt. 280 // 281 // Precondition: g.protocolMU must be locked. 282 func (g *GenericMulticastProtocolState) SendQueuedReportsLocked() { 283 for groupAddress, info := range g.memberships { 284 switch info.state { 285 case nonMember, delayingMember, idleMember: 286 case pendingMember: 287 // pendingMembers failed to send their initial unsolicited report so try 288 // to send the report and queue the extra unsolicited reports. 289 g.maybeSendInitialReportLocked(groupAddress, &info) 290 case queuedDelayingMember: 291 // queuedDelayingMembers failed to send their delayed reports so try to 292 // send the report and transition them to the idle state. 293 g.maybeSendDelayedReportLocked(groupAddress, &info) 294 default: 295 panic(fmt.Sprintf("unrecognized host state = %d", info.state)) 296 } 297 g.memberships[groupAddress] = info 298 } 299 } 300 301 // JoinGroupLocked handles joining a new group. 302 // 303 // Precondition: g.protocolMU must be locked. 304 func (g *GenericMulticastProtocolState) JoinGroupLocked(groupAddress tcpip.Address) { 305 if info, ok := g.memberships[groupAddress]; ok { 306 // The group has already been joined. 307 info.joins++ 308 g.memberships[groupAddress] = info 309 return 310 } 311 312 info := multicastGroupState{ 313 // Since we just joined the group, its count is 1. 314 joins: 1, 315 // The state will be updated below, if required. 316 state: nonMember, 317 lastToSendReport: false, 318 delayedReportJob: tcpip.NewJob(g.opts.Clock, g.protocolMU, func() { 319 if !g.opts.Protocol.Enabled() { 320 panic(fmt.Sprintf("delayed report job fired for group %s while the multicast group protocol is disabled", groupAddress)) 321 } 322 323 info, ok := g.memberships[groupAddress] 324 if !ok { 325 panic(fmt.Sprintf("expected to find group state for group = %s", groupAddress)) 326 } 327 328 g.maybeSendDelayedReportLocked(groupAddress, &info) 329 g.memberships[groupAddress] = info 330 }), 331 } 332 333 if g.opts.Protocol.Enabled() { 334 g.initializeNewMemberLocked(groupAddress, &info) 335 } 336 337 g.memberships[groupAddress] = info 338 } 339 340 // IsLocallyJoinedRLocked returns true if the group is locally joined. 341 // 342 // Precondition: g.protocolMU must be read locked. 343 func (g *GenericMulticastProtocolState) IsLocallyJoinedRLocked(groupAddress tcpip.Address) bool { 344 _, ok := g.memberships[groupAddress] 345 return ok 346 } 347 348 // LeaveGroupLocked handles leaving the group. 349 // 350 // Returns false if the group is not currently joined. 351 // 352 // Precondition: g.protocolMU must be locked. 353 func (g *GenericMulticastProtocolState) LeaveGroupLocked(groupAddress tcpip.Address) bool { 354 info, ok := g.memberships[groupAddress] 355 if !ok { 356 return false 357 } 358 359 if info.joins == 0 { 360 panic(fmt.Sprintf("tried to leave group %s with a join count of 0", groupAddress)) 361 } 362 info.joins-- 363 if info.joins != 0 { 364 // If we still have outstanding joins, then do nothing further. 365 g.memberships[groupAddress] = info 366 return true 367 } 368 369 g.transitionToNonMemberLocked(groupAddress, &info) 370 delete(g.memberships, groupAddress) 371 return true 372 } 373 374 // HandleQueryLocked handles a query message with the specified maximum response 375 // time. 376 // 377 // If the group address is unspecified, then reports will be scheduled for all 378 // joined groups. 379 // 380 // Report(s) will be scheduled to be sent after a random duration between 0 and 381 // the maximum response time. 382 // 383 // Precondition: g.protocolMU must be locked. 384 func (g *GenericMulticastProtocolState) HandleQueryLocked(groupAddress tcpip.Address, maxResponseTime time.Duration) { 385 if !g.opts.Protocol.Enabled() { 386 return 387 } 388 389 // As per RFC 2236 section 2.4 (for IGMPv2), 390 // 391 // In a Membership Query message, the group address field is set to zero 392 // when sending a General Query, and set to the group address being 393 // queried when sending a Group-Specific Query. 394 // 395 // As per RFC 2710 section 3.6 (for MLDv1), 396 // 397 // In a Query message, the Multicast Address field is set to zero when 398 // sending a General Query, and set to a specific IPv6 multicast address 399 // when sending a Multicast-Address-Specific Query. 400 if groupAddress.Unspecified() { 401 // This is a general query as the group address is unspecified. 402 for groupAddress, info := range g.memberships { 403 g.setDelayTimerForAddressRLocked(groupAddress, &info, maxResponseTime) 404 g.memberships[groupAddress] = info 405 } 406 } else if info, ok := g.memberships[groupAddress]; ok { 407 g.setDelayTimerForAddressRLocked(groupAddress, &info, maxResponseTime) 408 g.memberships[groupAddress] = info 409 } 410 } 411 412 // HandleReportLocked handles a report message. 413 // 414 // If the report is for a joined group, any active delayed report will be 415 // cancelled and the host state for the group transitions to idle. 416 // 417 // Precondition: g.protocolMU must be locked. 418 func (g *GenericMulticastProtocolState) HandleReportLocked(groupAddress tcpip.Address) { 419 if !g.opts.Protocol.Enabled() { 420 return 421 } 422 423 // As per RFC 2236 section 3 pages 3-4 (for IGMPv2), 424 // 425 // If the host receives another host's Report (version 1 or 2) while it has 426 // a timer running, it stops its timer for the specified group and does not 427 // send a Report 428 // 429 // As per RFC 2710 section 4 page 6 (for MLDv1), 430 // 431 // If a node receives another node's Report from an interface for a 432 // multicast address while it has a timer running for that same address 433 // on that interface, it stops its timer and does not send a Report for 434 // that address, thus suppressing duplicate reports on the link. 435 if info, ok := g.memberships[groupAddress]; ok && info.state.isDelayingMember() { 436 info.cancelDelayedReportJob() 437 info.lastToSendReport = false 438 info.state = idleMember 439 g.memberships[groupAddress] = info 440 } 441 } 442 443 // initializeNewMemberLocked initializes a new group membership. 444 // 445 // Precondition: g.protocolMU must be locked. 446 func (g *GenericMulticastProtocolState) initializeNewMemberLocked(groupAddress tcpip.Address, info *multicastGroupState) { 447 if info.state != nonMember { 448 panic(fmt.Sprintf("host must be in non-member state to be initialized; group = %s, state = %d", groupAddress, info.state)) 449 } 450 451 info.lastToSendReport = false 452 453 if !g.opts.Protocol.ShouldPerformProtocol(groupAddress) { 454 info.state = idleMember 455 return 456 } 457 458 info.state = pendingMember 459 g.maybeSendInitialReportLocked(groupAddress, info) 460 } 461 462 // maybeSendInitialReportLocked attempts to start transmission of the initial 463 // set of reports after newly joining a group. 464 // 465 // Host must be in pending member state. 466 // 467 // Precondition: g.protocolMU must be locked. 468 func (g *GenericMulticastProtocolState) maybeSendInitialReportLocked(groupAddress tcpip.Address, info *multicastGroupState) { 469 if info.state != pendingMember { 470 panic(fmt.Sprintf("host must be in pending member state to send initial reports; group = %s, state = %d", groupAddress, info.state)) 471 } 472 473 // As per RFC 2236 section 3 page 5 (for IGMPv2), 474 // 475 // When a host joins a multicast group, it should immediately transmit an 476 // unsolicited Version 2 Membership Report for that group" ... "it is 477 // recommended that it be repeated". 478 // 479 // As per RFC 2710 section 4 page 6 (for MLDv1), 480 // 481 // When a node starts listening to a multicast address on an interface, 482 // it should immediately transmit an unsolicited Report for that address 483 // on that interface, in case it is the first listener on the link. To 484 // cover the possibility of the initial Report being lost or damaged, it 485 // is recommended that it be repeated once or twice after short delays 486 // [Unsolicited Report Interval]. 487 // 488 // TODO(github.com/SagerNet/issue/4901): Support a configurable number of initial 489 // unsolicited reports. 490 sent, err := g.opts.Protocol.SendReport(groupAddress) 491 if err == nil && sent { 492 info.lastToSendReport = true 493 g.setDelayTimerForAddressRLocked(groupAddress, info, g.opts.MaxUnsolicitedReportDelay) 494 } 495 } 496 497 // maybeSendDelayedReportLocked attempts to send the delayed report. 498 // 499 // Host must be in pending, delaying or queued delaying member state. 500 // 501 // Precondition: g.protocolMU must be locked. 502 func (g *GenericMulticastProtocolState) maybeSendDelayedReportLocked(groupAddress tcpip.Address, info *multicastGroupState) { 503 if !info.state.isDelayingMember() { 504 panic(fmt.Sprintf("host must be in delaying or queued delaying member state to send delayed reports; group = %s, state = %d", groupAddress, info.state)) 505 } 506 507 sent, err := g.opts.Protocol.SendReport(groupAddress) 508 if err == nil && sent { 509 info.lastToSendReport = true 510 info.state = idleMember 511 } else { 512 info.state = queuedDelayingMember 513 } 514 } 515 516 // maybeSendLeave attempts to send a leave message. 517 func (g *GenericMulticastProtocolState) maybeSendLeave(groupAddress tcpip.Address, lastToSendReport bool) { 518 if !g.opts.Protocol.Enabled() || !lastToSendReport { 519 return 520 } 521 522 if !g.opts.Protocol.ShouldPerformProtocol(groupAddress) { 523 return 524 } 525 526 // Okay to ignore the error here as if packet write failed, the multicast 527 // routers will eventually drop our membership anyways. If the interface is 528 // being disabled or removed, the generic multicast protocol's should be 529 // cleared eventually. 530 // 531 // As per RFC 2236 section 3 page 5 (for IGMPv2), 532 // 533 // When a router receives a Report, it adds the group being reported to 534 // the list of multicast group memberships on the network on which it 535 // received the Report and sets the timer for the membership to the 536 // [Group Membership Interval]. Repeated Reports refresh the timer. If 537 // no Reports are received for a particular group before this timer has 538 // expired, the router assumes that the group has no local members and 539 // that it need not forward remotely-originated multicasts for that 540 // group onto the attached network. 541 // 542 // As per RFC 2710 section 4 page 5 (for MLDv1), 543 // 544 // When a router receives a Report from a link, if the reported address 545 // is not already present in the router's list of multicast address 546 // having listeners on that link, the reported address is added to the 547 // list, its timer is set to [Multicast Listener Interval], and its 548 // appearance is made known to the router's multicast routing component. 549 // If a Report is received for a multicast address that is already 550 // present in the router's list, the timer for that address is reset to 551 // [Multicast Listener Interval]. If an address's timer expires, it is 552 // assumed that there are no longer any listeners for that address 553 // present on the link, so it is deleted from the list and its 554 // disappearance is made known to the multicast routing component. 555 // 556 // The requirement to send a leave message is also optional (it MAY be 557 // skipped): 558 // 559 // As per RFC 2236 section 6 page 8 (for IGMPv2), 560 // 561 // "send leave" for the group on the interface. If the interface 562 // state says the Querier is running IGMPv1, this action SHOULD be 563 // skipped. If the flag saying we were the last host to report is 564 // cleared, this action MAY be skipped. The Leave Message is sent to 565 // the ALL-ROUTERS group (224.0.0.2). 566 // 567 // As per RFC 2710 section 5 page 8 (for MLDv1), 568 // 569 // "send done" for the address on the interface. If the flag saying 570 // we were the last node to report is cleared, this action MAY be 571 // skipped. The Done message is sent to the link-scope all-routers 572 // address (FF02::2). 573 _ = g.opts.Protocol.SendLeave(groupAddress) 574 } 575 576 // transitionToNonMemberLocked transitions the given multicast group the the 577 // non-member/listener state. 578 // 579 // Precondition: g.protocolMU must be locked. 580 func (g *GenericMulticastProtocolState) transitionToNonMemberLocked(groupAddress tcpip.Address, info *multicastGroupState) { 581 if info.state == nonMember { 582 return 583 } 584 585 info.cancelDelayedReportJob() 586 g.maybeSendLeave(groupAddress, info.lastToSendReport) 587 info.lastToSendReport = false 588 info.state = nonMember 589 } 590 591 // setDelayTimerForAddressRLocked sets timer to send a delay report. 592 // 593 // Precondition: g.protocolMU MUST be read locked. 594 func (g *GenericMulticastProtocolState) setDelayTimerForAddressRLocked(groupAddress tcpip.Address, info *multicastGroupState, maxResponseTime time.Duration) { 595 if info.state == nonMember { 596 return 597 } 598 599 if !g.opts.Protocol.ShouldPerformProtocol(groupAddress) { 600 return 601 } 602 603 // As per RFC 2236 section 3 page 3 (for IGMPv2), 604 // 605 // If a timer for the group is already unning, it is reset to the random 606 // value only if the requested Max Response Time is less than the remaining 607 // value of the running timer. 608 // 609 // As per RFC 2710 section 4 page 5 (for MLDv1), 610 // 611 // If a timer for any address is already running, it is reset to the new 612 // random value only if the requested Maximum Response Delay is less than 613 // the remaining value of the running timer. 614 now := g.opts.Clock.Now() 615 if info.state == delayingMember { 616 if info.delayedReportJobFiresAt.IsZero() { 617 panic(fmt.Sprintf("delayed report unscheduled while in the delaying member state; group = %s", groupAddress)) 618 } 619 620 if info.delayedReportJobFiresAt.Sub(now) <= maxResponseTime { 621 // The timer is scheduled to fire before the maximum response time so we 622 // leave our timer as is. 623 return 624 } 625 } 626 627 info.state = delayingMember 628 info.cancelDelayedReportJob() 629 maxResponseTime = g.calculateDelayTimerDuration(maxResponseTime) 630 info.delayedReportJob.Schedule(maxResponseTime) 631 info.delayedReportJobFiresAt = now.Add(maxResponseTime) 632 } 633 634 // calculateDelayTimerDuration returns a random time between (0, maxRespTime]. 635 func (g *GenericMulticastProtocolState) calculateDelayTimerDuration(maxRespTime time.Duration) time.Duration { 636 // As per RFC 2236 section 3 page 3 (for IGMPv2), 637 // 638 // When a host receives a Group-Specific Query, it sets a delay timer to a 639 // random value selected from the range (0, Max Response Time]... 640 // 641 // As per RFC 2710 section 4 page 6 (for MLDv1), 642 // 643 // When a node receives a Multicast-Address-Specific Query, if it is 644 // listening to the queried Multicast Address on the interface from 645 // which the Query was received, it sets a delay timer for that address 646 // to a random value selected from the range [0, Maximum Response Delay], 647 // as above. 648 if maxRespTime == 0 { 649 return 0 650 } 651 return time.Duration(g.opts.Rand.Int63n(int64(maxRespTime))) 652 }