#!/bin/bash
# Reproducer: WireGuard sticky source address fails for local addresses on
# point-to-point interfaces (inet_confirm_addr vs ifa_address==peer).
#
# Topology (all in netns):
#   client <--veth (lan: 192.168.99.0/24)--> server
#   server also has a dummy PtP-addressed iface: 10.9.9.1 peer 10.9.9.2/32
#   client sends wg handshake to 10.9.9.1 (routed over the lan veth).
#
# Correct: server replies FROM 10.9.9.1 (sticky source = dst of initiation).
# Buggy:   server replies from 192.168.99.1 (inet_confirm_addr() rejects the
#          PtP local address, send4() falls back to kernel source selection).
set -e

cleanup() {
	ip netns del wg-c 2>/dev/null || true
	ip netns del wg-s 2>/dev/null || true
}
trap cleanup EXIT
cleanup 2>/dev/null || true

ip netns add wg-c
ip netns add wg-s
ip link add c-eth type veth peer name s-eth
ip link set c-eth netns wg-c
ip link set s-eth netns wg-s

ip -n wg-c addr add 192.168.99.2/24 dev c-eth
ip -n wg-s addr add 192.168.99.1/24 dev s-eth
ip -n wg-c link set c-eth up
ip -n wg-s link set s-eth up
ip -n wg-c link set lo up
ip -n wg-s link set lo up

# PtP-addressed interface on the server (same ifa shape as pppoe:
# ifa_local=10.9.9.1, ifa_address=peer=10.9.9.2, prefixlen 32)
ip -n wg-s link add ptp0 type dummy
ip -n wg-s addr add 10.9.9.1 peer 10.9.9.2/32 dev ptp0
ip -n wg-s link set ptp0 up

# Client reaches the server's PtP-local address over the lan veth
ip -n wg-c route add 10.9.9.1/32 via 192.168.99.1

# WireGuard setup
ckey=$(wg genkey); cpub=$(echo "$ckey" | wg pubkey)
skey=$(wg genkey); spub=$(echo "$skey" | wg pubkey)

ip -n wg-s link add wg0 type wireguard
ip netns exec wg-s wg set wg0 private-key <(echo "$skey") listen-port 51820 \
	peer "$cpub" allowed-ips 172.16.0.2/32
ip -n wg-s addr add 172.16.0.1/24 dev wg0
ip -n wg-s link set wg0 up

# Start capture of server->client wg packets BEFORE bringing the client up
ip netns exec wg-c sh -c \
	'timeout 6 tcpdump -l -c 3 -ni c-eth "udp src port 51820 and dst host 192.168.99.2" > /tmp/wg-ptp-cap.txt 2>/dev/null' &
CAPPID=$!
sleep 1

ip -n wg-c link add wg0 type wireguard
ip netns exec wg-c wg set wg0 private-key <(echo "$ckey") listen-port 51820 \
	peer "$spub" allowed-ips 172.16.0.1/32 endpoint 10.9.9.1:51820 \
	persistent-keepalive 1
ip -n wg-c addr add 172.16.0.2/24 dev wg0
ip -n wg-c link set wg0 up
ip netns exec wg-c ping -c2 -W1 172.16.0.1 >/dev/null 2>&1 || true

wait $CAPPID 2>/dev/null || true
echo "=== server->client wg packets (want src 10.9.9.1) ==="
cat /tmp/wg-ptp-cap.txt

if grep -q "IP 10.9.9.1.51820" /tmp/wg-ptp-cap.txt; then
	echo "PASS: server replied from its PtP address (sticky source works)"
elif grep -q "IP 192.168.99.1.51820" /tmp/wg-ptp-cap.txt; then
	echo "FAIL: server replied from 192.168.99.1 (sticky source discarded - bug present)"
else
	echo "INCONCLUSIVE: no reply captured"
fi
