From: Yeonggi Kim <[email protected]>
Hi Amaury, Frederic,
Following your comment on github issue #3503, here is a series which
sets the source address of the three packets emitted without connection
(Retry, stateless reset and Version Negotiation), as qc_snd_buf()
already does for connections using the listener socket. As you
suggested, each send function gets an extra source address parameter
next to the destination one, and each one is fixed in its own patch.
1/5 MINOR: prerequisite, adds quic_sock_sendto(), a sendto()-like
function with an optional source address relying on the existing
cmsg_set_saddr(), and two inline helpers. The wildcard-only rule
of qc_may_use_saddr() (EINVAL on FreeBSD for a specific bind) is
moved into one of them so that it is shared.
2/5 BUG/MEDIUM: Retry
3/5 BUG/MINOR: stateless reset
4/5 BUG/MINOR: Version Negotiation
5/5 REGTESTS: new reg-tests/quic/retry_wildcard.vtc
Testing was done on Linux (Debian 13, OpenSSL 3.5.7, aarch64) :
- retry_wildcard.vtc: a QUIC backend connects to 127.0.0.2 on a server
bound on 0.0.0.0 with quic-force-retry. It fails on current master
(Retry sent from 127.0.0.1 and dropped by the connected backend
socket, confirmed with a capture), and passes with the series. The
same test targeting 127.0.0.1 passes on master. It is limited to
Linux, where all of 127.0.0.0/8 is local, and I checked that it is
skipped on an osx build.
- stateless reset and Version Negotiation cannot be triggered from
vtest, so they were checked manually in network namespaces with the
VIPs on the server loopback and the client routing them through a
veth, which is the IPVS direct routing layout where we first hit the
issue. One datagram per packet type (Initial without token, unknown
version, short header with an unknown DCID), checking the source of
the reply, on [email protected], [email protected] with sock-per-conn
force-off, quic6@:::443 and quic6@:::443 v4v6. On master all replies
come from the route source address. Each patch fixes exactly its own
packet type, and all replies come from the VIP after the series. A
specific bind (quic4@<VIP>:443) is unchanged. With quic-force-retry
on the wildcard bind, a client with a connected socket (emulated
with aioquic and a firewall rule) cannot complete the handshake on
master, and completes it with the series.
- reg-tests/quic and reg-tests/qmux: 30/30 on master, 31/31 with the
series. Each commit builds with ERR=1 and USE_QUIC=1. The whole
series also builds with USE_QUIC_OPENSSL_COMPAT, without QUIC, and
on macOS.
FreeBSD was not tested. The source address is only set when the listener
is bound on a wildcard address, which is the same rule as the one used
by qc_snd_buf() since 1c33756f78.
Regards,
Yeonggi Kim
Yeonggi Kim (5):
MINOR: quic: define a function to emit a datagram without connection
BUG/MEDIUM: quic: use datagram destination as source for Retry
BUG/MINOR: quic: use datagram destination as source for stateless
reset
BUG/MINOR: quic: use datagram destination as source for version
negotiation
REGTESTS: quic: check Retry source address on a wildcard listener
include/haproxy/quic_sock.h | 30 +++++++++++++
include/haproxy/quic_tx.h | 3 ++
reg-tests/quic/retry_wildcard.vtc | 75 +++++++++++++++++++++++++++++++
src/quic_rx.c | 17 +++++--
src/quic_sock.c | 64 +++++++++++++++++++++++---
src/quic_tx.c | 28 +++++++-----
6 files changed, 195 insertions(+), 22 deletions(-)
create mode 100644 reg-tests/quic/retry_wildcard.vtc
base-commit: 04456142e3ed1d8b5a7d3d39861ee6529458fca7
--
2.50.1 (Apple Git-155)