API Reference

The Main ptadapter Module

Python interface for Pluggable Transports

The main module exports the adapter classes, as well as several Named Tuple classes used as return values of adapter class methods.

Adapters

class ptadapter.ClientAdapter(pt_exec, state, transports, proxy=None, *, exit_on_stdin_close=True)

Run a pluggable transport as client.

For each enabled transport, the PT will listen on a port, which can be looked up using get_transport(). Use open_transport_connection() to make a connection through a transport.

This object can be used as an async context manager. On entering the context, the PT is started, and on exiting the PT is stopped. The adapter itself is returned as the “as” variable.

__init__(pt_exec, state, transports, proxy=None, *, exit_on_stdin_close=True)

Create the adapter.

Parameters
  • pt_exec (Union[List[str], List[bytes]]) – The pluggable transport command line to execute. This has to be a list of str / bytes, since asyncio.create_subprocess_exec() does not accept an entire command line as a string. On non-Windows platforms shlex.split() can be used to split a command line string into a list, while on Windows it’s a bit more complicated.

  • state (Union[None, str, bytes, PathLike]) – The state directory. This is a directory where the PT is allowed to store state. Either specify an absolute path (which is not required to exist, in which case the PT will create the directory), or specify None to use a temporary directory created using tempfile.

  • transports (List[str]) – a list of client transports the PT should initialize. PTs will ignore names they don’t recognize.

  • proxy (Optional[str]) – The upstream proxy to use. Must be specified in the URI format: <proxy_type>://[<user_name>[:<password>][@]<ip>:<port>.

  • exit_on_stdin_close (bool) – Whether closing the PT’s STDIN indicates the PT should gracefully exit.

await open_transport_connection(transport, host, port, args, **kwargs)

(async) Open a connection through a client transport.

This method uses get_transport() and asyncio.open_connection(), and their exceptions will not be modified. Additional possible exceptions are listed below.

Parameters
  • transport (str) – Name of the transport.

  • host (Union[str, IPv4Address, IPv6Address]) – Destination IP address or host name. Depending on the PT, host names or IPv6 addresses may not be supported.

  • port (int) – Destination port number.

  • args (Optional[Dict[str, str]]) – Per-connection arguments. Both keys and values should be strings. (Backslash, equal signs and semicolons will be automatically escaped before passing to PT.)

  • kwargs – Any unrecognized keyword arguments are passed to asyncio.open_connection(). This can be useful for specifying limit and local_addr.

Return type

Tuple[StreamReader, StreamWriter]

Returns

A (StreamReader, StreamWriter) tuple.

Raises
get_transport(transport)

Look up initialized client transport methods.

Parameters

transport (str) – Name of the transport.

Return type

ClientTransport

Returns

A ClientTransport NamedTuple for the specified transport.

Raises
await start()

(async) Start the PT executable and wait until it’s ready.

“Ready” means that all transports have finished initializing.

Return type

None

state

The state directory.

If a temporary directory is used, this will be None before the adapter starts, and will be the actual path of the directory after the adapter has started. The temporary directory will be deleted once the adapter is stopped.

Return type

Optional[str]

await stop()

(async) Stop the PT executable.

First try to signal a graceful exit by closing PT’s STDIN (if enabled) and wait, then call terminate() and wait, then call kill().

Return type

None

await wait()

(async) Block until the PT process exit.

Return type

None

class ptadapter.ServerAdapter(pt_exec, state, forward_host, forward_port, *, exit_on_stdin_close=True)

Run a pluggable transport as server.

For each enabled transport, the PT will listen on a port, which can be either specified or left auto-assigned, and looked up using get_transport(). The PT will forward unobfuscated traffic directly to forward_host:forward_port.

This object can be used as an async context manager. On entering the context, the PT is started, and on exiting the PT is stopped. The adapter itself is returned as the “as” variable.

__init__(pt_exec, state, forward_host, forward_port, *, exit_on_stdin_close=True)

Create the adapter.

Parameters
  • pt_exec (Union[List[str], List[bytes]]) – The pluggable transport command line to execute. This has to be a list of str / bytes, since asyncio.create_subprocess_exec() does not accept an entire command line as a string. On non-Windows platforms shlex.split() can be used to split a command line string into a list, while on Windows it’s a bit more complicated.

  • state (Union[None, str, bytes, PathLike]) – The state directory. This is a directory where the PT is allowed to store state. Either specify a path (which is not required to exist, in which case the PT will create the directory), or specify None to use a temporary directory created using tempfile. For servers, using an actual persistent location is recommended.

  • forward_host (Union[str, IPv4Address, IPv6Address]) – IP address or host name to forward unobfuscated traffic to.

  • forward_port (int) – Port number to forward unobfuscated traffic to.

  • exit_on_stdin_close (bool) – Whether closing the PT’s STDIN indicates the PT should gracefully exit.

