Skip to main content

Device

Struct Device 

Source
pub struct Device { /* private fields */ }
Expand description

Tailscale client.

Implementations§

Source§

impl Device

Source

pub fn udp_bind<'p>( &self, py: Python<'p>, addr: (IpRepr, u16), ) -> PyResult<Bound<'p, PyAny>>

Bind a new UDP socket on the given addr.

addr must be given as (host, port). Presently, host must be an IP.

Source

pub fn tcp_listen<'p>( &self, py: Python<'p>, addr: (IpRepr, u16), ) -> PyResult<Bound<'p, PyAny>>

Bind a new TCP listen socket on the given addr and port.

addr must be given as (host, port). Presently, host must be an IP.

Source

pub fn tcp_connect<'p>( &self, py: Python<'p>, addr: (IpRepr, u16), ) -> PyResult<Bound<'p, PyAny>>

Create a new TCP connection to the given addr.

addr must be given as (host, port). Presently, host must be an IP.

Source

pub fn ipv4_addr<'p>(&self, py: Python<'p>) -> PyResult<Bound<'p, PyAny>>

Get the device’s IPv4 tailnet address.

Source

pub fn ipv6_addr<'p>(&self, py: Python<'p>) -> PyResult<Bound<'p, PyAny>>

Get the device’s IPv6 tailnet address.

Source

pub fn peer_by_name<'p>( &self, py: Python<'p>, name: String, ) -> PyResult<Bound<'p, PyAny>>

Look up info about a peer by its name.

name may be an unqualified hostname or a fully-qualified name.

Source

pub fn self_node<'p>(&self, py: Python<'p>) -> PyResult<Bound<'p, PyAny>>

Get this device’s node info.

Source

pub fn peer_by_tailnet_ip<'p>( &self, py: Python<'p>, ip: IpRepr, ) -> PyResult<Bound<'p, PyAny>>

Look up a peer by its tailnet IP address.

Source

pub fn peers_with_route<'p>( &self, py: Python<'p>, ip: IpRepr, ) -> PyResult<Bound<'p, PyAny>>

Look up peer(s) with the most specific route match for the given address.

If more than one peer has the same route covering the same address, more than one result may be returned.

Source

pub fn status<'p>(&self, py: Python<'p>) -> PyResult<Bound<'p, PyAny>>

Snapshot of this device and its tailnet peers (like tailscale status).

Returns a dict {"self_node": <node>|None, "peers": [<node>, ...]} where each node carries stable_id, display_name, ipv4, ipv6, online, allowed_routes, and is_exit_node.

Source

pub fn whois<'p>( &self, py: Python<'p>, addr: String, ) -> PyResult<Bound<'p, PyAny>>

Map a tailnet source addr to the node that owns its IP (like tsnet’s WhoIs).

addr may be an ip or host:port string; only the IP is used. Returns None if no tailnet node owns that address.

Source

pub fn netmap<'p>(&self, py: Python<'p>) -> PyResult<Bound<'p, PyAny>>

One-shot snapshot of the current netmap peers (the current value of the netmap watch).

Returns the list of peer nodes as of now, in the same shape as status()["peers"]. Mirrors reading the current value off tsnet’s WatchIPNBus subscription.

Source

pub fn resolve<'p>( &self, py: Python<'p>, name: String, ) -> PyResult<Bound<'p, PyAny>>

Resolve a tailnet peer (or this node) by MagicDNS name to its tailnet IPv4 address.

Returns the IPv4 address as a string, or None if no tailnet node has that name. This is an in-process netmap lookup — it does not query any DNS server. IPv6 is not resolved (this fork is IPv4-only on the tailnet).

Source

pub fn connect_by_name<'p>( &self, py: Python<'p>, name: String, port: u16, ) -> PyResult<Bound<'p, PyAny>>

Connect to a tailnet peer by MagicDNS name and port over TCP.

Resolves name via Device::resolve (an in-process netmap lookup, no DNS server), then dials the resulting tailnet IPv4 address. Raises if the name does not resolve to a tailnet node. Returns the same TcpStream as tcp_connect.

Source

pub fn ping<'p>( &self, py: Python<'p>, addr: IpRepr, timeout_ms: u64, ) -> PyResult<Bound<'p, PyAny>>

Ping a tailnet peer over the overlay with an ICMPv4 echo (like tailscale ping).

addr is the peer’s tailnet IP; timeout_ms is the timeout in milliseconds. Returns the round-trip time in milliseconds (a float), or raises on timeout / unsupported IPv6 destination. The echo is sent from this device’s own tailnet IPv4 over the overlay netstack — never a host socket.

Source

pub fn get_certificate<'p>( &self, py: Python<'p>, name: String, ) -> PyResult<Bound<'p, PyAny>>

Obtain a TLS certificate for a node’s MagicDNS name (like tsnet’s GetCertificate).

Fail-closed. This fork has no client-side ACME engine and no set-dns RPC, so this ALWAYS raises a Python exception carrying the underlying CertError (issuance is unimplemented). It NEVER self-signs and NEVER returns a placeholder certificate. When ACME issuance lands upstream, this starts succeeding with no API change.

Source

pub fn listen_tls<'p>( &self, py: Python<'p>, serve_config: ServeConfigArg, ) -> PyResult<Bound<'p, PyAny>>

Build a TLS listener config for serve_config on the overlay (like tsnet’s ListenTLS).

serve_config is a mapping {"name": str, "port": int, "target": <target>} where target is "accept" or {"proxy": "host:port"}.

Fail-closed. Delegates to Device::get_certificate; because no real certificate can be issued in this fork, this ALWAYS raises the same CertError rather than ever serving a self-signed cert or downgrading to plaintext. The serve config is validated first, so an off-tailnet name / zero port / empty proxy target raises a distinct error.

Source

pub fn fetch_id_token<'p>( &self, py: Python<'p>, audience: String, ) -> PyResult<Bound<'p, PyAny>>

Fetch an OIDC ID token from control scoped to audience (like tailscale id-token).

Returns the signed JWT as a string. The sub claim is this node’s MagicDNS name and the aud claim is audience, suitable for workload-identity federation (AWS/GCP). Raises if control does not support id-token issuance.

Source

pub fn metrics(&self) -> String

Snapshot this process’s client metrics in Prometheus text exposition format.

The metric registry is process-global, so the returned text covers every Device in the process. Synchronous — no overlay round-trip is involved.

Source

pub fn self_key_expiry_unix<'p>( &self, py: Python<'p>, ) -> PyResult<Bound<'p, PyAny>>

This node’s key-expiry instant as Unix seconds, or None if the key never expires.

This fork is reactive about key expiry (it reports rather than rotating in the background); schedule re-authentication around this time.

Source

pub fn self_key_expired<'p>(&self, py: Python<'p>) -> PyResult<Bound<'p, PyAny>>

Whether this node’s key has expired as of now. A key with no expiry is never expired.

Source

pub fn taildrop_waiting_files(&self) -> PyResult<Vec<(String, u64)>>

List the Taildrop files this device has fully received and not yet consumed.

Returns a list of dicts {"name": str, "size": int}, sorted by name. Returns an empty list when Taildrop is disabled (fail-closed, never an error). Synchronous (a local filesystem listing).

Source

pub fn taildrop_delete_file(&self, name: String) -> PyResult<()>

Delete a received Taildrop file by name (path-traversal-safe; validated in the store).

Raises when Taildrop is disabled, the name is invalid, or the file does not exist. Synchronous (a local filesystem delete).

Source

pub fn taildrop_save_file( &self, name: String, dst_path: String, ) -> PyResult<u64>

Save a received Taildrop file by name to dst_path on the local filesystem.

Opens the received file via the store (path-traversal-safe) and copies its bytes to dst_path, returning the number of bytes written. Pyo3 cannot hand back a raw file handle, so this save-to-path shape is the Pythonic equivalent of Go’s OpenFile. Synchronous (local filesystem I/O). Raises when Taildrop is disabled, the name is invalid, the source file does not exist, or dst_path cannot be written.

Source

pub fn send_file<'p>( &self, py: Python<'p>, peer_name: String, file_name: String, src_path: String, ) -> PyResult<Bound<'p, PyAny>>

Send a local file at src_path to tailnet peer peer_name via Taildrop (Go PushFile).

Resolves peer_name via peer_by_name, opens src_path as a tokio file, and streams it to the peer’s peerAPI over the encrypted overlay (never a host socket). file_name is the base name the receiver sees. Raises when the peer is unknown, the peer advertises no IPv4 peerAPI, or the transfer fails.

Source

pub fn capture_pcap<'p>( &self, py: Python<'p>, dst_path: String, ) -> PyResult<Bound<'p, PyAny>>

Begin a debug packet capture, writing a pcap of every dataplane packet to dst_path.

Opens dst_path and streams a classic pcap (Tailscale LINKTYPE_USER0) of every plaintext IP packet — outbound (pre-encrypt) and inbound (post-decrypt) — until stop_capture is called. Records are buffered and flushed on stop. Opens in Wireshark with Tailscale’s ts-dissector.lua.

Source

pub fn stop_capture<'p>(&self, py: Python<'p>) -> PyResult<Bound<'p, PyAny>>

