Skip to content

Instantly share code, notes, and snippets.

@pragma31
Created November 17, 2021 07:56
Show Gist options
  • Save pragma31/fc4c2b472cb5234a4c4a10f8b499b7d2 to your computer and use it in GitHub Desktop.
Save pragma31/fc4c2b472cb5234a4c4a10f8b499b7d2 to your computer and use it in GitHub Desktop.
from stem.control import Controller, EventType
from stem import StreamStatus
import functools
# using stem 1.8.0
TORBROWSER_CTRL = 9151
def stream_event(controller, event):
if event.status == StreamStatus.SUCCEEDED and event.circ_id:
circ = controller.get_circuit(event.circ_id)
exit_fingerprint = circ.path[-1][0]
exit_relay = controller.get_network_status(exit_fingerprint)
print("Exit relay for our connection to %s" % (event.target))
print(" address: %s:%i" % (exit_relay.address, exit_relay.or_port))
print(" fingerprint: %s" % exit_relay.fingerprint)
print(" nickname: %s" % exit_relay.nickname)
print(" locale: %s" % controller.get_info("ip-to-country/%s" % exit_relay.address, 'unknown'))
print('stream purpose', event.purpose)
print('circuit purpose', circ.purpose)
print('circuit flags', circ.build_flags)
if len(circ.path) == 1:
print('single hop!')
print()
def main():
'''
assumed: torbrowser is running
'''
with Controller.from_port(port=TORBROWSER_CTRL) as controller:
controller.authenticate()
print('connected - Tor version :', controller.get_version(), '\n')
stream_listener = functools.partial(stream_event, controller)
controller.add_event_listener(stream_listener, EventType.STREAM)
while True:
pass
if __name__ == '__main__':
main()
@pragma31
Copy link
Author

--- example outputs ---

hitting the page https://check.torproject.org :

Exit relay for our connection to 116.202.120.181:443
  address: 192.42.116.18:443
  fingerprint: AB4761E23AF511E8306E95E78F7E82F77B2E487F
  nickname: hviv118
  locale: nl
stream purpose None
circuit purpose GENERAL
circuit flags ('NEED_CAPACITY',)

as expected, the page shows "Your IP address appears to be: 192.42.116.18"

One-hop circuits sometimes show up, they look like this :

Exit relay for our connection to 31.164.191.83.$A170153BF63A9D2E2FBCA3FCD867286AC3B80CEA.exit:9001
  address: 31.164.191.83:9001
  fingerprint: A170153BF63A9D2E2FBCA3FCD867286AC3B80CEA
  nickname: yournicerelay
  locale: ch
stream purpose None
circuit purpose GENERAL
circuit flags ('ONEHOP_TUNNEL', 'IS_INTERNAL', 'NEED_CAPACITY')
single hop!

Occurrences are rare.
A way to make them appear more often is to open several tabs in torbrowser so as to force the tor daemon to build circuits.

@pragma31
Copy link
Author

filtering out with IS_INTERNAL :

from stem.control import Controller, EventType
from stem import StreamStatus
import functools

# using stem 1.8.0

TORBROWSER_CTRL = 9151

def stream_event(controller, event):
    if event.status == StreamStatus.SUCCEEDED and event.circ_id:
        circ = controller.get_circuit(event.circ_id)

        if 'IS_INTERNAL' not in circ.build_flags:               ###### 
            exit_fingerprint = circ.path[-1][0]
            exit_relay = controller.get_network_status(exit_fingerprint)

            print("Exit relay for our connection to %s" % (event.target))
            print("  address: %s:%i" % (exit_relay.address, exit_relay.or_port))
            print("  fingerprint: %s" % exit_relay.fingerprint)
            print("  nickname: %s" % exit_relay.nickname)
            print("  locale: %s" % controller.get_info("ip-to-country/%s" % exit_relay.address, 'unknown'))
            
            print('circuit purpose is', circ.purpose)           ######
            print('circuit has', len(circ.path), 'hops\n')      ######

def main():
    '''
    assumed: torbrowser is running
    '''
    with Controller.from_port(port=TORBROWSER_CTRL) as controller:
        controller.authenticate()
        
        stream_listener = functools.partial(stream_event, controller)
        controller.add_event_listener(stream_listener, EventType.STREAM)

        print('listening to stream events - hit enter to quit\n')
        input()

if __name__ == '__main__':
    main()

--- some numbers ---

a 25 minutes browsing session in torbrowser, using up to 5 tabs, asking for a new identity twice :

got 955 events, every one of them showed :

circuit purpose is GENERAL
circuit has 3 hops

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment