def handle(self): global HEARTBEAT_SOCKET_COUNT sock = self.connection HEARTBEAT_SOCKET_COUNT += 1 sock.settimeout(10) try: data = sock.recv(4096) except TimeoutError: logging.warning(f"HeartBeat Timed out") dec_data = decrypt(data) obj = hsp.handshake() peer_ip, port = sock.getpeername() # 收到请求时如果是白名单中的ip, 则不需要再校验 if peer_ip not in white_list: logging.info( f"received heartbeat from {peer_ip}, white_list:{white_list}, black_list:{black_list}" ) # 收到请求若是黑名单中的, 则直接拒绝 if peer_ip in black_list: logging.info(f"rejected black listed heartbeat {peer_ip}") raise Exception(f"rejected black listed heartbeat {peer_ip}") else: try: if obj.decode_protocol(dec_data) != 'Done': # 加入黑名单 black_list.append(peer_ip) logging.info( f"after {peer_ip}, white_list:{white_list}, black_list:{black_list}" ) else: # 加入白名单 white_list.append(peer_ip) if peer_ip in black_list: black_list.remove(peer_ip) logging.info( f"after {peer_ip}, white_list:{white_list}, black_list:{black_list}" ) except Exception as e: logging.error(e) exc_type, exc_obj, exc_tb = sys.exc_info() fname = os.path.split( exc_tb.tb_frame.f_code.co_filename)[1] logging.warning(f"{exc_type} {fname} {exc_tb.tb_lineno}") pass sock.close() HEARTBEAT_SOCKET_COUNT -= 1
def pulse(ip, port): try: remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM) remote.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) remote.connect((ip, port)) # logging.info(f"sending heartbeat to {ip}:{port}") send_all( remote, encrypt( hsp.handshake(addr='hello', port=str(port)).encode_protocol())) except ConnectionRefusedError: logging.warning(f"cannot talk to {ip}:{port}") except Exception as e: logging.warning(e) exc_type, exc_obj, exc_tb = sys.exc_info() fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] logging.warning(f"{exc_type} {fname} {exc_tb.tb_lineno}") global pulse_thread pulse_thread = threading.Timer(5, pulse, (ip, port)) pulse_thread.start()
import handshake_protocol_v1 as hsp m = hsp.handshake('ip', '1.1.1.1', '8080') n = hsp.handshake('url', 'www.baidu.com', '8080') u = hsp.handshake() print(m.encode_protocol()) print(n.encode_protocol()) print(u.encode_protocol()) k = u.decode_protocol(m.encode_protocol()) print(u.encode_protocol()) dd = hsp.bytedata( raw_data= b'd5edb61c315af758b4be428991d615b6f44156d01c17b9ab3ba26fd9452ba715db0d771da68cbca4f4c8ecfec9d1acf4f192d6042981dd9d9e0e8f6ba4b6452cfa612ac49d5b8dba93aeec38b4e63a1e5da8dd911a2ab6e015a924d6c6e6744ac6bfdceae3096c587dc560f241bf188ab0b4086a0161b341d045be5e138d26b331534e5ba4b3f77ecf6ac58a70ab465bb56034146748bd4157e7b3da9626d67d96e570ed46acd6507a5c77571f20961a5a35f582379fd86213f0acf590d08ce8e4c8e103f8419324b23052d6d8333995b0d7d08f75b8efc6f3497e17ba95959b5ca35bbd329a41e5aa57a997db06559a7b0636d7b31c9e5acc117cf6f7d70a6ffc68783df9d1e7cf10cb5ec494c82f094dacd65700dcb8efe0ed149577b8d324d70567ad45242b064b7ad628f9069d84bee82dd6db6b3c47107683598ed360f837aed83703aa547155d4974ba6d780a1ba40151378b656279319d530f736641f708bc9105eb165d61d72eb346da6dd995d1ecadcdcef14efad8f14af1c4eed1607592e95cbde33ab96cd7e974d3e86e94f444aebd747c369f379e1ad0b9ce8cae66cd2415d9e315d9135fa46357edb64ba5e49b51ca021ab7a473e29d349e9b98d7ed32f76097dd46b7d959348ab18ab3e0c884ae68e881b08830b3f48f878922daac26b7f782a83a6bd1bfdea34377e28163fc9ca1df33c6833df4406b30cb7ae0c05d07ee3f346b09725eb9bbedf2ac05d84515aeb304a4474701b2c7e7ca0c1276bcefe0f8f8f4d8e0cfef0cde3adb3ff3c6e6cb6f0fcebc3039b171f5dcf5379f1fbc7579f0caa7ec19bc095342b9d93ce53a85fbe0d6a02f81e9421e65ddce8376cdadfc97b30adaeb82e653b08e2f0470ce410e5856bdd148931176bfb370e74a2b9dfac5b15f1c3fbe323e9ec1bf13e3f8674ff5f8f1f4f1e3a3fbe7ff9fb1b9d9e3f2973a7efcd8f1e3278e1fbfad70fcf8daf1e3ebc78fe78e1fef8d8fefa58abd2afe4eec460353a9d151e162ea9899607d8ea48988ec01bbe074efb7974df0d59318d06590dcaa95f6aafb1448532f9e9c5b16497adb5940cb268ae95f3c628da6acdd164ae3df54217dec1773276e1d4dcf3d42208fa64c9e262a757a6ccea2a5acb3e294d39566b947fa548d8ae04558115852dc00c2a3b3bc3936718286b1d1abd5945040e11aace715f74a6875ac061cb409918ada0b0fb1b4480458b26b3dd2291ebd84b84c2b0501c13dd281ec351646ac4281cdfb66556a1a98e8962a4eb959717e7affa183d8c86836408934bff209a1e49c9faa3e148eea4d1272d84009b1827a1246714ca01bb39aecd8ed7860122eb778b826f3860012044eb50562e96fe856d967c24dce4acbc538fa25c011fcc4a464034b57a76d525235a70b7bc05a96dfa05e0aa57d32aa9759d0e0a85b77d2fa3746907f8f827dc34d07310ab1aa5510beb03cde2739e061d22f765b69dd2436a916addbacd49c45df0a5434f06ad64aa5468d7a1a17aea27e702d0d77b7f9e3bb8f3ec07c86e9385c5db75d69d66db7211dcbf740d7ea7552ed8e5386392ab5e57b0a3d8d8c8cceb1d2090953dba9379702d2a19e44f94d81e78d9dfaedb382a19d2d8f509a26a28268a99b1ed703ec71a9f03849e41820f5799ac7320431ca9ac24c3fa3b0f288faede80937b643a79120cd7e7d030e4fcfc05872da848e47105236bc090af88e91f14966e6c804fe9bc47f53f86f1affcde0bf3df86f2ffedb87ff6cfc57c27f65fc57c17f30b947aa2327304bf82a0c02057b52d63896052f3df44ddb720be373eefec9893977f7eed135cd87fc860cb0bbc1b3d96aad89d2fcb54d56781de0de6ae567c00d160c4d79661d1b1fb3f2d3277413d49db5bb20c81c732b3e304a8999744ca7d81e488d41a5a3da98b546c2323b92c3380aabce8e788e063c530c313b39330d4826a6f0cfe4ccf8384185f5d8baf0868c79509541e8d323dcd7883fc7f9a3206364d82cc066470b53c3445ea8354b76cd1bd014ac628ba605ec8da3797f3ccabd4eb759bfdbc15e0251da68c1ab4bd321080c3f16b6cd9d76272b75c889c0bf2d4878c7b135c945bb5269d2adac7283afc82174176fcfe0bdc784697a1ce893fa55730cbd23b3953eb36d074b9cb293cefd8236c749cc609898a63ed38f6acbfac7ef1d5860cc9a1dc77fa43af0784eaa959d6663d680cda93964258c3100631e2922e0526d8655265ec152303380923e2c6ea6738cca9f00259862ea17d4003b677449fd6994c9b67a9dc574086e5d8eda84e18d7f3dd358bf924f6a88066fd6c325a160dbb16b87bdc2fe68394bb1c8eb5e74fb69948bc19c8a2901d435f8515c5935426a08428dad87c02e3bbdef60e07c76d1d0926ad238129bd37735942108a90649bf573a916edca6d350ad89a8d59cc642773184a406829beedccff31e1c02a8788bee25068808202450ba7c272b3d59f3d6782280ba05d7ec139c0ee7cad03a54cf2010e08c656e2a467feb965383b65a8b525ddecbbf3ee49844eeb4b184f799b3593a3906ad547156b6858b1aa3e14195ac6e1276b38c288dc18e5aa05674ed4eb6d3aab9d04f0c0066a338a6a60ae65f8c30045e0f6b23a16ec2e3a1e2447d86ea4525ac0ab339563926e804e2eba8527496b2f490108b0e348d8812f86cd5255f7487b835f428cb14beb7aaa60e0c5a269f385c378a37918220c72e0ef997002e7d8b91ab6fa10a6e58027d1efbc64cdf6daf6e275aa62ca4d778ecd464c2d498159a28fb86e814fd5bb7e0662d2f62147940a223acab84b8cd7b1cc7f03165878eaa515e7d5d1fe525998043037790fc9b185e437904380816036dbb775a303862ed9c6283aafbaa874a8f59f566a557c32' ) print(dd.encode_protocol()) uu = hsp.bytedata() uu.decode_protocol(dd.encode_protocol()) print(uu.decode_protocol(dd.encode_protocol())) print(uu.encode_protocol()) print(uu.raw_data) print('test finished')
def handle(self): # override method global REMOTE_SOCKET_COUNT, LOCAL_SOCKET_COUNT try: sock = self.connection sock.settimeout(15) data = sock.recv(4096) LOCAL_SOCKET_COUNT += 1 dec_data = decrypt(data) remote = None addr = None peer_ip, peer_port = sock.getpeername() if peer_ip in black_list or peer_ip not in white_list: # 若已经在黑名单上, 或者不在白名单里, 则直接拒绝代理 logging.warning( f"[Socks5Server]rejected a request from {peer_ip}") raise Exception('illegal packet recvd!') try: obj = hsp.handshake() if obj.decode_protocol(dec_data) != 'Done': raise Exception('illegal packet recvd!') port = int(obj.port) addr = obj.addr except Exception as e: self.refuse_serve() exc_type, exc_obj, exc_tb = sys.exc_info() fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] logging.warning(f"{exc_type} {fname} {exc_tb.tb_lineno}") raise Exception("malformed handshake!") # got all required information try: remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM) remote.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) REMOTE_SOCKET_COUNT += 1 remote.settimeout(20) remote.connect( (addr, port)) # connect to dst, may fail if blocked by gfw # if connect successfully, should sent a random message to unblock the client. send_all( sock, encrypt( hsp.handshake(addr=addr, port=str(port)).encode_protocol())) # do exchange self.handle_tcp(sock, remote, str(addr)) except ConnectionRefusedError: logging.debug('connection refused: ' + str(addr)) except socket.timeout: logging.debug('TimeOut while connecting to: ' + str(addr)) except Exception as e: self.refuse_serve() logging.warning(str(addr)) logging.warning(e) exc_type, exc_obj, exc_tb = sys.exc_info() fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] logging.warning(f"{exc_type} {fname} {exc_tb.tb_lineno}") # send empty message to browser except Exception as e: logging.warning(e) exc_type, exc_obj, exc_tb = sys.exc_info() fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] logging.warning(f"{exc_type} {fname} {exc_tb.tb_lineno}") finally: if sock is not None: sock.close() LOCAL_SOCKET_COUNT -= 1 if remote is not None: remote.close() REMOTE_SOCKET_COUNT -= 1 if addr is not None: logging.info(f'released resource! {addr}')
def handle(self): try: remote = None addr = "" sock = self.connection # local socket [127.1:port] sock.settimeout(15) # follow SOCKS5 protocol sock.recv(262) # Sock5 Verification packet sock.send( b"\x05\x00" ) # Sock5 Response: '0x05' Version 5; '0x00' NO AUTHENTICATION REQUIRED data = sock.recv(65536).strip() if data == b'': return mode = data[1] # CMD == 0x01 (connect) data_to_send = {'type': 'handshake', 'version': 'v1'} if mode != 1: logging.warning('mode != 1') sock.close() return addrtype = data[3] # indicate destination address type ptr = 4 # next to read index if addrtype == 1: # IPv4 ip_range = data[ptr:4 + ptr] addr = socket.inet_ntoa(data[ptr:4 + ptr]) # get dst addr str_addr = addr ptr += 4 elif addrtype == 3: # FQDN (Fully Qualified Domain Name) addr_len = int(data[ptr]) # Domain name's Length ptr += 1 addr = data[ptr:ptr + addr_len] str_addr = addr.decode('utf-8') ptr += addr_len else: # not support logging.warning('addr_type not support') sock.close() return addr_port = data[ptr:2 + ptr] # Parse the big endian port number. Note: The result is a tuple even if it contains exactly one item. port = struct.unpack('>H', addr_port) data_to_send['dst_port'] = port[0] try: if '-6' in sys.argv[1:]: # IPv6 support remote = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) else: remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM) remote.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) # turn off Nagling remote.settimeout(20) # 随机挑选一个REMOTE_PORT 进行连接 dst_port = random.randint( 0, WORKING_THREAD - 1) + 10 + REMOTE_PORT logging.info(f"--------------random port is: {dst_port}") remote.connect((SERVER, dst_port)) # connected to the server, should complete authentication and after the peer has established connection # to host. # then should let browser send other data m = hsp.handshake(addr=str_addr, port=str(port[0])) msg = m.encode_protocol() send_encrypt(remote, msg) # encrypted handshake # 这里会阻塞 confirm_msg = remote.recv(4096) if b'0x15the_login_invalid_or_the_url_unreachable' == confirm_msg: logging.error( 'Error: 1. The url is unreachable for the proxy 2. Or encrypt method mismatch.' ) sock.close() return # tell the browser we are ready to proxy for you. reply = b"\x05\x00\x00\x01" # VER REP RSV ATYP # socks5 protocol needs this. its a must reply += socket.inet_aton('192.168.34.34') + struct.pack( ">H", 1030) self.wfile.write(reply) # response packet logging.info('requested: %s:%d' % (str_addr, port[0])) except ConnectionRefusedError: logging.warning("cannnot talk to server") except socket.error as es: logging.warning(es) exc_type, exc_obj, exc_tb = sys.exc_info() fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] logging.warning(f"{exc_type} {fname} {exc_tb.tb_lineno}") reply = b"\x05\x04\x00\x01" # host unreachable self.wfile.write(reply) # response packet sock.close() return self.handle_tcp(sock, remote, str_addr) except Exception as es: logging.warning(es) exc_type, exc_obj, exc_tb = sys.exc_info() fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] logging.warning(f"{exc_type} {fname} {exc_tb.tb_lineno}") finally: if sock is not None: sock.close() if remote is not None: remote.close() logging.info(f'connection closed.{addr}')
def handle(self): try: sock = self.connection # local socket [127.1:port] # follow SOCKS5 protocol sock.recv(262) # Sock5 Verification packet sock.send(b"\x05\x00") # Sock5 Response: '0x05' Version 5; '0x00' NO AUTHENTICATION REQUIRED data = sock.recv(4096).strip() if data == b'': return mode = data[1] # CMD == 0x01 (connect) data_to_send = {} data_to_send['type'] = 'handshake' data_to_send['version'] = 'v1' if mode != 1: logging.warn('mode != 1') sock.close() return addrtype = data[3] # indicate destination address type ptr = 4 # next to read index if addrtype == 1: # IPv4 ip_range = data[ptr:4+ptr] addr = socket.inet_ntoa(data[ptr:4+ptr]) # get dst addr ptr += 4 data_to_send['dst_addr'] = {'type':'ip', 'addr': addr} elif addrtype == 3: # FQDN (Fully Qualified Domain Name) addr_len = int(data[ptr]) # Domain name's Length ptr += 1 try: addr = data[ptr:ptr+addr_len] except: raise Exception('addr_len too long') ptr += addr_len addr_len = min(addr_len, 255) # in case the url length is too long byte_len_ = bytes([addr_len]) # 0~255 addr = addr.decode('utf-8') # covert url to string data_to_send['dst_addr'] = {'type':'url', 'addr':addr} else: logging.warn('addr_type not support') sock.close() # not support return addr_port = data[ptr: 2+ptr] # addr_to_send += addr_port # addr_to_send = ATYP + [Length] + dst addr/domain name + port port = struct.unpack('>H', addr_port) # prase the big endian port number. Note: The result is a tuple even if it contains exactly one item. data_to_send['dst_port'] = port[0] try: # reply immediately if '-6' in sys.argv[1:]: # IPv6 support remote = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) else: remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM) remote.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) # turn off Nagling remote.connect((SERVER, REMOTE_PORT)) # connected to the server, should complete authentication and after the peer has established connection to host. # then should let browser send other data m = hsp.handshake(addr=addr, port=str(port[0])) msg = m.encode_protocol() self.send_encrypt(remote, msg) # encrypted handshake confirm_msg = remote.recv(4096) if b'0x15the_login_invalid_or_the_url_unreachable' == confirm_msg: logging.error('Error: 1. The url is unreachable for the proxy 2. Or encrypt method mismatch.') sock.close() return # tell the browser we are ready to proxy for you. reply = b"\x05\x00\x00\x01" # VER REP RSV ATYP # socks5 protocol needs this. its a must reply += socket.inet_aton('192.168.34.34') + struct.pack(">H", 1030) self.wfile.write(reply) # response packet logging.info('requested: %s:%d' % (addr, port[0])) except socket.error as e: reply = b"\x05\x04\x00\x01" # host unreachable self.wfile.write(reply) # response packet logging.warn(e) sock.close() return self.handle_tcp(sock, remote) except Exception as e: logging.warn(data) logging.warn(e)