# sbaresearch/scanywhere architecture

> Architecture diagram of the GitHub repository sbaresearch/scanywhere, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-11-11). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/sbaresearch/scanywhere
- Repository: https://github.com/sbaresearch/scanywhere

## Overview

Scanywhere repeatedly launches measurement containers through selected VPN endpoints, optionally adding a Cloudflare Warp hop, and stores experiment outputs in mounted result directories. Its main controller also supports Tor and ephemeral AWS WireGuard endpoints; helper modules provide Tor relay and hide.me server selection. The documented experiments cover IP connectivity, VoWiFi domain resolution, and ePDG scanning. The sampled source shows orchestration and experiment behavior, but not all container networking or scan internals, so those links are limited to documented or directly visible relationships.

Main entry points: [`scanywhere.py`](https://github.com/sbaresearch/scanywhere/blob/main/scanywhere.py) (Scanywhere CLI), [`docker/vowifi-geoblocking-resolve-domains/resolve_domains.py`](https://github.com/sbaresearch/scanywhere/blob/main/docker/vowifi-geoblocking-resolve-domains/resolve_domains.py) (Mass GeoDNS Resolution), [`docker/check-ip-connectivity/main.py`](https://github.com/sbaresearch/scanywhere/blob/main/docker/check-ip-connectivity/main.py) (IP Connectivity Check), [`utils/ec2_manager.py`](https://github.com/sbaresearch/scanywhere/blob/main/utils/ec2_manager.py) (EC2 WireGuard)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_orchestration["Orchestration"]
  node_controller["Scanywhere CLI<br/>[scanywhere.py]"]
  node_docker["Docker Engine"]
end

subgraph group_tunnels["VPN Tunnels"]
  node_gluetun["Gluetun VPN"]
  node_warp["Cloudflare Warp"]
  node_tor["Tor Relay Selection<br/>[tor_utils.py]"]
  node_hideme["hide.me Servers<br/>[hideme.py]"]
end

subgraph group_experiments["Measurements"]
  node_connectivity["IP Connectivity Check<br/>[main.py]"]
  node_iputils["IP Address Utilities<br/>[ip_utils.py]"]
  node_results[("Experiment Results")]
end

subgraph group_vowifi["VoWiFi Study"]
  node_resolver["Mass GeoDNS Resolution<br/>[resolve_domains.py]"]
  node_massdns["MassDNS"]
  node_unbound["DNS Resolver List<br/>[local_unbound.txt]"]
  node_epdgscan["ePDG IKE Scanner<br/>[main.py]"]
end

subgraph group_cloud["Cloud Support"]
  node_ec2manager["EC2 WireGuard<br/>[ec2_manager.py]"]
  node_aws["AWS EC2"]
  node_deadman["Deadman Switch<br/>[deadman_switch.sh]"]
end

node_operator(("Operator"))

node_operator -->|"runs"| node_controller
node_controller -->|"starts containers"| node_docker
node_controller -->|"configures VPN"| node_gluetun
node_controller -->|"adds optional hop"| node_warp
node_controller -->|"selects Tor exit"| node_tor
node_controller -->|"gets servers"| node_hideme
node_controller -->|"starts endpoint"| node_ec2manager
node_ec2manager -->|"creates instance"| node_aws
node_ec2manager -->|"installs shutdown monitor"| node_deadman
node_docker -->|"runs measurement"| node_connectivity
node_connectivity -->|"checks IP"| node_iputils
node_connectivity -->|"writes results"| node_results
node_docker -->|"runs experiment"| node_resolver
node_resolver -->|"runs DNS queries"| node_massdns
node_resolver -->|"uses resolver list"| node_unbound
node_resolver -->|"writes results"| node_results
node_docker -->|"runs experiment"| node_epdgscan
node_epdgscan -.->|"stores scan output"| node_results

click node_controller "https://github.com/sbaresearch/scanywhere/blob/main/scanywhere.py"
click node_gluetun "https://github.com/sbaresearch/scanywhere/tree/main/docker/gluetun"
click node_warp "https://github.com/sbaresearch/scanywhere/tree/main/docker/gluetun-warp"
click node_tor "https://github.com/sbaresearch/scanywhere/blob/main/utils/tor_utils.py"
click node_hideme "https://github.com/sbaresearch/scanywhere/blob/main/utils/hideme.py"
click node_ec2manager "https://github.com/sbaresearch/scanywhere/blob/main/utils/ec2_manager.py"
click node_deadman "https://github.com/sbaresearch/scanywhere/blob/main/utils/deadman_switch.sh"
click node_connectivity "https://github.com/sbaresearch/scanywhere/blob/main/docker/check-ip-connectivity/main.py"
click node_iputils "https://github.com/sbaresearch/scanywhere/blob/main/utils/ip_utils.py"
click node_resolver "https://github.com/sbaresearch/scanywhere/blob/main/docker/vowifi-geoblocking-resolve-domains/resolve_domains.py"
click node_unbound "https://github.com/sbaresearch/scanywhere/blob/main/docker/vowifi-geoblocking-resolve-domains/resources/local_unbound.txt"
click node_epdgscan "https://github.com/sbaresearch/scanywhere/blob/main/docker/vowifi-geoblocking-scan-epdgs/main.py"
click node_results "https://github.com/sbaresearch/scanywhere/tree/main/docker"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_controller,node_docker toneBlue
class node_gluetun,node_warp,node_tor,node_hideme toneAmber
class node_connectivity,node_iputils,node_results toneMint
class node_resolver,node_massdns,node_unbound,node_epdgscan toneRose
class node_ec2manager,node_aws,node_deadman,node_operator toneIndigo
```

## Components

### Orchestration

- [Scanywhere CLI](https://github.com/sbaresearch/scanywhere/blob/main/scanywhere.py): `scanywhere.py`
- **Docker Engine**

### VPN Tunnels

- [Gluetun VPN](https://github.com/sbaresearch/scanywhere/tree/main/docker/gluetun): `docker/gluetun`
- [Cloudflare Warp](https://github.com/sbaresearch/scanywhere/tree/main/docker/gluetun-warp): `docker/gluetun-warp`
- [Tor Relay Selection](https://github.com/sbaresearch/scanywhere/blob/main/utils/tor_utils.py): `utils/tor_utils.py`
- [hide.me Servers](https://github.com/sbaresearch/scanywhere/blob/main/utils/hideme.py): `utils/hideme.py`

### Measurements

- [IP Connectivity Check](https://github.com/sbaresearch/scanywhere/blob/main/docker/check-ip-connectivity/main.py): `docker/check-ip-connectivity/main.py`
- [IP Address Utilities](https://github.com/sbaresearch/scanywhere/blob/main/utils/ip_utils.py): `utils/ip_utils.py`
- [Experiment Results](https://github.com/sbaresearch/scanywhere/tree/main/docker): `docker`

### VoWiFi Study

- [Mass GeoDNS Resolution](https://github.com/sbaresearch/scanywhere/blob/main/docker/vowifi-geoblocking-resolve-domains/resolve_domains.py): `docker/vowifi-geoblocking-resolve-domains/resolve_domains.py`
- **MassDNS**
- [DNS Resolver List](https://github.com/sbaresearch/scanywhere/blob/main/docker/vowifi-geoblocking-resolve-domains/resources/local_unbound.txt): `docker/vowifi-geoblocking-resolve-domains/resources/local_unbound.txt`
- [ePDG IKE Scanner](https://github.com/sbaresearch/scanywhere/blob/main/docker/vowifi-geoblocking-scan-epdgs/main.py): `docker/vowifi-geoblocking-scan-epdgs/main.py`

### Cloud Support

- [EC2 WireGuard](https://github.com/sbaresearch/scanywhere/blob/main/utils/ec2_manager.py): `utils/ec2_manager.py`
- **AWS EC2**
- [Deadman Switch](https://github.com/sbaresearch/scanywhere/blob/main/utils/deadman_switch.sh): `utils/deadman_switch.sh`

### Other components

- **Operator**

## Connections

- Operator → Scanywhere CLI: runs (evidence: `README.md`)
- Scanywhere CLI → Docker Engine: starts containers (evidence: `scanywhere.py`)
- Scanywhere CLI → Gluetun VPN: configures VPN (evidence: `scanywhere.py`)
- Scanywhere CLI → Cloudflare Warp: adds optional hop (evidence: `scanywhere.py`)
- Scanywhere CLI → Tor Relay Selection: selects Tor exit (evidence: `scanywhere.py`)
- Scanywhere CLI → hide.me Servers: gets servers (evidence: `scanywhere.py`)
- Scanywhere CLI → EC2 WireGuard: starts endpoint (evidence: `scanywhere.py`)
- EC2 WireGuard → AWS EC2: creates instance (evidence: `utils/ec2_manager.py`)
- EC2 WireGuard → Deadman Switch: installs shutdown monitor (evidence: `README.md`)
- Docker Engine → IP Connectivity Check: runs measurement (evidence: `README.md`)
- IP Connectivity Check → IP Address Utilities: checks IP (evidence: `docker/check-ip-connectivity/main.py`)
- IP Connectivity Check → Experiment Results: writes results (evidence: `docker/check-ip-connectivity/main.py`)
- Docker Engine → Mass GeoDNS Resolution: runs experiment (evidence: `README.md`)
- Mass GeoDNS Resolution → MassDNS: runs DNS queries (evidence: `docker/vowifi-geoblocking-resolve-domains/resolve_domains.py`)
- Mass GeoDNS Resolution → DNS Resolver List: uses resolver list (evidence: `docker/vowifi-geoblocking-resolve-domains/resolve_domains.py`)
- Mass GeoDNS Resolution → Experiment Results: writes results (evidence: `docker/vowifi-geoblocking-resolve-domains/resolve_domains.py`)
- Docker Engine → ePDG IKE Scanner: runs experiment (evidence: `README.md`)
- ePDG IKE Scanner → Experiment Results: stores scan output
