import multiprocessing import os import re import shutil import socket import subprocess import sys import time import traceback import psutil CURL = 'curl.exe -s -L -k -A "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36" -H "Accept-Language: en-US"' CURL_PROXY = ' --proxy-ntlm ' BASEURL = "" PROXY = "" PYTHON = "" TESTS = [] try: ConnectionRefusedError except NameError: ConnectionRefusedError = socket.error try: DEVNULL = subprocess.DEVNULL except AttributeError: DEVNULL = open(os.devnull, 'wb') def exec_output(cmd): pipe = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout if pipe != None: output = pipe.read().decode("UTF-8", "ignore") else: print("Error running curl") sys.exit() return output def curl(url, proxy="", ntlm=False, filename="", head=False): output = "" cmd = CURL if filename: cmd += " -o " + filename if head: cmd += ' -I' if proxy: cmd += " --proxy " + proxy if ntlm: cmd += ' --proxy-ntlm -U :' cmd += ' "%s"' % url if "--debug" in sys.argv: print(cmd) return exec_output(cmd) def getPyversion(cmd): return int(exec_output(cmd + " -V").split(" ")[1].replace(".", "")) def write(data, file): with open(file, "w") as f: f.write(data) def check(url, proxy, port): start = time.time() a = curl(url, proxy=proxy, ntlm=True) end = time.time() ta = end - start b = curl(url, proxy="localhost:%d" % port) tb = time.time() - end la = len(a) lb = len(b) out = 100 if la < lb: out = la / lb * 100 elif la > lb: out = lb / la * 100 print(" %.2f%%\t%.2fx\t%s" % (out, tb / ta, url)) def waitprocs(procs): ret = True while len(procs): for i in range(len(procs)): if not procs[i].is_alive(): if procs[i].exitcode: ret = False procs.pop(i) break time.sleep(0.1) return ret def run(base, port): if not checkPxStart("localhost", port): return False start = time.time() pop = "" while True: pop = curl(base, proxy="localhost:%d" % port) if pop == "": time.sleep(0.5) else: break procs = [] #urls = re.findall('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', pop) urls = re.findall("http[s]?://[a-zA-Z_./0-9-]+", pop) if len(urls) == 0: print("No urls found") return False for url in set(urls): p = multiprocessing.Process(target=check, args=(url, PROXY, port)) #p.daemon = True p.start() procs.append(p) time.sleep(0.5) ret = True if not waitprocs(procs): ret = False end = time.time() print((" Time: %.2fs" % (end-start)) + " sec") return ret def runPxTest(cmd, testproc, ips, port, proxy): global PROXY PROXY = proxy pipe = subprocess.Popen("cmd /k start /wait /min " + cmd + " --port=" + str(port), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) ret = testproc(ips, port) pxproc = psutil.Process(pipe.pid) for child in pxproc.children(recursive=True): try: child.kill() except psutil.NoSuchProcess: pass try: pxproc.kill() except: pass time.sleep(0.5) return ret def runTest(test, python, count): port = 3129 cmd = "px " if python: port = getPyversion(python) * 10 cmd = python + " px.py " cmd += "--debug --uniqlog " + test[0] + " --port=" + str(port) testproc = test[1] ips = test[2] print("Test %d: \"" % count + test[0] + "\" on port " + str(port)) p = multiprocessing.Process(target=runPxTest, args=(cmd, testproc, ips, port, PROXY)) p.start() return p def getips(): localips = [ip[4][0] for ip in socket.getaddrinfo(socket.gethostname(), 80, socket.AF_INET)] localips.insert(0, "127.0.0.1") return localips def checkPxStart(ip, port): # Make sure Px starts retry = 20 while True: try: socket.create_connection((ip, port), 2) break except (socket.timeout, ConnectionRefusedError): time.sleep(1) retry -= 1 if retry == 0: print("Px didn't start @ %s:%d" % (ip, port)) return False return True # Test --listen and --port, --hostonly, --gateway and --allow def checkCommon(ips, port, checkProc): if ips == [""]: ips = ["127.0.0.1"] if port == "": port = "3128" port = int(port) if not checkPxStart(ips[0], port): return False localips = getips() for lip in localips: for pport in set([3128, port]): sys.stdout.write(" Checking: " + lip + ":" + str(pport) + " = ") ret = checkProc(lip, pport) sys.stdout.write(str(ret) + ": ") if ((lip not in ips or port != pport) and ret is False) or (lip in ips and port == pport and ret is True): print("Passed") else: print("Failed") return False return True def checkSocket(ips, port): def checkProc(lip, pport): try: socket.create_connection((lip, pport), 2) except (socket.timeout, ConnectionRefusedError): return False return True return checkCommon(ips, port, checkProc) def checkFilter(ips, port): def checkProc(lip, port): rcode = subprocess.call("curl --proxy " + lip + ":" + str(port) + " http://google.com", stdout=DEVNULL, stderr=DEVNULL) sys.stdout.write(str(rcode) + " ") if rcode == 0: return True elif rcode in [7, 52, 56]: return False else: print("Weird curl return " + str(rcode)) sys.exit() return checkCommon(ips, port, checkProc) def remoteTest(port, fail=False): lip = 'echo $SSH_CLIENT ^| cut -d \\\" \\\" -f 1,1' cmd = os.getenv("REMOTE_SSH") if cmd is None: print(" Skipping: Remote test - REMOTE_SSH not set") return cmd = cmd + " curl --proxy `%s`:%s --connect-timeout 2 -s http://google.com" % (lip, port) sys.stdout.write(" Checking: Remote:" + str(port) + " = ") ret = subprocess.call(cmd, stdout=DEVNULL, stderr=DEVNULL) if (ret == 0 and fail == False) or (ret != 0 and fail == True) : print(str(ret) + ": Passed") else: print(str(ret) + ": Failed") return False return True def hostonlyTest(ips, port): return checkSocket(ips, port) and remoteTest(port, fail=True) def gatewayTest(ips, port): return checkSocket(ips, port) and remoteTest(port) def allowTest(ips, port): return checkFilter(ips, port) and remoteTest(port) def allowTestFail(ips, port): return checkFilter(ips, port) and remoteTest(port, fail=True) def listenTestLocal(ip, port): return checkSocket([ip], port) and remoteTest(port, fail=True) def listenTestRemote(ip, port): return checkSocket([ip], port) and remoteTest(port) def proxyTest(base, port): return run(base, port) def noproxyTest(base, port): return run(base, port) def socketTestSetup(): if "--nohostonly" not in sys.argv: TESTS.append(("--proxy=" + PROXY + " --hostonly", hostonlyTest, getips())) if "--nogateway" not in sys.argv: TESTS.append(("--proxy=" + PROXY + " --gateway", gatewayTest, getips())) if "--noallow" not in sys.argv: for ip in getips(): oct = ip.split(".")[0] atest = allowTestFail if oct in ["192"]: atest = allowTest TESTS.append(("--proxy=" + PROXY + " --gateway --allow=%s.*.*.*" % oct, atest, list(filter(lambda x: oct in x, getips())))) if "--nolisten" not in sys.argv: localips = getips() localips.insert(0, "") localips.remove("127.0.0.1") for ip in localips[:3]: cmd = "--proxy=" + PROXY if ip != "": cmd += " --listen=" + ip testproc = listenTestLocal if "192" in ip: testproc = listenTestRemote TESTS.append((cmd, testproc, ip)) def auto(): # Make temp directory try: shutil.rmtree("testrun") except: pass time.sleep(1) try: os.makedirs("testrun", exist_ok=True) except TypeError: try: os.makedirs("testrun") except WindowsError: pass os.chdir("testrun") # Load base px.ini shutil.copy("../px.ini", ".") shutil.copy("../px.py", ".") shutil.copy("../dist/px.exe", ".") # Setup tests socketTestSetup() if "--noproxy" not in sys.argv: TESTS.append(("--workers=4 --proxy=" + PROXY, proxyTest, BASEURL)) if "--nonoproxy" not in sys.argv: TESTS.append(("--workers=4 --threads=30 --noproxy=*.*.*.*", noproxyTest, BASEURL)) count = 1 for test in TESTS: procs = [] # Latest version procs.append(runTest(test, PYTHON + "/python.exe", count)) count += 1 if "--envs" in sys.argv: # Test different versions of Python pys = ["27", "35", "37"] for py in pys: procs.append(runTest(test, PYTHON + "/envs/%s/python.exe" % py, count)) count += 1 # Run px.exe procs.append(runTest(test, None, count)) count += 1 if not waitprocs(procs): break os.chdir("..") def get_argval(name): for i in range(len(sys.argv)): if "=" in sys.argv[i]: val = sys.argv[i].split("=")[1] if ("--%s=" % name) in sys.argv[i]: return val return "" if __name__ == "__main__": """python test.py --proxy=testproxy.org:80 --baseurl=http://baseurl.com [--all] Point test.py to the NTLM proxy server that Px should connect through Base URL is some base webpage which will be spidered for URLs to compare results directly through proxy and through Px""" PROXY = get_argval("proxy") BASEURL = get_argval("baseurl") PYTHON = get_argval("python") if PROXY == "": sys.argv.append("--noproxy") if BASEURL == "": sys.argv.append("--noproxy") sys.argv.append("--nonoproxy") if PYTHON == "": PYTHON = "c:/Miniconda" auto()