Skip to content

Commit

Permalink
Python Multitor 1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
realgam3 committed Sep 28, 2013
0 parents commit 113ce8c
Show file tree
Hide file tree
Showing 8 changed files with 1,019 additions and 0 deletions.
39 changes: 39 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#OS junk Files
[Tt]humbs.db
*.DS_Store
desktop.ini

# Python Files
*.py[cod]
torData
TorCtl

# C Extensions
*.so

# Packages
*.egg
*.egg-info
dist
build
eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
lib
lib64
__pycache__

# Installer Logs
pip-log.txt

# Translations
*.mo

# Developer
.project
.pydevproject
.idea
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

214 changes: 214 additions & 0 deletions MultiTor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
#!/usr/bin/env python
########################################################
# Python MultiTor
# Author: RealGame (Tomer Zait)
# Site: http://RealGame.co.il
########################################################

#Monkey Patch All - Change Everything To Gevent
from gevent.monkey import patch_all
patch_all()

from TorConfig import *
from gevent import Timeout
from re import findall
from os import makedirs
from time import time as now
from requesocks import request
from stem.process import launch_tor_with_config
from stem.control import Controller
from stem import Signal
from zipfile import ZipFile
from psutil import process_iter
from subprocess import check_output


#TorConnection - Contains Controller And Subprocess
class TorConnection(object):
def __init__(self, socksPort, ctrlPort):
#Variables
self.__isFree = False
self.__socksPort = socksPort
self.__ctrlPort = ctrlPort
self.__torConfig = None
self.__torProcess = None
self.__torCtrl = None
self.__proxies = None
self.__lastTimeIpChanged = 0
#Call Creator
self.__start()

def __torPrint(self, line):
if "Bootstrapped" in line:
print "%s\t->\t%s" % (self.getId(), line)

def __open(self):
#Open Tor Process
opened = False
while not opened:
with Timeout(PROCESS_TIMEOUT, False):
self.__torProcess = launch_tor_with_config(config=self.__torConfig,
tor_cmd=TOR_CMD,
init_msg_handler=self.__torPrint)
self.__torProcess.stdout.close()
opened = True
if not opened:
self.__torProcess.terminate()

#Open Tor Control
self.__torCtrl = Controller.from_port(address=HOST, port=self.__ctrlPort)
self.__torCtrl.authenticate(PASS_PHRASE)

def __start(self):
#Data Paths
dataPath = path.join(TOR_ROOT_DATA_PATH, "data_%d" % self.__socksPort)
if not path.exists(dataPath):
makedirs(dataPath)

#Create Configuration Dictionary
self.__torConfig = {"ControlPort": str(self.__ctrlPort),
"HashedControlPassword": passPhraseHash,
"ExcludeNodes": "{CN},{HK},{MO}",
"SOCKSPort": str(self.__socksPort),
"DataDirectory": dataPath}

#Open Tor Process
self.__open()

#Create Proxy String
self.__proxies = {"http": "socks5://%s:%d" % (HOST, self.__socksPort),
"https": "socks5://%s:%d" % (HOST, self.__socksPort)}

#The Tor Connection Is Now Ready To Use
self.__isFree = True

#Up And Running Message
print "%s\t->\tUp & Running!" % self.getId()

def changeState(self):
self.__isFree = not self.__isFree

def isFree(self):
return self.__isFree

def kill(self):
with Timeout(TOR_TIMEOUT, False):
self.__torCtrl.close()
self.__torProcess.terminate()

def reset(self):
#Kill All
self.kill()
#Start All
self.__open()

#Inform
print "%s\t->\tUp & Running After Reset!" % self.getId()

def changeIp(self, i, msg):
#Tor Need 10 Seconds(TOR_TIMEOUT) Difference Between Id Changes
if (now() - self.__lastTimeIpChanged) >= TOR_TIMEOUT:
print "%s\t->\t%d) ChangeIP (%s)" % (self.getId(), i, msg)
#Check If TimedOut
timedOut = True
with Timeout(TOR_TIMEOUT, False):
self.__torCtrl.signal(Signal.NEWNYM)
timedOut = False
if timedOut:
self.reset()
self.__lastTimeIpChanged = now()
return True
return False

def getId(self):
return "Tor_%d" % self.__socksPort

def getProxies(self):
return self.__proxies


#TorConnectionCollector - Sends Free TorConnection To The Thread Function
class TorConnectionCollector(object):
def __init__(self):
self.__torCons = []
for i in xrange(MAX_NUM_OF_THREADS):
self.__torCons.append(TorConnection(SOCKS_START_PORT + i, CONTROL_START_PORT + i))

def getFreeConnection(self):
while True:
for conn in self.__torCons:
if conn.isFree():
conn.changeState()
return conn

def killConnections(self):
for conn in self.__torCons:
conn.kill()


def pool_function(torRange):
#Important Variables
torConn = torConnColl.getFreeConnection()
proxies = torConn.getProxies()
torId = torConn.getId()
size = len(torRange)

print "%s\t->\tStart (%d - %d)" % (torId, torRange[0], torRange[-1])
i = 0
#I Use While Because For Cant Move Backwards
while i < size:
try:
#Send Request
req = request(method="GET",
url="http://checkip.dyndns.org/",
timeout=REQUEST_TIMEOUT,
headers=HEADERS,
proxies=proxies)
res = req.text
if res == "":
continue
except Exception as ex:
#Change IP
ipChanged = False
while not ipChanged:
ipChanged = torConn.changeIp(torRange[i], ex)
continue
#Print Result
print "%s\t->\t%d) %s" % (torId, torRange[i], "".join(findall(r"[0-9]+(?:\.[0-9]+){3}", res)))
i += 1

#Change IP
ipChanged = False
while not ipChanged:
ipChanged = torConn.changeIp(i, "Finished.")