Stop a packet capture started by capture_pcap.

Clears the dataplane capture hook; the writer is dropped and its buffered bytes flushed. Idempotent — stopping when no capture is installed is a no-op.

Source

pub fn loopback<'p>(&self, py: Python<'p>) -> PyResult<Bound<'p, PyAny>>

Start a host-loopback SOCKS5 proxy that dials into the tailnet (Go tsnet.Loopback).

Returns a tuple (addr, proxy_cred, handle) where addr is the bound 127.0.0.1:port string, proxy_cred is the SOCKS5 password (username is tsnet), and handle is a LoopbackHandle whose .stop() (or garbage collection) stops the proxy. Hold the handle for exactly as long as you want the proxy alive. Raises in TUN transport mode.

Source

pub fn tka_status<'p>(&self, py: Python<'p>) -> PyResult<Bound<'p, PyAny>>

Fetch the current Tailnet Lock (TKA) status pushed by control, if any.

Returns None when control has sent no TKAInfo, else a dict {"head": str, "disabled": bool} where head is the base32 (no-pad) AUMHash of the latest applied Authority Update Message.

Source

pub fn listen_funnel<'p>( &self, py: Python<'p>, serve_config: ServeConfigArg, funnel_only: bool, ) -> PyResult<Bound<'p, PyAny>>

Build a Funnel TLS listener config for serve_config (like tsnet’s ListenFunnel).

serve_config has the same shape as listen_tls. funnel_only (default False) rejects tailnet-internal connections, serving only public Funnel ingress.

Fail-closed. Enforces the node-attribute / port gates first, then obtains the node’s *.ts.net cert via the ACME-aware path (raising FunnelError on cert failure — never plaintext or a self-signed cert). On success the funnel ingress listener is registered; the returned FunnelAcceptedReceiver is dropped here (Python holds no Rust receiver), so this surfaces only the gate/cert outcome. The public ingress relay that feeds it is Tailscale infrastructure, present only against real Tailscale SaaS.

Source

pub fn listen_service<'p>( &self, py: Python<'p>, service_name: String, mode: ServiceModeArg, ) -> PyResult<Bound<'p, PyAny>>

Host a Tailscale VIP service (svc:<label>) by service_name (like ListenService).

mode is a dict {"mode": "tcp"|"http", "port": int}. Returns a [TcpListener] bound on the service’s control-assigned VIP over the overlay netstack.

Fail-closed. The service_name must be a valid svc:<dns-label>, this node must be tagged, and control must have assigned the service a VIP on this node; any unmet precondition raises before binding.

Trait Implementations§

Source§

impl DerefToPyAny for Device

Source§

impl ExtractPyClassWithClone for Device

Source§

impl<'py> IntoPyObject<'py> for Device

Source§

type Target = Device

The Python output type
Source§

type Output = Bound<'py, <Device as IntoPyObject<'py>>::Target>

The smart pointer type to use. Read more
Source§

type Error = PyErr

The type returned in the event of a conversion error.
Source§

