async def send_msg_body(self, msg_body, user: Optional[User] = None, allow_udp=False, f_pro_force=False): assert isinstance(msg_body, bytes), 'msg_body is bytes' # check user existence if len(self.user) == 0: raise PeerToPeerError('there is no user connection') # select random user if user is None: user = random.choice(self.user) # send message if allow_udp and f_pro_force: loop.run_in_executor(None, self.send_udp_body, msg_body, user) elif allow_udp and user.header.p2p_udp_accept and len(msg_body) < 1400: loop.run_in_executor(None, self.send_udp_body, msg_body, user) else: msg_body = zlib.compress(msg_body) msg_body = AESCipher.encrypt(key=user.aeskey, raw=msg_body) msg_len = len(msg_body).to_bytes(4, 'big') send_data = msg_len + msg_body await user.send(send_data) self.traffic.put_traffic_up(send_data) return user
async def send_msg_body(self, msg_body, user: Optional[User] = None, status=200, allow_udp=False, f_pro_force=False): # StatusCode: https://ja.wikipedia.org/wiki/HTTPステータスコード assert isinstance(msg_body, bytes), 'msg_body is bytes' assert 200 <= status < 600, 'Not found status code {}'.format(status) # check user existence if len(self.user) == 0: raise PeerToPeerError('there is no user connection') # select random user if user is None: user = random.choice(self.user) # send message if allow_udp and f_pro_force: self._send_udp_body(msg_body, user) elif allow_udp and user.header.p2p_udp_accept and len(msg_body) < 1400: self._send_udp_body(msg_body, user) else: msg_body = zlib.compress(msg_body) msg_body = AESCipher.encrypt(key=user.aeskey, raw=msg_body) msg_len = len(msg_body).to_bytes(4, 'big') send_data = msg_len + msg_body await user.send(send_data) self.traffic.put_traffic_up(send_data) return user
def _send_udp_body(self, msg_body, user): name_len = len(V.SERVER_NAME.encode()).to_bytes(1, 'big') msg_body = AESCipher.encrypt(key=user.aeskey, raw=msg_body) send_data = name_len + V.SERVER_NAME.encode() + msg_body host_port = user.get_host_port() sock_family = socket.AF_INET if len( host_port) == 2 else socket.AF_INET6 with socket.socket(sock_family, socket.SOCK_DGRAM) as sock: sock.sendto(send_data, host_port) self.traffic.put_traffic_up(send_data)
def _udp_body(self, msg_body, user): name_len = len(V.SERVER_NAME.encode()).to_bytes(1, 'big') msg_body = AESCipher.encrypt(key=user.aeskey, raw=msg_body) send_data = name_len + V.SERVER_NAME.encode() + msg_body host_port = user.get_host_port() if len(host_port) == 2: self.udp_ipv4_sock.sendto(send_data, host_port) else: self.udp_ipv6_sock.sendto(send_data, host_port) self.traffic.put_traffic_up(send_data)
def send_udp_body(self, msg_body, user): """send UDP message""" name_len = len(V.SERVER_NAME.encode()).to_bytes(1, 'big') msg_body = AESCipher.encrypt(key=user.aeskey, raw=msg_body) send_data = name_len + V.SERVER_NAME.encode() + msg_body host_port = user.get_host_port() sock_family = socket.AF_INET if len( host_port) == 2 else socket.AF_INET6 # warning: may block this closure, use run_in_executor with socket.socket(sock_family, socket.SOCK_DGRAM) as sock: sock.sendto(send_data, host_port) self.traffic.put_traffic_up(send_data)
def send_msg_body(self, msg_body, user=None, status=200, f_udp=False, f_pro_force=False): # StatusCode: https://ja.wikipedia.org/wiki/HTTPステータスコード assert type(msg_body) == bytes, 'msg_body is bytes' assert 200 <= status < 600, 'Not found status code {}'.format(status) # get client if len(self.user) == 0: raise ConnectionError('client connection is zero.') elif len(msg_body) > C.MAX_RECEIVE_SIZE + 5000: error = 'Max message size is {}kb (You try {}Kb)'.format( round(C.MAX_RECEIVE_SIZE / 1000000, 3), round(len(msg_body) / 1000000, 3)) self.send_msg_body(msg_body=bjson.dumps(error), user=user, status=500) raise ConnectionRefusedError(error) elif user is None: user = random.choice(self.user) # send message if f_udp and f_pro_force: self._udp_body(msg_body, user) elif f_udp and user.p2p_udp_accept and len(msg_body) < 1400: self._udp_body(msg_body, user) else: msg_body = zlib.compress(msg_body) msg_body = AESCipher.encrypt(key=user.aeskey, raw=msg_body) msg_len = len(msg_body).to_bytes(4, 'big') send_data = msg_len + msg_body user.send(send_data) self.traffic.put_traffic_up(send_data) # logging.debug("Send {}Kb to '{}'".format(len(msg_len+msg_body) / 1000, user.name)) return user
async def initial_connection_check(self, reader: StreamReader, writer: StreamWriter): host_port = writer.get_extra_info('peername') new_user: Optional[User] = None try: # 1. send plain message writer.write(b'hello') await writer.drain() # 2. receive other's header try: received = await asyncio.wait_for(reader.read(BUFFER_SIZE), 5.0) if len(received) == 0: raise PeerToPeerError('empty msg receive') header = json.loads(received.decode()) except asyncio.TimeoutError: raise PeerToPeerError('timeout on other\'s header receive') except json.JSONDecodeError: raise PeerToPeerError( 'json decode error on other\'s header receive') # 3. generate new user user_header = UserHeader(**header) new_user = User(user_header, self.number, reader, writer, host_port, AESCipher.create_key(), SERVER_SIDE) self.number += 1 if new_user.header.name == V.SERVER_NAME: raise ConnectionAbortedError('Same origin connection') # 4. send my public key my_sec, my_pub = generate_keypair() send = json.dumps({'public-key': my_pub}).encode() await new_user.send(send) self.traffic.put_traffic_up(send) # 5. receive public key try: receive = await new_user.recv() self.traffic.put_traffic_down(receive) if len(receive) == 0: raise ConnectionAbortedError('received msg is zero.') data = json.loads(receive.decode()) except asyncio.TimeoutError: raise PeerToPeerError('timeout on public key receive') except json.JSONDecodeError: raise PeerToPeerError( 'json decode error on public key receive') # 6. encrypt and send AES key and header send = json.dumps({ 'aes-key': new_user.aeskey, 'header': self.get_server_header(), }) key = generate_shared_key(my_sec, data['public-key']) encrypted = AESCipher.encrypt(key, send.encode()) await new_user.send(encrypted) self.traffic.put_traffic_up(encrypted) # 7. receive accept signal try: encrypted = await new_user.recv() self.traffic.put_traffic_down(encrypted) except asyncio.TimeoutError: raise PeerToPeerError('timeout on accept signal receive') receive = AESCipher.decrypt(new_user.aeskey, encrypted) if receive != b'accept': raise PeerToPeerError(f"Not accept signal! {receive}") # 8. accept connection log.info( f"established connection as server from {new_user.header.name} {new_user.get_host_port()}" ) asyncio.ensure_future(self.receive_loop(new_user)) # server port's reachable check await asyncio.sleep(1.0) await self.check_reachable(new_user) return except (ConnectionAbortedError, ConnectionResetError) as e: msg = f"disconnect error {host_port} {e}" except PeerToPeerError as e: msg = f"peer2peer error {host_port} {e}" except Exception as e: msg = "InitialConnCheck: {}".format(e) log.error(msg, exc_info=True) # EXCEPTION! if new_user: # remove user self.remove_connection(new_user, msg) else: # close socket log.debug(msg) try: writer.write(msg.encode()) await writer.drain() except Exception: pass try: writer.close() except Exception: pass
async def create_connection(self, host, port): for res in socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket.SOCK_STREAM): af, socktype, proto, canonname, host_port = res if host_port[0] in ban_address: return False # baned address try: if V.TOR_CONNECTION: if af != socket.AF_INET: continue sock = socks.socksocket() sock.setproxy(socks.PROXY_TYPE_SOCKS5, V.TOR_CONNECTION[0], V.TOR_CONNECTION[1]) else: sock = socket.socket(af, socktype, proto) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.connect(host_port) sock.setblocking(False) reader, writer = await asyncio.open_connection(sock=sock, loop=loop) break except ConnectionRefusedError: continue # try to connect closed socket except OSError as e: log.debug(f"socket creation error by {str(e)}") continue else: # create no connection return False log.debug(f"success create connection to {host_port}") try: # 1. receive plain message try: msg = await asyncio.wait_for(reader.read(BUFFER_SIZE), 5.0) if msg != b'hello': raise PeerToPeerError( 'first plain msg not correct? {}'.format(msg)) except asyncio.TimeoutError: raise PeerToPeerError('timeout on first plain msg receive') # 2. send my header send = json.dumps(self.get_server_header()).encode() writer.write(send) await writer.drain() self.traffic.put_traffic_up(send) # 3. receive public key try: my_sec, my_pub = generate_keypair() receive = await asyncio.wait_for(reader.read(BUFFER_SIZE), 5.0) self.traffic.put_traffic_down(receive) msg = json.loads(receive.decode()) except asyncio.TimeoutError: raise PeerToPeerError('timeout on public key receive') except json.JSONDecodeError: raise PeerToPeerError( 'json decode error on public key receive') # 4. send public key send = json.dumps({'public-key': my_pub}).encode() writer.write(send) await writer.drain() self.traffic.put_traffic_up(send) # 5. Get AES key and header and decrypt try: receive = await asyncio.wait_for(reader.read(BUFFER_SIZE), 5.0) self.traffic.put_traffic_down(receive) key = generate_shared_key(my_sec, msg['public-key']) dec = AESCipher.decrypt(key, receive) data = json.loads(dec.decode()) except asyncio.TimeoutError: raise PeerToPeerError('timeout on AES key and header receive') except json.JSONDecodeError: raise PeerToPeerError( 'json decode error on AES key and header receive') aeskey, header = data['aes-key'], data['header'] # 6. generate new user user_header = UserHeader(**header) new_user = User(user_header, self.number, reader, writer, host_port, aeskey, CLIENT_SIDE) # 7. check header if new_user.header.network_ver != V.NETWORK_VER: raise PeerToPeerError( 'Don\'t same network version [{}!={}]'.format( new_user.header.network_ver, V.NETWORK_VER)) self.number += 1 # 8. send accept signal encrypted = AESCipher.encrypt(new_user.aeskey, b'accept') await new_user.send(encrypted) self.traffic.put_traffic_up(encrypted) # 9. accept connection log.info( f"established connection as client to {new_user.header.name} {new_user.get_host_port()}" ) asyncio.ensure_future(self.receive_loop(new_user)) # server port's reachable check await asyncio.sleep(1.0) await self.check_reachable(new_user) return True except PeerToPeerError as e: msg = "peer2peer error, {} ({})".format(e, host) except ConnectionRefusedError as e: msg = "connection refused error, {} ({})".format(e, host) except ValueError as e: msg = "ValueError: {} {}".format(host, e) except Exception as e: log.error("NewConnectionError", exc_info=True) msg = "NewConnectionError {} {}".format(host, e) # close socket log.debug(msg) if not writer.transport.is_closing(): writer.close() return False
def create_connection(self, host, port): sock = host_port = None try: for res in socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket.SOCK_STREAM): af, socktype, proto, canonname, host_port = res if host_port[0] in ban_address: return False # baned address try: sock = socket.socket(af, socktype, proto) except OSError: continue sock.settimeout(10) # Connection try: sock.connect(host_port) break except OSError: sock.close() continue else: # create no connection return False logging.debug("Success connection create to {}".format(host_port)) # ヘッダーを送る send = json.dumps(self.get_server_header()).encode() sock.sendall(send) self.traffic.put_traffic_up(send) # 公開鍵を受取る receive = sock.recv(self.buffsize) self.traffic.put_traffic_down(receive) public_key = json.loads(receive.decode())['public-key'] # 公開鍵を送る send = json.dumps({'public-key': self.ecc.pk}).encode() sock.sendall(send) self.traffic.put_traffic_up(send) # AESKEYとヘッダーを取得し復号化する receive = sock.recv(self.buffsize) self.traffic.put_traffic_down(receive) data = json.loads( self.ecc.decrypt(sender_pk=public_key, enc=receive).decode()) aeskey, header = data['aes-key'], data['header'] logging.debug("Success ase-key receive {}".format(host_port)) # ユーザーを作成する with self.lock: new_user = User(self.number, sock, host_port, aeskey, C.T_CLIENT) new_user.deserialize(header) # headerのチェック if new_user.network_ver != V.NETWORK_VER: raise PeerToPeerError( 'Don\'t same network version [{}!={}]'.format( new_user.network_ver, V.NETWORK_VER)) self.number += 1 # Acceptシグナルを送る encrypted = AESCipher.encrypt(new_user.aeskey, b'accept') sock.sendall(encrypted) self.traffic.put_traffic_up(encrypted) logging.info("New connection to \"{}\" {}".format( new_user.name, new_user.get_host_port())) Thread(target=self._receive_msg, name='C:' + new_user.name, args=(new_user, ), daemon=True).start() c = 20 while new_user not in self.user and c > 0: sleep(1) c -= 1 self.is_reachable(new_user) if c == 0: return False else: return True except json.JSONDecodeError: error = "Json decode error." except PeerToPeerError as e: error = "NewConnectionError {} {}".format(host_port, e) except ConnectionRefusedError as e: error = "ConnectionRefusedError {} {}".format(host_port, e) except Exception as e: error = "NewConnectionError {} {}".format(host_port, e) # close socket logging.debug(error) try: sock.sendall(error.encode()) except: pass try: sock.shutdown(socket.SHUT_RDWR) except: pass try: sock.close() except: pass return False