Exemple #1
0
    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
Exemple #2
0
    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
Exemple #3
0
 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)
Exemple #4
0
 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)
Exemple #5
0
 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)
Exemple #6
0
    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
Exemple #7
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 #8
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 #9
0
    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