Exemplo n.º 1
0
Arquivo: onion.py Projeto: dimwap/tfc
def monitor_queues(tor: Tor, response: Any, queues: 'QueueDict') -> None:
    """Monitor queues for incoming packets."""
    while True:
        try:
            time.sleep(0.1)

            if queues[ONION_KEY_QUEUE].qsize() > 0:
                _, c_code = queues[ONION_KEY_QUEUE].get()

                m_print([
                    "Onion Service is already running.", '',
                    f"Onion Service confirmation code (to Transmitter): {c_code.hex()}"
                ],
                        box=True)

            if queues[ONION_CLOSE_QUEUE].qsize() > 0:
                command = queues[ONION_CLOSE_QUEUE].get()
                if not platform_is_tails(
                ) and command == EXIT and tor.controller is not None:
                    tor.controller.remove_hidden_service(response.service_id)
                    tor.stop()
                queues[EXIT_QUEUE].put(command)
                time.sleep(5)
                break

        except (EOFError, KeyboardInterrupt):
            pass
        except stem.SocketClosed:
            if tor.controller is not None:
                tor.controller.remove_hidden_service(response.service_id)
                tor.stop()
            break
Exemplo n.º 2
0
Arquivo: onion.py Projeto: dimwap/tfc
    def connect(self, port: int) -> None:
        """Launch Tor as a subprocess.

        If TFC is running on top of Tails, do not launch a separate
        instance of Tor.
        """
        if platform_is_tails():
            self.controller = Controller.from_port(port=TOR_CONTROL_PORT)
            self.controller.authenticate()
            return None

        tor_data_directory = tempfile.TemporaryDirectory()
        tor_control_socket = os.path.join(tor_data_directory.name,
                                          'control_socket')

        if not os.path.isfile('/usr/bin/tor'):
            raise CriticalError("Check that Tor is installed.")

        self.launch_tor_process(port, tor_control_socket, tor_data_directory)

        start_ts = time.monotonic()
        self.controller = stem.control.Controller.from_socket_file(
            path=tor_control_socket)
        self.controller.authenticate()

        while True:
            time.sleep(0.1)

            try:
                response = self.controller.get_info("status/bootstrap-phase")
            except stem.SocketClosed:
                raise CriticalError("Tor socket closed.")

            res_parts = shlex.split(response)
            summary = res_parts[4].split('=')[1]

            if summary == 'Done':
                tor_version = self.controller.get_version().version_str.split(
                    ' (')[0]
                rp_print(f"Setup  70% - Tor {tor_version} is now running",
                         bold=True)
                break

            if time.monotonic() - start_ts > 15:
                start_ts = time.monotonic()
                self.controller = stem.control.Controller.from_socket_file(
                    path=tor_control_socket)
                self.controller.authenticate()
Exemplo n.º 3
0
Arquivo: onion.py Projeto: dimwap/tfc
def get_available_port(min_port: int, max_port: int) -> int:
    """Find a random available port within the given range."""
    sys_rand = random.SystemRandom()

    with socket.socket() as temp_sock:
        while True:
            try:
                temp_sock.bind(
                    ('127.0.0.1', sys_rand.randint(min_port, max_port)))
                break
            except OSError:
                pass
        _, port = temp_sock.getsockname()  # type: str, int

    if platform_is_tails():
        return TOR_SOCKS_PORT

    return port
Exemplo n.º 4
0
Arquivo: relay.py Projeto: dimwap/tfc
def main() -> None:
    """Load persistent settings and launch the Relay Program.

    This function loads settings from the settings database and launches
    processes for the Relay Program. It then monitors the EXIT_QUEUE for
    EXIT/WIPE signals and each process in case one of them dies.

    If you're reading this code to get the big picture on how TFC works,
    start by looking at `tfc.py` for Transmitter Program functionality.
    After you have reviewed the Transmitter Program's code, revisit the
    code of this program.

    The Relay Program operates multiple processes to enable real time IO
    between multiple data sources and destinations.

    Symbols:
        process_name    denotes the name of the process

        ─>, <─, ↑, ↓    denotes the direction of data passed from one
                        process to another

        (Description)   denotes the description of data passed from one
                        process to another

        ┈, ┊            denotes the link between a description and path
                        of data matching the description

        ▶|, |◀          denotes the gateways where the direction of data
                        flow is enforced with hardware data diodes


                                         Relay Program (Networked Computer)
                    ┏━━  ━━  ━━  ━━  ━━  ━━  ━━  ━━  ━━  ━━  ━━  ━━  ━━  ━━  ━━  ━━  ━━  ━━  ━━┓
                    ┃                  (1: Onion Service private key)                          ┃
                                       (2: Contact management commands)
                    ┃  ┌──────────────────────────────┬────────────────────────┬────────────┐  ┃
                       │                              │                        ↓┈2          │
                    ┃  │                    ┌─────> relay_command  ┌───> c_req_manager      │  ┃
                       │                    │                  │   │                        │
                    ┃  │     (Relay Program┈│   (Onion Service┈│   │                        │  ┃
                       │      commands)     │    public key)   │   │┈(In: Contact requests) │
                    ┃  │                    │                  ↓   │       ┊              1┈↓  ┃
      Source ───▶|─────(── gateway_loop ─> src_incoming ─> flask_server <─────> onion_service <───> client on contact's
    Computer        ┃  │                            │              ↑       ┊                   ┃     Networked Computer
                       │   (Local keys, commands,   │              │ (Out: msg/file/pubkey/
                    ┃  │    and copies of messages)┄│              │  group mgmt message)      ┃
                       │                            │              │
                    ┃  │                            ↓              │                           ┃
 Destination <──|◀─────(────────────────────── dst_outgoing        │
    Computer        ┃  │                    ┊       ↑              │                           ┃
                       ├──> g_msg_manager   ┊       │              │
                    ┃  │               ↑    ┊       │              │                           ┃
                       │        (Group┈│  (Incoming┈│  (URL token)┈│
                    ┃  │    management │  messages) │              │                           ┃
                       │     messages) │            │              │
                    ┃  ↓┈1,2           │            │              │                           ┃
                      client_scheduler │            │              │
                    ┃         └──> client ──────────┴──────────────┘                           ┃
                                     ↑
                    ┃                │                                                         ┃
                                     └───────────────────────────────────────────────────────────> flask_server on
                    ┃                                        ┊                                 ┃   contact's Networked
                                (In: message/file/public key/group management message              Computer
                    ┃            Out: contact request)                                         ┃
                    ┗━━  ━━  ━━  ━━  ━━  ━━  ━━  ━━  ━━  ━━  ━━  ━━  ━━  ━━  ━━  ━━  ━━  ━━  ━━┛


    The diagram above gives a rough overview of the structure of the
    Relay Program. The Relay Program acts as a protocol converter that
    reads datagrams from the Source Computer. Outgoing
    message/file/public key datagrams are made available in the user's
    Tor v3 Onion Service. Copies of sent message datagrams as well as
    datagrams from contacts' Onion Services are forwarded to the
    Destination Computer. The Relay-to-Relay encrypted datagrams from
    contacts such as contact requests, public keys and group management
    messages are displayed by the Relay Program.

    Outgoing message datagrams are loaded by contacts from the user's
    Flask web server. To request messages intended for them, each
    contact uses a contact-specific URL token to load the messages.
    The URL token is the X448 shared secret derived from the per-session
    ephemeral X448 values of the two conversing parties. The private
    value stays on the Relay Program -- the public value is obtained by
    connecting to the root domain of contact's Onion Service.
    """
    if platform_is_tails():
        working_dir = f'{os.getenv("HOME")}/{DIR_TAILS_PERS}{DIR_TFC}'
    else:
        working_dir = f'{os.getenv("HOME")}/{DIR_TFC}'

    ensure_dir(working_dir)
    os.chdir(working_dir)

    _, local_test, data_diode_sockets, qubes = process_arguments()

    gateway = Gateway(NC, local_test, data_diode_sockets, qubes)

    print_title(NC)

    url_token_private_key = X448.generate_private_key()
    url_token_public_key = X448.derive_public_key(url_token_private_key).hex()

    queues = \
        {GATEWAY_QUEUE:       Queue(),  # All     datagrams           from `gateway_loop`          to `src_incoming`
         DST_MESSAGE_QUEUE:   Queue(),  # Message datagrams           from `src_incoming`/`client` to `dst_outgoing`
         TX_BUF_KEY_QUEUE:    Queue(),  # Datagram buffer key         from `onion_service`         to `src_incoming`
         RX_BUF_KEY_QUEUE:    Queue(),  # Datagram buffer key         from `onion_service`         to `flask_server`
         SRC_TO_RELAY_QUEUE:  Queue(),  # Command datagrams           from `src_incoming`          to `relay_command`
         DST_COMMAND_QUEUE:   Queue(),  # Command datagrams           from `src_incoming`          to `dst_outgoing`
         CONTACT_MGMT_QUEUE:  Queue(),  # Contact management commands from `relay_command`         to `client_scheduler`
         C_REQ_STATE_QUEUE:   Queue(),  # Contact req. notify setting from `relay_command`         to `c_req_manager`
         URL_TOKEN_QUEUE:     Queue(),  # URL tokens                  from `client`                to `flask_server`
         GROUP_MSG_QUEUE:     Queue(),  # Group management messages   from `client`                to `g_msg_manager`
         CONTACT_REQ_QUEUE:   Queue(),  # Contact requests            from `flask_server`          to `c_req_manager`
         C_REQ_MGMT_QUEUE:    Queue(),  # Contact list management     from `relay_command`         to `c_req_manager`
         GROUP_MGMT_QUEUE:    Queue(),  # Contact list management     from `relay_command`         to `g_msg_manager`
         ONION_CLOSE_QUEUE:   Queue(),  # Onion Service close command from `relay_command`         to `onion_service`
         ONION_KEY_QUEUE:     Queue(),  # Onion Service private key   from `relay_command`         to `onion_service`
         TOR_DATA_QUEUE:      Queue(),  # Open port for Tor           from `onion_service`         to `client_scheduler`
         EXIT_QUEUE:          Queue(),  # EXIT/WIPE signal            from `relay_command`         to `main`
         ACCOUNT_CHECK_QUEUE: Queue(),  # Incorrectly typed accounts  from `src_incoming`          to `account_checker`
         ACCOUNT_SEND_QUEUE:  Queue(),  # Contact requests            from `flask_server`          to `account_checker`
         USER_ACCOUNT_QUEUE:  Queue(),  # User's public key           from `onion_service`         to `account_checker`
         PUB_KEY_CHECK_QUEUE: Queue(),  # Typed public keys           from `src_incoming`          to `pub_key_checker`
         PUB_KEY_SEND_QUEUE:  Queue(),  # Received public keys        from `client`                to `pub_key_checker`
         GUI_INPUT_QUEUE:     Queue()  # User inputs                 from `GUI prompt`            to `account_checker`
         }  # type: Dict[bytes, Queue[Any]]

    process_list = [
        Process(target=gateway_loop, args=(queues, gateway)),
        Process(target=src_incoming, args=(queues, gateway)),
        Process(target=dst_outgoing, args=(queues, gateway)),
        Process(target=client_scheduler,
                args=(queues, gateway, url_token_private_key)),
        Process(target=g_msg_manager, args=(queues, )),
        Process(target=c_req_manager, args=(queues, )),
        Process(target=flask_server, args=(queues, url_token_public_key)),
        Process(target=onion_service, args=(queues, )),
        Process(target=relay_command, args=(
            queues,
            gateway,
        )),
        Process(target=account_checker, args=(queues, sys.stdin.fileno())),
        Process(target=pub_key_checker, args=(queues, local_test))
    ]

    for p in process_list:
        p.start()

    monitor_processes(process_list, NC, queues)