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