Exemple #1
0
 def udp_server_listen(server_sock, mask):
     try:
         msg, address = server_sock.recvfrom(8192)
         msg_len = msg[0]
         msg_name, msg_body = msg[1:msg_len + 1], msg[msg_len + 1:]
         user = self.name2user(msg_name.decode())
         if user is None or not user.p2p_udp_accept:
             return
         self.traffic.put_traffic_down(msg_body)
         msg_body = AESCipher.decrypt(key=user.aeskey, enc=msg_body)
         if msg_body == b'Ping':
             logging.debug("Get udp accept from {}".format(user))
             self.send_msg_body(msg_body=b'Pong', user=user)
         else:
             logging.debug("Get udp packet from {}".format(user))
             self.core_que.broadcast((user, msg_body))
     except OSError as e:
         logging.debug("OSError {}".format(e))
     except Exception as e:
         logging.debug(e, exc_info=Debug.P_EXCEPTION)
Exemple #2
0
async def udp_server_handle(msg, addr, core: Core):
    msg_body = None
    try:
        msg_len = msg[0]
        msg_name, msg_body = msg[1:msg_len + 1], msg[msg_len + 1:]
        user = core.name2user(msg_name.decode())
        if user is None:
            return
        core.traffic.put_traffic_down(msg_body)
        msg_body = AESCipher.decrypt(key=user.aeskey, enc=msg_body)
        if msg_body == b'Ping':
            log.info(f"get udp ping from {user.header.name} addr:{addr}")
            await core.send_msg_body(msg_body=b'Pong', user=user)
        else:
            log.debug(f"get udp packet from {user.header.name} addr:{addr}")
            await core.core_que.put((user, msg_body))
    except ValueError as e:
        log.debug(f"maybe decrypt failed by {e} {msg_body}")
    except OSError as e:
        log.debug(f"OSError on udp listen by {str(e)}")
    except Exception as e:
        log.debug("UDP handle exception", exc_info=Debug.P_PRINT_EXCEPTION)
Exemple #3
0
    async def receive_loop(self, user: User):
        # Accept connection
        for check_user in self.user.copy():
            if check_user.header.name != user.header.name:
                continue
            elif await self.ping(check_user):
                error = f"same origin found and ping success, remove new connection"
                self.remove_connection(user, error)
                return
            else:
                error = f"same origin found but ping failed, remove old connection"
                self.remove_connection(check_user, error)
        self.user.append(user)
        log.info(f"check success and go into loop {user}")

        bio = BytesIO(
        )  # Warning: don't use initial_bytes, same duplicate ID used?
        bio_length = 0
        msg_length = 0
        f_raise_timeout = False
        error = None
        while not self.f_stop:
            try:
                get_msg = await user.recv()
                if len(get_msg) == 0:
                    error = "Fall in loop, socket closed."
                    break

                # check message params init
                bio_length += bio.write(get_msg)
                if msg_length == 0:
                    # init message params
                    msg_bytes = bio.getvalue()
                    msg_length, initial_bytes = int.from_bytes(
                        msg_bytes[:4], 'big'), msg_bytes[4:]
                    bio.truncate(0)
                    bio.seek(0)
                    bio_length = bio.write(initial_bytes)
                elif bio_length == 0:
                    error = "Why bio_length is zero?, msg_length={}".format(
                        msg_length, bio_length)
                    break
                else:
                    pass

                # check complete message receive
                if bio_length >= msg_length:
                    # success, get all message
                    msg_bytes = bio.getvalue()
                    msg_body, initial_bytes = msg_bytes[:
                                                        msg_length], msg_bytes[
                                                            msg_length:]
                    if len(initial_bytes) == 0:
                        # no another message
                        msg_length = 0
                        f_raise_timeout = False
                    elif len(initial_bytes) < 4:
                        error = "Failed to get message length? {}".format(
                            initial_bytes)
                        break
                    else:
                        # another message pushing
                        msg_length, initial_bytes = int.from_bytes(
                            initial_bytes[:4], 'big'), initial_bytes[4:]
                        f_raise_timeout = True
                    bio.truncate(0)
                    bio.seek(0)
                    bio_length = bio.write(initial_bytes)
                else:
                    # continue getting message
                    f_raise_timeout = True
                    continue

                # continue to process msg_body
                self.traffic.put_traffic_down(msg_body)
                msg_body = AESCipher.decrypt(key=user.aeskey, enc=msg_body)
                msg_body = zlib.decompress(msg_body)
                if msg_body == b'Ping':
                    log.debug(f"receive Ping from {user.header.name}")
                    await self.send_msg_body(b'Pong', user)
                elif msg_body == b'Pong':
                    log.debug(f"receive Pong from {user.header.name}")
                    self._ping.set()
                else:
                    await self.core_que.put((user, msg_body))
                f_raise_timeout = False

            except asyncio.TimeoutError:
                if f_raise_timeout:
                    error = "Timeout: Not allowed timeout when getting message!"
                    break
            except ConnectionError as e:
                error = "ConnectionError: " + str(e)
                break
            except OSError as e:
                error = "OSError: " + str(e)
                break
            except Exception:
                import traceback
                error = "Exception: " + str(traceback.format_exc())
                break

        # After exit from loop, close socket
        if not bio.closed:
            bio.close()
        self.remove_connection(user, error)
