pythoncurlip-addresstorstem

Stem controller's new identity does not change tor IP


the following problem looks a lot like many related questions already on SO (I've read through them but my problem is slightly different and remains).

I've written the following code in Python 3.6.1 using the stem library (tested both on macOS Sierra and Ubuntu). All it does is creating a new tor process (configured to use an italian ip), open a controller connection to it and check the IP after trying to get a new tor identity and waiting 30 seconds.

My code is nothing more than a slightly modified version of the stem library documentation and, as such, expected to be working.

All the code seems to behave fine and I don't get any errors/exceptions, but each time I get the same IP (occasionally a second IP, but switching beetween the two)

Here's the code (main.py):

import stem.process
import pycurl
import io
import time

from stem.util import term
from stem.control import Controller
from stem import Signal


TOR_HOST = '127.0.0.1'
TOR_SOCKS_PORT = 9050
TOR_CONTROL_PORT = 9051
TOR_LANG = 'it'

SITE_URL = 'https://www.atagar.com/echo.php'


def print_bootstrap_lines(line):
    if "Bootstrapped " in line:
        print(term.format(line, term.Color.BLUE))


def query(url):
    output = io.BytesIO()

    conn = pycurl.Curl()
    conn.setopt(pycurl.URL, url)
    conn.setopt(pycurl.PROXY, TOR_HOST)
    conn.setopt(pycurl.PROXYPORT, TOR_SOCKS_PORT)
    conn.setopt(pycurl.PROXYTYPE, pycurl.PROXYTYPE_SOCKS5_HOSTNAME)
    conn.setopt(pycurl.WRITEFUNCTION, output.write)

    try:
        conn.perform()
        return output.getvalue().decode('ascii')
    except pycurl.error as exc:
        return "Unable to reach %s (%s)" % (url, exc)


tor = stem.process.launch_tor_with_config(
    config={
        'SocksPort': str(TOR_SOCKS_PORT),
        'ControlPort': str(TOR_CONTROL_PORT),
        'ExitNodes': '{' + TOR_LANG + '}'
    },
    init_msg_handler=print_bootstrap_lines
)

ctrl = Controller.from_port(TOR_HOST, port=TOR_CONTROL_PORT)
ctrl.authenticate()

print(query(SITE_URL))
for _ in range(10):
    ctrl.signal(Signal.NEWNYM)
    time.sleep(30)
    print(query(SITE_URL))

ctrl.close()
tor.kill()

And here's the program output:

/Library/Frameworks/Python.framework/Versions/3.6/bin/python3.6 /Users/tommaso/PycharmProjects/test/main.py
May 16 16:33:15.000 [notice] Bootstrapped 0%: Starting
May 16 16:33:16.000 [notice] Bootstrapped 80%: Connecting to the Tor network
May 16 16:33:17.000 [notice] Bootstrapped 85%: Finishing handshake with first hop
May 16 16:33:17.000 [notice] Bootstrapped 90%: Establishing a Tor circuit
May 16 16:33:17.000 [notice] Bootstrapped 100%: Done
IP Address: 162.220.246.230 (162.220.246.230:45631)
Locale: 

IP Address: 162.220.246.230 (162.220.246.230:33604)
Locale: 

IP Address: 5.249.145.164 (torexit-readme.balist.es:42397)
Locale: 

IP Address: 162.220.246.230 (162.220.246.230:53925)
Locale: 

IP Address: 162.220.246.230 (162.220.246.230:42953)
Locale: 

IP Address: 162.220.246.230 (162.220.246.230:60250)
Locale: 

IP Address: 162.220.246.230 (162.220.246.230:55945)
Locale: 

IP Address: 162.220.246.230 (162.220.246.230:44077)
Locale: 

IP Address: 5.249.145.164 (torexit-readme.balist.es:46375)
Locale: 

IP Address: 162.220.246.230 (162.220.246.230:33205)
Locale: 

IP Address: 5.249.145.164 (torexit-readme.balist.es:47870)
Locale: 


Process finished with exit code 0

Do you know why I'm getting the same 1-2 IP/IPs every time, and how to fix it? I'm not sure what's going wrong here. Maybe there are only two exit nodes from Italy (with italian IP)?

Thanks


Solution

  • Your code looks good and it appears to be working based on your comments and the output I see.

    Of the 64-79 nodes in Italy you see on that page, only a few are actually exits (you need to look at the icon flags to determine this). According to https://atlas.torproject.org/#search/country:it%20flag:Exit there are far fewer exits in Italy that you thought. It looks like there are about 6 Exits online at the time of writing.

    At least one has a really low capacity (75 KiB/s) and probably can't serve your requests, and one other I see does not allow exit traffic on port 80 or 443 (so it's not suitable and won't be selected for your use).

    So in conclusion, the fact that you're only getting 2 IP's sounds about right. It's a network capacity issue (being that there aren't a desirable amount of exits in the country you want) and not a code issue.