Skip to content

fix: advertise what StartOS exposes, report relay reachability; 0.4.9.12:3 → 0.4.9.12:4 - #33

Merged
MattDHill merged 2 commits into
masterfrom
fix/relay-advertise-reachability
Sep 19, 2026
Merged

MattDHill merged 2 commits into
masterfrom
fix/relay-advertise-reachability

Conversation

@stupleb

@stupleb stupleb commented Sep 19, 2026

Copy link
Copy Markdown
Member

The relay advertised whatever address the directory authorities saw on its outbound connections, and the configured OR port. Neither has to match the gateway and external port StartOS actually forwards. Separately, a bare ORPort is also an IPv6 ORPort, and Tor can't see the server's addresses from inside its container, so every relay logged Unable to find IPv6 address for ORPort once an hour (reported on 0.4.9.12:3 behind StartTunnel).

Changes

  • init/advertiseRelay derives from the or-multi binding:

    • Address, when the Public IPv4 address is enabled on exactly one gateway;
    • an ORPort … NoListen / … NoAdvertise pair, when the assigned external port differs from the configured one;
    • IPv4Only, while no public IPv6 address is enabled.

    All of this is stored in torrc and dropped when the OR port changes.

  • New Relay Reachability health check:

    • disabled while relay mode is off;
    • success needs Tor's self-test to pass and a directory authority to have accepted the descriptor, because the reachability flag reads true before any descriptor exists;
    • loading for the 20 minutes Tor gives itself, or 45 minutes when it knows an IPv6 address;
    • fails at once when no public address is enabled, because Tor never revisits a test it has passed;
    • dependents don't reference it.
  • Configure Relay restarts Tor when the OR port of an enabled relay changes. Reloaded onto a new port, Tor opens the new listener but keeps the old port's verdict and publishes a port nothing has tested. Only a start as a relay or an address change makes it test. The OR Port field says so. Turning the relay on or off still only reloads.

  • No IPv6 address is pinned, on purpose. Tor omits an auto-discovered IPv6 address that fails the self-test, but refuses to publish any descriptor while a configured one fails (relay_periodic.c, reachability_warnings_callback).

  • README and instructions updated. The README's claim that the listener is IPv4-only was wrong and is removed.

Verified on a StartOS box (x86_64, home router)

  • Update from 0.4.9.11:8 with relay mode on:
    • torrc became ORPort 9001 IPv4Only plus Address <public IP>;
    • Tor opened 0.0.0.0:9001 only, where the old version also opened [::]:9001;
    • neither "Unable to find … address" notice appeared;
    • the self-test passed 17 s after the update.
  • Public address off:
    • the check failed at once and Address was withdrawn;
    • Tor logged only a reload and never re-tested.
    • Turning it back on pinned the address again and the check passed.
  • OR port set to one another service holds externally:
    • StartOS assigned a different external port;
    • torrc got the NoListen/NoAdvertise pair;
    • after a restart Tor tested the assigned port.
  • OR port changed on a reachable relay:
    • Tor restarted, listened on the new port only and tested it;
    • the check failed at once until a Public address was enabled, then showed loading;
    • enabling and disabling the relay only reloaded.
  • IPv4Only removed nothing: a comparable package port forward is equally unreachable over the box's link-local IPv6, while the OS's own ports answer.

Also verified offline on this package's image (Tor 0.4.9.12)

  • A bare ORPort opens both listeners and logs the IPv6 notice; IPv4Only does neither.
  • All flag combinations pass --verify-config.
  • A torrc round-trip test against the real toFile/fromFile, including the :3 parser reading a :4 file after a downgrade.
  • tsc, prettier and the x86 build pass.

Not verified

  • A relay behind StartTunnel.
  • A public IPv6 address, because the test box has none.
  • The health check's failure after the full 20-minute allowance.

Known, not addressed

FileHelper.merge is an unlocked read-merge-write, and this adds a tenth torrc writer. It writes only when the advertised state actually changes.

stupleb and others added 2 commits September 19, 2026 15:08
….12:3 → 0.4.9.12:4

The relay advertised whatever address the directory authorities saw on its
outbound connections and the configured OR port, neither of which has to match
the gateway and external port StartOS actually forwards. A bare ORPort is also
an IPv6 ORPort, so Tor logged "Unable to find IPv6 address for ORPort" hourly
on every relay, since it cannot see the server's addresses from its container.

- init/advertiseRelay derives from the or-multi binding: Address when the
  Public IPv4 is enabled on exactly one gateway, an ORPort NoListen/NoAdvertise
  pair when the assigned external port differs, and IPv4Only while no public
  IPv6 address is enabled.
- A Relay Reachability health check reports Tor's self-test, requires an
  accepted descriptor as well, and fails at once when no public address is
  enabled, because Tor never revisits a test it has passed.
- Configure Relay restarts Tor when the OR port of an enabled relay changes.
  Reloaded onto a new port, Tor keeps the old port's verdict and publishes a
  port nothing has tested.
- No IPv6 address is ever pinned: Tor refuses to publish any descriptor while
  a configured IPv6 fails its self-test.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Helix-Harness: pi
Helix-Model: openai-codex/gpt-5.6-sol

@helix-a helix-a left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Reviewed the relay advertisement derivation, torrc round-trip, init reactivity, reachability health check, action lifecycle, and docs. I pushed 304db95 to cover one edge case: clearing the optional OR Port field restores 9001, so an enabled relay must restart just as it does for an explicitly entered port change.

Verified with npm ci, npm run check, npm run build, Prettier, tsc --noEmit --noUnusedLocals, and x86_64/aarch64/riscv64 package builds.

@MattDHill
MattDHill merged commit 8372585 into master Sep 19, 2026
4 checks passed
@MattDHill
MattDHill deleted the fix/relay-advertise-reachability branch September 19, 2026 15:20
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.

3 participants