diff options
Diffstat (limited to 'pkg/tcpip/header')
-rw-r--r-- | pkg/tcpip/header/ipv4.go | 37 | ||||
-rw-r--r-- | pkg/tcpip/header/ipv6.go | 9 | ||||
-rw-r--r-- | pkg/tcpip/header/parse/parse.go | 3 |
3 files changed, 35 insertions, 14 deletions
diff --git a/pkg/tcpip/header/ipv4.go b/pkg/tcpip/header/ipv4.go index 7e32b31b4..91fe7b6a5 100644 --- a/pkg/tcpip/header/ipv4.go +++ b/pkg/tcpip/header/ipv4.go @@ -89,7 +89,17 @@ type IPv4Fields struct { // DstAddr is the "destination ip address" of an IPv4 packet. DstAddr tcpip.Address - // Options is between 0 and 40 bytes or nil if empty. + // Options must be 40 bytes or less as they must fit along with the + // rest of the IPv4 header into the maximum size describable in the + // IHL field. RFC 791 section 3.1 says: + // IHL: 4 bits + // + // Internet Header Length is the length of the internet header in 32 + // bit words, and thus points to the beginning of the data. Note that + // the minimum value for a correct header is 5. + // + // That leaves ten 32 bit (4 byte) fields for options. An attempt to encode + // more will fail. Options IPv4Options } @@ -275,22 +285,19 @@ func (b IPv4) DestinationAddress() tcpip.Address { // IPv4Options is a buffer that holds all the raw IP options. type IPv4Options []byte -// AllocationSize implements stack.NetOptions. +// SizeWithPadding implements stack.NetOptions. // It reports the size to allocate for the Options. RFC 791 page 23 (end of // section 3.1) says of the padding at the end of the options: // The internet header padding is used to ensure that the internet // header ends on a 32 bit boundary. -func (o IPv4Options) AllocationSize() int { +func (o IPv4Options) SizeWithPadding() int { return (len(o) + IPv4IHLStride - 1) & ^(IPv4IHLStride - 1) } -// Options returns a buffer holding the options or nil. +// Options returns a buffer holding the options. func (b IPv4) Options() IPv4Options { hdrLen := b.HeaderLength() - if hdrLen > IPv4MinimumSize { - return IPv4Options(b[options:hdrLen:hdrLen]) - } - return nil + return IPv4Options(b[options:hdrLen:hdrLen]) } // TransportProtocol implements Network.TransportProtocol. @@ -368,14 +375,20 @@ func (b IPv4) Encode(i *IPv4Fields) { // worth a bit of optimisation here to keep the copy out of the fast path. hdrLen := IPv4MinimumSize if len(i.Options) != 0 { - // AllocationSize is always >= len(i.Options). - aLen := i.Options.AllocationSize() + // SizeWithPadding is always >= len(i.Options). + aLen := i.Options.SizeWithPadding() hdrLen += aLen if hdrLen > len(b) { panic(fmt.Sprintf("encode received %d bytes, wanted >= %d", len(b), hdrLen)) } - if aLen != copy(b[options:], i.Options) { - _ = copy(b[options+len(i.Options):options+aLen], []byte{0, 0, 0, 0}) + opts := b[options:] + // This avoids bounds checks on the next line(s) which would happen even + // if there's no work to do. + if n := copy(opts, i.Options); n != aLen { + padding := opts[n:][:aLen-n] + for i := range padding { + padding[i] = 0 + } } } b.SetHeaderLength(uint8(hdrLen)) diff --git a/pkg/tcpip/header/ipv6.go b/pkg/tcpip/header/ipv6.go index 4e7e5f76a..55d09355a 100644 --- a/pkg/tcpip/header/ipv6.go +++ b/pkg/tcpip/header/ipv6.go @@ -54,7 +54,7 @@ type IPv6Fields struct { // NextHeader is the "next header" field of an IPv6 packet. NextHeader uint8 - // HopLimit is the "hop limit" field of an IPv6 packet. + // HopLimit is the "Hop Limit" field of an IPv6 packet. HopLimit uint8 // SrcAddr is the "source ip address" of an IPv6 packet. @@ -171,7 +171,7 @@ func (b IPv6) PayloadLength() uint16 { return binary.BigEndian.Uint16(b[IPv6PayloadLenOffset:]) } -// HopLimit returns the value of the "hop limit" field of the ipv6 header. +// HopLimit returns the value of the "Hop Limit" field of the ipv6 header. func (b IPv6) HopLimit() uint8 { return b[hopLimit] } @@ -236,6 +236,11 @@ func (b IPv6) SetDestinationAddress(addr tcpip.Address) { copy(b[v6DstAddr:][:IPv6AddressSize], addr) } +// SetHopLimit sets the value of the "Hop Limit" field. +func (b IPv6) SetHopLimit(v uint8) { + b[hopLimit] = v +} + // SetNextHeader sets the value of the "next header" field of the ipv6 header. func (b IPv6) SetNextHeader(v uint8) { b[IPv6NextHeaderOffset] = v diff --git a/pkg/tcpip/header/parse/parse.go b/pkg/tcpip/header/parse/parse.go index 5ca75c834..2042f214a 100644 --- a/pkg/tcpip/header/parse/parse.go +++ b/pkg/tcpip/header/parse/parse.go @@ -109,6 +109,9 @@ traverseExtensions: fragOffset = extHdr.FragmentOffset() fragMore = extHdr.More() } + rawPayload := it.AsRawHeader(true /* consume */) + extensionsSize = dataClone.Size() - rawPayload.Buf.Size() + break traverseExtensions case header.IPv6RawPayloadHeader: // We've found the payload after any extensions. |