Welcome, guest | Sign In | My Account | Store | Cart

patches socket to tunnel through a tor server either by socks4a or socks5 (tor-resolve required for socks5), being careful not to leak dns requests

pyconstruct required, http://construct.wikispaces.com/

Python, 171 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
from construct import *
import socket
import sys
import subprocess
import logging

# monkeys were here
# currently only works with AF_INET and SOCK_STREAM due
# to my shitty understanding of patching getaddrinfo
# but at least it doesn't leak DNS resolves

TORIP="127.0.0.1"
TORPORT=9050
PROTO="socks4a" # or socks5, dependent on tor-resolve
USERID="anonymous" # for 4a only

log = logging.getLogger("torSocket")

class IpAddressAdapter(Adapter):
	def _encode(self, obj, context):
		return "".join(chr(int(b)) for b in obj.split("."))
	def _decode(self, obj, context):
		return ".".join(str(ord(b)) for b in obj)

def IpAddress(name):
	return IpAddressAdapter(Bytes(name, 4))

class SocksException(Exception):
	pass

class TorSocket():
	def __init__(self, *args, **kwargs):
		self._sock = oldSocket(socket.AF_INET, socket.SOCK_STREAM)
		self.connect = getattr(self, "%sconnect" % PROTO)
		self._sock.connect((TORIP, TORPORT))

	def socks5connect(self, address):
		log.debug("using socks5")
		connect = Struct("connect",
				Byte("ver"),
				Byte("nmethods"),
				Byte("methods"),
		)

		connectResponse = Struct("response",
				Byte("ver"),
				Byte("method"),
		)

		p = Container(
				ver=5,
				nmethods=1,
				methods=0
		)

		self._sock.send(connect.build(p))
		data = self._sock.recv(1024)

		response = connectResponse.parse(data)
		if response.method == 255:
			raise SocksException

		request = Struct("request",
				Byte("ver"),
				Byte("cmd"),
				Byte("rsv"),
				Byte("atyp"),
				IpAddress("dstaddr"),
				UBInt16("dstport")
		)

		requestResponse = Struct("requestResponse",
				Byte("ver"),
				Byte("rep"),
				Byte("rsv"),
				Byte("atyp"),
				UBInt16("bndport")
		)

		p = Container(
				ver=5,
				cmd=1,
				rsv=0,
				atyp=1,
				dstaddr=address[0],
				dstport=address[1]
		)

		self._sock.send(request.build(p))

		data = self._sock.recv(1024)
		response = requestResponse.parse(data)

		if response.rep != 0:
			raise SocksException

	def socks4aconnect(self, address):
		log.debug("using socks4a")

		connect = Struct("connect",
				Byte("ver"),
				Byte("cd"),
				UBInt16("dstport"),
				IpAddress("dstip"),
				CString("userid"),
				CString("domain")
		)

		connectResponse = Struct("response",
				Byte("ver"),
				Byte("cd"),
				UBInt16("dstport"),
				IpAddress("dstip")
		)

		p = Container(
				ver=4,
				cd=1,
				dstport=address[1],
				dstip="0.0.0.1",
				userid=USERID,
				domain=address[0]
		)

		self._sock.send(connect.build(p))
		data = self._sock.recv(1024)

		response = connectResponse.parse(data)
		if response.cd != 90:
			raise SocksException

	def connect(self, address):
		raise NotImplementedError

	def makefile(self, *args):
		return self._sock.makefile(*args)

	def sendall(self, *args):
		self._sock.sendall(*args)

	def send(self, *args):
		self._sock.send(*args)

	def recv(self, *args):
		return self._sock.recv(*args)

	def close(self):
		self._sock.close()

def torResolve(name):
	log.debug("resolving %s with tor-resolve" % name)
	p = subprocess.Popen(['tor-resolve', name], stdout=subprocess.PIPE)
	ip = p.stdout.read().strip()
	return ip

def getaddrinfo(*args):
	if PROTO == "socks4a":
		return [(socket.AF_INET, socket.SOCK_STREAM, 6, '', (args[0], args[1]))]
	elif PROTO == "socks5":
		ip = torResolve(args[0])
		return [(socket.AF_INET, socket.SOCK_STREAM, 6, '', (ip, args[1]))]
	else:
		raise SocksException

oldSocket = socket.socket
oldAddrInfo = socket.getaddrinfo

socket.socket = TorSocket
socket.getaddrinfo = getaddrinfo
socket.gethostbyname = torResolve
sys.modules['socket'] = socket

for anonymity. import the module before any other modules that are dependent on socket and use as normal