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.
 
 

421 lines
15 KiB

  1. import unittest
  2. import aiosocks
  3. import asyncio
  4. from unittest import mock
  5. from .socks_serv import fake_socks_srv
  6. try:
  7. from asyncio import ensure_future
  8. except ImportError:
  9. ensure_future = asyncio.async
  10. class TestCreateConnection(unittest.TestCase):
  11. def setUp(self):
  12. self.loop = asyncio.new_event_loop()
  13. asyncio.set_event_loop(None)
  14. def tearDown(self):
  15. self.loop.close()
  16. def _fake_coroutine(self, return_value):
  17. def coro(*args, **kwargs):
  18. if isinstance(return_value, Exception):
  19. raise return_value
  20. return return_value
  21. return mock.Mock(side_effect=asyncio.coroutine(coro))
  22. def test_init(self):
  23. addr = aiosocks.Socks5Addr('localhost')
  24. auth = aiosocks.Socks5Auth('usr', 'pwd')
  25. dst = ('python.org', 80)
  26. # proxy argument
  27. with self.assertRaises(AssertionError) as ct:
  28. conn = aiosocks.create_connection(None, None, auth, dst)
  29. self.loop.run_until_complete(conn)
  30. self.assertEqual(str(ct.exception),
  31. 'proxy must be Socks4Addr() or Socks5Addr() tuple')
  32. with self.assertRaises(AssertionError) as ct:
  33. conn = aiosocks.create_connection(None, auth, auth, dst)
  34. self.loop.run_until_complete(conn)
  35. self.assertEqual(str(ct.exception),
  36. 'proxy must be Socks4Addr() or Socks5Addr() tuple')
  37. # proxy_auth
  38. with self.assertRaises(AssertionError) as ct:
  39. conn = aiosocks.create_connection(None, addr, addr, dst)
  40. self.loop.run_until_complete(conn)
  41. self.assertIn('proxy_auth must be None or Socks4Auth()',
  42. str(ct.exception))
  43. # dst
  44. with self.assertRaises(AssertionError) as ct:
  45. conn = aiosocks.create_connection(None, addr, auth, None)
  46. self.loop.run_until_complete(conn)
  47. self.assertIn('invalid dst format, tuple("dst_host", dst_port))',
  48. str(ct.exception))
  49. # addr and auth compatibility
  50. with self.assertRaises(ValueError) as ct:
  51. conn = aiosocks.create_connection(
  52. None, addr, aiosocks.Socks4Auth(''), dst
  53. )
  54. self.loop.run_until_complete(conn)
  55. self.assertIn('proxy is Socks5Addr but proxy_auth is not Socks5Auth',
  56. str(ct.exception))
  57. with self.assertRaises(ValueError) as ct:
  58. conn = aiosocks.create_connection(
  59. None, aiosocks.Socks4Addr(''), auth, dst
  60. )
  61. self.loop.run_until_complete(conn)
  62. self.assertIn('proxy is Socks4Addr but proxy_auth is not Socks4Auth',
  63. str(ct.exception))
  64. # test ssl, server_hostname
  65. with self.assertRaises(ValueError) as ct:
  66. conn = aiosocks.create_connection(
  67. None, addr, auth, dst, server_hostname='python.org'
  68. )
  69. self.loop.run_until_complete(conn)
  70. self.assertIn('server_hostname is only meaningful with ssl',
  71. str(ct.exception))
  72. def test_connection_fail(self):
  73. addr = aiosocks.Socks5Addr('localhost')
  74. auth = aiosocks.Socks5Auth('usr', 'pwd')
  75. dst = ('python.org', 80)
  76. loop_mock = mock.Mock()
  77. loop_mock.create_connection = self._fake_coroutine(OSError())
  78. with self.assertRaises(aiosocks.SocksConnectionError):
  79. conn = aiosocks.create_connection(
  80. None, addr, auth, dst, loop=loop_mock
  81. )
  82. self.loop.run_until_complete(conn)
  83. class TestCreateSocks4Connection(unittest.TestCase):
  84. def setUp(self):
  85. self.loop = asyncio.new_event_loop()
  86. asyncio.set_event_loop(None)
  87. def tearDown(self):
  88. self.loop.close()
  89. def test_connect_success(self):
  90. server, port = self.loop.run_until_complete(
  91. fake_socks_srv(self.loop, b'\x00\x5a\x04W\x01\x01\x01\x01test')
  92. )
  93. addr = aiosocks.Socks4Addr('127.0.0.1', port)
  94. auth = aiosocks.Socks4Auth('usr')
  95. dst = ('python.org', 80)
  96. coro = aiosocks.create_connection(
  97. None, addr, auth, dst, loop=self.loop)
  98. transport, protocol = self.loop.run_until_complete(coro)
  99. _, addr = protocol._negotiate_fut.result()
  100. self.assertEqual(addr, ('1.1.1.1', 1111))
  101. data = self.loop.run_until_complete(protocol._stream_reader.read(4))
  102. self.assertEqual(data, b'test')
  103. server.close()
  104. transport.close()
  105. def test_invalid_ver(self):
  106. server, port = self.loop.run_until_complete(
  107. fake_socks_srv(self.loop, b'\x01\x5a\x04W\x01\x01\x01\x01')
  108. )
  109. addr = aiosocks.Socks4Addr('127.0.0.1', port)
  110. auth = aiosocks.Socks4Auth('usr')
  111. dst = ('python.org', 80)
  112. with self.assertRaises(aiosocks.SocksError) as ct:
  113. coro = aiosocks.create_connection(
  114. None, addr, auth, dst, loop=self.loop)
  115. transport, protocol = self.loop.run_until_complete(coro)
  116. transport.close()
  117. self.assertIn('invalid data', str(ct.exception))
  118. server.close()
  119. def test_access_not_granted(self):
  120. server, port = self.loop.run_until_complete(
  121. fake_socks_srv(self.loop, b'\x00\x5b\x04W\x01\x01\x01\x01')
  122. )
  123. addr = aiosocks.Socks4Addr('127.0.0.1', port)
  124. auth = aiosocks.Socks4Auth('usr')
  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. transport, protocol = self.loop.run_until_complete(coro)
  130. transport.close()
  131. self.assertIn('0x5b', str(ct.exception))
  132. server.close()
  133. class TestCreateSocks5Connect(unittest.TestCase):
  134. def setUp(self):
  135. self.loop = asyncio.new_event_loop()
  136. asyncio.set_event_loop(None)
  137. def tearDown(self):
  138. self.loop.close()
  139. def test_connect_success_anonymous(self):
  140. server, port = self.loop.run_until_complete(
  141. fake_socks_srv(
  142. self.loop,
  143. b'\x05\x00\x05\x00\x00\x01\x01\x01\x01\x01\x04Wtest'
  144. )
  145. )
  146. addr = aiosocks.Socks5Addr('127.0.0.1', port)
  147. auth = aiosocks.Socks5Auth('usr', 'pwd')
  148. dst = ('python.org', 80)
  149. coro = aiosocks.create_connection(
  150. None, addr, auth, dst, loop=self.loop)
  151. transport, protocol = self.loop.run_until_complete(coro)
  152. _, addr = protocol._negotiate_fut.result()
  153. self.assertEqual(addr, ('1.1.1.1', 1111))
  154. data = self.loop.run_until_complete(protocol._stream_reader.read(4))
  155. self.assertEqual(data, b'test')
  156. server.close()
  157. transport.close()
  158. def test_connect_success_usr_pwd(self):
  159. server, port = self.loop.run_until_complete(
  160. fake_socks_srv(
  161. self.loop,
  162. b'\x05\x02\x01\x00\x05\x00\x00\x01\x01\x01\x01\x01\x04Wtest'
  163. )
  164. )
  165. addr = aiosocks.Socks5Addr('127.0.0.1', port)
  166. auth = aiosocks.Socks5Auth('usr', 'pwd')
  167. dst = ('python.org', 80)
  168. coro = aiosocks.create_connection(
  169. None, addr, auth, dst, loop=self.loop)
  170. transport, protocol = self.loop.run_until_complete(coro)
  171. _, addr = protocol._negotiate_fut.result()
  172. self.assertEqual(addr, ('1.1.1.1', 1111))
  173. data = self.loop.run_until_complete(protocol._stream_reader.read(4))
  174. self.assertEqual(data, b'test')
  175. server.close()
  176. transport.close()
  177. def test_auth_ver_err(self):
  178. server, port = self.loop.run_until_complete(
  179. fake_socks_srv(self.loop, b'\x04\x02')
  180. )
  181. addr = aiosocks.Socks5Addr('127.0.0.1', port)
  182. auth = aiosocks.Socks5Auth('usr', 'pwd')
  183. dst = ('python.org', 80)
  184. with self.assertRaises(aiosocks.SocksError) as ct:
  185. coro = aiosocks.create_connection(
  186. None, addr, auth, dst, loop=self.loop)
  187. transport, protocol = self.loop.run_until_complete(coro)
  188. transport.close()
  189. self.assertIn('invalid version', str(ct.exception))
  190. server.close()
  191. def test_auth_method_rejected(self):
  192. server, port = self.loop.run_until_complete(
  193. fake_socks_srv(self.loop, b'\x05\xFF')
  194. )
  195. addr = aiosocks.Socks5Addr('127.0.0.1', port)
  196. auth = aiosocks.Socks5Auth('usr', 'pwd')
  197. dst = ('python.org', 80)
  198. with self.assertRaises(aiosocks.SocksError) as ct:
  199. coro = aiosocks.create_connection(
  200. None, addr, auth, dst, loop=self.loop)
  201. transport, protocol = self.loop.run_until_complete(coro)
  202. transport.close()
  203. self.assertIn('authentication methods were rejected',
  204. str(ct.exception))
  205. server.close()
  206. def test_auth_status_invalid(self):
  207. server, port = self.loop.run_until_complete(
  208. fake_socks_srv(self.loop, b'\x05\xF0')
  209. )
  210. addr = aiosocks.Socks5Addr('127.0.0.1', port)
  211. auth = aiosocks.Socks5Auth('usr', 'pwd')
  212. dst = ('python.org', 80)
  213. with self.assertRaises(aiosocks.SocksError) as ct:
  214. coro = aiosocks.create_connection(
  215. None, addr, auth, dst, loop=self.loop)
  216. transport, protocol = self.loop.run_until_complete(coro)
  217. transport.close()
  218. self.assertIn('invalid data', str(ct.exception))
  219. server.close()
  220. def test_auth_status_invalid2(self):
  221. server, port = self.loop.run_until_complete(
  222. fake_socks_srv(self.loop, b'\x05\x02\x02\x00')
  223. )
  224. addr = aiosocks.Socks5Addr('127.0.0.1', port)
  225. auth = aiosocks.Socks5Auth('usr', 'pwd')
  226. dst = ('python.org', 80)
  227. with self.assertRaises(aiosocks.SocksError) as ct:
  228. coro = aiosocks.create_connection(
  229. None, addr, auth, dst, loop=self.loop)
  230. transport, protocol = self.loop.run_until_complete(coro)
  231. transport.close()
  232. self.assertIn('invalid data', str(ct.exception))
  233. server.close()
  234. def test_auth_failed(self):
  235. server, port = self.loop.run_until_complete(
  236. fake_socks_srv(self.loop, b'\x05\x02\x01\x01')
  237. )
  238. addr = aiosocks.Socks5Addr('127.0.0.1', port)
  239. auth = aiosocks.Socks5Auth('usr', 'pwd')
  240. dst = ('python.org', 80)
  241. with self.assertRaises(aiosocks.SocksError) as ct:
  242. coro = aiosocks.create_connection(
  243. None, addr, auth, dst, loop=self.loop)
  244. transport, protocol = self.loop.run_until_complete(coro)
  245. transport.close()
  246. self.assertIn('authentication failed', str(ct.exception))
  247. server.close()
  248. def test_cmd_ver_err(self):
  249. server, port = self.loop.run_until_complete(
  250. fake_socks_srv(self.loop, b'\x05\x02\x01\x00\x04\x00\x00')
  251. )
  252. addr = aiosocks.Socks5Addr('127.0.0.1', port)
  253. auth = aiosocks.Socks5Auth('usr', 'pwd')
  254. dst = ('python.org', 80)
  255. with self.assertRaises(aiosocks.SocksError) as ct:
  256. coro = aiosocks.create_connection(
  257. None, addr, auth, dst, loop=self.loop)
  258. transport, protocol = self.loop.run_until_complete(coro)
  259. transport.close()
  260. self.assertIn('invalid version', str(ct.exception))
  261. server.close()
  262. def test_cmd_not_granted(self):
  263. server, port = self.loop.run_until_complete(
  264. fake_socks_srv(self.loop, b'\x05\x02\x01\x00\x05\x01\x00')
  265. )
  266. addr = aiosocks.Socks5Addr('127.0.0.1', port)
  267. auth = aiosocks.Socks5Auth('usr', 'pwd')
  268. dst = ('python.org', 80)
  269. with self.assertRaises(aiosocks.SocksError) as ct:
  270. coro = aiosocks.create_connection(
  271. None, addr, auth, dst, loop=self.loop)
  272. transport, protocol = self.loop.run_until_complete(coro)
  273. transport.close()
  274. self.assertIn('General SOCKS server failure', str(ct.exception))
  275. server.close()
  276. def test_invalid_address_type(self):
  277. server, port = self.loop.run_until_complete(
  278. fake_socks_srv(self.loop, b'\x05\x02\x01\x00\x05\x00\x00\xFF')
  279. )
  280. addr = aiosocks.Socks5Addr('127.0.0.1', port)
  281. auth = aiosocks.Socks5Auth('usr', 'pwd')
  282. dst = ('python.org', 80)
  283. with self.assertRaises(aiosocks.SocksError) as ct:
  284. coro = aiosocks.create_connection(
  285. None, addr, auth, dst, loop=self.loop)
  286. transport, protocol = self.loop.run_until_complete(coro)
  287. transport.close()
  288. self.assertIn('invalid data', str(ct.exception))
  289. server.close()
  290. def test_atype_ipv4(self):
  291. server, port = self.loop.run_until_complete(
  292. fake_socks_srv(
  293. self.loop,
  294. b'\x05\x02\x01\x00\x05\x00\x00\x01\x01\x01\x01\x01\x04W'
  295. )
  296. )
  297. addr = aiosocks.Socks5Addr('127.0.0.1', port)
  298. auth = aiosocks.Socks5Auth('usr', 'pwd')
  299. dst = ('python.org', 80)
  300. coro = aiosocks.create_connection(
  301. None, addr, auth, dst, loop=self.loop)
  302. transport, protocol = self.loop.run_until_complete(coro)
  303. _, addr = protocol._negotiate_fut.result()
  304. self.assertEqual(addr, ('1.1.1.1', 1111))
  305. transport.close()
  306. server.close()
  307. def test_atype_ipv6(self):
  308. server, port = self.loop.run_until_complete(
  309. fake_socks_srv(
  310. self.loop,
  311. b'\x05\x02\x01\x00\x05\x00\x00\x04\x00\x00\x00\x00'
  312. b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x11\x04W')
  313. )
  314. addr = aiosocks.Socks5Addr('127.0.0.1', port)
  315. auth = aiosocks.Socks5Auth('usr', 'pwd')
  316. dst = ('python.org', 80)
  317. coro = aiosocks.create_connection(
  318. None, addr, auth, dst, loop=self.loop)
  319. transport, protocol = self.loop.run_until_complete(coro)
  320. _, addr = protocol._negotiate_fut.result()
  321. self.assertEqual(addr, ('::111', 1111))
  322. transport.close()
  323. server.close()
  324. def test_atype_domain(self):
  325. server, port = self.loop.run_until_complete(
  326. fake_socks_srv(
  327. self.loop,
  328. b'\x05\x02\x01\x00\x05\x00\x00\x03\x0apython.org\x04W'
  329. )
  330. )
  331. addr = aiosocks.Socks5Addr('127.0.0.1', port)
  332. auth = aiosocks.Socks5Auth('usr', 'pwd')
  333. dst = ('python.org', 80)
  334. coro = aiosocks.create_connection(
  335. None, addr, auth, dst, loop=self.loop)
  336. transport, protocol = self.loop.run_until_complete(coro)
  337. _, addr = protocol._negotiate_fut.result()
  338. self.assertEqual(addr, (b'python.org', 1111))
  339. transport.close()
  340. server.close()