-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Cannot advertise WebTransport with public IP addresses discovered by identify (e.g. port forwarding behind a NAT with a dynamic public IP) #2233
Comments
We don't do address discovery via AutoNAT any more (#2148). But you're raising an interesting point, especially for #2229: How should AutoNAT treat WebTransport addresses when certificates are rotated? One could argue that AutoNAT should only care about the part before the certificate hash. This would make sure that the WebTransport address doesn't change its NAT status when we rotate certificates. However, it would be nice if AutoNAT would discover if there was a problem with the certificate hashes. Alternatively, we could write a bit of extra logic for WebTransport addresses: When certificates are rotated, we could just "transfer" the NAT status from the old to the new address, so that there's no downtime for WebTransport addresses. We'd then retroactively confirm that the new address actually works. |
@marten-seemann perhaps a different case, but @MarcoPolo was effectively filing a placeholder issue here for something I was reporting (thanks Marco 🙏). User ProblemIf I enable port forwarding on my router say 4001 -> mymachine:4001 and leave everything default (except UPnP disabled) then eventually my node discovers its public addresses via identify and then I can start advertising public addresses and become reachable 🎉. However, this does not work with (ipv4) WebTransport addresses. Technical issueI think where things are currently falling apart is here go-libp2p/p2p/protocol/identify/obsaddr.go Lines 378 to 379 in 8c466ab
Unfortunately, doing this comparison fails because FixI'm not sure which fix is most correct. Obviously we could just filter out the certhashes from the listen addresses before doing the comparison, but in order to run into fewer problems here I suspect (in lieu of having types that enforce this) we need at least:
Any ideas what's correct here (e.g. should
|
Had a chat with @MarcoPolo today about this and it seems like a reasonable strategy here would be something like:
There are some tradeoffs here that seem fine, including:
|
Maybe not, I think @MarcoPolo favored this approach of allowing the transports to do more of the transport-specific work. This seems pretty reasonable, it definitely felt pretty bad in the two PRs linked above to be putting in knowledge specifically about webtransport into the host/contructor code when it feels like it should just be another transport.
Yeah, I get it. When you have a larger refactor in mind the last thing you want are more moving pieces.
It does make me feel better that it's a P0, but it seems like it's going to be a lot of work/time to land especially given upcoming events, etc. I'm really excited about all the work libp2p has done with WebTransport 🎉 so trying to find ways we can get at it sooner. Do you have any ideas around how this could be implemented in a way that's more compatible with how you see the refactor playing out? |
Yes, realistically speaking this won’t happen before IPFS Thing. I think I’d prefer to just merge your PR, as it’s the most succinct solution of the problem. As you’ve said, it’s not the cleanest way to solve it, but at least it doesn’t introduce too many new moving parts. |
We could do the most minimal thing here, which is a bit hacky:
It's hacky because 1 & 3 involve these components having special knowledge of the whole system. But it would probably be the fastest and smallest short term fix. And we could write a test for the behavior to protect against a future regression. |
That sounds reasonable. There won’t be any way of having an address pipeline that doesn’t have special knowledge of certhashes if we
I think that’s fine, as long as this doesn’t leak out of the pipeline (see what I did there ;)). |
I think this might be clear already, but just making sure: Unfortunately there are two issues and mine/Marco's existing PRs don't fix this problem
|
Is there a typo there? Did you mean
Because I think there will be, but we can cross that bridge when we get there. Or am I misunderstanding? |
Have a method that outputs these that are broken in the wild: with js-libp2p@0.43.3 and the connectionGater config of connectionGater: {
denyDialMultiaddr: (peerId, multiaddr) => {
const isWebTransport: boolean = multiaddr.toString().includes('/webtransport')
if (isWebTransport) {
const hasCerthash: boolean = multiaddr.toString().includes('/certhash')
if (!hasCerthash) {
console.log('denyDialMultiaddr: ', peerId.toString(), multiaddr.toString())
return true
}
}
return false
}
}, I get the following output after running for a while
And adding the peerIds I see to a set and doing some numbers:
|
I think there are a few different types of broken here. One is if some advertised addresses are missing certhashes, another is if some addresses aren't advertised at all (e.g. they have private IPs for quic-v1 and webtransport, but only public IPs for quic-v1). Getting an understanding of both sets would be helpful, my guess is the latter is a bigger set than the former but would need to measure to gain more confidence. I'm also not sure if collecting numbers in a browser context (where you have fewer transports) is going to skew the numbers for your collection. It might not, but not sure. |
@MarcoPolo Indeed, that was a very unfortunate typo in my post. I corrected it. Sorry for the confusion caused. Agreed that we need a solution now. We can’t wait for the address pipeline to come into existence. No matter how quickly we manage to write the code for it, it still depends on AutoNAT v2, which requires a gradual rollout. So we’re likely talking about months anyway. I suggest to start thinking about this from an API perspective. Assume that we have the address pipeline, how would the user tell their libp2p stack that they think that their node has a specific public address? Realistically, there are two options:
This would act somewhat similar to the
Kubo could then stop wrapping the Once we have the address pipeline, we can start confirming these addresses via AutoNAT v2. @aschmahmann @MarcoPolo I believe this resolves both problems. Does this make sense to you? Any preferences on the API? I’m leaning towards a constructor option, since I don’t think that users will dynamically discover addresses outside of the libp2p stack (of course, libp2p will do address discovery internally). |
@marten-seemann I'm not sure how your proposal solves the issue with port-forwarding behind a dynamic IP. AFAICT the only thing that would be resolved via giving the host address hints for this case (as opposed to the externally-known IP/DNS address case) is if someone had go-libp2p auto-generated certs for some WebTransport addresses and external CA signed ones for others. However, this isn't possible today in go-libp2p anyway so isn't our current concern. So for dealing with port-forwarding behind a dynamic IP (I'm going to rename this issue to that to avoid confusion with #2223) it seems like the main thing to figure out is where the plumbing goes to deal with attaching the autogenerated WebTransport certhashes to the dynamically discovered via identify public IP addresses. So far there are two options proposed:
I think @MarcoPolo and I are both fine doing option 1 (more hard coding) for now if there's concern about adding extraneous interfaces/public exports and then figuring out how to deal with the abstractions more cleanly (e.g. if we run into a similar issue with WebRTC) later. The proposal around address hints seems better suited for resolving #2223. Does this seem about right to both of you or am I missing something? (Note: I'm changing the issue name, but feel free to change it to something else if you have something better in mind) |
Sorry, posted on the wrong issue 🤦🏻♂️ That said, I've convinced myself that the correct solution is to advertise the address including the certificate hash in Identify. To do that, that's just a super easy fix inside the WebTransport transport, to add the certhashes to the address returned by Why is this the correct solution? Assume a node behind a node that complete scrambles ports is listening on two WebTransport addresses, with different certificate configurations. In that case, the node would need to know which address is which one, and without the certhash, it won't be able to do so. The downside is that this fix will take a while to propagate through the network. Not sure if we can live with that. On the other hand, this would justify implementing the hackiest / easiest solution, since we'll be able remove that code anyway right after the next release. |
Certhashes are generated per host by their key. A host wont have more than one set of certhashes. Also certhashes expire/rollover. We want to keep that in mind when comparing certhashes. |
Because this is preventing the widespread use of webtransport, I'm going to this hacky fix to unblock things: #2233 (comment). @marten-seemann is there something specific with that proposed change you disagree with? |
That's an implementation detail. It would be nice to not hard-code that into any components outside of the WebTransport transport. |
I haven't repro'd this myself yet, but we should investigate and add a test case for this.
The text was updated successfully, but these errors were encountered: