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.

148 lines
4.6 KiB

6 years ago
6 years ago
6 years ago
6 years ago
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. #
  4. # Copyright 2015 clowwindy
  5. #
  6. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  7. # not use this file except in compliance with the License. You may obtain
  8. # a copy of the License at
  9. #
  10. # http://www.apache.org/licenses/LICENSE-2.0
  11. #
  12. # Unless required by applicable law or agreed to in writing, software
  13. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  14. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  15. # License for the specific language governing permissions and limitations
  16. # under the License.
  17. from __future__ import absolute_import, division, print_function, \
  18. with_statement
  19. import sys
  20. import os
  21. import signal
  22. import select
  23. import time
  24. import argparse
  25. from subprocess import Popen, PIPE
  26. default_url = 'http://www.google.com/'
  27. parser = argparse.ArgumentParser(description='test Shadowsocks')
  28. parser.add_argument('-c', '--client-conf', type=str, default=None)
  29. parser.add_argument('-s', '--server-conf', type=str, default=None)
  30. parser.add_argument('-a', '--client-args', type=str, default=None)
  31. parser.add_argument('-b', '--server-args', type=str, default=None)
  32. parser.add_argument('--should-fail', action='store_true', default=None)
  33. parser.add_argument('--url', type=str, default=default_url)
  34. parser.add_argument('--dns', type=str, default='8.8.8.8')
  35. parser.add_argument('--bin', type=str, default='')
  36. config = parser.parse_args()
  37. client_args = ['%s%s' % (config.bin, 'ss-local'), '-v']
  38. server_args = ['%s%s' % (config.bin, 'ss-server'), '-v', '-u']
  39. tunnel_args = ['%s%s' % (config.bin, 'ss-tunnel'), '-v', '-u', '-l1082', '-L%s:53' % config.dns]
  40. if config.client_conf:
  41. client_args.extend(['-c', config.client_conf])
  42. tunnel_args.extend(['-c', config.client_conf])
  43. if config.server_conf:
  44. server_args.extend(['-c', config.server_conf])
  45. else:
  46. server_args.extend(['-c', config.client_conf])
  47. if config.client_args:
  48. client_args.extend(config.client_args.split())
  49. tunnel_args.extend(config.client_args.split())
  50. if config.server_args:
  51. server_args.extend(config.server_args.split())
  52. else:
  53. server_args.extend(config.client_args.split())
  54. p1 = Popen(server_args, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
  55. p2 = Popen(client_args, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
  56. p5 = Popen(tunnel_args, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
  57. p3 = None
  58. p4 = None
  59. p3_fin = False
  60. p4_fin = False
  61. # 1 shadowsocks started
  62. # 2 curl started
  63. # 3 curl finished
  64. # 4 dig started
  65. # 5 dig finished
  66. stage = 1
  67. try:
  68. fdset = []
  69. time.sleep(2)
  70. p3 = Popen(['curl', config.url, '-v', '-L',
  71. '--socks5-hostname', '127.0.0.1:1081',
  72. '-m', '15', '--connect-timeout', '10'],
  73. stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
  74. if p3 is not None:
  75. fdset.append(p3.stdout)
  76. fdset.append(p3.stderr)
  77. stage = 2
  78. else:
  79. sys.exit(1)
  80. while True:
  81. r, w, e = select.select(fdset, [], fdset)
  82. if e:
  83. break
  84. for fd in r:
  85. line = fd.readline()
  86. if not line:
  87. if stage == 2 and fd == p3.stdout:
  88. stage = 3
  89. if stage == 4 and fd == p4.stdout:
  90. stage = 5
  91. if bytes != str:
  92. line = bytes(line)
  93. sys.stderr.buffer.write(line)
  94. else:
  95. sys.stderr.write(line)
  96. if stage == 3 and p3 is not None:
  97. fdset.remove(p3.stdout)
  98. fdset.remove(p3.stderr)
  99. r = p3.wait()
  100. if config.should_fail:
  101. if r == 0:
  102. sys.exit(1)
  103. else:
  104. if r != 0:
  105. sys.exit(1)
  106. p4 = Popen(['dig', '@127.0.0.1', '-p1082',
  107. 'www.google.com'],
  108. stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
  109. if p4 is not None:
  110. fdset.append(p4.stdout)
  111. fdset.append(p4.stderr)
  112. stage = 4
  113. else:
  114. sys.exit(1)
  115. if stage == 5:
  116. r = p4.wait()
  117. if config.should_fail:
  118. if r == 0:
  119. sys.exit(1)
  120. print('test passed (expecting failure)')
  121. else:
  122. if r != 0:
  123. sys.exit(1)
  124. print('test passed')
  125. break
  126. finally:
  127. for p in [p1, p2, p5]:
  128. try:
  129. os.kill(p.pid, signal.SIGINT)
  130. os.waitpid(p.pid, 0)
  131. except OSError:
  132. pass