summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip/header/ipv4.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/tcpip/header/ipv4.go')
-rw-r--r--pkg/tcpip/header/ipv4.go37
1 files changed, 25 insertions, 12 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))