aboutsummaryrefslogtreecommitdiffstats
path: root/libmproxy/protocol/tcp.py
blob: 406a6f7b225ca206a6bc38ea22eef38374465b2b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
from . import ProtocolHandler
import select, socket
from cStringIO import StringIO


class TCPHandler(ProtocolHandler):
    """
    TCPHandler acts as a generic TCP forwarder.
    Data will be .log()ed, but not stored any further.
    """
    def handle_messages(self):
        conns = [self.c.client_conn.rfile, self.c.server_conn.rfile]
        while not self.c.close:
            r, _, _ = select.select(conns, [], [], 10)
            for rfile in r:
                if self.c.client_conn.rfile == rfile:
                    src, dst = self.c.client_conn, self.c.server_conn
                    direction = "-> tcp ->"
                    dst_str = "%s:%s" % self.c.server_conn.address()[:2]
                else:
                    dst, src = self.c.client_conn, self.c.server_conn
                    direction = "<- tcp <-"
                    dst_str = "client"

                data = StringIO()
                while range(4096):
                    # Do non-blocking select() to see if there is further data on in the buffer.
                    r, _, _ = select.select([rfile], [], [], 0)
                    if len(r):
                        d = rfile.read(1)
                        if d == "":  # connection closed
                            break
                        data.write(d)

                        """
                        OpenSSL Connections have an internal buffer that might contain data altough everything is read
                        from the socket. Thankfully, connection.pending() returns the amount of bytes in this buffer,
                        so we can read it completely at once.
                        """
                        if src.ssl_established:
                            data.write(rfile.read(src.connection.pending()))
                    else:  # no data left, but not closed yet
                        break
                data = data.getvalue()

                if data == "":  # no data received, rfile is closed
                    self.c.log("Close writing connection to %s" % dst_str)
                    conns.remove(rfile)
                    if dst.ssl_established:
                        dst.connection.shutdown()
                    else:
                        dst.connection.shutdown(socket.SHUT_WR)
                    if len(conns) == 0:
                        self.c.close = True
                    break

                self.c.log("%s %s\r\n%s" % (direction, dst_str,data))
                dst.wfile.write(data)
                dst.wfile.flush()