├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tailscale" 3 | description = "A set of application-level primitives for Tailscale." 4 | version = "0.1.1" 5 | authors = ["Morgan Gallant "] 6 | edition = "2021" 7 | readme = "README.md" 8 | repository = "https://github.com/xortechnologies/tailscale-rs" 9 | license = "MIT" 10 | keywords = ["tailscale", "ipn", "intranet"] 11 | categories = ["network-programming"] 12 | 13 | [dependencies] 14 | pnet = "0.31.0" 15 | ipnetwork = "0.20.0" 16 | pnet_datalink = "0.31.0" 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 XOR Technologies Corp. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Crate](https://img.shields.io/crates/v/tailscale.svg)](https://crates.io/crates/tailscale) 2 | [![API](https://docs.rs/tailscale/badge.svg)](https://docs.rs/tailscale) 3 | 4 | __tailscale-rs__ is an unofficial client library for [Tailscale](https://tailscale.com). Its purpose is to provide application-level primitives for accessing the Tailscale interface of a machine, as well as utilities for building distributed systems such as automatic peer discovery. Feature requests are welcome and encouraged! 5 | 6 | All versions v0.X.X are unofficial, and if Tailscale, Inc. chooses to create an official client library, the ownership of this crate will be transferred to them to release and maintain V1+. At this time, breaking API changes may or may not be introduced. 7 | 8 | ### Changelog 9 | 10 | All changes to this crate over time will be documented here. 11 | 12 | #### V0.1.1 13 | 14 | - Fixed documentation typos. 15 | 16 | #### V0.1.0 17 | 18 | - Added the ability to query for a machine's Tailscale interface IPv4 address. 19 | - Published to crates.io. 20 | 21 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! tailscale-rs is a client library for [Tailscale](https://tailscale.com). 2 | //! 3 | //! All versions v0.X.X are unofficial, and if Tailscale, Inc. chooses 4 | //! to create an official client library, the ownership of this crate 5 | //! will be transferred to them to release and maintain V1+. At this 6 | //! time, breaking API changes may or may not be introduced. 7 | extern crate ipnetwork; 8 | extern crate pnet; 9 | 10 | use ipnetwork::IpNetwork; 11 | use std::net::IpAddr; 12 | 13 | fn maybe_tailscale(s: &str) -> bool { 14 | s.starts_with("wg") 15 | || s.starts_with("ts") 16 | || s.starts_with("tailscale") 17 | || s.starts_with("utun") 18 | } 19 | 20 | /// Retrieve the IP address of the current machine's Tailscale interface, if any. 21 | /// ``` 22 | /// let iface = tailscale::interface().expect("no tailscale interface found"); 23 | /// ``` 24 | pub fn interface() -> Option { 25 | let ifaces = pnet_datalink::interfaces(); 26 | let netmask: IpNetwork = "100.64.0.0/10".parse().unwrap(); 27 | ifaces 28 | .iter() 29 | .filter(|iface| maybe_tailscale(&iface.name)) 30 | .flat_map(|iface| iface.ips.clone()) 31 | .filter(|ipnet| ipnet.is_ipv4() && netmask.contains(ipnet.network())) 32 | .map(|ipnet| ipnet.ip()) 33 | .next() 34 | } 35 | --------------------------------------------------------------------------------