fn into_pyobject( self, py: Python<'py>, ) -> Result<<Self as IntoPyObject<'_>>::Output, <Self as IntoPyObject<'_>>::Error>

Performs the conversion.
Source§

impl PyClass for Device

Source§

const NAME: &str = "Device"

Name of the class. Read more
Source§

type Frozen = True

Whether the pyclass is frozen. Read more
Source§

impl PyClassImpl for Device

Source§

const MODULE: Option<&str>

Module which the class will be associated with. Read more
Source§

const IS_BASETYPE: bool = false

#[pyclass(subclass)]
Source§

const IS_SUBCLASS: bool = false

#[pyclass(extends=…)]
Source§

const IS_MAPPING: bool = false

#[pyclass(mapping)]
Source§

const IS_SEQUENCE: bool = false

#[pyclass(sequence)]
Source§

const IS_IMMUTABLE_TYPE: bool = false

#[pyclass(immutable_type)]
Source§

const RAW_DOC: &'static CStr = /// Tailscale client.

Docstring for the class provided on the struct or enum. Read more
Source§

const DOC: &'static CStr

Fully rendered class doc, including the text_signature if a constructor is defined. Read more
Source§

type Layout = <<Device as PyClassImpl>::BaseNativeType as PyClassBaseType>::Layout<Device>

Description of how this class is laid out in memory
Source§

type BaseType = PyAny

Base class
Source§

type ThreadChecker = NoopThreadChecker

This handles following two situations: Read more
Source§

type PyClassMutability = <<PyAny as PyClassBaseType>::PyClassMutability as PyClassMutability>::ImmutableChild

Immutable or mutable
Source§

type Dict = PyClassDummySlot

Specify this class has #[pyclass(dict)] or not.
Source§

type WeakRef = PyClassDummySlot

Specify this class has #[pyclass(weakref)] or not.
Source§

type BaseNativeType = PyAny

The closest native ancestor. This is PyAny by default, and when you declare #[pyclass(extends=PyDict)], it’s PyDict.
Source§

fn items_iter() -> PyClassItemsIter

Source§

fn lazy_type_object() -> &'static LazyTypeObject<Self>

Source§

fn dict_offset() -> Option<PyObjectOffset>

Used to provide the dictoffset slot (equivalent to tp_dictoffset)
Source§

fn weaklist_offset() -> Option<PyObjectOffset>

Used to provide the weaklistoffset slot (equivalent to tp_weaklistoffset
Source§

impl PyMethods<Device> for PyClassImplCollector<Device>

Source§

fn py_methods(self) -> &'static PyClassItems

Source§

impl PyTypeInfo for Device

Source§

const NAME: &str = <Self as ::pyo3::PyClass>::NAME

👎Deprecated since 0.28.0:

prefer using ::type_object(py).name() to get the correct runtime value

Class name.
Source§

const MODULE: Option<&str> = <Self as ::pyo3::impl_::pyclass::PyClassImpl>::MODULE

👎Deprecated since 0.28.0:

prefer using ::type_object(py).module() to get the correct runtime value

Module name, if any.
Source§

fn type_object_raw(py: Python<'_>) -> *mut PyTypeObject

Returns the PyTypeObject instance for this type.
Source§

fn type_object(py: Python<'_>) -> Bound<'_, PyType>

Returns the safe abstraction over the type object.
Source§

fn is_type_of(object: &Bound<'_, PyAny>) -> bool

Checks if object is an instance of this type or a subclass of this type.
Source§

fn is_exact_type_of(object: &Bound<'_, PyAny>) -> bool

Checks if object is an instance of this type.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Converts Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Converts Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Converts &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Converts &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSend for T
where T: Any + Send,

Source§

fn into_any_send(self: Box<T>) -> Box<dyn Any + Send>

Converts Box<Trait> (where Trait: DowncastSend) to Box<dyn Any + Send>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_sync(self: Box<T>) -> Box<dyn Any + Send + Sync>

Converts Box<Trait> (where Trait: DowncastSync) to Box<dyn Any + Send + Sync>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Converts Arc<Trait> (where Trait: DowncastSync) to Arc<Any>, which can then be downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<A, T> DynMessage<A> for T
where A: Actor + Message<T>, T: Send + 'static,

Source§

fn handle_dyn<'a>( self: Box<T>, state: &'a mut A, actor_ref: ActorRef<A>, tx: Option<Sender<Result<Box<dyn Any + Send>, SendError<Box<dyn Any + Send>, Box<dyn Any + Send>>>>>, stop: &'a mut bool, ) -> Pin<Box<dyn Future<Output = Result<(), Box<dyn ReplyError>>> + Send + 'a>>

Handles the dyn message with the provided actor state, ref, and reply sender.
Source§

fn as_any(self: Box<T>) -> Box<dyn Any>

Casts the type to a Box<dyn Any>.
Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<'py, T> IntoPyObjectExt<'py> for T
where T: IntoPyObject<'py>,

Source§

fn into_bound_py_any(self, py: Python<'py>) -> Result<Bound<'py, PyAny>, PyErr>

Converts self into an owned Python object, dropping type information.
Source§

fn into_py_any(self, py: Python<'py>) -> Result<Py<PyAny>, PyErr>

Converts self into an owned Python object, dropping type information and unbinding it from the 'py lifetime.
Source§

fn into_pyobject_or_pyerr(self, py: Python<'py>) -> Result<Self::Output, PyErr>

Converts self into a Python object. Read more
Source§

impl<T> PyErrArguments for T
where T: for<'py> IntoPyObject<'py> + Send + Sync,

Source§

fn arguments(self, py: Python<'_>) -> Py<PyAny>

Arguments for exception
Source§

impl<T> PyTypeCheck for T
where T: PyTypeInfo,

Source§

const NAME: &'static str = T::NAME

👎Deprecated since 0.27.0:

Use ::classinfo_object() instead and format the type name at runtime. Note that using built-in cast features is often better than manual PyTypeCheck usage.

Name of self. This is used in error messages, for example.
Source§

fn type_check(object: &Bound<'_, PyAny>) -> bool

Checks if object is an instance of Self, which may include a subtype. Read more
Source§

fn classinfo_object(py: Python<'_>) -> Bound<'_, PyAny>

Returns the expected type as a possible argument for the isinstance and issubclass function. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> Ungil for T
where T: Send,

Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more