Files
3x-ui/internal/amneziawgnet/identity_test.go
T
MHSanaei ecd817658c fix(amneziawg): attribute an equal-prefix source to the peer the device picks
PeerIndex names the peer a source address came from, but for two peers
holding the same prefix, which only a default route can be after the
overlap check, it kept the first while amneziawg-go's allowed-IPs table
hands the prefix to the peer configured last. Traffic was then billed
to a different client than the one the device accepted it from.

An equal-length match now goes to the later peer, as in the device.
2026-11-01 10:02:11 +01:00

73 lines
2.1 KiB
Go

package amneziawgnet
import (
"net/netip"
"slices"
"testing"
"github.com/mhsanaei/3x-ui/v3/internal/amneziawg"
"github.com/mhsanaei/3x-ui/v3/internal/util/wireguard"
)
// TestPeerIndexLookupMatchesDeviceAllowedIPs catches Lookup attributing a
// prefix two peers both carry to a peer the device accepts no such source from.
func TestPeerIndexLookupMatchesDeviceAllowedIPs(t *testing.T) {
serverPriv, serverPub, err := wireguard.GenerateWireguardKeypair()
if err != nil {
t.Fatalf("generate server keypair: %v", err)
}
var peers []amneziawg.Peer
for _, p := range []amneziawg.Peer{
{Email: "first@example.com", AllowedIPs: []string{"10.202.0.2/32", "fd00:202::2/128", "0.0.0.0/0", "::/0"}},
{Email: "last@example.com", AllowedIPs: []string{"10.202.0.3/32", "fd00:202::3/128", "0.0.0.0/0", "::/0"}},
} {
if _, p.PublicKey, err = wireguard.GenerateWireguardKeypair(); err != nil {
t.Fatalf("generate peer keypair: %v", err)
}
peers = append(peers, p)
}
dev, err := NewDevice(amneziawg.Instance{
Id: 1,
PrivateKey: serverPriv,
PublicKey: serverPub,
Address: []string{"10.202.0.1/24"},
MTU: 1420,
Peers: peers,
}, DeviceOptions{})
if err != nil {
t.Fatalf("NewDevice: %v", err)
}
defer dev.Close()
dump, err := dev.IpcGet()
if err != nil {
t.Fatalf("IpcGet: %v", err)
}
_, states := parseUAPIDump(dump)
idx := NewPeerIndex(peers)
for _, tc := range []struct{ addr, prefix string }{
{"10.99.0.1", "0.0.0.0/0"},
{"fd00:99::1", "::/0"},
{"10.202.0.2", "10.202.0.2/32"},
{"10.202.0.3", "10.202.0.3/32"},
{"fd00:202::2", "fd00:202::2/128"},
{"fd00:202::3", "fd00:202::3/128"},
} {
t.Run(tc.addr, func(t *testing.T) {
got, ok := idx.Lookup(netip.MustParseAddr(tc.addr))
if !ok {
t.Fatalf("Lookup(%s) found no peer", tc.addr)
}
gotHex, err := wireguard.KeyToHex(got.PublicKey)
if err != nil {
t.Fatalf("KeyToHex: %v", err)
}
if !slices.Contains(states[gotHex].allowedIPs, tc.prefix) {
t.Errorf("Lookup(%s) = %s, but the device holds %s for another peer", tc.addr, got.Email, tc.prefix)
}
})
}
}