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

fix(client): wait for public reachability before registering #4

Merged
merged 4 commits into from
Nov 7, 2024

Conversation

aschmahmann
Copy link
Contributor

@aschmahmann aschmahmann commented Oct 30, 2024

This PR attempts to not send out any challenges at all until the libp2p host has signaled that the node is public. The current level of filtering for public IP addresses does not totally work in that if you have a public IPv6 address but it's inaccessible due to a firewall then we will still reach out too early and hit a failure. Some of the current problems with this are:

  1. It delays how long the user has to wait to get a cert due to the internal backoff
  2. It's extra wasted work for both the client and server
  3. The user will see error logs that either they'll be concerned about or learn to ignore entirely, neither of which is really right here

AFAICT this does not work due to a mismatch between the ObsAddrManager and EvtLocalReachabilityChanged as emitted by autonat:

This seems like a bug we'd ideally fix within go-libp2p, but maybe I'm missing something

cc @sukunrt @MarcoPolo @lidel → please discuss in #7

@aschmahmann aschmahmann changed the base branch from feat/initial-implementation to main October 30, 2024 21:21
@lidel lidel mentioned this pull request Nov 4, 2024
28 tasks
@lidel lidel marked this pull request as draft November 4, 2024 19:44
doing this in `Present` was too late, it was called in the middle of the
ACME dance, and we want to avoid the entire ACME management and flow if
we are not publicly reachable.

this change delays management only if there is no certificate cached
locally, and impacts only the very first cold start when p2p-forge
registration needs to occur.

entire ACME/p2p-forge flow can be delayed/disabled on nodes that are not
(yet) publicly diallable by only calling `ManageAsync`
in `func (m *P2PForgeCertMgr) Start() error` once we have connectivity
checks passed.

for now, we just listen for network.ReachabilityPublic, but this can be
refined further in the future.
@lidel lidel changed the title Have client wait for public reachability before attempting a challenge fix(client): wait for public reachability before registering Nov 5, 2024
client/acme.go Outdated
@@ -407,6 +409,25 @@ func (d *dns01P2PForgeSolver) Wait(ctx context.Context, challenge acme.Challenge
func (d *dns01P2PForgeSolver) Present(ctx context.Context, challenge acme.Challenge) error {
h := d.hostFn()
addrs := h.Addrs()

if !d.allowPrivateForgeAddresses {
Copy link
Contributor

@lidel lidel Nov 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aschmahmann doing this in Present is too late, it is called in the middle of the ACME dance, and we want to avoid the entire ACME flow if we are not publicly reachable.

Pushed 5157ed9 which is tackling problem at a higher level: it is delaying calling ManageAsync for respective domain/cert in the top level func (m *P2PForgeCertMgr) Start() error, and the delay occurs only when necessary (no cert cached), and does not occur when you already have a cert.

It seems to do the trick for my Kubo setup (ipv4-only, NAT + port forwarding with uPnP) and also gives us framework for plugging up more nuanced checks if needed (right now it just waits for network.ReachabilityPublic).

Thoughts? Ok to remove this check from Present? (feels too late / redundant)

Copy link
Contributor

@lidel lidel Nov 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed further refactor in d638643 which extracts connectivity checks to separate reusable func withHostConnectivity.

Also filled #7 to tackle IPv6 separately.

moved logic to reusable funcs and adjusted logger for better ux
@lidel lidel marked this pull request as ready for review November 6, 2024 00:02
Copy link
Contributor

@lidel lidel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored slightly so connectivity check is in separate func withHostConnectivity that we can improve later.

I'd like to ship this in Kubo 0.32.0-rc2 as-is, we can refine in follow-up releases. It already handles ipv4 NAT without uPnP correctly:

2024-11-06T01:12:34.218+0100	INFO	autotls.start	client/acme.go:359	no cert found for "*.k51qzi5uqu5dmbef23gjfbtpzbgbm0upn8quu4335d0edxzvmqx9zre6z2nwt5.libp2p.direct"
2024-11-06T01:12:34.218+0100	INFO	autotls.start	client/acme.go:384	waiting until libp2p reports event network.ReachabilityPublic
Swarm listening on 127.0.0.1:4081 (TCP+UDP)
[..]
Daemon is ready
2024-11-06T01:12:51.348+0100	INFO	autotls.start	client/acme.go:394	libp2p reachability status changed to Private
2024-11-06T01:12:51.348+0100	INFO	autotls.start	client/acme.go:399	certificate will not be requested while libp2p reachability status is Private

Filled #7 to tackle IPv6 issue upstream.

@lidel lidel merged commit 17d209b into main Nov 7, 2024
4 checks passed
@lidel lidel deleted the feat/wait-on-libp2p-public branch November 7, 2024 00:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants