Skip to content

[v0.21.x-branch] Backport #10813: Drop tor v2 onion production, keep wire codec faithful#10844

Merged
ziggie1984 merged 2 commits into
v0.21.x-branchfrom
backport-10813-to-v0.21.x-branch
May 26, 2026
Merged

[v0.21.x-branch] Backport #10813: Drop tor v2 onion production, keep wire codec faithful#10844
ziggie1984 merged 2 commits into
v0.21.x-branchfrom
backport-10813-to-v0.21.x-branch

Conversation

@github-actions

Copy link
Copy Markdown

Backport of #10813


Context

This PR is split out from #10795 ("multi: remove deprecated RPCs and
config flags scheduled for 0.21"), which removes everything that was
announced for removal in 0.21 via the 0.20 release notes. That parent
PR was carved into smaller, independently-reviewable PRs by topic;
this is the tor v2 piece.

Tor v2 onion services have been obsolete since October 2021, when
the Tor network dropped support for them. The --tor.v2 flag was deprecated
in 0.20 with a scheduled removal in 0.21, and that's what this PR
ships.

lnd should not produce v2 addresses on any code path anymore, but it
must still verify signatures on and re-broadcast peer
NodeAnnouncement messages that carry v2 entries alongside still-
valid addresses, so we cannot strip v2 from the wire codec.

This PR draws that line: stop producing v2 everywhere, keep the codec
byte-faithful.

What changes

Stop producing v2

  • lncfg.ParseAddressString rejects v2 .onion strings at the
    operator-input boundary, so --externalip, --listen,
    lncli connect <pubkey>@<v2>.onion, and
    lncli wtclient towers add <pubkey>@<v2>.onion fail fast with a
    clear error.
  • The --tor.v2 flag and its sample-config entry are gone (the
    deprecation announced in 0.20).
  • The self-announcement builder filters any v2 entry inherited from a
    previously stored self-node, so upgraded lnd instances never re-emit
    their own v2 onions.
  • tor.OnionHostToFakeIP (the OnionCat v2 → fake-IPv6 helper) and the
    matching decoder cluster (FakeIPToOnionHost, IsOnionFakeIP,
    onionPrefixBytes) are removed. The scheme is v2-only by
    construction — v3 decodes to 35 bytes and doesn't fit in an IPv6
    address.
  • On-disk legacy v2 keys (RSA1024:…) are rejected with the new
    ErrNonV3OnionKey rather than silently regenerating a fresh v3
    service, which would change the advertised onion identity.
  • tor.OnionType enum, AddOnionConfig.Type, and
    watchtower.Config.Type are removed — only V3 was left, the field
    was a no-op pass-through.

Keep the wire codec faithful

lnwire.WriteOnionAddr, graph/db.encodeOnionAddr, and the matching
decoders round-trip v2 bytes so:

  • DataToSign reproduces the exact bytes the remote peer signed,
  • signature validation succeeds,
  • the announcement is persisted to the graph DB and re-broadcast
    across restarts byte-for-byte.

RPC surfaces (GetNodeInfo, DescribeGraph) continue to expose the
full address set so external tools can independently reproduce and
verify the signed bytes.

Breaking changes / operator-facing notes

This is a breaking change for any node still configured with v2. The
--tor.v2 flag has been deprecated since 0.20 and v3 has been the
only working option network-side since October 2021, so there should
be no production node still relying on it, but the migration steps
are:

  • A v2 .onion entry in lnd.conf (under externalip /
    tor.privatekeypath / wtclient.tower etc.) will now cause lnd to
    refuse to start. Remove the entry before upgrading.
  • A pre-existing v2 private key file on disk (v2_onion_private_key,
    or a renamed key whose contents begin with RSA1024:) will cause
    the hidden-service setup to error out at startup with
    ErrNonV3OnionKey. Delete the file to let lnd generate a fresh v3
    service.
  • Peer/tower addresses already persisted from a previous version
    still decode correctly through the wire-faithful codec, only new
    operator input is refused.
  • GetNodeInfo / DescribeGraph continue to expose v2 entries when a
    remote peer's announcement contains them, so downstream tools that
    independently verify announcement signatures keep working.

Tor stopped serving v2 onion services in October 2021; lnd should not
produce v2 addresses anymore, but it must still verify signatures on
and re-broadcast peer NodeAnnouncement messages that carry v2 entries.

Stop accepting v2 as configuration input (lncfg), strip the legacy
`--tor.v2` flag from the sample config, and remove the
`tor.OnionHostToFakeIP` helper. Operator entry points (`--externalip`,
`--listen`, `lncli connect`, `lncli wtclient towers add`) fail fast on
a v2 `.onion` string, so upgrading nodes must remove any v2 entry from
`lnd.conf` before lnd will start.

Filter persisted v2 state before use without rewriting on-disk records:
the self-announcement builder strips any v2 entry inherited from the
stored self-node; the watchtower client drops v2 entries from each
persisted tower's address list (skipping the tower entirely if no
non-v2 address remains); the autopilot connector, graph bootstrapper,
and static-channel backup restore paths skip v2 entries before
attempting outbound dials. Restrict the Tor controller's ADD_ONION
path to v3 keys, including the encrypted on-disk legacy-key fallback.

For inbound announcements, keep the wire codec wire-faithful:
`lnwire.WriteOnionAddr`, `graph/db.encodeOnionAddr`, and the matching
decoders round-trip v2 bytes so `DataToSign` reproduces the bytes the
remote peer signed, signature validation succeeds, and the announcement
is persisted to the graph DB and re-broadcast across restarts byte-for-
byte. RPC surfaces continue to expose the full address set so external
tools can independently reproduce and verify the signed bytes.

Add a netann regression test that signs a [v3, v2, ipv4] announcement,
round-trips it through Encode/Decode, verifies the signature, and
confirms the resulting models.Node preserves the v2 entry. Add a
graph bootstrapper test asserting v2 entries are skipped while v3 and
plain TCP entries on the same node still surface as bootstrap
candidates.

(cherry picked from commit 2ae1db8)
Add a 0.21 release-notes entry covering the `--tor.v2` removal, the
boundary rejection of v2 input on operator entry points, the
persisted-state filtering (self-node announcement, watchtower client,
autopilot, graph bootstrapper, SCB restore), the Tor controller's
v3-only ADD_ONION restriction, and the wire-faithful behavior that
preserves peer-signed v2 entries through `lnwire`, `graph/db`, and
the graph RPCs.

(cherry picked from commit fad749d)

@ziggie1984 ziggie1984 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM

ziggie1984

This comment was marked as duplicate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants