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 header
16 17 import (
18 "encoding/binary"
19 "fmt"
20 "time"
21 22 "gvisor.dev/gvisor/pkg/tcpip"
23 "gvisor.dev/gvisor/pkg/tcpip/checksum"
24 )
25 26 // IGMP represents an IGMP header stored in a byte array.
27 type IGMP []byte
28 29 // IGMP implements `Transport`.
30 var _ Transport = (*IGMP)(nil)
31 32 const (
33 // IGMPMinimumSize is the minimum size of a valid IGMP packet in bytes,
34 // as per RFC 2236, Section 2, Page 2.
35 IGMPMinimumSize = 8
36 37 // IGMPQueryMinimumSize is the minimum size of a valid Membership Query
38 // Message in bytes, as per RFC 2236, Section 2, Page 2.
39 IGMPQueryMinimumSize = 8
40 41 // IGMPReportMinimumSize is the minimum size of a valid Report Message in
42 // bytes, as per RFC 2236, Section 2, Page 2.
43 IGMPReportMinimumSize = 8
44 45 // IGMPLeaveMessageMinimumSize is the minimum size of a valid Leave Message
46 // in bytes, as per RFC 2236, Section 2, Page 2.
47 IGMPLeaveMessageMinimumSize = 8
48 49 // IGMPTTL is the TTL for all IGMP messages, as per RFC 2236, Section 3, Page
50 // 3.
51 IGMPTTL = 1
52 53 // igmpTypeOffset defines the offset of the type field in an IGMP message.
54 igmpTypeOffset = 0
55 56 // igmpMaxRespTimeOffset defines the offset of the MaxRespTime field in an
57 // IGMP message.
58 igmpMaxRespTimeOffset = 1
59 60 // igmpChecksumOffset defines the offset of the checksum field in an IGMP
61 // message.
62 igmpChecksumOffset = 2
63 64 // igmpGroupAddressOffset defines the offset of the Group Address field in an
65 // IGMP message.
66 igmpGroupAddressOffset = 4
67 68 // IGMPProtocolNumber is IGMP's transport protocol number.
69 IGMPProtocolNumber tcpip.TransportProtocolNumber = 2
70 )
71 72 // IGMPType is the IGMP type field as per RFC 2236.
73 type IGMPType byte
74 75 // Values for the IGMP Type described in RFC 2236 Section 2.1, Page 2.
76 // Descriptions below come from there.
77 const (
78 // IGMPMembershipQuery indicates that the message type is Membership Query.
79 // "There are two sub-types of Membership Query messages:
80 // - General Query, used to learn which groups have members on an
81 // attached network.
82 // - Group-Specific Query, used to learn if a particular group
83 // has any members on an attached network.
84 // These two messages are differentiated by the Group Address, as
85 // described in section 1.4 ."
86 IGMPMembershipQuery IGMPType = 0x11
87 // IGMPv1MembershipReport indicates that the message is a Membership Report
88 // generated by a host using the IGMPv1 protocol: "an additional type of
89 // message, for backwards-compatibility with IGMPv1"
90 IGMPv1MembershipReport IGMPType = 0x12
91 // IGMPv2MembershipReport indicates that the Message type is a Membership
92 // Report generated by a host using the IGMPv2 protocol.
93 IGMPv2MembershipReport IGMPType = 0x16
94 // IGMPLeaveGroup indicates that the message type is a Leave Group
95 // notification message.
96 IGMPLeaveGroup IGMPType = 0x17
97 // IGMPv3MembershipReport indicates that the message type is a IGMPv3 report.
98 IGMPv3MembershipReport IGMPType = 0x22
99 )
100 101 // Type is the IGMP type field.
102 func (b IGMP) Type() IGMPType { return IGMPType(b[igmpTypeOffset]) }
103 104 // SetType sets the IGMP type field.
105 func (b IGMP) SetType(t IGMPType) { b[igmpTypeOffset] = byte(t) }
106 107 // MaxRespTime gets the MaxRespTimeField. This is meaningful only in Membership
108 // Query messages, in other cases it is set to 0 by the sender and ignored by
109 // the receiver.
110 func (b IGMP) MaxRespTime() time.Duration {
111 // As per RFC 2236 section 2.2,
112 //
113 // The Max Response Time field is meaningful only in Membership Query
114 // messages, and specifies the maximum allowed time before sending a
115 // responding report in units of 1/10 second. In all other messages, it
116 // is set to zero by the sender and ignored by receivers.
117 return DecisecondToDuration(uint16(b[igmpMaxRespTimeOffset]))
118 }
119 120 // SetMaxRespTime sets the MaxRespTimeField.
121 func (b IGMP) SetMaxRespTime(m byte) { b[igmpMaxRespTimeOffset] = m }
122 123 // Checksum is the IGMP checksum field.
124 func (b IGMP) Checksum() uint16 {
125 return binary.BigEndian.Uint16(b[igmpChecksumOffset:])
126 }
127 128 // SetChecksum sets the IGMP checksum field.
129 func (b IGMP) SetChecksum(checksum uint16) {
130 binary.BigEndian.PutUint16(b[igmpChecksumOffset:], checksum)
131 }
132 133 // GroupAddress gets the Group Address field.
134 func (b IGMP) GroupAddress() tcpip.Address {
135 return tcpip.AddrFrom4([4]byte(b[igmpGroupAddressOffset:][:IPv4AddressSize]))
136 }
137 138 // SetGroupAddress sets the Group Address field.
139 func (b IGMP) SetGroupAddress(address tcpip.Address) {
140 addrBytes := address.As4()
141 if n := copy(b[igmpGroupAddressOffset:], addrBytes[:]); n != IPv4AddressSize {
142 panic(fmt.Sprintf("copied %d bytes, expected %d", n, IPv4AddressSize))
143 }
144 }
145 146 // SourcePort implements Transport.SourcePort.
147 func (IGMP) SourcePort() uint16 {
148 return 0
149 }
150 151 // DestinationPort implements Transport.DestinationPort.
152 func (IGMP) DestinationPort() uint16 {
153 return 0
154 }
155 156 // SetSourcePort implements Transport.SetSourcePort.
157 func (IGMP) SetSourcePort(uint16) {
158 }
159 160 // SetDestinationPort implements Transport.SetDestinationPort.
161 func (IGMP) SetDestinationPort(uint16) {
162 }
163 164 // Payload implements Transport.Payload.
165 func (IGMP) Payload() []byte {
166 return nil
167 }
168 169 // IGMPCalculateChecksum calculates the IGMP checksum over the provided IGMP
170 // header.
171 func IGMPCalculateChecksum(h IGMP) uint16 {
172 // The header contains a checksum itself, set it aside to avoid checksumming
173 // the checksum and replace it afterwards.
174 existingXsum := h.Checksum()
175 h.SetChecksum(0)
176 xsum := ^checksum.Checksum(h, 0)
177 h.SetChecksum(existingXsum)
178 return xsum
179 }
180 181 // DecisecondToDuration converts a value representing deci-seconds to a
182 // time.Duration.
183 func DecisecondToDuration(ds uint16) time.Duration {
184 return time.Duration(ds) * time.Second / 10
185 }
186