Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add QUIC Address Discovery to iroh #3049

Open
wants to merge 4 commits into
base: ramfox/net-report-simplify
Choose a base branch
from

Conversation

ramfox
Copy link
Contributor

@ramfox ramfox commented Dec 14, 2024

Description

There were two main things to "solve" on the iroh side:

  1. gross circular dependency between magicsock and the quinn endpoint
  2. needing to handle QAD packets in a special way, like we do with STUN packets that get sent from net-report

The first was accomplished by figuring out how to make MagicSock::spawn be the location that builds the quinn::Endpoint. This is what was changed:

  • implemented AsyncUdpSocket on MagicSock itself, rather than magicsock::Handle
  • magicsock::Handle now contains the quinn::Endpoint
  • we now pass down a server_config as a MagicSock::Option
  • in MagicSock::spawn:
    • after building the MagicSock we now build the quinn::Endpoint using Arc<MagicSock> as the AsyncUdpSocket
    • then we clone the quinn::Endpoint and passed it to the magicsock::Actor (which is independent of MagicSock)
    • give the quinn::Endpoint to the magicsock::Handle, which is the actual struct that we use to interact with the magicsocket
  • the iroh::Endpoint now interacts with the quinn::Endpoint using msock.endpoint() in all places

The second was accomplished by keeping a list of special "QAD addresses" on the NodeMap (NodeMap::qad_addrs), and using specific methods to add_qad_addrs, get_qad_addrs_for_send and get_qad_addrs_for_recv to deal with the fickle way that the quinn::Endpoint expects SocketAddrs to behave when it dials and when it receives packets:

  • before we do a net-report, we first attempt to resolve the RelayUrls in the RelayMap to get the SocketAddrs that we expect we will dial when we do a QAD probe
  • we add those addresses to the NodeMap
  • on the "send" side of the AsyncUdpSocket, after we do our normal checks for QuicMappedAddrs, we then check to see if the QuicMappedAddr is actually just a normal socket addr that we expect to use for QAD. If so, we just send the packets using the get_qad_addr_for_send address
  • on the "recv" side of the AsyncUdpSocket, after we check to see if the recv'd address can be mapped to a QuicMappedAddr & therefore can be received using our normal process, we then check to see if the address is one that we expect for QAD. If so, we make sure to associate the packet with the get_qad_addr_for_recv address and pass it along

The most "unreliable" bits of this are due to dns. Before running a net report, we now have to do dns discovery for all the RelayUrls. I've capped this at 300 ms but it means that until we cache the dns responses then we have this delay before starting net-report. I've also done a bit of a cheat: when we initially start the magicsock::Actor, I've added a call to resolve_qad_addrs that has a timeout of 10 ms, just to send out the dns packets and hopefully get a jump on caching the responses.

Most interesting bit

So...rather than limiting this to QAD, we could actually generalize it (bypass_addrs (bikeshed) rather than qad_addrs) & allow folks to use the Endpoint as a sort of normal quinn::Endpoint, bypassing our special iroh holepunching sauce. You just have to have to add the SocketAddr to the node_map before calling connect so that we know to let packets for that particular address through.

Just a thought, if we ever want to allow that.

conclusion

I don't know if we actually want to do this, but it works!

Test it by editing the listen & connect examples to use RelayMap::Staging & limit net-report to use only QAD probes by replacing line 2450 in magicsock from

        opts = opts.quic_config(quic_config);

to

	opts = net_report::Options::empty().quic_config(quic_config);

And you should see both public and private IP addresses in the "listening addresses" list

depends on #3032

Change checklist

  • Self-review.
  • Documentation updates following the style guide, if relevant.
  • Tests if relevant.
  • All breaking changes documented.

“ramfox” added 3 commits December 14, 2024 02:13
`MagicSock::spawn` creates a `quinn::Endpoint`. `MagicSock` is now an `AsyncUdpSocket`, and can be passed into the `quinn::Endpoint`. `magicsock::Handle` now owns the `quinn::Endpoint`, and `iroh::Endpoint` interacts with the `quinn::Endpoint` through `Handle::endpoint()`.

This allows us to pass the `quinn::Endpoint` to the `magicsock::Actor` for use in QAD, without any circular dependencies.
@ramfox ramfox changed the base branch from main to ramfox/net-report-simplify December 14, 2024 07:27
Copy link

github-actions bot commented Dec 14, 2024

Documentation for this PR has been generated and is available at: https://n0-computer.github.io/iroh/pr/3049/docs/iroh/

Last updated: 2024-12-14T07:48:24Z

@ramfox ramfox force-pushed the ramfox/qad-in-iroh branch 2 times, most recently from 00926bd to 2a51de3 Compare December 14, 2024 07:33
@ramfox ramfox force-pushed the ramfox/qad-in-iroh branch from 2a51de3 to d18f3d1 Compare December 14, 2024 07:47
@ramfox ramfox self-assigned this Dec 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: 🏗 In progress
Development

Successfully merging this pull request may close these issues.

1 participant