wsproxy.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. #!/usr/bin/python
  2. import sys, os, socket, time, traceback
  3. from base64 import b64encode, b64decode
  4. from select import select
  5. buffer_size = 65536
  6. send_seq = 0
  7. server_handshake = """HTTP/1.1 101 Web Socket Protocol Handshake\r
  8. Upgrade: WebSocket\r
  9. Connection: Upgrade\r
  10. WebSocket-Origin: %s\r
  11. WebSocket-Location: ws://%s%s\r
  12. WebSocket-Protocol: sample\r
  13. \r
  14. """
  15. policy_response = """<cross-domain-policy><allow-access-from domain="*" to-ports="*" /></cross-domain-policy>"""
  16. traffic_legend = """
  17. Traffic Legend:
  18. } - Client receive
  19. }. - Client receive partial
  20. { - Target receive
  21. > - Target send
  22. >. - Target send partial
  23. < - Client send
  24. <. - Client send partial
  25. """
  26. def handshake(client):
  27. handshake = client.recv(1024)
  28. print "Handshake [%s]" % handshake
  29. if handshake.startswith("<policy-file-request/>"):
  30. print "Sending:", policy_response
  31. client.send(policy_response)
  32. handshake = client.recv(1024)
  33. print "Handshake [%s]" % handshake
  34. req_lines = handshake.split("\r\n")
  35. _, path, _ = req_lines[0].split(" ")
  36. _, origin = req_lines[4].split(" ")
  37. _, host = req_lines[3].split(" ")
  38. client.send(server_handshake % (origin, host, path))
  39. def traffic(token="."):
  40. sys.stdout.write(token)
  41. sys.stdout.flush()
  42. def decode(buf):
  43. """ Parse out WebSocket packets. """
  44. if buf.count('\xff') > 1:
  45. traffic(str(buf.count('\xff')))
  46. return [b64decode(d[1:]) for d in buf.split('\xff')]
  47. else:
  48. return [b64decode(buf[1:-1])]
  49. def proxy(client, target):
  50. """ Proxy WebSocket to normal socket. """
  51. global send_seq
  52. cqueue = []
  53. cpartial = ""
  54. tqueue = []
  55. socks = [client, target]
  56. while True:
  57. ins, outs, excepts = select(socks, socks, socks, 1)
  58. if excepts: raise Exception("Socket exception")
  59. if tqueue and target in outs:
  60. #print "Target send: %s" % repr(tqueue[0])
  61. log.write("Target send: %s\n" % map(ord, tqueue[0]))
  62. dat = tqueue.pop(0)
  63. sent = target.send(dat)
  64. if sent == len(dat):
  65. traffic(">")
  66. else:
  67. tqueue.insert(0, dat[sent:])
  68. traffic(">.")
  69. if cqueue and client in outs:
  70. dat = cqueue.pop(0)
  71. sent = client.send(dat)
  72. if sent == len(dat):
  73. traffic("<")
  74. log.write("Client send: %s\n" % repr(dat))
  75. else:
  76. cqueue.insert(0, dat[sent:])
  77. traffic("<.")
  78. log.write("Client send partial: %s\n" % repr(dat[0:send]))
  79. if target in ins:
  80. buf = target.recv(buffer_size)
  81. if len(buf) == 0: raise Exception("Target closed")
  82. #enc = b64encode(buf)
  83. #chksum = sum([ord(c) for c in enc])
  84. #cqueue.append("\x00^" + str(chksum) + "@" + enc + "$\xff")
  85. cqueue.append("\x00%d:%s\xff" % (send_seq, b64encode(buf)))
  86. send_seq += 1
  87. log.write("Target recv (%d): %s\n" % (len(buf), map(ord, buf)))
  88. traffic("{")
  89. if client in ins:
  90. buf = client.recv(buffer_size)
  91. if len(buf) == 0: raise Exception("Client closed")
  92. if buf[-1] == "\xff":
  93. traffic("}")
  94. log.write("Client recv (%d): %s\n" % (len(buf), repr(buf)))
  95. if cpartial:
  96. tqueue.extend(decode(cpartial + buf))
  97. cpartial = ""
  98. else:
  99. tqueue.extend(decode(buf))
  100. else:
  101. traffic("}.")
  102. log.write("Client recv partial (%d): %s\n" % (len(buf), repr(buf)))
  103. cpartial = cpartial + buf
  104. def start_server(listen_port, target_host, target_port):
  105. global send_seq
  106. lsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  107. lsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  108. lsock.bind(('', listen_port))
  109. lsock.listen(100)
  110. print traffic_legend
  111. while True:
  112. try:
  113. csock = tsock = None
  114. print 'waiting for connection on port %s' % listen_port
  115. csock, address = lsock.accept()
  116. print 'Got client connection from %s' % address[0]
  117. handshake(csock)
  118. print "Connecting to: %s:%s" % (target_host, target_port)
  119. tsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  120. tsock.connect((target_host, target_port))
  121. send_seq = 0
  122. proxy(csock, tsock)
  123. except Exception:
  124. print "Ignoring exception:"
  125. print traceback.format_exc()
  126. if csock: csock.close()
  127. if tsock: tsock.close()
  128. if __name__ == '__main__':
  129. log = open("ws.log", 'w')
  130. try:
  131. if len(sys.argv) != 4: raise
  132. listen_port = int(sys.argv[1])
  133. target_host = sys.argv[2]
  134. target_port = int(sys.argv[3])
  135. except:
  136. print "Usage: <listen_port> <target_host> <target_port>"
  137. sys.exit(1)
  138. start_server(listen_port, target_host, target_port)