| // Copyright 2016 The Netstack Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package header |
| |
| import ( |
| "encoding/binary" |
| |
| "github.com/google/netstack/tcpip" |
| ) |
| |
| const ( |
| versTCFL = 0 |
| payloadLen = 4 |
| nextHdr = 6 |
| hopLimit = 7 |
| v6SrcAddr = 8 |
| v6DstAddr = 24 |
| ) |
| |
| // IPv6Fields contains the fields of an IPv6 packet. It is used to describe the |
| // fields of a packet that needs to be encoded. |
| type IPv6Fields struct { |
| // TrafficClass is the "traffic class" field of an IPv6 packet. |
| TrafficClass uint8 |
| |
| // FlowLabel is the "flow label" field of an IPv6 packet. |
| FlowLabel uint32 |
| |
| // PayloadLength is the "payload length" field of an IPv6 packet. |
| PayloadLength uint16 |
| |
| // NextHeader is the "next header" field of an IPv6 packet. |
| NextHeader uint8 |
| |
| // HopLimit is the "hop limit" field of an IPv6 packet. |
| HopLimit uint8 |
| |
| // SrcAddr is the "source ip address" of an IPv6 packet. |
| SrcAddr tcpip.Address |
| |
| // DstAddr is the "destination ip address" of an IPv6 packet. |
| DstAddr tcpip.Address |
| } |
| |
| // IPv6 represents an ipv6 header stored in a byte array. |
| // Most of the methods of IPv6 access to the underlying slice without |
| // checking the boundaries and could panic because of 'index out of range'. |
| // Always call IsValid() to validate an instance of IPv6 before using other methods. |
| type IPv6 []byte |
| |
| const ( |
| // IPv6MinimumSize is the minimum size of a valid IPv6 packet. |
| IPv6MinimumSize = 40 |
| |
| // IPv6AddressSize is the size, in bytes, of an IPv6 address. |
| IPv6AddressSize = 16 |
| |
| // IPv6ProtocolNumber is IPv6's network protocol number. |
| IPv6ProtocolNumber tcpip.NetworkProtocolNumber = 0x86dd |
| |
| // IPv6Version is the version of the ipv6 procotol. |
| IPv6Version = 6 |
| |
| // IPv6MinimumMTU is the minimum MTU required by IPv6, per RFC 2460, |
| // section 5. |
| IPv6MinimumMTU = 1280 |
| |
| // IPv6Loopback is the loopback address of the IPv6 procotol. |
| IPv6Loopback tcpip.Address = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" |
| ) |
| |
| // PayloadLength returns the value of the "payload length" field of the ipv6 |
| // header. |
| func (b IPv6) PayloadLength() uint16 { |
| return binary.BigEndian.Uint16(b[payloadLen:]) |
| } |
| |
| // HopLimit returns the value of the "hop limit" field of the ipv6 header. |
| func (b IPv6) HopLimit() uint8 { |
| return b[hopLimit] |
| } |
| |
| // NextHeader returns the value of the "next header" field of the ipv6 header. |
| func (b IPv6) NextHeader() uint8 { |
| return b[nextHdr] |
| } |
| |
| // TransportProtocol implements Network.TransportProtocol. |
| func (b IPv6) TransportProtocol() tcpip.TransportProtocolNumber { |
| return tcpip.TransportProtocolNumber(b.NextHeader()) |
| } |
| |
| // Payload implements Network.Payload. |
| func (b IPv6) Payload() []byte { |
| return b[IPv6MinimumSize:][:b.PayloadLength()] |
| } |
| |
| // SourceAddress returns the "source address" field of the ipv6 header. |
| func (b IPv6) SourceAddress() tcpip.Address { |
| return tcpip.Address(b[v6SrcAddr : v6SrcAddr+IPv6AddressSize]) |
| } |
| |
| // DestinationAddress returns the "destination address" field of the ipv6 |
| // header. |
| func (b IPv6) DestinationAddress() tcpip.Address { |
| return tcpip.Address(b[v6DstAddr : v6DstAddr+IPv6AddressSize]) |
| } |
| |
| // Checksum implements Network.Checksum. Given that IPv6 doesn't have a |
| // checksum, it just returns 0. |
| func (IPv6) Checksum() uint16 { |
| return 0 |
| } |
| |
| // TOS returns the "traffic class" and "flow label" fields of the ipv6 header. |
| func (b IPv6) TOS() (uint8, uint32) { |
| v := binary.BigEndian.Uint32(b[versTCFL:]) |
| return uint8(v >> 20), v & 0xfffff |
| } |
| |
| // SetTOS sets the "traffic class" and "flow label" fields of the ipv6 header. |
| func (b IPv6) SetTOS(t uint8, l uint32) { |
| vtf := (6 << 28) | (uint32(t) << 20) | (l & 0xfffff) |
| binary.BigEndian.PutUint32(b[versTCFL:], vtf) |
| } |
| |
| // SetPayloadLength sets the "payload length" field of the ipv6 header. |
| func (b IPv6) SetPayloadLength(payloadLength uint16) { |
| binary.BigEndian.PutUint16(b[payloadLen:], payloadLength) |
| } |
| |
| // SetSourceAddress sets the "source address" field of the ipv6 header. |
| func (b IPv6) SetSourceAddress(addr tcpip.Address) { |
| copy(b[v6SrcAddr:v6SrcAddr+IPv6AddressSize], addr) |
| } |
| |
| // SetDestinationAddress sets the "destination address" field of the ipv6 |
| // header. |
| func (b IPv6) SetDestinationAddress(addr tcpip.Address) { |
| copy(b[v6DstAddr:v6DstAddr+IPv6AddressSize], addr) |
| } |
| |
| // SetChecksum implements Network.SetChecksum. Given that IPv6 doesn't have a |
| // checksum, it is empty. |
| func (IPv6) SetChecksum(uint16) { |
| } |
| |
| // Encode encodes all the fields of the ipv6 header. |
| func (b IPv6) Encode(i *IPv6Fields) { |
| b.SetTOS(i.TrafficClass, i.FlowLabel) |
| b.SetPayloadLength(i.PayloadLength) |
| b[nextHdr] = i.NextHeader |
| b[hopLimit] = i.HopLimit |
| copy(b[v6SrcAddr:v6SrcAddr+IPv6AddressSize], i.SrcAddr) |
| copy(b[v6DstAddr:v6DstAddr+IPv6AddressSize], i.DstAddr) |
| } |
| |
| // IsValid performs basic validation on the packet. |
| func (b IPv6) IsValid(pktSize int) bool { |
| if len(b) < IPv6MinimumSize { |
| return false |
| } |
| |
| dlen := int(b.PayloadLength()) |
| if dlen > pktSize-IPv6MinimumSize { |
| return false |
| } |
| |
| return true |
| } |
| |
| // IsV4MappedAddress determines if the provided address is an IPv4 mapped |
| // address by checking if its prefix is 0:0:0:0:0:ffff::/96. |
| func IsV4MappedAddress(addr tcpip.Address) bool { |
| if len(addr) != IPv6AddressSize { |
| return false |
| } |
| |
| const prefix = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff" |
| for i := 0; i < len(prefix); i++ { |
| if prefix[i] != addr[i] { |
| return false |
| } |
| } |
| |
| return true |
| } |
| |
| // IsV6MulticastAddress determines if the provided address is an IPv6 |
| // multicast address (anything starting with FF). |
| func IsV6MulticastAddress(addr tcpip.Address) bool { |
| if len(addr) != IPv6AddressSize { |
| return false |
| } |
| return addr[0] == 0xff |
| } |