Skip to content

Commit

Permalink
fix(client): pack all zero netmask
Browse files Browse the repository at this point in the history
An IPv6 netmask prefix of 0 is distinct from the Mask's zero case, and
should be encoded into the netlink message. This matches the behavior of
libipvs.
  • Loading branch information
terinjokes committed Jul 7, 2024
1 parent 0aade8f commit e906274
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 1 deletion.
2 changes: 1 addition & 1 deletion client_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ func packService(svc Service) func() ([]byte, error) {
case svc.Netmask.Is4():
ae.Bytes(cipvs.SvcAttrNetmask, svc.Netmask.AsSlice())
case svc.Netmask.Is6():
if ones := svc.Netmask.Bits(); ones > 0 {
if ones := svc.Netmask.Bits(); ones >= 0 {
b := make([]byte, 4)
nlenc.PutUint32(b, uint32(ones))
ae.Bytes(cipvs.SvcAttrNetmask, b)
Expand Down
52 changes: 52 additions & 0 deletions client_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ package ipvs

import (
"io"
"net"
"net/netip"
"os"
"testing"
"unicode"

"github.com/cloudflare/ipvs/internal/cipvs"
"github.com/cloudflare/ipvs/netmask"
Expand All @@ -17,6 +19,7 @@ import (
"github.com/mdlayher/netlink"
"github.com/mdlayher/netlink/nltest"
"gotest.tools/v3/assert"
"pgregory.net/rapid"
)

const familyID = 0x24
Expand Down Expand Up @@ -282,6 +285,55 @@ func TestServices(t *testing.T) {
}
}

func TestService_PackUnpack(t *testing.T) {
rapid.Check(t, func(t *rapid.T) {
svc := rapid.Custom[Service](func(t *rapid.T) Service {
family := rapid.SampledFrom([]AddressFamily{INET, INET6}).Draw(t, "Family")
var addr netip.Addr
var mask netmask.Mask

switch family {
case INET:
addr, _ = netip.AddrFromSlice(rapid.SliceOfN(rapid.Byte(), net.IPv4len, net.IPv4len).Draw(t, "Address"))
mask = netmask.MaskFrom(rapid.IntRange(0, 32).Draw(t, "ones"), 32)
case INET6:
addr, _ = netip.AddrFromSlice(rapid.SliceOfN(rapid.Byte(), net.IPv6len, net.IPv6len).Draw(t, "Address"))
mask = netmask.MaskFrom(rapid.IntRange(0, 128).Draw(t, "ones"), 128)
}

return Service{
Address: addr,
Netmask: mask,
Scheduler: rapid.StringOf(rapid.RuneFrom(nil, unicode.Letter, unicode.Number)).Draw(t, "Scheduler"),
Timeout: rapid.Uint32().Draw(t, "Timeout"),
Flags: Flags(rapid.Uint32().Draw(t, "Flags")),
Port: rapid.Uint16().Draw(t, "Port"),
Family: family,
Protocol: Protocol(rapid.Uint16().Draw(t, "Protocol")),
}
}).Draw(t, "svc")

ae := netlink.NewAttributeEncoder()
ae.Do(cipvs.CmdAttrService, packService(svc))
p, err := ae.Encode()

assert.NilError(t, err)

ad, err := netlink.NewAttributeDecoder(p)
assert.NilError(t, err)

var out ServiceExtended
for ad.Next() {
if ad.Type() == cipvs.CmdAttrService {
ad.Do(unpackService(&out))
}
}

assert.NilError(t, ad.Err())
assert.DeepEqual(t, out.Service, svc, cmp.Comparer(NetipAddrCompare))
})
}

func TestDestinations_Pack(t *testing.T) {
type testCase struct {
name string
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# 2024/07/07 01:08:05.415620 [TestService_PackUnpack] [rapid] draw svc: ipvs.Service{Address:netip.Addr{addr:netip.uint128{hi:0x0, lo:0x0}, z:(*intern.Value)(0xc00011c0a8)}, Netmask:netmask.Mask{mask:0x0, z:2}, Scheduler:"", Timeout:0x0, Flags:0x0, Port:0x0, FWMark:0x0, Family:0xa, Protocol:0x0}
# 2024/07/07 01:08:05.416260 [TestService_PackUnpack] assertion failed:
# --- out.Service
# +++ svc
# ipvs.Service{
# Address: s"::",
# - Netmask: s"invalid Mask",
# + Netmask: s"0",
# Scheduler: "",
# Timeout: 0,
# ... // 5 identical fields
# }
#
v0.4.8#30582461511489384
0x0
0x1
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0
0x0

0 comments on commit e906274

Please sign in to comment.