add_transport(transport, host, port, options=None)

Add a server transport.

This can only be called before PT starts. Unlike when running as client, PTs only support one tunnel per transport when running as server. Calling this with the same transport again will overwrite the previous entry.

Parameters
  • transport (str) – The transport name. PT will ignore names it does not recognize.

  • host (Union[None, str, IPv4Address, IPv6Address]) – The IP address to listen on. This must not be a host name. host and port must be either specified at the same time, or set to None at the same time.

  • port (Optional[int]) – The port number to listen on.

  • options (Optional[Dict[str, str]]) – Transport options.

Return type

None

get_transport(transport)

Look up initialized server transport methods.

Parameters

transport (str) – Name of the transport.

Return type

ServerTransport

Returns

A ServerTransport NamedTuple for the specified transport.

Raises
await start()

(async) Start the PT executable and wait until it’s ready.

“Ready” means that all transports have finished initializing.

Return type

None

state

The state directory.

If a temporary directory is used, this will be None before the adapter starts, and will be the actual path of the directory after the adapter has started. The temporary directory will be deleted once the adapter is stopped.

Return type

Optional[str]

await stop()

(async) Stop the PT executable.

First try to signal a graceful exit by closing PT’s STDIN (if enabled) and wait, then call terminate() and wait, then call kill().

Return type

None

await wait()

(async) Block until the PT process exit.

Return type

None

class ptadapter.ExtServerAdapter(pt_exec, state, client_connected_cb, *, preconnect_cb=None, auth_cookie_file=None, ext_host='localhost', ext_port=0, ext_family=<AddressFamily.AF_UNSPEC: 0>, exit_on_stdin_close=True)

Run a pluggable transport as server.

For each enabled transport, the PT will listen on a port, which can be either specified or left auto-assigned, and looked up using get_transport(). The PT will connect to the adapter using the ExtOrPort protocol, and a callback will be invoked.

This object can be used as an async context manager. On entering the context, the PT is started, and on exiting the PT is stopped. The adapter itself is returned as the “as” variable.

__init__(pt_exec, state, client_connected_cb, *, preconnect_cb=None, auth_cookie_file=None, ext_host='localhost', ext_port=0, ext_family=<AddressFamily.AF_UNSPEC: 0>, exit_on_stdin_close=True)

Create the adapter.

Parameters
  • pt_exec (Union[List[str], List[bytes]]) – The pluggable transport command line to execute. This has to be a list of str / bytes, since asyncio.create_subprocess_exec() does not accept an entire command line as a string. On non-Windows platforms shlex.split() can be used to split a command line string into a list, while on Windows it’s a bit more complicated.

  • state (Union[None, str, bytes, PathLike]) – The state directory. This is a directory where the PT is allowed to store state. Either specify a path (which is not required to exist, in which case the PT will create the directory), or specify None to use a temporary directory created using tempfile. For servers, using an actual persistent location is recommended.

  • client_connected_cb (Callable[[StreamReader, StreamWriter, ExtOrPortClientConnection], Awaitable[None]]) – Async callback function called to handle incoming client connections. It will be called with three arguments: (reader, writer, connection_info), where reader and writer are a StreamReader, StreamWriter pair, and connection_info is a ExtOrPortClientConnection containing information on the connecting client.

  • preconnect_cb (Optional[Callable[[ExtOrPortClientConnection], Awaitable[bool]]]) – Optional async callback function called before client_connect_cb, where an incoming connection can be rejected. It will be called with a single argument of ExtOrPortClientConnection containing information on the connecting client, and should return a boolean, where True means to allow the connection and False means to reject.

  • auth_cookie_file (Union[str, bytes, PathLike, None]) – Path to the ExtOrPort authentication cookie file. If specified, this should be a path + filename to a writable location that is not readable by other users. If unspecified, a temporary directory is created using tempfile, and the cookie file created inside.

  • ext_host (str) – IP address / host name to bind ExtOrPort to. The ExtOrPort is used internally between the PT and the adapter, so this should be a loopback address.

  • ext_port (int) – Port number to bind ExtOrPort to. 0 means a random ephemeral port.

  • ext_family (int) – The family flag passed while binding ExtOrPort. socket.AF_INET or socket.AF_INET6 can be passed to restrict ExtOrPort to IPv4 or IPv6 respectively.

  • exit_on_stdin_close (bool) – Whether closing the PT’s STDIN indicates the PT should gracefully exit.

add_transport(transport, host, port, options=None)

Add a server transport.

