Home | History | Annotate | Download | only in platform_TLSDateActual
      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 
     15 import subprocess
     16 import test
     17 
     18 # Taken and hacked from https://code.google.com/p/python-socks5/
     19 
     20 import socket
     21 from threading import Thread
     22 
     23 from autotest_lib.client.common_lib import error
     24 
     25 SOCKTIMEOUT=5
     26 RESENDTIMEOUT=300
     27 
     28 class Forwarder(Thread):
     29     def __init__(self,src,dest):
     30         Thread.__init__(self)
     31         self.src=src
     32         self.dest=dest
     33 
     34 
     35     def __str__(self):
     36         return '<Forwarder from %s to %s>' % (self.src, self.dest)
     37 
     38 
     39     def run(self):
     40         print '%s: starting' % self
     41         try:
     42             self.forward()
     43         except socket.error as e:
     44             print '%s: exception %s' % (self, e)
     45             self.src.close()
     46             self.dest.close()
     47         finally:
     48             print '%s: exiting' % self
     49 
     50 
     51     def forward(self):
     52         BUFSIZE = 1024
     53         data = self.src.recv(BUFSIZE)
     54         while data:
     55             self.dest.sendall(data)
     56             data = self.src.recv(BUFSIZE)
     57         self.src.close()
     58         self.dest.close()
     59         print '%s: client quit normally' % self
     60 
     61 
     62 class ProxyForwarder(Forwarder):
     63     def __init__(self, src, dest_addr):
     64         Forwarder.__init__(self, src, None)
     65         self.dest_addr = dest_addr
     66         self.src = src
     67         self.dest = None
     68 
     69 
     70     def __str__(self):
     71         return '<ProxyForwarder between %s and %s (%s:%d)' % (
     72             self.src, self.dest, self.dest_addr[0], self.dest_addr[1])
     73 
     74 
     75     def forward(self):
     76         self.dest = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
     77         self.dest.connect(self.dest_addr)
     78         self.src.settimeout(RESENDTIMEOUT)
     79         self.dest.settimeout(RESENDTIMEOUT)
     80         Forwarder(self.src,self.dest).start()
     81         Forwarder(self.dest,self.src).start()
     82 
     83 
     84 def recvbytes(sock, n):
     85     bs = sock.recv(n)
     86     return [ ord(x) for x in bs ]
     87 
     88 
     89 def recvshort(sock):
     90     x = recvbytes(sock, 2)
     91     return x[0] * 256 + x[1]
     92 
     93 
     94 def create_server(ip,port):
     95     SOCKS5_VER = "\x05"
     96     AUTH_NONE = "\x00"
     97 
     98     ATYP_DOMAIN = 0x03
     99 
    100     CMD_CONNECT = 0x01
    101 
    102     ERR_SUCCESS = "\x00"
    103     ERR_UNSUPP = "\x07"
    104 
    105     transformer = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    106     transformer.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    107     transformer.bind((ip, port))
    108     transformer.listen(1000)
    109 
    110     network_port = chr(port >> 8) + chr(port & 0xff)
    111     # Turn the textual IP address we were supplied with into a
    112     # network-byte-order IP address for SOCKS5 wire protocol
    113     network_ip = "".join(chr(int(i)) for i in ip.split("."))
    114     while True:
    115         sock = transformer.accept()[0]
    116         sock.settimeout(SOCKTIMEOUT)
    117         print "Got one client connection"
    118         (_, nmethods) = recvbytes(sock, 2)
    119         _ = recvbytes(sock, nmethods)
    120         sock.sendall(SOCKS5_VER + AUTH_NONE)
    121         (_, cmd, _, atyp) = recvbytes(sock, 4)
    122         dst_addr = None
    123         dst_port = None
    124         if atyp == ATYP_DOMAIN:
    125             addr_len = recvbytes(sock, 1)[0]
    126             dst_addr = "".join([unichr(x) for x in recvbytes(sock, addr_len)])
    127             dst_port = recvshort(sock)
    128         else:
    129             socket.sendall(SOCKS5_VER + ERR_UNSUPP + network_ip + network_port)
    130         print "Proxying to %s:%d" %(dst_addr,dst_port)
    131 
    132         if cmd == CMD_CONNECT:
    133             sock.sendall(SOCKS5_VER + ERR_SUCCESS + "\x00" + "\x01" +
    134                          network_ip + network_port)
    135             print "Starting forwarding thread"
    136             ProxyForwarder(sock, (dst_addr, dst_port)).start()
    137         else:
    138             sock.sendall(SOCKS5_VER + ERR_UNSUPP + network_ip + network_port)
    139             sock.close()
    140 
    141 
    142 class ServingThread(Thread):
    143     def __init__(self, ip, port):
    144         Thread.__init__(self)
    145         self.ip = ip
    146         self.port = port
    147 
    148 
    149     def run(self):
    150         create_server(self.ip, self.port)
    151 
    152 
    153 class platform_TLSDateActual(test.test):
    154     version = 1
    155 
    156 
    157     def tlsdate(self, host, proxy):
    158         args = ['/usr/bin/tlsdate', '-v', '-l', '-H', host]
    159         if proxy:
    160             args += ['-x', proxy]
    161         p = subprocess.Popen(args, stderr=subprocess.PIPE)
    162         out = p.communicate()[1]
    163         print out
    164         return p.returncode
    165 
    166 
    167     def run_once(self):
    168         t = ServingThread("127.0.0.1", 8083)
    169         t.start()
    170         r = self.tlsdate('clients3.google.com', None)
    171         if r != 0:
    172             raise error.TestFail('tlsdate with no proxy to good host failed: %d' % r)
    173         r = self.tlsdate('clients3.google.com', 'socks5://127.0.0.1:8083')
    174         if r != 0:
    175             raise error.TestFail('tlsdate with proxy to good host failed: %d' % r)
    176         r = self.tlsdate('invalid-host.example.com', None)
    177         if r == 0:
    178             raise error.TestFail('tlsdate with no proxy to bad host succeeded')
    179         r = self.tlsdate('invalid-host.example.com', 'socks5://127.0.0.1:8083')
    180         if r == 0:
    181             raise error.TestFail('tlsdate with proxy to bad host succeeded')
    182