gossvf: zero ContactInfos with multicast auxiliary sockets#8962
gossvf: zero ContactInfos with multicast auxiliary sockets#8962jherrera-jump merged 6 commits intofiredancer-io:mainfrom
Conversation
Gossip already validates the gossip socket address against multicast, but non-gossip sockets (TVU, TPU, repair, etc.) were accepted without checking. A malicious peer could advertise a multicast address for these sockets, causing the validator to send traffic to unintended destinations. Resolves firedancer-io#8396
There was a problem hiding this comment.
Pull request overview
Extends Firedancer’s gossip verification (gossvf) to reject ContactInfo messages that advertise multicast IPv4 addresses on any auxiliary socket (e.g., TPU/TVU/repair), mitigating the risk of a peer inducing unintended multicast traffic.
Changes:
- Adds a multicast IPv4 check across all
ContactInfosockets duringverify_addresses(). - Keeps existing behavior for IPv6 sockets by skipping them (no coercion to zero).
|
This behavior diverges from Agave, so I need to review why that is and how they solve this |
My read of Agave is that it already sanitizes all ContactInfo sockets during deserialization, not just gossip. In TryFrom, the loop at L569 iterates every SocketEntry and calls sanitize_socket(), which rejects multicast via is_multicast(). This covers all socket types — TPU, TVU, repair, etc. The difference is in severity: Agave silently omits the bad socket from the cache (L578-580) but still accepts the ContactInfo into CRDS — only a bad gossip socket triggers full rejection via verify_gossip_addr(). This PR is stricter: it drops the entire ContactInfo at L662, which seems like the right call given there's no legitimate multicast use case — Agave's own codebase explicitly states "Agave does not currently support multicast," and turbine/repair/TPU are all unicast. I'll leave the PR open as is lmk what you think @mmcgee-jump |
Firedancer aims to match Agave's CRDS filtering rules exactly. If either side filters more aggressively it would just cause persistent unnecessary traffic, because the protocol gets into a loop where the more lenient side keeps retransmitting the dropped value to the more aggressively-filtering side over and over. |
Given this, the divergence is entirely Multicast non-gossip socket (TVU, repair, etc.):
So I think to reach parity firedancer should also accept ContactInfo into CRDS but sanitize at deserialization time. I'd implement it by adjusting the current pr's drop to in place zeroing, something like: if( fd_ip4_addr_is_mcast( sock->ip4 ) ) {
sock->ip4 = 0;
sock->port = 0;
}if yall think that makes sense, i'll adjust the PR. edit, parity caveats:
|
|
Updated to match Agave's CRDS filtering: non-gossip multicast sockets are now zeroed in place (ip4=0, port=0) instead of dropping the entire ContactInfo. Deffered for follow up work: txsend and repair treat zeroed sockets as "keep old cached value" rather than "socket absent" |
There was a problem hiding this comment.
Pull request overview
This PR updates the gossvf validation path for incoming gossip ContactInfo CRDS values by adding multicast filtering for non-gossip sockets (TPU/TVU/repair/etc.) during verify_addresses().
Changes:
- Add a loop over all
ContactInfosockets to detect multicast IPv4 addresses. - Zero out (
ip4=0,port=0) any non-IPv6 socket that advertises a multicast IPv4 address.
copilot adjust comment Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
filtering now matches
Summary
Zero out ContactInfo fields from gossip where any auxiliary socket (TVU, TPU, repair, etc.) has a multicast IP address. The gossip socket was already validated against multicast; this extends the check to all other sockets.
verify_addresses()Resolves #8396
cc @mmcgee-jump