github.com/polevpn/netstack@v1.10.9/tcpip/header/ndp_options.go (about) 1 // Copyright 2019 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 "errors" 20 "time" 21 22 "github.com/polevpn/netstack/tcpip" 23 ) 24 25 const ( 26 // NDPTargetLinkLayerAddressOptionType is the type of the Target 27 // Link-Layer Address option, as per RFC 4861 section 4.6.1. 28 NDPTargetLinkLayerAddressOptionType = 2 29 30 // ndpTargetEthernetLinkLayerAddressSize is the size of a Target 31 // Link Layer Option for an Ethernet address. 32 ndpTargetEthernetLinkLayerAddressSize = 8 33 34 // NDPPrefixInformationType is the type of the Prefix Information 35 // option, as per RFC 4861 section 4.6.2. 36 NDPPrefixInformationType = 3 37 38 // ndpPrefixInformationLength is the expected length, in bytes, of the 39 // body of an NDP Prefix Information option, as per RFC 4861 section 40 // 4.6.2 which specifies that the Length field is 4. Given this, the 41 // expected length, in bytes, is 30 becuase 4 * lengthByteUnits (8) - 2 42 // (Type & Length) = 30. 43 ndpPrefixInformationLength = 30 44 45 // ndpPrefixInformationPrefixLengthOffset is the offset of the Prefix 46 // Length field within an NDPPrefixInformation. 47 ndpPrefixInformationPrefixLengthOffset = 0 48 49 // ndpPrefixInformationFlagsOffset is the offset of the flags byte 50 // within an NDPPrefixInformation. 51 ndpPrefixInformationFlagsOffset = 1 52 53 // ndpPrefixInformationOnLinkFlagMask is the mask of the On-Link Flag 54 // field in the flags byte within an NDPPrefixInformation. 55 ndpPrefixInformationOnLinkFlagMask = (1 << 7) 56 57 // ndpPrefixInformationAutoAddrConfFlagMask is the mask of the 58 // Autonomous Address-Configuration flag field in the flags byte within 59 // an NDPPrefixInformation. 60 ndpPrefixInformationAutoAddrConfFlagMask = (1 << 6) 61 62 // ndpPrefixInformationReserved1FlagsMask is the mask of the Reserved1 63 // field in the flags byte within an NDPPrefixInformation. 64 ndpPrefixInformationReserved1FlagsMask = 63 65 66 // ndpPrefixInformationValidLifetimeOffset is the start of the 4-byte 67 // Valid Lifetime field within an NDPPrefixInformation. 68 ndpPrefixInformationValidLifetimeOffset = 2 69 70 // ndpPrefixInformationPreferredLifetimeOffset is the start of the 71 // 4-byte Preferred Lifetime field within an NDPPrefixInformation. 72 ndpPrefixInformationPreferredLifetimeOffset = 6 73 74 // ndpPrefixInformationReserved2Offset is the start of the 4-byte 75 // Reserved2 field within an NDPPrefixInformation. 76 ndpPrefixInformationReserved2Offset = 10 77 78 // ndpPrefixInformationReserved2Length is the length of the Reserved2 79 // field. 80 // 81 // It is 4 bytes. 82 ndpPrefixInformationReserved2Length = 4 83 84 // ndpPrefixInformationPrefixOffset is the start of the Prefix field 85 // within an NDPPrefixInformation. 86 ndpPrefixInformationPrefixOffset = 14 87 88 // lengthByteUnits is the multiplier factor for the Length field of an 89 // NDP option. That is, the length field for NDP options is in units of 90 // 8 octets, as per RFC 4861 section 4.6. 91 lengthByteUnits = 8 92 ) 93 94 var ( 95 // NDPPrefixInformationInfiniteLifetime is a value that represents 96 // infinity for the Valid and Preferred Lifetime fields in a NDP Prefix 97 // Information option. Its value is (2^32 - 1)s = 4294967295s 98 // 99 // This is a variable instead of a constant so that tests can change 100 // this value to a smaller value. It should only be modified by tests. 101 NDPPrefixInformationInfiniteLifetime = time.Second * 4294967295 102 ) 103 104 // NDPOptionIterator is an iterator of NDPOption. 105 // 106 // Note, between when an NDPOptionIterator is obtained and last used, no changes 107 // to the NDPOptions may happen. Doing so may cause undefined and unexpected 108 // behaviour. It is fine to obtain an NDPOptionIterator, iterate over the first 109 // few NDPOption then modify the backing NDPOptions so long as the 110 // NDPOptionIterator obtained before modification is no longer used. 111 type NDPOptionIterator struct { 112 // The NDPOptions this NDPOptionIterator is iterating over. 113 opts NDPOptions 114 } 115 116 // Potential errors when iterating over an NDPOptions. 117 var ( 118 ErrNDPOptBufExhausted = errors.New("Buffer unexpectedly exhausted") 119 ErrNDPOptZeroLength = errors.New("NDP option has zero-valued Length field") 120 ErrNDPOptMalformedBody = errors.New("NDP option has a malformed body") 121 ) 122 123 // Next returns the next element in the backing NDPOptions, or true if we are 124 // done, or false if an error occured. 125 // 126 // The return can be read as option, done, error. Note, option should only be 127 // used if done is false and error is nil. 128 func (i *NDPOptionIterator) Next() (NDPOption, bool, error) { 129 for { 130 // Do we still have elements to look at? 131 if len(i.opts) == 0 { 132 return nil, true, nil 133 } 134 135 // Do we have enough bytes for an NDP option that has a Length 136 // field of at least 1? Note, 0 in the Length field is invalid. 137 if len(i.opts) < lengthByteUnits { 138 return nil, true, ErrNDPOptBufExhausted 139 } 140 141 // Get the Type field. 142 t := i.opts[0] 143 144 // Get the Length field. 145 l := i.opts[1] 146 147 // This would indicate an erroneous NDP option as the Length 148 // field should never be 0. 149 if l == 0 { 150 return nil, true, ErrNDPOptZeroLength 151 } 152 153 // How many bytes are in the option body? 154 numBytes := int(l) * lengthByteUnits 155 numBodyBytes := numBytes - 2 156 157 potentialBody := i.opts[2:] 158 159 // This would indicate an erroenous NDPOptions buffer as we ran 160 // out of the buffer in the middle of an NDP option. 161 if left := len(potentialBody); left < numBodyBytes { 162 return nil, true, ErrNDPOptBufExhausted 163 } 164 165 // Get only the options body, leaving the rest of the options 166 // buffer alone. 167 body := potentialBody[:numBodyBytes] 168 169 // Update opts with the remaining options body. 170 i.opts = i.opts[numBytes:] 171 172 switch t { 173 case NDPTargetLinkLayerAddressOptionType: 174 return NDPTargetLinkLayerAddressOption(body), false, nil 175 176 case NDPPrefixInformationType: 177 // Make sure the length of a Prefix Information option 178 // body is ndpPrefixInformationLength, as per RFC 4861 179 // section 4.6.2. 180 if numBodyBytes != ndpPrefixInformationLength { 181 return nil, true, ErrNDPOptMalformedBody 182 } 183 184 return NDPPrefixInformation(body), false, nil 185 default: 186 // We do not yet recognize the option, just skip for 187 // now. This is okay because RFC 4861 allows us to 188 // skip/ignore any unrecognized options. However, 189 // we MUST recognized all the options in RFC 4861. 190 // 191 // TODO(b/141487990): Handle all NDP options as defined 192 // by RFC 4861. 193 } 194 } 195 } 196 197 // NDPOptions is a buffer of NDP options as defined by RFC 4861 section 4.6. 198 type NDPOptions []byte 199 200 // Iter returns an iterator of NDPOption. 201 // 202 // If check is true, Iter will do an integrity check on the options by iterating 203 // over it and returning an error if detected. 204 // 205 // See NDPOptionIterator for more information. 206 func (b NDPOptions) Iter(check bool) (NDPOptionIterator, error) { 207 it := NDPOptionIterator{opts: b} 208 209 if check { 210 for it2 := it; true; { 211 if _, done, err := it2.Next(); err != nil || done { 212 return it, err 213 } 214 } 215 } 216 217 return it, nil 218 } 219 220 // Serialize serializes the provided list of NDP options into o. 221 // 222 // Note, b must be of sufficient size to hold all the options in s. See 223 // NDPOptionsSerializer.Length for details on the getting the total size 224 // of a serialized NDPOptionsSerializer. 225 // 226 // Serialize may panic if b is not of sufficient size to hold all the options 227 // in s. 228 func (b NDPOptions) Serialize(s NDPOptionsSerializer) int { 229 done := 0 230 231 for _, o := range s { 232 l := paddedLength(o) 233 234 if l == 0 { 235 continue 236 } 237 238 b[0] = o.Type() 239 240 // We know this safe because paddedLength would have returned 241 // 0 if o had an invalid length (> 255 * lengthByteUnits). 242 b[1] = uint8(l / lengthByteUnits) 243 244 // Serialize NDP option body. 245 used := o.serializeInto(b[2:]) 246 247 // Zero out remaining (padding) bytes, if any exists. 248 for i := used + 2; i < l; i++ { 249 b[i] = 0 250 } 251 252 b = b[l:] 253 done += l 254 } 255 256 return done 257 } 258 259 // NDPOption is the set of functions to be implemented by all NDP option types. 260 type NDPOption interface { 261 // Type returns the type of the receiver. 262 Type() uint8 263 264 // Length returns the length of the body of the receiver, in bytes. 265 Length() int 266 267 // serializeInto serializes the receiver into the provided byte 268 // buffer. 269 // 270 // Note, the caller MUST provide a byte buffer with size of at least 271 // Length. Implementers of this function may assume that the byte buffer 272 // is of sufficient size. serializeInto MAY panic if the provided byte 273 // buffer is not of sufficient size. 274 // 275 // serializeInto will return the number of bytes that was used to 276 // serialize the receiver. Implementers must only use the number of 277 // bytes required to serialize the receiver. Callers MAY provide a 278 // larger buffer than required to serialize into. 279 serializeInto([]byte) int 280 } 281 282 // paddedLength returns the length of o, in bytes, with any padding bytes, if 283 // required. 284 func paddedLength(o NDPOption) int { 285 l := o.Length() 286 287 if l == 0 { 288 return 0 289 } 290 291 // Length excludes the 2 Type and Length bytes. 292 l += 2 293 294 // Add extra bytes if needed to make sure the option is 295 // lengthByteUnits-byte aligned. We do this by adding lengthByteUnits-1 296 // to l and then stripping off the last few LSBits from l. This will 297 // make sure that l is rounded up to the nearest unit of 298 // lengthByteUnits. This works since lengthByteUnits is a power of 2 299 // (= 8). 300 mask := lengthByteUnits - 1 301 l += mask 302 l &^= mask 303 304 if l/lengthByteUnits > 255 { 305 // Should never happen because an option can only have a max 306 // value of 255 for its Length field, so just return 0 so this 307 // option does not get serialized. 308 // 309 // Returning 0 here will make sure that this option does not get 310 // serialized when NDPOptions.Serialize is called with the 311 // NDPOptionsSerializer that holds this option, effectively 312 // skipping this option during serialization. Also note that 313 // a value of zero for the Length field in an NDP option is 314 // invalid so this is another sign to the caller that this NDP 315 // option is malformed, as per RFC 4861 section 4.6. 316 return 0 317 } 318 319 return l 320 } 321 322 // NDPOptionsSerializer is a serializer for NDP options. 323 type NDPOptionsSerializer []NDPOption 324 325 // Length returns the total number of bytes required to serialize. 326 func (b NDPOptionsSerializer) Length() int { 327 l := 0 328 329 for _, o := range b { 330 l += paddedLength(o) 331 } 332 333 return l 334 } 335 336 // NDPTargetLinkLayerAddressOption is the NDP Target Link Layer Option 337 // as defined by RFC 4861 section 4.6.1. 338 // 339 // It is the first X bytes following the NDP option's Type and Length field 340 // where X is the value in Length multiplied by lengthByteUnits - 2 bytes. 341 type NDPTargetLinkLayerAddressOption tcpip.LinkAddress 342 343 // Type implements NDPOption.Type. 344 func (o NDPTargetLinkLayerAddressOption) Type() uint8 { 345 return NDPTargetLinkLayerAddressOptionType 346 } 347 348 // Length implements NDPOption.Length. 349 func (o NDPTargetLinkLayerAddressOption) Length() int { 350 return len(o) 351 } 352 353 // serializeInto implements NDPOption.serializeInto. 354 func (o NDPTargetLinkLayerAddressOption) serializeInto(b []byte) int { 355 return copy(b, o) 356 } 357 358 // EthernetAddress will return an ethernet (MAC) address if the 359 // NDPTargetLinkLayerAddressOption's body has at minimum EthernetAddressSize 360 // bytes. If the body has more than EthernetAddressSize bytes, only the first 361 // EthernetAddressSize bytes are returned as that is all that is needed for an 362 // Ethernet address. 363 func (o NDPTargetLinkLayerAddressOption) EthernetAddress() tcpip.LinkAddress { 364 if len(o) >= EthernetAddressSize { 365 return tcpip.LinkAddress(o[:EthernetAddressSize]) 366 } 367 368 return tcpip.LinkAddress([]byte(nil)) 369 } 370 371 // NDPPrefixInformation is the NDP Prefix Information option as defined by 372 // RFC 4861 section 4.6.2. 373 // 374 // The length, in bytes, of a valid NDP Prefix Information option body MUST be 375 // ndpPrefixInformationLength bytes. 376 type NDPPrefixInformation []byte 377 378 // Type implements NDPOption.Type. 379 func (o NDPPrefixInformation) Type() uint8 { 380 return NDPPrefixInformationType 381 } 382 383 // Length implements NDPOption.Length. 384 func (o NDPPrefixInformation) Length() int { 385 return ndpPrefixInformationLength 386 } 387 388 // serializeInto implements NDPOption.serializeInto. 389 func (o NDPPrefixInformation) serializeInto(b []byte) int { 390 used := copy(b, o) 391 392 // Zero out the Reserved1 field. 393 b[ndpPrefixInformationFlagsOffset] &^= ndpPrefixInformationReserved1FlagsMask 394 395 // Zero out the Reserved2 field. 396 reserved2 := b[ndpPrefixInformationReserved2Offset:][:ndpPrefixInformationReserved2Length] 397 for i := range reserved2 { 398 reserved2[i] = 0 399 } 400 401 return used 402 } 403 404 // PrefixLength returns the value in the number of leading bits in the Prefix 405 // that are valid. 406 // 407 // Valid values are in the range [0, 128], but o may not always contain valid 408 // values. It is up to the caller to valdiate the Prefix Information option. 409 func (o NDPPrefixInformation) PrefixLength() uint8 { 410 return o[ndpPrefixInformationPrefixLengthOffset] 411 } 412 413 // OnLinkFlag returns true of the prefix is considered on-link. On-link means 414 // that a forwarding node is not needed to send packets to other nodes on the 415 // same prefix. 416 // 417 // Note, when this function returns false, no statement is made about the 418 // on-link property of a prefix. That is, if OnLinkFlag returns false, the 419 // caller MUST NOT conclude that the prefix is off-link and MUST NOT update any 420 // previously stored state for this prefix about its on-link status. 421 func (o NDPPrefixInformation) OnLinkFlag() bool { 422 return o[ndpPrefixInformationFlagsOffset]&ndpPrefixInformationOnLinkFlagMask != 0 423 } 424 425 // AutonomousAddressConfigurationFlag returns true if the prefix can be used for 426 // Stateless Address Auto-Configuration (as specified in RFC 4862). 427 func (o NDPPrefixInformation) AutonomousAddressConfigurationFlag() bool { 428 return o[ndpPrefixInformationFlagsOffset]&ndpPrefixInformationAutoAddrConfFlagMask != 0 429 } 430 431 // ValidLifetime returns the length of time that the prefix is valid for the 432 // purpose of on-link determination. This value is relative to the send time of 433 // the packet that the Prefix Information option was present in. 434 // 435 // Note, a value of 0 implies the prefix should not be considered as on-link, 436 // and a value of infinity/forever is represented by 437 // NDPPrefixInformationInfiniteLifetime. 438 func (o NDPPrefixInformation) ValidLifetime() time.Duration { 439 // The field is the time in seconds, as per RFC 4861 section 4.6.2. 440 return time.Second * time.Duration(binary.BigEndian.Uint32(o[ndpPrefixInformationValidLifetimeOffset:])) 441 } 442 443 // PreferredLifetime returns the length of time that an address generated from 444 // the prefix via Stateless Address Auto-Configuration remains preferred. This 445 // value is relative to the send time of the packet that the Prefix Information 446 // option was present in. 447 // 448 // Note, a value of 0 implies that addresses generated from the prefix should 449 // no longer remain preferred, and a value of infinity is represented by 450 // NDPPrefixInformationInfiniteLifetime. 451 // 452 // Also note that the value of this field MUST NOT exceed the Valid Lifetime 453 // field to avoid preferring addresses that are no longer valid, for the 454 // purpose of Stateless Address Auto-Configuration. 455 func (o NDPPrefixInformation) PreferredLifetime() time.Duration { 456 // The field is the time in seconds, as per RFC 4861 section 4.6.2. 457 return time.Second * time.Duration(binary.BigEndian.Uint32(o[ndpPrefixInformationPreferredLifetimeOffset:])) 458 } 459 460 // Prefix returns an IPv6 address or a prefix of an IPv6 address. The Prefix 461 // Length field (see NDPPrefixInformation.PrefixLength) contains the number 462 // of valid leading bits in the prefix. 463 // 464 // Hosts SHOULD ignore an NDP Prefix Information option where the Prefix field 465 // holds the link-local prefix (fe80::). 466 func (o NDPPrefixInformation) Prefix() tcpip.Address { 467 return tcpip.Address(o[ndpPrefixInformationPrefixOffset:][:IPv6AddressSize]) 468 } 469 470 // Subnet returns the Prefix field and Prefix Length field represented in a 471 // tcpip.Subnet. 472 func (o NDPPrefixInformation) Subnet() tcpip.Subnet { 473 addrWithPrefix := tcpip.AddressWithPrefix{ 474 Address: o.Prefix(), 475 PrefixLen: int(o.PrefixLength()), 476 } 477 return addrWithPrefix.Subnet() 478 }