Proposal: Machine-readable discovery flag for Lyrebird (Pluggable Transports)

Hi everyone!

I’m popping over from the Whonix community. Lately, we’ve been running into a bit of a headache with integrating downstream Pluggable Transports (PTs). Right now, whenever a new transport like WebTunnel drops, downstream projects have to manually hard-code all the updates for UI menus and AppArmor profiles. It honestly causes a pretty big lag across release cycles!

To fix this and make Lyrebird way easier to integrate right out of the box, I’d love to propose adding a simple discovery flag to the binary—something like lyrebird --capabilities.

If Lyrebird could just spit out a JSON spec to stdout and exit (bypassing the strict environment variable checks that usually keep it from running on its own), downstream projects could figure out what’s supported dynamically! Since Lyrebird has such a nice, modular Go architecture, it feels like this could be added cleanly right in main.go. We could just use the standard flag and encoding/json libraries without needing any extra external dependencies.

Proposed Schema:

{
  "version": "0.8.1",
  "supported_transports": ["obfs4", "webtunnel", "snowflake", "meek"],
  "env_vars_required": [
    "TOR_PT_MANAGED_TRANSPORT_VER", 
    "TOR_PT_STATE_LOCATION",
    "TOR_PT_CLIENT_TRANSPORTS"
  ],
  "sandbox_requirements": {
    "network": ["tcp", "udp"],
    "rw_paths": ["$TOR_PT_STATE_LOCATION"]
  }
}

Why this helps downstream:

  • Zero-Touch UIs: Integrators can easily parse supported_transports to auto-populate Tor connection menus. That means day-one support for new PTs!

  • Automated Sandboxing: Instead of guessing or relying on hardcoded state paths, hardened environments can generate AppArmor or SELinux rules dynamically using the exposed rw_paths.

  • Pre-Execution Validation: Front-end launchers can double-check the required environment variables before running the daemon, which stops those annoying silent crashes.

I just wanted to float the idea here first to see if it matches up with the team’s roadmap. Would a JSON flag like this work for you guys, or do you think extending the official PT spec is a better way to go?

Hi, thank you for the proposal! It’s a good one and well-motivated. We’d like to create a GitLab issue so we can continue to discuss the design details and track progress on it. We’ll have to discuss as a team what is possible and what the complexity tradeoffs are. Would you like to open one yourself in the lyrebird repo? Otherwise I can copy-paste your proposal from here :slight_smile:

“Hi Cecylia, thank you so much for the encouraging feedback! I would really appreciate it if you could copy-paste the proposal and open the GitLab issue on your end. I’d love to follow the team’s discussion on the design details and complexity trade-offs there. Thanks again!”

But is this proposal feasible in long term

I don’t want to promise anything yet before we’ve had a chance to discuss specifics as a team, but in short yes it sounds feasible. The big question is whether we can provide enough details to make this output useful, without adding too much complexity to the code.

One example of something that might need to change is that different transports have different sandbox requirements. Snowflake requires UDP but obfs4 and meek do not. So we might need to make that a property of the transport.

I’m also not sure about how to populate the “rw_paths" you’ve requested here in "sandbox_requirements”. This environment variable should be set by the tor process. So to get the state location used by Tor, the proposed --capabilities command would require a modification of tor to call it, which we probably won’t do.

Here’s the issue I’ve created:

but if it’s easier for you to respond here, we’ll probably continue the discussion here as well.