diff --git a/CHANGELOG.md b/CHANGELOG.md index 00266f93..ab136a14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ Record breaking or significant changes here. All dates are UTC. Put changes for the upcoming release here! +- Changed (Rust API, lang bindings): the `TS_RS_EXPERIMENT` environment variable is no longer required to use the + library. The library logs a warning during initialization, as a reminder that it's still work-in-progress software. + ## [0.5.0](https://github.com/tailscale/tailscale-rs/releases/tag/v0.5.0) - 2026-08-14 - **Breaking** (Rust API, lang bindings, ts_control): Support for `ephemeral` diff --git a/README.md b/README.md index 155b7494..89e6301f 100644 --- a/README.md +++ b/README.md @@ -7,14 +7,8 @@ https://tailscale.com `tailscale-rs` is a work-in-progress Tailscale library written in Rust, with language bindings to C, Elixir, and Python. -> [!CAUTION] -> This software is unstable and insecure. -> -> We welcome enthusiasm and interest, but please **do not** build production software using these -> libraries or rely on it for data privacy until we have a chance to batten down some hatches -> and complete a third-party audit. -> -> See [Caveats](#caveats) for more details. +> [!NOTE] +> This software is under active development. See [Caveats](#caveats) for more details. ## Getting Started @@ -72,32 +66,28 @@ async fn main() -> Result<(), Box> { This software is still a work-in-progress! We are providing it in the open at this stage out of a belief in open-source and to see where the community runs with it, but please be aware of a few important considerations: -- This implementation contains unaudited cryptography and hasn't undergone a comprehensive security analysis. - Conservatively, assume there could be a critical security hole meaning anything you send or receive could be in the - clear on the public Internet. -- There are no compatibility guarantees at the moment. This is early-days software — we may break dependent code - in order to get things right. -- We currently rely on DERP relays for all communication. Direct connections via NAT holepunching will be a seamless - upgrade in the future, but for now, this puts a cap on data throughput. -- The `TS_RS_EXPERIMENT` environment variable is required to be set to `this_is_unstable_software` - for all code linked against `tailscale-rs`; this includes Rust, C, Elixir, and Python code. We'll remove this - requirement after a third-party code/cryptography audit and any necessary fixes. +- There are no compatibility guarantees at the moment. We may break dependent code in order to get things right, + although we will try to avoid doing so gratuitously. +- Direct connections via NAT traversal is a work in progress. Communication may fall back to DERP relaying in more cases, + with a corresponding hit to latency and throughput. +- Core networking functionality is implemented. Many other features are still either in progress or not implemented yet. + See [Status](#status) for details. -## Versioning, Releases, and Compatability +We encourage you to experiment with this library and build things with it, as long as you're okay with these caveats. -We follow semver and aim to make a point release roughly monthly. Since we are pre-1.0, we make no -backwards-compatability guarantees. We are aiming to have a stable 1.0 release as soon as we can, but we currently don't -have a timeline. +## Versioning, Releases, and Compatibility + +We follow semver and aim to make a point release roughly monthly. Since we are pre-1.0, we make no strong +backwards-compatibility guarantees. ## MSRV and Edition The current MSRV is 1.94.1. The current edition is Rust 2024. `tailscale-rs` has a rolling MSRV (Minimum Supported Rust Version) policy to support the current and previous Rust -compiler versions, and the latest -[edition of Rust](https://doc.rust-lang.org/edition-guide/editions/index.html). +compiler versions, and the latest [edition of Rust](https://doc.rust-lang.org/edition-guide/editions/index.html). -We may lag the latest version/edition in rare cases for our dependencies to catch up and for us to perform any necessary +We may periodically lag the MSRV behind this latest version/edition in rare cases for our dependencies to catch up and for us to perform any necessary fixes. ## Platform Support @@ -110,9 +100,8 @@ We support the following platforms and architectures: ## Status -`tailscale-rs` is a work-in-progress - we're still rapidly iterating, fixing bugs, and adding new features. We aim to -keep this section up-to-date, but our [issue tracker](https://github.com/tailscale/tailscale-rs/issues) -is the best way to see the latest updates. +`tailscale-rs` is a work-in-progress. We're still rapidly iterating, fixing bugs, and adding new features. +We aim to keep this section up-to-date, but our [issue tracker](https://github.com/tailscale/tailscale-rs/issues) is the best way to see the latest updates. ### Implemented @@ -133,7 +122,6 @@ timeline or completion: - Direct connections (NAT traversal, STUN, and Disco) - Peer lookups (addressing peers by hostname) -- Third-party code and cryptography audit ### Unsupported diff --git a/examples/README.md b/examples/README.md index d7ad5c33..2c50cabe 100644 --- a/examples/README.md +++ b/examples/README.md @@ -14,9 +14,6 @@ tailnet, referred to as `$AUTH_KEY` below examples take care of that for you - A tailnet policy configured to allow access between your local machine and the example code -Also note the `TS_RS_EXPERIMENT=this_is_unstable_software` environment variable in all the examples -below; for an explanation, see [the Caveats section of the README](../README.md#caveats). - ## Overview Brief descriptions and links to each example. diff --git a/examples/axum/README.md b/examples/axum/README.md index 3b0c9a5e..fbad138b 100644 --- a/examples/axum/README.md +++ b/examples/axum/README.md @@ -7,7 +7,7 @@ An `axum`-based HTTP server that serves a simple webpage over the tailnet. This `tailscale-rs` to be compiled with the `axum` feature: ```sh -$ TS_RS_EXPERIMENT=this_is_unstable_software cargo run --example axum --features axum -- --auth-key $AUTH_KEY --key-file tsrs_keys.json +$ cargo run --example axum --features axum -- --auth-key $AUTH_KEY --key-file tsrs_keys.json ... INFO axum: http server listening url=http://:80/index.html ``` diff --git a/examples/peer_ping/README.md b/examples/peer_ping/README.md index 8ff37f2a..454735f8 100644 --- a/examples/peer_ping/README.md +++ b/examples/peer_ping/README.md @@ -23,7 +23,7 @@ Then, in another terminal, run the example: ```sh # Terminal 2 -$ TS_RS_EXPERIMENT=this_is_unstable_software cargo run --example peer_ping -- --auth-key $AUTH_KEY --key-file tsrs_keys.json --peer :5678 +$ cargo run --example peer_ping -- --auth-key $AUTH_KEY --key-file tsrs_keys.json --peer :5678 ... INFO ts_runtime::multiderp: new home derp region selected region_id=1 latency_ms=12.223305702209473 ... diff --git a/examples/tcp_echo/README.md b/examples/tcp_echo/README.md index 38d5bec8..fa485083 100644 --- a/examples/tcp_echo/README.md +++ b/examples/tcp_echo/README.md @@ -9,7 +9,7 @@ For this example, you can use netcat (`nc`) to test the server. First, start the ```sh # Terminal 1 -$ TS_RS_EXPERIMENT=this_is_unstable_software cargo run --example tcp_echo -- --auth-key $AUTH_KEY --key-file tsrs_keys.json +$ cargo run --example tcp_echo -- --auth-key $AUTH_KEY --key-file tsrs_keys.json ... INFO tcp_echo: listening_addr=:1234 ... diff --git a/src/error.rs b/src/error.rs index e8cd261c..9c781ad6 100644 --- a/src/error.rs +++ b/src/error.rs @@ -25,14 +25,6 @@ pub enum Error { #[error("an error writing out the key file")] KeyFileWrite, - /// The environment variable `TS_RS_EXPERIMENT` was not set. - /// - /// The end-user must set `TS_RS_EXPERIMENT=this_is_unstable_software` to acknowledge that tailscale-rs - /// is early-days experimental software containing bugs, unvalidated cryptography, and no stability - /// or compatibility guarantees. - #[error("the environment variable `{}` was not set", crate::ENV_MAGIC_VAR)] - UnstableEnvVar, - /// An error occurred which can not be anticipated or handled by a library user. /// /// This is likely due to a bug in our code or a rare and unexpected error. diff --git a/src/lib.rs b/src/lib.rs index e9e29185..b4cc7f3a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,10 +57,6 @@ //! //! ## Using `tailscale` //! -//! To use this crate or the language bindings, you will need to set the `TS_RS_EXPERIMENT` env var -//! to `this_is_unstable_software`. We'll remove this requirement after a third-party code/cryptography -//! audit and any necessary fixes. -//! //! Under the hood, we use Tokio for our async runtime. You must also use Tokio, any kind and most //! configurations of Tokio runtimes should work, but there must be one available when you call any //! async API functions. The easiest way to do this is to use `#[tokio::main]`, see the @@ -189,7 +185,9 @@ impl Device { /// # Ok(()) } /// ``` pub async fn new(config: &Config, auth_key: Option) -> Result { - check_magic_env()?; + tracing::warn!( + "tailscale-rs is early software in active development, expect more bugs and missing features than usual." + ); let keys = (&config.key_state).into(); let rt = ts_runtime::Runtime::spawn(ts_runtime::Config { @@ -376,24 +374,3 @@ pub mod keys { NodeKeyPair, NodePrivateKey, NodePublicKey, NodeState, PersistState, }; } - -const ENV_MAGIC_VAR: &str = "TS_RS_EXPERIMENT"; -const ENV_MAGIC_VALUE: &str = "this_is_unstable_software"; - -fn check_magic_env() -> Result<(), Error> { - if std::env::var(ENV_MAGIC_VAR).as_deref() != Ok(ENV_MAGIC_VALUE) { - let warning = format!( - " -check failed: set {ENV_MAGIC_VAR}={ENV_MAGIC_VALUE} to acknowledge that tailscale-rs is early-days -experimental software containing bugs, unvalidated cryptography, and no stability or compatibility -guarantees. - " - ); - - eprintln!("{}", warning.trim()); - - return Err(Error::UnstableEnvVar); - }; - - Ok(()) -} diff --git a/tests/basic.rs b/tests/basic.rs index 5d593763..b04ed5ac 100644 --- a/tests/basic.rs +++ b/tests/basic.rs @@ -197,7 +197,5 @@ async fn test_udp_unidir(tx: &UdpSocket, rx: &UdpSocket) { } async fn make_ts_device() -> Result { - unsafe { std::env::set_var("TS_RS_EXPERIMENT", "this_is_unstable_software") }; - Device::new(&Config::default(), Some(ts_test_util::auth_key().unwrap())).await } diff --git a/ts_python/README.md b/ts_python/README.md index 9a9f5e72..1cef1296 100644 --- a/ts_python/README.md +++ b/ts_python/README.md @@ -36,7 +36,7 @@ if __name__ == "__main__": To run this demo: ```console -$ TS_RS_EXPERIMENT=this_is_unstable_software python demo.py +$ python demo.py ``` ## Building and Usage diff --git a/ts_python/examples/README.md b/ts_python/examples/README.md index 650c0cfa..7f2698b9 100644 --- a/ts_python/examples/README.md +++ b/ts_python/examples/README.md @@ -16,9 +16,6 @@ For all the examples, you'll need: - A tailnet policy configured to allow access between your local machine and the example code, and between the examples themselves -Also note the `TS_RS_EXPERIMENT=this_is_unstable_software` environment variable is required for all -the examples below; for an explanation, see [the Caveats section of the README](../../README.md#caveats). - ## [UDP](udp) A UDP sender and receiver. The sender sends UDP datagrams to the receiver over the tailnet. \ No newline at end of file diff --git a/ts_python/examples/udp/README.md b/ts_python/examples/udp/README.md index 9685d5ae..0bd78127 100644 --- a/ts_python/examples/udp/README.md +++ b/ts_python/examples/udp/README.md @@ -10,7 +10,7 @@ First, start the receiver: ```sh # Terminal 1 -$ TS_RS_EXPERIMENT=this_is_unstable_software ./recv.py $AUTH_KEY_1 5678 +$ ./recv.py $AUTH_KEY_1 5678 ... [:5678] udp bound, local endpoint: ('', 5678) ... @@ -20,7 +20,7 @@ Then, in another terminal, start the sender: ```sh # Terminal 2 -$ TS_RS_EXPERIMENT=this_is_unstable_software ./send.py $AUTH_KEY_2 5678 +$ ./send.py $AUTH_KEY_2 5678 ... [:1234] udp bound, local endpoint: ('', 1234) [:1234->:5678|0001] sent message: b'HELLO' diff --git a/ts_python/examples/udp/recv.py b/ts_python/examples/udp/recv.py index 7b15ba62..53da8c4a 100755 --- a/ts_python/examples/udp/recv.py +++ b/ts_python/examples/udp/recv.py @@ -33,7 +33,7 @@ async def main(auth_key: str, bind_port: int) -> None: if __name__ == "__main__": parser = argparse.ArgumentParser( description="UDP receiver built with `tailscale-py`", - usage="TS_RS_EXPERIMENT=this_is_unstable_software %(prog)s [options]", + usage="%(prog)s [options]", ) parser.add_argument("auth_key", help="auth key to register with tailnet") parser.add_argument("bind_port", help="local UDP port to bind", type=int) diff --git a/ts_python/examples/udp/send.py b/ts_python/examples/udp/send.py index 58810d6d..150eeb52 100755 --- a/ts_python/examples/udp/send.py +++ b/ts_python/examples/udp/send.py @@ -36,7 +36,7 @@ async def main(auth_key: str, peer_ip: str, peer_port: int) -> None: if __name__ == "__main__": parser = argparse.ArgumentParser( description="UDP sender built with `tailscale-py`", - usage="TS_RS_EXPERIMENT=this_is_unstable_software %(prog)s [options]", + usage="%(prog)s [options]", ) parser.add_argument("auth_key", help="auth key to register with tailnet") parser.add_argument("peer_ip", help="peer's tailnet IP address") diff --git a/ts_tunnel/README.md b/ts_tunnel/README.md index 948dbe1d..790cc220 100644 --- a/ts_tunnel/README.md +++ b/ts_tunnel/README.md @@ -21,8 +21,8 @@ tests). ## Security limitations -This crate has not yet been subjected to a code audit by expert cryptography engineers. Conservatively, assume that -there could be a critical security hole that exposes your traffic to attackers. +The code in this crate has been reviewed by third-party security experts. However, it's still relatively young code +that's still being worked on, so depending on your comfort level you may want to conduct your own evaluation. As stated above, this crate by itself is NOT a complete implementation of WireGuard, and should not be used as one.