The sync server had no protection (the old transfer guard was
'removed DOS prototection until we can design something better'):
any peer could open unlimited reconciliation sessions, claim an
int.high-sized payload with one length prefix, and push unsolicited
transfer messages for free.
- reconciliation: a RequestRateLimiter now fronts the server handler
(new 'storesync' bucket in --rate-limit, default 30 sessions/5 min,
the cheap check running before any processing); one active session
per peer at a time, enforced on both the serving and initiating
side; payload reads bounded to 64 MiB (large legitimate diffs are
~40 B per difference, so the largest honest rounds stay well under)
- transfer: messages are only accepted from peers with a
reconciliation session in the last 10 minutes; each session
(re)opens that peer's window, unsolicited pushes are dropped,
counted and disconnected. A stricter accept-only-granted-hashes
model was tried and rejected: for an empty or far-behind receiver
the sender computes the diff, so the receiver cannot enumerate the
hashes it is owed
- re-enables the transfer test disabled 'until we impl. DOS
protection again'; adds session-guard, rate-limit and
unsolicited-drop regression tests
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>