From 505e1fd33f6aa9548fa4403c2553471dc28bd6a7 Mon Sep 17 00:00:00 2001 From: Nayana Bidari Date: Fri, 1 Dec 2023 13:28:16 -0800 Subject: [PATCH] Change IPv4 ID generation algorithm. This addresses an issue discovered by Inon Kaplan (PhD candidate in the Hebrew University School of Computer Science and Engineering), Ron Even (BSc graduate of Bar Ilan University) and Amit Klein (faculty member in the Hebrew University School of Computer Science and Engineering). Details will be provided in their paper, to be presented in a forthcoming academic conference. The ID generation for IPv4 is changed to return a completely random number. PiperOrigin-RevId: 587102343 --- pkg/rand/rng.go | 9 +++++++++ pkg/tcpip/network/ipv4/ipv4.go | 30 +++++++++--------------------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/pkg/rand/rng.go b/pkg/rand/rng.go index d11d9f3fc..5159c202a 100644 --- a/pkg/rand/rng.go +++ b/pkg/rand/rng.go @@ -33,6 +33,15 @@ func RNGFrom(r io.Reader) RNG { return RNG{Reader: r} } +// Uint16 is analogous to the standard library's math/rand.Uint16. +func (rg *RNG) Uint16() uint16 { + var data [2]byte + if _, err := rg.Reader.Read(data[:]); err != nil { + panic(fmt.Sprintf("Read() failed: %v", err)) + } + return binary.NativeEndian.Uint16(data[:]) +} + // Uint32 is analogous to the standard library's math/rand.Uint32. func (rg *RNG) Uint32() uint32 { var data [4]byte diff --git a/pkg/tcpip/network/ipv4/ipv4.go b/pkg/tcpip/network/ipv4/ipv4.go index ef105d95a..8aa4a92a7 100644 --- a/pkg/tcpip/network/ipv4/ipv4.go +++ b/pkg/tcpip/network/ipv4/ipv4.go @@ -437,26 +437,15 @@ func (e *endpoint) NetworkProtocolNumber() tcpip.NetworkProtocolNumber { return e.protocol.Number() } -func (e *endpoint) generateID(srcAddr, dstAddr tcpip.Address, params stack.NetworkHeaderParams) uint32 { - // Get the time difference between the last time 'ids' was accessed and - // now. Update 'idTS' to the current time. - now := e.protocol.stack.Clock().NowMonotonic().Milliseconds() - oldTS := e.protocol.idTS.Load() - diff := now - oldTS +// getID returns a random uint16 number (other than zero) to be used as ID in +// the IPv4 header. +func (e *endpoint) getID() uint16 { rng := e.protocol.stack.SecureRNG() - e.protocol.idTS.Store(now) - - var counter uint32 - if diff < 1 { - counter = rng.Uint32() - } else { - // Increment ID with a random number in the range [0, diff). - counter = uint32(rng.Int63n(diff)) + id := rng.Uint16() + for id == 0 { + id = rng.Uint16() } - - // Calculate the hash value. - hash := hashRoute(srcAddr, dstAddr, params.Protocol, e.protocol.hashIV) % buckets - return e.protocol.ids[hash].Add(counter) + return id } func (e *endpoint) addIPHeader(srcAddr, dstAddr tcpip.Address, pkt stack.PacketBufferPtr, params stack.NetworkHeaderParams, options header.IPv4OptionsSerializer) tcpip.Error { @@ -477,10 +466,9 @@ func (e *endpoint) addIPHeader(srcAddr, dstAddr tcpip.Address, pkt stack.PacketB // RFC 6864 section 4.3 mandates uniqueness of ID values for non-atomic // datagrams. Since the DF bit is never being set here, all datagrams // are non-atomic and need an ID. - id := e.generateID(srcAddr, dstAddr, params) ipH.Encode(&header.IPv4Fields{ TotalLength: uint16(length), - ID: uint16(id), + ID: e.getID(), TTL: params.TTL, TOS: params.TOS, Protocol: uint8(params.Protocol), @@ -650,7 +638,7 @@ func (e *endpoint) WriteHeaderIncludedPacket(r *stack.Route, pkt stack.PacketBuf // non-atomic datagrams, so assign an ID to all such datagrams // according to the definition given in RFC 6864 section 4. if ipH.Flags()&header.IPv4FlagDontFragment == 0 || ipH.Flags()&header.IPv4FlagMoreFragments != 0 || ipH.FragmentOffset() > 0 { - ipH.SetID(uint16(e.generateID(r.LocalAddress(), r.RemoteAddress(), stack.NetworkHeaderParams{}))) + ipH.SetID(e.getID()) } }