pyptlib documentation

API overview

«  pyptlib README   ::   Contents   ::   Pluggable transports glossary  »

API overview

Be sure to read API.rst and glossary.rst before reading this file.

General Overview

Applications begin by initializing pyptlib.

Then pyptlib informs the application about which transports it should spawn, in which ports they should listen for connections, etc.

Then the application launches the appropriate transports as instructed, and for each transport it reports to pyptlib whether it was launched successfully or not. Finally, the application announces to pyptlib that it finished launching transports.

From that point and on the application should forget about pyptlib and start accepting connections.

Detailed API Overview

0) Find if it’s a client or a server

An application using pyptlib should start by calling pyptlib.config.checkClientMode() to learn whether Tor wants it to run as a client or as a server.

You should then create a pyptlib.client.ClientTransportPlugin or pyptlib.server.ServerTransportPlugin as appropriate. This object is your main entry point to the pyptlib API, so you should keep it somewhere for later access.

1) Get transport information from Tor

The next step is to run init to parse the rest of the configuration and communicate the results to Tor. You should pass a list of names of the transports your application supports.

The application should be prepared for pyptlib.config.EnvError, which signifies that the environment was not prepared by Tor.

Consider an example of the fictional application rot0r which implements the pluggable transports rot13 and rot26. If rot0r, in step 1, learned that Tor expects it to act as a client, it should now do:

from pyptlib.client import ClientTransportPlugin
from pyptlib.config import EnvError

client = ClientTransportPlugin()
try:
    client.init(supported_transports=["rot13", "rot26"])
except EnvError, err:
    print "pyptlib could not bootstrap ('%s')." % str(err)

Afterwards, the API’s config attribute provides methods to find out how Tor wants your application to be configured. For example, if you store state, it should go in client.config.getStateLocation(). For a complete list, see the documentation for that module.

2) Launch transports

Client case (skip if you are a server)

Your application should then use client.getTransports() to learn which transports it should launch.

Proceeding with the previous example:

if 'rot13' in client.getTransports():
    launch_rot13_client()
if 'rot26' in client.getTransports():
    launch_rot26_client()

For a full list of the methods available, see the module docs for client and client.config.

Note

Since the application runs as a client, it should launch a SOCKS server in the upstream side of the proxy.

Server case (skip if you are a client):

Your application should then use server.getBindAddresses() to learn which transports it should launch.

Since the application runs as a server, it will push data to Tor’s ORPort, which you can get using server.config.getORPort().

Proceeding with the previous example:

transports = server.getBindAddresses()
if 'rot13' in transports:
    launch_rot13_server(transports['rot13'], server.config.getORPort())
if 'rot26' in transports:
    launch_rot26_server(transports['rot26'], server.config.getORPort())

For a full list of the methods available, see the module docs for server and server.config.

3) Report results back to Tor.

For every transport that the application launches, it reports to pyptlib whether it was launched successfully or not. This way, Tor is informed on whether a transport is expected to work or not.

Client case (skip if you are a server):

Every time a transport is successfully launched, the application calls client.reportMethodSuccess with the name of the transport that was launched, the address where it is listening for connections, and the SOCKS version that the upstream SOCKS server supports.

For example, if rot13 was launched successfully, waits for connections in ‘127.0.0.1:42042’ and supports SOCKSv4, the appropriate call would be:

client.reportMethodSuccess('rot13', 'socks5', ('127.0.0.1', 42042))

Every time a transport failed to launch, the application calls client.reportMethodError with the name of the transport and a message.

For example, if rot26 failed to launch, the appropriate call would be:

client.reportMethodError('rot26', 'Could not bind to 127.0.0.1:666 (Operation not permitted)')

Server case (skip if you are a client):

Everytime a transport is successfully launched, the application calls server.reportMethodSuccess with the name of the transport that was launched, and the address where it is listening for connections.

For example, if rot13 was launched successfully and waits for connections in ‘127.0.0.1:42042’, the appropriate call would be:

server.reportMethodSuccess('rot13', ('127.0.0.1', 42042))

Everytime a transport failed to launch, the application should call server.reportMethodError with the name of the transport and a message.

For example, if rot26 failed to launch, the appropriate call would be:

server.reportMethodError('rot26', 'Could not bind to 127.0.0.1:666 (Operation not permitted)')

4) Stop using pyptlib and start accepting connections

When the application finishes launching connections, it should call reportMethodsEnd(), to announce to pyptlib that all transports were launched. This way, Tor knows that it can start pushing traffic to the application.

After this point, the API object (in this current version of pyptlib) has no other use.

«  pyptlib README   ::   Contents   ::   Pluggable transports glossary  »