Exemple #4
0
    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
Exemple #5
0
    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
Exemple #6
0
    def _receive_msg(self, user):
        # Accept connection
        with self.lock:
            for check_user in self.user:
                if check_user.name != user.name:
                    continue
                if self.ping(check_user):
                    error = "Remove new connection {}, continue connect {}".format(
                        user, check_user)
                    self.remove_connection(user, error)
                    logging.info(error)
                else:
                    error = "Same origin, Replace new connection {} => {}".format(
                        check_user, user)
                    self.remove_connection(check_user, error)
                    logging.info(error)
            self.user.append(user)
        logging.info("Accept connection \"{}\"".format(user.name))

        # pooling
        msg_prefix = b''
        msg_len = 0
        msg_body = b''
        error = None
        try:
            while not self.f_stop:
                if len(msg_prefix) == 0:
                    user.sock.settimeout(3600)
                    first_msg = user.sock.recv(self.buffsize)
                    user.sock.settimeout(10)
                else:
                    first_msg, msg_prefix = msg_prefix, b''

                # Start receive message
                msg_len = int.from_bytes(first_msg[:4], 'big')
                msg_body = first_msg[4:]

                # Notice long message
                if Debug.F_LONG_MSG_INFO and msg_len != len(msg_body):
                    logging.debug("Receive long msg, len=%d, body=%d" %
                                  (msg_len, len(msg_body)))

                if msg_len == 0:
                    raise ConnectionAbortedError(
                        "1:Socket error, fall in loop.")
                elif len(msg_body) == 0:
                    raise ConnectionAbortedError(
                        "2:Socket error, fall in loop.")
                elif len(msg_body) >= msg_len:
                    msg_body, msg_prefix = msg_body[:msg_len], msg_body[
                        msg_len:]
                    self.traffic.put_traffic_down(msg_body)
                    msg_body = AESCipher.decrypt(key=user.aeskey, enc=msg_body)
                    msg_body = zlib.decompress(msg_body)
                    if msg_body == b'Ping':
                        logging.debug("receive ping from {}".format(user.name))
                        self.send_msg_body(b'Pong', user)
                        continue
                    elif msg_body == b'Pong':
                        logging.debug("receive Pong from {}".format(user.name))
                        self._ping.set()
                        continue
                    else:
                        self.core_que.broadcast((user, msg_body))
                    continue

                # continue receiving message
                while True:
                    new_body = user.sock.recv(self.buffsize)
                    msg_body += new_body
                    if len(new_body) == 0:
                        raise ConnectionAbortedError(
                            "3:Socket error, fall in loop.")
                    elif len(msg_body) >= msg_len:
                        msg_body, msg_prefix = msg_body[:msg_len], msg_body[
                            msg_len:]
                        self.traffic.put_traffic_down(msg_body)
                        msg_body = AESCipher.decrypt(key=user.aeskey,
                                                     enc=msg_body)
                        msg_body = zlib.decompress(msg_body)
                        self.core_que.broadcast((user, msg_body))
                        break
                    elif len(msg_body) > C.MAX_RECEIVE_SIZE + 5000:
                        raise ConnectionAbortedError(
                            "Too many data! (MAX {}Kb)".format(
                                C.MAX_RECEIVE_SIZE // 1000))
                    else:
                        continue

        except socket.timeout:
            error = "socket timeout {}".format(user.name)
            logging.debug(error)
        except ConnectionAbortedError as e:
            error = "ConnectionAbortedError :len={}, msg={} e={}".format(
                msg_len, msg_body, e)
        except ConnectionResetError:
            error = "ConnectionResetError by {}".format(user.name)
        except OSError as e:
            error = "OSError by {}, {}".format(user.name, e)
        except Exception as e:
            error = "BaseException by {}, {}".format(user.name, e)

        # raised exception on loop
        logging.debug(error)
        if not self.remove_connection(user, error):
            logging.debug("Failed remove user {}".format(user.name))
Exemple #7
0
 def _initial_connection_check(self, sock, host_port):
     sock.settimeout(10)
     try:
         # ヘッダーを受取る
         received = sock.recv(self.buffsize)
         if len(received) == 0:
             raise ConnectionAbortedError('zero msg, connection closed.')
         self.traffic.put_traffic_down(received)
         header = json.loads(received.decode())
         with self.lock:
             new_user = User(self.number,
                             sock,
                             host_port,
                             aeskey=AESCipher.create_key(),
                             sock_type=C.T_SERVER)
             self.number += 1
         new_user.deserialize(header)
         if new_user.name == V.SERVER_NAME:
             raise ConnectionAbortedError('Same origin connection.')
         # こちらの公開鍵を送る
         send = json.dumps({'public-key': self.ecc.pk}).encode()
         sock.sendall(send)
         self.traffic.put_traffic_up(send)
         # 公開鍵を取得する
         receive = new_user.sock.recv(self.buffsize)
         self.traffic.put_traffic_down(receive)
         if len(receive) == 0:
             raise ConnectionAbortedError('received msg is zero.')
         public_key = json.loads(receive.decode())['public-key']
         # AESKEYとHeaderを暗号化して送る
         encrypted = self.ecc.encrypt(recipient_pk=public_key,
                                      msg=json.dumps({
                                          'aes-key':
                                          new_user.aeskey,
                                          'header':
                                          self.get_server_header()
                                      }).encode(),
                                      encode='raw')
         new_user.send(encrypted)
         self.traffic.put_traffic_up(encrypted)
         # Accept信号を受け取る
         encrypted = new_user.sock.recv(self.buffsize)
         self.traffic.put_traffic_down(encrypted)
         receive = AESCipher.decrypt(new_user.aeskey, encrypted)
         if receive != b'accept':
             raise ConnectionAbortedError('Not accept signal.')
         # Accept connection
         logging.info("New connection from \"{}\" {}".format(
             new_user.name, new_user.get_host_port()))
         Thread(target=self._receive_msg,
                name='S:' + new_user.name,
                args=(new_user, ),
                daemon=True).start()
         # Port accept check
         sleep(10)
         if new_user in self.user:
             self.is_reachable(new_user)
         return
     except ConnectionAbortedError as e:
         error = "ConnectionAbortedError, {}".format(e)
     except json.decoder.JSONDecodeError as e:
         error = "JSONDecodeError, {}".format(e)
     except socket.timeout:
         error = "socket.timeout"
     except Exception as e:
         error = "Exception as {}".format(e)
     # close socket
     error = "Close on initial check " + error
     logging.debug(error)
     try:
         sock.sendall(error.encode())
     except:
         pass
     try:
         sock.close()
     except:
         pass