Files
moby/daemon/libnetwork/drivers/overlay/encryption_test.go
Cory Snider 51664a25d7 libn/d/overlay: calculate SPI like older engines
The Security Parameter Index value signals to the recipient which key to
decrypt the packet with. The overlay driver derives the SPI value for a
flow from a hash digest of the source and destination IP addresses. The
source and destination need to derive the same digest given the same
information as the SPI values are not signaled over the overlay driver's
control plane. Refactoring the overlay driver to use netip types
accidentally changed the hash function to digest IPv4 addresses in
4-byte form, causing newer engines to calculate a different SPI value
for a flow than older engines would. Restore the original calculation
by hashing IPv4 addresses in their 16-byte form, and refactor the
buildSPI function to take netip.Addr parameters to prevent 16-byte vs
4-byte mixups from being possible in the future.

Signed-off-by: Cory Snider <csnider@mirantis.com>
2026-01-27 18:32:10 -05:00

52 lines
1.4 KiB
Go

//go:build linux
package overlay
import (
"encoding/binary"
"hash/fnv"
"net"
"net/netip"
"testing"
)
func legacyBuildSPI(src, dst net.IP, st uint32) int {
b := make([]byte, 4)
binary.BigEndian.PutUint32(b, st)
h := fnv.New32a()
h.Write(src)
h.Write(b)
h.Write(dst)
return int(binary.BigEndian.Uint32(h.Sum(nil)))
}
func TestBuildSPI(t *testing.T) {
cases := []struct {
src, dst string
st uint32
}{
{"1.2.3.4", "5.6.7.8", 1234},
{"::ffff:1.2.3.4", "::ffff:5.6.7.8", 1234},
{"10.0.0.1", "2001:db8::1", 5678},
{"2002::abcd:1", "172.15.14.13", 54321},
{"2002:db8::42", "2002:db8::69", 9999},
}
for _, tc := range cases {
// The legacy buildSPI function is sensitive to whether src and
// dst are in 4-byte or 16-byte form. Versions of the driver
// using this function always pass the results of net.ParseIP(),
// which always parses the address into 16-byte form.
expected := legacyBuildSPI(net.ParseIP(tc.src), net.ParseIP(tc.dst), tc.st)
src, dst := netip.MustParseAddr(tc.src), netip.MustParseAddr(tc.dst)
actual := buildSPI(src, dst, tc.st)
if expected != actual {
t.Errorf("buildSPI(%v, %v, %v) = %v; want %v", src, dst, tc.st, actual, expected)
}
actual = buildSPI(src.Unmap(), dst.Unmap(), tc.st)
if expected != actual {
t.Errorf("buildSPI(%v, %v, %v) = %v; want %v", src.Unmap(), dst.Unmap(), tc.st, actual, expected)
}
}
}