Tools for finding accessible cloud IP ranges during internet shutdowns and provisioning proxy servers on those IPs.
- Download ranges (
download_ranges.sh) — run outside Iran to fetch IP ranges from all major cloud providers - Iran scanner (
iran_scanner.sh) — run inside Iran to discover which cloud IP ranges are accessible during a shutdown - Cloud setup (
cloud_setup.sh) — run outside Iran to reserve a public IP in an accessible range, create a VM, and SSH in for proxy setup via MoaV
# 1. Outside Iran — download all provider IP ranges
./download_ranges.sh samples/
# 2. Send the samples/ folder to someone inside Iran (USB, Bluetooth, etc.)
# 3. Inside Iran — find which ranges are open
./iran_scanner.sh --file samples/azure_servicetags.json --output open_ranges_scan.txt
./iran_scanner.sh --file samples/aws_ip_ranges.json --output open_ranges_scan.txt
./iran_scanner.sh --file samples/all_cidrs.txt --output open_ranges_scan.txt # scan everything
# 4. Outside Iran — provision a VM on an accessible IP
./cloud_setup.sh --provider azure --ranges "102.37.128.0/17" --region southafricanorth
# 5. Inside the SSH session that opens:
curl -fsSL moav.sh/install.sh | sudo bash
sudo moav domainlessDownloads IP ranges from all supported cloud providers into a directory. Run this outside Iran where internet is unrestricted.
./download_ranges.sh [output_dir] # default: samples/Downloads from:
| Provider | File | Source URL |
|---|---|---|
| Azure | azure_servicetags.json |
ServiceTags_Public |
| AWS | aws_ip_ranges.json |
https://ip-ranges.amazonaws.com/ip-ranges.json |
| GCP | gcp_cloud.json |
https://www.gstatic.com/ipranges/cloud.json |
| Oracle Cloud | oracle_ip_ranges.json |
https://docs.oracle.com/en-us/iaas/tools/public_ip_ranges.json |
| Cloudflare | cloudflare_ips.txt |
https://www.cloudflare.com/ips-v4 |
| Fastly | fastly_ips.json |
https://api.fastly.com/public-ip-list |
Also generates all_cidrs.txt — a deduplicated plain CIDR list combining all providers.
Discovers which cloud IP ranges are reachable from inside Iran. Supports multiple input formats.
Usage: iran_scanner.sh [OPTIONS]
Input (one of):
--file <path> Local file: JSON (Azure/AWS/GCP/OCI/Fastly) or plain CIDR list
--provider <name> Download from: azure, aws, gcp, oracle, cloudflare, fastly
Options:
--format <fmt> Force format (auto-detected if omitted):
azure, aws, gcp, oracle, cloudflare, fastly, cidrs
--region <pattern> Only scan regions matching pattern (e.g. "southafrica|us-east")
--parallel <N> Max concurrent probes (default: 50)
--ports <list> Comma-separated ports to test (default: 443,80,22)
--probes <list> Probe types to run: icmp,tcp,https (default: all three)
--resume <path> Resume an interrupted scan (path to previous .csv)
--output <path> Output CSV file path (default: scans/scan_TIMESTAMP.csv)
--output-dir <dir> Output directory (default: scans/)
--min-prefix <N> Skip CIDRs smaller than /N (default: 28)
-v, --verbose Show detailed probe logs for each IP
Supported input formats (auto-detected from file content):
| Format | JSON Structure | Region filtering |
|---|---|---|
azure |
.values[].properties.addressPrefixes[] |
By service tag name |
aws |
.prefixes[].ip_prefix |
By .region field |
gcp |
.prefixes[].ipv4Prefix |
By .scope field |
oracle |
.regions[].cidrs[].cidr |
By .region field |
fastly |
.addresses[] |
None |
cloudflare |
Plain text, one CIDR per line | None |
cidrs |
Plain text, one CIDR per line | None |
Examples:
# Auto-download and scan Azure ranges
./iran_scanner.sh --provider azure
# Use pre-downloaded Azure JSON, filter to South Africa
./iran_scanner.sh --file samples/azure_servicetags.json --region "southafrica"
# Use pre-downloaded AWS JSON, filter to US East
./iran_scanner.sh --file samples/aws_ip_ranges.json --region "us-east"
# Use pre-downloaded GCP JSON
./iran_scanner.sh --file samples/gcp_cloud.json --region "me-central"
# Use pre-extracted plain CIDR list (like all_azure_ips.txt or all_cidrs.txt)
./iran_scanner.sh --file samples/all_azure_ips.txt
# Scan all providers at once using the combined file
./iran_scanner.sh --file samples/all_cidrs.txt --parallel 100
# Verbose mode — see every probe result
./iran_scanner.sh --file samples/aws_ip_ranges.json -v
# Ping only (fastest scan)
./iran_scanner.sh --file samples/all_cidrs.txt --probes icmp
# Ping + TCP only (skip HTTPS)
./iran_scanner.sh --file samples/aws_ip_ranges.json --probes icmp,tcp
# Resume an interrupted scan (picks up where it left off)
./iran_scanner.sh --file samples/azure_servicetags.json --resume scans/scan_20260311.csvTip: Two-pass scanning — The fastest strategy for large range files (e.g. all Azure or
all_cidrs.txt) is two passes:
- Fast ping sweep to find reachable ranges:
./iran_scanner.sh --file samples/azure_servicetags.json --probes icmp --parallel 200- Deep scan only the reachable CIDRs with TCP + HTTPS:
./iran_scanner.sh --file scans/scan_YYYYMMDD.csv --probes tcp,https --parallel 100Ping probes complete in ~2s each vs ~8-10s for full TCP+HTTPS, so pass 1 finishes much faster. Pass 2 then only tests the ranges that responded — typically a small fraction of the total.
Minimal dependencies: bash, curl, ping. Uses jq if available, falls back to grep.
Optional accelerators: Install any of these for dramatically faster scans:
| Tool | What it accelerates | Speedup | Install |
|---|---|---|---|
fping |
ICMP sweep — bulk pings all IPs in one process | 50-100x | apt install fping / brew install fping |
nmap |
TCP port scan — parallel SYN/connect scanning | 5-10x | apt install nmap / brew install nmap |
masscan |
TCP port scan — async, very fast (needs root) | 10-50x | apt install masscan / brew install masscan |
Tools are auto-detected at startup. If available, they run as a bulk pre-scan phase before per-IP probes. If not installed, the scanner falls back to built-in bash probes — no functionality is lost.
When all enabled probes have bulk tools available (e.g. --probes icmp with fping installed), the scanner skips the per-IP loop entirely and compiles results directly from the bulk output — finishing in seconds instead of minutes.
Offline mode: Have someone outside Iran run download_ranges.sh and send the files, then:
./iran_scanner.sh --file samples/all_cidrs.txtOutput format (CSV in scans/ directory):
cidr,ip,methods
102.37.128.0/17,102.37.128.1,"tcp443,tcp22,https"
34.64.0.0/11,34.64.0.1,"tcp443,https"A .progress file is written alongside each CSV, tracking every CIDR attempted (not just accessible ones). This enables resuming interrupted scans.
Resuming interrupted scans: If a scan is interrupted (Ctrl+C, network drop, etc.), resume it:
# The scanner tells you the exact command on Ctrl+C:
# "Resume with: ./iran_scanner.sh --resume scans/scan_20260311_025400.csv --file <input>"
./iran_scanner.sh --file samples/azure_servicetags.json --resume scans/scan_20260311_025400.csv
# Resuming scan: 2400 CIDRs already scanned
# Remaining: 5333 blocks to scanThe --resume flag reads the .progress file to skip already-scanned CIDRs and appends new results to the existing CSV. All other flags (e.g. --probes, --parallel, --region) work normally alongside --resume.
Multi-provider VPS provisioner. Brute-force reserves public IPs until one lands in a target range, then creates a VM and opens an SSH session.
Usage: cloud_setup.sh --provider <provider> [OPTIONS]
Providers:
azure Microsoft Azure
oracle Oracle Cloud (free tier available)
gcp Google Cloud Platform
digitalocean DigitalOcean
hetzner Hetzner Cloud
vultr Vultr
Options:
--provider <name> Cloud provider (default: azure)
--ranges <cidrs> Comma-separated target CIDRs
--ranges-file <path> File with target CIDRs (iran_scanner output or open_ranges.txt)
--region <region> Cloud region
--rg <name> Resource group name (default: iran-proxy-rg)
--vm-name <name> VM name (default: proxy-vm)
--vm-size <size> VM size (uses cheapest if omitted)
--ssh-key <path> SSH public key (default: ~/.ssh/id_rsa.pub)
--max-attempts <N> Max IP allocation attempts (default: 500)
--scan-only Only find/reserve an IP, don't create a VM
--list-regions List available regions for the provider
-v, --verbose Show detailed logs (full CLI output, CIDR matching, errors)
Examples:
# Azure — South Africa range
./cloud_setup.sh --provider azure --ranges "102.37.128.0/17" --region southafricanorth
# Oracle Cloud — free tier, Middle East region
./cloud_setup.sh --provider oracle --ranges-file open_ranges.txt --region me-jeddah-1
# GCP — Google service ranges (likely whitelisted since Google services were accessible)
./cloud_setup.sh --provider gcp --ranges "34.64.0.0/11" --region me-central1-a
# Hetzner — cheap EU option
./cloud_setup.sh --provider hetzner --ranges-file open_ranges.txt --region hel1
# Just scan, don't create VM
./cloud_setup.sh --provider azure --ranges "102.37.0.0/16" --region southafricanorth --scan-only
# List available regions
./cloud_setup.sh --provider azure --list-regionsSimpler Azure-only version of cloud_setup.sh. Same IP scanning logic but only supports Azure. Use this if you only need Azure.
Pre-populated list of cloud IP ranges likely to be accessible during Iranian shutdowns, based on services confirmed working during the January 2026 shutdown.
| Category | Ranges | Why likely accessible |
|---|---|---|
| Azure South Africa | 102.37.0.0/16, 102.133.0.0/16 |
Original target |
| Azure UAE/Qatar | 20.37.64.0/18, 20.21.0.0/18, etc. |
Middle East regions |
| Azure M365 | 52.96.0.0/14, 13.107.128.0/22, etc. |
Outlook was accessible |
| Azure GitHub | 140.82.112.0/20, 192.30.252.0/22 |
GitHub was accessible |
| Azure OpenAI | 13.65.0.0/16, 40.78.0.0/17 |
ChatGPT was accessible |
| Google Services | 142.250.0.0/15, 172.217.0.0/16, etc. |
Gmail, Meet, Search, Maps, Play all working |
| Cloudflare CDN | 104.16.0.0/13, 172.64.0.0/13, etc. |
Custom domains route; Iranian banks use Cloudflare |
| Apple | 17.0.0.0/8 |
App Store was accessible |
| Oracle Cloud | 129.146.0.0/16, 152.67.0.0/16, etc. |
Free tier VMs available |
| Fastly/Akamai | 151.101.0.0/16, 23.32.0.0/11 |
CDN ranges |
The file is tab-separated with columns: CIDR, Category, Notes. It's automatically filtered by provider when used with cloud_setup.sh --ranges-file.
Pre-downloaded IP range files. Use download_ranges.sh to populate, or add files manually.
| File | Description |
|---|---|
ServiceTags_Public_20260309.json |
Azure ServiceTags JSON (use with --file + --format azure) |
all_azure_ips.txt |
Pre-extracted Azure CIDRs (use with --file, auto-detects as cidrs) |
azure_servicetags.json |
Downloaded by download_ranges.sh |
aws_ip_ranges.json |
Downloaded by download_ranges.sh |
gcp_cloud.json |
Downloaded by download_ranges.sh |
oracle_ip_ranges.json |
Downloaded by download_ranges.sh |
cloudflare_ips.txt |
Downloaded by download_ranges.sh |
fastly_ips.json |
Downloaded by download_ranges.sh |
all_cidrs.txt |
Combined deduplicated CIDRs from all providers |
For manual download or reference:
| Provider | URL | Updated |
|---|---|---|
| Azure | ServiceTags_Public JSON | Weekly |
| AWS | https://ip-ranges.amazonaws.com/ip-ranges.json | As needed |
| GCP | https://www.gstatic.com/ipranges/cloud.json | As needed |
| Oracle | https://docs.oracle.com/en-us/iaas/tools/public_ip_ranges.json | Weekly |
| Cloudflare | https://www.cloudflare.com/ips-v4 | As needed |
| Fastly | https://api.fastly.com/public-ip-list | As needed |
| DigitalOcean | Not officially published | — |
| Hetzner | Not officially published | — |
| Provider | CLI Tool | Free Tier | IP Method | Default VM Size |
|---|---|---|---|---|
| Azure | az |
No | Static public IP | Standard_B1s |
| Oracle Cloud | oci |
Yes (A1 ARM, 4 OCPU/24GB) | Reserved public IP | VM.Standard.A1.Flex |
| GCP | gcloud |
$300 credit | Static address | e2-micro |
| DigitalOcean | doctl |
No | Reserved IP | s-1vcpu-1gb |
| Hetzner | hcloud |
No | Floating IP | cx22 |
| Vultr | vultr-cli |
No | Reserved IP | — |
- bash 4.0+
- curl
- jq (recommended, not required for iran_scanner.sh)
- fping, nmap, masscan (optional — auto-detected, dramatically faster scans)
- Cloud provider CLI installed and authenticated for the provider you choose
- SSH key pair (
ssh-keygen -t ed25519if you don't have one)
Cloud providers assign public IPs from regional pools but don't let you choose a specific IP. The scripts brute-force it:
- Request a new public IP in the target region
- Check if the assigned IP falls within a target CIDR range
- If yes, keep it. If no, delete it and try again
- Once a matching IP is found, create a VM and attach it
The probability of hitting a target range depends on the pool size. Smaller regional pools (South Africa, Middle East) have better odds. Expect anywhere from 1 to 100+ attempts.
Azure-specific: Azure has a 3 public IP limit per subscription per region on free/trial accounts. The script handles this by waiting for deletes to propagate before retrying.
After the VM is created and you're SSH'd in:
# Install MoaV (installs Docker + proxy stack)
curl -fsSL moav.sh/install.sh | sudo bash
# Set up domain-less mode (no domain/DNS needed)
sudo moav domainlessMoaV supports multiple protocols: VLESS/Reality, WireGuard, Hysteria2, Telegram MTProxy, and more. Domain-less mode uses protocols that don't require a domain name or TLS certificate — ideal when DNS may be unreliable.
Share the server IP with users inside Iran. They connect using compatible clients (v2rayNG, Nekoray, etc.).
During shutdowns, Iran switches to a "block-by-default" model where only explicitly whitelisted services are accessible. Whitelisted services historically include:
- Microsoft: Outlook, Bing (→ Azure/M365 IP ranges routable)
- Google: Gmail, Meet, Search, Maps, Play Store (→ Google IP ranges routable)
- GitHub: Accessible (→ Microsoft/GitHub IP ranges routable)
- ChatGPT: Accessible (→ Azure/OpenAI IP ranges routable)
- Apple: App Store (→ Apple IP ranges routable)
- Cloudflare: Custom domains work, workers.dev blocked (→ CF CDN IPs routable)
- Domestic: Banking, government sites, Bale messenger
If a cloud VPS has an IP within one of these routable ranges, traffic to it passes through the firewall — enabling proxy access.
├── iran_scanner.sh # Inside Iran: discover accessible IP ranges (multi-provider)
├── cloud_setup.sh # Outside Iran: multi-provider VPS provisioner
├── azure_setup.sh # Outside Iran: Azure-only (simpler)
├── download_ranges.sh # Download IP ranges from all providers
├── open_ranges.txt # Pre-populated whitelisted ranges
├── scanner.sh # Original Azure IP scanner (v1)
├── scanner_v2.sh # Azure IP scanner (v2, sequential)
├── scans/ # Scan results (gitignored)
│ └── scan_20260311_013645.csv
├── samples/ # Downloaded IP range files
│ ├── azure_servicetags.json
│ ├── aws_ip_ranges.json
│ ├── gcp_cloud.json
│ ├── oracle_ip_ranges.json
│ ├── cloudflare_ips.txt
│ ├── fastly_ips.json
│ └── all_cidrs.txt
├── .gitignore # Ignores scans/
└── README.md