#Free The TorConnection
torConn.changeState()


def main():
#Kill All Tor Processes
for process in process_iter():
if path.basename(TOR_CMD) == process.name:
process.terminate()
#Extract Tor Windows Files If Needed
if isWindows() and not path.exists(TOR_ROOT_DATA_PATH):
makedirs(TOR_ROOT_DATA_PATH)
ZipFile(path.join(getcwd(), "torWin.data")).extractall(TOR_ROOT_DATA_PATH)
#Create TorConnectionCollector And Tor PassPhrase Hash
global torConnColl, passPhraseHash
passPhraseHash = check_output([TOR_CMD, "--hash-password", PASS_PHRASE]).strip().split("\n")[-1]
torConnColl = TorConnectionCollector()
#Create The Threads Pool
for i in xrange(START, END, INC):
POOL.spawn(pool_function, range(i, i + INC))
#Block Until Pool Done
POOL.join()
#Kill All TorConnections
print "Kill Tor Connections"
torConnColl.killConnections()
#Finish
print "Finished Scanning"

if __name__ == "__main__":
main()
33 changes: 33 additions & 0 deletions README
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
Requirements:
Linux Installation:
1) sudo apt-get install python-dev python-pip libevent-dev openssl tor
2) sudo pip install -r requirements.txt
3) sudo update-rc.d -f tor disable

MacOSx Installation:
1) Install Xcode Command Line Tools (AppStore)
2) ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go)"
3) brew install openssl tor
4) sudo easy_install pip
5) sudo pip install -r requirements.txt

Windows 32bit Installation:
1) Install setuptools (http://www.lfd.uci.edu/~gohlke/pythonlibs/3n2nz84p/setuptools-1.1.5.win32-py2.7.exe) - No Need In ActivePython
2) Install greenlet (http://www.lfd.uci.edu/~gohlke/pythonlibs/3n2nz84p/greenlet-0.4.1.win32-py2.7.exe)
3) Install gevent (http://www.lfd.uci.edu/~gohlke/pythonlibs/3n2nz84p/gevent-0.13.8.win32-py2.7.exe)
4) Install psutil (http://www.lfd.uci.edu/~gohlke/pythonlibs/3n2nz84p/psutil-1.0.1.win32-py2.7.exe)
5) Open Command Prompt(cmd) as Administrator -> Goto python folder -> Scripts (cd c:\Python27\Scripts)
6) pip install -r (Full Path To requirements.txt), OR pip install requesocks && pip install stem

Windows 64bit Installation:
1) Install setuptools (http://www.lfd.uci.edu/~gohlke/pythonlibs/3n2nz84p/setuptools-1.1.5.win-amd64-py2.7.exe) - No Need In ActivePython
2) Install greenlet (http://www.lfd.uci.edu/~gohlke/pythonlibs/3n2nz84p/greenlet-0.4.1.win-amd64-py2.7.exe)
3) Install gevent (http://www.lfd.uci.edu/~gohlke/pythonlibs/3n2nz84p/gevent-0.13.8.win-amd64-py2.7.exe)
4) Install psutil (http://www.lfd.uci.edu/~gohlke/pythonlibs/3n2nz84p/psutil-1.0.1.win-amd64-py2.7.exe)
5) Open Command Prompt(cmd) as Administrator -> Goto python folder -> Scripts (cd c:\Python27\Scripts)
6) pip install -r (Full Path To requirements.txt), OR pip install requesocks && pip install stem

Thanks:
* Omri Bahumi
* Shimon Tolts
* Roman Labunsky
4 changes: 4 additions & 0 deletions TODO
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
TODO:
1) TorConnections as Threads - For Faster Initialize.
2) Create Semaphores / Locks - For TorConnections Threads.
3) Make MAX_REQUEST_THREADS - For Faster Fequests.
50 changes: 50 additions & 0 deletions TorConfig.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
########################################################
__author__ = 'RealGame (Tomer Zait)'
__license__ = 'GPL v3'
__version__ = '1.0.0'
__email__ = '[email protected]'
########################################################

from gevent.pool import Pool
from os import getcwd, path
from sys import platform
from requesocks.defaults import defaults


def isWindows():
return platform == 'win32'


def isMacosx():
return platform == 'darwin'


#Define Configuration Variables:
TOR_ROOT_DATA_PATH = path.join(getcwd(), 'torData')

# Create Tor Command For Linux / Windows / MacOSX
TOR_CMD = 'tor'
if isWindows():
TOR_CMD = path.join(TOR_ROOT_DATA_PATH, TOR_CMD + '.exe')
elif isMacosx():
TOR_CMD = path.join('/usr/local/bin', TOR_CMD)

MAX_NUM_OF_THREADS = 4
TOR_TIMEOUT = 10
PROCESS_TIMEOUT = 120
REQUEST_TIMEOUT = 15
MAX_RETRIES = 2
CONTROL_START_PORT = 9050
SOCKS_START_PORT = 5050
PASS_PHRASE = 'lol'
HOST = '127.0.0.1'
POOL = Pool(size=MAX_NUM_OF_THREADS)
HEADERS = {'User-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Firefox/24.0'}
START = 1
END = 400
INC = 50
# Change Requesocks Default Configurations
defaults['pool_connections'] = MAX_NUM_OF_THREADS
defaults['pool_maxsize'] = MAX_NUM_OF_THREADS
defaults['max_retries'] = MAX_RETRIES
defaults['max_redirects'] = 2
5 changes: 5 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
gevent >= 0.13.8
greenlet >= 0.4.1
requesocks >= 0.10.8
stem >= 1.0.1
psutil >= 1.0.1
Binary file added torWin.data
Binary file not shown.

0 comments on commit 113ce8c

Please sign in to comment.