This can only be called before PT starts. Unlike when running as client, PTs only support one tunnel per transport when running as server. Calling this with the same transport again will overwrite the previous entry.

Parameters
  • transport (str) – The transport name. PT will ignore names it does not recognize.

  • host (Union[None, str, IPv4Address, IPv6Address]) – The IP address to listen on. This must not be a host name. host and port must be either specified at the same time, or set to None at the same time.

  • port (Optional[int]) – The port number to listen on.

  • options (Optional[Dict[str, str]]) – Transport options.

Return type

None

get_transport(transport)

Look up initialized server transport methods.

Parameters

transport (str) – Name of the transport.

Return type

ServerTransport

Returns

A ServerTransport NamedTuple for the specified transport.

Raises
await start()

(async) Start the PT executable and wait until it’s ready.

“Ready” means that all transports have finished initializing.

Return type

None

state

The state directory.

If a temporary directory is used, this will be None before the adapter starts, and will be the actual path of the directory after the adapter has started. The temporary directory will be deleted once the adapter is stopped.

Return type

Optional[str]

await stop()

(async) Stop the PT executable.

First try to signal a graceful exit by closing PT’s STDIN (if enabled) and wait, then call terminate() and wait, then call kill().

Return type

None

await wait()

(async) Block until the PT process exit.

Return type

None

Supporting Classes

class ptadapter.ClientTransport(scheme: str, host: str, port: int)

NamedTuple describing an initialized client transport method.

scheme

The proxy scheme, either “socks4” or “socks5”.

host

Proxy IP address.

port

Proxy port.

class ptadapter.ServerTransport(host: str, port: int, options: Optional[str])

NamedTuple describing an initialized server transport method.

host

Reverse proxy IP address.

port

Reverse proxy port.

options

Per-transport option field returned by PT.

parse_args()

Parse the “ARGS” option in the options field into a dict.

If the options field is not present, or it does not contain an “ARGS” option, return an empty dict.

Raises

ValueError – if the “ARGS” option is not well-formed.

Return type

Dict[str, str]

class ptadapter.ExtOrPortClientConnection(transport: Optional[str], host: Union[None, ipaddress.IPv4Address, ipaddress.IPv6Address], port: Optional[int])

NamedTuple describing an incoming client connection.

In practice, PTs should provide all the information represented here, but the ExtOrPort specs does not explicitly require PT to provide everything, so there still might be cases where some of the entries are None.

transport

Name of transport used by the client.

host

IP address of the client.

Note: this is not a string, but an instance of either ipaddress.IPv4Address or ipaddress.IPv6Address. Call str() on it if you need a string.

port

Port number of the client.

exceptions Submodule

Exceptions raised by this package.

Two Enums used in these exceptions are also imported in this module for convenience.

exception ptadapter.exceptions.PTConnectError

Bases: ConnectionError

Error while PT tries to connect to destination.

This is the base class of some other connection errors. To make catching connectivity-related exceptions easier, this inherits from the built-in ConnectionError.

exception ptadapter.exceptions.PTSOCKS5ConnectError

Bases: ptadapter.exceptions.PTConnectError

Error reported by client PT using SOCKS5 connecting to destination.

The args of this exception contains the reason of failure returned by the PT, as an instance of ptadapter.socks.SOCKS5Reply. This may or may not be useful; do not be surprised if PTs only ever return GENERAL_FAILURE.

exception ptadapter.exceptions.PTSOCKS4ConnectError

Bases: ptadapter.exceptions.PTConnectError

Error reported by client PT using SOCKS4 connecting to destination.

The args of this exception contains the reason of failure returned by the PT, as an instance of ptadapter.socks.SOCKS4Reply. This is likely to be even less useful than a SOCKS5 reply, since the specific errors are all related to identd, which we are not using.

class ptadapter.exceptions.SOCKS5Reply(value)

Bases: ptadapter.enums.BytesEnum

Command reply from SOCKS5 server to client.

SUCCESS = b'\x00'
GENERAL_FAILURE = b'\x01'
CONNECTION_NOT_ALLOWED_BY_RULESET = b'\x02'
NETWORK_UNREACHABLE = b'\x03'
HOST_UNREACHABLE = b'\x04'
CONNECTION_REFUSED = b'\x05'
TTL_EXPIRED = b'\x06'
COMMAND_NOT_SUPPORTED = b'\x07'
ADDRESS_TYPE_NOT_SUPPORTED = b'\x08'
class ptadapter.exceptions.SOCKS4Reply(value)

Bases: ptadapter.enums.BytesEnum

Command reply from SOCKS4 server to client.

GRANTED = b'Z'
REJECTED_OR_FAILED = b'['
NO_IDENTD = b'\\'
USER_ID_MISMATCH = b']'