LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1293|回复: 0

一个python的代理验证脚本

[复制链接]
发表于 2006-11-10 22:43:29 | 显示全部楼层 |阅读模式

  1. #!/bin/env python

  2. import sys
  3. import getopt
  4. import threading
  5. import string
  6. import socket
  7. import base64
  8. import time
  9. import urlparse
  10. import struct

  11. class Proxy:
  12.         """
  13.         Maintain the proxy and the status of it.
  14.         """
  15.         def __init__(self, urlStr):
  16.                 # parse scheme
  17.                 [self.scheme, t] = string.split(urlStr, "://")

  18.                 # parse auth
  19.                 if string.find(t, "@") == -1:
  20.                         self.needAuth = False
  21.                 else:
  22.                         [auth, t] = string.split(t, "@")
  23.                         self.needAuth = True
  24.                         if string.find(auth, ":") == -1:
  25.                                 self.needPassword = False
  26.                                 self.username = auth
  27.                         else:
  28.                                 self.needPassword = True
  29.                                 [self.username, self.password] = string.split(auth, ":")

  30.                 # parse host and port
  31.                 if string.find(t, ":") == -1:
  32.                         self.host = t
  33.                         self.port = 8080
  34.                 else:
  35.                         [self.host, t] = string.split(t, ":")
  36.                         self.port = int(t)

  37.                 # set this non validated
  38.                 self.validated = False;

  39.         def _parseHttpHeader(self, sock):
  40.                 """
  41.                 Parse the http response header
  42.                 return true if success
  43.                 """
  44.                 retval = False
  45.                 data = ""
  46.                 while True:
  47.                         data += sock.recv(1)
  48.                         if string.find(data, "\r\n") != -1:
  49.                                 if len(data) == 2:
  50.                                         break
  51.                         elif string.find(data, "\n") != -1:
  52.                                 if len(data) == 1:
  53.                                         break
  54.                         else:
  55.                                 continue
  56.                         if string.find(data, "HTTP/1.") == 0:
  57.                                 s = string.split(data, " ")
  58.                                 if len(s) >= 3 and s[1] == "200":
  59.                                         retval = True
  60.                         data = ""

  61.                 return retval

  62.         def _getHttpBody(self, sock):
  63.                 # get the body
  64.                 while True:
  65.                         data = sock.recv(256)
  66.                         if data == "":
  67.                                 break

  68.         def validateHttp(self, testUrl, sock):
  69.                 """
  70.                 Validate the HTTP proxy with the testUrl
  71.                 """
  72.                 data = "GET " + testUrl + " HTTP/1.1\r\n"
  73.                 data += "Connection: close\r\n"
  74.                 if self.needAuth == True and self.needPassword == True:
  75.                         auth = base64.b64encode(self.username + ":" + self.password)
  76.                         data += "Proxy-Authorization: Basic " + auth + "\r\n";
  77.                 data += "\r\n"
  78.                 sock.sendall(data)

  79.                 retval = self._parseHttpHeader(sock)
  80.                 if retval:
  81.                         self._getHttpBody(sock)

  82.                 return retval

  83.         def _getAddrFromUrl(self, testUrl):
  84.                 t = urlparse.urlparse(testUrl)
  85.                 netloc = t[1]
  86.                 retval = []
  87.                 if string.find(netloc, "@") != -1:
  88.                         t = string.split(netloc, "@")
  89.                         netloc = t[1]
  90.                 if string.find(netloc, ":") != -1:
  91.                         t = string.split(netloc, ":")
  92.                         host = t[0]
  93.                         port = int(t[1])
  94.                 else:
  95.                         host = netloc
  96.                         port = 80
  97.                 retval.append(host)
  98.                 retval.append(port)

  99.                 return retval

  100.         def _getHttpPage(self, testUrl, sock):
  101.                 [hostname, port] = self._getAddrFromUrl(testUrl)
  102.                 t = urlparse.urlparse(testUrl)
  103.                 if len(t) < 3 or len(t[2]) == 0:
  104.                         path = "/"
  105.                 else:
  106.                         path = t[2]
  107.                 data = "GET " + path + " HTTP/1.1\r\n"
  108.                 data += "Host: " + hostname + "\r\n"
  109.                 data += "Connection: close\r\n"
  110.                 data += "\r\n"
  111.                 sock.sendall(data)
  112.                 if self._parseHttpHeader(sock) != True:
  113.                         return False
  114.                 self._getHttpBody(sock)

  115.                 return True

  116.         def validateHttpc(self, testUrl, sock):
  117.                 """
  118.                 Validate the HTTP-CONNECT proxy with the testURL
  119.                 """
  120.                 [hostname, port] = self._getAddrFromUrl(testUrl)
  121.                 data = "CONNECT " + hostname + ":" + str(port) + " HTTP/1.1\r\n"
  122.                 if self.needAuth == True and self.needPassword == True:
  123.                         auth = base64.b64encode(self.username + ":" + self.password)
  124.                         data += "Proxy-Authorization: Basic " + auth + "\r\n";
  125.                 data += "\r\n"
  126.                 sock.sendall(data)
  127.                 if self._parseHttpHeader(sock) != True:
  128.                         return False

  129.                 return self._getHttpPage(testUrl, sock)

  130.         def _recvn(self, sock, length):
  131.                 res = ""
  132.                 while len(res) < length:
  133.                         ret = sock.recv(length - len(res))
  134.                         if (len(ret) == 0):
  135.                                 return ""
  136.                         res += ret

  137.                 return res

  138.         def validateSocks4(self, testUrl, sock):
  139.                 """
  140.                 Validate the Socks4 proxy with testUrl
  141.                 """
  142.                 [hostname, port] = self._getAddrFromUrl(testUrl)
  143.                 ip = socket.gethostbyname(hostname)
  144.                 # send connect request
  145.                 req = struct.pack("!BBH", 4, 1, port)
  146.                 req = "%s%s" % (req, socket.inet_aton(ip))
  147.                 if self.needAuth:
  148.                         req = "%s%s\x00" % (req, self.username)
  149.                 else:
  150.                         req = "%s\x00" % (req)
  151.                 sock.sendall(req)

  152.                 # get and parse the response
  153.                 res = self._recvn(sock, 8)
  154.                 if len(res) == 0:
  155.                         return False
  156.                 (vn, cd) = struct.unpack("!BB", res[:2])
  157.                 if vn != 0 or cd != 90:
  158.                         return False

  159.                 return self._getHttpPage(testUrl, sock)

  160.         def validateSocks5(self, testUrl, sock):
  161.                 """
  162.                 Validate the Socks4 proxy with testUrl
  163.                 """
  164.                 # hello and authorization
  165.                 if self.needAuth:
  166.                         req = struct.pack("!BBBB", 5, 2, 0, 2)
  167.                 else:
  168.                         req = struct.pack("!BBB", 5, 1, 0)
  169.                 sock.sendall(req)
  170.                 res = self._recvn(sock, 2)
  171.                 if len(res) == 0:
  172.                         return False
  173.                 (ver, method) = struct.unpack("!BB", res)
  174.                 if ver != 5:
  175.                         return False
  176.                 if method == 2:
  177.                         if self.needAuth != True or self.needPassword != True:
  178.                                 return False
  179.                         req = struct.pack("!BB", 1, len(self.username))
  180.                         req = "%s%s%s%s" % (req, self.username, \
  181.                                         struct.pack("!B", len(self.password)), \
  182.                                         self.password)
  183.                         sock.sendall(req)
  184.                         res = self._recvn(sock, 2)
  185.                         if len(res) == 0:
  186.                                 return False
  187.                         (ver, status) = struct.unpack("!BB", res)
  188.                         if ver != 0 or status != 0:
  189.                                 return False
  190.                 elif method != 0:
  191.                         return False

  192.                 # connect
  193.                 [hostname, port] = self._getAddrFromUrl(testUrl)
  194.                 ip = socket.gethostbyname(hostname)
  195.                 req = struct.pack("!BBBB", 5, 1, 0, 1)
  196.                 req = "%s%s%s" % (req, socket.inet_aton(ip), struct.pack("!H", port))
  197.                 sock.sendall(req)
  198.                 res = self._recvn(sock, 5)
  199.                 if len(res) == 0:
  200.                         return False
  201.                 (ver, rep, rsv, atyp, addrLen) = struct.unpack("!BBBBB", res)
  202.                 if (ver != 5 or rep != 0 or rsv != 0):
  203.                         return False
  204.                 if atyp == 1:
  205.                         res = self._recvn(sock, 5)
  206.                 elif atyp == 3:
  207.                         res = self._recvn(sock, addrLen + 2)
  208.                 elif atyp == 4:
  209.                         res = self._recvn(sock, 17)
  210.                 else:
  211.                         return False
  212.                 if (len(res) == 0):
  213.                         return False

  214.                 return self._getHttpPage(testUrl, sock)

  215.         def validate(self, testUrl):
  216.                 """
  217.                 Validate the proxy server, return true if successfully.
  218.                 """
  219.                 self.startTime = time.time()

  220.                 # connect to the proxy server
  221.                 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP)
  222.                 sock.connect((self.host, self.port))
  223.                 self.connectTime = time.time()

  224.                 if self.scheme == "http":
  225.                         retval = self.validateHttp(testUrl, sock)
  226.                 elif self.scheme == "httpc":
  227.                         retval = self.validateHttpc(testUrl, sock)
  228.                 elif self.scheme == "socks4":
  229.                         retval = self.validateSocks4(testUrl, sock)
  230.                 elif self.scheme == "socks5":
  231.                         retval = self.validateSocks5(testUrl, sock)
  232.                 else:
  233.                         retval = False

  234.                 sock.close()
  235.                 self.endTime = time.time()
  236.                 self.validated = True

  237.                 return retval

  238. class ValidateThread(threading.Thread):
  239.         def __init__(self, proxy, url, sema, lock):
  240.                 threading.Thread.__init__(self)
  241.                 self._proxy = proxy
  242.                 self._sema = sema
  243.                 self._sema.acquire()
  244.                 self._lock = lock
  245.                 self._url = url

  246.         def __del__(self):
  247.                 self._sema.release()

  248.         def run(self):
  249.                 if self._proxy.validate(url) == True:
  250.                         self._lock.acquire()
  251.                         proxy = self._proxy
  252.                         urlStr = proxy.scheme + "://"
  253.                         if (proxy.needAuth):
  254.                                 urlStr += proxy.username
  255.                                 if (proxy.needPassword):
  256.                                         urlStr += ":" + proxy.password
  257.                                 urlStr += "@"
  258.                         urlStr += proxy.host + ":" + str(proxy.port)
  259.                         print urlStr, proxy.connectTime - proxy.startTime, \
  260.                                         proxy.endTime - proxy.connectTime, \
  261.                                         proxy.endTime - proxy.startTime
  262.                         self._lock.release()

  263. def CreateValidateThread(proxy, url, sema, lock):
  264.         thread = ValidateThread(proxy, url, sema, lock)
  265.         thread.setDaemon(True)
  266.         thread.start()

  267. def showHelp(prog):
  268.         print "valproxy 0.0.1: A proxies validating tool."
  269.         print "Usage: %s [option]..." % prog
  270.         print "Options:"
  271.         print "  -h, --help             Show the help information"
  272.         print "  -i, --input-file=file  Use the file as input instead of stdin"
  273.         print "  -l, --test-url=url     Use the url as the test url "\
  274.                         + "instead of www.163.com"
  275.         print "  -n, --max-thread-num=n Set the max thread number at "\
  276.                         + "the same time to n, default 10"

  277. if __name__ == "__main__":
  278.         maxThreadNum = 10
  279.         lock = threading.Lock()
  280.         url = "http://www.163.com/index.html"
  281.         inFile = sys.stdin

  282.         # parse the arguments
  283.         try:
  284.                 (opts, args) = getopt.getopt(sys.argv[1:], "hi:l:n:", \
  285.                                 ["help", "input-file=", "test-url=", "max-thread-num="])
  286.         except getopt.GetoptError:
  287.                 showHelp(sys.argv[0])
  288.                 sys.exit(1)
  289.         if len(args) > 0:
  290.                 showHelp(sys.argv[0])
  291.                 sys.exit(1)
  292.         for (o, a) in opts:
  293.                 if o in ("-h", "--help"):
  294.                         showHelp(sys.argv[0])
  295.                         sys.exit(0)
  296.                 elif o in ("-i", "--input-file"):
  297.                         inFile = file(a, "r")
  298.                 elif o in ("-l", "--test-url"):
  299.                         url = a
  300.                 elif o in ("-n", "--max-thread-num"):
  301.                         maxThreadNum = int(a)
  302.                         if (maxThreadNum <= 0):
  303.                                 print "the argument for options n and max-thread-num must"\
  304.                                                 + "be no less than 0"
  305.                                 sys.exit(1)
  306.                 else:
  307.                         print "Unknown option: " + o
  308.                         showHelp(sys.argv[0])
  309.                         sys.exit(1)

  310.         sema = threading.Semaphore(maxThreadNum)

  311.         # validate the proxy one by one
  312.         while True:
  313.                 line = string.strip(inFile.readline())
  314.                 if len(line) == 0:
  315.                         break
  316.                 proxy = Proxy(line)
  317.                 CreateValidateThread(proxy, url, sema, lock)

  318.         # wait until all the threads exit
  319.         n = maxThreadNum
  320.         while n > 0:
  321.                 sema.acquire()
  322.                 n -= 1
  323.         while n < maxThreadNum:
  324.                 sema.release()
  325.                 n += 1
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表