1# Copyright (c) 2013 The Chromium OS Authors and the python-socks5 authors. 2# 3# This program is free software: you can redistribute it and/or modify 4# it under the terms of the GNU General Public License version 3, 5# as published by the Free Software Foundation. 6# 7# This program is distributed in the hope that it will be useful, 8# but WITHOUT ANY WARRANTY; without even the implied warranty of 9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10# GNU General Public License for more details. 11# 12# You should have received a copy of the GNU General Public License 13# along with this program. If not, see <http://www.gnu.org/licenses/>. 14 15import subprocess 16import test 17 18# Taken and hacked from https://code.google.com/p/python-socks5/ 19 20import socket 21from threading import Thread 22 23SOCKTIMEOUT=5 24RESENDTIMEOUT=300 25 26class Forwarder(Thread): 27 def __init__(self,src,dest): 28 Thread.__init__(self) 29 self.src=src 30 self.dest=dest 31 32 def __str__(self): 33 return '<Forwarder from %s to %s>' % (self.src, self.dest) 34 35 def run(self): 36 print '%s: starting' % self 37 try: 38 self.forward() 39 except socket.error as e: 40 print '%s: exception %s' % (self, e) 41 self.src.close() 42 self.dest.close() 43 finally: 44 print '%s: exiting' % self 45 46 def forward(self): 47 BUFSIZE = 1024 48 data = self.src.recv(BUFSIZE) 49 while data: 50 self.dest.sendall(data) 51 data = self.src.recv(BUFSIZE) 52 self.src.close() 53 self.dest.close() 54 print '%s: client quit normally' % self 55 56class ProxyForwarder(Forwarder): 57 def __init__(self, src, dest_addr): 58 Forwarder.__init__(self, src, None) 59 self.dest_addr = dest_addr 60 self.src = src 61 self.dest = None 62 63 def __str__(self): 64 return '<ProxyForwarder between %s and %s (%s:%d)' % ( 65 self.src, self.dest, self.dest_addr[0], self.dest_addr[1]) 66 67 def forward(self): 68 self.dest = socket.socket(socket.AF_INET,socket.SOCK_STREAM) 69 self.dest.connect(self.dest_addr) 70 self.src.settimeout(RESENDTIMEOUT) 71 self.dest.settimeout(RESENDTIMEOUT) 72 Forwarder(self.src,self.dest).start() 73 Forwarder(self.dest,self.src).start() 74 75def recvbytes(sock, n): 76 bs = sock.recv(n) 77 return [ ord(x) for x in bs ] 78 79def recvshort(sock): 80 x = recvbytes(sock, 2) 81 return x[0] * 256 + x[1] 82 83def create_server(ip,port): 84 SOCKS5_VER = "\x05" 85 AUTH_NONE = "\x00" 86 87 ATYP_DOMAIN = 0x03 88 89 CMD_CONNECT = 0x01 90 91 ERR_SUCCESS = "\x00" 92 ERR_UNSUPP = "\x07" 93 94 transformer = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 95 transformer.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 96 transformer.bind((ip, port)) 97 transformer.listen(1000) 98 99 network_port = chr(port >> 8) + chr(port & 0xff) 100 # Turn the textual IP address we were supplied with into a 101 # network-byte-order IP address for SOCKS5 wire protocol 102 network_ip = "".join(chr(int(i)) for i in ip.split(".")) 103 while True: 104 sock = transformer.accept()[0] 105 sock.settimeout(SOCKTIMEOUT) 106 print "Got one client connection" 107 (_, nmethods) = recvbytes(sock, 2) 108 _ = recvbytes(sock, nmethods) 109 sock.sendall(SOCKS5_VER + AUTH_NONE) 110 (_, cmd, _, atyp) = recvbytes(sock, 4) 111 dst_addr = None 112 dst_port = None 113 if atyp == ATYP_DOMAIN: 114 addr_len = recvbytes(sock, 1)[0] 115 dst_addr = "".join([unichr(x) for x in recvbytes(sock, addr_len)]) 116 dst_port = recvshort(sock) 117 else: 118 socket.sendall(SOCKS5_VER + ERR_UNSUPP + network_ip + network_port) 119 print "Proxying to %s:%d" %(dst_addr,dst_port) 120 121 if cmd == CMD_CONNECT: 122 sock.sendall(SOCKS5_VER + ERR_SUCCESS + "\x00" + "\x01" + 123 network_ip + network_port) 124 print "Starting forwarding thread" 125 ProxyForwarder(sock, (dst_addr, dst_port)).start() 126 else: 127 sock.sendall(SOCKS5_VER + ERR_UNSUPP + network_ip + network_port) 128 sock.close() 129 130class ServingThread(Thread): 131 def __init__(self, ip, port): 132 Thread.__init__(self) 133 self.ip = ip 134 self.port = port 135 136 def run(self): 137 create_server(self.ip, self.port) 138 139class platform_TLSDateActual(test.test): 140 version = 1 141 142 def tlsdate(self, host, proxy): 143 args = ['/usr/bin/tlsdate', '-v', '-l', '-H', host] 144 if proxy: 145 args += ['-x', proxy] 146 p = subprocess.Popen(args, stderr=subprocess.PIPE) 147 out = p.communicate()[1] 148 print out 149 return p.returncode 150 151 def run_once(self): 152 t = ServingThread("127.0.0.1", 8083) 153 t.start() 154 r = self.tlsdate('clients3.google.com', None) 155 if r != 0: 156 raise error.TestFail('tlsdate with no proxy to good host failed: %d' % r) 157 r = self.tlsdate('clients3.google.com', 'socks5://127.0.0.1:8083') 158 if r != 0: 159 raise error.TestFail('tlsdate with proxy to good host failed: %d' % r) 160 r = self.tlsdate('invalid-host.example.com', None) 161 if r == 0: 162 raise error.TestFail('tlsdate with no proxy to bad host succeeded') 163 r = self.tlsdate('invalid-host.example.com', 'socks5://127.0.0.1:8083') 164 if r == 0: 165 raise error.TestFail('tlsdate with proxy to bad host succeeded') 166