An attempt at adding UDP support to aiosocks. Untested due to lack of server support.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

369 lines
14 KiB

  1. import aiosocks
  2. import asyncio
  3. import aiohttp
  4. import unittest
  5. from aiosocks.connector import SocksConnector
  6. try:
  7. from asyncio import ensure_future
  8. except ImportError:
  9. ensure_future = asyncio.async
  10. from .helpers import fake_socks_srv, fake_socks4_srv, http_srv
  11. class TestCreateSocks4Connection(unittest.TestCase):
  12. def setUp(self):
  13. self.loop = asyncio.new_event_loop()
  14. asyncio.set_event_loop(None)
  15. def tearDown(self):
  16. self.loop.close()
  17. def test_connect_success(self):
  18. with fake_socks_srv(self.loop,
  19. b'\x00\x5a\x04W\x01\x01\x01\x01test') as port:
  20. addr = aiosocks.Socks4Addr('127.0.0.1', port)
  21. auth = aiosocks.Socks4Auth('usr')
  22. dst = ('python.org', 80)
  23. coro = aiosocks.create_connection(
  24. None, addr, auth, dst, loop=self.loop)
  25. transport, protocol = self.loop.run_until_complete(coro)
  26. self.assertEqual(protocol.proxy_sockname, ('1.1.1.1', 1111))
  27. data = self.loop.run_until_complete(
  28. protocol._stream_reader.read(4))
  29. self.assertEqual(data, b'test')
  30. transport.close()
  31. def test_invalid_data(self):
  32. with fake_socks_srv(self.loop,
  33. b'\x01\x5a\x04W\x01\x01\x01\x01') as port:
  34. addr = aiosocks.Socks4Addr('127.0.0.1', port)
  35. auth = aiosocks.Socks4Auth('usr')
  36. dst = ('python.org', 80)
  37. with self.assertRaises(aiosocks.SocksError) as ct:
  38. coro = aiosocks.create_connection(
  39. None, addr, auth, dst, loop=self.loop)
  40. self.loop.run_until_complete(coro)
  41. self.assertIn('invalid data', str(ct.exception))
  42. def test_socks_srv_error(self):
  43. with fake_socks_srv(self.loop,
  44. b'\x00\x5b\x04W\x01\x01\x01\x01') as port:
  45. addr = aiosocks.Socks4Addr('127.0.0.1', port)
  46. auth = aiosocks.Socks4Auth('usr')
  47. dst = ('python.org', 80)
  48. with self.assertRaises(aiosocks.SocksError) as ct:
  49. coro = aiosocks.create_connection(
  50. None, addr, auth, dst, loop=self.loop)
  51. self.loop.run_until_complete(coro)
  52. self.assertIn('0x5b', str(ct.exception))
  53. class TestCreateSocks5Connect(unittest.TestCase):
  54. def setUp(self):
  55. self.loop = asyncio.new_event_loop()
  56. asyncio.set_event_loop(None)
  57. def tearDown(self):
  58. self.loop.close()
  59. def test_connect_success_anonymous(self):
  60. with fake_socks_srv(
  61. self.loop,
  62. b'\x05\x00\x05\x00\x00\x01\x01\x01\x01\x01\x04Wtest') as port:
  63. addr = aiosocks.Socks5Addr('127.0.0.1', port)
  64. auth = aiosocks.Socks5Auth('usr', 'pwd')
  65. dst = ('python.org', 80)
  66. coro = aiosocks.create_connection(
  67. None, addr, auth, dst, loop=self.loop)
  68. transport, protocol = self.loop.run_until_complete(coro)
  69. self.assertEqual(protocol.proxy_sockname, ('1.1.1.1', 1111))
  70. data = self.loop.run_until_complete(
  71. protocol._stream_reader.read(4))
  72. self.assertEqual(data, b'test')
  73. transport.close()
  74. def test_connect_success_usr_pwd(self):
  75. with fake_socks_srv(
  76. self.loop,
  77. b'\x05\x02\x01\x00\x05\x00\x00\x01\x01\x01\x01\x01\x04Wtest'
  78. ) as port:
  79. addr = aiosocks.Socks5Addr('127.0.0.1', port)
  80. auth = aiosocks.Socks5Auth('usr', 'pwd')
  81. dst = ('python.org', 80)
  82. coro = aiosocks.create_connection(
  83. None, addr, auth, dst, loop=self.loop)
  84. transport, protocol = self.loop.run_until_complete(coro)
  85. self.assertEqual(protocol.proxy_sockname, ('1.1.1.1', 1111))
  86. data = self.loop.run_until_complete(
  87. protocol._stream_reader.read(4))
  88. self.assertEqual(data, b'test')
  89. transport.close()
  90. def test_auth_ver_err(self):
  91. with fake_socks_srv(self.loop, b'\x04\x02') as port:
  92. addr = aiosocks.Socks5Addr('127.0.0.1', port)
  93. auth = aiosocks.Socks5Auth('usr', 'pwd')
  94. dst = ('python.org', 80)
  95. with self.assertRaises(aiosocks.SocksError) as ct:
  96. coro = aiosocks.create_connection(
  97. None, addr, auth, dst, loop=self.loop)
  98. self.loop.run_until_complete(coro)
  99. self.assertIn('invalid version', str(ct.exception))
  100. def test_auth_method_rejected(self):
  101. with fake_socks_srv(self.loop, b'\x05\xFF') as port:
  102. addr = aiosocks.Socks5Addr('127.0.0.1', port)
  103. auth = aiosocks.Socks5Auth('usr', 'pwd')
  104. dst = ('python.org', 80)
  105. with self.assertRaises(aiosocks.SocksError) as ct:
  106. coro = aiosocks.create_connection(
  107. None, addr, auth, dst, loop=self.loop)
  108. self.loop.run_until_complete(coro)
  109. self.assertIn('authentication methods were rejected',
  110. str(ct.exception))
  111. def test_auth_status_invalid(self):
  112. with fake_socks_srv(self.loop, b'\x05\xF0') as port:
  113. addr = aiosocks.Socks5Addr('127.0.0.1', port)
  114. auth = aiosocks.Socks5Auth('usr', 'pwd')
  115. dst = ('python.org', 80)
  116. with self.assertRaises(aiosocks.SocksError) as ct:
  117. coro = aiosocks.create_connection(
  118. None, addr, auth, dst, loop=self.loop)
  119. self.loop.run_until_complete(coro)
  120. self.assertIn('invalid data', str(ct.exception))
  121. def test_auth_status_invalid2(self):
  122. with fake_socks_srv(self.loop, b'\x05\x02\x02\x00') as port:
  123. addr = aiosocks.Socks5Addr('127.0.0.1', port)
  124. auth = aiosocks.Socks5Auth('usr', 'pwd')
  125. dst = ('python.org', 80)
  126. with self.assertRaises(aiosocks.SocksError) as ct:
  127. coro = aiosocks.create_connection(
  128. None, addr, auth, dst, loop=self.loop)
  129. self.loop.run_until_complete(coro)
  130. self.assertIn('invalid data', str(ct.exception))
  131. def test_auth_failed(self):
  132. with fake_socks_srv(self.loop, b'\x05\x02\x01\x01') as port:
  133. addr = aiosocks.Socks5Addr('127.0.0.1', port)
  134. auth = aiosocks.Socks5Auth('usr', 'pwd')
  135. dst = ('python.org', 80)
  136. with self.assertRaises(aiosocks.SocksError) as ct:
  137. coro = aiosocks.create_connection(
  138. None, addr, auth, dst, loop=self.loop)
  139. self.loop.run_until_complete(coro)
  140. self.assertIn('authentication failed', str(ct.exception))
  141. def test_cmd_ver_err(self):
  142. with fake_socks_srv(self.loop,
  143. b'\x05\x02\x01\x00\x04\x00\x00') as port:
  144. addr = aiosocks.Socks5Addr('127.0.0.1', port)
  145. auth = aiosocks.Socks5Auth('usr', 'pwd')
  146. dst = ('python.org', 80)
  147. with self.assertRaises(aiosocks.SocksError) as ct:
  148. coro = aiosocks.create_connection(
  149. None, addr, auth, dst, loop=self.loop)
  150. self.loop.run_until_complete(coro)
  151. self.assertIn('invalid version', str(ct.exception))
  152. def test_cmd_not_granted(self):
  153. with fake_socks_srv(self.loop,
  154. b'\x05\x02\x01\x00\x05\x01\x00') as port:
  155. addr = aiosocks.Socks5Addr('127.0.0.1', port)
  156. auth = aiosocks.Socks5Auth('usr', 'pwd')
  157. dst = ('python.org', 80)
  158. with self.assertRaises(aiosocks.SocksError) as ct:
  159. coro = aiosocks.create_connection(
  160. None, addr, auth, dst, loop=self.loop)
  161. self.loop.run_until_complete(coro)
  162. self.assertIn('General SOCKS server failure', str(ct.exception))
  163. def test_invalid_address_type(self):
  164. with fake_socks_srv(self.loop,
  165. b'\x05\x02\x01\x00\x05\x00\x00\xFF') as port:
  166. addr = aiosocks.Socks5Addr('127.0.0.1', port)
  167. auth = aiosocks.Socks5Auth('usr', 'pwd')
  168. dst = ('python.org', 80)
  169. with self.assertRaises(aiosocks.SocksError) as ct:
  170. coro = aiosocks.create_connection(
  171. None, addr, auth, dst, loop=self.loop)
  172. self.loop.run_until_complete(coro)
  173. self.assertIn('invalid data', str(ct.exception))
  174. def test_atype_ipv4(self):
  175. with fake_socks_srv(
  176. self.loop,
  177. b'\x05\x02\x01\x00\x05\x00\x00\x01\x01\x01\x01\x01\x04W'
  178. ) as port:
  179. addr = aiosocks.Socks5Addr('127.0.0.1', port)
  180. auth = aiosocks.Socks5Auth('usr', 'pwd')
  181. dst = ('python.org', 80)
  182. coro = aiosocks.create_connection(
  183. None, addr, auth, dst, loop=self.loop)
  184. transport, protocol = self.loop.run_until_complete(coro)
  185. self.assertEqual(protocol.proxy_sockname, ('1.1.1.1', 1111))
  186. transport.close()
  187. def test_atype_ipv6(self):
  188. with fake_socks_srv(
  189. self.loop,
  190. b'\x05\x02\x01\x00\x05\x00\x00\x04\x00\x00\x00\x00'
  191. b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x11\x04W'
  192. ) as port:
  193. addr = aiosocks.Socks5Addr('127.0.0.1', port)
  194. auth = aiosocks.Socks5Auth('usr', 'pwd')
  195. dst = ('python.org', 80)
  196. coro = aiosocks.create_connection(
  197. None, addr, auth, dst, loop=self.loop)
  198. transport, protocol = self.loop.run_until_complete(coro)
  199. self.assertEqual(protocol.proxy_sockname, ('::111', 1111))
  200. transport.close()
  201. def test_atype_domain(self):
  202. with fake_socks_srv(
  203. self.loop,
  204. b'\x05\x02\x01\x00\x05\x00\x00\x03\x0apython.org\x04W'
  205. ) as port:
  206. addr = aiosocks.Socks5Addr('127.0.0.1', port)
  207. auth = aiosocks.Socks5Auth('usr', 'pwd')
  208. dst = ('python.org', 80)
  209. coro = aiosocks.create_connection(
  210. None, addr, auth, dst, loop=self.loop)
  211. transport, protocol = self.loop.run_until_complete(coro)
  212. self.assertEqual(protocol.proxy_sockname, (b'python.org', 1111))
  213. transport.close()
  214. class TestSocksConnector(unittest.TestCase):
  215. def setUp(self):
  216. self.loop = asyncio.new_event_loop()
  217. asyncio.set_event_loop(None)
  218. def tearDown(self):
  219. self.loop.close()
  220. def test_http_connect(self):
  221. with fake_socks4_srv(self.loop) as proxy_port:
  222. addr = aiosocks.Socks4Addr('127.0.0.1', proxy_port)
  223. conn = SocksConnector(proxy=addr, proxy_auth=None, loop=self.loop,
  224. remote_resolve=False)
  225. with http_srv(self.loop) as url:
  226. with aiohttp.ClientSession(connector=conn,
  227. loop=self.loop) as ses:
  228. @asyncio.coroutine
  229. def make_req():
  230. return (yield from ses.request('get', url=url))
  231. resp = self.loop.run_until_complete(make_req())
  232. self.assertEqual(resp.status, 200)
  233. content = self.loop.run_until_complete(resp.text())
  234. self.assertEqual(content, 'Test message')
  235. resp.close()
  236. def test_https_connect(self):
  237. with fake_socks4_srv(self.loop) as proxy_port:
  238. addr = aiosocks.Socks4Addr('127.0.0.1', proxy_port)
  239. conn = SocksConnector(proxy=addr, proxy_auth=None, loop=self.loop,
  240. remote_resolve=False, verify_ssl=False)
  241. with http_srv(self.loop, use_ssl=True) as url:
  242. with aiohttp.ClientSession(connector=conn,
  243. loop=self.loop) as ses:
  244. @asyncio.coroutine
  245. def make_req():
  246. return (yield from ses.request('get', url=url))
  247. resp = self.loop.run_until_complete(make_req())
  248. self.assertEqual(resp.status, 200)
  249. content = self.loop.run_until_complete(resp.text())
  250. self.assertEqual(content, 'Test message')
  251. resp.close()
  252. def test_fingerprint_success(self):
  253. with fake_socks4_srv(self.loop) as proxy_port:
  254. addr = aiosocks.Socks4Addr('127.0.0.1', proxy_port)
  255. fp = (b's\x93\xfd:\xed\x08\x1do\xa9\xaeq9'
  256. b'\x1a\xe3\xc5\x7f\x89\xe7l\xf9')
  257. conn = SocksConnector(proxy=addr, proxy_auth=None, loop=self.loop,
  258. remote_resolve=False, verify_ssl=False,
  259. fingerprint=fp)
  260. with http_srv(self.loop, use_ssl=True) as url:
  261. with aiohttp.ClientSession(connector=conn,
  262. loop=self.loop) as ses:
  263. @asyncio.coroutine
  264. def make_req():
  265. return (yield from ses.request('get', url=url))
  266. resp = self.loop.run_until_complete(make_req())
  267. self.assertEqual(resp.status, 200)
  268. content = self.loop.run_until_complete(resp.text())
  269. self.assertEqual(content, 'Test message')
  270. resp.close()
  271. def test_fingerprint_fail(self):
  272. with fake_socks4_srv(self.loop) as proxy_port:
  273. addr = aiosocks.Socks4Addr('127.0.0.1', proxy_port)
  274. fp = (b's\x93\xfd:\xed\x08\x1do\xa9\xaeq9'
  275. b'\x1a\xe3\xc5\x7f\x89\xe7l\x10')
  276. conn = SocksConnector(proxy=addr, proxy_auth=None, loop=self.loop,
  277. remote_resolve=False, verify_ssl=False,
  278. fingerprint=fp)
  279. with http_srv(self.loop, use_ssl=True) as url:
  280. with aiohttp.ClientSession(connector=conn,
  281. loop=self.loop) as ses:
  282. @asyncio.coroutine
  283. def make_req():
  284. return (yield from ses.request('get', url=url))
  285. with self.assertRaises(aiohttp.FingerprintMismatch):
  286. self.loop.run_until_complete(make_req())