diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 18ebb44..0000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,3 +0,0 @@ -custom: - - "https://boosty.to/andrey27/donate" - - "https://finance.ozon.ru/apps/sbp/ozonbankpay/019dc200-2a5d-7931-a619-782d285f6798" diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 371721f..0000000 --- a/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -__pycache__/ -*.pyc -windows/build/ diff --git a/BETA.md b/BETA.md deleted file mode 100644 index 990cb1f..0000000 --- a/BETA.md +++ /dev/null @@ -1,10 +0,0 @@ -# Каналы PCA Phobos - -С версии **1.4.0** все три канала (stable / beta / dev) — одна и та же версия. -Новые фичи по-прежнему сначала выкатываются в `dev`, затем в `beta`, затем в `main` -(`promote.sh`), но база одна — без расхождений. - -```bash -phobos-update # stable (открытый) -GH_TOKEN=… phobos-update beta|dev # для подписчиков Boosty -``` diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index b1cdc0f..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,137 +0,0 @@ -# Changelog — PCA Phobos - -Каналы: **stable** (публичный, без токена) · **beta** / **dev** (приватный repo, токен подписчика). -Обновление: `phobos-update stable` · `GH_TOKEN=… phobos-update beta|dev` · из панели → «Версия и обновления». - ---- - -## Как обновиться после фиксов - -```bash -# stable (открытый) -phobos-update stable - -# beta/dev (токен уже сохранён в /opt/phobos-panel/.gh_token) -phobos-update beta # или: phobos-update dev -``` -Затем **пересоздать клиентов** в панели (старые конфиги могли содержать неверный порт обфускатора). -Обновляются: панель, скрипты онбординга, агент, updater. Ключи WireGuard, `server.env`, клиенты — НЕ трогаются. - ---- - -## 1.4.2 — настройка обфускатора сервера - -- **feat:** в панели «Настройки» → «Обфускатор сервера»: masking (AUTO/STUN/NONE), max-dummy, idle — записываются во все порты сервера, обфускатор перезапускается (клиенты переподключаются за секунды). -- **fix (Android PCA Phobos VPN 1.4.3):** конфиги других сборок Phobos с лишними ключами (`obfuscate-bytes` и т. п.) больше не роняют обфускатор («обфускатор завершился, код 1»): передаются только ключи, известные wg-obfuscator v1.6. - -## 1.4.1 — резервный TCP-канал, «РФ напрямую» - -- **feat:** резервный канал TCP: если провайдер режет UDP, клиент сам переходит на TCP (порт 443, иначе 8443/2096/4433). Сервер: служба `phobos-tcp` (`udptcp`), ставится и включается автоматически при установке и обновлении. Проверено реальной блокировкой UDP: переключение за ~15 с, без блокировки остаётся UDP. -- **feat (Android 1.4.2):** «Российские сайты — напрямую, без VPN» (по умолчанию), выбор канала Авто/UDP/TCP, журнал TCP-канала. -- **fix:** установка и обновления с git.bobyrev.com (GitHub — запасной), каскад раздаёт панель. -- Ограничения: TCP-резерв пока только на основном сервере (не на вторых) и только в приложении PCA Phobos VPN (роутеры и PhobosWG — по-прежнему UDP с перебором портов). - -## 1.4.0 — единая версия (stable = beta = dev) - -Три канала сведены в одну версию: всё из dev (WARP, ttyd, бэкап, маршрут Keenetic, параметры обфускатора) -+ фиксы beta (обновлятор через API, порт/схема панели) + новое: -- **feat:** светлая/тёмная тема, компактные карточки клиентов, мобильная версия без горизонтальной прокрутки. -- **feat:** лимит скорости на клиента (tc на wg0, применяется и на вторых серверах). -- **feat:** замер скорости сервера (реальный) и клиента (живой + `/speedtest` на устройстве через туннель). -- **feat:** домен панели (nginx + Let's Encrypt), адрес для клиентов по домену, каскад (`phobos-cascade.sh`). -- **feat:** сторож — блоклист сканеров РКН (`phobos-guard.sh`). -- **fix:** secondary-setup на чистой Ubuntu 24.04 (нет iptables → wg0 не поднимался), без tty, `SERVER_IP` для NAT; клиенты досылаются на новый сервер сразу. -- **fix:** очистка orphan-peer (не было WG_CONFIG), дубль карточки WARP и кнопки WARP, имена клиентов кириллицей. -- **fix:** после обновления старым обновлятором 1.2.x/1.3.x панель сама докачивает новые скрипты. -- **fix:** APK без токена подписчика — из публичного релиза (как в 1.2.8). - -Обновление: `phobos-update` (stable) — клиенты, ключи и `server.env` не трогаются. Проверено на школе: 1.2.8 → 1.4.0, старый клиент работает без переустановки. - -## stable - -### v1.2.7 -- **fix:** импорт `phobos://` в PhobosWG. Конфиги дополняются `= none` для недостающих полей (`PresharedKey` и др.) перед base64 — иначе приложение писало «невозможно импортировать туннель». - -### v1.2.6 -- **fix:** бинарники wg-obfuscator для роутеров. Keenetic = aarch64, а Ground-Zerro раздаёт только x86_64. Теперь install.sh и сборка пакета клиента авто-качают aarch64/mipsel/armv7 из ClusterM/wg-obfuscator releases. - -### v1.2.5 -- **feat:** поле токена подписчика + кнопки каналов (stable/beta/dev) прямо в карточке «Версия и обновления». Подписчик вставляет токен в панель и переключается на beta/dev без консоли. - -### v1.2.4 -- **feat:** установка по умолчанию стабильная; beta/dev — опционально (`CHANNEL=`). - -### v1.2.3 -- **fix:** дебаунс DOWN-алертов (3 цикла + повтор) — убирает ложный флап серверов. -- **fix:** `phobos-update` отменяет обновление на несуществующую версию (текущая не трогается). -- **feat:** `--check` / `--versions`, кнопка «Проверить обновления». - -### v1.2.2 -- контакт во всех местах → группа `@PCAdministration`. - ---- - -## Критичные фиксы (общие, во всех каналах) - -| Версия | Проблема | Решение | -|--------|----------|---------| -| 1.2.8 / 1.3.x | Android PhobosWG: «Неправильная длина ключа в PublicKey» | Android/iOS payload восстанавливает потерянный `=` в WireGuard ключах и не добавляет `PresharedKey = none`; QR/link нужно открыть заново | -| 1.2.8 / 1.3.x | Установка/обновление могли пройти, но потом панель генерила кривую ссылку | `phobos-self-check --fix` встроен в install/update и доступен как отдельная команда | -| 1.2.7 / 1.3.x | PhobosWG: «невозможно импортировать туннель» | `phobos://` дополняется `= none` для всех обязательных полей (`PresharedKey`) по спеке формата | -| 1.2.8 / 1.3.x | Install `[6/9] PCA patches`: `curl: (23) Failure writing output to destination` | `fetch()` создаёт папку назначения перед `curl -o` | -| 1.2.8 / 1.3.x | VPS x86_64: `ERROR: obfuscator binary for x86_64 missing` | авто-загрузка `linux-x64` из ClusterM releases + нормализация `amd64 -> x86_64` | -| 1.2.6 / 1.3.x | Роутер aarch64: «бинарник не найден в архиве» | авто-загрузка aarch64/mipsel/armv7 из ClusterM releases | -| (внутр.) | Клиент не подключается, «НЕТ СОЕДИНЕНИЯ», handshake не встаёт | клиентский обфускатор целился в порт 51821 (никто не слушал); теперь берёт первый из `OBFUSCATOR_PORTS` (2083) | -| (внутр.) | агент secondary не обновлялся через `phobos-update` | `server/api.py` добавлен в managed_files | - ---- - -## beta (приватный) - -### v1.3.0-beta -- **fix:** install/update теперь запускают `phobos-self-check --fix`: автоматически чинят потерянный `=` в `SERVER_WG_PUBLIC_KEY`, сверяют ключ с `wg0`, проверяют router helper-файлы и shell syntax до выдачи клиентских ссылок. -- **fix:** Android/iOS phone configs теперь восстанавливают потерянный `=` в WireGuard `PrivateKey/PublicKey/PresharedKey`. Это закрывает ошибку PhobosWG «Неправильная длина ключа в PublicKey». -- **fix:** `lib-core.sh` больше не теряет финальный `=` при чтении `server.env`, поэтому новые клиентские `.conf` получают полный `PublicKey`. -- **fix:** клиентский router package теперь содержит обязательные `lib-client.sh`, `install-obfuscator.sh`, `install-wireguard.sh` и дополнительные helper-скрипты из PCA repo, поэтому `wget .../init/TOKEN.sh | sh` больше не падает с `can't open './lib-client.sh'`. -- **fix:** шаг `[6/9] PCA patches` больше не падает с `curl: (23) Failure writing output to destination`, если папки `repo/server/scripts` или `repo/client/templates` не были созданы upstream sparse clone. -- **fix:** установка `wg-obfuscator` на x86_64 больше не падает с `ERROR: obfuscator binary for x86_64 missing`. Installer и secondary installer берут `linux-x64` из ClusterM releases. -- **fix:** свежая beta-установка снова получает `lib-core.sh`, без которого client helper мог ломаться на чистой машине. -- **fix:** старые ссылки `/tags` теперь ведут в `/labels`, без 404. -- **fix:** поле имени клиента больше не даёт ошибку в консоли Chrome из-за HTML `pattern`. UI bench-test прошёл без console/page errors. -- **fix:** WG tunnel subnet перестала быть жёстко зашита в `10.25.0.0/16`. Installer, secondary deploy, client packaging и router pull теперь используют `SERVER_WG_IPV4_NETWORK`, так что `10.26`/`10.27` и другие отдельные WG-сети на разных VPS работают без ручных правок. -- **fix:** в клиентский пакет добавляется `panel_tunnel_ip`, а `phobos-pull` использует его как tunnel endpoint панели вместо жёсткого `10.25.0.1`. -- скачивание `.conf` для телефона (Android `phobos://` + QR, iOS обычный WireGuard + QR); -- кнопка скачивания приложения **PhobosWG (APK)** — авто-загрузка из GitHub Release приватного repo; -- все критичные фиксы выше. - ---- - -## dev (приватный, активная разработка) - -### v1.3.4-dev -- **fix:** install/update теперь запускают `phobos-self-check --fix`: автоматически чинят потерянный `=` в `SERVER_WG_PUBLIC_KEY`, сверяют ключ с `wg0`, проверяют router helper-файлы и shell syntax до выдачи клиентских ссылок. -- **fix:** Android/iOS phone configs теперь восстанавливают потерянный `=` в WireGuard `PrivateKey/PublicKey/PresharedKey`. Это закрывает ошибку PhobosWG «Неправильная длина ключа в PublicKey». -- **fix:** `lib-core.sh` и WARP helper больше не теряют финальный `=` при чтении `server.env`, поэтому новые клиентские `.conf` получают полный `PublicKey`. -- **fix:** клиентский router package теперь содержит обязательные `lib-client.sh`, `install-obfuscator.sh`, `install-wireguard.sh` и дополнительные helper-скрипты из PCA repo, поэтому `wget .../init/TOKEN.sh | sh` больше не падает с `can't open './lib-client.sh'`. -- **fix:** шаг `[6/9] PCA patches` больше не падает с `curl: (23) Failure writing output to destination`, если папки `repo/server/scripts` или `repo/client/templates` не были созданы upstream sparse clone. -- **fix:** установка `wg-obfuscator` на x86_64 больше не падает с `ERROR: obfuscator binary for x86_64 missing`. Installer и secondary installer берут `linux-x64` из ClusterM releases. -- **fix:** поле имени клиента больше не даёт ошибку в консоли Chrome из-за HTML `pattern`. UI bench-test прошёл без console/page errors. -- **fix:** WG tunnel subnet больше не зашита в `10.25.0.0/16`. `install.sh`, `secondary-setup.sh`, client packaging, router pull и secondary deploy теперь берут `SERVER_WG_IPV4_NETWORK`, поэтому один сервер можно держать на `10.25`, другой на `10.26`, `10.27` и дальше без ручного `nano`. -- **fix:** в клиентский пакет добавляется `panel_tunnel_ip`, а `phobos-pull`/`phobos-ttyd` используют его вместо жёсткого `10.25.0.1`. Это убирает поломку управления роутером после смены WG-подсети на сервере. -- **fix:** per-client WARP стал действительно точечным. Удалено старое правило на всю подсеть WG, правила теперь ставятся и снимаются только по `client tunnel IP /32`. -- **fix:** клиентские пакеты и install-команды снова собираются стабильно: создаётся `/opt/Phobos/bin`, шаблон `install-router.sh.template` обрабатывается мягко, пустой `OBFUSCATOR_KEY` больше не валит сборку. -- **fix:** `/clients` больше не падает при неполной выкладке dev-стенда. Добавлены обязательные `lib-core.sh` и client templates в install/update flow. -- **fix:** “живой peer есть, клиента нет” больше не выглядит как пропавший клиент. Сиротские peer теперь отображаются в `Сессии` и `Клиенты` как `orphan-*`, с кнопками `WARP`, `Kick`, `Purge`. -- **fix:** старые ссылки `/tags` теперь ведут в `/labels`. -- **security:** login hardening — `HttpOnly` + `SameSite=Lax` cookie, ограничение попыток входа, constant-time compare для пароля и API keys, upload limit `64 MB`. -- **ops:** `phobos-update` и `phobos-backup restore` теперь сами определяют активный panel service (`phobos-panel` или `phobos-dev-test`) и перезапускают правильный unit. -- **security/cleanup:** из secondary API убран `shell=True` там, где он был не нужен; чтение CPU/mem/network переведено на более безопасный путь. - -### v1.3.1-dev -- **баланс по трафику:** агенты отдают пропускную способность канала (rx/tx NIC), `server_load = 0.45·cpu + 0.30·mem + 0.25·bw`; карточки серверов показывают ↕ Mbps; -- **WARP / WARP+:** в `/settings` добавлен отдельный блок с режимами `egress`, `relay`, `custom profile` и полем `WARP+ key`; -- **egress mode:** исходящий трафик клиентов можно завернуть через Cloudflare WARP на стороне сервера; -- **relay mode:** добавлен UDP relay по мотивам `warp-relay` для отдельных WARP/WireGuard профилей; -- **custom profile:** полный `warp.conf` можно вставить и сохранить прямо из веб-панели; -- **help UI:** у блока WARP появился `?` с человеческим объяснением режимов, ограничений и сценариев использования; -- все фиксы и фичи из beta. diff --git a/README.md b/README.md index 38bafce..26cb44d 100644 --- a/README.md +++ b/README.md @@ -1,235 +1,11 @@ -# PCA Phobos — VPN, который не отключается +# PCA Phobos — канал dev закрыт -**Веб-панель и turnkey-установщик для [Phobos](https://github.com/Ground-Zerro/Phobos)** — обфусцированного WireGuard VPN. Ставится на чистый VPS одной командой, управляет десятками роутеров и устройств с одной страницы, сам переключается между серверами при сбоях и восстанавливается после перезагрузок. +Каналы **beta** и **dev** выдаются по токену подписчика (read-only токен Gitea) и лежат в приватном репозитории. +Здесь их нет — публичная только стабильная версия (`main`, теги `v*`). -
-
-
" + url + "
" - + desc + "
Проверьте адрес и порт, интернет и что сервер включён. Кнопка ⟳ — повторить.
"; - } - - private void external(Uri u) { - try { - startActivity(new Intent(Intent.ACTION_VIEW, u)); - } catch (ActivityNotFoundException e) { - if ("phobos".equals(u.getScheme())) { - new AlertDialog.Builder(this) - .setTitle("Нужно приложение PhobosWG") - .setMessage("Ссылки phobos:// открывает приложение PhobosWG. Скачайте его на странице Android-клиента в панели (кнопка «Скачать приложение PhobosWG»).") - .setPositiveButton("OK", null).show(); - } else { - toast("Нет приложения для " + u.getScheme()); - } - } - } - - private void toast(String s) { Toast.makeText(this, s, Toast.LENGTH_SHORT).show(); } - - @Override - public void onBackPressed() { - if (web != null && web.canGoBack()) { web.goBack(); return; } - if (web != null && panels().length() > 0) { showList(); return; } - super.onBackPressed(); - } -} diff --git a/app.py b/app.py deleted file mode 100644 index 1b65dde..0000000 --- a/app.py +++ /dev/null @@ -1,4569 +0,0 @@ -#!/usr/bin/env python3 -""" -PCA Phobos — Web Panel for Phobos (Obfuscated WireGuard VPN) -Management panel: clients, sessions, labels, subscriptions, Telegram alerts. -""" - -import json, os, subprocess, threading, time, secrets, hashlib, re, fcntl, hmac, ipaddress -import html as html_lib -from datetime import datetime, timedelta -from pathlib import Path -from flask import Flask, request, redirect, url_for, session, make_response, send_from_directory -try: - from flask_sock import Sock -except Exception: - Sock = None - -_settings_lock = threading.Lock() - -app = Flask(__name__) -# ttyd clients require the server to select the 'tty' subprotocol; simple_websocket -# only echoes it when the client requested it, so SSH-terminal WS (no subprotocol) -# is unaffected. -app.config["SOCK_SERVER_OPTIONS"] = {"subprotocols": ["tty"]} -sock = Sock(app) if Sock else None -app.config["MAX_CONTENT_LENGTH"] = 64 * 1024 * 1024 -app.config["SESSION_COOKIE_HTTPONLY"] = True -app.config["SESSION_COOKIE_SAMESITE"] = "Lax" -app.config["PERMANENT_SESSION_LIFETIME"] = timedelta(hours=12) - -PHOBOS_DIR = "/opt/Phobos" -CLIENTS_DIR = f"{PHOBOS_DIR}/clients" -SERVER_ENV = f"{PHOBOS_DIR}/server/server.env" -PANEL_DIR = "/opt/phobos-panel" -SETTINGS_FILE = f"{PANEL_DIR}/settings.json" -SECRET_FILE = f"{PANEL_DIR}/.secret_key" -WG_CONFIG = "/etc/wireguard/wg0.conf" -# Distribution: Gitea first (GitHub account is unavailable since 23.10.2026), GitHub fallback -PCA_GIT = "https://git.bobyrev.com/PCA/PCA_Phobos" -PCA_GH_RAW = "https://raw.githubusercontent.com/andrey271192/PCA_Phobos" -APK_TAG = "v1.4.2" -WARP_DIR = f"{PHOBOS_DIR}/server/warp" -WARP_CUSTOM_PROFILE_FILE = f"{WARP_DIR}/custom-profile.conf" -WARP_LICENSE_FILE = f"{WARP_DIR}/license.key" -SERVER_IP = subprocess.getoutput("curl -s https://api.ipify.org 2>/dev/null || hostname -I | awk '{print $1}'").strip() - -os.makedirs(PANEL_DIR, exist_ok=True) - -if os.path.exists(SECRET_FILE): - app.secret_key = open(SECRET_FILE).read().strip() -else: - app.secret_key = secrets.token_hex(32) - with open(SECRET_FILE, "w") as f: - f.write(app.secret_key) - -DEFAULT_SETTINGS = { - "admin_pass": "OcAdmin2026!", - "tg_bot_token": "", - "tg_chat_id": "", - "monitor_interval": 30, - "labels": {}, - "subscriptions": {}, - "warp": { - "mode": "egress", - "profile_source": "free", - "relay_ports": "4500", - "relay_target": "", - "license_key": "", - }, - "warp_clients": [], - "client_aliases": {}, - "obf_params": { - "masking": "AUTO", - "max_dummy": "4", - "idle": "300", - }, -} -LOGIN_ATTEMPTS = {} -LOGIN_WINDOW = 900 -LOGIN_MAX_ATTEMPTS = 10 - - -def load_settings(): - with _settings_lock: - if os.path.exists(SETTINGS_FILE): - with open(SETTINGS_FILE) as f: - s = json.load(f) - for k, v in DEFAULT_SETTINGS.items(): - s.setdefault(k, v) - if not s.get("server_api_key"): - s["server_api_key"] = secrets.token_hex(16) - with open(SETTINGS_FILE, "w") as f: - json.dump(s, f, indent=2, ensure_ascii=False) - return s - s = dict(DEFAULT_SETTINGS) - s["server_api_key"] = secrets.token_hex(16) - return s - - -def save_settings(s): - with _settings_lock: - with open(SETTINGS_FILE, "w") as f: - json.dump(s, f, indent=2, ensure_ascii=False) - - -SRV_OBF_KEYS = ("masking", "max-dummy", "idle-timeout") - - -def _srv_obf_confs(): - import glob - return sorted(glob.glob(f"{PHOBOS_DIR}/server/wg-obfuscator-*.conf")) - - -def read_server_obf(): - """Current server wg-obfuscator params (from the first instance config).""" - vals = {"masking": "AUTO", "max-dummy": "50", "idle-timeout": "300"} - confs = _srv_obf_confs() - if confs: - for ln in Path(confs[0]).read_text().splitlines(): - k, _, v = ln.partition("=") - if k.strip() in SRV_OBF_KEYS: - vals[k.strip()] = v.strip() - return vals - - -def write_server_obf(vals): - """Rewrite masking/max-dummy/idle-timeout in every server instance and restart them.""" - done = [] - for f in _srv_obf_confs(): - lines, seen = [], set() - for ln in Path(f).read_text().splitlines(): - k = ln.partition("=")[0].strip() - if k in vals: - ln = f"{k} = {vals[k]}"; seen.add(k) - lines.append(ln) - lines += [f"{k} = {v}" for k, v in vals.items() if k not in seen] - Path(f).write_text("\n".join(lines) + "\n") - port = re.search(r"wg-obfuscator-(\d+)\.conf$", f).group(1) - subprocess.run(["systemctl", "restart", f"wg-obfuscator-{port}"], timeout=30) - done.append(port) - return done - - -def _load_server_env(): - """Load server.env as dict for subprocess env.""" - env = {} - if os.path.exists(SERVER_ENV): - with open(SERVER_ENV) as f: - for line in f: - line = line.strip() - if "=" in line and not line.startswith("#"): - k, v = line.split("=", 1) - env[k] = v - return env - - -def _server_wg_interface(): - env = _load_server_env() - iface = (env.get("SERVER_WG_IPV4_ADDRESS") or "").strip() - if iface: - return iface - try: - if os.path.exists("/etc/wireguard/wg0.conf"): - with open("/etc/wireguard/wg0.conf") as fh: - for raw in fh: - raw = raw.strip() - if raw.startswith("Address"): - value = raw.split("=", 1)[1].split(",", 1)[0].strip() - if value: - return value - except Exception: - pass - net = (env.get("SERVER_WG_IPV4_NETWORK") or "10.25.0.0/16").strip() - try: - network = ipaddress.ip_network(net, strict=False) - return str(ipaddress.ip_interface(f"{next(network.hosts())}/{network.prefixlen}")) - except Exception: - return "10.25.0.1/16" - - -def server_wg_network(): - env = _load_server_env() - raw = (env.get("SERVER_WG_IPV4_NETWORK") or "").strip() - if raw: - try: - return str(ipaddress.ip_network(raw, strict=False)) - except Exception: - pass - try: - return str(ipaddress.ip_interface(_server_wg_interface()).network) - except Exception: - return "10.25.0.0/16" - - -def server_tunnel_ip(): - try: - return str(ipaddress.ip_interface(_server_wg_interface()).ip) - except Exception: - return "10.25.0.1" - - -def client_display_name(cid, s=None): - cid = str(cid or "").strip() - aliases = (s or load_settings()).get("client_aliases", {}) or {} - alias = str(aliases.get(cid, "") or "").strip() - return alias or cid - - -def panel_service_name(): - for name in ("phobos-dev-test", "phobos-panel"): - try: - r = subprocess.run(["systemctl", "is-active", name], capture_output=True, text=True, timeout=5) - if (r.stdout or "").strip() in ("active", "inactive", "failed", "activating", "deactivating"): - return name - except Exception: - pass - return "phobos-panel" - - -def login_allowed(ip): - now = int(time.time()) - rec = [ts for ts in LOGIN_ATTEMPTS.get(ip, []) if now - ts < LOGIN_WINDOW] - LOGIN_ATTEMPTS[ip] = rec - return len(rec) < LOGIN_MAX_ATTEMPTS - - -def login_failed(ip): - now = int(time.time()) - rec = [ts for ts in LOGIN_ATTEMPTS.get(ip, []) if now - ts < LOGIN_WINDOW] - rec.append(now) - LOGIN_ATTEMPTS[ip] = rec - - -def login_reset(ip): - LOGIN_ATTEMPTS.pop(ip, None) - - -def _default_warp_settings(): - return dict(DEFAULT_SETTINGS["warp"]) - - -def get_warp_settings(s=None): - src = (s or load_settings()).get("warp", {}) - out = _default_warp_settings() - if isinstance(src, dict): - out.update({k: str(v) for k, v in src.items() if v is not None}) - out["mode"] = out.get("mode", "egress") if out.get("mode", "egress") in ("egress", "relay") else "egress" - out["profile_source"] = out.get("profile_source", "free") if out.get("profile_source", "free") in ("free", "custom") else "free" - out["relay_ports"] = out.get("relay_ports", "4500").strip() or "4500" - out["relay_target"] = out.get("relay_target", "").strip() - out["license_key"] = out.get("license_key", "").strip() - return out - - -def read_custom_warp_profile(): - try: - return Path(WARP_CUSTOM_PROFILE_FILE).read_text() - except Exception: - return "" - - -def save_custom_warp_profile(text): - text = (text or "").strip() - os.makedirs(WARP_DIR, exist_ok=True) - Path(WARP_CUSTOM_PROFILE_FILE).write_text(text + ("\n" if text else "")) - return True - - -def read_warp_license_key(): - try: - return Path(WARP_LICENSE_FILE).read_text().strip() - except Exception: - return "" - - -def save_warp_license_key(text): - text = (text or "").strip() - os.makedirs(WARP_DIR, exist_ok=True) - Path(WARP_LICENSE_FILE).write_text(text + ("\n" if text else "")) - return True - - -def delete_warp_license_key(): - try: - os.remove(WARP_LICENSE_FILE) - return True - except FileNotFoundError: - return False - except Exception: - return False - - -def delete_custom_warp_profile(): - try: - os.remove(WARP_CUSTOM_PROFILE_FILE) - return True - except FileNotFoundError: - return False - except Exception: - return False - - -def tg_send(text): - s = load_settings() - token, chat = s.get("tg_bot_token", ""), s.get("tg_chat_id", "") - if not token or not chat: - return - try: - import urllib.request - url = f"https://api.telegram.org/bot{token}/sendMessage" - data = json.dumps({"chat_id": chat, "text": text, "parse_mode": "HTML"}).encode() - req = urllib.request.Request(url, data=data, headers={"Content-Type": "application/json"}) - urllib.request.urlopen(req, timeout=10) - except Exception: - pass - - -def notify_on(cid): - return load_settings().get("client_notify", {}).get(cid, True) - - -def warp_clients_enabled(): - vals = load_settings().get("warp_clients", []) - return {str(x).strip() for x in vals if str(x).strip()} - - -def client_warp_enabled(cid): - return cid in warp_clients_enabled() - - -def client_script_path(): - return f"{PHOBOS_DIR}/repo/server/scripts/phobos-client.sh" - - -def create_client_cli(name): - """Create a client (add + assign + fanout + install link). Returns (ok, html_msg). Used by web + Telegram bot.""" - import re as _re - name = (name or "").strip() - cid = _normalize_client_id(name) - if not name or not _re.match(r"^[a-zA-Z0-9_-]+$", name): - return False, "Имя: латиница, цифры, _ и - (без пробелов)." - if os.path.isdir(os.path.join(CLIENTS_DIR, cid)): - return False, "Клиент %s уже существует." % cid - script = client_script_path() - try: - subprocess.check_output([script, "add", name], text=True, timeout=45, - stderr=subprocess.STDOUT, env={**os.environ, **_load_server_env()}) - except subprocess.CalledProcessError as e: - return False, "Ошибка создания: %s" % (e.output or "")[-300:] - try: - auto_assign_server(cid); fanout_router_config(cid) - except Exception: - pass - cmd = "" - try: - out = subprocess.check_output([script, "link", name], text=True, timeout=25, - stderr=subprocess.STDOUT, env={**os.environ, **_load_server_env()}) - for ln in out.splitlines(): - if ln.strip().startswith("curl") or "/init/" in ln: - cmd = ln.strip(); break - except Exception: - pass - msg = "\u2705 Клиент %s создан." % cid - if cmd: - msg += "\n\nКоманда установки на роутер:\n%s" % cmd
- return True, msg
-
-
-def delete_client_cli(cid):
- cid = (cid or "").strip()
- if not cid or not os.path.isdir(os.path.join(CLIENTS_DIR, cid)):
- return False, "Клиент %s не найден." % cid
- script = client_script_path()
- try:
- subprocess.check_output([script, "remove", cid], text=True, timeout=25,
- stderr=subprocess.STDOUT, env={**os.environ, **_load_server_env()})
- except subprocess.CalledProcessError as e:
- return False, "Ошибка удаления: %s" % (e.output or "")[-300:]
- try:
- st = load_settings()
- st.get("client_assignments", {}).pop(cid, None)
- st.get("client_notify", {}).pop(cid, None)
- save_settings(st)
- except Exception:
- pass
- return True, "\U0001F5D1 Клиент %s удалён." % cid
-
-
-def tg_api(method, payload, token=None):
- import urllib.request
- if token is None:
- token = load_settings().get("tg_bot_token", "")
- if not token:
- return None
- try:
- data = json.dumps(payload).encode()
- req = urllib.request.Request("https://api.telegram.org/bot%s/%s" % (token, method),
- data=data, headers={"Content-Type": "application/json"})
- return json.loads(urllib.request.urlopen(req, timeout=15).read())
- except Exception:
- return None
-
-
-MAIN_KB = {
- "keyboard": [
- ["➕ Создать клиента", "\U0001F4CB Список"],
- ["\U0001F5D1 Удалить", "\U0001F4CA Статус"],
- ["❓ Помощь"],
- ],
- "resize_keyboard": True,
-}
-
-_bot_state = {}
-
-
-def _bot_status_text():
- servers = [{"ip": SERVER_IP, "is_primary": True}] + load_servers()
- lines = ["\U0001F4CA Серверы:"]
- for sv in servers:
- ip = sv.get("ip", "")
- st = "ok" if ip == SERVER_IP else server_stats_cache.get(ip, {}).get("status", "?")
- emoji = "\U0001F7E2" if st == "ok" else ("\U0001F534" if st == "down" else "⚪")
- lines.append("%s %s%s" % (emoji, ip, " (primary)" if sv.get("is_primary") else ""))
- online = set()
- try:
- for p, info in get_wg_peers().items():
- if is_peer_online(info.get("latest handshake", "")):
- online.add(p)
- for _ip, hs in server_handshakes_cache.items():
- for p, tsv in hs.items():
- if tsv and (time.time() - tsv) < 180:
- online.add(p)
- except Exception:
- pass
- lines.append("\n\U0001F4F1 Клиенты:")
- cl = get_clients()
- if not cl:
- lines.append("нет")
- for c in cl:
- on = c.get("public_key", "") in online
- lines.append(("\U0001F7E2 " if on else "⚪ ") + c.get("client_id", ""))
- return "\n".join(lines)
-
-
-def qr_png_bytes(data):
- import qrcode, io
- buf = io.BytesIO(); qrcode.make(data).save(buf, format="PNG"); return buf.getvalue()
-
-
-def tg_send_photo(chat, png, caption=""):
- import urllib.request, secrets as _sec
- token = load_settings().get("tg_bot_token", "")
- if not token:
- return None
- boundary = "----phobos" + _sec.token_hex(8)
- def fld(name, val):
- return ("--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n" % (boundary, name, val)).encode()
- body = fld("chat_id", str(chat)) + fld("caption", caption) + fld("parse_mode", "HTML")
- body += ("--%s\r\nContent-Disposition: form-data; name=\"photo\"; filename=\"qr.png\"\r\nContent-Type: image/png\r\n\r\n" % boundary).encode()
- body += png + ("\r\n--%s--\r\n" % boundary).encode()
- try:
- req = urllib.request.Request("https://api.telegram.org/bot%s/sendPhoto" % token, data=body,
- headers={"Content-Type": "multipart/form-data; boundary=%s" % boundary})
- return urllib.request.urlopen(req, timeout=25).read()
- except Exception:
- return None
-
-
-def bot_send_new_client(chat, name):
- ok, rep = create_client_cli(name)
- tg_api("sendMessage", {"chat_id": chat, "text": rep, "parse_mode": "HTML", "reply_markup": MAIN_KB})
- if ok:
- try:
- conf, link = build_phone_config(name, "android")
- if link:
- tg_send_photo(chat, qr_png_bytes(link), "📱 Android (PhobosWG) — отсканируй QR в приложении")
- tg_api("sendMessage", {"chat_id": chat, "text": "phobos:// ссылка (Android):\n%s" % link, "parse_mode": "HTML"})
- except Exception:
- pass
-
-
-def telegram_bot():
- offset = 0
- import urllib.request
- while True:
- try:
- s = load_settings()
- token = s.get("tg_bot_token", "")
- chat = str(s.get("tg_chat_id", ""))
- if not token or not chat:
- time.sleep(15); continue
- url = "https://api.telegram.org/bot%s/getUpdates?timeout=30&offset=%d" % (token, offset)
- data = json.loads(urllib.request.urlopen(url, timeout=40).read())
- for upd in data.get("result", []):
- offset = upd["update_id"] + 1
- cq = upd.get("callback_query")
- if cq:
- if str(cq.get("message", {}).get("chat", {}).get("id", "")) != chat:
- continue
- cdata = cq.get("data", "")
- if cdata.startswith("del:"):
- _, rep = delete_client_cli(cdata[4:])
- tg_api("answerCallbackQuery", {"callback_query_id": cq["id"], "text": "OK"})
- tg_api("sendMessage", {"chat_id": chat, "text": rep, "parse_mode": "HTML", "reply_markup": MAIN_KB})
- continue
- m = upd.get("message") or upd.get("channel_post")
- if not m:
- continue
- if str(m.get("chat", {}).get("id", "")) != chat:
- continue
- text = (m.get("text") or "").strip()
- if not text:
- continue
- # detect reply-keyboard button by its emoji prefix (NOT a command/arg)
- btn = None
- if not text.startswith("/"):
- if text.startswith("➕"):
- btn = "add"
- elif text.startswith("\U0001F5D1"):
- btn = "del"
- elif text.startswith("\U0001F4CB"):
- btn = "list"
- elif text.startswith("\U0001F4CA"):
- btn = "status"
- elif text.startswith("❓"):
- btn = "help"
- # conversation: awaiting a client name to create
- if _bot_state.get(chat) == "add":
- if btn is None and not text.startswith("/"):
- _bot_state.pop(chat, None)
- bot_send_new_client(chat, text)
- continue
- _bot_state.pop(chat, None) # a button/command cancels the prompt
- # parse slash command + arg (buttons carry no arg)
- cmd = ""
- arg = ""
- if text.startswith("/"):
- toks = text.split()
- cmd = toks[0].split("@")[0].lower()
- arg = toks[1] if len(toks) > 1 else ""
- if btn == "add" or cmd in ("/add", "/new", "/create"):
- if arg:
- bot_send_new_client(chat, arg)
- else:
- _bot_state[chat] = "add"
- tg_api("sendMessage", {"chat_id": chat, "text": "Введите имя нового клиента (латиница, цифры, _ и -):"})
- elif btn == "del" or cmd in ("/del", "/delete", "/remove", "/rm"):
- if arg:
- _, rep = delete_client_cli(arg)
- tg_api("sendMessage", {"chat_id": chat, "text": rep, "parse_mode": "HTML", "reply_markup": MAIN_KB})
- else:
- cl = get_clients()
- if not cl:
- tg_api("sendMessage", {"chat_id": chat, "text": "Клиентов нет.", "reply_markup": MAIN_KB})
- else:
- kb = {"inline_keyboard": [[{"text": "\U0001F5D1 " + c.get("client_id", ""), "callback_data": "del:" + c.get("client_id", "")}] for c in cl]}
- tg_api("sendMessage", {"chat_id": chat, "text": "Кого удалить? Нажми на клиента:", "reply_markup": kb})
- elif btn == "list" or cmd in ("/list", "/ls"):
- cl = [c.get("client_id", "") for c in get_clients()]
- rep = ("Клиенты (%d):\n" % len(cl)) + "\n".join("• " + c for c in cl) if cl else "Клиентов нет."
- tg_api("sendMessage", {"chat_id": chat, "text": rep, "reply_markup": MAIN_KB})
- elif btn == "status" or cmd in ("/status", "/stat"):
- tg_api("sendMessage", {"chat_id": chat, "text": _bot_status_text(), "parse_mode": "HTML", "reply_markup": MAIN_KB})
- elif btn == "help" or cmd in ("/help", "/start"):
- rep = ("PCA Phobos — бот\n\n"
- "Кнопки внизу или команды:\n"
- "➕ /add <имя> — создать клиента\n"
- "\U0001F5D1 /del <имя> — удалить\n"
- "\U0001F4CB /list — список\n"
- "\U0001F4CA /status — статус")
- tg_api("sendMessage", {"chat_id": chat, "text": rep, "parse_mode": "HTML", "reply_markup": MAIN_KB})
- except Exception:
- time.sleep(10)
-
-def get_wg_peers():
- """Parse `wg show wg0` to get active peers with transfer/handshake info."""
- try:
- out = subprocess.check_output(["wg", "show", "wg0"], text=True, timeout=5)
- except Exception:
- return {}
-
- peers = {}
- current_pub = None
- for line in out.split("\n"):
- line = line.strip()
- if line.startswith("peer:"):
- current_pub = line.split("peer:")[1].strip()
- peers[current_pub] = {}
- elif current_pub and ":" in line:
- key, val = line.split(":", 1)
- peers[current_pub][key.strip()] = val.strip()
- return peers
-
-
-def get_wg_allowed_ips():
- try:
- out = subprocess.check_output(["wg", "show", "wg0", "allowed-ips"], text=True, timeout=5)
- except Exception:
- return {}
- data = {}
- for line in out.splitlines():
- parts = line.split()
- if len(parts) >= 2:
- data[parts[0].strip()] = parts[1].strip()
- return data
-
-
-def _orphan_client_id(tunnel_ip):
- tip = (tunnel_ip or "").split("/")[0].strip() or "unknown"
- return "orphan-" + re.sub(r"[^a-zA-Z0-9]+", "-", tip).strip("-")
-
-
-def get_clients(include_orphans=False):
- """Read all clients from /opt/Phobos/clients/*/metadata.json."""
- clients = []
- clients_path = Path(CLIENTS_DIR)
- if not clients_path.exists():
- clients_path = None
- if clients_path:
- for d in sorted(clients_path.iterdir()):
- meta_file = d / "metadata.json"
- if meta_file.exists():
- try:
- with open(meta_file) as f:
- meta = json.load(f)
- meta["_dir"] = str(d)
- clients.append(meta)
- except Exception:
- pass
- if include_orphans:
- known = {c.get("public_key", ""): c for c in clients if c.get("public_key", "")}
- allowed = get_wg_allowed_ips()
- for pub, ip in allowed.items():
- if pub in known:
- continue
- tip = (ip or "").split(",")[0].strip()
- clients.append({
- "client_id": _orphan_client_id(tip),
- "client_name": _orphan_client_id(tip),
- "tunnel_ip_v4": tip,
- "public_key": pub,
- "created_at": "",
- "_orphan": True,
- })
- return clients
-
-
-def purge_orphan_peer(public_key):
- pub = (public_key or "").strip()
- if not pub:
- return False, "empty public key"
- try:
- subprocess.run(["wg", "set", "wg0", "peer", pub, "remove"], check=True, timeout=5)
- except Exception as e:
- return False, f"wg remove failed: {e}"
- try:
- cfg = Path(WG_CONFIG)
- if cfg.exists():
- text = cfg.read_text()
- blocks = [b for b in re.split(r"\n\s*\n", text.strip()) if b.strip()]
- kept = []
- for block in blocks:
- if pub in block and "[Peer]" in block:
- continue
- kept.append(block)
- cfg.write_text("\n\n".join(kept).strip() + "\n")
- except Exception:
- pass
- return True, f"orphan peer removed: {pub[:12]}..."
-
-
-def get_active_sessions():
- """Combine WG peers with client metadata to build session list."""
- peers = get_wg_peers()
- clients = get_clients(include_orphans=True)
-
- pub_to_client = {}
- for c in clients:
- pub_to_client[c.get("public_key", "")] = c
-
- sessions = []
- for pub_key, info in peers.items():
- handshake = info.get("latest handshake", "")
- if not handshake:
- continue
-
- client = pub_to_client.get(pub_key, {})
- client_id = client.get("client_id", "unknown")
- tunnel_ip = client.get("tunnel_ip_v4", "")
-
- endpoint = info.get("endpoint", "")
- real_ip = endpoint.split(":")[0] if endpoint else ""
-
- rx = info.get("transfer", "")
- rx_bytes = rx.split("received,")[0].strip() if "received," in rx else ""
- tx_bytes = rx.split("received,")[1].strip().replace("sent", "").strip() if "received," in rx else ""
-
- sessions.append({
- "client_id": client_id,
- "public_key": pub_key,
- "tunnel_ip": tunnel_ip,
- "real_ip": real_ip,
- "endpoint": endpoint,
- "handshake": handshake,
- "rx": rx_bytes,
- "tx": tx_bytes,
- })
- return sessions
-
-
-def is_peer_online(handshake_str):
- """Check if peer had a handshake within last 3 minutes."""
- s = (handshake_str or "").strip()
- # never handshaked ("" / "(none)") or days old -> offline
- if not re.search(r"\d", s) or "day" in s or "week" in s:
- return False
- try:
- parts = s.split(",")
- total_seconds = 0
- for p in parts:
- p = p.strip()
- if "minute" in p:
- total_seconds += int(re.search(r"(\d+)", p).group(1)) * 60
- elif "second" in p:
- total_seconds += int(re.search(r"(\d+)", p).group(1))
- elif "hour" in p:
- total_seconds += int(re.search(r"(\d+)", p).group(1)) * 3600
- return total_seconds < 180
- except Exception:
- return False
-
-
-def kick_peer(public_key):
- """Remove and re-add peer to force disconnect."""
- try:
- out = subprocess.check_output(["wg", "show", "wg0"], text=True, timeout=5)
- allowed = ""
- found = False
- for line in out.split("\n"):
- if line.strip().startswith("peer:") and public_key in line:
- found = True
- elif found and "allowed ips:" in line:
- allowed = line.split("allowed ips:")[1].strip()
- break
-
- subprocess.run(["wg", "set", "wg0", "peer", public_key, "remove"], timeout=5)
- if allowed:
- subprocess.run(["wg", "set", "wg0", "peer", public_key, "allowed-ips", allowed], timeout=5)
- return True
- except Exception:
- return False
-
-
-def check_expiry():
- """Check subscription expiry, lock expired clients."""
- s = load_settings() # Always reload fresh to avoid overwriting concurrent changes
- subs = s.get("subscriptions", {})
- today = datetime.now().date()
- changed = False
-
- for client_id, info in list(subs.items()):
- if not info.get("expiry"):
- continue
- try:
- exp_date = datetime.strptime(info["expiry"], "%Y-%m-%d").date()
- except ValueError:
- continue
-
- days_left = (exp_date - today).days
-
- if days_left <= 0 and not info.get("locked"):
- info["locked"] = True
- changed = True
- kick_client_by_id(client_id)
- tg_send(f"⛔ {client_id} — подписка истекла! Клиент заблокирован.")
- elif days_left == 3 and not info.get("warn3"):
- info["warn3"] = True
- changed = True
- tg_send(f"⚠️ {client_id} — подписка истекает через 3 дня ({info['expiry']})")
- elif days_left == 1 and not info.get("warn1"):
- info["warn1"] = True
- changed = True
- tg_send(f"⚠️ {client_id} — подписка истекает ЗАВТРА ({info['expiry']})")
-
- if changed:
- save_settings(s)
-
-
-def kick_client_by_id(client_id):
- """Find client's public key and kick them."""
- clients = get_clients()
- for c in clients:
- if c.get("client_id") == client_id:
- kick_peer(c.get("public_key", ""))
- return True
- return False
-
-
-prev_session_keys = None
-prev_server_status = {}
-_down_streak = {}
-_last_fanout = 0
-_last_peer_sync = 0
-server_stats_cache = {}
-server_handshakes_cache = {}
-
-
-def count_client_peers():
- """Count only client peers (exclude secondary server peers)."""
- clients = get_clients()
- client_pubs = {c.get("public_key", "") for c in clients}
- wg_peers = get_wg_peers()
- return sum(1 for pub in wg_peers if pub in client_pubs)
-
-
-_net_prev = {} # key -> (rx, tx, ts) for rate calc
-BW_CAP_MBPS = float(os.environ.get("BW_CAP_MBPS", "1000")) # link cap ref for load fraction
-
-_geo_cache = {}
-
-
-def _ip_country(ip):
- """Flag + country code for a public IP (ip-api.com, cached). '' for private."""
- ip = (ip or "").strip()
- if not ip or ip.startswith(("10.", "192.168.", "127.")) or ip.startswith("172.16."):
- return ""
- if ip in _geo_cache:
- return _geo_cache[ip]
- res = ""
- try:
- import urllib.request as _u, json as _j
- d = _j.loads(_u.urlopen(f"http://ip-api.com/json/{ip}?fields=countryCode", timeout=4).read())
- cc = (d.get("countryCode") or "").upper()
- if len(cc) == 2 and cc.isalpha():
- flag = "".join(chr(0x1F1E6 + ord(c) - 65) for c in cc)
- res = f"{flag} {cc}"
- except Exception:
- res = ""
- _geo_cache[ip] = res
- return res
-
-
-def _calc_mbps(key, rx, tx, ts):
- """Throughput Mbps from consecutive NIC byte counters. First sample -> 0."""
- prev = _net_prev.get(key)
- _net_prev[key] = (rx, tx, ts)
- if not prev:
- return 0.0
- prx, ptx, pts = prev
- dt = ts - pts
- if dt <= 0 or rx < prx or tx < ptx: # no time passed / counter reset
- return 0.0
- return round(((rx - prx) + (tx - ptx)) * 8 / (dt * 1e6), 1)
-
-
-def _local_net_bytes():
- try:
- iface = subprocess.getoutput("ip route get 8.8.8.8 2>/dev/null | awk '{for(i=1;i{tr("Возможно, ссылка устарела или раздел был переименован.","Link may be outdated or section was renamed.")}
- -{tr("Панель поймала ошибку. Обнови страницу. Если повторяется — проверь логи сервиса phobos-panel/phobos-dev-test.","Panel hit an error. Refresh page. If it repeats, check phobos-panel/phobos-dev-test logs.")}
- {tr("На главную","Back to dashboard")} -{tr("Лимит загрузки 64 MB. Уменьши файл или восстанавливай через shell.","Upload limit is 64 MB. Shrink file or restore via shell.")}
- {tr("К настройкам","Back to settings")} -")
-def set_lang(code):
- from flask import make_response
- resp = make_response(redirect(request.referrer or url_for("dashboard")))
- resp.set_cookie("lang", "en" if code == "en" else "ru", max_age=31536000)
- return resp
-
-
-
-
-
-@app.route("/login", methods=["GET", "POST"])
-def login():
- s = load_settings()
- msg = ""
- if request.method == "POST":
- rip = request.headers.get("X-Forwarded-For", request.remote_addr or "?").split(",")[0].strip()
- if not login_allowed(rip):
- msg = f'{tr("Слишком много попыток. Подожди 15 минут.","Too many attempts. Wait 15 minutes.")}'
- elif hmac.compare_digest(request.form.get("password", ""), s["admin_pass"]):
- login_reset(rip)
- session["auth"] = True
- session.permanent = True
- return redirect(url_for("dashboard"))
- else:
- login_failed(rip)
- msg = f'{tr("Неверный пароль","Wrong password")}'
- html = f"""
-
- {tr("Вход в панель","Sign in")}
- {msg}
-
- """
- return render(html)
-
-
-@app.route("/logout")
-def logout():
- session.clear()
- return redirect(url_for("login"))
-
-
-def auth_required(f):
- from functools import wraps
- @wraps(f)
- def decorated(*args, **kwargs):
- if not session.get("auth"):
- return redirect(url_for("login"))
- return f(*args, **kwargs)
- return decorated
-
-
-@app.route("/tags")
-@auth_required
-def tags_alias():
- return redirect(url_for("labels_page"))
-
-
-@app.route("/api/backup/download")
-@auth_required
-def backup_download():
- """Create a full server backup and stream it (contains private keys)."""
- from flask import send_file
- try:
- r = subprocess.run(["bash", BACKUP_SCRIPT, "create"],
- capture_output=True, text=True, timeout=60)
- path = (r.stdout or "").strip().splitlines()[-1] if r.stdout.strip() else ""
- if not path or not os.path.exists(path):
- return ("backup failed: " + (r.stderr or "no output")[-300:], 500)
- return send_file(path, as_attachment=True, download_name=os.path.basename(path),
- mimetype="application/gzip")
- except Exception as e:
- return ("backup error: " + str(e), 500)
-
-
-@app.route("/api/backup/restore", methods=["POST"])
-@auth_required
-def backup_restore():
- """Restore a server from an uploaded backup tarball."""
- import tempfile
- f = request.files.get("backup")
- if not f:
- return ("no file", 400)
- tmp = tempfile.NamedTemporaryFile(suffix=".tar.gz", delete=False)
- try:
- f.save(tmp.name)
- r = subprocess.run(["bash", BACKUP_SCRIPT, "restore", tmp.name],
- capture_output=True, text=True, timeout=120)
- out = html_lib.escape((r.stdout + r.stderr)[-1200:])
- return render(f'''{nav("settings")}''')
- finally:
- try:
- os.unlink(tmp.name)
- except Exception:
- pass
-
-
-# ── ttyd web-terminal for Keenetic routers (over WG tunnel) ─────────────────
-# Router runs ttyd (web pty) bound to its tunnel IP, firewalled to the panel
-# only. Panel reverse-proxies HTTP + bridges the websocket so the browser gets
-# a full shell behind NAT without SSH. (awg-manager-style, but over our tunnel.)
-def _ttyd_upstream(cid):
- acc = load_settings().get("router_access", {}).get(cid, {})
- ip = (acc.get("ttyd_ip") or acc.get("ssh_ip") or "").strip()
- if not ip:
- client = next((c for c in get_clients() if c.get("client_id") == cid), None)
- ip = (client or {}).get("tunnel_ip_v4", "").split("/")[0]
- port = str(acc.get("ttyd_port", "7681") or "7681")
- token = acc.get("ttyd_token", "")
- return ip, port, token
-
-
-def _ttyd_auth_header(token):
- import base64
- return "Basic " + base64.b64encode(("phobos:" + token).encode()).decode()
-
-
-@app.route("/ttyd//", defaults={"subpath": ""})
-@app.route("/ttyd//", methods=["GET", "POST"])
-@auth_required
-def ttyd_proxy(cid, subpath):
- import urllib.request, urllib.error
- ip, port, token = _ttyd_upstream(cid)
- if not ip:
- return ("ttyd: tunnel IP unknown", 502)
- url = f"http://{ip}:{port}/ttyd/{cid}/{subpath}"
- data = request.get_data() if request.method == "POST" else None
- req = urllib.request.Request(url, data=data, method=request.method,
- headers={"Authorization": _ttyd_auth_header(token)})
- try:
- r = urllib.request.urlopen(req, timeout=12)
- body = r.read()
- ct = r.headers.get("Content-Type", "text/html")
- return (body, r.status, {"Content-Type": ct})
- except urllib.error.HTTPError as e:
- return (e.read(), e.code, {"Content-Type": e.headers.get("Content-Type", "text/plain")})
- except Exception as e:
- return (f"ttyd proxy error: {e}", 502)
-
-
-if sock:
- @sock.route("/ttyd//ws")
- def ttyd_ws(ws, cid):
- import threading
- if not session.get("auth"): # WS routes bypass @auth_required — gate here
- return
- try:
- import websocket as _wsclient
- except Exception:
- ws.send("ttyd bridge: websocket-client not installed (phobos-update dev)\r\n")
- return
- ip, port, token = _ttyd_upstream(cid)
- if not ip:
- return
- try:
- up = _wsclient.create_connection(
- f"ws://{ip}:{port}/ttyd/{cid}/ws",
- header=["Authorization: " + _ttyd_auth_header(token)],
- subprotocols=["tty"], timeout=12)
- except Exception:
- return
- stop = {"v": False}
-
- def up_to_browser():
- try:
- while not stop["v"]:
- opcode, data = up.recv_data(True)
- if data is None:
- break
- ws.send(data if isinstance(data, (bytes, bytearray)) else data)
- except Exception:
- pass
- stop["v"] = True
-
- t = threading.Thread(target=up_to_browser, daemon=True)
- t.start()
- try:
- while not stop["v"]:
- msg = ws.receive(timeout=30)
- if msg is None:
- continue
- if isinstance(msg, (bytes, bytearray)):
- up.send_binary(msg)
- else:
- up.send(msg)
- except Exception:
- pass
- finally:
- stop["v"] = True
- try:
- up.close()
- except Exception:
- pass
-
-
-@app.route("/console/router/")
-@auth_required
-def ttyd_console(cid):
- ip, port, token = _ttyd_upstream(cid)
- ready = bool(ip and token)
- note = "" if ready else tr(
- "ttyd-терминал не настроен. Включи его кнопкой ниже (нужен запуск phobos-ttyd на роутере).",
- "ttyd terminal not configured. Enable it below (run phobos-ttyd on the router).")
- if ready:
- body = f''
- else:
- body = (f'{note}'
- f'')
- return render(f'''{nav('clients')}
-
- 🖥️ {tr("Терминал","Terminal")} {_html_attr(cid)} {hlp("Полноценный shell роутера в браузере через ttyd. Работает за NAT по WG-туннелю (без SSH). ttyd слушает только панель.", "Full router shell in the browser via ttyd. Works behind NAT over the WG tunnel (no SSH). ttyd is reachable only by the panel.")}
- {tr("Назад","Back")}
-
- {body}
- ''')
-
-
-@app.route("/console/router//enable", methods=["POST"])
-@auth_required
-def ttyd_enable(cid):
- import secrets
- s = load_settings()
- ra = s.setdefault("router_access", {})
- acc = ra.setdefault(cid, {})
- token = acc.get("ttyd_token") or secrets.token_hex(12)
- client = next((c for c in get_clients() if c.get("client_id") == cid), None)
- tip = acc.get("ttyd_ip") or acc.get("ssh_ip") or (client or {}).get("tunnel_ip_v4", "").split("/")[0]
- acc.update({"ttyd_token": token, "ttyd_ip": tip, "ttyd_port": acc.get("ttyd_port", "7681")})
- save_settings(s)
- srv_tip = server_tunnel_ip()
- panel = f"http://{srv_tip}:{request.host.split(':')[-1] if ':' in request.host else '8443'}"
- cmd = f"curl -fsSL {panel}/router/phobos-ttyd.sh | sh -s {cid} {token} {srv_tip}"
- return render(f'''{nav('clients')}
- ⌨️ {tr("Включение терминала","Enable terminal")} — {_html_attr(cid)}
- {tr("Выполни ОДНУ команду на роутере (SSH/консоль Entware) — поставит ttyd и откроет порт только для панели:","Run ONE command on the router (Entware SSH/console) — installs ttyd and opens the port only to the panel:")}
-
- {tr("После запуска вернись на страницу терминала — появится shell в браузере.","After running it, return to the terminal page — the browser shell appears.")}
- {tr("← к терминалу","← to terminal")}
- ''')
-
-
-@app.route("/router/phobos-ttyd.sh")
-def serve_ttyd_script():
- """Unauthenticated: routers fetch the ttyd setup script over the tunnel.
- Script carries no secrets (token passed as arg by the operator)."""
- for p in ("/opt/Phobos/repo/client/templates/phobos-ttyd.sh",
- "/opt/Phobos/www/phobos-ttyd.sh"):
- if os.path.exists(p):
- return (open(p).read(), 200, {"Content-Type": "text/x-shellscript"})
- return ("phobos-ttyd.sh not found", 404)
-
-
-@app.route("/")
-@auth_required
-def dashboard():
- return redirect(url_for("sessions_page"))
-
-
-@app.route("/sessions")
-@auth_required
-def sessions_page():
- s = load_settings()
- labels = s.get("labels", {})
- sessions = get_active_sessions()
- # Online = fresh handshake on ANY server (router may be on a backup)
- online_all = set()
- for _pub, _info in get_wg_peers().items():
- if is_peer_online(_info.get("latest handshake", "")):
- online_all.add(_pub)
- for _ip, _hs in server_handshakes_cache.items():
- for _pub, _ts in _hs.items():
- if _ts and (time.time() - _ts) < 180:
- online_all.add(_pub)
-
- rows = ""
- online_count = 0
- for sess in sessions:
- online = sess["public_key"] in online_all
- if online:
- online_count += 1
- status = 'Online' if online else 'Offline'
- real_ip = sess["real_ip"]
- label = labels.get(sess.get("tunnel_ip", ""), "") or labels.get(real_ip, "")
- disp = client_display_name(sess["client_id"], s)
- disp_html = html_lib.escape(disp)
- client_cell = disp_html if disp == sess["client_id"] else f'{disp_html}{sess["client_id"]}'
-
- rows += f"""
- {client_cell}
- {sess['tunnel_ip']}
- {real_ip}
- {('' + label + '') if label else '—'}
- {sess['handshake']}
- {sess['rx']} / {sess['tx']}
- {status}
- {tr("Отключить","Kick")}{hlp("Принудительно разорвать текущую сессию клиента (сбросить WG-пир). Клиент переподключится автоматически.","Force-drop the client current session (reset the WG peer). The client reconnects automatically.")}
- """
-
- if not rows:
- rows = '{tr("Нет активных сессий","No active sessions")} '
-
- html = f"""
-
- {nav('sessions', online_count)}
-
- {tr("Активные сессии","Active sessions")}
-
- Клиент VPN IP Real IP Метка Handshake RX / TX Статус
- {rows}
-
-
- """
- return render(html)
-
-
-@app.route("/kick/")
-@auth_required
-def kick(pub_key):
- kick_peer(pub_key)
- return redirect(url_for("sessions_page"))
-
-
-def _html_attr(value):
- return html_lib.escape(str(value or ""), quote=True)
-
-
-def _terminal_button(url, title):
- return (f'🖥️')
-
-
-@app.route("/clients", methods=["GET", "POST"])
-@auth_required
-def clients_page():
- s = load_settings()
- subs = s.get("subscriptions", {})
- msg = ""
-
- if request.method == "POST":
- action = request.form.get("action")
- if action == "add":
- name = request.form.get("name", "").strip()
- if name and re.match(r"^[a-zA-Z0-9_-]+$", name):
- ok, rep = create_client_cli(name)
- if ok:
- msg = f'{rep}'
- else:
- msg = f'{rep}'
- else:
- msg = 'Имя: буквы, цифры, _ и -'
-
- elif action == "delete":
- client_id = request.form.get("client_id", "").strip()
- if client_id:
- ok, rep = delete_client_cli(client_id)
- if ok:
- msg = f'{rep}'
- else:
- msg = f'{rep}'
-
- elif action == "purge_orphan":
- public_key = request.form.get("public_key", "").strip()
- ok, rep = purge_orphan_peer(public_key)
- msg = f'{rep}'
-
- elif action == "toggle_warp_client":
- client_id = request.form.get("client_id", "").strip()
- desired = request.form.get("desired", "").strip() == "on"
- if client_id:
- ok, rep = warp_toggle_client(client_id, desired)
- msg = f'{rep}'
-
- elif action == "toggle_warp_client":
- client_id = request.form.get("client_id", "").strip()
- desired = request.form.get("desired", "").strip() == "on"
- if client_id:
- ok, rep = warp_toggle_client(client_id, desired)
- msg = f'{rep}'
-
- elif action == "rename_client":
- client_id = request.form.get("client_id", "").strip()
- new_name = request.form.get("display_name", "").strip()
- if client_id:
- aliases = s.setdefault("client_aliases", {})
- if new_name:
- if not re.match(r"^[\w. -]{1,64}$", new_name):
- msg = f'{tr("Имя: буквы, цифры, пробел, _, -, точка.", "Name: letters, digits, space, _, -, dot.")}'
- else:
- aliases[client_id] = new_name
- save_settings(s)
- msg = f'{tr("Имя сохранено:", "Name saved:")} {html_lib.escape(new_name)}'
- else:
- aliases.pop(client_id, None)
- save_settings(s)
- msg = f'{tr("Псевдоним очищен.", "Alias cleared.")}'
-
- elif action == "toggle_notify":
- client_id = request.form.get("client_id", "").strip()
- if client_id:
- cn = s.setdefault("client_notify", {})
- cn[client_id] = not cn.get(client_id, True)
- save_settings(s)
- st = "вкл" if cn[client_id] else "выкл"
- msg = f'Уведомления {client_id}: {st}'
-
- elif action == "set_limit":
- client_id = request.form.get("client_id", "").strip()
- raw = request.form.get("limit_mbit", "").strip()
- if client_id and (raw == "" or raw.isdigit()):
- lim = s.setdefault("speed_limits", {})
- if raw in ("", "0"):
- lim.pop(client_id, None)
- else:
- lim[client_id] = int(raw)
- save_settings(s)
- ok, rep = apply_speed_limits()
- msg = f'{html_lib.escape(rep)}'
-
- elif action == "set_expiry":
- client_id = request.form.get("client_id", "").strip()
- expiry = request.form.get("expiry", "").strip()
- if client_id:
- if client_id not in subs:
- subs[client_id] = {}
- subs[client_id]["expiry"] = expiry
- subs[client_id].pop("locked", None)
- subs[client_id].pop("warn3", None)
- subs[client_id].pop("warn1", None)
- save_settings(s)
- msg = f'Срок для {client_id} обновлён'
-
- elif action == "push_config":
- client_id = request.form.get("client_id", "").strip()
- res = push_config_to_router(client_id)
- if res["status"] == "ok":
- msg = f'{res["msg"]}'
- else:
- msg = f'{client_id}: saved — router will pull config within ~2 min (SSH not needed for NAT routers)'
-
- elif action == "assign_server":
- client_id = request.form.get("client_id", "").strip()
- server_ip = request.form.get("server_ip", "").strip()
- if client_id and server_ip:
- # 1. Find client public key + tunnel IP for WG peer
- client_meta = None
- for c in get_clients():
- if c.get("client_id") == client_id:
- client_meta = c
- break
- errors = []
- # 2. Add WG peer on target server
- if client_meta:
- pub = client_meta.get("public_key", "")
- tip = client_meta.get("tunnel_ip_v4", "").split("/")[0]
- if pub and tip:
- allowed = f"{tip}/32"
- peer_res = add_peer_to_server(server_ip, pub, allowed)
- if peer_res.get("status") != "ok":
- errors.append(f"Peer add: {peer_res.get('msg', 'fail')}")
- # 3. Save assignment
- ca = s.get("client_assignments", {})
- ca[client_id] = server_ip
- s["client_assignments"] = ca
- save_settings(s)
- fanout_router_config(client_id) # push conf to all servers (tunnel pull)
- # 4. Router applies via pull (~15s). No synchronous SSH push:
- # NAT routers can't be reached, and the SSH attempt blocked
- # the click for seconds. Pull channel handles the apply.
- if errors:
- msg = f'{client_id} → {server_ip}: {"; ".join(errors)}'
- else:
- msg = f'{client_id} → {server_ip} ✓ (saved — router applies within ~15s)'
-
- clients = get_clients(include_orphans=True)
- peers = get_wg_peers()
- online_pubs = set()
- for pub, info in peers.items():
- if is_peer_online(info.get("latest handshake", "")):
- online_pubs.add(pub)
-
- all_srv = get_all_servers_ordered()
- assignments = s.get("client_assignments", {})
- assignments_notify = s.get("client_notify", {})
- aliases = s.get("client_aliases", {})
- warp_cfg = get_warp_settings(s)
- warp_enabled_clients = set(str(x).strip() for x in s.get("warp_clients", []) if str(x).strip())
- warp_state = warp_status()
- # Online = fresh handshake on ANY server (truthful during failover/transition)
- online_all = set(online_pubs)
- for _sv in all_srv:
- if _sv.get("ip") == SERVER_IP:
- continue
- for _pub, _ts in remote_handshakes(_sv["ip"]).items():
- if _ts and (time.time() - _ts) < 180:
- online_all.add(_pub)
-
- limits = s.get("speed_limits", {})
- rows = ""
- today = datetime.now().date()
- for c in clients:
- cid = c.get("client_id", "")
- disp = str(aliases.get(cid, "") or "").strip() or cid
- disp_input = _html_attr(aliases.get(cid, ""))
- disp_html = html_lib.escape(disp)
- pub = c.get("public_key", "")
- ip = c.get("tunnel_ip_v4", "")
- is_orphan = bool(c.get("_orphan"))
- created = c.get("created_at", "")[:10]
- is_online = pub in online_all
- status = 'Online' if is_online else 'Offline'
- if is_orphan:
- status += ' orphan'
-
- sub = subs.get(cid, {})
- expiry = sub.get("expiry", "")
- locked = sub.get("locked", False)
- expiry_badge = ""
- if expiry:
- try:
- exp_date = datetime.strptime(expiry, "%Y-%m-%d").date()
- days = (exp_date - today).days
- if locked:
- expiry_badge = 'expired'
- elif days <= 1:
- expiry_badge = f'{days}d'
- elif days <= 3:
- expiry_badge = f'{days}d'
- else:
- expiry_badge = f'{days}d'
- except ValueError:
- pass
-
- assigned_ip = assignments.get(cid, SERVER_IP)
- srv_opts = ""
- for sv in all_srv:
- sel = " selected" if sv["ip"] == assigned_ip else ""
- label = f'{sv["ip"]} (Primary)' if sv.get("is_primary") else sv["ip"]
- srv_opts += f''
-
- set_lbl = tr("Задать", "Set")
- h_set = hlp("Выбери сервер выхода для этого роутера и нажми «Задать». Роутер сам переключится за ~15 секунд. Кнопку Push нажимать НЕ нужно — конфигурация подтягивается автоматически.",
- "Pick the exit server for this router and press Set. The router switches itself within ~15 seconds. You do NOT need a Push button — the config is pulled automatically.")
- h_exp = hlp("Дата окончания подписки клиента. После этой даты клиент автоматически блокируется. Оставь пустым — без срока.",
- "Client subscription expiry date. After this date the client is locked automatically. Leave empty for no expiry.")
- h_del = hlp("Безвозвратно удалить клиента, его ключи и конфигурацию. Отменить нельзя.",
- "Permanently delete the client, its keys and config. Cannot be undone.")
- del_confirm = tr("Удалить " + cid + "?", "Delete " + cid + "?")
- _notify = assignments_notify.get(cid, True)
- notify_icon = "🔔" if _notify else "🔕"
- notify_bg = "#4f46e5" if _notify else "#64748b"
- notify_ttl = tr("Уведомления в Telegram включены — нажми, чтобы выключить", "Telegram notifications ON — click to turn off") if _notify else tr("Уведомления выключены — нажми, чтобы включить", "Notifications OFF — click to turn on")
- term_btn = ""
- if not is_orphan:
- term_btn = _terminal_button(f"/terminal/router/{cid}", tr("SSH терминал роутера", "Router SSH terminal"))
- rci_btn = (f'🛠️')
- tty_btn = (f'⌨️')
- term_btn = term_btn + " " + rci_btn + " " + tty_btn
- warp_on = cid in warp_enabled_clients
- warp_mode_ok = warp_cfg.get("mode") == "egress"
- warp_btn_bg = "#0f766e" if warp_on else "#475569"
- warp_btn_lbl = "WARP ON" if warp_on else "WARP OFF"
- warp_btn_title = tr("Индивидуальный WARP для этого клиента", "Per-client WARP for this client")
- if not warp_mode_ok:
- warp_btn_bg = "#334155"
- warp_btn_title = tr("Per-client WARP работает только в режиме egress", "Per-client WARP works only in egress mode")
- elif warp_state.get("service") != "active":
- warp_btn_title = tr("Сохранит выбор. Применится после включения WARP egress.", "Saves choice. Applies after WARP egress is enabled.")
- server_cell = f"""
-
- """
- expiry_cell = f"""
-
- """
- actions_cell = f"""
-
-
-
- 📱
- 🍎
- 📡
- {term_btn}
- {h_del}
- """
- if is_orphan:
- server_cell = f'{tr("Сиротский peer в wg0", "Orphan peer in wg0")} {hlp("Панель видит WireGuard peer и handshake, но папка клиента и metadata отсутствуют. Такое бывает после ручной чистки или старого бага. Можно оставить как есть, либо очистить peer кнопкой Purge.", "Panel sees live WireGuard peer and handshake, but client folder and metadata are missing. This can happen after manual cleanup or old bug. You can keep it, or remove peer with Purge button.")}'
- expiry_cell = '—'
- actions_cell = f"""
-
- {tr("Отключить", "Kick")}
-
- """
- client_cell = html_lib.escape(disp)
- if disp != cid:
- client_cell += f'{cid}'
- rename_box = f"""
-
- """
- lim = str(limits.get(cid, "") or "")
- rate = client_rates.get(pub)
- speed = (f'↓{rate[0]:.1f} ↑{rate[1]:.1f} {tr("Мбит/с","Mbit/s")}' if rate else "")
- limit_cell = "" if is_orphan else f"""
- """
- rows += f"""
- {client_cell} {ip} {status} {expiry_badge} {f'≤{_html_attr(lim)} Mbit' if lim and lim != "0" else ""} {speed}
- {server_cell}{expiry_cell}{limit_cell}{rename_box}
- {actions_cell}
- """
- if not rows:
- rows = f'{tr("Пока нет клиентов. Создай первого клиента выше.","No clients yet. Create first client above.")}
'
-
- page_html = f"""
-
- {nav('clients')}
- {msg}
-
- {tr("VPN-клиенты", "VPN Clients")}
-
- ⚡ {tr("Скорость на устройстве клиента (с включённым VPN)","Speed on the client device (VPN on)")}: http://{server_tunnel_ip()}:{panel_port()}/speedtest
- {rows}
-
- """
- return render(page_html)
-
-
-@app.route("/labels", methods=["GET", "POST"])
-@auth_required
-def labels_page():
- s = load_settings()
- msg = ""
- if request.method == "POST":
- action = request.form.get("action")
- if action == "add":
- ip = request.form.get("ip", "").strip()
- label = request.form.get("label", "").strip()
- if ip and label:
- s["labels"][ip] = label
- save_settings(s)
- msg = f'Метка добавлена: {ip} → {label}'
- elif action == "delete":
- ip = request.form.get("ip", "").strip()
- s["labels"].pop(ip, None)
- save_settings(s)
- msg = f'Метка удалена'
-
- labels = s.get("labels", {})
- rows = ""
- for ip, label in sorted(labels.items()):
- rows += f"""
- {ip} {label}
- """
-
- html = f"""
-
- {nav('labels')}
- {msg}
-
- {tr("Метки (по IP)","Labels (by IP)")} {hlp("Человекочитаемые имена для IP/туннелей — показываются в Сессиях вместо голого адреса.","Human-readable names for IPs/tunnels — shown in Sessions instead of the raw address.")}
- Привяжите понятное имя (квартира, офис, дача) к внешнему IP адресу роутера. Метка отображается в таблице сессий и в Telegram уведомлениях вместо голого IP.
-
-
- Real IP Метка
- {rows}
-
-
- """
- return render(html)
-
-
-@app.route("/settings", methods=["GET", "POST"])
-@auth_required
-def settings_page():
- s = load_settings()
- msg = ""
- if request.method == "POST" and request.form.get("action") in (
- "update", "rollback", "check", "save_token",
- "warp_save", "warp_enable", "warp_disable", "warp_status"
- ):
- _act = request.form.get("action")
- # subscriber token may be pasted in the version card -> persist for beta/dev
- _tok = request.form.get("gh_token", "").strip()
- if _tok:
- save_gh_token(_tok)
- warp_cfg = apply_warp_form(s)
- save_settings(s)
- if _act == "save_token":
- _out = tr("Токен подписчика сохранён. Теперь можно переключаться на beta/dev.",
- "Subscriber token saved. You can now switch to beta/dev.") if _tok else \
- tr("Поле токена пустое.", "Token field is empty.")
- elif _act == "warp_save":
- _out = tr("WARP настройки сохранены.", "WARP settings saved.")
- elif _act == "update":
- _out = run_update(request.form.get("target", "").strip() or "main")
- elif _act == "check":
- _out = run_update("--check")
- elif _act == "warp_enable":
- if warp_cfg["mode"] == "relay":
- _out = run_warp("enable", "relay", warp_cfg["profile_source"],
- warp_cfg["relay_ports"], warp_cfg["relay_target"])
- else:
- _out = run_warp("enable", "egress", warp_cfg["profile_source"])
- for _cid in [str(x).strip() for x in s.get("warp_clients", []) if str(x).strip()]:
- _cl = next((c for c in get_clients() if c.get("client_id") == _cid), None)
- _tip = ((_cl or {}).get("tunnel_ip_v4") or "").split("/")[0].strip()
- if _tip:
- run_warp("client-enable", _tip)
- elif _act == "warp_disable":
- _out = run_warp("disable")
- elif _act == "warp_status":
- _out = run_warp("status")
- else:
- _out = run_update("--rollback")
- s = load_settings()
- return render(f'''{nav("settings")}''')
- if request.method == "POST" and request.form.get("action") in (
- "domain_set", "domain_remove", "endpoints_save",
- "guard_enable", "guard_disable", "guard_update"
- ):
- _act = request.form.get("action")
- if _act == "domain_set":
- ok, _out = run_server_script("phobos-domain.sh", "set",
- request.form.get("domain", "").strip(),
- request.form.get("domain_email", "").strip(), timeout=300)
- elif _act == "domain_remove":
- ok, _out = run_server_script("phobos-domain.sh", "remove")
- elif _act == "endpoints_save":
- ok, _out = save_client_endpoints(request.form)
- else:
- ok, _out = run_server_script("phobos-guard.sh", _act.split("_", 1)[1], timeout=300)
- cls = "alert-ok" if ok else "alert-error"
- return render(f'''{nav("settings")}
- {tr("Результат", "Result")}
- {tr("Готово", "Done") if ok else tr("Ошибка", "Error")}
- {html_lib.escape(_out)}
- {tr("← к настройкам", "← back to settings")}''')
- if request.method == "POST" and request.form.get("action") == "save_obf":
- masking = request.form.get("obf_masking", "AUTO").strip().upper()
- if masking not in ("AUTO", "STUN", "NONE"):
- masking = "AUTO"
- s["obf_params"] = {
- "masking": masking,
- "max_dummy": request.form.get("obf_max_dummy", "4").strip() or "4",
- "idle": request.form.get("obf_idle", "300").strip() or "300",
- }
- save_settings(s)
- pushed = 0
- for c in get_clients():
- try:
- fanout_router_config(c.get("client_id", ""))
- pushed += 1
- except Exception:
- pass
- msg = f'{tr("Параметры обфускатора сохранены и отправлены на роутеры", "Obfuscator params saved and pushed to routers")} ({pushed})'
- elif request.method == "POST" and request.form.get("action") == "save_srv_obf":
- masking = request.form.get("srv_masking", "AUTO").strip().upper()
- if masking not in ("AUTO", "STUN", "NONE"):
- masking = "AUTO"
- try:
- dummy = str(min(255, max(0, int(request.form.get("srv_max_dummy", "50")))))
- idle = str(min(3600, max(10, int(request.form.get("srv_idle", "300")))))
- except ValueError:
- dummy, idle = "50", "300"
- ports = write_server_obf({"masking": masking, "max-dummy": dummy, "idle-timeout": idle})
- msg = f'{tr("Серверный обфускатор перезапущен с новыми параметрами, порты", "Server obfuscator restarted with new params, ports")}: {", ".join(ports) or "—"}'
- elif request.method == "POST":
- new_pass = request.form.get("admin_pass", "").strip()
- if new_pass:
- s["admin_pass"] = new_pass
- s["tg_bot_token"] = request.form.get("tg_bot_token", "").strip()
- s["tg_chat_id"] = request.form.get("tg_chat_id", "").strip()
- try:
- s["monitor_interval"] = max(10, int(request.form.get("monitor_interval", 30)))
- except ValueError:
- pass
- save_settings(s)
- msg = 'Настройки сохранены'
-
- warp_cfg = get_warp_settings(s)
- custom_warp_profile = read_custom_warp_profile()
- warp_license_key = read_warp_license_key()
- warp = warp_status()
- srv_obf = read_server_obf()
- warp_service = warp.get("service", "unknown")
- warp_state = tr("включён", "enabled") if warp.get("enabled") else tr("выключен", "disabled")
- warp_subnet = _html_attr(warp.get("subnet", server_wg_network()))
- warp_endpoint = _html_attr(warp.get("endpoint", ""))
- warp_egress = _html_attr(warp.get("egress_ipv4", ""))
- warp_error = _html_attr(warp.get("error", ""))
- warp_mode = _html_attr(warp.get("mode", warp_cfg.get("mode", "egress")))
- warp_profile_source = _html_attr(warp.get("profile_source", warp_cfg.get("profile_source", "free")))
- warp_relay_ports = _html_attr(warp.get("relay_ports", warp_cfg.get("relay_ports", "4500")))
- warp_relay_target = _html_attr(warp.get("relay_target", warp_cfg.get("relay_target", "")))
- warp_client_count = len(warp.get("clients", [])) if isinstance(warp.get("clients", []), list) else len(s.get("warp_clients", []))
- custom_profile_saved = bool(warp.get("custom_profile_saved")) or bool(custom_warp_profile.strip())
- warp_license_saved = bool(warp.get("license_key_saved")) or bool(warp_license_key.strip()) or bool(warp_cfg.get("license_key", "").strip())
-
- dom = script_status("phobos-domain.sh")
- guard = script_status("phobos-guard.sh")
- dom_q = tr("Убрать домен?", "Remove domain?")
- dom_remove = (f''
- if dom.get("domain") else "")
- eps = s.get("endpoints", {})
- ep_rows = "".join(
- f''
- f''
- for sv in get_all_servers_ordered())
- _cu = f"{panel_base_url()}/server/phobos-cascade.sh"
- cascade_cmd = f"SELF_URL={_cu} bash <(curl -kfsSL {_cu}) enable {SERVER_IP} {_load_server_env().get('OBFUSCATOR_PORTS', '2083,5443,993')}"
- extras_html = f"""
-
- {tr("Домен панели","Panel domain")} {hlp("Панель по адресу https://ваш-домен/ с бесплатным сертификатом Let's Encrypt (nginx на 443). Домен (A-запись) должен указывать на IP этого сервера, порт 80 открыт. Старый адрес http://IP:порт продолжает работать — роутеры и второй сервер ничего не заметят.", "Panel at https://your-domain/ with a free Let's Encrypt certificate (nginx on 443). The domain A record must point to this server, port 80 open. The old http://IP:port keeps working — routers and secondaries notice nothing.")}
- {f'{tr("Сейчас","Now")}: https://{_html_attr(dom.get("domain"))}/ · {tr("сертификат до","certificate until")} {_html_attr(dom.get("cert_expires") or "—")}
' if dom.get("domain") else f'{tr("Домен не задан.","No domain set.")}
'}
-
- {dom_remove}
-
-
-
- {tr("Адрес для клиентов и каскад","Client address & cascade")} {hlp("Куда подключаются клиенты для каждого сервера. Пусто = IP сервера. Можно вписать домен (A-запись на сервер) — сменится IP, поменяешь только DNS. Каскад: поставь на входной VPS (например, в РФ) ретранслятор командой ниже и впиши сюда IP/домен этого входа — клиенты пойдут вход → этот сервер. Роутеры получат новый адрес сами через pull (~15 с), телефонам нужно заново открыть ссылку/QR.", "Which host clients dial for each server. Empty = server IP. Put a domain (A record) to survive IP changes. Cascade: install the relay on an entry VPS with the command below and put that entry IP/domain here — clients go entry -> this server. Routers get it via pull (~15s); phones must reopen the link/QR.")}
-
- {tr("Каскад — выполни на входном VPS (чистый Debian/Ubuntu, root):","Cascade — run on the entry VPS (clean Debian/Ubuntu, root):")}
- {cascade_cmd}
- {tr("Отключить: phobos-cascade disable · статус: phobos-cascade status. iOS/обычный WireGuard (порт 51820) через каскад не идёт.","Disable: phobos-cascade disable · status: phobos-cascade status. iOS/plain WireGuard (port 51820) does not go through the cascade.")}
-
-
-
- {tr("Защита сервера (сторож)","Server protection (guard)")} {hlp("Блокирует подсети зондов и сканеров РКН до того, как они дойдут до сервера (nftables). Список IP — из проекта Loorrr293/Auto_IPtables, обновляется раз в сутки. Частные сети (LAN, туннель) никогда не блокируются.", "Drops RKN probe/scanner subnets before they reach the server (nftables). IP list from Loorrr293/Auto_IPtables, refreshed daily. Private networks (LAN, tunnel) are never blocked.")}
- {tr("Статус","Status")}: {tr("включён","enabled") if guard.get("enabled") else tr("выключен","disabled")}
- · {tr("подсетей","networks")}: {guard.get("networks", 0)} · {tr("отброшено пакетов","dropped packets")}: {guard.get("dropped_packets", 0)}
-
-
-
-
-
- {tr("«Прикрывашка» (WARP на выход + Psiphon, автор miha75vu-bit/Flashkeen) — интерактивная, ставится по SSH: bash <(curl -fsSL https://raw.githubusercontent.com/miha75vu-bit/Flashkeen/main/wp). Она перестраивает выход wg0 — не включай одновременно со встроенным WARP egress ниже.","“Prikryvashka” (WARP egress + Psiphon by miha75vu-bit/Flashkeen) is interactive, run it over SSH: bash <(curl -fsSL https://raw.githubusercontent.com/miha75vu-bit/Flashkeen/main/wp). It rebuilds wg0 egress — do not combine with the built-in WARP egress below.")}
-
-"""
-
- html = f"""
-
- {nav('settings')}
- {msg}
-
- {tr("Настройки панели","Panel settings")}
-
-
- {extras_html}
-
-
- {tr("Версия и обновления","Version & updates")} {hlp("Скачивает свежие файлы PCA-слоя (панель + скрипты) с GitHub и перезапускает панель. Ключи WireGuard, server.env и клиенты НЕ трогаются. Пусто или main = последняя версия; можно указать тег (например v1.1.0). Откат восстанавливает предыдущую версию из автоматического бэкапа.", "Fetches the latest PCA files (panel + scripts) from GitHub and restarts the panel. WireGuard keys, server.env and clients are NOT touched. Empty or main = latest; you can pass a tag (e.g. v1.1.0). Rollback restores the previous version from an automatic backup.")}
- {tr("Установленная версия","Installed version")}: {panel_version()}
- {tr("Каналы","Channels")}:
- stable — {tr("стабильная","stable")} ·
- beta — {tr("тест","testing")} ·
- dev — {tr("разработка","development")}.
- {tr("С 1.4.0 все каналы открыты и берутся с git.bobyrev.com (GitHub — запасной). Токен больше не нужен.","Since 1.4.0 all channels are open and served from git.bobyrev.com (GitHub as fallback). No token needed.")}
-
-
-
-
-
-
-
-
-
-
-
-
- {tr("Бэкап и восстановление","Backup & restore")} {hlp("Полный бэкап состояния сервера: ключ WireGuard, server.env, все клиенты и ключи, токены, настройки панели (метки, назначения, доступы, токен подписчика). НЕ включает бинарники/пакеты. Восстановление на чистом VPS: сначала turnkey-установка, потом загрузи бэкап здесь — ключ сервера вернётся, клиенты переподключатся без пересоздания. ВНИМАНИЕ: файл содержит приватные ключи — храни в защищённом месте.", "Full server state backup: WireGuard key, server.env, all clients and keys, tokens, panel settings (labels, assignments, access, subscriber token). Excludes binaries/packages. Restore on a clean VPS: run the turnkey install first, then upload the backup here — the server key returns and clients reconnect without recreation. WARNING: the file contains private keys — store it securely.")}
- ⚠ {tr("Файл содержит приватные ключи. Храни в защищённом месте.","File contains private keys. Store it securely.")}
- ⬇ {tr("Скачать бэкап","Download backup")}
-
-
-
-
- {tr("Обфускация (маскировка)","Obfuscation (masking)")} {hlp("Параметры wg-obfuscator. masking: AUTO (адаптивно), STUN (под STUN-трафик), NONE (без маскировки). max-dummy — добавочные мусорные байты. idle — таймаут простоя (сек). Сохранение отправляет параметры на ВСЕ роутеры по pull-каналу — применяются за ~15 сек без перевыдачи конфига. Серверный обфускатор остаётся AUTO и принимает любой клиентский режим.", "wg-obfuscator params. masking: AUTO (adaptive), STUN (mimic STUN), NONE (no masking). max-dummy — extra junk bytes. idle — idle timeout (s). Saving pushes the params to ALL routers over the pull channel — applied in ~15s without re-issuing configs. The server obfuscator stays AUTO and accepts any client mode.")}
-
-
-
-
- {tr("Обфускатор сервера","Server obfuscator")} {hlp("Параметры wg-obfuscator на ЭТОМ сервере (все порты). masking: AUTO принимает любой режим клиента — менять, только если знаете зачем; STUN/NONE — клиенты должны работать в том же режиме. max-dummy — мусорные байты в ответах, idle — таймаут простоя (сек). Сохранение перезапускает обфускатор: клиенты переподключатся за пару секунд.", "wg-obfuscator params on THIS server (all ports). masking: AUTO accepts any client mode — change only if you know why; with STUN/NONE clients must use the same mode. max-dummy — junk bytes in replies, idle — idle timeout (s). Saving restarts the obfuscator: clients reconnect within seconds.")}
-
-
-
-
- {tr("Информация о сервере","Server info")}
-
- VPS IP {SERVER_IP}
- {tr("WireGuard порт","WireGuard port")} 51820 (localhost)
- {tr("Порты обфускатора","Obfuscator ports")} {_load_server_env().get('OBFUSCATOR_PORTS', '2083,5443,993')}
- {tr("Адрес панели","Panel URL")} {panel_base_url()}
- {tr("Порт панели","Panel port")} {panel_port()}
- {tr("Протокол панели","Panel protocol")} {panel_scheme().upper()}
- {tr("Клиенты Phobos","Phobos clients")} {CLIENTS_DIR}
-
-
-
-
- WARP / WARP+ {hlp("Этот блок нужен для двух разных задач. Первая: отправить весь исходящий трафик клиентов Phobos через Cloudflare WARP. Вторая: открыть на сервере отдельные UDP relay-порты и перекинуть их на endpoint WARP/WARP+. Ниже можно выбрать режим, источник профиля и при желании вставить WARP+ key или полный custom WireGuard профиль.", "This block handles two different jobs. First: send all Phobos client egress through Cloudflare WARP. Second: open dedicated UDP relay ports on this server and forward them to WARP/WARP+ endpoint. Below you can choose mode, profile source, and optionally paste WARP+ key or full custom WireGuard profile.")}
- {tr("Как это работает: выбираешь режим, заполняешь только нужные поля, жмёшь «Сохранить WARP настройки», потом «Enable selected mode». В каждый момент активен один режим: либо egress, либо relay. Кнопка Disable выключает текущий режим и убирает его правила.", "How it works: choose mode, fill only fields you need, press 'Save WARP settings', then 'Enable selected mode'. Only one mode is active at a time: either egress or relay. Disable turns current mode off and removes its rules.")}
-
- {tr("Статус","Status")} {warp_state} ({_html_attr(warp_service)})
- {tr("Режим","Mode")} {warp_mode} {hlp("egress включает интерфейс warp и меняет исходящий маршрут для подсети клиентов Phobos. relay не меняет интернет-выход клиентов, а только открывает UDP relay-порты на этом сервере.", "egress brings up warp interface and changes egress route for Phobos client subnet. relay does not change client internet egress; it only opens UDP relay ports on this server.")}
- {tr("Источник профиля","Profile source")} {warp_profile_source} {hlp("free — профиль собирается через wgcf. Если сохранён WARP+ key, он применяется к wgcf-аккаунту. custom — используется твой готовый WireGuard профиль, который вставлен ниже.", "free — profile is built through wgcf. If WARP+ key is saved, it is applied to wgcf account. custom — uses your ready WireGuard profile pasted below.")}
- {tr("Подсеть клиентов","Client subnet")} {warp_subnet}
- Endpoint {warp_endpoint or '—'}
- {tr("Relay ports","Relay ports")} {warp_relay_ports or '—'}
- {tr("Relay target","Relay target")} {warp_relay_target or '—'}
- {tr("Что именно включается","What gets enabled")} {tr("Только выбранный режим. Одновременно egress и relay не держатся.", "Only selected mode. egress and relay are not kept active together.")} {hlp("Если сейчас активен egress и ты включаешь relay, старый egress будет выключен и заменён relay. И наоборот.", "If egress is active and you enable relay, old egress is turned off and replaced by relay. Same in reverse.")}
- {tr("По отдельным клиентам","Per-client control")} {tr("Да, через кнопки WARP ON/OFF в списке клиентов.", "Yes, via WARP ON/OFF buttons in client list.")} ({warp_client_count}) {hlp("В режиме egress WARP можно включать точечно по клиентам. Панель запоминает выбор и применяет правила по tunnel IP клиента. В relay режиме эти кнопки не работают.", "In egress mode WARP can be enabled per client. Panel remembers the choice and applies rules by client tunnel IP. These buttons do not work in relay mode.")}
- {tr("WARP+ key","WARP+ key")} {tr("сохранён","saved") if warp_license_saved else tr("не задан","not set")}
- {tr("Custom profile","Custom profile")} {tr("сохранён","saved") if custom_profile_saved else tr("не задан","not set")}
- {tr("Egress IPv4","Egress IPv4")} {warp_egress or '—'}
-
-
- {tr("Коротко: egress поднимает WARP на сервере, а дальше ты сам включаешь WARP точечно по клиентам кнопками WARP ON/OFF в разделе клиентов. relay нужен, когда нужен отдельный UDP вход на этом сервере с переадресацией в WARP/WARP+. Relay — это сценарий для отдельного WARP/WireGuard профиля, а не для штатного Phobos home.conf.", "Short version: egress brings WARP up on server, then you enable it per client with WARP ON/OFF buttons in client list. relay is for dedicated UDP entrypoint on this server forwarded into WARP/WARP+. Relay is for separate WARP/WireGuard profile, not for standard Phobos home.conf.")}
-
-
-
-
-
- {f'{warp_error}
' if warp_error else ''}
-
-
-
- {tr("Установка на роутер","Router install")}
- {tr("Keenetic/Netcraze с Entware — выполнить по SSH на роутере:","Keenetic/Netcraze with Entware — run over SSH on the router:")}
- {_render_install_commands()}
-
- """
- return render(html)
-
-
-TOKENS_FILE = f"{PHOBOS_DIR}/tokens/tokens.json"
-
-
-def _render_install_commands():
- """Read tokens and render install commands for each client."""
- try:
- if os.path.exists(TOKENS_FILE):
- with open(TOKENS_FILE) as f:
- tokens = json.load(f)
- else:
- tokens = []
- except Exception:
- tokens = []
-
- if not tokens:
- return 'Нет активных токенов. Добавьте клиента.
'
-
- port = panel_port()
- lines = ""
- for t in tokens:
- client = t.get("client", "?")
- token = t.get("token", "")
- expires = t.get("expires", 0)
- exp_str = datetime.fromtimestamp(expires).strftime("%Y-%m-%d %H:%M") if expires else "?"
- cmd = install_command(token, port)
- lines += f"""
-
- {client}
- (до {exp_str})
-
- {cmd}
-
-
- """
- uninstall_cmd = "/opt/etc/Phobos/phobos-uninstall.sh"
- lines += f"""
-
- {tr("Удалить с роутера", "Remove from router")}
- ({tr("общая команда для всех клиентов", "same command for all clients")})
-
- {uninstall_cmd}
-
-
- """
- return lines
-
-
-SERVERS_FILE = f"{PANEL_DIR}/servers.json"
-
-
-def load_servers():
- if os.path.exists(SERVERS_FILE):
- with open(SERVERS_FILE) as f:
- return json.load(f)
- return []
-
-
-def save_servers(servers):
- with open(SERVERS_FILE, "w") as f:
- json.dump(servers, f, indent=2)
-
-
-def panel_port():
- try:
- return open(os.path.join(PANEL_DIR, ".port")).read().strip() or "8443"
- except Exception:
- return "8443"
-
-
-def panel_scheme():
- scheme = (os.environ.get("PANEL_SCHEME") or "").strip().lower()
- if scheme in ("http", "https"):
- return scheme
- try:
- scheme = open(os.path.join(PANEL_DIR, ".scheme")).read().strip().lower()
- if scheme in ("http", "https"):
- return scheme
- except Exception:
- pass
- return "http"
-
-
-def panel_base_url(host=None):
- return f"{panel_scheme()}://{host or SERVER_IP}:{panel_port()}"
-
-
-def _server_api_key_candidates(server):
- keys = []
- for key in (server.get("api_key", ""), load_settings().get("server_api_key", "")):
- if key and key not in keys:
- keys.append(key)
- return keys
-
-
-def _remember_server_api_key(ip, api_key):
- if not ip or not api_key:
- return
- servers = load_servers()
- changed = False
- for srv in servers:
- if srv.get("ip") == ip and srv.get("api_key") != api_key:
- srv["api_key"] = api_key
- changed = True
- if changed:
- save_servers(servers)
-
-
-def secondary_api_request(server, path, data=None, timeout=10):
- import urllib.error
- import urllib.request
- headers = {"Content-Type": "application/json"}
- body = json.dumps(data).encode() if data is not None else None
- last_error = None
- for key in _server_api_key_candidates(server):
- headers["X-API-Key"] = key
- try:
- req = urllib.request.Request(
- f"http://{server['ip']}:8444{path}",
- data=body,
- headers=headers,
- method="POST" if body is not None else "GET",
- )
- resp = urllib.request.urlopen(req, timeout=timeout)
- _remember_server_api_key(server.get("ip", ""), key)
- server["api_key"] = key
- return json.loads(resp.read())
- except urllib.error.HTTPError as e:
- last_error = e
- if e.code in (401, 403):
- continue
- raise
- if last_error:
- raise last_error
- raise RuntimeError("no API key for secondary server")
-
-
-def install_command(token, port=None):
- port = port or panel_port()
- primary = f"{panel_scheme()}://{SERVER_IP}:{port}/init/{token}.sh"
- urls = [primary, f"http://{SERVER_IP}/init/{token}.sh"]
- return ("p=/tmp/phobos-init-$$.sh; ok=0; "
- f"for u in {' '.join(urls)}; do "
- "rm -f $p; "
- "(wget -q -O $p $u || wget --no-check-certificate -q -O $p $u || curl -kfsSL -o $p $u || curl -fsSL -o $p $u) 2>/dev/null || continue; "
- "head -c 2 $p | grep -q \"#!\" || continue; "
- "sh $p && ok=1 && break; "
- "done; rm -f $p; [ $ok -eq 1 ] || echo ERROR_install_script_download_failed")
-
-
-@app.route("/init/")
-def serve_init(name):
- return send_from_directory(f"{PHOBOS_DIR}/www/init", name, mimetype="application/x-sh")
-
-
-@app.route("/packages/")
-def serve_package(name):
- return send_from_directory(f"{PHOBOS_DIR}/www/packages", name, mimetype="application/octet-stream")
-
-
-_SPEED_CHUNK = os.urandom(1 << 20)
-_speed_busy = set()
-
-
-@app.route("/speedtest")
-def speedtest_page():
- """Public: a VPN client opens http://10.25.0.1:/speedtest on its device
- to measure real device <-> server speed through the tunnel."""
- return f"""
-Phobos speed test
-
-🛡️ Phobos — {tr("скорость до сервера", "speed to server")}
-ping—
-↓ {tr("Мбит/с", "Mbit/s")}—
-↑ {tr("Мбит/с", "Mbit/s")}—
-
-{tr("Открой эту страницу на устройстве с включённым VPN по адресу туннеля — так замеряется реальный канал до сервера.", "Open this page on a device with VPN on, via the tunnel address — this measures the real path to the server.")}
-"""
-
-
-@app.route("/speedtest/down")
-def speedtest_down():
- try:
- mb = max(0, min(100, int(request.args.get("mb", "10"))))
- except ValueError:
- mb = 10
- ip = request.remote_addr or "?"
- if mb and ip in _speed_busy:
- return ("busy", 429)
-
- def gen():
- _speed_busy.add(ip)
- try:
- for _ in range(mb):
- yield _SPEED_CHUNK
- finally:
- _speed_busy.discard(ip)
- return app.response_class(gen(), mimetype="application/octet-stream",
- headers={"Cache-Control": "no-store", "Content-Length": str(mb << 20)})
-
-
-@app.route("/speedtest/up", methods=["POST"])
-def speedtest_up():
- n = 0
- stream = request.stream
- while n < (100 << 20):
- chunk = stream.read(1 << 16)
- if not chunk:
- break
- n += len(chunk)
- return {"bytes": n}
-
-
-@app.route("/server/")
-def serve_server_bootstrap(name):
- # Public bootstrap files only. No secrets live in these scripts.
- if name not in ("secondary-setup.sh", "api.py", "update.sh", "phobos-limit.sh", "phobos-speedtest.sh",
- "phobos-cascade.sh"):
- return ("not found", 404)
- mimetype = "application/x-sh" if name.endswith(".sh") else "text/plain"
- return send_from_directory(f"{PHOBOS_DIR}/server", name, mimetype=mimetype)
-
-
-def get_main_server_info():
- env = _load_server_env()
- return {
- "ip": SERVER_IP,
- "ports": env.get("OBFUSCATOR_PORTS", "2083,5443,993"),
- "obfuscator_key": env.get("OBFUSCATOR_KEY", ""),
- "is_primary": True
- }
-
-
-def get_all_servers_ordered():
- s = load_settings()
- servers = load_servers()
- main_info = get_main_server_info()
- order = s.get("server_order", [])
-
- by_ip = {}
- by_ip[main_info["ip"]] = {"ip": main_info["ip"], "ports": main_info["ports"],
- "obfuscator_key": main_info["obfuscator_key"], "is_primary": True}
- for srv in servers:
- by_ip[srv["ip"]] = {**srv, "is_primary": False}
-
- if not order or main_info["ip"] not in order:
- order = [main_info["ip"]] + [sv["ip"] for sv in servers]
-
- result = []
- for ip in order:
- if ip in by_ip:
- result.append(by_ip[ip])
- for ip, sv in by_ip.items():
- if ip not in order:
- result.append(sv)
- return result
-
-
-def check_server_health(server):
- """Check secondary server health via API."""
- try:
- return secondary_api_request(server, "/api/health", timeout=5)
- except Exception as e:
- return {"status": "error", "error": str(e)}
-
-
-def sync_peer_to_server(server, public_key, allowed_ips, action="add"):
- """Add or remove peer on secondary server."""
- try:
- return secondary_api_request(server, f"/api/peers/{action}", {
- "public_key": public_key, "allowed_ips": allowed_ips
- }, timeout=10)
- except Exception as e:
- return {"status": "error", "msg": str(e)[:200]}
-
-
-def sync_peer_to_all_servers(public_key, allowed_ips, action="add"):
- """Sync peer to all secondary servers."""
- servers = load_servers()
- for srv in servers:
- if srv.get("enabled", True):
- sync_peer_to_server(srv, public_key, allowed_ips, action)
-
-
-def sync_missing_peers_to_secondaries(server=None):
- """Best-effort peer repair: every secondary must already know every client.
- Router failover can only work if the target server has the client's WG peer.
- """
- servers = [server] if server else [srv for srv in load_servers() if srv.get("enabled", True)]
- clients = get_clients()
- synced = 0
- for srv in servers:
- health = check_server_health(srv)
- if health.get("status") not in ("ok", None):
- continue
- remote_keys = set(health.get("peer_keys", []) or [])
- for c in clients:
- pub = c.get("public_key", "")
- tip = (c.get("tunnel_ip_v4") or "").split("/")[0]
- if not pub or not tip or pub in remote_keys:
- continue
- res = sync_peer_to_server(srv, pub, f"{tip}/32", "add")
- if res.get("status") == "ok":
- synced += 1
- remote_keys.add(pub)
- return synced
-
-
-@app.route("/download/apk")
-@auth_required
-def download_apk():
- """PhobosWG APK: local copy if the server has one, else the release on Gitea."""
- local = "/opt/Phobos/www/app/PhobosWG.apk"
- if os.path.exists(local):
- from flask import send_file
- return send_file(local, as_attachment=True, download_name="PhobosWG.apk",
- mimetype="application/vnd.android.package-archive")
- return redirect(f"{PCA_GIT}/releases/download/{APK_TAG}/PhobosWG.apk")
-
-
-@app.route("/client//conf/")
-@auth_required
-def client_conf_download(cid, mode):
- m = "ios" if mode == "ios" else "android"
- if m == "android":
- return ("Android/PhobosWG uses phobos:// QR/link import; .conf import is only valid for iOS/plain WireGuard.", 400)
- conf, _link = build_phone_config(cid, m)
- if conf is None:
- return ("client not found", 404)
- if m == "android":
- conf = _pad_conf_with_none(conf)
- return (conf, 200, {
- "Content-Type": "text/plain; charset=utf-8",
- "Content-Disposition": 'attachment; filename="%s-%s.conf"' % (cid, m),
- })
-
-
-@app.route("/client//phone/")
-@auth_required
-def client_phone(cid, mode):
- if mode not in ("android", "ios"):
- mode = "android"
- conf, link = build_phone_config(cid, mode)
- if conf is None:
- return ("client not found", 404)
- qr = qr_datauri(link if (mode == "android" and link) else conf)
- if mode == "android":
- title = tr("Android — PhobosWG (с обфускацией)", "Android — PhobosWG (obfuscated)")
- apk_btn = ""
- _apk_local = "/opt/Phobos/www/app/PhobosWG.apk"
- if os.path.exists(_apk_local):
- apk_btn = (f'📥 {tr("Скачать приложение PhobosWG (APK)","Download PhobosWG app (APK)")}
')
- else:
- _gh_token = ""
- try:
- _gh_token = open("/opt/phobos-panel/.gh_token").read().strip()
- except Exception:
- pass
- if _gh_token:
- apk_btn = (f'📥 {tr("Скачать PhobosWG (APK)","Download PhobosWG (APK)")}'
- f'{tr("с GitHub","from GitHub")}
')
- else:
- apk_btn = (f'📥 {tr("Скачать PhobosWG (APK)","Download PhobosWG (APK)")}
')
- client_btn = (f''
- f'{tr("Поставь любое из двух приложений и открой ссылку ниже на телефоне — профиль импортируется сам.","Install either app and open the link below on the phone — the profile imports itself.")}
')
- extra = (client_btn + apk_btn +
- f'{tr("phobos:// ссылка — импорт в PCA Phobos VPN или PhobosWG:", "phobos:// link — import into PCA Phobos VPN or PhobosWG:")} {tr("открыть", "open")}
'
- f'')
- else:
- title = tr("iPhone / iOS WireGuard (без обфускации)", "iPhone / iOS WireGuard (plain, no obfuscation)")
- extra = (f'📥 {tr("WireGuard в App Store","WireGuard on the App Store")} ⬇ {tr("Скачать .conf","Download .conf")}
'
- f'{tr("⚠ Обычный WireGuard без маскировки (Endpoint → :51820). На сервере должен быть открыт порт 51820 (ALLOW_PLAIN_WG=1).", "⚠ Plain WireGuard, no obfuscation (Endpoint → :51820). Port 51820 must be open on the server (ALLOW_PLAIN_WG=1).")}
')
- html = f"""
-
- {nav('clients')}
-
- {cid} — {title}
- 
- {tr("Отсканируй QR в приложении или импортируй конфиг:", "Scan the QR in the app or import the config:")}
- {extra}
-
-
- """
- return render(html)
-
-
-@app.route("/api/router-config/")
-def router_config(client_id):
- """NAT-friendly config pull: router fetches its own failover.conf.
- Auth via per-client pull_token (falls back to server_api_key)."""
- st = load_settings()
- token = request.args.get("token", "")
- acc = st.get("router_access", {}).get(client_id, {})
- expected = acc.get("pull_token", "") or st.get("server_api_key", "")
- if not expected or token != expected:
- return ("forbidden", 403)
- conf = generate_failover_conf_for_client(client_id)
- return (conf, 200, {"Content-Type": "text/plain; charset=utf-8"})
-
-
-@app.route("/client//router-config")
-@auth_required
-def client_router_config(cid):
- if not any(c.get("client_id") == cid for c in get_clients()):
- return ("client not found", 404)
- token = _latest_token_for_client(cid)
- cmd = install_command(token) if token else ""
- title = tr("Установка на роутер", "Router install")
- copy = tr("Копировать", "Copy")
- copied = tr("Скопировано", "Copied")
- body = (f"""
- {tr("Одна команда для вставки в SSH роутера.", "One command to paste into router SSH.")}
-
- {cmd}
-
-
- """ if cmd else f'{tr("Нет активной команды установки. Создай/обнови клиента, чтобы выпустить install token.", "No active install command. Create/update the client to issue an install token.")}
')
- html = f"""
-
- {nav('clients')}
-
- {cid} — {title}
- {body}
-
- """
- return render(html)
-
-
-# ── Keenetic RCI console (KeenDNS, ndm-challenge auth) ──────────────────────
-# Keenetic routers behind NAT don't accept SSH (neither WAN nor WG tunnel).
-# Control them via RCI over KeenDNS HTTPS: ndmc CLI commands -> POST /rci/.
-# Auth: sha256(challenge + md5(login:realm:password)) (ndm challenge).
-def _rci_base(cid):
- acc = load_settings().get("router_access", {}).get(cid, {})
- url = (acc.get("web_url") or "").strip()
- if not url:
- return None, None, None
- if not url.startswith("http"):
- url = "https://" + url
- return url.rstrip("/"), (acc.get("web_login") or "admin"), (acc.get("web_pass") or "")
-
-
-def _rci_run(cid, command):
- """Run a ndmc CLI command on a Keenetic router via RCI/KeenDNS.
- Returns (ok, text)."""
- import urllib.request, urllib.error, ssl, json as _json, http.cookiejar, hashlib
- base, login, pwd = _rci_base(cid)
- if not base:
- return False, "Не задан web-адрес роутера (Настройки → Доступ к роутерам → KeenDNS URL)."
- ctx = ssl.create_default_context(); ctx.check_hostname = False; ctx.verify_mode = ssl.CERT_NONE
- cj = http.cookiejar.CookieJar()
- op = urllib.request.build_opener(urllib.request.HTTPSHandler(context=ctx),
- urllib.request.HTTPCookieProcessor(cj))
- try:
- op.open(base + "/auth", timeout=12) # already authed (cookie) or 200
- except urllib.error.HTTPError as e:
- if e.code != 401:
- return False, f"auth error: HTTP {e.code}"
- realm = e.headers.get("X-NDM-Realm", ""); ch = e.headers.get("X-NDM-Challenge", "")
- if not realm or not ch:
- return False, "auth: no challenge headers"
- md5 = hashlib.md5(f"{login}:{realm}:{pwd}".encode()).hexdigest()
- sha = hashlib.sha256(f"{ch}{md5}".encode()).hexdigest()
- body = _json.dumps({"login": login, "password": sha}).encode()
- req = urllib.request.Request(base + "/auth", data=body,
- headers={"Content-Type": "application/json"})
- try:
- op.open(req, timeout=12)
- except Exception as ex:
- return False, f"auth failed (проверь логин/пароль web-панели роутера): {ex}"
- except Exception as e:
- return False, f"connect failed: {e}"
- try:
- req = urllib.request.Request(base + "/rci/", data=_json.dumps({"parse": command}).encode(),
- headers={"Content-Type": "application/json"})
- r = op.open(req, timeout=25)
- data = _json.loads(r.read())
- return True, _json.dumps(data, ensure_ascii=False, indent=2)
- except Exception as e:
- return False, f"rci error: {e}"
-
-
-@app.route("/api/router//rci", methods=["POST"])
-@auth_required
-def api_router_rci(cid):
- command = (request.form.get("command", "") or "").strip()
- if not command:
- return ("no command", 400)
- ok, text = _rci_run(cid, command)
- return (text, 200 if ok else 502, {"Content-Type": "text/plain; charset=utf-8"})
-
-
-@app.route("/rci/router/")
-@auth_required
-def rci_console(cid):
- base, _login, _pwd = _rci_base(cid)
- configured = bool(base)
- note = "" if configured else tr(
- "Web-адрес роутера не задан. Настройки → «Доступ к роутерам» → заполни KeenDNS URL + web-логин/пароль.",
- "Router web URL not set. Settings → Router access → fill KeenDNS URL + web login/password.")
- html_page = f"""
-
- {nav('clients')}
-
-
- 🛠 RCI {_html_attr(cid)} {hlp("Консоль ndmc-команд Keenetic через KeenDNS (работает за NAT, SSH не нужен). Введи команду CLI (напр. show version, show interface Wireguard3, show ip hotspot) — роутер выполнит и вернёт JSON. Это НЕ интерактивный bash: каждая строка — отдельная команда RCI.", "Keenetic ndmc command console via KeenDNS (works behind NAT, no SSH). Type a CLI command (e.g. show version) — the router runs it and returns JSON. Not an interactive bash: each line is a separate RCI command.")}
- {tr("Назад","Back")}
-
- {f'{note}' if note else ''}
-
-
-
-
- {tr("Быстрые","Quick")}:
- show version ·
- show interface Wireguard3 ·
- show ip hotspot ·
- show system ·
- show running-config
-
-
-
- """
- return render(html_page)
-
-
-def _terminal_target(kind, target):
- if kind == "server":
- if target in ("main", SERVER_IP):
- return {
- "title": f"Main server {SERVER_IP}",
- "mode": "local",
- "cmd": ["/bin/bash", "-l"],
- "env": os.environ.copy(),
- }
- srv = next((sv for sv in load_servers() if sv.get("ip") == target), None)
- if not srv:
- raise ValueError("server not found")
- ssh_pass = srv.get("ssh_pass", "")
- if not ssh_pass:
- raise ValueError("server SSH password missing")
- ssh_user = srv.get("ssh_user", "root") or "root"
- ssh_port = str(srv.get("ssh_port", "22") or "22")
- return {
- "title": f"Server {target}",
- "mode": "ssh",
- "hosts": [target],
- "username": ssh_user,
- "password": ssh_pass,
- "port": int(ssh_port),
- }
- if kind == "router":
- clients = get_clients()
- client = next((c for c in clients if c.get("client_id") == target), None)
- if not client:
- raise ValueError("client not found")
- acc = load_settings().get("router_access", {}).get(target, {})
- ssh_pass = acc.get("ssh_pass", "")
- if not ssh_pass:
- raise ValueError("router SSH password missing")
- ssh_user = acc.get("ssh_user", "root") or "root"
- ssh_port = str(acc.get("ssh_port", "22") or "22")
- ssh_ip = acc.get("ssh_ip") or client.get("tunnel_ip_v4", "").split("/")[0]
- ssh_static = acc.get("ssh_static", "")
- hosts = [h for h in (ssh_static, ssh_ip) if h]
- if not hosts:
- raise ValueError("router SSH IP missing")
- return {
- "title": f"Router {target}",
- "mode": "ssh",
- "hosts": hosts,
- "username": ssh_user,
- "password": ssh_pass,
- "port": int(ssh_port),
- }
- raise ValueError("bad terminal target")
-
-
-@app.route("/terminal//")
-@auth_required
-def terminal_page(kind, target):
- try:
- spec = _terminal_target(kind, target)
- error = "" if sock else "flask-sock is not installed; run phobos-update dev to install terminal dependencies"
- except Exception as e:
- spec = {"title": f"{kind} {target}"}
- error = str(e)
- title = _html_attr(spec.get("title", f"{kind} {target}"))
- ws_path = f"/ws/terminal/{kind}/{target}"
- js_error_line = ""
- if error:
- safe_error = _html_attr(error).replace("\\", "\\\\").replace('"', '\\"')
- js_error_line = f'term.writeln("ERROR: {safe_error}"); return;'
- html_page = f"""
-
- {nav('servers' if kind == 'server' else 'clients')}
-
-
- 🖥️ {title}
- {tr("Назад", "Back")}
-
-
- {_html_attr(error) if error else tr("Подключение...", "Connecting...")}
-
-
-
-
- """
- return render(html_page)
-
-
-def _terminal_ws_loop(ws, kind, target):
- try:
- spec = _terminal_target(kind, target)
- except Exception as e:
- ws.send(f"ERROR: {e}\r\n")
- return
- if spec.get("mode") == "ssh":
- return _terminal_ssh_ws_loop(ws, spec)
- return _terminal_local_ws_loop(ws, spec)
-
-
-def _terminal_local_ws_loop(ws, spec):
- import pty, select, signal, struct, termios
- master_fd, slave_fd = pty.openpty()
- proc = subprocess.Popen(spec["cmd"], stdin=slave_fd, stdout=slave_fd, stderr=slave_fd,
- env=spec.get("env") or os.environ.copy(), close_fds=True,
- preexec_fn=os.setsid)
- os.close(slave_fd)
- stop = threading.Event()
-
- def set_winsize(cols, rows):
- try:
- fcntl.ioctl(master_fd, termios.TIOCSWINSZ, struct.pack("HHHH", int(rows), int(cols), 0, 0))
- except Exception:
- pass
-
- def reader():
- try:
- while not stop.is_set():
- r, _, _ = select.select([master_fd], [], [], 0.2)
- if master_fd in r:
- data = os.read(master_fd, 4096)
- if not data:
- break
- ws.send(data.decode(errors="replace"))
- if proc.poll() is not None:
- break
- except Exception:
- pass
- finally:
- stop.set()
-
- threading.Thread(target=reader, daemon=True).start()
- try:
- while not stop.is_set():
- raw = ws.receive(timeout=1)
- if raw is None:
- if proc.poll() is not None:
- break
- continue
- try:
- msg = json.loads(raw)
- except Exception:
- msg = {"type": "input", "data": raw}
- if msg.get("type") == "resize":
- set_winsize(msg.get("cols", 80), msg.get("rows", 24))
- else:
- os.write(master_fd, str(msg.get("data", raw)).encode())
- finally:
- stop.set()
- try:
- os.killpg(os.getpgid(proc.pid), signal.SIGHUP)
- except Exception:
- pass
- try:
- os.close(master_fd)
- except Exception:
- pass
-
-
-def _terminal_ssh_ws_loop(ws, spec):
- import asyncio
- try:
- import asyncssh
- except Exception as e:
- ws.send(f"ERROR: asyncssh is not installed: {e}\r\n")
- return
-
- def format_ssh_error(exc):
- detail = str(exc).strip()
- if detail:
- return detail
- if isinstance(exc, TimeoutError):
- return "Connection timed out"
- return exc.__class__.__name__ or "Connection failed"
-
- async def run_ssh():
- last_error = None
- for host in spec.get("hosts", []):
- try:
- conn = await asyncssh.connect(
- host=host,
- port=spec.get("port", 22),
- username=spec.get("username", "root"),
- password=spec.get("password", ""),
- known_hosts=None,
- connect_timeout=10,
- )
- ws.send(f"Connected to {host}\r\n")
- break
- except Exception as e:
- last_error = e
- ws.send(f"ssh: connect to host {host} port {spec.get('port', 22)}: {format_ssh_error(e)}\r\n")
- else:
- ws.send(f"\r\nConnection error: {format_ssh_error(last_error)}\r\n")
- return
-
- async with conn:
- process = await conn.create_process(term_type="xterm-256color", term_size=(120, 40))
- stop = asyncio.Event()
-
- async def read_output():
- try:
- while not stop.is_set():
- data = await process.stdout.read(4096)
- if not data:
- break
- ws.send(data)
- except Exception:
- pass
- finally:
- stop.set()
-
- async def read_input():
- try:
- while not stop.is_set():
- raw = await asyncio.to_thread(lambda: ws.receive(timeout=1))
- if raw is None:
- continue
- try:
- msg = json.loads(raw)
- except Exception:
- process.stdin.write(raw)
- continue
- if msg.get("type") == "resize":
- process.change_terminal_size(int(msg.get("cols", 120)), int(msg.get("rows", 40)))
- else:
- process.stdin.write(str(msg.get("data", "")))
- except Exception:
- pass
- finally:
- stop.set()
-
- tasks = [asyncio.create_task(read_output()), asyncio.create_task(read_input())]
- await stop.wait()
- for task in tasks:
- task.cancel()
- process.close()
-
- asyncio.run(run_ssh())
-
-
-if sock:
- @sock.route("/ws/terminal//")
- def terminal_ws(ws, kind, target):
- if not session.get("auth"):
- ws.send("ERROR: unauthorized\r\n")
- return
- _terminal_ws_loop(ws, kind, target)
-
-
-@app.route("/api/servers/register", methods=["POST"])
-def api_register_server():
- s = load_settings()
- api_key = request.headers.get("X-API-Key", "")
- if api_key != s.get("server_api_key", ""):
- return json.dumps({"error": "unauthorized"}), 401, {"Content-Type": "application/json"}
-
- data = request.json
- servers = load_servers()
- ip = data.get("ip", "")
-
- for srv in servers:
- if srv["ip"] == ip:
- srv.update(data)
- srv["api_key"] = api_key
- srv["last_seen"] = datetime.now().isoformat()
- save_servers(servers)
- # push existing clients to the (re)registered server right away
- threading.Thread(target=lambda: (time.sleep(5), sync_missing_peers_to_secondaries()), daemon=True).start()
- return json.dumps({"status": "updated"}), 200, {"Content-Type": "application/json"}
-
- data["last_seen"] = datetime.now().isoformat()
- data["enabled"] = True
- data["api_key"] = api_key
- servers.append(data)
- save_servers(servers)
- # push existing clients to the (re)registered server right away
- threading.Thread(target=lambda: (time.sleep(5), sync_missing_peers_to_secondaries()), daemon=True).start()
- return json.dumps({"status": "registered"}), 200, {"Content-Type": "application/json"}
-
-
-# ---------------------------------------------------------------------------
-# Client provisioning API — used by Keenetic Unified (KU) to auto-create a
-# unique Phobos client per router (name "ku-") and return its
-# install command. Each call guarantees a unique WG keypair + tunnel IP +
-# peer on ALL servers, so per-router configs never collide.
-# ---------------------------------------------------------------------------
-
-CLIENT_SCRIPT = client_script_path()
-
-
-def _normalize_client_id(name):
- return name.strip().lower().replace(" ", "-")
-
-
-def _latest_token_for_client(cid):
- try:
- with open(TOKENS_FILE) as f:
- toks = json.load(f)
- except Exception:
- return ""
- for t in reversed(toks):
- if t.get("client") == cid:
- return t.get("token", "")
- return ""
-
-
-@app.route("/api/client/ensure", methods=["POST"])
-def api_client_ensure():
- s = load_settings()
- if request.headers.get("X-API-Key", "") != s.get("server_api_key", ""):
- return json.dumps({"error": "unauthorized"}), 401, {"Content-Type": "application/json"}
- data = request.json or {}
- name = (data.get("name") or "").strip()
- if not name or not re.match(r"^[a-zA-Z0-9_-]+$", name):
- return json.dumps({"error": "bad_name"}), 400, {"Content-Type": "application/json"}
- cid = _normalize_client_id(name)
- env = {**os.environ, **_load_server_env()}
- exists = Path(f"{CLIENTS_DIR}/{cid}").is_dir()
- sub = "link" if exists else "add"
- try:
- out = subprocess.check_output([CLIENT_SCRIPT, sub, name], text=True,
- timeout=60, stderr=subprocess.STDOUT, env=env)
- except subprocess.CalledProcessError as e:
- return json.dumps({"error": "script_failed", "output": (e.output or "")[-1500:]}), 500, {"Content-Type": "application/json"}
-
- meta = next((c for c in get_clients() if c.get("client_id") == cid), None)
- if not meta:
- return json.dumps({"error": "no_meta", "output": out[-800:]}), 500, {"Content-Type": "application/json"}
- pub = meta.get("public_key", "")
- tip = (meta.get("tunnel_ip_v4") or "").split("/")[0]
-
- # Peer on ALL servers so failover works on every server, not just primary.
- if pub and tip:
- try:
- sync_peer_to_all_servers(pub, f"{tip}/32", "add")
- except Exception:
- pass
- assigned = auto_assign_server(cid)
-
- # Per-client pull token for the NAT-friendly config pull channel.
- s = load_settings()
- ra = s.get("router_access", {})
- acc = ra.get(cid) or {}
- if not acc.get("pull_token"):
- acc["pull_token"] = secrets.token_hex(16)
- ra[cid] = acc
- s["router_access"] = ra
- save_settings(s)
- pull_token = ra[cid]["pull_token"]
-
- token = _latest_token_for_client(cid)
- # phobos-client.sh writes these 0600 (umask 077 in action_add) → nginx (www-data)
- # can't read them → 403 on /init and /packages. Make them world-readable.
- if token:
- _www = f"{PHOBOS_DIR}/www"
- for pth in (f"{_www}/init/{token}.sh",
- f"{_www}/packages/{token}/phobos-{cid}.tar.gz"):
- try:
- os.chmod(pth, 0o644)
- except Exception:
- pass
- try:
- os.chmod(f"{_www}/packages/{token}", 0o755)
- except Exception:
- pass
- install_url = f"{panel_base_url()}/init/{token}.sh" if token else ""
- return json.dumps({
- "ok": True, "client_id": cid, "install_url": install_url, "token": token,
- "install_command": install_command(token) if token else "",
- "pull_token": pull_token, "tunnel_ip": tip, "assigned_server": assigned,
- }), 200, {"Content-Type": "application/json"}
-
-
-@app.route("/api/client/remove", methods=["POST"])
-def api_client_remove():
- s = load_settings()
- if request.headers.get("X-API-Key", "") != s.get("server_api_key", ""):
- return json.dumps({"error": "unauthorized"}), 401, {"Content-Type": "application/json"}
- data = request.json or {}
- cid = _normalize_client_id((data.get("name") or "").strip())
- if not cid:
- return json.dumps({"error": "bad_name"}), 400, {"Content-Type": "application/json"}
- meta = next((c for c in get_clients() if c.get("client_id") == cid), None)
- pub = (meta or {}).get("public_key", "")
- tip = ((meta or {}).get("tunnel_ip_v4") or "").split("/")[0]
- env = {**os.environ, **_load_server_env()}
- try:
- subprocess.check_output([CLIENT_SCRIPT, "remove", cid], text=True,
- timeout=30, stderr=subprocess.STDOUT, env=env)
- except subprocess.CalledProcessError as e:
- return json.dumps({"error": "script_failed", "output": (e.output or "")[-1500:]}), 500, {"Content-Type": "application/json"}
- if pub and tip:
- try:
- sync_peer_to_all_servers(pub, f"{tip}/32", "remove")
- except Exception:
- pass
- s = load_settings()
- for key in ("router_access", "client_assignments"):
- d = s.get(key, {})
- if cid in d:
- del d[cid]
- s[key] = d
- save_settings(s)
- return json.dumps({"ok": True, "client_id": cid}), 200, {"Content-Type": "application/json"}
-
-
-@app.route("/api/obf-health")
-def api_obf_health():
- """Liveness of the obfuscator path on THIS (primary) server.
- Returns 200 only if all wg-obfuscator-* services are active, else 503.
- Router check_primary uses this as a valid switchback signal (the panel
- HTTP port stays up even when the tunnel path is dead, so it cannot be
- used directly)."""
- try:
- listing = subprocess.check_output(
- ["systemctl", "list-units", "--type=service", "--no-legend",
- "wg-obfuscator-*"], text=True, timeout=5)
- names = [ln.split()[0] for ln in listing.splitlines() if ln.strip()]
- except Exception:
- names = []
- if not names:
- names = ["wg-obfuscator-2083.service",
- "wg-obfuscator-5443.service",
- "wg-obfuscator-993.service"]
- bad = []
- for n in names:
- st = subprocess.getoutput("systemctl is-active " + n).strip()
- if st != "active":
- bad.append(n + "=" + st)
- if bad:
- return "obf-down: " + ",".join(bad), 503, {"Content-Type": "text/plain"}
- return "obf-ok " + str(len(names)), 200, {"Content-Type": "text/plain"}
-
-
-@app.route("/servers", methods=["GET", "POST"])
-@auth_required
-def servers_page():
- s = load_settings()
- servers = load_servers()
- msg = ""
-
- if request.method == "POST":
- action = request.form.get("action")
- if action == "add":
- ip = request.form.get("ip", "").strip()
- api_key = request.form.get("api_key", "").strip() or s.get("server_api_key", "")
- ssh_user = request.form.get("ssh_user", "root").strip() or "root"
- ssh_pass = request.form.get("ssh_pass", "").strip()
- ssh_port = request.form.get("ssh_port", "22").strip() or "22"
- if ip:
- servers.append({
- "ip": ip, "api_key": api_key, "enabled": True,
- "last_seen": "", "wg_public_key": "", "obfuscator_key": "", "ports": "",
- "ssh_user": ssh_user, "ssh_pass": ssh_pass, "ssh_port": ssh_port
- })
- save_servers(servers)
- order = s.get("server_order", [])
- if ip not in order:
- order.append(ip)
- s["server_order"] = order
- save_settings(s)
- synced = sync_missing_peers_to_secondaries(servers[-1])
- msg = f'Сервер {ip} добавлен, синхронизировано {synced} клиентов'
-
- elif action == "remove":
- ip = request.form.get("ip", "").strip()
- servers = [sv for sv in servers if sv.get("ip") != ip]
- save_servers(servers)
- order = s.get("server_order", [])
- if ip in order:
- order.remove(ip)
- s["server_order"] = order
- save_settings(s)
- msg = f'Сервер удалён'
-
- elif action == "sync":
- ip = request.form.get("ip", "").strip()
- srv = next((sv for sv in servers if sv["ip"] == ip), None)
- if srv:
- clients = get_clients()
- synced = 0
- for c in clients:
- pub = c.get("public_key", "")
- tip = c.get("tunnel_ip_v4", "")
- if pub and tip:
- res = sync_peer_to_server(srv, pub, f"{tip}/32", "add")
- if res.get("status") == "ok":
- synced += 1
- msg = f'Синхронизировано {synced} клиентов на {ip}'
-
- elif action == "fetch_info":
- ip = request.form.get("ip", "").strip()
- for srv in servers:
- if srv["ip"] == ip:
- try:
- info = secondary_api_request(srv, "/api/info", timeout=5)
- srv["wg_public_key"] = info.get("wg_public_key", "")
- srv["obfuscator_key"] = info.get("obfuscator_key", "")
- srv["ports"] = ",".join(info.get("ports", []))
- save_servers(servers)
- msg = f'Инфо получено от {ip}'
- except Exception as e:
- msg = f'Ошибка: {e}'
-
- elif action == "set_api_key":
- new_key = request.form.get("server_api_key", "").strip()
- if new_key:
- s["server_api_key"] = new_key
- save_settings(s)
- msg = 'API ключ обновлён'
-
- elif action in ("move_up", "move_down"):
- ip = request.form.get("ip", "").strip()
- order = s.get("server_order", [])
- if not order or SERVER_IP not in order:
- order = [SERVER_IP] + [sv["ip"] for sv in servers]
- if ip in order:
- idx = order.index(ip)
- if action == "move_up" and idx > 0:
- order[idx], order[idx-1] = order[idx-1], order[idx]
- elif action == "move_down" and idx < len(order) - 1:
- order[idx], order[idx+1] = order[idx+1], order[idx]
- s["server_order"] = order
- save_settings(s)
-
- elif action == "save_router_access":
- clients = get_clients()
- ra = s.get("router_access", {})
- for c in clients:
- cid = c.get("client_id", "")
- ssh_ip = request.form.get(f"ssh_ip_{cid}", "").strip()
- ssh_static = request.form.get(f"ssh_static_{cid}", "").strip()
- ssh_user = request.form.get(f"ssh_user_{cid}", "root").strip() or "root"
- ssh_pass = request.form.get(f"ssh_pass_{cid}", "").strip()
- ssh_port = request.form.get(f"ssh_port_{cid}", "22").strip() or "22"
- web_url = request.form.get(f"web_url_{cid}", "").strip()
- web_login = request.form.get(f"web_login_{cid}", "").strip() or "admin"
- web_pass = request.form.get(f"web_pass_{cid}", "").strip()
- prev = ra.get(cid, {})
- if ssh_ip or ssh_pass or web_url or prev.get("ttyd_token"):
- ra[cid] = {"ssh_ip": ssh_ip, "ssh_static": ssh_static, "ssh_user": ssh_user,
- "ssh_pass": ssh_pass, "ssh_port": ssh_port,
- "web_url": web_url, "web_login": web_login, "web_pass": web_pass,
- "ttyd_token": prev.get("ttyd_token", ""), "ttyd_ip": prev.get("ttyd_ip", ""),
- "ttyd_port": prev.get("ttyd_port", "7681"),
- "ssh_ok": prev.get("ssh_ok", False)}
- elif cid in ra and not ssh_ip and not ssh_pass and not web_url:
- del ra[cid]
- s["router_access"] = ra
- save_settings(s)
- msg = 'SSH доступ сохранён'
-
- elif action == "test_ssh":
- cid = request.form.get("client_id", "").strip()
- ra = s.get("router_access", {})
- acc = ra.get(cid, {})
- results = []
- ok_ip = ""
- # Try tunnel IP first, then static
- for label, ip in [("tunnel", acc.get("ssh_ip", "")), ("static", acc.get("ssh_static", ""))]:
- if not ip:
- continue
- try:
- r = subprocess.run(
- ["sshpass", "-p", acc.get("ssh_pass", ""), "ssh",
- "-p", str(acc.get("ssh_port", "22") or "22"), "-o", "StrictHostKeyChecking=no", "-o", "ConnectTimeout=5",
- f"{acc.get('ssh_user','root')}@{ip}", "echo OK"],
- capture_output=True, text=True, timeout=10
- )
- if "OK" in r.stdout:
- results.append(f"{label} ({ip}): ✓")
- if not ok_ip:
- ok_ip = ip
- else:
- results.append(f"{label} ({ip}): ✗ {r.stderr[:80]}")
- except Exception as e:
- results.append(f"{label} ({ip}): ✗ {str(e)[:80]}")
- if cid in ra:
- ra[cid]["ssh_ok"] = bool(ok_ip)
- ra[cid]["ssh_tested"] = ok_ip or ""
- s["router_access"] = ra
- save_settings(s)
- # SSH is optional under the pull model. Frame the result around whether
- # the router is actually reachable/managed, not raw SSH success.
- client_pub = ""
- for _c in get_clients():
- if _c.get("client_id") == cid:
- client_pub = _c.get("public_key", "")
- break
- online = False
- for _p, _i in get_wg_peers().items():
- if _p == client_pub and is_peer_online(_i.get("latest handshake", "")):
- online = True
- for _ip, _hs in server_handshakes_cache.items():
- _ts = _hs.get(client_pub, 0)
- if _ts and (time.time() - _ts) < 180:
- online = True
- ssh_line = " | ".join(results) if results else tr("SSH не настроен", "SSH not configured")
- if ok_ip:
- msg = f'{cid}: SSH ✓ {ok_ip} — {ssh_line}'
- elif online:
- msg = f'{cid}: {tr("роутер ОНЛАЙН, управляется через pull. SSH по туннелю недоступен — это нормально для роутера за NAT (входящий SSH закрыт); управление SSH не требует.", "router is ONLINE, managed via pull. Tunnel SSH unreachable — normal for a NAT router (inbound SSH closed); management does not need SSH.")}'
- else:
- msg = f'{cid}: {tr("роутер НЕ виден — нет свежего handshake ни на одном сервере, и SSH недоступен.", "router NOT visible — no fresh handshake on any server, and SSH unreachable.")} {ssh_line}'
-
- elif action == "push_all":
- clients = get_clients()
- results = []
- for c in clients:
- cid = c.get("client_id", "")
- res = push_config_to_router(cid)
- results.append(f"{cid}: {res['msg']}")
- msg = '' + '
'.join(results) + ''
-
- elif action == "save_server_access":
- for srv in servers:
- ip = srv["ip"]
- su = request.form.get(f"srv_ssh_user_{ip}", "").strip()
- sp = request.form.get(f"srv_ssh_pass_{ip}", "").strip()
- sport = request.form.get(f"srv_ssh_port_{ip}", "22").strip() or "22"
- if su:
- srv["ssh_user"] = su
- if sp:
- srv["ssh_pass"] = sp
- srv["ssh_port"] = sport
- save_servers(servers)
- msg = 'SSH доступ к серверам сохранён'
-
- elif action == "speedtest":
- ip = request.form.get("ip", "").strip()
- res = run_speedtest(ip)
- if res.get("error"):
- msg = f'{tr("Замер не удался", "Speed test failed")}: {html_lib.escape(str(res["error"]))}'
- else:
- msg = f'{html_lib.escape(ip)}: ↓ {res.get("download_mbit")} / ↑ {res.get("upload_mbit")} {tr("Мбит/с", "Mbit/s")}, ping {res.get("ping_ms")} ms'
-
- elif action == "rebalance":
- clients = get_clients()
- all_srv = get_all_servers_ordered()
- server_ips = [sv["ip"] for sv in all_srv]
- # Load-aware greedy: base load from live CPU+RAM (cached by monitor),
- # then each client goes to the least-loaded server, with a per-client
- # penalty so load spreads evenly. Down servers excluded (unless all down).
- base_load = {ip: server_load(server_stats_cache.get(ip, {})) for ip in server_ips}
- usable = [ip for ip in server_ips if base_load[ip] < 0.99] or server_ips
- placed = {ip: 0 for ip in server_ips}
- PEN = 0.08 # extra load each assigned client adds to a server's score
- assignments = {}
- rb_err = []
- for c in clients:
- cid = c["client_id"]
- target = min(usable, key=lambda ip: base_load[ip] + placed[ip] * PEN)
- placed[target] += 1
- assignments[cid] = target
- # Provision the WG peer on the target server. Round-robin assignment
- # alone is not enough — without the peer the handshake fails there and
- # the router's health monitor just fails back.
- pub = c.get("public_key", "")
- tip = c.get("tunnel_ip_v4", "").split("/")[0]
- if pub and tip:
- r = add_peer_to_server(target, pub, f"{tip}/32")
- if r.get("status") != "ok":
- rb_err.append(f"{cid}->{target}: {r.get('msg', 'peer fail')}")
- s["client_assignments"] = assignments
- save_settings(s)
- for _cid in assignments:
- fanout_router_config(_cid) # push conf to all servers (tunnel pull)
- if rb_err:
- msg = f'Rebalance: {"; ".join(rb_err)}'
- else:
- msg = f'{tr("Перераспределено", "Rebalanced")}: {len(clients)} -> {len(server_ips)} {tr("серв.; пиры добавлены, роутеры применят за ~15с", "servers; peers added, routers apply within ~15s")}'
-
- # Build ordered server list
- all_ordered = get_all_servers_ordered()
- assignments = s.get("client_assignments", {})
- clients = get_clients()
-
- # Count assigned clients per server
- assign_counts = {}
- for cid, sip in assignments.items():
- assign_counts[sip] = assign_counts.get(sip, 0) + 1
-
- # Stats dashboard cards
- stats_cards = ""
- for srv in all_ordered:
- ip = srv.get("ip", "")
- is_primary = srv.get("is_primary", False)
- cached = server_stats_cache.get(ip, {})
- ports = srv.get("ports", "?")
- assigned = assign_counts.get(ip, 0)
-
- if is_primary:
- local = get_local_stats()
- cpu_val = local.get("cpu", "?")
- mem_val = local.get("mem", "?")
- peers_val = local.get("peers", 0)
- mbps_val = local.get("mbps", 0.0)
- st_class = "badge-on"
- st_text = "Primary"
- else:
- cpu_val = cached.get("cpu", "—")
- mem_val = cached.get("mem", "—")
- peers_val = cached.get("peers", "?")
- mbps_val = cached.get("mbps", 0.0)
- is_up = cached.get("status", "down") == "ok"
- st_class = "badge-on" if is_up else "badge-off"
- st_text = "Online" if is_up else "Offline"
- term_target = "main" if is_primary else ip
- term_btn = _terminal_button(f"/terminal/server/{term_target}", tr("SSH терминал сервера", "Server SSH terminal"))
- _offline = (not is_primary) and (cached.get("status", "down") != "ok")
- mbps_disp = "—" if _offline else f"{mbps_val} Mbps"
- _st = load_settings().get("speedtests", {}).get(ip, {})
- speed_line = (f'⚡ ↓ {_st.get("download_mbit")} / ↑ {_st.get("upload_mbit")} {tr("Мбит/с", "Mbit/s")} · '
- f'{datetime.fromtimestamp(int(_st.get("ts", 0))).strftime("%d.%m %H:%M")}') if _st.get("ts") else ""
- country = _ip_country(ip)
- country_html = f'{country}' if country else ""
-
- stats_cards += f"""
-
-
- {ip}{country_html}
- {term_btn}{st_text}
-
-
- CPU: {cpu_val} RAM: {mem_val}
- Peers: {peers_val} Assigned: {assigned} Ports: {ports}
- ↕ {mbps_disp}
- {speed_line}
-
-
- """
-
- # Server priority rows
- rows = ""
- for idx, srv in enumerate(all_ordered):
- ip = srv.get("ip", "")
- is_primary = srv.get("is_primary", False)
- ports = srv.get("ports", "?")
- cached = server_stats_cache.get(ip, {})
- peers_val = cached.get("peers", get_local_stats().get("peers", "?") if is_primary else "?")
- assigned = assign_counts.get(ip, 0)
-
- if is_primary:
- st_class, st_text = "badge-on", "Primary"
- else:
- is_up = cached.get("status", "down") == "ok"
- st_class = "badge-on" if is_up else "badge-off"
- st_text = "Online" if is_up else "Offline"
-
- prio = f'#{idx+1}'
- ptag = ' Primary' if is_primary else ""
-
- mv = f"""
- """
-
- acts = ""
- term_target = "main" if is_primary else ip
- term_btn = _terminal_button(f"/terminal/server/{term_target}", tr("SSH терминал сервера", "Server SSH terminal"))
- if not is_primary:
- acts = f"""
-
- """
-
- rows += f"""
- {prio}{ip}{ptag} {ports} {peers_val} {assigned}
- {st_text}
-
- """
-
- api_key = s.get("server_api_key", "")
-
- # Router access rows — tunnel IP + optional static IP
- router_access = s.get("router_access", {})
- access_rows = ""
- for c in clients:
- cid = c.get("client_id", "")
- tunnel_ip = c.get("tunnel_ip_v4", "")
- acc = router_access.get(cid, {})
- ssh_ip = acc.get("ssh_ip", tunnel_ip)
- ssh_static = acc.get("ssh_static", "")
- ssh_user = acc.get("ssh_user", "root")
- ssh_pass = acc.get("ssh_pass", "")
- ssh_port = acc.get("ssh_port", "22")
- web_url = acc.get("web_url", "")
- web_login = acc.get("web_login", "")
- web_pass = acc.get("web_pass", "")
- ssh_ok = acc.get("ssh_ok", False)
- ssh_tested = acc.get("ssh_tested", "")
- if ssh_ok:
- badge_cls = "badge-on"
- badge_txt = f"✓ {ssh_tested}" if ssh_tested else "✓"
- elif ssh_ip and ssh_pass:
- badge_cls = "badge-warn"
- badge_txt = "не проверен"
- else:
- badge_cls = "badge-off"
- badge_txt = "—"
- access_rows += f"""
- {cid}
-
-
-
-
-
-
-
-
- {badge_txt}
- """
-
- html = f"""
-
- {nav('servers')}
- {msg}
-
-
- {tr("Панель серверов", "Server Dashboard")} {hlp("Живая статистика всех VPN-серверов. Peers = активные WG-подключения. Assigned = клиенты, у которых этот сервер основной. Фоновый монитор опрашивает каждые " + str(s.get('monitor_interval',30)) + " сек и шлёт оповещения в Telegram при падении/восстановлении сервера.", "Live stats for all VPN servers. Peers = active WG connections. Assigned = clients whose primary is this server. Background monitor polls every " + str(s.get('monitor_interval',30)) + "s and sends Telegram alerts on server up/down.")}
- {stats_cards}
-
-
-
- {tr("Приоритет серверов и балансировка", "Server Priority & Load Balancing")} {hlp("У каждого клиента есть основной сервер. При сбое роутер сам перебирает серверы сверху вниз. Стрелки меняют общий порядок резервирования. Роутеры за NAT подтягивают конфиг сами — ручных действий не нужно.", "Each client has a primary server. On failure the router tries servers top-to-bottom by itself. Arrows change the global fallback order. NAT routers pull config themselves — no manual action needed.")}
-
- {tr("Сервер","Server")} {tr("Порты","Ports")} Peers {tr("Назначено","Assigned")} {tr("Статус","Status")} {tr("Действия","Actions")}
- {rows}
-
-
-
- {hlp("Равномерно распределить всех клиентов по серверам (round-robin). Меняет основной сервер у клиентов — они переключатся автоматически.", "Evenly redistribute all clients across servers (round-robin). Changes clients primary server — they switch automatically.")}
-
- {hlp("Принудительно отправить конфиг на роутеры с прямым SSH. Роутеры за NAT это игнорируют и сами подтягивают конфиг за ~15 сек — обычно эта кнопка не нужна.", "Force-push config to routers reachable by SSH. NAT routers ignore it and auto-pull within ~15s — you usually do not need this.")}
-
-
-
-
-
- {tr("Доступ к роутерам — SSH / RCI (опционально)", "Router access — SSH / RCI (optional)")} {hlp("НЕ обязательно для работы VPN (роутеры сами тянут конфиг по HTTP/HTTPS через pull). SSH-поля — для роутеров с прямым IP (мгновенный push). KeenDNS URL + web-логин/пароль — для RCI-консоли Keenetic (кнопка 🛠 RCI у клиента): управление ndmc-командами через KeenDNS, работает за NAT без SSH. Для Keenetic за NAT используй именно RCI (SSH к ним недоступен).", "NOT required for VPN (routers auto-pull config over HTTP/HTTPS). SSH fields — for direct-IP routers (instant push). KeenDNS URL + web login/password — for the Keenetic RCI console (🛠 RCI button): run ndmc commands via KeenDNS, works behind NAT without SSH. For NAT Keenetic use RCI (SSH is unreachable).")}
-
-
- {"".join(f'' for c in clients)}
-
-
-
-
- Server SSH Access
- SSH credentials for secondary servers. Used by panel to add/remove WG peers when switching client servers. Main server uses local commands.
-
-
-
-
- API Key
-
-
-
-
- Deploy Secondary Server
- One command deploys WG + obfuscator + mini-API on a new VPS. Auto-registers in panel. Run via SSH on new VPS:
- MAIN_PROTO={panel_scheme()} MAIN_SERVER={SERVER_IP} MAIN_PORT={panel_port()} MAIN_API_KEY={api_key} bash <(curl -kfsSL {panel_base_url()}/server/secondary-setup.sh)
-
- """
- return render(html)
-if __name__ == "__main__":
- ssl_context = None
- cert = os.environ.get("PANEL_TLS_CERT", "")
- key = os.environ.get("PANEL_TLS_KEY", "")
- if panel_scheme() == "https" and cert and key:
- ssl_context = (cert, key)
- app.run(host="0.0.0.0", port=int(panel_port()), debug=False, ssl_context=ssl_context)
diff --git a/client/failover.conf.example b/client/failover.conf.example
deleted file mode 100644
index 81703b9..0000000
--- a/client/failover.conf.example
+++ /dev/null
@@ -1,15 +0,0 @@
-# Phobos Failover Configuration
-# Format: SERVER_N=host:port1,port2,port3
-# KEY_N=obfuscation_key_for_server_N
-
-# Primary server (main, with web panel)
-SERVER_1=144.124.252.104:2083,5443,993
-KEY_1=Fc3X8GbVQD2FuHPbOjKiaP83nWSwNojJ
-
-# Secondary server (backup, VPN only)
-# SERVER_2=backup.example.com:51821,51822
-# KEY_2=backup_obfuscation_key_here
-
-# Emergency server (last resort)
-# SERVER_3=emergency.example.com:43210
-# KEY_3=emergency_key_here
diff --git a/client/phobos-health.sh b/client/phobos-health.sh
deleted file mode 100644
index 414bb11..0000000
--- a/client/phobos-health.sh
+++ /dev/null
@@ -1,247 +0,0 @@
-#!/bin/sh
-# ============================================================
-# Phobos Health Monitor — Auto-heal + Failover for routers
-# Runs via cron every 60 seconds on Keenetic/Entware
-#
-# Install: crontab -e → */1 * * * * /opt/etc/Phobos/phobos-health.sh
-# ============================================================
-
-PHOBOS_DIR="/opt/etc/Phobos"
-CONF="$PHOBOS_DIR/failover.conf"
-STATE="$PHOBOS_DIR/state"
-LOG="$PHOBOS_DIR/health.log"
-WG_CONF="$PHOBOS_DIR/wg0.conf"
-OBF_CONF="$PHOBOS_DIR/wg-obfuscator.conf"
-LOCKFILE="/tmp/phobos-health.lock"
-
-MAX_LOG_LINES=200
-HANDSHAKE_WARN=180
-HANDSHAKE_RESTART_OBF=300
-HANDSHAKE_RESTART_WG=600
-HANDSHAKE_FAILOVER=900
-
-log() {
- echo "$(date '+%H:%M:%S') $1" >> "$LOG"
- # Trim log
- if [ "$(wc -l < "$LOG" 2>/dev/null)" -gt "$MAX_LOG_LINES" ]; then
- tail -n 100 "$LOG" > "$LOG.tmp" && mv "$LOG.tmp" "$LOG"
- fi
-}
-
-# Prevent concurrent runs
-if [ -f "$LOCKFILE" ]; then
- pid=$(cat "$LOCKFILE" 2>/dev/null)
- if kill -0 "$pid" 2>/dev/null; then
- exit 0
- fi
-fi
-echo $$ > "$LOCKFILE"
-trap 'rm -f "$LOCKFILE"' EXIT
-
-# Create state dir
-mkdir -p "$STATE"
-
-# ── Read failover config ──
-if [ ! -f "$CONF" ]; then
- log "ERROR: no failover.conf"
- exit 1
-fi
-
-# Parse servers: SERVER_1=ip:port1,port2,port3
-# Parse current state
-CURRENT_SERVER=$(cat "$STATE/current_server" 2>/dev/null || echo "1")
-CURRENT_PORT_IDX=$(cat "$STATE/current_port_idx" 2>/dev/null || echo "0")
-RESTART_COUNT=$(cat "$STATE/restart_count" 2>/dev/null || echo "0")
-PRIMARY_CHECK_TS=$(cat "$STATE/primary_check_ts" 2>/dev/null || echo "0")
-
-# Load server list
-SERVER_COUNT=0
-idx=1
-while true; do
- val=$(grep "^SERVER_${idx}=" "$CONF" 2>/dev/null | cut -d= -f2-)
- if [ -z "$val" ]; then
- break
- fi
- eval "SERVER_${idx}_HOST=$(echo "$val" | cut -d: -f1)"
- eval "SERVER_${idx}_PORTS=$(echo "$val" | cut -d: -f2-)"
- eval "SERVER_${idx}_KEY=$(grep "^KEY_${idx}=" "$CONF" 2>/dev/null | cut -d= -f2-)"
- SERVER_COUNT=$idx
- idx=$((idx + 1))
-done
-
-if [ "$SERVER_COUNT" -eq 0 ]; then
- log "ERROR: no servers in failover.conf"
- exit 1
-fi
-
-# ── Get current handshake age ──
-get_handshake_age() {
- hs=$(wg show wg0 latest-handshakes 2>/dev/null | awk '{print $2}')
- if [ -z "$hs" ] || [ "$hs" = "0" ]; then
- echo "9999"
- return
- fi
- now=$(date +%s)
- age=$((now - hs))
- echo "$age"
-}
-
-# ── Get port by index from comma-separated list ──
-get_port() {
- server_idx=$1
- port_idx=$2
- eval "ports=\$SERVER_${server_idx}_PORTS"
- echo "$ports" | tr ',' '\n' | sed -n "$((port_idx + 1))p"
-}
-
-get_port_count() {
- server_idx=$1
- eval "ports=\$SERVER_${server_idx}_PORTS"
- echo "$ports" | tr ',' '\n' | wc -l
-}
-
-# ── Switch to specific server:port ──
-switch_endpoint() {
- server_idx=$1
- port_idx=$2
-
- eval "host=\$SERVER_${server_idx}_HOST"
- eval "obf_key=\$SERVER_${server_idx}_KEY"
- port=$(get_port "$server_idx" "$port_idx")
-
- if [ -z "$host" ] || [ -z "$port" ]; then
- log "ERROR: invalid server $server_idx port_idx $port_idx"
- return 1
- fi
-
- log "SWITCH → server $server_idx ($host:$port)"
-
- # Update obfuscator config target
- if [ -f "$OBF_CONF" ]; then
- sed -i "s|^target = .*|target = ${host}:${port}|" "$OBF_CONF"
- if [ -n "$obf_key" ]; then
- sed -i "s|^key = .*|key = ${obf_key}|" "$OBF_CONF"
- fi
- fi
-
- # Restart obfuscator
- killall wg-obfuscator 2>/dev/null
- sleep 1
- wg-obfuscator --config "$OBF_CONF" &
-
- # Save state
- echo "$server_idx" > "$STATE/current_server"
- echo "$port_idx" > "$STATE/current_port_idx"
- echo "0" > "$STATE/restart_count"
-}
-
-# ── Try next port on current server ──
-try_next_port() {
- port_count=$(get_port_count "$CURRENT_SERVER")
- next_idx=$(( (CURRENT_PORT_IDX + 1) % port_count ))
-
- if [ "$next_idx" -eq 0 ]; then
- return 1
- fi
-
- log "PORT HOP → port idx $next_idx on server $CURRENT_SERVER"
- switch_endpoint "$CURRENT_SERVER" "$next_idx"
- return 0
-}
-
-# ── Try next server ──
-try_next_server() {
- next=$((CURRENT_SERVER + 1))
- if [ "$next" -gt "$SERVER_COUNT" ]; then
- next=1
- fi
-
- if [ "$next" -eq "$CURRENT_SERVER" ]; then
- log "WARN: only one server, can't failover"
- return 1
- fi
-
- log "FAILOVER → server $next"
- switch_endpoint "$next" "0"
- return 0
-}
-
-# ── Check if primary is back (every 5 min when on secondary) ──
-check_primary() {
- if [ "$CURRENT_SERVER" -eq 1 ]; then
- return
- fi
-
- now=$(date +%s)
- elapsed=$((now - PRIMARY_CHECK_TS))
- if [ "$elapsed" -lt 300 ]; then
- return
- fi
- echo "$now" > "$STATE/primary_check_ts"
-
- eval "host=\$SERVER_1_HOST"
- port=$(get_port 1 0)
-
- # Quick UDP probe — send a byte, see if port responds
- if ping -c 1 -W 2 "$host" >/dev/null 2>&1; then
- log "PRIMARY alive, switching back"
- switch_endpoint 1 0
- fi
-}
-
-# ── Main logic ──
-AGE=$(get_handshake_age)
-
-if [ "$AGE" -lt "$HANDSHAKE_WARN" ]; then
- # All good, reset counters
- if [ "$RESTART_COUNT" -gt 0 ]; then
- log "OK: connection restored (age=${AGE}s)"
- echo "0" > "$STATE/restart_count"
- fi
- check_primary
- exit 0
-fi
-
-log "STALE handshake: ${AGE}s (server=$CURRENT_SERVER port_idx=$CURRENT_PORT_IDX restarts=$RESTART_COUNT)"
-
-if [ "$AGE" -lt "$HANDSHAKE_RESTART_OBF" ]; then
- # Restart obfuscator only
- RESTART_COUNT=$((RESTART_COUNT + 1))
- echo "$RESTART_COUNT" > "$STATE/restart_count"
- log "ACTION: restart obfuscator (attempt $RESTART_COUNT)"
- killall wg-obfuscator 2>/dev/null
- sleep 1
- wg-obfuscator --config "$OBF_CONF" &
- exit 0
-fi
-
-if [ "$AGE" -lt "$HANDSHAKE_RESTART_WG" ]; then
- # Restart WireGuard + obfuscator
- RESTART_COUNT=$((RESTART_COUNT + 1))
- echo "$RESTART_COUNT" > "$STATE/restart_count"
- log "ACTION: restart WG + obfuscator (attempt $RESTART_COUNT)"
- wg-quick down wg0 2>/dev/null
- killall wg-obfuscator 2>/dev/null
- sleep 2
- wg-quick up wg0 2>/dev/null
- sleep 1
- wg-obfuscator --config "$OBF_CONF" &
- exit 0
-fi
-
-if [ "$AGE" -lt "$HANDSHAKE_FAILOVER" ]; then
- # Try next port
- log "ACTION: try port hop"
- if ! try_next_port; then
- log "ACTION: all ports exhausted, try next server"
- try_next_server
- fi
- exit 0
-fi
-
-# Full failover
-log "ACTION: failover (handshake ${AGE}s)"
-if ! try_next_server; then
- # Only one server, cycle ports
- try_next_port
-fi
diff --git a/docs/PORTS.md b/docs/PORTS.md
deleted file mode 100644
index b471d37..0000000
--- a/docs/PORTS.md
+++ /dev/null
@@ -1,107 +0,0 @@
-# PCA Phobos ports and firewall checklist
-
-This page is the short truth table for normal Phobos work. Use it before
-opening a ticket about "router does not switch", "secondary is online but sync
-fails", or "panel is too exposed".
-
-## Primary server
-
-| Port | Protocol | Who connects | Required | Why |
-| --- | --- | --- | --- | --- |
-| `PANEL_PORT` | TCP | admin browser, secondary setup/register, router pull fallback | yes | Web panel and `/api/*`. Real value: `cat /opt/phobos-panel/.port`. |
-| `80` | TCP | routers during install, Android APK download | recommended | nginx serves `/init/`, `/packages/`, `/app/`. |
-| `2083,5443,993` | UDP | routers and Android PhobosWG | yes | wg-obfuscator public entry ports. Real value: `grep OBFUSCATOR_PORTS /opt/Phobos/server/server.env`. |
-| `51820` | UDP | plain WireGuard clients only | no by default | Usually blocked to force obfuscation. Open only if installed with `ALLOW_PLAIN_WG=1` for iOS/plain WG. |
-| `22` | TCP | admin only | optional | SSH maintenance. Do not expose broadly. |
-
-`PANEL_PORT` is random on clean install unless passed as env:
-
-```bash
-cat /opt/phobos-panel/.port
-```
-
-## Secondary server
-
-| Port | Protocol | Who connects | Required | Why |
-| --- | --- | --- | --- | --- |
-| `8444` | TCP | primary panel, routers via tunnel/public path | yes | Mini-API: health, peer sync, router config cache. |
-| `2083,5443,993` | UDP | routers and Android PhobosWG | yes | wg-obfuscator public entry ports. |
-| `51820` | UDP | nobody public | no | WireGuard listens locally behind obfuscator; public access is blocked. |
-| `22` | TCP | admin during install | optional | SSH maintenance. |
-
-If secondary is "Online" but `Info`, `Sync`, or client assignment fails, check
-`8444/tcp` first and confirm the API key matches the main panel key.
-
-## Router outbound access
-
-Routers need outbound access to:
-
-- every server UDP obfuscator port, default `2083,5443,993`;
-- primary `PANEL_PORT/tcp` for initial install and public pull fallback;
-- primary `80/tcp` if using the nginx install fallback;
-- tunnel management paths after VPN is up:
- - `http://10.25.0.1:8444` for secondary mini-API;
- - `http(s)://10.25.0.1:` for primary panel API.
-
-Current router packages write these files on the router:
-
-```bash
-/opt/etc/Phobos/panel_url
-/opt/etc/Phobos/panel_urls
-/opt/etc/Phobos/panel_port
-/opt/etc/Phobos/panel_scheme
-```
-
-If a router does not switch after changing its server in the panel, check:
-
-```bash
-cat /opt/etc/Phobos/panel_urls
-cat /opt/etc/Phobos/failover.conf
-tail -n 80 /opt/etc/Phobos/health.log
-/opt/etc/Phobos/phobos-pull.sh
-```
-
-If `panel_urls` contains an old IP or old panel port, create a fresh install
-command in the panel and reinstall/update that router package.
-
-## HTTPS panel
-
-Native HTTPS is supported by the primary installer:
-
-```bash
-PANEL_TLS_CERT=/etc/letsencrypt/live/example.com/fullchain.pem \
-PANEL_TLS_KEY=/etc/letsencrypt/live/example.com/privkey.pem \
-bash <(curl -fsSL https://git.bobyrev.com/PCA/PCA_Phobos/raw/branch/main/install.sh)
-```
-
-Then the panel runs as:
-
-```text
-https://:
-```
-
-The generated router and secondary commands use `curl -k`/`wget
---no-check-certificate` fallback so a self-signed certificate can work for
-bootstrap. For humans in a browser, use a real certificate to avoid warnings.
-
-## Can I IP-whitelist the panel port?
-
-Yes, but with care. `PANEL_PORT` is not only the admin UI. It also carries
-server registration and router pull API. If you whitelist it too tightly, these
-features break:
-
-- secondary auto-register;
-- `Info` / `Sync` / client assignment to secondary;
-- router pull fallback before tunnel is up;
-- router config update when public path is the only available path.
-
-Minimum allowlist for `PANEL_PORT`:
-
-- your admin IPs;
-- all secondary server public IPs;
-- router public IPs, if they are static;
-- or no router IP restriction until first install is complete and tunnel pull is proven.
-
-For CGNAT/dynamic-router fleets, do not rely on a strict public-IP allowlist for
-router management. Use strong panel password, API key secrecy, optional HTTPS,
-and keep only the required ports open.
diff --git a/docs/WARP_DEV_NOTES.md b/docs/WARP_DEV_NOTES.md
deleted file mode 100644
index 8253203..0000000
--- a/docs/WARP_DEV_NOTES.md
+++ /dev/null
@@ -1,160 +0,0 @@
-# WARP in `dev` — modes, checks, current limits
-
-Date: `2026-06-06`
-Channel: `dev`
-Version: `v1.3.1-dev`
-
-## What was added
-
-The `dev` panel now has a dedicated `WARP / WARP+` block in `/settings`.
-
-Supported modes:
-
-- `egress` — route client outbound traffic through WARP on the server side;
-- `relay` — expose a UDP relay for a separate WARP/WireGuard client profile;
-- `custom profile` — save a full custom `warp.conf` from the web UI;
-- `WARP+ key` — save a license key and rebuild the profile through `wgcf`.
-
-The UI also has a `?` help block with plain-language explanations:
-
-- what each mode does;
-- when to use `free` vs `custom`;
-- what `WARP+ key` changes;
-- what `Enable` and `Disable` do;
-- how per-client WARP works from the client list.
-
-## How the modes work
-
-### `egress`
-
-Use this when you want Phobos clients to keep connecting the usual way, but send
-their outgoing traffic through Cloudflare WARP after they land on the server.
-
-Implementation:
-
-- WireGuard clients still connect to the Phobos server;
-- server-side policy routing sends only selected client tunnel IPs through `warp`;
-- NAT is done with `POSTROUTING MASQUERADE`;
-- client rows in `/clients` have `WARP ON/OFF`, which adds/removes `ip rule from /32`.
-
-### `relay`
-
-Use this when you need a separate relay endpoint for another WARP/WireGuard
-client profile.
-
-Important:
-
-- this is **not** a drop-in replacement for the normal Phobos router config;
-- the client must use a separate WARP/WireGuard profile aimed at the relay port;
-- this mode is for relay-style scenarios, not for replacing the regular
- `home.conf` path one-to-one.
-
-Implementation:
-
-- UDP relay rules are added with tagged iptables entries;
-- incoming UDP on the selected port is DNAT'ed to the target WARP endpoint;
-- outgoing packets are MASQUERADE'd back through the relay host.
-
-### `custom profile` and `WARP+`
-
-Two ways to use a non-default profile:
-
-- paste a full custom `warp.conf`;
-- save a `WARP+ key` and let `wgcf` rebuild the profile from it.
-
-This keeps the UI simple:
-
-- `free WARP` still works out of the box;
-- `WARP+` is possible when the owner has a real key;
-- no hidden magic is required outside the panel.
-
-## Live checks completed
-
-### Server-side checks
-
-Passed:
-
-- `python3 -m py_compile app.py server/api.py`
-- `bash -n install.sh update.sh server/phobos-warp.sh`
-- live `status` checks on dev server `64.188.81.115`
-
-Verified on the dev server:
-
-- `egress` mode enables cleanly;
-- current egress IPv4 is reported in status JSON;
-- `custom profile` and `WARP+ key` save from the web UI;
-- relay rules appear with separate tagged iptables entries.
-
-### Real router check
-
-Router used for testing:
-
-- public SSH: `95.72.5.253`
-- web: `https://homesmart.netcraze.pro/dashboard`
-
-Confirmed:
-
-- real router traffic was sent through the dev server;
-- with `egress` enabled, a live `curl https://api.ipify.org` from the router
- returned WARP egress IP `104.28.193.219`;
-- this proves the real data path for `router -> Phobos -> WARP -> internet`.
-
-### Relay check
-
-Confirmed:
-
-- relay mode enables from the server side;
-- relay iptables rules are created;
-- counters increase on live traffic;
-- a separate WARP profile pointed at the relay port completes handshake.
-
-Not fully closed yet:
-
-- relay handshake and packet flow were confirmed;
-- a full end-to-end "internet works through relay profile" check on the router
- was not fully finished in a clean state before router access became limited.
-
-## Router recovery note
-
-During live tests, WAN SSH access to the router stopped responding, so full file
-restore over shell was blocked.
-
-What was still restored safely:
-
-- temporary KeenDNS helper proxies created for testing were removed;
-- temporary extra WireGuard peer entries were cleaned up;
-- the router is currently left on a **working direct dev WireGuard peer** so it
- stays reachable through the test tunnel rather than returning to a broken
- down state.
-
-What still needs one final shell pass later:
-
-- restore `/opt/etc/Phobos/home.conf` from backup;
-- restore `/opt/etc/Phobos/wg-obfuscator.conf` from backup;
-- restore `/opt/etc/Phobos/failover.conf` from backup;
-- restore minute cron jobs for `phobos-health.sh` and `phobos-pull.sh`.
-
-Known backup path on the router:
-
-- `/opt/etc/Phobos/test-backup-20260606-044834`
-
-## Current honest status
-
-Ready now:
-
-- `egress` mode
-- per-client `WARP ON/OFF`
-- `custom profile`
-- `WARP+ key`
-- UI help text
-
-Partially verified:
-
-- `relay` mode
-
-Extra audit fixes after live testing:
-
-- orphan WireGuard peers now show up in both `Sessions` and `Clients` as `orphan-*` instead of disappearing into `unknown`;
-- orphan rows can be `Kick`ed, `Purge`d, and also toggled through per-peer WARP;
-- client package build no longer fails when `/opt/Phobos/bin` is missing or `OBFUSCATOR_KEY` is empty;
-- update / restore scripts now restart the active panel service automatically (`phobos-panel` or `phobos-dev-test`).
diff --git a/docs/img/README.md b/docs/img/README.md
deleted file mode 100644
index c16fafd..0000000
--- a/docs/img/README.md
+++ /dev/null
@@ -1,9 +0,0 @@
-# Скриншоты
-
-Положи сюда 3 PNG (панель открыта — сделай скрины своих страниц):
-
-- `sessions.png` — страница «Сессии»
-- `clients.png` — страница «Клиенты»
-- `servers.png` — страница «Серверы»
-
-README в корне на них ссылается. Рекомендуемая ширина ~1000–1400px.
diff --git a/docs/img/android-admin.png b/docs/img/android-admin.png
deleted file mode 100644
index 7eb7481..0000000
Binary files a/docs/img/android-admin.png and /dev/null differ
diff --git a/docs/img/android-vpn-apps.png b/docs/img/android-vpn-apps.png
deleted file mode 100644
index 08bdbd9..0000000
Binary files a/docs/img/android-vpn-apps.png and /dev/null differ
diff --git a/docs/img/android-vpn-import.png b/docs/img/android-vpn-import.png
deleted file mode 100644
index 3d02233..0000000
Binary files a/docs/img/android-vpn-import.png and /dev/null differ
diff --git a/docs/img/android-vpn.png b/docs/img/android-vpn.png
deleted file mode 100644
index ed98c3e..0000000
Binary files a/docs/img/android-vpn.png and /dev/null differ
diff --git a/docs/img/clients-dark.png b/docs/img/clients-dark.png
deleted file mode 100644
index 3f822c9..0000000
Binary files a/docs/img/clients-dark.png and /dev/null differ
diff --git a/docs/img/clients.png b/docs/img/clients.png
deleted file mode 100644
index 9d8e27d..0000000
Binary files a/docs/img/clients.png and /dev/null differ
diff --git a/docs/img/ios-app.png b/docs/img/ios-app.png
deleted file mode 100644
index ce53f68..0000000
Binary files a/docs/img/ios-app.png and /dev/null differ
diff --git a/docs/img/mobile-clients-dark.png b/docs/img/mobile-clients-dark.png
deleted file mode 100644
index 77627b3..0000000
Binary files a/docs/img/mobile-clients-dark.png and /dev/null differ
diff --git a/docs/img/mobile-clients.png b/docs/img/mobile-clients.png
deleted file mode 100644
index 3120c7f..0000000
Binary files a/docs/img/mobile-clients.png and /dev/null differ
diff --git a/docs/img/mobile-servers.png b/docs/img/mobile-servers.png
deleted file mode 100644
index 89df012..0000000
Binary files a/docs/img/mobile-servers.png and /dev/null differ
diff --git a/docs/img/servers-dark.png b/docs/img/servers-dark.png
deleted file mode 100644
index 88c9d14..0000000
Binary files a/docs/img/servers-dark.png and /dev/null differ
diff --git a/docs/img/servers.png b/docs/img/servers.png
deleted file mode 100644
index 8842aff..0000000
Binary files a/docs/img/servers.png and /dev/null differ
diff --git a/docs/img/sessions-dark.png b/docs/img/sessions-dark.png
deleted file mode 100644
index 05ac22b..0000000
Binary files a/docs/img/sessions-dark.png and /dev/null differ
diff --git a/docs/img/sessions.png b/docs/img/sessions.png
deleted file mode 100644
index 3c77619..0000000
Binary files a/docs/img/sessions.png and /dev/null differ
diff --git a/docs/img/settings-dark.png b/docs/img/settings-dark.png
deleted file mode 100644
index a3253ca..0000000
Binary files a/docs/img/settings-dark.png and /dev/null differ
diff --git a/docs/img/settings.png b/docs/img/settings.png
deleted file mode 100644
index b2048a8..0000000
Binary files a/docs/img/settings.png and /dev/null differ
diff --git a/install.sh b/install.sh
deleted file mode 100755
index bc0c16a..0000000
--- a/install.sh
+++ /dev/null
@@ -1,350 +0,0 @@
-#!/bin/bash
-# ============================================================
-# PCA Phobos — TURNKEY installer (primary / panel node)
-#
-# One command, all dependencies, from a clean VPS:
-# bash <(curl -fsSL https://git.bobyrev.com/PCA/PCA_Phobos/raw/branch/main/install.sh)
-#
-# Installs, in order:
-# deps -> wg-obfuscator (Ground-Zerro) -> WireGuard wg0 ->
-# obfuscator services -> Phobos repo (onboarding scripts) +
-# PCA patches -> web panel -> nginx (/init,/packages) ->
-# server-side router watchdog.
-#
-# Env (all optional):
-# PANEL_PORT random 10000-59999 web panel port
-# PANEL_TLS_CERT / PANEL_TLS_KEY enable native HTTPS for panel
-# PANEL_PASS OcAdmin2026! panel admin password
-# API_KEY random shared key (agents + router pull token)
-# OBF_PORTS 2083,5443,993 obfuscator listen ports
-# TG_TOKEN / TG_CHAT Telegram alerts
-# PCA_BRANCH main branch to pull PCA files from
-# ============================================================
-set -e
-
-PANEL_PASS="${PANEL_PASS:-OcAdmin2026!}"
-PANEL_TLS_CERT="${PANEL_TLS_CERT:-}"
-PANEL_TLS_KEY="${PANEL_TLS_KEY:-}"
-PANEL_SCHEME="${PANEL_SCHEME:-http}"
-TG_TOKEN="${TG_TOKEN:-}"
-TG_CHAT="${TG_CHAT:-}"
-OBF_PORTS="${OBF_PORTS:-2083,5443,993}"
-SERVER_WG_IPV4_NETWORK="${SERVER_WG_IPV4_NETWORK:-10.25.0.0/16}"
-# Источник: Gitea git.bobyrev.com (основной), GitHub — запасной.
-# Каналы stable/beta/dev — ветки main/beta/dev одного публичного репозитория.
-PCA_GIT="${PCA_GIT:-https://git.bobyrev.com/PCA/PCA_Phobos}"
-GH_RAW="${GH_RAW:-https://raw.githubusercontent.com/andrey271192/PCA_Phobos}"
-CHANNEL="${CHANNEL:-stable}"
-case "$CHANNEL" in
- stable|main|"") PCA_BRANCH="${PCA_BRANCH:-main}";;
- *) PCA_BRANCH="${PCA_BRANCH:-$CHANNEL}";;
-esac
-case "$PCA_BRANCH" in v[0-9]*) _kind=tag;; *) _kind=branch;; esac
-PHOBOS_DIR="/opt/Phobos"
-PANEL_DIR="/opt/phobos-panel"
-RAW="$PCA_GIT/raw/$_kind/$PCA_BRANCH"
-SRC="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-
-[ "$EUID" -eq 0 ] || { echo "Run as root"; exit 1; }
-
-if [ -z "$PANEL_PORT" ]; then
- PANEL_PORT=$(shuf -i 10000-59999 -n 1 2>/dev/null || awk 'BEGIN{srand(); print int(10000+rand()*50000)}')
-fi
-if [ -n "$PANEL_TLS_CERT" ] || [ -n "$PANEL_TLS_KEY" ]; then
- [ -f "$PANEL_TLS_CERT" ] || { echo "ERROR: PANEL_TLS_CERT not found: $PANEL_TLS_CERT"; exit 1; }
- [ -f "$PANEL_TLS_KEY" ] || { echo "ERROR: PANEL_TLS_KEY not found: $PANEL_TLS_KEY"; exit 1; }
- PANEL_SCHEME="https"
-fi
-case "$PANEL_SCHEME" in http|https) ;; *) echo "ERROR: PANEL_SCHEME must be http or https"; exit 1;; esac
-API_KEY="${API_KEY:-$(head -c 24 /dev/urandom | base64 | tr -d '/+=' | head -c 24)}"
-WG_SERVER_IPV4="$(python3 - "$SERVER_WG_IPV4_NETWORK" <<'PY'
-import ipaddress, sys
-net = ipaddress.ip_network(sys.argv[1], strict=False)
-print(next(net.hosts()))
-PY
-)"
-WG_PREFIXLEN="$(python3 - "$SERVER_WG_IPV4_NETWORK" <<'PY'
-import ipaddress, sys
-print(ipaddress.ip_network(sys.argv[1], strict=False).prefixlen)
-PY
-)"
-
-SERVER_IP=$(curl -s -m8 https://api.ipify.org || hostname -I | awk '{print $1}')
-IFACE=$(ip route get 8.8.8.8 2>/dev/null | awk '{for(i=1;i/dev/null
-apt-get install -y -qq python3-flask-sock >/dev/null 2>&1 || true
-apt-get install -y -qq python3-asyncssh >/dev/null 2>&1 || true
-apt-get install -y -qq python3-websocket >/dev/null 2>&1 || true
-python3 - <<'PY' >/dev/null 2>&1 || python3 -m pip install flask-sock asyncssh websocket-client >/dev/null 2>&1 || python3 -m pip install --break-system-packages flask-sock asyncssh websocket-client >/dev/null
-import flask_sock, asyncssh, websocket
-PY
-mkdir -p "$PANEL_DIR/static"
-curl -fsSL -m20 https://cdn.jsdelivr.net/npm/@xterm/xterm@5.5.0/css/xterm.css -o "$PANEL_DIR/static/xterm.min.css" 2>/dev/null || true
-curl -fsSL -m20 https://cdn.jsdelivr.net/npm/@xterm/xterm@5.5.0/lib/xterm.js -o "$PANEL_DIR/static/xterm.min.js" 2>/dev/null || true
-curl -fsSL -m20 https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.8.0/lib/xterm-addon-fit.js -o "$PANEL_DIR/static/xterm-addon-fit.min.js" 2>/dev/null || true
-systemctl enable cron -q 2>/dev/null || true; systemctl start cron 2>/dev/null || true
-
-# ── 2. wg-obfuscator binary (Ground-Zerro) ──
-echo "[2/9] wg-obfuscator..."
-mkdir -p "$PHOBOS_DIR"/{server,clients,bin,tokens,www/init,www/packages,packages}
-OBF_ARCH="$ARCH"
-[ "$OBF_ARCH" = "amd64" ] && OBF_ARCH="x86_64"
-[ "$OBF_ARCH" = "arm64" ] && OBF_ARCH="aarch64"
-if [ ! -x /usr/local/bin/wg-obfuscator ]; then
- R=/tmp/phobos-obf; rm -rf "$R"; mkdir -p "$R"; cd "$R"
- git init -q; git remote add origin https://github.com/Ground-Zerro/Phobos.git
- git config core.sparseCheckout true; echo "wg-obfuscator" > .git/info/sparse-checkout
- git pull origin main -q
- cp -f "wg-obfuscator/bin/"wg-obfuscator-* "$PHOBOS_DIR/bin/" 2>/dev/null || true
- chmod +x "$PHOBOS_DIR/bin/"wg-obfuscator-* 2>/dev/null || true
- ln -sf "$PHOBOS_DIR/bin/wg-obfuscator-${OBF_ARCH}" /usr/local/bin/wg-obfuscator 2>/dev/null || true
- cd /; rm -rf "$R"
-fi
-_OBF_TAG=$(curl -fsSL -m10 https://api.github.com/repos/ClusterM/wg-obfuscator/releases/latest 2>/dev/null | grep '"tag_name"' | head -1 | sed 's/.*"tag_name": *"\(.*\)".*/\1/')
-_CB="https://github.com/ClusterM/wg-obfuscator/releases/download/${_OBF_TAG}"
-for _am in "x86_64:linux-x64" "aarch64:linux-arm64" "mipsel:linux-mipsel-mips32" "mips:linux-mips-mips32" "armv7:linux-armv7-hf"; do
- _da="${_am%%:*}"; _ss="${_am##*:}"
- if [ ! -f "$PHOBOS_DIR/bin/wg-obfuscator-${_da}" ] && [ -n "$_OBF_TAG" ]; then
- _t=$(mktemp -d)
- curl -fsSL -m30 "${_CB}/wg-obfuscator-${_OBF_TAG}-${_ss}.tar.gz" -o "$_t/o.tgz" 2>/dev/null &&
- tar -xzf "$_t/o.tgz" -C "$_t" 2>/dev/null &&
- _b=$(find "$_t" -name "wg-obfuscator" -type f | head -1) &&
- [ -n "$_b" ] && cp "$_b" "$PHOBOS_DIR/bin/wg-obfuscator-${_da}" && chmod +x "$PHOBOS_DIR/bin/wg-obfuscator-${_da}" && echo " +wg-obfuscator-${_da} (ClusterM ${_OBF_TAG})"
- rm -rf "$_t"
- fi
-done
-[ -x /usr/local/bin/wg-obfuscator ] || ln -sf "$PHOBOS_DIR/bin/wg-obfuscator-${OBF_ARCH}" /usr/local/bin/wg-obfuscator 2>/dev/null || true
-[ -x /usr/local/bin/wg-obfuscator ] || { echo "ERROR: obfuscator binary for $ARCH missing"; exit 1; }
-echo " bins: $(ls $PHOBOS_DIR/bin/ | tr '\n' ' ')"
-
-# ── 3. Phobos repo (onboarding scripts) ──
-echo "[3/9] Phobos repo (onboarding scripts)..."
-R="$PHOBOS_DIR/repo"; rm -rf "$R"; mkdir -p "$R"; cd "$R"
-git init -q; git remote add origin https://github.com/Ground-Zerro/Phobos.git
-git config core.sparseCheckout true
-printf 'server\nclient\n' > .git/info/sparse-checkout
-git pull origin main -q; rm -rf .git
-find "$R" -name '*.sh' -exec chmod +x {} \; 2>/dev/null || true
-cd /
-
-# ── 4. WireGuard wg0 (primary) ──
-echo "[4/9] WireGuard wg0..."
-if [ ! -f /etc/wireguard/wg0.conf ]; then
- WG_PRIV=$(wg genkey); WG_PUB=$(echo "$WG_PRIV" | wg pubkey)
- cat > /etc/wireguard/wg0.conf <> /etc/sysctl.conf
-systemctl enable wg-quick@wg0 -q 2>/dev/null || true
-systemctl restart wg-quick@wg0
-
-# ── 5. obfuscator services (multi-port) ──
-echo "[5/9] obfuscator services..."
-OBF_KEY=$(head -c 32 /dev/urandom | base64 | tr -d '/+=' | head -c 32)
-# Block direct WG (force obfuscation) unless ALLOW_PLAIN_WG=1 (e.g. for iOS WireGuard)
-if [ -z "${ALLOW_PLAIN_WG:-}" ]; then
- iptables -C INPUT -p udp --dport 51820 ! -s 127.0.0.1 -j DROP 2>/dev/null \
- || iptables -A INPUT -p udp --dport 51820 ! -s 127.0.0.1 -j DROP
-else
- iptables -D INPUT -p udp --dport 51820 ! -s 127.0.0.1 -j DROP 2>/dev/null || true
-fi
-IFS=',' read -ra PORTS <<< "$OBF_PORTS"
-for PORT in "${PORTS[@]}"; do
- cat > "$PHOBOS_DIR/server/wg-obfuscator-${PORT}.conf" < /etc/systemd/system/wg-obfuscator-${PORT}.service < "$PHOBOS_DIR/server/server.env" </dev/null || true
-fetch overlay/phobos-uninstall.sh "$PHOBOS_DIR/repo/client/templates/phobos-uninstall.sh" && chmod +x "$PHOBOS_DIR/repo/client/templates/phobos-uninstall.sh"
-fetch overlay/3xui.sh "$PHOBOS_DIR/repo/client/templates/3xui.sh" && chmod +x "$PHOBOS_DIR/repo/client/templates/3xui.sh"
-fetch server/phobos-warp.sh "$PHOBOS_DIR/server/phobos-warp.sh" && chmod +x "$PHOBOS_DIR/server/phobos-warp.sh" && ln -sf "$PHOBOS_DIR/server/phobos-warp.sh" /usr/local/bin/phobos-warp
-fetch server/phobos-guard.sh "$PHOBOS_DIR/server/phobos-guard.sh" && chmod +x "$PHOBOS_DIR/server/phobos-guard.sh" && ln -sf "$PHOBOS_DIR/server/phobos-guard.sh" /usr/local/bin/phobos-guard
-fetch server/phobos-cascade.sh "$PHOBOS_DIR/server/phobos-cascade.sh" && chmod +x "$PHOBOS_DIR/server/phobos-cascade.sh" && ln -sf "$PHOBOS_DIR/server/phobos-cascade.sh" /usr/local/bin/phobos-cascade
-fetch server/phobos-domain.sh "$PHOBOS_DIR/server/phobos-domain.sh" && chmod +x "$PHOBOS_DIR/server/phobos-domain.sh" && ln -sf "$PHOBOS_DIR/server/phobos-domain.sh" /usr/local/bin/phobos-domain
-fetch server/phobos-limit.sh "$PHOBOS_DIR/server/phobos-limit.sh" && chmod +x "$PHOBOS_DIR/server/phobos-limit.sh"
-fetch server/phobos-speedtest.sh "$PHOBOS_DIR/server/phobos-speedtest.sh" && chmod +x "$PHOBOS_DIR/server/phobos-speedtest.sh"
-fetch server/phobos-tcp.sh "$PHOBOS_DIR/server/phobos-tcp.sh" && chmod +x "$PHOBOS_DIR/server/phobos-tcp.sh" && ln -sf "$PHOBOS_DIR/server/phobos-tcp.sh" /usr/local/bin/phobos-tcp
-fetch "udptcp/bin/udptcp-$OBF_ARCH" "$PHOBOS_DIR/bin/udptcp" && chmod +x "$PHOBOS_DIR/bin/udptcp"
-fetch server/phobos-health.sh "$PHOBOS_DIR/server/phobos-health.sh" && chmod +x "$PHOBOS_DIR/server/phobos-health.sh"
-fetch server/phobos-self-check.sh "$PHOBOS_DIR/server/phobos-self-check.sh" && chmod +x "$PHOBOS_DIR/server/phobos-self-check.sh" && ln -sf "$PHOBOS_DIR/server/phobos-self-check.sh" /usr/local/bin/phobos-self-check
-fetch server/phobos-pull.sh "$PHOBOS_DIR/server/phobos-pull.sh" && chmod +x "$PHOBOS_DIR/server/phobos-pull.sh"
-fetch server/phobos-router-watchdog.py "$PHOBOS_DIR/server/phobos-router-watchdog.py"
-fetch server/api.py "$PHOBOS_DIR/server/api.py"
-fetch server/secondary-setup.sh "$PHOBOS_DIR/server/secondary-setup.sh" && chmod +x "$PHOBOS_DIR/server/secondary-setup.sh"
-fetch update.sh "$PHOBOS_DIR/server/update.sh" && chmod +x "$PHOBOS_DIR/server/update.sh" && ln -sf "$PHOBOS_DIR/server/update.sh" /usr/local/bin/phobos-update
-fetch server/phobos-backup.sh "$PHOBOS_DIR/server/phobos-backup.sh" && chmod +x "$PHOBOS_DIR/server/phobos-backup.sh" && ln -sf "$PHOBOS_DIR/server/phobos-backup.sh" /usr/local/bin/phobos-backup
-mkdir -p "$PANEL_DIR"; fetch VERSION "$PANEL_DIR/.version" 2>/dev/null || true
-[ -f "$PHOBOS_DIR/tokens/tokens.json" ] || echo '[]' > "$PHOBOS_DIR/tokens/tokens.json"
-"$PHOBOS_DIR/server/phobos-self-check.sh" --fix
-
-# ── 7. web panel ──
-echo "[7/9] web panel..."
-mkdir -p "$PANEL_DIR"
-fetch app.py "$PANEL_DIR/app.py" || { echo "ERROR: panel app.py fetch failed"; exit 1; }
-if [ ! -f "$PANEL_DIR/settings.json" ]; then
- cat > "$PANEL_DIR/settings.json" < "$PANEL_DIR/.port"
-echo "$PANEL_SCHEME" > "$PANEL_DIR/.scheme"
-TLS_ARGS=""
-if [ "$PANEL_SCHEME" = "https" ]; then
- TLS_ARGS="--certfile $PANEL_TLS_CERT --keyfile $PANEL_TLS_KEY"
-fi
-cat > /etc/systemd/system/phobos-panel.service </dev/null || true
-cat > /etc/nginx/sites-available/phobos <<'NGINX'
-server {
- listen 80 default_server;
- listen [::]:80 default_server;
- location /init/ { alias /opt/Phobos/www/init/; default_type application/x-sh; }
- location /packages/ { alias /opt/Phobos/www/packages/; default_type application/octet-stream; }
- location /app/ { alias /opt/Phobos/www/app/; default_type application/octet-stream; }
- location / { return 404; }
-}
-NGINX
-ln -sf /etc/nginx/sites-available/phobos /etc/nginx/sites-enabled/phobos
-mkdir -p /opt/Phobos/www/app; chmod 755 /opt/Phobos/www /opt/Phobos/www/init /opt/Phobos/www/packages /opt/Phobos/www/app
-nginx -t >/dev/null 2>&1 && systemctl enable nginx -q 2>/dev/null && systemctl restart nginx || echo " WARN: nginx config test failed"
-
-# ── 9. router watchdog (auto reboot-recovery) ──
-echo "[9/9] router watchdog..."
-if [ -f "$PHOBOS_DIR/server/phobos-router-watchdog.py" ]; then
- # set -e safe: grep -v on an empty crontab returns 1, so guard with || true
- CRON_CUR=$(crontab -l 2>/dev/null | grep -v phobos-router-watchdog || true)
- printf '%s\n%s\n' "$CRON_CUR" \
- "*/3 * * * * /usr/bin/python3 $PHOBOS_DIR/server/phobos-router-watchdog.py >/dev/null 2>&1" \
- | grep -v '^[[:space:]]*$' | crontab -
-fi
-
-sleep 2
-
-# persist channel so phobos-update follows it
-mkdir -p "$PANEL_DIR"
-echo "$CHANNEL" > "$PANEL_DIR/.channel" 2>/dev/null || true
-
-echo ""
-echo "============================================"
-echo " Installation complete"
-echo " Panel : $PANEL_SCHEME://$SERVER_IP:$PANEL_PORT"
-echo " Login : admin"
-echo " Pass : $PANEL_PASS"
-echo " API key (agents+pull): $API_KEY"
-echo " WG pub: $WG_PUB"
-echo "============================================"
-echo "Status:"
-for s in wg-quick@wg0 phobos-panel nginx; do printf " %-18s %s\n" "$s" "$(systemctl is-active $s 2>/dev/null)"; done
-for PORT in "${PORTS[@]}"; do printf " %-18s %s\n" "wg-obfuscator-$PORT" "$(systemctl is-active wg-obfuscator-$PORT 2>/dev/null)"; done
diff --git a/ios/.gitignore b/ios/.gitignore
deleted file mode 100644
index ff2c642..0000000
--- a/ios/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-build/
-*.xcuserstate
-xcuserdata/
diff --git a/ios/App/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/App/Assets.xcassets/AppIcon.appiconset/Contents.json
deleted file mode 100644
index e13552c..0000000
--- a/ios/App/Assets.xcassets/AppIcon.appiconset/Contents.json
+++ /dev/null
@@ -1 +0,0 @@
-{"images":[{"filename":"icon-1024.png","idiom":"universal","platform":"ios","size":"1024x1024"}],"info":{"author":"xcode","version":1}}
diff --git a/ios/App/Assets.xcassets/AppIcon.appiconset/icon-1024.png b/ios/App/Assets.xcassets/AppIcon.appiconset/icon-1024.png
deleted file mode 100644
index 9237726..0000000
Binary files a/ios/App/Assets.xcassets/AppIcon.appiconset/icon-1024.png and /dev/null differ
diff --git a/ios/App/Assets.xcassets/Contents.json b/ios/App/Assets.xcassets/Contents.json
deleted file mode 100644
index f223229..0000000
--- a/ios/App/Assets.xcassets/Contents.json
+++ /dev/null
@@ -1 +0,0 @@
-{"info":{"author":"xcode","version":1}}
diff --git a/ios/App/ContentView.swift b/ios/App/ContentView.swift
deleted file mode 100644
index 6228620..0000000
--- a/ios/App/ContentView.swift
+++ /dev/null
@@ -1,97 +0,0 @@
-import NetworkExtension
-import SwiftUI
-
-struct ContentView: View {
- @EnvironmentObject var vpn: VPNController
- @State private var pasteText = ""
- @State private var showImport = false
-
- var body: some View {
- NavigationStack {
- ScrollView {
- VStack(spacing: 18) {
- profileCard
- powerButton
- statusLine
- optionsCard
- Button { showImport = true } label: {
- Label("Импорт ссылки phobos://", systemImage: "square.and.arrow.down")
- .frame(maxWidth: .infinity).padding(.vertical, 12)
- }
- .buttonStyle(.borderedProminent).tint(.indigo)
- Link(destination: URL(string: "https://speed.cloudflare.com/")!) {
- Label("Проверить скорость", systemImage: "speedometer").frame(maxWidth: .infinity).padding(.vertical, 12)
- }
- .buttonStyle(.bordered)
- if !vpn.message.isEmpty {
- Text(vpn.message).font(.footnote).foregroundStyle(.secondary).multilineTextAlignment(.center)
- }
- }
- .padding()
- }
- .navigationTitle("PCA Phobos VPN")
- .alert("Ссылка из панели", isPresented: $showImport) {
- TextField("phobos://…", text: $pasteText)
- Button("Импорт") { vpn.importLink(pasteText); pasteText = "" }
- Button("Из буфера") { vpn.importLink(UIPasteboard.general.string ?? "") }
- Button("Отмена", role: .cancel) {}
- } message: {
- Text("В панели: клиент → 📱 → ссылка phobos://. Можно просто открыть ссылку на iPhone — профиль импортируется сам.")
- }
- }
- }
-
- private var profileCard: some View {
- VStack(alignment: .leading, spacing: 4) {
- if let p = vpn.profile {
- Text(vpn.name).font(.title3.bold())
- Text("Сервер: \(p.target ?? "?")").font(.subheadline).foregroundStyle(.secondary)
- if let tcp = p.tcpPort { Text("Резервный TCP: порт \(tcp)").font(.caption).foregroundStyle(.secondary) }
- } else {
- Text("Профиль не импортирован").font(.headline)
- Text("Откройте на iPhone ссылку phobos:// из панели PCA Phobos или вставьте её кнопкой ниже.")
- .font(.subheadline).foregroundStyle(.secondary)
- }
- }
- .frame(maxWidth: .infinity, alignment: .leading)
- .padding().background(.thinMaterial, in: RoundedRectangle(cornerRadius: 16))
- }
-
- private var powerButton: some View {
- Button(action: vpn.toggle) {
- Text(vpn.isOn ? "Отключить" : "Подключить")
- .font(.title2.bold()).foregroundStyle(.white)
- .frame(width: 180, height: 180)
- .background(Circle().fill(vpn.isOn ? Color.green : Color.indigo))
- }
- .padding(.top, 8)
- }
-
- private var statusLine: some View {
- let text: String = {
- switch vpn.status {
- case .connected: return "🟢 VPN включён" + (vpn.transport.isEmpty ? "" : " · \(vpn.transport)")
- case .connecting, .reasserting: return "🟡 Подключение…"
- case .disconnecting: return "Отключение…"
- default: return "⚪ VPN выключен"
- }
- }()
- return Text(text).font(.headline)
- }
-
- private var optionsCard: some View {
- VStack(alignment: .leading, spacing: 12) {
- Toggle("Российские сайты — напрямую, без VPN", isOn: $vpn.ruDirect)
- VStack(alignment: .leading, spacing: 6) {
- Text("Канал до сервера").font(.subheadline.bold())
- Picker("Канал", selection: $vpn.transportMode) {
- Text("Авто").tag("auto"); Text("UDP").tag("udp"); Text("TCP").tag("tcp")
- }
- .pickerStyle(.segmented)
- Text("Авто: если UDP режут, через 15 секунд переходит на TCP. Изменения применяются сразу.")
- .font(.caption).foregroundStyle(.secondary)
- }
- }
- .padding().background(.thinMaterial, in: RoundedRectangle(cornerRadius: 16))
- }
-}
diff --git a/ios/App/Info.plist b/ios/App/Info.plist
deleted file mode 100644
index 5b0f071..0000000
--- a/ios/App/Info.plist
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
- CFBundleDevelopmentRegion
- $(DEVELOPMENT_LANGUAGE)
- CFBundleDisplayName
- PCA Phobos
- CFBundleExecutable
- $(EXECUTABLE_NAME)
- CFBundleIdentifier
- $(PRODUCT_BUNDLE_IDENTIFIER)
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleName
- $(PRODUCT_NAME)
- CFBundlePackageType
- APPL
- CFBundleShortVersionString
- 1.0
- CFBundleURLTypes
-
-
- CFBundleURLName
- com.bobyrev.pcaphobos.link
- CFBundleURLSchemes
-
- phobos
-
-
-
- CFBundleVersion
- 1
- UILaunchScreen
-
- UISupportedInterfaceOrientations
-
- UIInterfaceOrientationPortrait
-
-
-
diff --git a/ios/App/PCAPhobos.entitlements b/ios/App/PCAPhobos.entitlements
deleted file mode 100644
index ffab33e..0000000
--- a/ios/App/PCAPhobos.entitlements
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
- com.apple.developer.networking.networkextension
-
- packet-tunnel-provider
-
-
-
diff --git a/ios/App/PCAPhobosApp.swift b/ios/App/PCAPhobosApp.swift
deleted file mode 100644
index 740dd56..0000000
--- a/ios/App/PCAPhobosApp.swift
+++ /dev/null
@@ -1,103 +0,0 @@
-import NetworkExtension
-import SwiftUI
-
-@main
-struct PCAPhobosApp: App {
- @StateObject private var vpn = VPNController()
-
- var body: some Scene {
- WindowGroup {
- ContentView()
- .environmentObject(vpn)
- .onOpenURL { vpn.importLink($0.absoluteString) } // phobos:// from the panel
- }
- }
-}
-
-/// Owns the NETunnelProviderManager: profile, options, connect/disconnect, live status.
-@MainActor
-final class VPNController: ObservableObject {
- @Published var name = UserDefaults.standard.string(forKey: "name") ?? ""
- @Published var conf = UserDefaults.standard.string(forKey: "conf") ?? ""
- @Published var ruDirect = UserDefaults.standard.object(forKey: "ruDirect") as? Bool ?? true { didSet { saveOptions() } }
- @Published var transportMode = UserDefaults.standard.string(forKey: "transport") ?? "auto" { didSet { saveOptions() } }
- @Published var status: NEVPNStatus = .invalid
- @Published var transport = ""
- @Published var message = ""
-
- private var manager: NETunnelProviderManager?
- private var timer: Timer?
-
- init() {
- Task { await load() }
- NotificationCenter.default.addObserver(forName: .NEVPNStatusDidChange, object: nil, queue: .main) { [weak self] _ in
- Task { @MainActor in self?.status = self?.manager?.connection.status ?? .invalid }
- }
- timer = Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { [weak self] _ in
- Task { @MainActor in self?.pollTransport() }
- }
- }
-
- var profile: PhobosProfile? { conf.isEmpty ? nil : PhobosProfile(conf) }
- var isOn: Bool { status == .connected || status == .connecting || status == .reasserting }
-
- func load() async {
- let all = (try? await NETunnelProviderManager.loadAllFromPreferences()) ?? []
- manager = all.first
- status = manager?.connection.status ?? .invalid
- }
-
- func importLink(_ link: String) {
- guard let parsed = PhobosProfile.fromLink(link) else { message = "Это не ссылка phobos:// из панели"; return }
- conf = parsed.profile.raw
- name = parsed.name
- UserDefaults.standard.set(conf, forKey: "conf")
- UserDefaults.standard.set(name, forKey: "name")
- message = "Профиль «\(name)» импортирован"
- Task { await save(reconnect: isOn) }
- }
-
- private func saveOptions() {
- UserDefaults.standard.set(ruDirect, forKey: "ruDirect")
- UserDefaults.standard.set(transportMode, forKey: "transport")
- Task { await save(reconnect: isOn) }
- }
-
- /// Write the VPN configuration to iOS settings (asks the user once).
- func save(reconnect: Bool = false) async {
- guard let profile else { return }
- let m = manager ?? NETunnelProviderManager()
- let proto = NETunnelProviderProtocol()
- proto.providerBundleIdentifier = "com.bobyrev.pcaphobos.tunnel"
- proto.serverAddress = profile.targetHost ?? "Phobos"
- proto.providerConfiguration = ["conf": conf, "ruDirect": ruDirect, "transport": transportMode]
- m.protocolConfiguration = proto
- m.localizedDescription = "PCA Phobos"
- m.isEnabled = true
- do {
- try await m.saveToPreferences()
- try await m.loadFromPreferences()
- manager = m
- if reconnect { m.connection.stopVPNTunnel(); try await Task.sleep(nanoseconds: 1_000_000_000); try m.connection.startVPNTunnel() }
- } catch {
- message = "Не удалось сохранить VPN: \(error.localizedDescription)"
- }
- }
-
- func toggle() {
- Task {
- if isOn { manager?.connection.stopVPNTunnel(); return }
- guard profile != nil else { message = "Сначала импортируйте ссылку phobos:// из панели"; return }
- await save()
- do { try manager?.connection.startVPNTunnel() } catch { message = "Ошибка: \(error.localizedDescription)" }
- }
- }
-
- private func pollTransport() {
- guard status == .connected, let session = manager?.connection as? NETunnelProviderSession else { transport = ""; return }
- try? session.sendProviderMessage(Data()) { [weak self] data in
- guard let data, let obj = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { return }
- Task { @MainActor in self?.transport = obj["transport"] as? String ?? "" }
- }
- }
-}
diff --git a/ios/PCAPhobos.xcodeproj/project.pbxproj b/ios/PCAPhobos.xcodeproj/project.pbxproj
deleted file mode 100644
index 44d583f..0000000
--- a/ios/PCAPhobos.xcodeproj/project.pbxproj
+++ /dev/null
@@ -1,572 +0,0 @@
-// !$*UTF8*$!
-{
- archiveVersion = 1;
- classes = {
- };
- objectVersion = 77;
- objects = {
-
-/* Begin PBXBuildFile section */
- 008DA398D56DFBDB16D97CE1 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF14952A4263FF0E004A3F04 /* ContentView.swift */; };
- 08C4842C3185E04B2154C971 /* WireGuardKit in Frameworks */ = {isa = PBXBuildFile; productRef = FA829997FAB330F6EFA104C9 /* WireGuardKit */; };
- 11F2A6A8D281AB36B45D4603 /* TunnelConfiguration+WgQuickConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C1AA6DED9B45949864A9B7D /* TunnelConfiguration+WgQuickConfig.swift */; };
- 1C05D29ACA95548374AD6FD9 /* logging.c in Sources */ = {isa = PBXBuildFile; fileRef = 9FC04650634F03E6DB09AB6B /* logging.c */; settings = {COMPILER_FLAGS = "-Dmain=wgobf_main -w"; }; };
- 38870650A7C2B1F0927A1230 /* wg-obfuscator.c in Sources */ = {isa = PBXBuildFile; fileRef = 1FADBB2A65AF77D4ECCAFE78 /* wg-obfuscator.c */; settings = {COMPILER_FLAGS = "-Dmain=wgobf_main -w"; }; };
- 4E4255B9E0F8626F6E209B0F /* String+ArrayConversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7500F0B31797D49B5BBEC5CC /* String+ArrayConversion.swift */; };
- 56F35C68C6A387E499703CFF /* masking.c in Sources */ = {isa = PBXBuildFile; fileRef = CCE5C98CD905BDE16A8D83D4 /* masking.c */; settings = {COMPILER_FLAGS = "-Dmain=wgobf_main -w"; }; };
- 5F5D376513C0B27C45A3E7B6 /* ru_bypass.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2572D9A6F822B038D0652619 /* ru_bypass.txt */; };
- 78B74F81E0042D9AD94B7A6B /* config.c in Sources */ = {isa = PBXBuildFile; fileRef = 0E5C1673464AAC3EF81DD2FE /* config.c */; settings = {COMPILER_FLAGS = "-Dmain=wgobf_main -w"; }; };
- 7D8AB66421409CBFCCF2769A /* PhobosProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98DC1765DEC5F326E2B5F9C4 /* PhobosProfile.swift */; };
- 99F5DB52833E3B5505EEA727 /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E36BA501FDCB2034F09415A /* PacketTunnelProvider.swift */; };
- B3BB8BE3409D63FEB59B5449 /* obfuscation.c in Sources */ = {isa = PBXBuildFile; fileRef = EF9115CA0D5EC52C8679A12A /* obfuscation.c */; settings = {COMPILER_FLAGS = "-Dmain=wgobf_main -w"; }; };
- C3C41D3C419E8D17F20A38B5 /* PCAPhobosApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3E470E13EF603CB26991683 /* PCAPhobosApp.swift */; };
- C6116E8B9CDFEE363BCBD2D6 /* PhobosTunnel.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = A81F96BF4131FDBB816623BE /* PhobosTunnel.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
- CBC338B91B5FCE1E207B36AC /* PhobosProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98DC1765DEC5F326E2B5F9C4 /* PhobosProfile.swift */; };
- D8CCC1E6CC8164EDD4E34D25 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6359B8954E69147DA50EDB46 /* Assets.xcassets */; };
- DF6D62C526E908CA5CDDFCAE /* pcarelay.c in Sources */ = {isa = PBXBuildFile; fileRef = 211950F8776D3D14D7B9C49A /* pcarelay.c */; };
- E88105F9325A93041D617213 /* masking_stun.c in Sources */ = {isa = PBXBuildFile; fileRef = 05DD44245829A52D32B42AF8 /* masking_stun.c */; settings = {COMPILER_FLAGS = "-Dmain=wgobf_main -w"; }; };
-/* End PBXBuildFile section */
-
-/* Begin PBXContainerItemProxy section */
- B9875EF5DEB6362919B43F22 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = E59D1112D2B128DF6FE7A1E9 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 0FD066BC2C51A1E092914FE8;
- remoteInfo = PhobosTunnel;
- };
-/* End PBXContainerItemProxy section */
-
-/* Begin PBXCopyFilesBuildPhase section */
- 9FC25420ED5EF973CE140584 /* Embed Foundation Extensions */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 2147483647;
- dstPath = "";
- dstSubfolderSpec = 13;
- files = (
- C6116E8B9CDFEE363BCBD2D6 /* PhobosTunnel.appex in Embed Foundation Extensions */,
- );
- name = "Embed Foundation Extensions";
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXCopyFilesBuildPhase section */
-
-/* Begin PBXFileReference section */
- 027878C5E0654DB27FAE88A3 /* PCAPhobos.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = PCAPhobos.app; sourceTree = BUILT_PRODUCTS_DIR; };
- 05DD44245829A52D32B42AF8 /* masking_stun.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = masking_stun.c; sourceTree = ""; };
- 0E5C1673464AAC3EF81DD2FE /* config.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = config.c; sourceTree = ""; };
- 1FADBB2A65AF77D4ECCAFE78 /* wg-obfuscator.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "wg-obfuscator.c"; sourceTree = ""; };
- 211950F8776D3D14D7B9C49A /* pcarelay.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pcarelay.c; sourceTree = ""; };
- 2572D9A6F822B038D0652619 /* ru_bypass.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = ru_bypass.txt; sourceTree = ""; };
- 2C1AA6DED9B45949864A9B7D /* TunnelConfiguration+WgQuickConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TunnelConfiguration+WgQuickConfig.swift"; sourceTree = ""; };
- 6359B8954E69147DA50EDB46 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
- 722DE8EFC35A88BC68637FB4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; };
- 7500F0B31797D49B5BBEC5CC /* String+ArrayConversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+ArrayConversion.swift"; sourceTree = ""; };
- 7E66B3AD4BB22D2AB5676E10 /* PCAPhobos.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = PCAPhobos.entitlements; sourceTree = ""; };
- 8E36BA501FDCB2034F09415A /* PacketTunnelProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelProvider.swift; sourceTree = ""; };
- 98DC1765DEC5F326E2B5F9C4 /* PhobosProfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhobosProfile.swift; sourceTree = ""; };
- 9FC04650634F03E6DB09AB6B /* logging.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = logging.c; sourceTree = ""; };
- A81F96BF4131FDBB816623BE /* PhobosTunnel.appex */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "wrapper.app-extension"; path = PhobosTunnel.appex; sourceTree = BUILT_PRODUCTS_DIR; };
- B3E470E13EF603CB26991683 /* PCAPhobosApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PCAPhobosApp.swift; sourceTree = ""; };
- CA6480536DA633DB94B6930F /* WireGuardKit */ = {isa = PBXFileReference; lastKnownFileType = folder; name = WireGuardKit; path = WireGuardKit; sourceTree = SOURCE_ROOT; };
- CCE5C98CD905BDE16A8D83D4 /* masking.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = masking.c; sourceTree = ""; };
- EF9115CA0D5EC52C8679A12A /* obfuscation.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = obfuscation.c; sourceTree = ""; };
- FF14952A4263FF0E004A3F04 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
- D366EA9C7C0EC88CAE5EA47E /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 08C4842C3185E04B2154C971 /* WireGuardKit in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
- 1EBBB94A186F7080FE3609C8 /* Products */ = {
- isa = PBXGroup;
- children = (
- 027878C5E0654DB27FAE88A3 /* PCAPhobos.app */,
- A81F96BF4131FDBB816623BE /* PhobosTunnel.appex */,
- );
- name = Products;
- sourceTree = "";
- };
- 2500D202DC9E96E7BBCE29B1 /* Tunnel */ = {
- isa = PBXGroup;
- children = (
- 8E36BA501FDCB2034F09415A /* PacketTunnelProvider.swift */,
- 211950F8776D3D14D7B9C49A /* pcarelay.c */,
- 2572D9A6F822B038D0652619 /* ru_bypass.txt */,
- 7500F0B31797D49B5BBEC5CC /* String+ArrayConversion.swift */,
- 2C1AA6DED9B45949864A9B7D /* TunnelConfiguration+WgQuickConfig.swift */,
- );
- path = Tunnel;
- sourceTree = "";
- };
- 527268DF962A8B7EC120C536 /* obfuscator */ = {
- isa = PBXGroup;
- children = (
- 0E5C1673464AAC3EF81DD2FE /* config.c */,
- 9FC04650634F03E6DB09AB6B /* logging.c */,
- 05DD44245829A52D32B42AF8 /* masking_stun.c */,
- CCE5C98CD905BDE16A8D83D4 /* masking.c */,
- EF9115CA0D5EC52C8679A12A /* obfuscation.c */,
- 1FADBB2A65AF77D4ECCAFE78 /* wg-obfuscator.c */,
- );
- name = obfuscator;
- path = Tunnel/obfuscator;
- sourceTree = "";
- };
- D4CB33FA621F53C8F82ED115 /* Packages */ = {
- isa = PBXGroup;
- children = (
- CA6480536DA633DB94B6930F /* WireGuardKit */,
- );
- name = Packages;
- sourceTree = "";
- };
- DD1FD95C0B2DE48623872799 /* App */ = {
- isa = PBXGroup;
- children = (
- 6359B8954E69147DA50EDB46 /* Assets.xcassets */,
- FF14952A4263FF0E004A3F04 /* ContentView.swift */,
- 722DE8EFC35A88BC68637FB4 /* Info.plist */,
- 7E66B3AD4BB22D2AB5676E10 /* PCAPhobos.entitlements */,
- B3E470E13EF603CB26991683 /* PCAPhobosApp.swift */,
- );
- path = App;
- sourceTree = "";
- };
- E31449B836D353F74991D905 = {
- isa = PBXGroup;
- children = (
- DD1FD95C0B2DE48623872799 /* App */,
- 527268DF962A8B7EC120C536 /* obfuscator */,
- D4CB33FA621F53C8F82ED115 /* Packages */,
- F6FC482145D1EFAD5A15F63B /* Shared */,
- 2500D202DC9E96E7BBCE29B1 /* Tunnel */,
- 1EBBB94A186F7080FE3609C8 /* Products */,
- );
- sourceTree = "";
- };
- F6FC482145D1EFAD5A15F63B /* Shared */ = {
- isa = PBXGroup;
- children = (
- 98DC1765DEC5F326E2B5F9C4 /* PhobosProfile.swift */,
- );
- path = Shared;
- sourceTree = "";
- };
-/* End PBXGroup section */
-
-/* Begin PBXNativeTarget section */
- 0FD066BC2C51A1E092914FE8 /* PhobosTunnel */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 329F6A5A13B95B1525F94841 /* Build configuration list for PBXNativeTarget "PhobosTunnel" */;
- buildPhases = (
- 173BA4C39EE769A34EBB19CB /* Sources */,
- A5352C1E8C48FFB2CCEC38F3 /* Resources */,
- D366EA9C7C0EC88CAE5EA47E /* Frameworks */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = PhobosTunnel;
- packageProductDependencies = (
- FA829997FAB330F6EFA104C9 /* WireGuardKit */,
- );
- productName = PhobosTunnel;
- productReference = A81F96BF4131FDBB816623BE /* PhobosTunnel.appex */;
- productType = "com.apple.product-type.app-extension";
- };
- E1F7E69029753CF102C6CE2E /* PCAPhobos */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 61EF055D39FD21A29FA039D5 /* Build configuration list for PBXNativeTarget "PCAPhobos" */;
- buildPhases = (
- F83DEE91B85335727CA6B39E /* Sources */,
- D18596DD6D613F6BC9647644 /* Resources */,
- 9FC25420ED5EF973CE140584 /* Embed Foundation Extensions */,
- );
- buildRules = (
- );
- dependencies = (
- 0B334C04E5AD898D8736FFAA /* PBXTargetDependency */,
- );
- name = PCAPhobos;
- packageProductDependencies = (
- );
- productName = PCAPhobos;
- productReference = 027878C5E0654DB27FAE88A3 /* PCAPhobos.app */;
- productType = "com.apple.product-type.application";
- };
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
- E59D1112D2B128DF6FE7A1E9 /* Project object */ = {
- isa = PBXProject;
- attributes = {
- BuildIndependentTargetsInParallel = YES;
- LastUpgradeCheck = 1430;
- TargetAttributes = {
- 0FD066BC2C51A1E092914FE8 = {
- DevelopmentTeam = "";
- ProvisioningStyle = Automatic;
- };
- E1F7E69029753CF102C6CE2E = {
- DevelopmentTeam = "";
- ProvisioningStyle = Automatic;
- };
- };
- };
- buildConfigurationList = F73680B923D76C65D03B442C /* Build configuration list for PBXProject "PCAPhobos" */;
- developmentRegion = en;
- hasScannedForEncodings = 0;
- knownRegions = (
- Base,
- en,
- );
- mainGroup = E31449B836D353F74991D905;
- minimizedProjectReferenceProxies = 1;
- packageReferences = (
- 9F8EC62EA6724F5FA6B8BAE0 /* XCLocalSwiftPackageReference "WireGuardKit" */,
- );
- preferredProjectObjectVersion = 77;
- productRefGroup = 1EBBB94A186F7080FE3609C8 /* Products */;
- projectDirPath = "";
- projectRoot = "";
- targets = (
- E1F7E69029753CF102C6CE2E /* PCAPhobos */,
- 0FD066BC2C51A1E092914FE8 /* PhobosTunnel */,
- );
- };
-/* End PBXProject section */
-
-/* Begin PBXResourcesBuildPhase section */
- A5352C1E8C48FFB2CCEC38F3 /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 5F5D376513C0B27C45A3E7B6 /* ru_bypass.txt in Resources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D18596DD6D613F6BC9647644 /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D8CCC1E6CC8164EDD4E34D25 /* Assets.xcassets in Resources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXSourcesBuildPhase section */
- 173BA4C39EE769A34EBB19CB /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 99F5DB52833E3B5505EEA727 /* PacketTunnelProvider.swift in Sources */,
- 7D8AB66421409CBFCCF2769A /* PhobosProfile.swift in Sources */,
- 4E4255B9E0F8626F6E209B0F /* String+ArrayConversion.swift in Sources */,
- 11F2A6A8D281AB36B45D4603 /* TunnelConfiguration+WgQuickConfig.swift in Sources */,
- 78B74F81E0042D9AD94B7A6B /* config.c in Sources */,
- 1C05D29ACA95548374AD6FD9 /* logging.c in Sources */,
- 56F35C68C6A387E499703CFF /* masking.c in Sources */,
- E88105F9325A93041D617213 /* masking_stun.c in Sources */,
- B3BB8BE3409D63FEB59B5449 /* obfuscation.c in Sources */,
- DF6D62C526E908CA5CDDFCAE /* pcarelay.c in Sources */,
- 38870650A7C2B1F0927A1230 /* wg-obfuscator.c in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- F83DEE91B85335727CA6B39E /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 008DA398D56DFBDB16D97CE1 /* ContentView.swift in Sources */,
- C3C41D3C419E8D17F20A38B5 /* PCAPhobosApp.swift in Sources */,
- CBC338B91B5FCE1E207B36AC /* PhobosProfile.swift in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXSourcesBuildPhase section */
-
-/* Begin PBXTargetDependency section */
- 0B334C04E5AD898D8736FFAA /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 0FD066BC2C51A1E092914FE8 /* PhobosTunnel */;
- targetProxy = B9875EF5DEB6362919B43F22 /* PBXContainerItemProxy */;
- };
-/* End PBXTargetDependency section */
-
-/* Begin XCBuildConfiguration section */
- 35473CF1EA2AAAC350F346D0 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- CODE_SIGN_ENTITLEMENTS = App/PCAPhobos.entitlements;
- CODE_SIGN_IDENTITY = "iPhone Developer";
- INFOPLIST_FILE = App/Info.plist;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/Frameworks",
- );
- PRODUCT_BUNDLE_IDENTIFIER = com.bobyrev.pcaphobos;
- SDKROOT = iphoneos;
- TARGETED_DEVICE_FAMILY = "1,2";
- };
- name = Release;
- };
- 62739003B63EE4EE3B3FF1FB /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CODE_SIGN_ENTITLEMENTS = Tunnel/PhobosTunnel.entitlements;
- "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = x86_64;
- HEADER_SEARCH_PATHS = (
- "$(PROJECT_DIR)/Tunnel",
- "$(PROJECT_DIR)/Tunnel/obfuscator",
- );
- INFOPLIST_FILE = Tunnel/Info.plist;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/Frameworks",
- "@executable_path/../../Frameworks",
- );
- "LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = (
- "$(PROJECT_DIR)/WireGuardGo/iphoneos",
- );
- "LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]" = (
- "$(PROJECT_DIR)/WireGuardGo/iphonesimulator",
- );
- PRODUCT_BUNDLE_IDENTIFIER = com.bobyrev.pcaphobos.tunnel;
- SDKROOT = iphoneos;
- SWIFT_OBJC_BRIDGING_HEADER = "Tunnel/Tunnel-Bridging-Header.h";
- TARGETED_DEVICE_FAMILY = "1,2";
- };
- name = Release;
- };
- 7ABA8220043DEF78154F9F38 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
- CLANG_CXX_LIBRARY = "libc++";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_ENABLE_OBJC_WEAK = YES;
- CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_COMMA = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
- CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
- CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
- CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
- CLANG_WARN_STRICT_PROTOTYPES = YES;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- CODE_SIGN_STYLE = Automatic;
- COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 141;
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- DEVELOPMENT_TEAM = "";
- ENABLE_NS_ASSERTIONS = NO;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- GCC_C_LANGUAGE_STANDARD = gnu11;
- GCC_NO_COMMON_BLOCKS = YES;
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 16.0;
- MARKETING_VERSION = 1.4.1;
- MTL_ENABLE_DEBUG_INFO = NO;
- MTL_FAST_MATH = YES;
- PRODUCT_NAME = "$(TARGET_NAME)";
- SDKROOT = iphoneos;
- SWIFT_COMPILATION_MODE = wholemodule;
- SWIFT_OPTIMIZATION_LEVEL = "-O";
- SWIFT_VERSION = 5.0;
- };
- name = Release;
- };
- B5D2F9B70DD37D3A57737EED /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
- CLANG_CXX_LIBRARY = "libc++";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_ENABLE_OBJC_WEAK = YES;
- CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_COMMA = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
- CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
- CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
- CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
- CLANG_WARN_STRICT_PROTOTYPES = YES;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- CODE_SIGN_STYLE = Automatic;
- COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 141;
- DEBUG_INFORMATION_FORMAT = dwarf;
- DEVELOPMENT_TEAM = "";
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- ENABLE_TESTABILITY = YES;
- GCC_C_LANGUAGE_STANDARD = gnu11;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_NO_COMMON_BLOCKS = YES;
- GCC_OPTIMIZATION_LEVEL = 0;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "$(inherited)",
- "DEBUG=1",
- );
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 16.0;
- MARKETING_VERSION = 1.4.1;
- MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
- MTL_FAST_MATH = YES;
- ONLY_ACTIVE_ARCH = YES;
- PRODUCT_NAME = "$(TARGET_NAME)";
- SDKROOT = iphoneos;
- SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
- SWIFT_OPTIMIZATION_LEVEL = "-Onone";
- SWIFT_VERSION = 5.0;
- };
- name = Debug;
- };
- D0AEA32C3C7BFB88918AB206 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- CODE_SIGN_ENTITLEMENTS = Tunnel/PhobosTunnel.entitlements;
- "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = x86_64;
- HEADER_SEARCH_PATHS = (
- "$(PROJECT_DIR)/Tunnel",
- "$(PROJECT_DIR)/Tunnel/obfuscator",
- );
- INFOPLIST_FILE = Tunnel/Info.plist;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/Frameworks",
- "@executable_path/../../Frameworks",
- );
- "LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = (
- "$(PROJECT_DIR)/WireGuardGo/iphoneos",
- );
- "LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]" = (
- "$(PROJECT_DIR)/WireGuardGo/iphonesimulator",
- );
- PRODUCT_BUNDLE_IDENTIFIER = com.bobyrev.pcaphobos.tunnel;
- SDKROOT = iphoneos;
- SWIFT_OBJC_BRIDGING_HEADER = "Tunnel/Tunnel-Bridging-Header.h";
- TARGETED_DEVICE_FAMILY = "1,2";
- };
- name = Debug;
- };
- D42BF07983FD43EBB6D84762 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- CODE_SIGN_ENTITLEMENTS = App/PCAPhobos.entitlements;
- CODE_SIGN_IDENTITY = "iPhone Developer";
- INFOPLIST_FILE = App/Info.plist;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/Frameworks",
- );
- PRODUCT_BUNDLE_IDENTIFIER = com.bobyrev.pcaphobos;
- SDKROOT = iphoneos;
- TARGETED_DEVICE_FAMILY = "1,2";
- };
- name = Debug;
- };
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
- 329F6A5A13B95B1525F94841 /* Build configuration list for PBXNativeTarget "PhobosTunnel" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- D0AEA32C3C7BFB88918AB206 /* Debug */,
- 62739003B63EE4EE3B3FF1FB /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Debug;
- };
- 61EF055D39FD21A29FA039D5 /* Build configuration list for PBXNativeTarget "PCAPhobos" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- D42BF07983FD43EBB6D84762 /* Debug */,
- 35473CF1EA2AAAC350F346D0 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Debug;
- };
- F73680B923D76C65D03B442C /* Build configuration list for PBXProject "PCAPhobos" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- B5D2F9B70DD37D3A57737EED /* Debug */,
- 7ABA8220043DEF78154F9F38 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Debug;
- };
-/* End XCConfigurationList section */
-
-/* Begin XCLocalSwiftPackageReference section */
- 9F8EC62EA6724F5FA6B8BAE0 /* XCLocalSwiftPackageReference "WireGuardKit" */ = {
- isa = XCLocalSwiftPackageReference;
- relativePath = WireGuardKit;
- };
-/* End XCLocalSwiftPackageReference section */
-
-/* Begin XCSwiftPackageProductDependency section */
- FA829997FAB330F6EFA104C9 /* WireGuardKit */ = {
- isa = XCSwiftPackageProductDependency;
- productName = WireGuardKit;
- };
-/* End XCSwiftPackageProductDependency section */
- };
- rootObject = E59D1112D2B128DF6FE7A1E9 /* Project object */;
-}
diff --git a/ios/PCAPhobos.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/PCAPhobos.xcodeproj/project.xcworkspace/contents.xcworkspacedata
deleted file mode 100644
index 919434a..0000000
--- a/ios/PCAPhobos.xcodeproj/project.xcworkspace/contents.xcworkspacedata
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
diff --git a/ios/README.md b/ios/README.md
deleted file mode 100644
index ee9dc76..0000000
--- a/ios/README.md
+++ /dev/null
@@ -1,26 +0,0 @@
-# PCA Phobos VPN — iPhone
-
-То же, что Android-клиент: импорт `phobos://` из панели, обфускация (wg-obfuscator внутри
-расширения), **российские сайты напрямую**, канал **Авто/UDP/TCP** (при блокировке UDP — сам на TCP).
-Выбор отдельных приложений на iOS невозможен (Apple даёт это только через MDM) — делим по адресам.
-
-Устройство:
-- `App/` — SwiftUI-приложение (профиль, кнопка, настройки), `Shared/PhobosProfile.swift` — разбор ссылки.
-- `Tunnel/` — Packet Tunnel: WireGuardKit → 127.0.0.1:13255 wg-obfuscator (`-Dmain=wgobf_main`, один
- экземпляр: iOS запрещает fork) → 127.0.0.1:13258 `pcarelay.c` → сервер по UDP или TCP (формат udptcp).
-- `WireGuardKit/` — wireguard-apple (MIT), `WireGuardGo//libwg-go.a` — собран `make` (iphoneos) и
- `go build -buildmode c-archive` с `-target arm64-apple-ios15.0-simulator` (симулятор).
-
-Сборка: `xcodegen generate` → `PCAPhobos.xcodeproj`. Проверка без телефона: `Tests/ProfileCheck`.
-
-## Установка на iPhone (нужен ПЛАТНЫЙ Apple Developer, $99/год)
-Network Extension (packet-tunnel-provider) Apple выдаёт только платным аккаунтам — с бесплатным
-Xcode не подпишет даже одно приложение. Когда аккаунт есть:
-1. В `project.yml` вписать `DEVELOPMENT_TEAM: `, `xcodegen generate`.
-2. Xcode → Signing: включить capability Network Extensions (Packet Tunnel) для обоих таргетов.
-3. iPhone по кабелю → Run, либо Product → Archive → TestFlight (тестировщики по e-mail, 90 дней).
-4. В панели клиента → 📱 → открыть ссылку `phobos://` на iPhone → «Открыть в PCA Phobos» → Подключить
- → разрешить добавление VPN.
-
-Проверено 23.10.2026: сборка под iphoneos и симулятор, UI и импорт реальной ссылки в симуляторе.
-Сам туннель в симуляторе iOS не работает — проверяется только на телефоне.
diff --git a/ios/Shared/PhobosProfile.swift b/ios/Shared/PhobosProfile.swift
deleted file mode 100644
index 05bac0c..0000000
--- a/ios/Shared/PhobosProfile.swift
+++ /dev/null
@@ -1,84 +0,0 @@
-import Foundation
-
-/// Parsed phobos:// payload from the PCA Phobos panel:
-/// [Interface] + [Peer] (WireGuard) + [instance] (wg-obfuscator) + "# pca-tcp = ".
-struct PhobosProfile {
- let raw: String
-
- init(_ raw: String) { self.raw = raw }
-
- /// phobos://#name
- static func fromLink(_ link: String) -> (profile: PhobosProfile, name: String)? {
- var s = link.trimmingCharacters(in: .whitespacesAndNewlines)
- guard s.hasPrefix("phobos://") else { return nil }
- s.removeFirst("phobos://".count)
- var name = "Phobos"
- if let hash = s.firstIndex(of: "#") {
- name = String(s[s.index(after: hash)...]).removingPercentEncoding ?? name
- s = String(s[.. [(key: String, line: String)] {
- var inSection = false
- var out: [(String, String)] = []
- for rawLine in raw.split(separator: "\n") {
- let line = rawLine.trimmingCharacters(in: .whitespaces)
- if line.hasPrefix("[") && line.hasSuffix("]") { inSection = line.lowercased() == header.lowercased(); continue }
- guard inSection, !line.hasPrefix("#"), let eq = line.firstIndex(of: "=") else { continue }
- let value = line[line.index(after: eq)...].trimmingCharacters(in: .whitespaces)
- if value.lowercased() == "none" { continue }
- out.append((line[.. String? {
- lines(header).first { $0.key == key }.map { line in
- line.line[line.line.index(after: line.line.firstIndex(of: "=")!)...].trimmingCharacters(in: .whitespaces)
- }
- }
-
- var target: String? { value("[instance]", "target") }
- var targetHost: String? { target.map { String($0[..<($0.lastIndex(of: ":") ?? $0.endIndex)]) } }
- var targetPort: Int? { target.flatMap { $0.split(separator: ":").last.flatMap { Int($0) } } }
-
- /// "# pca-tcp = 443" written by the panel when the server has the TCP fallback.
- var tcpPort: Int? {
- for rawLine in raw.split(separator: "\n") {
- let line = rawLine.trimmingCharacters(in: .whitespaces)
- if line.hasPrefix("#"), line.contains("pca-tcp"), let eq = line.firstIndex(of: "=") {
- return Int(line[line.index(after: eq)...].trimmingCharacters(in: .whitespaces))
- }
- }
- return nil
- }
-
- func obfuscatorConfig(listen: Int, target: String) -> String {
- var out = "[instance]\nsource-if = 127.0.0.1\nsource-lport = \(listen)\ntarget = \(target)\n"
- for item in lines("[instance]") where !["source-if", "source-lport", "target", "verbose"].contains(item.key) {
- out += item.line + "\n"
- }
- return out + "verbose = INFO\n"
- }
-
- func wireGuardConfig(endpoint: String, allowedIPs: String?) -> String {
- var out = "[Interface]\n"
- for item in lines("[Interface]") where !item.key.hasSuffix("applications") { out += item.line + "\n" }
- out += "\n[Peer]\n"
- for item in lines("[Peer]") {
- switch item.key {
- case "endpoint": out += "Endpoint = \(endpoint)\n"
- case "allowedips" where allowedIPs != nil: out += "AllowedIPs = \(allowedIPs!)\n"
- default: out += item.line + "\n"
- }
- }
- return out
- }
-}
diff --git a/ios/Tests/ProfileCheck/main.swift b/ios/Tests/ProfileCheck/main.swift
deleted file mode 100644
index e42aef3..0000000
--- a/ios/Tests/ProfileCheck/main.swift
+++ /dev/null
@@ -1,38 +0,0 @@
-// Self-check of phobos:// parsing (no device needed):
-// cd ios/Tests/ProfileCheck && xcrun swiftc -o /tmp/pc ../../Shared/PhobosProfile.swift main.swift && /tmp/pc
-import Foundation
-let conf = """
-[Interface]
-PrivateKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
-Address = 10.25.0.9/32
-DNS = 1.1.1.1
-MTU = 1420
-
-[Peer]
-PublicKey = BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=
-PresharedKey = none
-Endpoint = 127.0.0.1:51820
-AllowedIPs = 0.0.0.0/0, ::/0
-PersistentKeepalive = 25
-
-[instance]
-source-if = 127.0.0.1
-source-lport = 51820
-target = 203.0.113.10:2083
-key = testkey
-masking = STUN
-verbose = INFO
-idle-timeout = 300
-max-dummy = 4
-# pca-tcp = 443
-"""
-let link = "phobos://" + Data(conf.utf8).base64EncodedString()
- .replacingOccurrences(of: "+", with: "-").replacingOccurrences(of: "/", with: "_")
- .replacingOccurrences(of: "=", with: "") + "#demo"
-let (p, name) = PhobosProfile.fromLink(link)!
-precondition(name == "demo" && p.targetHost == "203.0.113.10" && p.targetPort == 2083 && p.tcpPort == 443)
-let obf = p.obfuscatorConfig(listen: 13255, target: "127.0.0.1:13258")
-precondition(obf.contains("target = 127.0.0.1:13258") && obf.contains("key = testkey") && !obf.contains("203.0.113.10"))
-let wg = p.wireGuardConfig(endpoint: "127.0.0.1:13255", allowedIPs: "1.0.0.0/8")
-precondition(wg.contains("Endpoint = 127.0.0.1:13255") && wg.contains("AllowedIPs = 1.0.0.0/8") && !wg.contains("= none"))
-print("profile_check ok")
diff --git a/ios/Tunnel/Info.plist b/ios/Tunnel/Info.plist
deleted file mode 100644
index 60c53ac..0000000
--- a/ios/Tunnel/Info.plist
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
- CFBundleDevelopmentRegion
- $(DEVELOPMENT_LANGUAGE)
- CFBundleDisplayName
- PhobosTunnel
- CFBundleExecutable
- $(EXECUTABLE_NAME)
- CFBundleIdentifier
- $(PRODUCT_BUNDLE_IDENTIFIER)
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleName
- $(PRODUCT_NAME)
- CFBundlePackageType
- XPC!
- CFBundleShortVersionString
- 1.0
- CFBundleVersion
- 1
- NSExtension
-
- NSExtensionPointIdentifier
- com.apple.networkextension.packet-tunnel
- NSExtensionPrincipalClass
- $(PRODUCT_MODULE_NAME).PacketTunnelProvider
-
-
-
diff --git a/ios/Tunnel/PacketTunnelProvider.swift b/ios/Tunnel/PacketTunnelProvider.swift
deleted file mode 100644
index ce40613..0000000
--- a/ios/Tunnel/PacketTunnelProvider.swift
+++ /dev/null
@@ -1,92 +0,0 @@
-import Foundation
-import NetworkExtension
-import WireGuardKit
-
-/// PCA Phobos packet tunnel:
-/// WireGuard (userspace) -> 127.0.0.1:13255 wg-obfuscator -> 127.0.0.1:13258 pcarelay -> server (UDP or TCP).
-/// providerConfiguration: "conf" (phobos:// payload), "ruDirect" (Bool), "transport" ("auto"|"udp"|"tcp").
-final class PacketTunnelProvider: NEPacketTunnelProvider {
- private static let wgPort = 13255, relayPort = 13258
- private static var obfuscatorStarted = false // one wg-obfuscator per process (it forks for more)
-
- private lazy var adapter = WireGuardAdapter(with: self) { _, message in NSLog("wg: %@", message) }
-
- override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) {
- let pc = (protocolConfiguration as? NETunnelProviderProtocol)?.providerConfiguration ?? [:]
- guard let conf = pc["conf"] as? String, !conf.isEmpty else {
- completionHandler(NSError(domain: "PCAPhobos", code: 1, userInfo: [NSLocalizedDescriptionKey: "нет профиля"]))
- return
- }
- let ruDirect = pc["ruDirect"] as? Bool ?? true
- let transport = pc["transport"] as? String ?? "auto"
- let profile = PhobosProfile(conf)
-
- guard let host = profile.targetHost, let udpPort = profile.targetPort else {
- completionHandler(NSError(domain: "PCAPhobos", code: 2, userInfo: [NSLocalizedDescriptionKey: "в профиле нет адреса сервера"]))
- return
- }
- let tcpPort = profile.tcpPort ?? 0
- if transport == "tcp" && tcpPort == 0 {
- completionHandler(NSError(domain: "PCAPhobos", code: 3, userInfo: [NSLocalizedDescriptionKey: "на сервере нет TCP-канала"]))
- return
- }
-
- pcarelay_use_tcp(transport == "tcp" ? 1 : 0)
- if !Self.obfuscatorStarted {
- Self.obfuscatorStarted = true
- pcarelay_start(Int32(Self.relayPort), host, Int32(udpPort), Int32(tcpPort))
- let path = NSTemporaryDirectory() + "obf.conf"
- try? profile.obfuscatorConfig(listen: Self.wgPort, target: "127.0.0.1:\(Self.relayPort)")
- .write(toFile: path, atomically: true, encoding: .utf8)
- Thread.detachNewThread {
- var args: [UnsafeMutablePointer?] = ["wg-obfuscator", "-c", path].map { strdup($0) }
- _ = wgobf_main(Int32(args.count), &args)
- }
- }
-
- let allowed = ruDirect ? Self.ruBypassAllowedIPs() : nil
- let wgText = profile.wireGuardConfig(endpoint: "127.0.0.1:\(Self.wgPort)", allowedIPs: allowed)
- let tunnelConfig: TunnelConfiguration
- do {
- tunnelConfig = try TunnelConfiguration(fromWgQuickConfig: wgText, called: "phobos")
- } catch {
- completionHandler(error)
- return
- }
- adapter.start(tunnelConfiguration: tunnelConfig) { [weak self] error in
- completionHandler(error)
- if error == nil && transport == "auto" && tcpPort != 0 { self?.watchUdp() }
- }
- }
-
- /// Auto: nothing came back over UDP within 15 s -> UDP is cut, move the relay to TCP.
- private func watchUdp() {
- DispatchQueue.global().asyncAfter(deadline: .now() + 15) {
- if pcarelay_is_tcp() == 0 && pcarelay_rx_bytes() == 0 {
- NSLog("PCAPhobos: no UDP answer in 15 s -> TCP")
- pcarelay_use_tcp(1)
- }
- }
- }
-
- override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
- adapter.stop { _ in
- completionHandler()
- // the obfuscator thread cannot be stopped cleanly; a fresh process starts next time
- exit(0)
- }
- }
-
- /// App asks for status: {"transport": "UDP"|"TCP", "rx": bytes}
- override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) {
- let status: [String: Any] = ["transport": pcarelay_is_tcp() != 0 ? "TCP" : "UDP",
- "rx": pcarelay_rx_bytes()]
- completionHandler?(try? JSONSerialization.data(withJSONObject: status))
- }
-
- private static func ruBypassAllowedIPs() -> String? {
- guard let url = Bundle.main.url(forResource: "ru_bypass", withExtension: "txt"),
- let text = try? String(contentsOf: url, encoding: .utf8) else { return nil }
- return text.split(separator: "\n").first { !$0.hasPrefix("#") && $0.contains("/") }.map(String.init)
- }
-}
diff --git a/ios/Tunnel/PhobosTunnel.entitlements b/ios/Tunnel/PhobosTunnel.entitlements
deleted file mode 100644
index ffab33e..0000000
--- a/ios/Tunnel/PhobosTunnel.entitlements
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
- com.apple.developer.networking.networkextension
-
- packet-tunnel-provider
-
-
-
diff --git a/ios/Tunnel/String+ArrayConversion.swift b/ios/Tunnel/String+ArrayConversion.swift
deleted file mode 100644
index 97984f8..0000000
--- a/ios/Tunnel/String+ArrayConversion.swift
+++ /dev/null
@@ -1,32 +0,0 @@
-// SPDX-License-Identifier: MIT
-// Copyright © 2018-2023 WireGuard LLC. All Rights Reserved.
-
-import Foundation
-
-extension String {
-
- func splitToArray(separator: Character = ",", trimmingCharacters: CharacterSet? = nil) -> [String] {
- return split(separator: separator)
- .map {
- if let charSet = trimmingCharacters {
- return $0.trimmingCharacters(in: charSet)
- } else {
- return String($0)
- }
- }
- }
-
-}
-
-extension Optional where Wrapped == String {
-
- func splitToArray(separator: Character = ",", trimmingCharacters: CharacterSet? = nil) -> [String] {
- switch self {
- case .none:
- return []
- case .some(let wrapped):
- return wrapped.splitToArray(separator: separator, trimmingCharacters: trimmingCharacters)
- }
- }
-
-}
diff --git a/ios/Tunnel/Tunnel-Bridging-Header.h b/ios/Tunnel/Tunnel-Bridging-Header.h
deleted file mode 100644
index 8e6dc13..0000000
--- a/ios/Tunnel/Tunnel-Bridging-Header.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "pcarelay.h"
diff --git a/ios/Tunnel/TunnelConfiguration+WgQuickConfig.swift b/ios/Tunnel/TunnelConfiguration+WgQuickConfig.swift
deleted file mode 100644
index d8cc11e..0000000
--- a/ios/Tunnel/TunnelConfiguration+WgQuickConfig.swift
+++ /dev/null
@@ -1,253 +0,0 @@
-// SPDX-License-Identifier: MIT
-// Copyright © 2018-2023 WireGuard LLC. All Rights Reserved.
-
-import Foundation
-import WireGuardKit
-
-extension TunnelConfiguration {
-
- enum ParserState {
- case inInterfaceSection
- case inPeerSection
- case notInASection
- }
-
- enum ParseError: Error {
- case invalidLine(String.SubSequence)
- case noInterface
- case multipleInterfaces
- case interfaceHasNoPrivateKey
- case interfaceHasInvalidPrivateKey(String)
- case interfaceHasInvalidListenPort(String)
- case interfaceHasInvalidAddress(String)
- case interfaceHasInvalidDNS(String)
- case interfaceHasInvalidMTU(String)
- case interfaceHasUnrecognizedKey(String)
- case peerHasNoPublicKey
- case peerHasInvalidPublicKey(String)
- case peerHasInvalidPreSharedKey(String)
- case peerHasInvalidAllowedIP(String)
- case peerHasInvalidEndpoint(String)
- case peerHasInvalidPersistentKeepAlive(String)
- case peerHasInvalidTransferBytes(String)
- case peerHasInvalidLastHandshakeTime(String)
- case peerHasUnrecognizedKey(String)
- case multiplePeersWithSamePublicKey
- case multipleEntriesForKey(String)
- }
-
- convenience init(fromWgQuickConfig wgQuickConfig: String, called name: String? = nil) throws {
- var interfaceConfiguration: InterfaceConfiguration?
- var peerConfigurations = [PeerConfiguration]()
-
- let lines = wgQuickConfig.split { $0.isNewline }
-
- var parserState = ParserState.notInASection
- var attributes = [String: String]()
-
- for (lineIndex, line) in lines.enumerated() {
- var trimmedLine: String
- if let commentRange = line.range(of: "#") {
- trimmedLine = String(line[.. = ["address", "allowedips", "dns"]
- if let presentValue = attributes[key] {
- if keysWithMultipleEntriesAllowed.contains(key) {
- attributes[key] = presentValue + "," + value
- } else {
- throw ParseError.multipleEntriesForKey(keyWithCase)
- }
- } else {
- attributes[key] = value
- }
- let interfaceSectionKeys: Set = ["privatekey", "listenport", "address", "dns", "mtu"]
- let peerSectionKeys: Set = ["publickey", "presharedkey", "allowedips", "endpoint", "persistentkeepalive"]
- if parserState == .inInterfaceSection {
- guard interfaceSectionKeys.contains(key) else {
- throw ParseError.interfaceHasUnrecognizedKey(keyWithCase)
- }
- } else if parserState == .inPeerSection {
- guard peerSectionKeys.contains(key) else {
- throw ParseError.peerHasUnrecognizedKey(keyWithCase)
- }
- }
- } else if lowercasedLine != "[interface]" && lowercasedLine != "[peer]" {
- throw ParseError.invalidLine(line)
- }
- }
-
- let isLastLine = lineIndex == lines.count - 1
-
- if isLastLine || lowercasedLine == "[interface]" || lowercasedLine == "[peer]" {
- // Previous section has ended; process the attributes collected so far
- if parserState == .inInterfaceSection {
- let interface = try TunnelConfiguration.collate(interfaceAttributes: attributes)
- guard interfaceConfiguration == nil else { throw ParseError.multipleInterfaces }
- interfaceConfiguration = interface
- } else if parserState == .inPeerSection {
- let peer = try TunnelConfiguration.collate(peerAttributes: attributes)
- peerConfigurations.append(peer)
- }
- }
-
- if lowercasedLine == "[interface]" {
- parserState = .inInterfaceSection
- attributes.removeAll()
- } else if lowercasedLine == "[peer]" {
- parserState = .inPeerSection
- attributes.removeAll()
- }
- }
-
- let peerPublicKeysArray = peerConfigurations.map { $0.publicKey }
- let peerPublicKeysSet = Set(peerPublicKeysArray)
- if peerPublicKeysArray.count != peerPublicKeysSet.count {
- throw ParseError.multiplePeersWithSamePublicKey
- }
-
- if let interfaceConfiguration = interfaceConfiguration {
- self.init(name: name, interface: interfaceConfiguration, peers: peerConfigurations)
- } else {
- throw ParseError.noInterface
- }
- }
-
- func asWgQuickConfig() -> String {
- var output = "[Interface]\n"
- output.append("PrivateKey = \(interface.privateKey.base64Key)\n")
- if let listenPort = interface.listenPort {
- output.append("ListenPort = \(listenPort)\n")
- }
- if !interface.addresses.isEmpty {
- let addressString = interface.addresses.map { $0.stringRepresentation }.joined(separator: ", ")
- output.append("Address = \(addressString)\n")
- }
- if !interface.dns.isEmpty || !interface.dnsSearch.isEmpty {
- var dnsLine = interface.dns.map { $0.stringRepresentation }
- dnsLine.append(contentsOf: interface.dnsSearch)
- let dnsString = dnsLine.joined(separator: ", ")
- output.append("DNS = \(dnsString)\n")
- }
- if let mtu = interface.mtu {
- output.append("MTU = \(mtu)\n")
- }
-
- for peer in peers {
- output.append("\n[Peer]\n")
- output.append("PublicKey = \(peer.publicKey.base64Key)\n")
- if let preSharedKey = peer.preSharedKey?.base64Key {
- output.append("PresharedKey = \(preSharedKey)\n")
- }
- if !peer.allowedIPs.isEmpty {
- let allowedIPsString = peer.allowedIPs.map { $0.stringRepresentation }.joined(separator: ", ")
- output.append("AllowedIPs = \(allowedIPsString)\n")
- }
- if let endpoint = peer.endpoint {
- output.append("Endpoint = \(endpoint.stringRepresentation)\n")
- }
- if let persistentKeepAlive = peer.persistentKeepAlive {
- output.append("PersistentKeepalive = \(persistentKeepAlive)\n")
- }
- }
-
- return output
- }
-
- private static func collate(interfaceAttributes attributes: [String: String]) throws -> InterfaceConfiguration {
- guard let privateKeyString = attributes["privatekey"] else {
- throw ParseError.interfaceHasNoPrivateKey
- }
- guard let privateKey = PrivateKey(base64Key: privateKeyString) else {
- throw ParseError.interfaceHasInvalidPrivateKey(privateKeyString)
- }
- var interface = InterfaceConfiguration(privateKey: privateKey)
- if let listenPortString = attributes["listenport"] {
- guard let listenPort = UInt16(listenPortString) else {
- throw ParseError.interfaceHasInvalidListenPort(listenPortString)
- }
- interface.listenPort = listenPort
- }
- if let addressesString = attributes["address"] {
- var addresses = [IPAddressRange]()
- for addressString in addressesString.splitToArray(trimmingCharacters: .whitespacesAndNewlines) {
- guard let address = IPAddressRange(from: addressString) else {
- throw ParseError.interfaceHasInvalidAddress(addressString)
- }
- addresses.append(address)
- }
- interface.addresses = addresses
- }
- if let dnsString = attributes["dns"] {
- var dnsServers = [DNSServer]()
- var dnsSearch = [String]()
- for dnsServerString in dnsString.splitToArray(trimmingCharacters: .whitespacesAndNewlines) {
- if let dnsServer = DNSServer(from: dnsServerString) {
- dnsServers.append(dnsServer)
- } else {
- dnsSearch.append(dnsServerString)
- }
- }
- interface.dns = dnsServers
- interface.dnsSearch = dnsSearch
- }
- if let mtuString = attributes["mtu"] {
- guard let mtu = UInt16(mtuString) else {
- throw ParseError.interfaceHasInvalidMTU(mtuString)
- }
- interface.mtu = mtu
- }
- return interface
- }
-
- private static func collate(peerAttributes attributes: [String: String]) throws -> PeerConfiguration {
- guard let publicKeyString = attributes["publickey"] else {
- throw ParseError.peerHasNoPublicKey
- }
- guard let publicKey = PublicKey(base64Key: publicKeyString) else {
- throw ParseError.peerHasInvalidPublicKey(publicKeyString)
- }
- var peer = PeerConfiguration(publicKey: publicKey)
- if let preSharedKeyString = attributes["presharedkey"] {
- guard let preSharedKey = PreSharedKey(base64Key: preSharedKeyString) else {
- throw ParseError.peerHasInvalidPreSharedKey(preSharedKeyString)
- }
- peer.preSharedKey = preSharedKey
- }
- if let allowedIPsString = attributes["allowedips"] {
- var allowedIPs = [IPAddressRange]()
- for allowedIPString in allowedIPsString.splitToArray(trimmingCharacters: .whitespacesAndNewlines) {
- guard let allowedIP = IPAddressRange(from: allowedIPString) else {
- throw ParseError.peerHasInvalidAllowedIP(allowedIPString)
- }
- allowedIPs.append(allowedIP)
- }
- peer.allowedIPs = allowedIPs
- }
- if let endpointString = attributes["endpoint"] {
- guard let endpoint = Endpoint(from: endpointString) else {
- throw ParseError.peerHasInvalidEndpoint(endpointString)
- }
- peer.endpoint = endpoint
- }
- if let persistentKeepAliveString = attributes["persistentkeepalive"] {
- guard let persistentKeepAlive = UInt16(persistentKeepAliveString) else {
- throw ParseError.peerHasInvalidPersistentKeepAlive(persistentKeepAliveString)
- }
- peer.persistentKeepAlive = persistentKeepAlive
- }
- return peer
- }
-
-}
diff --git a/ios/Tunnel/obfuscator/config.c b/ios/Tunnel/obfuscator/config.c
deleted file mode 100644
index 75c2477..0000000
--- a/ios/Tunnel/obfuscator/config.c
+++ /dev/null
@@ -1,535 +0,0 @@
-#include
-#include
-#include
-#include
-#include "config.h"
-#include "wg-obfuscator.h"
-#include "mini_argp.h"
-#include "masking.h"
-
-// Executable name
-static const char *arg0;
-
-/* The options we understand. */
-static const mini_argp_opt options[] = {
- { "help", '?', 0 },
- { "config", 'c', 1 },
- { "source-if", 'i', 1 },
- { "source", 's', 1 },
- { "source-lport", 'p', 1 },
- { "target-if", 'o', 1 },
- { "target", 't', 1 },
- { "target-lport", 'r', 1 },
- { "key", 'k', 1 },
- { "masking", 'a', 1 },
- { "static-bindings", 'b', 1 },
- { "max-clients" , 'm', 1 },
- { "idle-timeout", 'l', 1 },
- { "in-timeout", 'n', 1 },
- { "max-dummy", 'd', 1 },
- { "fwmark", 'f', 1 },
- { "allow-clean", 'e', 0 },
- { "verbose", 'v', 1 },
- { "log-file", 'L', 1 },
- { "log-timestamps", 'T', 1 },
- { "resolve-interval", 'R', 1 },
- { 0 }
-};
-
-static void show_usage(void)
-{
- printf("Usage: %s [options]\n%s", arg0,
- " -?, --help Give this help list\n"
- "\n"
- "Main settings:\n"
- " -c, --config= Read configuration from file\n"
- " (can be used instead of the rest arguments)\n"
- " -i, --source-if= Source interface to listen on\n"
- " (optional, default - 0.0.0.0, e.g. all)\n"
- " -p, --source-lport= Source port to listen\n"
- " -t, --target=: Target IP and port\n"
- " -k, --key= Obfuscation key \n"
- " (required, must be 1-255 characters long)\n"
- " -a, --masking= Masking type (optional, default - AUTO)\n"
- " Supported values: STUN, AUTO, NONE\n"
- " -b, --static-bindings=::,...\n"
- " Comma-separated static bindings for two-way mode\n"
- " as ::\n"
- " You can also repeat this option.\n"
- " -f, --fwmark= Firewall mark to set on all packets\n"
- " (optional, default - 0, e.g. disabled)\n"
- " -v, --verbose= Verbosity level (optional, default - INFO)\n"
- " ERRORS (critical errors only)\n"
- " WARNINGS (important messages)\n"
- " 2 - INFO (informational messages: status messages,\n"
- " connection established, etc.)\n"
- " 3 - DEBUG (detailed debug messages)\n"
- " 4 - TRACE (very detailed debug messages, including\n"
- " packet dumps)\n"
- " -L, --log-file= Write the log to this file instead of stderr\n"
- " (optional, the file is reopened on SIGHUP)\n"
- " -T, --log-timestamps= Prefix log lines with a timestamp\n"
- " (optional, default - AUTO, e.g. only when\n"
- " writing to a log file)\n"
- " Supported values: AUTO, TRUE, FALSE\n"
- "\n"
- "Additional options:\n"
- " -m, --max-clients= Maximum number of clients (default: 1024)\n"
- " -l, --idle-timeout= Idle timeout in seconds (default: 300)\n"
- " -n, --in-timeout= Incoming timeout in seconds (default: 0 - disabled)\n"
- " -d, --max-dummy= Maximum length of dummy bytes for data packets\n"
- " (default: 4)\n"
- " -e, --allow-clean For servers, allow non-obfuscated incoming connections\n"
- " -R, --resolve-interval=\n"
- " Re-resolve target and static-binding hostnames\n"
- " every N seconds (default: 0 - disabled).\n"
- " SIGHUP always triggers a refresh.\n"
- " If non-zero, a failed resolve at startup is retried\n"
- " instead of exiting.\n");
-}
-
-static int parse_opt(const char *lname, char sname, const char *val, void *ctx);
-
-/**
- * @brief Resets the configuration structure to its default values.
- *
- * This function clears the configuration structure by setting all fields to zero
- * and resetting the verbosity level to the default value.
- *
- * @param config Pointer to the obfuscator_config structure to be reset.
- */
-static void reset_config(obfuscator_config_t *config)
-{
- if (config->static_bindings) {
- free(config->static_bindings);
- }
- memset(config, 0, sizeof(*config));
- config->max_clients = MAX_CLIENTS_DEFAULT;
- config->idle_timeout = IDLE_TIMEOUT_DEFAULT;
- config->in_timeout = IN_TIMEOUT_DEFAULT;
- config->max_dummy_length_data = MAX_DUMMY_LENGTH_DATA_DEFAULT;
- config->log_timestamps = -1; // auto
- verbose = LL_DEFAULT;
-}
-
-/**
- * Checks if the given string represents a valid integer.
- *
- * @param str Pointer to the null-terminated string to check.
- * @return Non-zero value if the string is a valid integer, 0 otherwise.
- */
-static uint8_t is_integer(const char *str)
-{
- if (!str || !*str) {
- return 0; // Empty string is not an integer
- }
- while (*str) {
- if (!isdigit((unsigned char)*str)) {
- return 0; // Non-digit character found
- }
- str++;
- }
- return 1; // All characters are digits
-}
-
-/**
- * Parses a boolean value from a string.
- *
- * @param str Pointer to the null-terminated string to parse.
- * @return 1 for true values ("true", "yes", "on", "1"),
- * 0 for false values ("false", "no", "off", "0"),
- * -1 if the string is not a valid boolean value.
- */
-static int parse_bool(const char *str)
-{
- char lower[16];
- if (!str || !*str || strlen(str) >= sizeof(lower)) {
- return -1;
- }
- strcpy(lower, str);
- for (char *p = lower; *p; ++p) *p = tolower((unsigned char)*p);
- if (!strcmp(lower, "true") || !strcmp(lower, "yes") || !strcmp(lower, "on") || !strcmp(lower, "1")) {
- return 1;
- }
- if (!strcmp(lower, "false") || !strcmp(lower, "no") || !strcmp(lower, "off") || !strcmp(lower, "0")) {
- return 0;
- }
- return -1;
-}
-
-/**
- * @brief Reads and processes the configuration file.
- *
- * This function opens the specified configuration file and parses its contents
- * to initialize or update the application's configuration settings.
- *
- * @param filename The path to the configuration file to be read.
- * @param config Pointer to the obfuscator_config structure where the parsed settings will be stored.
- */
-static void read_config_file(const char *filename, obfuscator_config_t *config)
-{
- // Read configuration from the file
- uint8_t first_section = 1; // Flag to indicate if this is the first section being processed
- char line[10 * 1024]; // Buffer to hold each line from the config file
-
- FILE *config_file = fopen(filename, "r");
- if (config_file == NULL) {
- perror("Can't open config file");
- exit(EXIT_FAILURE);
- }
-
- while (fgets(line, sizeof(line), config_file)) {
- // Remove trailing newlines, carriage returns, spaces and tabs
- while (strlen(line) && (line[strlen(line) - 1] == '\n' || line[strlen(line) - 1] == '\r'
- || line[strlen(line) - 1] == ' ' || line[strlen(line) - 1] == '\t')) {
- line[strlen(line) - 1] = 0;
- }
- // Remove leading spaces and tabs
- while (strlen(line) && (line[0] == ' ' || line[0] == '\t')) {
- memmove(line, line + 1, strlen(line));
- }
- // Ignore comments
- char *comment_index = strstr(line, "#");
- if (comment_index != NULL) {
- *comment_index = 0;
- }
- // Skip empty lines or with spaces only
- size_t line_len = strlen(line);
- if (strspn(line, " \t\r\n") == line_len) {
- continue;
- }
-
- // It can be new section
- if (line_len > 0 && line[0] == '[' && line[line_len - 1] == ']') {
- if (!first_section) {
- // new config, need to fork the process
- pid_t pid = fork();
- if (pid < 0) {
- log(LL_ERROR, "Can't fork a new instance - %s (%d)", strerror(errno), errno);
- exit(EXIT_FAILURE);
- }
- if (pid == 0) {
- // Close in the child process
- fclose(config_file);
- // Stop config file processing for this instance
- return;
- }
- // Remember the instance to be able to forward signals to it
- register_child_instance(pid);
- }
- size_t len = strlen(line) - 2;
- if (len > sizeof(section_name) - 1) {
- len = sizeof(section_name) - 1;
- }
- strncpy(section_name, line + 1, len);
- section_name[len] = 0;
-
- // Reset all the parameters
- reset_config(config);
-
- first_section = 0; // We have processed the first section
- continue;
- }
-
- // Parse key-value pairs
- char *key = strtok(line, "=");
- key = trim(key);
- while (strlen(key) && (key[strlen(key) - 1] == ' ' || key[strlen(key) - 1] == '\t' || key[strlen(key) - 1] == '\r' || key[strlen(key) - 1] == '\n')) {
- key[strlen(key) - 1] = 0;
- }
- char *value = strtok(NULL, "=");
- if (value == NULL) {
- log(LL_ERROR, "Invalid configuration line: %s", line);
- exit(EXIT_FAILURE);
- }
- value = trim(value);
- if (!*value) {
- log(LL_ERROR, "Invalid configuration line: %s", line);
- exit(EXIT_FAILURE);
- }
- const mini_argp_opt *o = margp_find(options, key, 0);
- if (o == NULL) {
- log(LL_ERROR, "Unknown configuration key: %s", key);
- exit(EXIT_FAILURE);
- }
- if (!o->has_arg) {
- // Flag options are represented as booleans in the config file
- int b = parse_bool(value);
- if (b < 0) {
- log(LL_ERROR, "Configuration key '%s' accepts only boolean values (true/yes/on/1 or false/no/off/0)", key);
- exit(EXIT_FAILURE);
- }
- if (!b) {
- continue;
- }
- value = NULL;
- }
- parse_opt(o->long_name, o->short_name, value, config);
- }
- fclose(config_file);
-}
-
-/* Parse a single option. */
-static int parse_opt(const char *lname, char sname, const char *val, void *ctx)
-{
- obfuscator_config_t *config = (obfuscator_config_t *)ctx;
- char val_lower[16];
-
- switch (sname)
- {
- case '?':
- // Show usage and exit
- show_usage();
- exit(EXIT_SUCCESS);
- case 'c':
- read_config_file(val, config);
- break;
- case 'i':
- strncpy(config->client_interface, val, sizeof(config->client_interface) - 1);
- config->client_interface[sizeof(config->client_interface) - 1] = 0; // Ensure null-termination
- config->client_interface_set = 1;
- break;
- case 'p':
- if (!is_integer(val)) {
- log(LL_ERROR, "Invalid source port: %s (must be an integer)", val);
- exit(EXIT_FAILURE);
- }
- config->listen_port = atoi(val);
- if (config->listen_port <= 0 || config->listen_port > 65535) {
- log(LL_ERROR, "Invalid listen port: %s (must be between 1 and 65535)", val);
- exit(EXIT_FAILURE);
- }
- config->listen_port_set = 1;
- break;
- case 't':
- strncpy(config->forward_host_port, val, sizeof(config->forward_host_port) - 1);
- config->forward_host_port[sizeof(config->forward_host_port) - 1] = 0; // Ensure null-termination
- config->forward_host_port_set = 1;
- break;
- case 'b':
- {
- char *new_bindings;
- if (!config->static_bindings) {
- new_bindings = strdup(val);
- } else {
- size_t old_len = strlen(config->static_bindings);
- new_bindings = realloc(config->static_bindings, old_len + strlen(val) + 2);
- if (new_bindings) {
- new_bindings[old_len] = ',';
- strcpy(new_bindings + old_len + 1, val);
- }
- }
- if (!new_bindings) {
- log(LL_ERROR, "Out of memory while parsing static-bindings");
- exit(EXIT_FAILURE);
- }
- config->static_bindings = new_bindings;
- config->static_bindings_set = 1;
- }
- break;
- case 'k':
- strncpy(config->xor_key, val, sizeof(config->xor_key));
- config->xor_key[sizeof(config->xor_key) - 1] = 0; // Ensure null-termination
- if (strlen(config->xor_key) == 0) {
- log(LL_ERROR, "XOR key cannot be empty");
- exit(EXIT_FAILURE);
- }
- config->xor_key_set = 1;
- break;
- case 'm':
- if (!is_integer(val)) {
- log(LL_ERROR, "Invalid maximum number of clients: %s (must be an integer)", val);
- exit(EXIT_FAILURE);
- }
- config->max_clients = atoi(val);
- if (config->max_clients <= 0) {
- log(LL_ERROR, "Invalid maximum number of clients: %s (must be greater than 0)", val);
- exit(EXIT_FAILURE);
- }
- break;
- case 'l':
- if (!is_integer(val)) {
- log(LL_ERROR, "Invalid idle timeout: %s (must be an integer)", val);
- exit(EXIT_FAILURE);
- }
- config->idle_timeout = atol(val);
- if (config->idle_timeout <= 0) {
- log(LL_ERROR, "Invalid idle timeout: %s (must be greater than 0)", val);
- exit(EXIT_FAILURE);
- }
- config->idle_timeout *= 1000; // Convert to milliseconds
- break;
- case 'n':
- if (!is_integer(val)) {
- log(LL_ERROR, "Invalid incoming timeout: %s (must be an integer)", val);
- exit(EXIT_FAILURE);
- }
- config->in_timeout = atol(val);
- if (config->in_timeout <= 0) {
- log(LL_ERROR, "Invalid incoming timeout: %s (must be greater than 0)", val);
- exit(EXIT_FAILURE);
- }
- config->in_timeout *= 1000; // Convert to milliseconds
- break;
- case 'd':
- if (!is_integer(val)) {
- log(LL_ERROR, "Invalid maximum dummy length for data packets: %s (must be an integer)", val);
- exit(EXIT_FAILURE);
- }
- config->max_dummy_length_data = atoi(val);
- if (config->max_dummy_length_data < 0 || config->max_dummy_length_data > MAX_DUMMY_LENGTH_TOTAL) {
- log(LL_ERROR, "Invalid maximum dummy length for data packets: %s (must be between 0 and %d)", val, MAX_DUMMY_LENGTH_TOTAL);
- exit(EXIT_FAILURE);
- }
- break;
- case 'e':
- config->allow_clean = 1;
- break;
- case 'f':
- // parse string with decimal and hexadecimal support
-#ifdef __linux__
- {
- long int v = strtol(val, NULL, 0);
- if (v <= 0 || v > UINT16_MAX) {
- log(LL_ERROR, "Invalid firewall mark: %s", val);
- exit(EXIT_FAILURE);
- }
- config->fwmark = (uint16_t)v;
- }
-#else
- log(LL_WARN, "Firewall mark is not supported on this platform");
-#endif
- break;
- case 'a':
- {
- strncpy(val_lower, val, sizeof(val_lower) - 1);
- val_lower[sizeof(val_lower) - 1] = 0;
- for (char *p = val_lower; *p; ++p) *p = tolower((unsigned char)*p);
- if (strcmp(val_lower, "none") == 0) {
- config->masking_handler = NULL;
- config->masking_handler_set = 1;
- break;
- }
- if (strcmp(val_lower, "auto") == 0) {
- config->masking_handler = NULL;
- config->masking_handler_set = 0;
- break;
- }
- masking_handler_t *handler = get_masking_handler_by_name(val_lower);
- if (handler == NULL) {
- log(LL_ERROR, "Unknown masking type: %s", val);
- exit(EXIT_FAILURE);
- }
- config->masking_handler = handler;
- config->masking_handler_set = 1;
- }
- break;
- case 'v':
- strncpy(val_lower, val, sizeof(val_lower) - 1);
- val_lower[sizeof(val_lower) - 1] = 0;
- for (char *p = val_lower; *p; ++p) *p = tolower((unsigned char)*p);
- if (strcmp(val_lower, "error") == 0) {
- verbose = LL_ERROR;
- } else if (strcmp(val_lower, "warn") == 0) {
- verbose = LL_WARN;
- } else if (strcmp(val_lower, "info") == 0) {
- verbose = LL_INFO;
- } else if (strcmp(val_lower, "debug") == 0) {
- verbose = LL_DEBUG;
- } else if (strcmp(val_lower, "trace") == 0) {
- verbose = LL_TRACE;
- } else {
- // check if it's a number
- if (is_integer(val)) {
- verbose = atoi(val);
- if (verbose < 0 || verbose > 4) {
- log(LL_ERROR, "Invalid verbosity level: %s (must be one of 'ERROR', 'WARN', 'INFO', 'DEBUG', 'TRACE')", val);
- exit(EXIT_FAILURE);
- }
- } else {
- log(LL_ERROR, "Invalid verbosity level: %s (must be one of 'ERROR', 'WARN', 'INFO', 'DEBUG', 'TRACE')", val);
- exit(EXIT_FAILURE);
- }
- }
- break;
- case 'L':
- strncpy(config->log_file, val, sizeof(config->log_file) - 1);
- config->log_file[sizeof(config->log_file) - 1] = 0; // Ensure null-termination
- if (strlen(config->log_file) == 0) {
- log(LL_ERROR, "Log file path cannot be empty");
- exit(EXIT_FAILURE);
- }
- config->log_file_set = 1;
- break;
- case 'T':
- {
- strncpy(val_lower, val, sizeof(val_lower) - 1);
- val_lower[sizeof(val_lower) - 1] = 0;
- for (char *p = val_lower; *p; ++p) *p = tolower((unsigned char)*p);
- if (strcmp(val_lower, "auto") == 0) {
- config->log_timestamps = -1;
- break;
- }
- int b = parse_bool(val_lower);
- if (b < 0) {
- log(LL_ERROR, "Invalid log timestamps mode: %s (must be one of 'AUTO', 'TRUE', 'FALSE')", val);
- exit(EXIT_FAILURE);
- }
- config->log_timestamps = b;
- }
- break;
- case 'R':
- if (!is_integer(val)) {
- log(LL_ERROR, "Invalid resolve interval: %s (must be an integer)", val);
- exit(EXIT_FAILURE);
- }
- config->resolve_interval = atol(val);
- if (config->resolve_interval < 0) {
- log(LL_ERROR, "Invalid resolve interval: %s (must be 0 or greater)", val);
- exit(EXIT_FAILURE);
- }
- config->resolve_interval *= 1000; // Convert to milliseconds
- break;
- default:
- // should never happen
- return -1;
- }
- return 0;
-}
-
-int parse_config(int argc, char **argv, obfuscator_config_t *config)
-{
- /* Parse command line arguments */
- reset_config(config);
- arg0 = argv[0]; // Save the executable name
- if (argc == 1) {
- fprintf(stderr, "No arguments provided, use \"%s --help\" command for usage information\n", argv[0]);
- return -1;
- }
- if (mini_argp_parse(argc, argv, options, config, parse_opt) != 0) {
- fprintf(stderr, "Failed to parse command line arguments\n");
- return -1;
- }
-
- return 0;
-}
-
-/**
- * @brief Removes leading and trailing whitespace characters from the input string.
- *
- * This function modifies the input string in place by trimming any whitespace
- * characters (such as spaces, tabs, or newlines) from both the beginning and end.
- *
- * @param s Pointer to the null-terminated string to be trimmed.
- * @return Pointer to the trimmed string.
- */
-char *trim(char *s) {
- char *end;
- // Trim leading spaces, tabs, carriage returns and newlines
- while (*s && (*s == ' ' || *s == '\t' || *s == '\r' || *s == '\n')) s++;
- if (!*s) return s;
- // Trim trailing spaces, tabs, carriage returns and newlines
- end = s + strlen(s) - 1;
- while (end > s && (*end == ' ' || *end == '\t' || *end == '\r' || *end == '\n')) *end-- = 0;
- return s;
-}
diff --git a/ios/Tunnel/obfuscator/config.h b/ios/Tunnel/obfuscator/config.h
deleted file mode 100644
index 1083bc5..0000000
--- a/ios/Tunnel/obfuscator/config.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef _CONFIG_H_
-#define _CONFIG_H_
-
-#include "wg-obfuscator.h"
-
-char *trim(char *s);
-int parse_config(int argc, char **argv, obfuscator_config_t *config);
-
-#endif // _CONFIG_H_
diff --git a/ios/Tunnel/obfuscator/logging.c b/ios/Tunnel/obfuscator/logging.c
deleted file mode 100644
index 3b809f1..0000000
--- a/ios/Tunnel/obfuscator/logging.c
+++ /dev/null
@@ -1,258 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include "wg-obfuscator.h"
-
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
-#ifndef STDERR_FILENO
-#define STDERR_FILENO 2
-#endif
-
-// Log files may contain client addresses, so they are not world-readable
-#define LOG_FILE_MODE 0640
-
-// File descriptor of the log file, -1 when logging to stderr
-static int log_fd = -1;
-// Path of the log file, kept to be able to reopen it on SIGHUP
-static char *log_path = NULL;
-// 1 if every line must be prefixed with a timestamp
-static int log_timestamps = 0;
-
-/**
- * @brief Returns the single character representing a logging level.
- */
-static char level_char(int level)
-{
- switch (level) {
- case LL_ERROR: return 'E';
- case LL_WARN: return 'W';
- case LL_INFO: return 'I';
- case LL_DEBUG: return 'D';
- case LL_TRACE: return 'T';
- default: return '?';
- }
-}
-
-/**
- * @brief Writes the whole buffer to the descriptor, retrying on partial writes.
- *
- * @param fd Descriptor to write to.
- * @param buf Data to write.
- * @param len Number of bytes to write.
- */
-static void write_all(int fd, const char *buf, size_t len)
-{
- while (len) {
- ssize_t written = write(fd, buf, len);
- if (written <= 0) {
- if (written < 0 && errno == EINTR) {
- continue;
- }
- // Nothing sensible can be done about a broken log, drop the rest of the line
- return;
- }
- buf += written;
- len -= (size_t)written;
- }
-}
-
-/**
- * @brief Appends formatted text to the buffer without ever overflowing it.
- *
- * @param buf Buffer to append to.
- * @param size Usable size of the buffer, including the terminating zero.
- * @param len Current length of the text in the buffer.
- * @param fmt Format string.
- * @param args Arguments for the format string.
- * @return New length of the text in the buffer.
- */
-static size_t append_vfmt(char *buf, size_t size, size_t len, const char *fmt, va_list args)
-{
- int n;
-
- if (len + 1 >= size) {
- return len;
- }
- n = vsnprintf(buf + len, size - len, fmt, args);
- if (n < 0) {
- return len;
- }
- if ((size_t)n >= size - len) {
- return size - 1; // truncated
- }
- return len + (size_t)n;
-}
-
-/**
- * @brief Appends formatted text to the buffer without ever overflowing it.
- *
- * @param buf Buffer to append to.
- * @param size Usable size of the buffer, including the terminating zero.
- * @param len Current length of the text in the buffer.
- * @param fmt Format string.
- * @return New length of the text in the buffer.
- */
-static size_t append_fmt(char *buf, size_t size, size_t len, const char *fmt, ...)
-{
- va_list args;
-
- va_start(args, fmt);
- len = append_vfmt(buf, size, len, fmt, args);
- va_end(args);
-
- return len;
-}
-
-/**
- * @brief Writes the common line prefix (timestamp and instance name) to the buffer.
- *
- * @param buf Buffer to write to.
- * @param size Usable size of the buffer, including the terminating zero.
- * @param level Logging level of the line.
- * @return Length of the prefix.
- */
-static size_t log_prefix(char *buf, size_t size, int level)
-{
- size_t len = 0;
-
- if (log_timestamps) {
- struct timespec ts;
- struct tm *tm;
- if (clock_gettime(CLOCK_REALTIME, &ts) == 0 && (tm = localtime(&ts.tv_sec)) != NULL) {
- len = strftime(buf, size, "%Y-%m-%d %H:%M:%S", tm);
- len = append_fmt(buf, size, len, ".%03ld ", (long)(ts.tv_nsec / 1000000));
- }
- }
-
- return append_fmt(buf, size, len, "[%s][%c] ", section_name, level_char(level));
-}
-
-/**
- * @brief Terminates the line and writes it out with a single write() call.
- *
- * A single write() to a descriptor opened with O_APPEND keeps lines of different
- * instances from interleaving when they share the same log file.
- *
- * @param buf Buffer holding the line, must have one spare byte for the newline.
- * @param len Length of the line.
- */
-static void log_emit(char *buf, size_t len)
-{
- buf[len++] = '\n';
- write_all(log_fd >= 0 ? log_fd : STDERR_FILENO, buf, len);
-}
-
-/**
- * @brief Writes a single log line.
- *
- * This is the implementation behind the log() macro, which is the one that
- * checks the verbosity level, so the line written here is unconditional.
- *
- * @param level Logging level of the line.
- * @param fmt Format string.
- */
-void log_printf(int level, const char *fmt, ...)
-{
- char buf[LOG_LINE_MAX];
- va_list args;
- size_t len = log_prefix(buf, sizeof(buf) - 1, level);
-
- va_start(args, fmt);
- len = append_vfmt(buf, sizeof(buf) - 1, len, fmt, args);
- va_end(args);
-
- log_emit(buf, len);
-}
-
-/**
- * @brief Writes a hexadecimal dump of a buffer, one or more prefixed lines.
- *
- * @param level Logging level of the dump.
- * @param prefix Text to put right after the line prefix, e.g. a direction marker.
- * @param data Data to dump.
- * @param length Number of bytes to dump.
- */
-void log_hexdump(int level, const char *prefix, const uint8_t *data, int length)
-{
- char buf[LOG_LINE_MAX];
- int i = 0;
-
- if (verbose < level) {
- return;
- }
-
- // Long dumps are split into several lines, each one with its own prefix
- do {
- size_t len = log_prefix(buf, sizeof(buf) - 1, level);
- len = append_fmt(buf, sizeof(buf) - 1, len, "%s", prefix);
- while ((i < length) && (len + 3 < sizeof(buf) - 1)) {
- len = append_fmt(buf, sizeof(buf) - 1, len, "%02X ", data[i++]);
- }
- log_emit(buf, len);
- } while (i < length);
-}
-
-/**
- * @brief Initializes logging.
- *
- * @param path Path of the log file or NULL to keep logging to stderr.
- * @param timestamps_mode 1 to force timestamps on, 0 to force them off,
- * negative to enable them only when logging to a file.
- */
-void log_init(const char *path, int8_t timestamps_mode)
-{
- log_timestamps = (timestamps_mode >= 0) ? (timestamps_mode != 0) : (path != NULL);
-
- if (!path) {
- return;
- }
-
- log_path = strdup(path);
- if (!log_path) {
- fprintf(stderr, "Out of memory while initializing the log file\n");
- exit(EXIT_FAILURE);
- }
-
- log_fd = open(path, O_WRONLY | O_CREAT | O_APPEND | O_BINARY, LOG_FILE_MODE);
- if (log_fd < 0) {
- // Logging into nowhere is worse than not starting at all
- fprintf(stderr, "Can't open log file '%s' - %s (%d)\n", path, strerror(errno), errno);
- exit(EXIT_FAILURE);
- }
-
- // Make every log file start with the version, no matter the verbosity level
- log_printf(LL_INFO, "Starting %s", version_string());
-}
-
-/**
- * @brief Reopens the log file, to be called after the log has been rotated.
- */
-void log_reopen(void)
-{
- int fd;
-
- if (!log_path) {
- return;
- }
-
- fd = open(log_path, O_WRONLY | O_CREAT | O_APPEND | O_BINARY, LOG_FILE_MODE);
- if (fd < 0) {
- // Keep the old descriptor, losing the log completely would be worse
- fprintf(stderr, "Can't reopen log file '%s' - %s (%d)\n", log_path, strerror(errno), errno);
- return;
- }
- if (log_fd >= 0) {
- close(log_fd);
- }
- log_fd = fd;
-
- log_printf(LL_INFO, "Log file reopened, %s", version_string());
-}
diff --git a/ios/Tunnel/obfuscator/masking.c b/ios/Tunnel/obfuscator/masking.c
deleted file mode 100644
index bc9b4e0..0000000
--- a/ios/Tunnel/obfuscator/masking.c
+++ /dev/null
@@ -1,170 +0,0 @@
-#include
-#include
-#include
-#include "wg-obfuscator.h"
-#include "masking.h"
-#include "masking_handlers.h"
-
-static _Thread_local struct {
- int listen_sock;
- struct sockaddr_in *sender_addr;
- int server_sock;
-} g_send_ctx;
-
-static ssize_t send_to_client_cb(uint8_t *buffer, int length) {
- return sendto(g_send_ctx.listen_sock, buffer, length, 0, (struct sockaddr *)g_send_ctx.sender_addr, sizeof(*g_send_ctx.sender_addr));
-}
-
-static ssize_t send_to_server_cb(uint8_t *buffer, int length) {
- return send(g_send_ctx.server_sock, buffer, length, 0);
-}
-
-masking_handler_t * get_masking_handler_by_name(const char *name) {
- if (!name) return NULL;
-
- for (int i = 0; masking_handlers[i]; ++i) {
- char handler_name_lower[MASKING_HANDLER_NAME_LEN];
- strncpy(handler_name_lower, masking_handlers[i]->name, sizeof(handler_name_lower) - 1);
- handler_name_lower[sizeof(handler_name_lower) - 1] = 0;
- for (char *p = handler_name_lower; *p; ++p) *p = tolower((unsigned char)*p);
-
- if (strcmp(name, handler_name_lower) == 0) {
- return masking_handlers[i];
- }
- }
- return NULL;
-}
-
-void masking_on_handshake_req_from_client(obfuscator_config_t *config,
- client_entry_t *client,
- int listen_sock,
- struct sockaddr_in *client_addr,
- struct sockaddr_in *server_addr) {
- if (!client->masking_handler || !client->masking_handler->on_handshake_req) {
- return;
- }
-
- g_send_ctx.listen_sock = listen_sock;
- g_send_ctx.sender_addr = &client->client_addr;
- g_send_ctx.server_sock = client->server_sock;
- client->masking_handler->on_handshake_req(config, client, DIR_CLIENT_TO_SERVER, client_addr, server_addr, send_to_client_cb, send_to_server_cb);
-}
-
-void masking_on_handshake_req_from_server(obfuscator_config_t *config,
- client_entry_t *client,
- int listen_sock,
- struct sockaddr_in *client_addr,
- struct sockaddr_in *server_addr) {
- if (!client->masking_handler || !client->masking_handler->on_handshake_req) {
- return;
- }
-
- g_send_ctx.listen_sock = listen_sock;
- g_send_ctx.sender_addr = &client->client_addr;
- g_send_ctx.server_sock = client->server_sock;
- client->masking_handler->on_handshake_req(config, client, DIR_SERVER_TO_CLIENT, server_addr, client_addr, send_to_server_cb, send_to_client_cb);
-}
-
-int masking_unwrap_from_client(uint8_t **buffer_ptr, int length,
- obfuscator_config_t *config,
- client_entry_t *client, // can be NULL!
- int listen_sock,
- struct sockaddr_in *client_addr,
- struct sockaddr_in *server_addr,
- masking_handler_t **masking_handler_out) {
- g_send_ctx.listen_sock = listen_sock;
- g_send_ctx.sender_addr = client_addr;
- g_send_ctx.server_sock = client ? client->server_sock : 0;
-
- if (!client && !config->masking_handler_set) {
- // Brueteforce detection of masking type if no client entry and no default masking handler
- for (int i = 0; masking_handlers[i]; ++i) {
- // A handler may move *buffer_ptr while unwrapping. If it does not match
- // (returns < 0), restore the pointer so the next handler sees the original data.
- uint8_t *saved_buffer = *buffer_ptr;
- int r = masking_handlers[i]->on_data_unwrap(buffer_ptr, length, config, NULL, DIR_CLIENT_TO_SERVER, client_addr, server_addr, send_to_client_cb, send_to_server_cb);
- if (r < 0) {
- *buffer_ptr = saved_buffer;
- continue;
- }
- // Found a matching masking handler
- log(LL_TRACE, "Autodetected masking handler for packet from %s:%d: %s", inet_ntoa(client_addr->sin_addr), ntohs(client_addr->sin_port), masking_handlers[i]->name);
- if (masking_handler_out) {
- *masking_handler_out = masking_handlers[i];
- }
- return r;
- }
-
- // No matching masking handler found
- if (masking_handler_out) {
- *masking_handler_out = NULL;
- }
- return length;
- }
-
- masking_handler_t *handler = client ? client->masking_handler : config->masking_handler;
- if (!handler || !handler->on_data_unwrap) {
- return length; // no masking handler, nothing to do
- }
-
- return handler->on_data_unwrap(buffer_ptr, length, config, client, DIR_CLIENT_TO_SERVER, client_addr, server_addr, send_to_client_cb, client ? send_to_server_cb : NULL);
-}
-
-int masking_unwrap_from_server(uint8_t **buffer_ptr, int length,
- obfuscator_config_t *config,
- client_entry_t *client,
- int listen_sock,
- struct sockaddr_in *server_addr) {
- if (!client->masking_handler || !client->masking_handler->on_data_unwrap) {
- return length; // no masking handler, nothing to do
- }
-
- g_send_ctx.listen_sock = listen_sock;
- g_send_ctx.sender_addr = &client->client_addr;
- g_send_ctx.server_sock = client->server_sock;
- return client->masking_handler->on_data_unwrap(buffer_ptr, length, config, client, DIR_SERVER_TO_CLIENT, server_addr, &client->client_addr, send_to_server_cb, send_to_client_cb);
-}
-
-int masking_data_wrap_to_client(uint8_t **buffer_ptr, int length,
- obfuscator_config_t *config,
- client_entry_t *client,
- int listen_sock,
- struct sockaddr_in *server_addr) {
- if (!client->masking_handler || !client->masking_handler->on_data_wrap) {
- return length; // no masking handler, nothing to do
- }
-
- g_send_ctx.listen_sock = listen_sock;
- g_send_ctx.sender_addr = &client->client_addr;
- g_send_ctx.server_sock = client->server_sock;
- return client->masking_handler->on_data_wrap(buffer_ptr, length, config, client, DIR_SERVER_TO_CLIENT, server_addr, &client->client_addr, send_to_server_cb, send_to_client_cb);
-}
-
-int masking_data_wrap_to_server(uint8_t **buffer_ptr, int length,
- obfuscator_config_t *config,
- client_entry_t *client,
- int listen_sock,
- struct sockaddr_in *server_addr) {
- if (!client->masking_handler || !client->masking_handler->on_data_wrap) {
- return length; // no masking handler, nothing to do
- }
-
- g_send_ctx.listen_sock = listen_sock;
- g_send_ctx.sender_addr = &client->client_addr;
- g_send_ctx.server_sock = client->server_sock;
- return client->masking_handler->on_data_wrap(buffer_ptr, length, config, client, DIR_CLIENT_TO_SERVER, &client->client_addr, server_addr, send_to_client_cb, send_to_server_cb);
-}
-
-void masking_on_timer(obfuscator_config_t *config,
- client_entry_t *client,
- int listen_sock,
- struct sockaddr_in *server_addr) {
- if (!client->masking_handler || !client->masking_handler->on_timer) {
- return;
- }
-
- g_send_ctx.listen_sock = listen_sock;
- g_send_ctx.sender_addr = &client->client_addr;
- g_send_ctx.server_sock = client->server_sock;
- client->masking_handler->on_timer(config, client, &client->client_addr, server_addr, send_to_client_cb, send_to_server_cb);
-}
diff --git a/ios/Tunnel/obfuscator/masking.h b/ios/Tunnel/obfuscator/masking.h
deleted file mode 100644
index 4a9cc22..0000000
--- a/ios/Tunnel/obfuscator/masking.h
+++ /dev/null
@@ -1,91 +0,0 @@
-#ifndef _MASKING_H_
-#define _MASKING_H_
-
-#include
-#include
-#include "wg-obfuscator.h"
-
-#define MASKING_HANDLER_NAME_LEN 32
-
-typedef ssize_t (*send_data_callback_t)(uint8_t *buffer, int length);
-
-typedef void (*masking_event_handler_t)(obfuscator_config_t *config,
- client_entry_t *client,
- direction_t direction,
- const struct sockaddr_in *src_addr,
- const struct sockaddr_in *dest_addr,
- send_data_callback_t send_back_callback,
- send_data_callback_t send_forward_callback);
-
-typedef int (*masking_data_handler_t)(uint8_t **buffer_ptr, int length,
- obfuscator_config_t *config,
- client_entry_t *client,
- direction_t direction,
- const struct sockaddr_in *src_addr,
- const struct sockaddr_in *dest_addr,
- send_data_callback_t send_back_callback,
- send_data_callback_t send_forward_callback);
-
-typedef void (*masking_timer_handler_t)(obfuscator_config_t *config,
- client_entry_t *client,
- const struct sockaddr_in *client_addr,
- const struct sockaddr_in *server_addr,
- send_data_callback_t send_to_client_callback,
- send_data_callback_t send_to_server_callback);
-
-struct masking_handler {
- char name[MASKING_HANDLER_NAME_LEN];
- masking_event_handler_t on_handshake_req;
- masking_data_handler_t on_data_wrap;
- masking_data_handler_t on_data_unwrap;
- masking_timer_handler_t on_timer;
- uint32_t timer_interval_s;
-};
-typedef struct masking_handler masking_handler_t;
-
-masking_handler_t * get_masking_handler_by_name(const char *name);
-
-void masking_on_handshake_req_from_client(obfuscator_config_t *config,
- client_entry_t *client,
- int listen_sock,
- struct sockaddr_in *client_addr,
- struct sockaddr_in *server_addr);
-
-void masking_on_handshake_req_from_server(obfuscator_config_t *config,
- client_entry_t *client,
- int listen_sock,
- struct sockaddr_in *client_addr,
- struct sockaddr_in *server_addr);
-
-int masking_data_wrap_to_client(uint8_t **buffer_ptr, int length,
- obfuscator_config_t *config,
- client_entry_t *client,
- int listen_sock,
- struct sockaddr_in *server_addr);
-
-int masking_data_wrap_to_server(uint8_t **buffer_ptr, int length,
- obfuscator_config_t *config,
- client_entry_t *client,
- int listen_sock,
- struct sockaddr_in *server_addr);
-
-int masking_unwrap_from_client(uint8_t **buffer_ptr, int length,
- obfuscator_config_t *config,
- client_entry_t *client,
- int listen_sock,
- struct sockaddr_in *client_addr,
- struct sockaddr_in *server_addr,
- masking_handler_t **masking_handler_out);
-
-int masking_unwrap_from_server(uint8_t **buffer_ptr, int length,
- obfuscator_config_t *config,
- client_entry_t *client,
- int listen_sock,
- struct sockaddr_in *server_addr);
-
-void masking_on_timer(obfuscator_config_t *config,
- client_entry_t *client,
- int listen_sock,
- struct sockaddr_in *server_addr);
-
-#endif // _MASKING_H_
diff --git a/ios/Tunnel/obfuscator/masking_handlers.h b/ios/Tunnel/obfuscator/masking_handlers.h
deleted file mode 100644
index c7745a7..0000000
--- a/ios/Tunnel/obfuscator/masking_handlers.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef _MASKING_HANDLERS_H_
-#define _MASKING_HANDLERS_H_
-
-#include "masking.h"
-
-/* List of available masking handlers */
-#include "masking_stun.h"
-
-static masking_handler_t * const masking_handlers[] = {
- &stun_masking_handler,
- NULL
-};
-
-#endif
\ No newline at end of file
diff --git a/ios/Tunnel/obfuscator/masking_stun.c b/ios/Tunnel/obfuscator/masking_stun.c
deleted file mode 100644
index 0a274b9..0000000
--- a/ios/Tunnel/obfuscator/masking_stun.c
+++ /dev/null
@@ -1,298 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include
-#include "wg-obfuscator.h"
-#include "masking.h"
-#include "masking_stun.h"
-
-// Bytes prepended in front of the payload when wrapping data in a STUN Data Indication
-// (20-byte STUN header + 4-byte attribute header). Must fit into PREBUFFER_SIZE so that
-// wrapping can be done by shifting the buffer pointer instead of moving the payload.
-#define STUN_WRAP_OVERHEAD 24
-_Static_assert(STUN_WRAP_OVERHEAD <= PREBUFFER_SIZE,
- "PREBUFFER_SIZE is too small to hold the STUN wrap header");
-
-static void rand_bytes(uint8_t* p, size_t n){ for(size_t i=0;i> 8;
- b[1] = type & 0xFF;
- b[2] = mlen >> 8;
- b[3] = mlen & 0xFF;
- memcpy(b + 4, COOKIE_BE, 4);
- memcpy(b + 8, txid, 12);
- return 20;
-}
-
-static int stun_attr_xor_mapped_addr(uint8_t *b, const struct sockaddr_in *src) {
- // type,len
- b[0] = STUN_ATTR_XORMAPPED >> 8;
- b[1] = STUN_ATTR_XORMAPPED & 0xFF;
- b[2] = 0;
- b[3] = 8; // len=8 (family + port + addr)
- b[4] = 0;
- b[5] = 0x01; // family IPv4
- memcpy(b + 6, &src->sin_port, 2); // network-order bytes
- ((uint8_t*)b)[6] ^= COOKIE_BE[0];
- ((uint8_t*)b)[7] ^= COOKIE_BE[1];
- memcpy(b + 8, &src->sin_addr.s_addr, 4); // network-order bytes
- ((uint8_t*)b)[8] ^= COOKIE_BE[0];
- ((uint8_t*)b)[9] ^= COOKIE_BE[1];
- ((uint8_t*)b)[10] ^= COOKIE_BE[2];
- ((uint8_t*)b)[11] ^= COOKIE_BE[3];
- return 12; // 4 hdr + 8 val
-}
-
-/*
-static int stun_attr_software(uint8_t *b, const char *s) {
- uint16_t n = (uint16_t)strlen(s);
- uint16_t pad = (4 - (n & 3)) & 3;
- if (b) {
- b[0] = STUN_ATTR_SOFTWARE >> 8;
- b[1] = STUN_ATTR_SOFTWARE&0xFF;
- b[2] = n>>8;
- b[3] = n&0xFF;
- memcpy(b+4,s,n);
- if (pad) memset(b+4+n,0,pad);
- }
- return 4 + n + pad;
-}
-*/
-
-static uint32_t crc32(const uint8_t *p, size_t n) {
- uint32_t crc = ~0u;
- for(size_t i = 0; i < n; i++){
- crc ^= p[i];
- for(int k = 0; k < 8; k++)
- crc = (crc >> 1) ^ (0xEDB88320u & (-(int)(crc & 1)));
- }
- return ~crc;
-}
-
-static int stun_attr_fingerprint(uint8_t *pkt, size_t cur_len) {
- uint8_t *b = pkt + cur_len;
- b[0] = STUN_ATTR_FINGERPR >> 8;
- b[1] = STUN_ATTR_FINGERPR & 0xFF;
- b[2] = 0;
- b[3] = 4;
- uint32_t fp = htonl(crc32(pkt, cur_len) ^ 0x5354554eu);
- memcpy(b + 4, &fp, 4);
- return 8; // 4 hdr + 4 val
-}
-
-static int stun_build_binding_request(uint8_t *out) {
- uint8_t txid[12];
- rand_bytes(txid, 12);
- stun_write_header(out, STUN_BINDING_REQ, 0, txid);
- size_t mlen = 0;
- // optional SOFTWARE
- //mlen += stun_attr_software(out+20+mlen, "wgo/1.0");
- mlen += stun_attr_fingerprint(out, 20 + mlen);
- out[2] = (mlen >> 8) & 0xFF;
- out[3] = mlen & 0xFF;
- return (int)(20 + mlen);
-}
-
-static int stun_build_binding_success(uint8_t *out,
- const uint8_t txid[12],
- const struct sockaddr_in *src) {
- if (BUFFER_SIZE < 20 + 12 + 8) return -1; // header + XOR-MAPPED-ADDRESS + fingerprint
- stun_write_header(out, STUN_BINDING_RESP, 0, (uint8_t*)txid);
- size_t mlen = 0;
- mlen += stun_attr_xor_mapped_addr(out + 20 + mlen, src);
- // optional SOFTWARE
- //mlen += stun_attr_software(out+20+mlen, "wgo/1.0");
- mlen += stun_attr_fingerprint(out, 20 + mlen);
- out[2] = (mlen >> 8) & 0xFF;
- out[3] = mlen & 0xFF;
- return (int)(20 + mlen);
-}
-
-static int stun_wrap(uint8_t **buf_ptr, size_t data_len) {
- size_t mlen = 0;
-
- // The caller guarantees the payload already fits into the main buffer (it was
- // received/encoded within BUFFER_SIZE), so the wrapped packet cannot overflow
- // the tail of full_buffer. The attribute length field is also 16-bit only.
- // Note: BUFFER_SIZE (65535) equals the maximum value of a 16-bit unsigned
- // integer (0xFFFF), so this single check covers both the buffer limit and
- // the STUN attribute length field limit.
- if (data_len > BUFFER_SIZE) {
- log(LL_WARN, "Can't wrap data in STUN, data too large (%zu bytes)", data_len);
- return -ENOMEM;
- }
-
- // Header is prepended into the prebuffer (checked at compile time via _Static_assert).
- *buf_ptr -= STUN_WRAP_OVERHEAD;
- uint8_t *buf = *buf_ptr;
-
- uint8_t txid[12];
- rand_bytes(txid,12);
- mlen += stun_write_header(buf, STUN_TYPE_DATA_IND, 0, txid);
-
- buf[mlen] = STUN_ATTR_DATA >> 8;
- buf[mlen + 1] = STUN_ATTR_DATA & 0xFF;
- buf[mlen + 2] = data_len >> 8;
- buf[mlen + 3] = data_len & 0xFF;
-
- return STUN_WRAP_OVERHEAD + data_len;
-}
-
-static int stun_unwrap(uint8_t **buf_ptr, size_t len) {
- uint8_t *buf = *buf_ptr;
- if (len < 20 + 4) return -1; // header + attr
-
- uint16_t msg_type = (buf[0] << 8) | buf[1];
- if (msg_type != STUN_TYPE_DATA_IND) return -1;
-
- uint16_t msg_len = (buf[2] << 8) | buf[3];
- if (msg_len + 20 > len) return -1;
-
- uint16_t attr_type = (buf[20] << 8) | buf[21];
- if (attr_type != STUN_ATTR_DATA) return -1;
-
- uint16_t data_len = (buf[22] << 8) | buf[23];
- if (data_len + 24 > len) return -1;
-
- // Move the buffer pointer to avoid moving the data
- *buf_ptr += 24;
-
- return data_len;
-}
-
-static void stun_on_handshake_req(obfuscator_config_t *config,
- client_entry_t *client,
- direction_t direction,
- const struct sockaddr_in *src_addr,
- const struct sockaddr_in *dest_addr,
- send_data_callback_t send_back_callback,
- send_data_callback_t send_forward_callback) {
- uint8_t buffer[128];
- int len = stun_build_binding_request(buffer);
- if (len < 0) return;
-
- int sent = send_forward_callback(buffer, len);
- if (sent < 0) {
- serror("Can't send STUN binding request to %s:%d", inet_ntoa(dest_addr->sin_addr), ntohs(dest_addr->sin_port));
- } else if (sent != len) {
- log(LL_WARN, "Partial send of STUN binding request to %s:%d (%d of %d bytes)", inet_ntoa(dest_addr->sin_addr), ntohs(dest_addr->sin_port), sent, len);
- } else {
- log(LL_TRACE, "Sent STUN binding request (%d bytes) to %s:%d", len, inet_ntoa(dest_addr->sin_addr), ntohs(dest_addr->sin_port));
- }
-}
-
-static int stun_on_data_unwrap(uint8_t **buffer_ptr, int length,
- obfuscator_config_t *config,
- client_entry_t *client,
- direction_t direction,
- const struct sockaddr_in *src_addr,
- const struct sockaddr_in *dest_addr,
- send_data_callback_t send_back_callback,
- send_data_callback_t send_forward_callback) {
- if (!stun_check_magic(*buffer_ptr, length)) {
- return -EINVAL;
- }
-
- uint16_t stun_type = stun_peek_type(*buffer_ptr);
-
- switch (stun_type) {
- case STUN_BINDING_REQ: {
- // Received STUN Binding Request from client, send Binding Success Response
- log(LL_TRACE, "Received STUN Binding Request from %s:%d", inet_ntoa(src_addr->sin_addr), ntohs(src_addr->sin_port));
- uint8_t txid[12];
- memcpy(txid, (*buffer_ptr) + 8, 12);
- int resp_len = stun_build_binding_success(*buffer_ptr, txid, src_addr);
- if (resp_len > 0) {
- int sent = send_back_callback(*buffer_ptr, resp_len);
- if (sent < 0) {
- serror("sendto STUN response to %s:%d", inet_ntoa(src_addr->sin_addr), ntohs(src_addr->sin_port));
- } else if (sent != resp_len) {
- log(LL_WARN, "Partial send of STUN Binding Success Response to %s:%d (%d of %d bytes)", inet_ntoa(src_addr->sin_addr), ntohs(src_addr->sin_port), sent, resp_len);
- } else {
- log(LL_TRACE, "Sent STUN Binding Success Response (%d bytes) to %s:%d", resp_len, inet_ntoa(src_addr->sin_addr), ntohs(src_addr->sin_port));
- }
- } else {
- log(LL_ERROR, "Failed to build STUN Binding Success Response");
- }
- return 0;
- }
- case STUN_BINDING_RESP:
- log(LL_TRACE, "Received STUN Binding Success Response from %s:%d, ignoring", inet_ntoa(src_addr->sin_addr), ntohs(src_addr->sin_port));
- return 0;
- case STUN_TYPE_DATA_IND:
- length = stun_unwrap(buffer_ptr, length);
- if (length < 0) {
- log(LL_DEBUG, "Failed to unwrap STUN Data Indication from %s:%d", inet_ntoa(src_addr->sin_addr), ntohs(src_addr->sin_port));
- return length;
- }
- log(LL_TRACE, "Unwrapped STUN Data Indication from %s:%d (%d bytes)", inet_ntoa(src_addr->sin_addr), ntohs(src_addr->sin_port), length);
- return length;
- default:
- log(LL_DEBUG, "Received unknown STUN type %04X from %s:%d, ignoring", stun_type, inet_ntoa(src_addr->sin_addr), ntohs(src_addr->sin_port));
- return 0;
- }
-}
-
-static int stun_on_data_wrap(uint8_t **buffer_ptr, int length,
- obfuscator_config_t *config,
- client_entry_t *client,
- direction_t direction,
- const struct sockaddr_in *src_addr,
- const struct sockaddr_in *dest_addr,
- send_data_callback_t send_back_callback,
- send_data_callback_t send_forward_callback) {
- return stun_wrap(buffer_ptr, length);
-}
-
-static void stun_on_timer(obfuscator_config_t *config,
- client_entry_t *client,
- const struct sockaddr_in *client_addr,
- const struct sockaddr_in *server_addr,
- send_data_callback_t send_to_client_callback,
- send_data_callback_t send_to_server_callback) {
- uint8_t buffer[128];
- int len = stun_build_binding_request(buffer);
- if (len < 0) return;
-
- if (client->client_obfuscated) {
- int sent = send_to_client_callback(buffer, len);
- if (sent < 0) {
- serror("STUN binding request to client");
- } else if (sent != len) {
- log(LL_WARN, "Partial send of STUN binding request to client (%d of %d bytes)", sent, len);
- } else {
- log(LL_TRACE, "Sent STUN binding request (%d bytes) to %s:%d", len, inet_ntoa(client_addr->sin_addr), ntohs(client_addr->sin_port));
- }
- }
- if (client->server_obfuscated) {
- int sent = send_to_server_callback(buffer, len);
- if (sent < 0) {
- serror("STUN binding request to server");
- } else if (sent != len) {
- log(LL_WARN, "Partial send of STUN binding request to server (%d of %d bytes)", sent, len);
- } else {
- log(LL_TRACE, "Sent STUN binding request (%d bytes) to %s:%d", len, inet_ntoa(server_addr->sin_addr), ntohs(server_addr->sin_port));
- }
- }
-}
-
-masking_handler_t stun_masking_handler = {
- .name = "STUN",
- .on_handshake_req = stun_on_handshake_req,
- .on_data_wrap = stun_on_data_wrap,
- .on_data_unwrap = stun_on_data_unwrap,
- .on_timer = stun_on_timer,
- .timer_interval_s = 10, // 10 seconds
-};
diff --git a/ios/Tunnel/obfuscator/masking_stun.h b/ios/Tunnel/obfuscator/masking_stun.h
deleted file mode 100644
index e6d906a..0000000
--- a/ios/Tunnel/obfuscator/masking_stun.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef _MASKING_STUN_H_
-#define _MASKING_STUN_H_
-
-#include
-#include
-#include "wg-obfuscator.h"
-
-static const uint8_t COOKIE_BE[4] = {0x21,0x12,0xA4,0x42};
-#define STUN_TYPE_DATA_IND 0x0115
-#define STUN_BINDING_REQ 0x0001
-#define STUN_BINDING_RESP 0x0101
-#define STUN_ATTR_XORMAPPED 0x0020
-#define STUN_ATTR_SOFTWARE 0x8022
-#define STUN_ATTR_FINGERPR 0x8028
-#define STUN_ATTR_DATA 0x0013
-
-extern masking_handler_t stun_masking_handler;
-
-#endif // _MASKING_STUN_H_
diff --git a/ios/Tunnel/obfuscator/mini_argp.h b/ios/Tunnel/obfuscator/mini_argp.h
deleted file mode 100644
index 017c348..0000000
--- a/ios/Tunnel/obfuscator/mini_argp.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/* mini_argp.h
- * Tiny callback-based CLI parser */
-
-#ifndef _MINI_ARGP_H_
-#define _MINI_ARGP_H_
-#include
-#include
-
-typedef int (*mini_argp_cb)(const char *lname, char sname,
- const char *val, void *ctx);
-
-typedef struct {
- const char *long_name; /* "--target" or NULL */
- char short_name; /* 't' or 0 */
- int has_arg; /* 0 flag, 1 needs val */
- mini_argp_cb cb; /* your handler */
-} mini_argp_opt;
-
-/* internal: find desc by name */
-static const mini_argp_opt *
-margp_find(const mini_argp_opt *o, char *lname, char sname)
-{
- for (; o->long_name || o->short_name; o++)
- if ((lname && o->long_name && !strcmp(lname,o->long_name)) ||
- (sname && o->short_name==sname))
- return o;
- return NULL;
-}
-
-static int mini_argp_parse(int argc, char **argv,
- const mini_argp_opt *opts,
- void *ctx,
- mini_argp_cb cb)
-{
- for (int i = 1; i < argc; ++i) {
- char *arg = argv[i];
-
- /* long option: --foo or --foo=bar */
- if (!strncmp(arg, "--", 2)) {
- char *name = arg + 2, *val = NULL;
- if ((val = strchr(name, '='))) { *val = 0; ++val; }
-
- const mini_argp_opt *o = margp_find(opts, name, 0);
- if (!o) { fprintf(stderr,"unknown --%s\n", name); return -1; }
- if (o->has_arg && !val) {
- if (++i == argc) { fprintf(stderr,"--%s needs value\n",name);return -1; }
- val = argv[i];
- }
- if (!o->has_arg) val = NULL;
- mini_argp_cb to_call = o->cb ? o->cb : cb;
- if (to_call(o->long_name, o->short_name, val, ctx)) return -1;
- }
-
- /* short(s): -a, -fVAL, -xzvf */
- else if (arg[0]=='-' && arg[1]) {
- for (size_t pos=1; arg[pos]; ++pos) {
- char c = arg[pos];
- const mini_argp_opt *o = margp_find(opts,NULL,c);
- if (!o){ fprintf(stderr,"unknown -%c\n",c); return -1;}
- const char *val = NULL;
-
- if (o->has_arg) {
- if (arg[pos+1]) val = &arg[pos+1]; /* -fVAL */
- else if (++i < argc) val = argv[i]; /* -f VAL */
- else { fprintf(stderr,"-%c needs value\n",c); return -1;}
- /* Stop further char-scanning: the rest of the arg is the value */
- pos = strlen(arg)-1;
- }
- mini_argp_cb to_call = o->cb ? o->cb : cb;
- if (to_call(o->long_name, o->short_name, val, ctx)) return -1;
- }
- }
-
- /* positional not allowed */
- else {
- fprintf(stderr,"unexpected arg: %s\n",arg); return -1;
- }
- }
- return 0;
-}
-
-#endif/* _MINI_ARGP_H_ */
diff --git a/ios/Tunnel/obfuscator/obfuscation.c b/ios/Tunnel/obfuscator/obfuscation.c
deleted file mode 100644
index 20b4aa4..0000000
--- a/ios/Tunnel/obfuscator/obfuscation.c
+++ /dev/null
@@ -1,130 +0,0 @@
-#include
-#include
-#include
-#include "wg-obfuscator.h"
-#include "obfuscation.h"
-
-static uint8_t crc_a[256]; // step(crc, 0): contribution of the current CRC state
-static uint8_t crc_b[256]; // step(0, inbyte): contribution of the input byte
-static uint8_t tables_ready = 0;
-
-typedef struct {
- uint8_t *data; // cached keystream bytes, NULL until first allocation
- int valid; // number of valid bytes in data
- int cap; // allocated capacity of data
- uint8_t crc; // CRC state right after the 'valid' bytes
-} keystream_row_t;
-
-static keystream_row_t rows[256];
-
-// Single step of the original bit-by-bit CRC8 update, kept only to build the tables.
-static uint8_t crc8_step(uint8_t crc, uint8_t inbyte) {
- for (uint8_t j = 0; j < 8; j++) {
- uint8_t mix = (crc ^ inbyte) & 0x01;
- crc >>= 1;
- if (mix) {
- crc ^= 0x8C;
- }
- inbyte >>= 1;
- }
- return crc;
-}
-
-static void ensure_tables(void) {
- if (tables_ready) {
- return;
- }
- for (int i = 0; i < 256; i++) {
- crc_a[i] = crc8_step((uint8_t)i, 0);
- crc_b[i] = crc8_step(0, (uint8_t)i);
- }
- tables_ready = 1;
-}
-
-// Ensure the given row holds at least 'need' valid keystream bytes (capped at
-// KEYSTREAM_ROW_MAX). On allocation failure the row is left as large as it could
-// grow; the caller then computes the missing tail on the fly.
-static void grow_row(keystream_row_t *row, int cls, int need, const char *key, int key_length) {
- if (need > KEYSTREAM_ROW_MAX) {
- need = KEYSTREAM_ROW_MAX;
- }
- if (row->valid >= need) {
- return;
- }
- if (row->cap < need) {
- int newcap = (need + 255) & ~255; // round up to a 256-byte chunk
- if (newcap > KEYSTREAM_ROW_MAX) {
- newcap = KEYSTREAM_ROW_MAX;
- }
- uint8_t *p = realloc(row->data, newcap);
- if (!p) {
- return; // keep whatever we already have; tail handled by caller
- }
- row->data = p;
- row->cap = newcap;
- }
-
- uint8_t crc = row->crc;
- int ki = row->valid % key_length;
- for (int i = row->valid; i < need; i++) {
- uint8_t inbyte = (uint8_t)(key[ki] + cls + key_length);
- crc = crc_a[crc] ^ crc_b[inbyte];
- row->data[i] = crc;
- if (++ki == key_length) {
- ki = 0;
- }
- }
- row->valid = need;
- row->crc = crc;
-}
-
-// XOR 'n' keystream bytes into dst, 8 bytes at a time. memcpy avoids both
-// strict-aliasing violations and unaligned-access assumptions.
-static void xor_block(uint8_t *dst, const uint8_t *ks, int n) {
- int i = 0;
- for (; i + 8 <= n; i += 8) {
- uint64_t a, b;
- memcpy(&a, dst + i, 8);
- memcpy(&b, ks + i, 8);
- a ^= b;
- memcpy(dst + i, &a, 8);
- }
- for (; i < n; i++) {
- dst[i] ^= ks[i];
- }
-}
-
-void xor_data(uint8_t *buffer, int length, char *key, int key_length) {
- if (length <= 0) {
- return;
- }
- ensure_tables();
-
- int cls = length & 0xFF;
- keystream_row_t *row = &rows[cls];
-
- int cached = (length <= KEYSTREAM_ROW_MAX) ? length : KEYSTREAM_ROW_MAX;
- if (row->valid < cached) {
- grow_row(row, cls, cached, key, key_length);
- }
-
- int n = (length < row->valid) ? length : row->valid;
- if (n > 0) {
- xor_block(buffer, row->data, n);
- }
-
- // Tail beyond the cache limit (or beyond what we could allocate): compute on
- // the fly, continuing the CRC chain from the last cached state.
- if (n < length) {
- uint8_t crc = row->crc;
- int ki = n % key_length;
- for (int i = n; i < length; i++) {
- uint8_t inbyte = (uint8_t)(key[ki] + cls + key_length);
- crc = crc_a[crc] ^ crc_b[inbyte];
- buffer[i] ^= crc;
- if (++ki == key_length) {
- ki = 0;
- }
- }
- }
-}
diff --git a/ios/Tunnel/obfuscator/obfuscation.h b/ios/Tunnel/obfuscator/obfuscation.h
deleted file mode 100644
index e69a41a..0000000
--- a/ios/Tunnel/obfuscator/obfuscation.h
+++ /dev/null
@@ -1,139 +0,0 @@
-#ifndef _OBFUSCATION_H_
-#define _OBFUSCATION_H_
-
-#include
-
-// Current obfuscation version
-#define OBFUSCATION_VERSION 1
-
-// Maximum length (in bytes) of a single cached keystream row.
-// The keystream depends only on (key, length mod 256), so it is cached in 256
-// lazily-grown rows. Packets longer than this limit are still handled correctly:
-// the part beyond the limit is computed on the fly. Worst-case cache memory is
-// 256 * KEYSTREAM_ROW_MAX bytes. 2048 covers a typical MTU plus masking overhead.
-#define KEYSTREAM_ROW_MAX 2048
-
-// WireGuard packet types
-#define WG_TYPE_HANDSHAKE 0x01
-#define WG_TYPE_HANDSHAKE_RESP 0x02
-#define WG_TYPE_COOKIE 0x03
-#define WG_TYPE_DATA 0x04
-
-#define WG_TYPE(data) ((uint32_t)(data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24)))
-#ifndef MIN
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
-#endif
-
-/**
- * Checks if the given data is obfuscated.
- *
- * @param data Pointer to the data buffer to check.
- * @return uint8_t Returns a non-zero value if the data is obfuscated, 0 otherwise.
- */
-static inline uint8_t is_obfuscated(uint8_t *data) {
- uint32_t packet_type = WG_TYPE(data);
- return !(packet_type >= 1 && packet_type <= 4);
-}
-
-/**
- * @brief XORs the data in the given buffer with the key-derived keystream.
- *
- * The keystream is a per-byte CRC8 value derived from the key, the byte position
- * and the packet length; it depends only on (key, length mod 256), so it is
- * cached (see obfuscation.c). The on-the-wire result is byte-for-byte identical
- * to the original bit-by-bit implementation.
- *
- * @param buffer Pointer to the data buffer to be XORed.
- * @param length Length of the data buffer in bytes.
- * @param key Pointer to the key used for XOR operation.
- * @param key_length Length of the key in bytes.
- */
-void xor_data(uint8_t *buffer, int length, char *key, int key_length);
-
-/**
- * @brief Encodes the given buffer using the specified key and version.
- *
- * This function applies an encoding algorithm to the input buffer using the provided key and version.
- * WARNING: buffer must be at least 4 bytes long and aligned to 4 bytes.
- *
- * @param buffer Pointer to the data buffer to encode.
- * @param length Length of the data buffer in bytes.
- * @param key Pointer to the key used for encoding.
- * @param key_length Length of the key in bytes.
- * @param version Encoding version to use.
- * @param max_dummy_length_data Maximum length of dummy data for data packets.
- * @return 0 on success, or a negative value on error.
- */
-static inline int encode(uint8_t *buffer, int length, char *key, int key_length, uint8_t version, int max_dummy_length_data) {
- if (version >= 1) {
- uint32_t packet_type = WG_TYPE(buffer);
- // Add some randomness to the packet
- uint8_t rnd = 1 + (rand() % 255);
- buffer[0] ^= rnd; // Xor the first byte to a random value
- buffer[1] = rnd; // Set the second byte to a random value
- // Add dummy data to the packet
- if (length < MAX_DUMMY_LENGTH_TOTAL) {
- uint16_t dummy_length = 0;
- uint16_t max_dummy_length = MAX_DUMMY_LENGTH_TOTAL - length;
- switch (packet_type) {
- case WG_TYPE_HANDSHAKE:
- case WG_TYPE_HANDSHAKE_RESP:
- // length to MAX_DUMMY_LENGTH_HANDSHAKE
- dummy_length = rand() % MIN(max_dummy_length, MAX_DUMMY_LENGTH_HANDSHAKE);
- break;
- case WG_TYPE_COOKIE:
- case WG_TYPE_DATA:
- // length to MAX_DUMMY_LENGTH_HANDSHAKE
- if (max_dummy_length_data) {
- dummy_length = rand() % MIN(max_dummy_length, max_dummy_length_data);
- }
- break;
- default:
- //assert(0);
- break;
- }
- buffer[2] = dummy_length & 0xFF; // Set the dummy length in the packet
- buffer[3] = dummy_length >> 8; // Set the dummy length in
- if (dummy_length > 0) {
- int i = length;
- length += dummy_length;
- for (; i < length; ++i) {
- buffer[i] = 0xFF; // Fill with FFs, random data is not needed
- }
- }
- }
- }
-
- xor_data(buffer, length, key, key_length);
-
- return length;
-}
-
-/**
- * Decodes the given buffer using the provided key.
- *
- * WARNING: buffer must be at least 4 bytes long and aligned to 4 bytes.
- *
- * @param buffer Pointer to the input buffer to decode.
- * @param length Length of the input buffer.
- * @param key Pointer to the key used for decoding.
- * @param key_length Length of the key.
- * @param version_out Pointer to a variable where the decoded version will be stored.
- * @return Length of the decoded data (smaller than or equal to the input length).
- */
-static inline int decode(uint8_t *buffer, int length, char *key, int key_length, uint8_t *version_out) {
- xor_data(buffer, length, key, key_length);
-
- if (!is_obfuscated(buffer)) {
- // Looks like an old version
- *version_out = 0;
- return length;
- }
-
- buffer[0] ^= buffer[1]; // Restore the first byte by XORing it with the second byte
- length -= (uint16_t)(buffer[2] | (buffer[3] << 8)); // Remove dummy data length from the packet
- buffer[1] = buffer[2] = buffer[3] = 0; // Reset the dummy length field to 0
- return length;
-}
-
-#endif // _OBFUSCATION_H_
\ No newline at end of file
diff --git a/ios/Tunnel/obfuscator/uthash.h b/ios/Tunnel/obfuscator/uthash.h
deleted file mode 100644
index 06c2eeb..0000000
--- a/ios/Tunnel/obfuscator/uthash.h
+++ /dev/null
@@ -1,1137 +0,0 @@
-/*
-Copyright (c) 2003-2025, Troy D. Hanson https://troydhanson.github.io/uthash/
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
-TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
-OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#ifndef UTHASH_H
-#define UTHASH_H
-
-#define UTHASH_VERSION 2.3.0
-
-#include /* memcmp, memset, strlen */
-#include /* ptrdiff_t */
-#include /* exit */
-
-#if defined(HASH_NO_STDINT) && HASH_NO_STDINT
-/* The user doesn't have , and must figure out their own way
- to provide definitions for uint8_t and uint32_t. */
-#else
-#include /* uint8_t, uint32_t */
-#endif
-
-/* These macros use decltype or the earlier __typeof GNU extension.
- As decltype is only available in newer compilers (VS2010 or gcc 4.3+
- when compiling c++ source) this code uses whatever method is needed
- or, for VS2008 where neither is available, uses casting workarounds. */
-#if !defined(DECLTYPE) && !defined(NO_DECLTYPE)
-#if defined(_MSC_VER) /* MS compiler */
-#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */
-#define DECLTYPE(x) (decltype(x))
-#else /* VS2008 or older (or VS2010 in C mode) */
-#define NO_DECLTYPE
-#endif
-#elif defined(__MCST__) /* Elbrus C Compiler */
-#define DECLTYPE(x) (__typeof(x))
-#elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__)
-#define NO_DECLTYPE
-#else /* GNU, Sun and other compilers */
-#define DECLTYPE(x) (__typeof(x))
-#endif
-#endif
-
-#ifdef NO_DECLTYPE
-#define DECLTYPE(x)
-#define DECLTYPE_ASSIGN(dst,src) \
-do { \
- char **_da_dst = (char**)(&(dst)); \
- *_da_dst = (char*)(src); \
-} while (0)
-#else
-#define DECLTYPE_ASSIGN(dst,src) \
-do { \
- (dst) = DECLTYPE(dst)(src); \
-} while (0)
-#endif
-
-#ifndef uthash_malloc
-#define uthash_malloc(sz) malloc(sz) /* malloc fcn */
-#endif
-#ifndef uthash_free
-#define uthash_free(ptr,sz) free(ptr) /* free fcn */
-#endif
-#ifndef uthash_bzero
-#define uthash_bzero(a,n) memset(a,'\0',n)
-#endif
-#ifndef uthash_strlen
-#define uthash_strlen(s) strlen(s)
-#endif
-
-#ifndef HASH_FUNCTION
-#define HASH_FUNCTION(keyptr,keylen,hashv) HASH_JEN(keyptr, keylen, hashv)
-#endif
-
-#ifndef HASH_KEYCMP
-#define HASH_KEYCMP(a,b,n) memcmp(a,b,n)
-#endif
-
-#ifndef uthash_noexpand_fyi
-#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */
-#endif
-#ifndef uthash_expand_fyi
-#define uthash_expand_fyi(tbl) /* can be defined to log expands */
-#endif
-
-#ifndef HASH_NONFATAL_OOM
-#define HASH_NONFATAL_OOM 0
-#endif
-
-#if HASH_NONFATAL_OOM
-/* malloc failures can be recovered from */
-
-#ifndef uthash_nonfatal_oom
-#define uthash_nonfatal_oom(obj) do {} while (0) /* non-fatal OOM error */
-#endif
-
-#define HASH_RECORD_OOM(oomed) do { (oomed) = 1; } while (0)
-#define IF_HASH_NONFATAL_OOM(x) x
-
-#else
-/* malloc failures result in lost memory, hash tables are unusable */
-
-#ifndef uthash_fatal
-#define uthash_fatal(msg) exit(-1) /* fatal OOM error */
-#endif
-
-#define HASH_RECORD_OOM(oomed) uthash_fatal("out of memory")
-#define IF_HASH_NONFATAL_OOM(x)
-
-#endif
-
-/* initial number of buckets */
-#define HASH_INITIAL_NUM_BUCKETS 32U /* initial number of buckets */
-#define HASH_INITIAL_NUM_BUCKETS_LOG2 5U /* lg2 of initial number of buckets */
-#define HASH_BKT_CAPACITY_THRESH 10U /* expand when bucket count reaches */
-
-/* calculate the element whose hash handle address is hhp */
-#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho)))
-/* calculate the hash handle from element address elp */
-#define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle*)(void*)(((char*)(elp)) + ((tbl)->hho)))
-
-#define HASH_ROLLBACK_BKT(hh, head, itemptrhh) \
-do { \
- struct UT_hash_handle *_hd_hh_item = (itemptrhh); \
- unsigned _hd_bkt; \
- HASH_TO_BKT(_hd_hh_item->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \
- (head)->hh.tbl->buckets[_hd_bkt].count++; \
- _hd_hh_item->hh_next = NULL; \
- _hd_hh_item->hh_prev = NULL; \
-} while (0)
-
-#define HASH_VALUE(keyptr,keylen,hashv) \
-do { \
- HASH_FUNCTION(keyptr, keylen, hashv); \
-} while (0)
-
-#define HASH_FIND_BYHASHVALUE(hh,head,keyptr,keylen,hashval,out) \
-do { \
- (out) = NULL; \
- if (head) { \
- unsigned _hf_bkt; \
- HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt); \
- if (HASH_BLOOM_TEST((head)->hh.tbl, hashval)) { \
- HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], keyptr, keylen, hashval, out); \
- } \
- } \
-} while (0)
-
-#define HASH_FIND(hh,head,keyptr,keylen,out) \
-do { \
- (out) = NULL; \
- if (head) { \
- unsigned _hf_hashv; \
- HASH_VALUE(keyptr, keylen, _hf_hashv); \
- HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out); \
- } \
-} while (0)
-
-#ifdef HASH_BLOOM
-#define HASH_BLOOM_BITLEN (1UL << HASH_BLOOM)
-#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8UL) + (((HASH_BLOOM_BITLEN%8UL)!=0UL) ? 1UL : 0UL)
-#define HASH_BLOOM_MAKE(tbl,oomed) \
-do { \
- (tbl)->bloom_nbits = HASH_BLOOM; \
- (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \
- if (!(tbl)->bloom_bv) { \
- HASH_RECORD_OOM(oomed); \
- } else { \
- uthash_bzero((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \
- (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \
- } \
-} while (0)
-
-#define HASH_BLOOM_FREE(tbl) \
-do { \
- uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \
-} while (0)
-
-#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8U] |= (1U << ((idx)%8U)))
-#define HASH_BLOOM_BITTEST(bv,idx) ((bv[(idx)/8U] & (1U << ((idx)%8U))) != 0)
-
-#define HASH_BLOOM_ADD(tbl,hashv) \
- HASH_BLOOM_BITSET((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U)))
-
-#define HASH_BLOOM_TEST(tbl,hashv) \
- HASH_BLOOM_BITTEST((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U)))
-
-#else
-#define HASH_BLOOM_MAKE(tbl,oomed)
-#define HASH_BLOOM_FREE(tbl)
-#define HASH_BLOOM_ADD(tbl,hashv)
-#define HASH_BLOOM_TEST(tbl,hashv) 1
-#define HASH_BLOOM_BYTELEN 0U
-#endif
-
-#define HASH_MAKE_TABLE(hh,head,oomed) \
-do { \
- (head)->hh.tbl = (UT_hash_table*)uthash_malloc(sizeof(UT_hash_table)); \
- if (!(head)->hh.tbl) { \
- HASH_RECORD_OOM(oomed); \
- } else { \
- uthash_bzero((head)->hh.tbl, sizeof(UT_hash_table)); \
- (head)->hh.tbl->tail = &((head)->hh); \
- (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \
- (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \
- (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \
- (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \
- HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \
- (head)->hh.tbl->signature = HASH_SIGNATURE; \
- if (!(head)->hh.tbl->buckets) { \
- HASH_RECORD_OOM(oomed); \
- uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
- } else { \
- uthash_bzero((head)->hh.tbl->buckets, \
- HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \
- HASH_BLOOM_MAKE((head)->hh.tbl, oomed); \
- IF_HASH_NONFATAL_OOM( \
- if (oomed) { \
- uthash_free((head)->hh.tbl->buckets, \
- HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \
- uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
- } \
- ) \
- } \
- } \
-} while (0)
-
-#define HASH_REPLACE_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,replaced,cmpfcn) \
-do { \
- (replaced) = NULL; \
- HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \
- if (replaced) { \
- HASH_DELETE(hh, head, replaced); \
- } \
- HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn); \
-} while (0)
-
-#define HASH_REPLACE_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add,replaced) \
-do { \
- (replaced) = NULL; \
- HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \
- if (replaced) { \
- HASH_DELETE(hh, head, replaced); \
- } \
- HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add); \
-} while (0)
-
-#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \
-do { \
- unsigned _hr_hashv; \
- HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \
- HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced); \
-} while (0)
-
-#define HASH_REPLACE_INORDER(hh,head,fieldname,keylen_in,add,replaced,cmpfcn) \
-do { \
- unsigned _hr_hashv; \
- HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \
- HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced, cmpfcn); \
-} while (0)
-
-#define HASH_APPEND_LIST(hh, head, add) \
-do { \
- (add)->hh.next = NULL; \
- (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \
- (head)->hh.tbl->tail->next = (add); \
- (head)->hh.tbl->tail = &((add)->hh); \
-} while (0)
-
-#define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \
-do { \
- do { \
- if (cmpfcn(DECLTYPE(head)(_hs_iter), add) > 0) { \
- break; \
- } \
- } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \
-} while (0)
-
-#ifdef NO_DECLTYPE
-#undef HASH_AKBI_INNER_LOOP
-#define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \
-do { \
- char *_hs_saved_head = (char*)(head); \
- do { \
- DECLTYPE_ASSIGN(head, _hs_iter); \
- if (cmpfcn(head, add) > 0) { \
- DECLTYPE_ASSIGN(head, _hs_saved_head); \
- break; \
- } \
- DECLTYPE_ASSIGN(head, _hs_saved_head); \
- } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \
-} while (0)
-#endif
-
-#if HASH_NONFATAL_OOM
-
-#define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \
-do { \
- if (!(oomed)) { \
- unsigned _ha_bkt; \
- (head)->hh.tbl->num_items++; \
- HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \
- HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \
- if (oomed) { \
- HASH_ROLLBACK_BKT(hh, head, &(add)->hh); \
- HASH_DELETE_HH(hh, head, &(add)->hh); \
- (add)->hh.tbl = NULL; \
- uthash_nonfatal_oom(add); \
- } else { \
- HASH_BLOOM_ADD((head)->hh.tbl, hashval); \
- HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \
- } \
- } else { \
- (add)->hh.tbl = NULL; \
- uthash_nonfatal_oom(add); \
- } \
-} while (0)
-
-#else
-
-#define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \
-do { \
- unsigned _ha_bkt; \
- (head)->hh.tbl->num_items++; \
- HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \
- HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \
- HASH_BLOOM_ADD((head)->hh.tbl, hashval); \
- HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \
-} while (0)
-
-#endif
-
-
-#define HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh,head,keyptr,keylen_in,hashval,add,cmpfcn) \
-do { \
- IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \
- (add)->hh.hashv = (hashval); \
- (add)->hh.key = (char*) (keyptr); \
- (add)->hh.keylen = (unsigned) (keylen_in); \
- if (!(head)) { \
- (add)->hh.next = NULL; \
- (add)->hh.prev = NULL; \
- HASH_MAKE_TABLE(hh, add, _ha_oomed); \
- IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \
- (head) = (add); \
- IF_HASH_NONFATAL_OOM( } ) \
- } else { \
- void *_hs_iter = (head); \
- (add)->hh.tbl = (head)->hh.tbl; \
- HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn); \
- if (_hs_iter) { \
- (add)->hh.next = _hs_iter; \
- if (((add)->hh.prev = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev)) { \
- HH_FROM_ELMT((head)->hh.tbl, (add)->hh.prev)->next = (add); \
- } else { \
- (head) = (add); \
- } \
- HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev = (add); \
- } else { \
- HASH_APPEND_LIST(hh, head, add); \
- } \
- } \
- HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \
- HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE_INORDER"); \
-} while (0)
-
-#define HASH_ADD_KEYPTR_INORDER(hh,head,keyptr,keylen_in,add,cmpfcn) \
-do { \
- unsigned _hs_hashv; \
- HASH_VALUE(keyptr, keylen_in, _hs_hashv); \
- HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, _hs_hashv, add, cmpfcn); \
-} while (0)
-
-#define HASH_ADD_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,cmpfcn) \
- HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn)
-
-#define HASH_ADD_INORDER(hh,head,fieldname,keylen_in,add,cmpfcn) \
- HASH_ADD_KEYPTR_INORDER(hh, head, &((add)->fieldname), keylen_in, add, cmpfcn)
-
-#define HASH_ADD_KEYPTR_BYHASHVALUE(hh,head,keyptr,keylen_in,hashval,add) \
-do { \
- IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \
- (add)->hh.hashv = (hashval); \
- (add)->hh.key = (const void*) (keyptr); \
- (add)->hh.keylen = (unsigned) (keylen_in); \
- if (!(head)) { \
- (add)->hh.next = NULL; \
- (add)->hh.prev = NULL; \
- HASH_MAKE_TABLE(hh, add, _ha_oomed); \
- IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \
- (head) = (add); \
- IF_HASH_NONFATAL_OOM( } ) \
- } else { \
- (add)->hh.tbl = (head)->hh.tbl; \
- HASH_APPEND_LIST(hh, head, add); \
- } \
- HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \
- HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE"); \
-} while (0)
-
-#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \
-do { \
- unsigned _ha_hashv; \
- HASH_VALUE(keyptr, keylen_in, _ha_hashv); \
- HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, _ha_hashv, add); \
-} while (0)
-
-#define HASH_ADD_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add) \
- HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add)
-
-#define HASH_ADD(hh,head,fieldname,keylen_in,add) \
- HASH_ADD_KEYPTR(hh, head, &((add)->fieldname), keylen_in, add)
-
-#define HASH_TO_BKT(hashv,num_bkts,bkt) \
-do { \
- bkt = ((hashv) & ((num_bkts) - 1U)); \
-} while (0)
-
-/* delete "delptr" from the hash table.
- * "the usual" patch-up process for the app-order doubly-linked-list.
- * The use of _hd_hh_del below deserves special explanation.
- * These used to be expressed using (delptr) but that led to a bug
- * if someone used the same symbol for the head and deletee, like
- * HASH_DELETE(hh,users,users);
- * We want that to work, but by changing the head (users) below
- * we were forfeiting our ability to further refer to the deletee (users)
- * in the patch-up process. Solution: use scratch space to
- * copy the deletee pointer, then the latter references are via that
- * scratch pointer rather than through the repointed (users) symbol.
- */
-#define HASH_DELETE(hh,head,delptr) \
- HASH_DELETE_HH(hh, head, &(delptr)->hh)
-
-#define HASH_DELETE_HH(hh,head,delptrhh) \
-do { \
- const struct UT_hash_handle *_hd_hh_del = (delptrhh); \
- if ((_hd_hh_del->prev == NULL) && (_hd_hh_del->next == NULL)) { \
- HASH_BLOOM_FREE((head)->hh.tbl); \
- uthash_free((head)->hh.tbl->buckets, \
- (head)->hh.tbl->num_buckets * sizeof(struct UT_hash_bucket)); \
- uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
- (head) = NULL; \
- } else { \
- unsigned _hd_bkt; \
- if (_hd_hh_del == (head)->hh.tbl->tail) { \
- (head)->hh.tbl->tail = HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev); \
- } \
- if (_hd_hh_del->prev != NULL) { \
- HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev)->next = _hd_hh_del->next; \
- } else { \
- DECLTYPE_ASSIGN(head, _hd_hh_del->next); \
- } \
- if (_hd_hh_del->next != NULL) { \
- HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->next)->prev = _hd_hh_del->prev; \
- } \
- HASH_TO_BKT(_hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \
- HASH_DEL_IN_BKT((head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \
- (head)->hh.tbl->num_items--; \
- } \
- HASH_FSCK(hh, head, "HASH_DELETE_HH"); \
-} while (0)
-
-/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */
-#define HASH_FIND_STR(head,findstr,out) \
-do { \
- unsigned _uthash_hfstr_keylen = (unsigned)uthash_strlen(findstr); \
- HASH_FIND(hh, head, findstr, _uthash_hfstr_keylen, out); \
-} while (0)
-#define HASH_ADD_STR(head,strfield,add) \
-do { \
- unsigned _uthash_hastr_keylen = (unsigned)uthash_strlen((add)->strfield); \
- HASH_ADD(hh, head, strfield[0], _uthash_hastr_keylen, add); \
-} while (0)
-#define HASH_REPLACE_STR(head,strfield,add,replaced) \
-do { \
- unsigned _uthash_hrstr_keylen = (unsigned)uthash_strlen((add)->strfield); \
- HASH_REPLACE(hh, head, strfield[0], _uthash_hrstr_keylen, add, replaced); \
-} while (0)
-#define HASH_FIND_INT(head,findint,out) \
- HASH_FIND(hh,head,findint,sizeof(int),out)
-#define HASH_ADD_INT(head,intfield,add) \
- HASH_ADD(hh,head,intfield,sizeof(int),add)
-#define HASH_REPLACE_INT(head,intfield,add,replaced) \
- HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced)
-#define HASH_FIND_PTR(head,findptr,out) \
- HASH_FIND(hh,head,findptr,sizeof(void *),out)
-#define HASH_ADD_PTR(head,ptrfield,add) \
- HASH_ADD(hh,head,ptrfield,sizeof(void *),add)
-#define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \
- HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced)
-#define HASH_DEL(head,delptr) \
- HASH_DELETE(hh,head,delptr)
-
-/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined.
- * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined.
- */
-#ifdef HASH_DEBUG
-#include /* fprintf, stderr */
-#define HASH_OOPS(...) do { fprintf(stderr, __VA_ARGS__); exit(-1); } while (0)
-#define HASH_FSCK(hh,head,where) \
-do { \
- struct UT_hash_handle *_thh; \
- if (head) { \
- unsigned _bkt_i; \
- unsigned _count = 0; \
- char *_prev; \
- for (_bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; ++_bkt_i) { \
- unsigned _bkt_count = 0; \
- _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \
- _prev = NULL; \
- while (_thh) { \
- if (_prev != (char*)(_thh->hh_prev)) { \
- HASH_OOPS("%s: invalid hh_prev %p, actual %p\n", \
- (where), (void*)_thh->hh_prev, (void*)_prev); \
- } \
- _bkt_count++; \
- _prev = (char*)(_thh); \
- _thh = _thh->hh_next; \
- } \
- _count += _bkt_count; \
- if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \
- HASH_OOPS("%s: invalid bucket count %u, actual %u\n", \
- (where), (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \
- } \
- } \
- if (_count != (head)->hh.tbl->num_items) { \
- HASH_OOPS("%s: invalid hh item count %u, actual %u\n", \
- (where), (head)->hh.tbl->num_items, _count); \
- } \
- _count = 0; \
- _prev = NULL; \
- _thh = &(head)->hh; \
- while (_thh) { \
- _count++; \
- if (_prev != (char*)_thh->prev) { \
- HASH_OOPS("%s: invalid prev %p, actual %p\n", \
- (where), (void*)_thh->prev, (void*)_prev); \
- } \
- _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \
- _thh = (_thh->next ? HH_FROM_ELMT((head)->hh.tbl, _thh->next) : NULL); \
- } \
- if (_count != (head)->hh.tbl->num_items) { \
- HASH_OOPS("%s: invalid app item count %u, actual %u\n", \
- (where), (head)->hh.tbl->num_items, _count); \
- } \
- } \
-} while (0)
-#else
-#define HASH_FSCK(hh,head,where)
-#endif
-
-/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to
- * the descriptor to which this macro is defined for tuning the hash function.
- * The app can #include to get the prototype for write(2). */
-#ifdef HASH_EMIT_KEYS
-#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \
-do { \
- unsigned _klen = fieldlen; \
- write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \
- write(HASH_EMIT_KEYS, keyptr, (unsigned long)fieldlen); \
-} while (0)
-#else
-#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen)
-#endif
-
-/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */
-#define HASH_BER(key,keylen,hashv) \
-do { \
- unsigned _hb_keylen = (unsigned)keylen; \
- const unsigned char *_hb_key = (const unsigned char*)(key); \
- (hashv) = 0; \
- while (_hb_keylen-- != 0U) { \
- (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; \
- } \
-} while (0)
-
-
-/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at
- * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
- * (archive link: https://archive.is/Ivcan )
- */
-#define HASH_SAX(key,keylen,hashv) \
-do { \
- unsigned _sx_i; \
- const unsigned char *_hs_key = (const unsigned char*)(key); \
- hashv = 0; \
- for (_sx_i=0; _sx_i < keylen; _sx_i++) { \
- hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \
- } \
-} while (0)
-/* FNV-1a variation */
-#define HASH_FNV(key,keylen,hashv) \
-do { \
- unsigned _fn_i; \
- const unsigned char *_hf_key = (const unsigned char*)(key); \
- (hashv) = 2166136261U; \
- for (_fn_i=0; _fn_i < keylen; _fn_i++) { \
- hashv = hashv ^ _hf_key[_fn_i]; \
- hashv = hashv * 16777619U; \
- } \
-} while (0)
-
-#define HASH_OAT(key,keylen,hashv) \
-do { \
- unsigned _ho_i; \
- const unsigned char *_ho_key=(const unsigned char*)(key); \
- hashv = 0; \
- for(_ho_i=0; _ho_i < keylen; _ho_i++) { \
- hashv += _ho_key[_ho_i]; \
- hashv += (hashv << 10); \
- hashv ^= (hashv >> 6); \
- } \
- hashv += (hashv << 3); \
- hashv ^= (hashv >> 11); \
- hashv += (hashv << 15); \
-} while (0)
-
-#define HASH_JEN_MIX(a,b,c) \
-do { \
- a -= b; a -= c; a ^= ( c >> 13 ); \
- b -= c; b -= a; b ^= ( a << 8 ); \
- c -= a; c -= b; c ^= ( b >> 13 ); \
- a -= b; a -= c; a ^= ( c >> 12 ); \
- b -= c; b -= a; b ^= ( a << 16 ); \
- c -= a; c -= b; c ^= ( b >> 5 ); \
- a -= b; a -= c; a ^= ( c >> 3 ); \
- b -= c; b -= a; b ^= ( a << 10 ); \
- c -= a; c -= b; c ^= ( b >> 15 ); \
-} while (0)
-
-#define HASH_JEN(key,keylen,hashv) \
-do { \
- unsigned _hj_i,_hj_j,_hj_k; \
- unsigned const char *_hj_key=(unsigned const char*)(key); \
- hashv = 0xfeedbeefu; \
- _hj_i = _hj_j = 0x9e3779b9u; \
- _hj_k = (unsigned)(keylen); \
- while (_hj_k >= 12U) { \
- _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \
- + ( (unsigned)_hj_key[2] << 16 ) \
- + ( (unsigned)_hj_key[3] << 24 ) ); \
- _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \
- + ( (unsigned)_hj_key[6] << 16 ) \
- + ( (unsigned)_hj_key[7] << 24 ) ); \
- hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \
- + ( (unsigned)_hj_key[10] << 16 ) \
- + ( (unsigned)_hj_key[11] << 24 ) ); \
- \
- HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
- \
- _hj_key += 12; \
- _hj_k -= 12U; \
- } \
- hashv += (unsigned)(keylen); \
- switch ( _hj_k ) { \
- case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); /* FALLTHROUGH */ \
- case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); /* FALLTHROUGH */ \
- case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); /* FALLTHROUGH */ \
- case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); /* FALLTHROUGH */ \
- case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); /* FALLTHROUGH */ \
- case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); /* FALLTHROUGH */ \
- case 5: _hj_j += _hj_key[4]; /* FALLTHROUGH */ \
- case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); /* FALLTHROUGH */ \
- case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); /* FALLTHROUGH */ \
- case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); /* FALLTHROUGH */ \
- case 1: _hj_i += _hj_key[0]; /* FALLTHROUGH */ \
- default: ; \
- } \
- HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
-} while (0)
-
-/* The Paul Hsieh hash function */
-#undef get16bits
-#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
- || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
-#define get16bits(d) (*((const uint16_t *) (d)))
-#endif
-
-#if !defined (get16bits)
-#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \
- +(uint32_t)(((const uint8_t *)(d))[0]) )
-#endif
-#define HASH_SFH(key,keylen,hashv) \
-do { \
- unsigned const char *_sfh_key=(unsigned const char*)(key); \
- uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen; \
- \
- unsigned _sfh_rem = _sfh_len & 3U; \
- _sfh_len >>= 2; \
- hashv = 0xcafebabeu; \
- \
- /* Main loop */ \
- for (;_sfh_len > 0U; _sfh_len--) { \
- hashv += get16bits (_sfh_key); \
- _sfh_tmp = ((uint32_t)(get16bits (_sfh_key+2)) << 11) ^ hashv; \
- hashv = (hashv << 16) ^ _sfh_tmp; \
- _sfh_key += 2U*sizeof (uint16_t); \
- hashv += hashv >> 11; \
- } \
- \
- /* Handle end cases */ \
- switch (_sfh_rem) { \
- case 3: hashv += get16bits (_sfh_key); \
- hashv ^= hashv << 16; \
- hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)]) << 18; \
- hashv += hashv >> 11; \
- break; \
- case 2: hashv += get16bits (_sfh_key); \
- hashv ^= hashv << 11; \
- hashv += hashv >> 17; \
- break; \
- case 1: hashv += *_sfh_key; \
- hashv ^= hashv << 10; \
- hashv += hashv >> 1; \
- break; \
- default: ; \
- } \
- \
- /* Force "avalanching" of final 127 bits */ \
- hashv ^= hashv << 3; \
- hashv += hashv >> 5; \
- hashv ^= hashv << 4; \
- hashv += hashv >> 17; \
- hashv ^= hashv << 25; \
- hashv += hashv >> 6; \
-} while (0)
-
-/* iterate over items in a known bucket to find desired item */
-#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,hashval,out) \
-do { \
- if ((head).hh_head != NULL) { \
- DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (head).hh_head)); \
- } else { \
- (out) = NULL; \
- } \
- while ((out) != NULL) { \
- if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) { \
- if (HASH_KEYCMP((out)->hh.key, keyptr, keylen_in) == 0) { \
- break; \
- } \
- } \
- if ((out)->hh.hh_next != NULL) { \
- DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (out)->hh.hh_next)); \
- } else { \
- (out) = NULL; \
- } \
- } \
-} while (0)
-
-/* add an item to a bucket */
-#define HASH_ADD_TO_BKT(head,hh,addhh,oomed) \
-do { \
- UT_hash_bucket *_ha_head = &(head); \
- _ha_head->count++; \
- (addhh)->hh_next = _ha_head->hh_head; \
- (addhh)->hh_prev = NULL; \
- if (_ha_head->hh_head != NULL) { \
- _ha_head->hh_head->hh_prev = (addhh); \
- } \
- _ha_head->hh_head = (addhh); \
- if ((_ha_head->count >= ((_ha_head->expand_mult + 1U) * HASH_BKT_CAPACITY_THRESH)) \
- && !(addhh)->tbl->noexpand) { \
- HASH_EXPAND_BUCKETS(addhh,(addhh)->tbl, oomed); \
- IF_HASH_NONFATAL_OOM( \
- if (oomed) { \
- HASH_DEL_IN_BKT(head,addhh); \
- } \
- ) \
- } \
-} while (0)
-
-/* remove an item from a given bucket */
-#define HASH_DEL_IN_BKT(head,delhh) \
-do { \
- UT_hash_bucket *_hd_head = &(head); \
- _hd_head->count--; \
- if (_hd_head->hh_head == (delhh)) { \
- _hd_head->hh_head = (delhh)->hh_next; \
- } \
- if ((delhh)->hh_prev) { \
- (delhh)->hh_prev->hh_next = (delhh)->hh_next; \
- } \
- if ((delhh)->hh_next) { \
- (delhh)->hh_next->hh_prev = (delhh)->hh_prev; \
- } \
-} while (0)
-
-/* Bucket expansion has the effect of doubling the number of buckets
- * and redistributing the items into the new buckets. Ideally the
- * items will distribute more or less evenly into the new buckets
- * (the extent to which this is true is a measure of the quality of
- * the hash function as it applies to the key domain).
- *
- * With the items distributed into more buckets, the chain length
- * (item count) in each bucket is reduced. Thus by expanding buckets
- * the hash keeps a bound on the chain length. This bounded chain
- * length is the essence of how a hash provides constant time lookup.
- *
- * The calculation of tbl->ideal_chain_maxlen below deserves some
- * explanation. First, keep in mind that we're calculating the ideal
- * maximum chain length based on the *new* (doubled) bucket count.
- * In fractions this is just n/b (n=number of items,b=new num buckets).
- * Since the ideal chain length is an integer, we want to calculate
- * ceil(n/b). We don't depend on floating point arithmetic in this
- * hash, so to calculate ceil(n/b) with integers we could write
- *
- * ceil(n/b) = (n/b) + ((n%b)?1:0)
- *
- * and in fact a previous version of this hash did just that.
- * But now we have improved things a bit by recognizing that b is
- * always a power of two. We keep its base 2 log handy (call it lb),
- * so now we can write this with a bit shift and logical AND:
- *
- * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0)
- *
- */
-#define HASH_EXPAND_BUCKETS(hh,tbl,oomed) \
-do { \
- unsigned _he_bkt; \
- unsigned _he_bkt_i; \
- struct UT_hash_handle *_he_thh, *_he_hh_nxt; \
- UT_hash_bucket *_he_new_buckets, *_he_newbkt; \
- _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \
- sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \
- if (!_he_new_buckets) { \
- HASH_RECORD_OOM(oomed); \
- } else { \
- uthash_bzero(_he_new_buckets, \
- sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \
- (tbl)->ideal_chain_maxlen = \
- ((tbl)->num_items >> ((tbl)->log2_num_buckets+1U)) + \
- ((((tbl)->num_items & (((tbl)->num_buckets*2U)-1U)) != 0U) ? 1U : 0U); \
- (tbl)->nonideal_items = 0; \
- for (_he_bkt_i = 0; _he_bkt_i < (tbl)->num_buckets; _he_bkt_i++) { \
- _he_thh = (tbl)->buckets[ _he_bkt_i ].hh_head; \
- while (_he_thh != NULL) { \
- _he_hh_nxt = _he_thh->hh_next; \
- HASH_TO_BKT(_he_thh->hashv, (tbl)->num_buckets * 2U, _he_bkt); \
- _he_newbkt = &(_he_new_buckets[_he_bkt]); \
- if (++(_he_newbkt->count) > (tbl)->ideal_chain_maxlen) { \
- (tbl)->nonideal_items++; \
- if (_he_newbkt->count > _he_newbkt->expand_mult * (tbl)->ideal_chain_maxlen) { \
- _he_newbkt->expand_mult++; \
- } \
- } \
- _he_thh->hh_prev = NULL; \
- _he_thh->hh_next = _he_newbkt->hh_head; \
- if (_he_newbkt->hh_head != NULL) { \
- _he_newbkt->hh_head->hh_prev = _he_thh; \
- } \
- _he_newbkt->hh_head = _he_thh; \
- _he_thh = _he_hh_nxt; \
- } \
- } \
- uthash_free((tbl)->buckets, (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \
- (tbl)->num_buckets *= 2U; \
- (tbl)->log2_num_buckets++; \
- (tbl)->buckets = _he_new_buckets; \
- (tbl)->ineff_expands = ((tbl)->nonideal_items > ((tbl)->num_items >> 1)) ? \
- ((tbl)->ineff_expands+1U) : 0U; \
- if ((tbl)->ineff_expands > 1U) { \
- (tbl)->noexpand = 1; \
- uthash_noexpand_fyi(tbl); \
- } \
- uthash_expand_fyi(tbl); \
- } \
-} while (0)
-
-
-/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */
-/* Note that HASH_SORT assumes the hash handle name to be hh.
- * HASH_SRT was added to allow the hash handle name to be passed in. */
-#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn)
-#define HASH_SRT(hh,head,cmpfcn) \
-do { \
- unsigned _hs_i; \
- unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \
- struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \
- if (head != NULL) { \
- _hs_insize = 1; \
- _hs_looping = 1; \
- _hs_list = &((head)->hh); \
- while (_hs_looping != 0U) { \
- _hs_p = _hs_list; \
- _hs_list = NULL; \
- _hs_tail = NULL; \
- _hs_nmerges = 0; \
- while (_hs_p != NULL) { \
- _hs_nmerges++; \
- _hs_q = _hs_p; \
- _hs_psize = 0; \
- for (_hs_i = 0; _hs_i < _hs_insize; ++_hs_i) { \
- _hs_psize++; \
- _hs_q = ((_hs_q->next != NULL) ? \
- HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \
- if (_hs_q == NULL) { \
- break; \
- } \
- } \
- _hs_qsize = _hs_insize; \
- while ((_hs_psize != 0U) || ((_hs_qsize != 0U) && (_hs_q != NULL))) { \
- if (_hs_psize == 0U) { \
- _hs_e = _hs_q; \
- _hs_q = ((_hs_q->next != NULL) ? \
- HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \
- _hs_qsize--; \
- } else if ((_hs_qsize == 0U) || (_hs_q == NULL)) { \
- _hs_e = _hs_p; \
- if (_hs_p != NULL) { \
- _hs_p = ((_hs_p->next != NULL) ? \
- HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \
- } \
- _hs_psize--; \
- } else if ((cmpfcn( \
- DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_p)), \
- DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_q)) \
- )) <= 0) { \
- _hs_e = _hs_p; \
- if (_hs_p != NULL) { \
- _hs_p = ((_hs_p->next != NULL) ? \
- HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \
- } \
- _hs_psize--; \
- } else { \
- _hs_e = _hs_q; \
- _hs_q = ((_hs_q->next != NULL) ? \
- HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \
- _hs_qsize--; \
- } \
- if ( _hs_tail != NULL ) { \
- _hs_tail->next = ((_hs_e != NULL) ? \
- ELMT_FROM_HH((head)->hh.tbl, _hs_e) : NULL); \
- } else { \
- _hs_list = _hs_e; \
- } \
- if (_hs_e != NULL) { \
- _hs_e->prev = ((_hs_tail != NULL) ? \
- ELMT_FROM_HH((head)->hh.tbl, _hs_tail) : NULL); \
- } \
- _hs_tail = _hs_e; \
- } \
- _hs_p = _hs_q; \
- } \
- if (_hs_tail != NULL) { \
- _hs_tail->next = NULL; \
- } \
- if (_hs_nmerges <= 1U) { \
- _hs_looping = 0; \
- (head)->hh.tbl->tail = _hs_tail; \
- DECLTYPE_ASSIGN(head, ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \
- } \
- _hs_insize *= 2U; \
- } \
- HASH_FSCK(hh, head, "HASH_SRT"); \
- } \
-} while (0)
-
-/* This function selects items from one hash into another hash.
- * The end result is that the selected items have dual presence
- * in both hashes. There is no copy of the items made; rather
- * they are added into the new hash through a secondary hash
- * hash handle that must be present in the structure. */
-#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \
-do { \
- unsigned _src_bkt, _dst_bkt; \
- void *_last_elt = NULL, *_elt; \
- UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \
- ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \
- if ((src) != NULL) { \
- for (_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \
- for (_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \
- _src_hh != NULL; \
- _src_hh = _src_hh->hh_next) { \
- _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \
- if (cond(_elt)) { \
- IF_HASH_NONFATAL_OOM( int _hs_oomed = 0; ) \
- _dst_hh = (UT_hash_handle*)(void*)(((char*)_elt) + _dst_hho); \
- _dst_hh->key = _src_hh->key; \
- _dst_hh->keylen = _src_hh->keylen; \
- _dst_hh->hashv = _src_hh->hashv; \
- _dst_hh->prev = _last_elt; \
- _dst_hh->next = NULL; \
- if (_last_elt_hh != NULL) { \
- _last_elt_hh->next = _elt; \
- } \
- if ((dst) == NULL) { \
- DECLTYPE_ASSIGN(dst, _elt); \
- HASH_MAKE_TABLE(hh_dst, dst, _hs_oomed); \
- IF_HASH_NONFATAL_OOM( \
- if (_hs_oomed) { \
- uthash_nonfatal_oom(_elt); \
- (dst) = NULL; \
- continue; \
- } \
- ) \
- } else { \
- _dst_hh->tbl = (dst)->hh_dst.tbl; \
- } \
- HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \
- HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt], hh_dst, _dst_hh, _hs_oomed); \
- (dst)->hh_dst.tbl->num_items++; \
- IF_HASH_NONFATAL_OOM( \
- if (_hs_oomed) { \
- HASH_ROLLBACK_BKT(hh_dst, dst, _dst_hh); \
- HASH_DELETE_HH(hh_dst, dst, _dst_hh); \
- _dst_hh->tbl = NULL; \
- uthash_nonfatal_oom(_elt); \
- continue; \
- } \
- ) \
- HASH_BLOOM_ADD(_dst_hh->tbl, _dst_hh->hashv); \
- _last_elt = _elt; \
- _last_elt_hh = _dst_hh; \
- } \
- } \
- } \
- } \
- HASH_FSCK(hh_dst, dst, "HASH_SELECT"); \
-} while (0)
-
-#define HASH_CLEAR(hh,head) \
-do { \
- if ((head) != NULL) { \
- HASH_BLOOM_FREE((head)->hh.tbl); \
- uthash_free((head)->hh.tbl->buckets, \
- (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \
- uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
- (head) = NULL; \
- } \
-} while (0)
-
-#define HASH_OVERHEAD(hh,head) \
- (((head) != NULL) ? ( \
- (size_t)(((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \
- ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \
- sizeof(UT_hash_table) + \
- (HASH_BLOOM_BYTELEN))) : 0U)
-
-#ifdef NO_DECLTYPE
-#define HASH_ITER(hh,head,el,tmp) \
-for(((el)=(head)), ((*(char**)(&(tmp)))=(char*)((head!=NULL)?(head)->hh.next:NULL)); \
- (el) != NULL; ((el)=(tmp)), ((*(char**)(&(tmp)))=(char*)((tmp!=NULL)?(tmp)->hh.next:NULL)))
-#else
-#define HASH_ITER(hh,head,el,tmp) \
-for(((el)=(head)), ((tmp)=DECLTYPE(el)((head!=NULL)?(head)->hh.next:NULL)); \
- (el) != NULL; ((el)=(tmp)), ((tmp)=DECLTYPE(el)((tmp!=NULL)?(tmp)->hh.next:NULL)))
-#endif
-
-/* obtain a count of items in the hash */
-#define HASH_COUNT(head) HASH_CNT(hh,head)
-#define HASH_CNT(hh,head) ((head != NULL)?((head)->hh.tbl->num_items):0U)
-
-typedef struct UT_hash_bucket {
- struct UT_hash_handle *hh_head;
- unsigned count;
-
- /* expand_mult is normally set to 0. In this situation, the max chain length
- * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If
- * the bucket's chain exceeds this length, bucket expansion is triggered).
- * However, setting expand_mult to a non-zero value delays bucket expansion
- * (that would be triggered by additions to this particular bucket)
- * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH.
- * (The multiplier is simply expand_mult+1). The whole idea of this
- * multiplier is to reduce bucket expansions, since they are expensive, in
- * situations where we know that a particular bucket tends to be overused.
- * It is better to let its chain length grow to a longer yet-still-bounded
- * value, than to do an O(n) bucket expansion too often.
- */
- unsigned expand_mult;
-
-} UT_hash_bucket;
-
-/* random signature used only to find hash tables in external analysis */
-#define HASH_SIGNATURE 0xa0111fe1u
-#define HASH_BLOOM_SIGNATURE 0xb12220f2u
-
-typedef struct UT_hash_table {
- UT_hash_bucket *buckets;
- unsigned num_buckets, log2_num_buckets;
- unsigned num_items;
- struct UT_hash_handle *tail; /* tail hh in app order, for fast append */
- ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */
-
- /* in an ideal situation (all buckets used equally), no bucket would have
- * more than ceil(#items/#buckets) items. that's the ideal chain length. */
- unsigned ideal_chain_maxlen;
-
- /* nonideal_items is the number of items in the hash whose chain position
- * exceeds the ideal chain maxlen. these items pay the penalty for an uneven
- * hash distribution; reaching them in a chain traversal takes >ideal steps */
- unsigned nonideal_items;
-
- /* ineffective expands occur when a bucket doubling was performed, but
- * afterward, more than half the items in the hash had nonideal chain
- * positions. If this happens on two consecutive expansions we inhibit any
- * further expansion, as it's not helping; this happens when the hash
- * function isn't a good fit for the key domain. When expansion is inhibited
- * the hash will still work, albeit no longer in constant time. */
- unsigned ineff_expands, noexpand;
-
- uint32_t signature; /* used only to find hash tables in external analysis */
-#ifdef HASH_BLOOM
- uint32_t bloom_sig; /* used only to test bloom exists in external analysis */
- uint8_t *bloom_bv;
- uint8_t bloom_nbits;
-#endif
-
-} UT_hash_table;
-
-typedef struct UT_hash_handle {
- struct UT_hash_table *tbl;
- void *prev; /* prev element in app order */
- void *next; /* next element in app order */
- struct UT_hash_handle *hh_prev; /* previous hh in bucket order */
- struct UT_hash_handle *hh_next; /* next hh in bucket order */
- const void *key; /* ptr to enclosing struct's key */
- unsigned keylen; /* enclosing struct's key len */
- unsigned hashv; /* result of hash-fcn(key) */
-} UT_hash_handle;
-
-#endif /* UTHASH_H */
diff --git a/ios/Tunnel/obfuscator/wg-obfuscator.c b/ios/Tunnel/obfuscator/wg-obfuscator.c
deleted file mode 100644
index 9470d38..0000000
--- a/ios/Tunnel/obfuscator/wg-obfuscator.c
+++ /dev/null
@@ -1,1320 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include "wg-obfuscator.h"
-#include "config.h"
-#include "obfuscation.h"
-#include "uthash.h"
-#include "masking.h"
-
-// Verbosity level
-int verbose = LL_DEFAULT;
-// Section name (for multiple instances)
-char section_name[256] = DEFAULT_INSTANCE_NAME;
-// Listening socket for receiving data from the clients
-static int listen_sock = 0;
-// Hash table for client connections
-static client_entry_t *conn_table = NULL;
-// PIDs of the other instances, filled by the parent process only
-static pid_t *child_pids = NULL;
-static int child_pids_count = 0;
-// Set by the SIGHUP handler, the log file is reopened from the main loop
-static volatile sig_atomic_t log_reopen_pending = 0;
-
-// Hostname re-resolve: the blocking getaddrinfo() runs in a helper thread
-#define RESOLVE_TAG_TARGET (-1)
-typedef struct {
- int32_t tag; // RESOLVE_TAG_TARGET or index into resolve_bindings
- int32_t err; // getaddrinfo() error, 0 on success
- uint32_t addr; // IPv4 address in network byte order
-} resolve_result_t;
-
-static int resolve_wake_rd = -1;
-static int resolve_wake_wr = -1;
-static int resolve_result_rd = -1;
-static int resolve_result_wr = -1;
-static char resolve_target_host[256];
-static int resolve_target_is_name = 0;
-static long resolve_interval_ms = 0;
-static client_entry_t **resolve_bindings = NULL;
-static int resolve_bindings_count = 0;
-
-#ifdef USE_EPOLL
- static int epfd = 0;
-#endif
-
-/**
- * @brief Handles incoming signals for the application.
- *
- * This function is registered as a signal handler and is invoked when the process
- * receives a signal. The specific actions taken depend on the signal received.
- *
- * @param signal The signal number received by the process.
- */
-static void signal_handler(int signal) {
- client_entry_t *current_entry, *tmp;
-
- // Close all connections and clean up
- if (listen_sock) {
- close(listen_sock);
- }
- HASH_ITER(hh, conn_table, current_entry, tmp) {
- if (current_entry->server_sock) {
- close(current_entry->server_sock);
- }
- HASH_DEL(conn_table, current_entry);
- free(current_entry);
- }
-#ifdef USE_EPOLL
- if (epfd) {
- close(epfd);
- }
-#endif
- log(LL_INFO, "Stopped.");
- exit(signal != -1 ? EXIT_SUCCESS : EXIT_FAILURE);
-}
-#define FAILURE() signal_handler(-1)
-
-/**
- * @brief Returns 1 if the string is a dotted IPv4 address, 0 otherwise.
- */
-static int is_ipv4_literal(const char *host)
-{
- struct in_addr tmp;
- return host && *host && inet_pton(AF_INET, host, &tmp) == 1;
-}
-
-/**
- * @brief Resolves a hostname to an IPv4 address.
- *
- * @param host Hostname or IPv4 literal.
- * @param out Filled with the first IPv4 address on success.
- * @return 0 on success, a getaddrinfo() error code otherwise.
- */
-static int resolve_hostname(const char *host, struct in_addr *out)
-{
- struct addrinfo hints = {
- .ai_family = AF_INET,
- .ai_socktype = SOCK_DGRAM,
- };
- struct addrinfo *addr = NULL;
- int err = getaddrinfo(host, NULL, &hints, &addr);
- if (err != 0 || addr == NULL) {
- if (addr) {
- freeaddrinfo(addr);
- }
- return err ? err : EAI_NONAME;
- }
- *out = ((struct sockaddr_in *)addr->ai_addr)->sin_addr;
- freeaddrinfo(addr);
- return 0;
-}
-
-/**
- * @brief Resolves a hostname at startup.
- *
- * On failure: if interval_ms is 0, returns the error immediately. Otherwise
- * retries every interval_ms until the name resolves, so the daemon can start
- * before the network or DNS is up. Sleep is interruptible by SIGINT/SIGTERM.
- *
- * @param host Hostname or IPv4 literal.
- * @param out Filled with the first IPv4 address on success.
- * @param interval_ms Retry interval in milliseconds, 0 to fail immediately.
- * @param what Short label for the log, e.g. "target" or "static binding".
- * @return 0 on success, a getaddrinfo() error code if interval_ms is 0 and resolve failed.
- */
-static int resolve_hostname_startup(const char *host, struct in_addr *out, long interval_ms, const char *what)
-{
- while (1) {
- int err = resolve_hostname(host, out);
- if (err == 0) {
- return 0;
- }
- if (interval_ms <= 0) {
- return err;
- }
- log(LL_WARN, "Can't resolve %s hostname '%s': %s, retrying in %ld seconds",
- what, host, gai_strerror(err), interval_ms / 1000);
- struct timespec ts = {
- .tv_sec = interval_ms / 1000,
- .tv_nsec = (interval_ms % 1000) * 1000000L,
- };
- while (nanosleep(&ts, &ts) < 0 && errno == EINTR) {
- }
- }
-}
-
-/**
- * @brief Sends one resolve result to the main thread. The write is at most
- * PIPE_BUF bytes, so it is atomic and cannot interleave with another result.
- */
-static void resolve_send_result(int32_t tag, int32_t err, uint32_t addr)
-{
- resolve_result_t r = { .tag = tag, .err = err, .addr = addr };
- const char *p = (const char *)&r;
- size_t left = sizeof(r);
- while (left) {
- ssize_t n = write(resolve_result_wr, p, left);
- if (n < 0) {
- if (errno == EINTR) {
- continue;
- }
- return;
- }
- p += n;
- left -= (size_t)n;
- }
-}
-
-static void resolve_one(int32_t tag, const char *host)
-{
- struct in_addr addr;
- int err = resolve_hostname(host, &addr);
- resolve_send_result(tag, err, err ? 0 : addr.s_addr);
-}
-
-/**
- * @brief Resolver thread: waits for SIGHUP (wake pipe) or the refresh interval,
- * then re-resolves every non-literal hostname. Never calls log().
- */
-static void *resolve_thread_fn(void *arg)
-{
- (void)arg;
- struct pollfd pfd = { .fd = resolve_wake_rd, .events = POLLIN };
- while (1) {
- int timeout = resolve_interval_ms > 0 ? (int)resolve_interval_ms : -1;
- int ret = poll(&pfd, 1, timeout);
- if (ret < 0) {
- if (errno == EINTR) {
- continue;
- }
- continue;
- }
- if (ret > 0 && (pfd.revents & POLLIN)) {
- char buf[64];
- while (read(resolve_wake_rd, buf, sizeof(buf)) > 0) {
- }
- }
- if (resolve_target_is_name) {
- resolve_one(RESOLVE_TAG_TARGET, resolve_target_host);
- }
- for (int i = 0; i < resolve_bindings_count; i++) {
- if (resolve_bindings[i] && resolve_bindings[i]->bind_host[0]) {
- resolve_one(i, resolve_bindings[i]->bind_host);
- }
- }
- }
- return NULL;
-}
-
-/**
- * @brief Wakes the resolver thread. Safe to call from a signal handler.
- */
-static void resolve_wake(void)
-{
- char c = 1;
- if (resolve_wake_wr < 0) {
- return;
- }
- if (write(resolve_wake_wr, &c, 1) < 0 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) {
- // Nothing useful can be done from a signal handler
- }
-}
-
-/**
- * @brief Applies one re-resolve result on the main thread.
- */
-static void apply_resolve_result(const resolve_result_t *r, struct sockaddr_in *forward_addr)
-{
- if (r->err != 0) {
- const char *name = "?";
- if (r->tag == RESOLVE_TAG_TARGET) {
- name = resolve_target_host;
- } else if (r->tag >= 0 && r->tag < resolve_bindings_count && resolve_bindings[r->tag]) {
- name = resolve_bindings[r->tag]->bind_host;
- }
- log(LL_WARN, "Can't re-resolve hostname '%s': %s", name, gai_strerror(r->err));
- return;
- }
-
- if (r->tag == RESOLVE_TAG_TARGET) {
- if (forward_addr->sin_addr.s_addr == r->addr) {
- return;
- }
- char old_ip[INET_ADDRSTRLEN], new_ip[INET_ADDRSTRLEN];
- inet_ntop(AF_INET, &forward_addr->sin_addr, old_ip, sizeof(old_ip));
- forward_addr->sin_addr.s_addr = r->addr;
- inet_ntop(AF_INET, &forward_addr->sin_addr, new_ip, sizeof(new_ip));
- log(LL_INFO, "Target address changed: %s -> %s", old_ip, new_ip);
-
- client_entry_t *e, *tmp;
- HASH_ITER(hh, conn_table, e, tmp) {
- if (connect(e->server_sock, (struct sockaddr *)forward_addr, sizeof(*forward_addr)) < 0) {
- serror_level(LL_WARN, "Failed to update target address for client %s:%d",
- inet_ntoa(e->client_addr.sin_addr), ntohs(e->client_addr.sin_port));
- }
- }
- return;
- }
-
- if (r->tag < 0 || r->tag >= resolve_bindings_count) {
- return;
- }
- client_entry_t *entry = resolve_bindings[r->tag];
- if (!entry || !entry->is_static) {
- return;
- }
- if (entry->client_addr.sin_addr.s_addr == r->addr) {
- return;
- }
-
- struct sockaddr_in new_addr = entry->client_addr;
- new_addr.sin_addr.s_addr = r->addr;
-
- client_entry_t *collision = NULL;
- HASH_FIND(hh, conn_table, &new_addr, sizeof(new_addr), collision);
- if (collision && collision != entry) {
- log(LL_WARN, "Static binding '%s' re-resolved to %s:%d, but that address is already in use",
- entry->bind_host, inet_ntoa(new_addr.sin_addr), ntohs(new_addr.sin_port));
- return;
- }
-
- char old_ip[INET_ADDRSTRLEN], new_ip[INET_ADDRSTRLEN];
- inet_ntop(AF_INET, &entry->client_addr.sin_addr, old_ip, sizeof(old_ip));
- inet_ntop(AF_INET, &new_addr.sin_addr, new_ip, sizeof(new_ip));
-
- HASH_DEL(conn_table, entry);
- entry->client_addr.sin_addr.s_addr = r->addr;
- HASH_ADD(hh, conn_table, client_addr, sizeof(entry->client_addr), entry);
- log(LL_INFO, "Static binding '%s' address changed: %s -> %s", entry->bind_host, old_ip, new_ip);
-}
-
-/**
- * @brief Reads every queued re-resolve result. Each write is atomic, so one
- * read of sizeof(resolve_result_t) is one message.
- */
-static void drain_resolve_results(struct sockaddr_in *forward_addr)
-{
- resolve_result_t r;
- while (1) {
- ssize_t n = read(resolve_result_rd, &r, sizeof(r));
- if (n < 0) {
- if (errno == EINTR) {
- continue;
- }
- if (errno == EAGAIN || errno == EWOULDBLOCK) {
- break;
- }
- serror_level(LL_WARN, "Failed to read hostname re-resolve result");
- break;
- }
- if (n == 0) {
- break;
- }
- if (n != (ssize_t)sizeof(r)) {
- log(LL_WARN, "Short read from hostname resolver (%zd bytes)", n);
- break;
- }
- apply_resolve_result(&r, forward_addr);
- }
-}
-
-/**
- * @brief Starts the resolver thread if there is at least one hostname to refresh.
- */
-static void resolve_start_thread(void)
-{
- int wake[2], result[2];
- pthread_t thread;
-
- if (!resolve_target_is_name && resolve_bindings_count == 0) {
- return;
- }
-
- if (pipe(wake) < 0 || pipe(result) < 0) {
- log(LL_WARN, "Can't create pipes for hostname re-resolve, periodic refresh disabled");
- return;
- }
- resolve_wake_rd = wake[0];
- resolve_wake_wr = wake[1];
- resolve_result_rd = result[0];
- resolve_result_wr = result[1];
-
- fcntl(resolve_wake_rd, F_SETFL, O_NONBLOCK);
- fcntl(resolve_wake_wr, F_SETFL, O_NONBLOCK);
- fcntl(resolve_result_rd, F_SETFL, O_NONBLOCK);
-
- if (pthread_create(&thread, NULL, resolve_thread_fn, NULL) != 0) {
- log(LL_WARN, "Can't start hostname resolver thread, periodic refresh disabled");
- close(resolve_wake_rd);
- close(resolve_wake_wr);
- close(resolve_result_rd);
- close(resolve_result_wr);
- resolve_wake_rd = resolve_wake_wr = resolve_result_rd = resolve_result_wr = -1;
- return;
- }
- pthread_detach(thread);
-
- if (resolve_interval_ms > 0) {
- log(LL_INFO, "Re-resolving hostnames every %ld seconds (and on SIGHUP)", resolve_interval_ms / 1000);
- } else {
- log(LL_INFO, "Re-resolving hostnames on SIGHUP");
- }
-}
-
-/**
- * @brief Remembers the PID of a forked instance.
- *
- * Called by the configuration parser for every additional section, so that the
- * parent process can forward signals to all the instances.
- *
- * @param pid PID of the forked instance.
- */
-void register_child_instance(pid_t pid)
-{
- pid_t *new_pids = realloc(child_pids, (child_pids_count + 1) * sizeof(pid_t));
- if (!new_pids) {
- log(LL_WARN, "Out of memory, instance with PID %ld will not receive forwarded signals", (long)pid);
- return;
- }
- child_pids = new_pids;
- child_pids[child_pids_count++] = pid;
-}
-
-#ifdef SIGHUP
-/**
- * @brief Handles SIGHUP: schedules reopening of the log file.
- *
- * The actual reopening is done by the main loop, the handler only sets a flag
- * and forwards the signal to the instances of the other configuration sections.
- *
- * @param sig Signal number received by the process.
- */
-static void sighup_handler(int sig)
-{
- (void)sig;
- log_reopen_pending = 1;
- resolve_wake();
- // The list is filled before the handler is installed, so it can't change here
- for (int i = 0; i < child_pids_count; i++) {
- kill(child_pids[i], SIGHUP);
- }
-}
-#endif
-
-/**
- * @brief Creates a new client_entry_t structure and initializes it with the provided client and forward addresses.
- *
- * @param config Pointer to the obfuscator configuration structure.
- * @param client_addr Pointer to a struct sockaddr_in representing the client's address.
- * @param forward_addr Pointer to a struct sockaddr_in representing the address to which traffic should be forwarded.
- * @return Pointer to the newly created client_entry_t structure, or NULL on failure.
- */
-static client_entry_t * new_client_entry(obfuscator_config_t *config, struct sockaddr_in *client_addr, struct sockaddr_in *forward_addr) {
- if (HASH_COUNT(conn_table) >= config->max_clients) {
- log(LL_ERROR, "Maximum number of clients reached (%d), cannot add new client", config->max_clients);
- return NULL;
- }
- client_entry_t * client_entry = malloc(sizeof(client_entry_t));
- if (!client_entry) {
- log(LL_ERROR, "Failed to allocate memory for client entry");
- return NULL;
- }
- memset(client_entry, 0, sizeof(client_entry_t));
- // Set default version (latest)
- client_entry->version = OBFUSCATION_VERSION;
- // Set the client address
- memcpy(&client_entry->client_addr, client_addr, sizeof(client_entry->client_addr));
- // Create a socket for the server connection
- client_entry->server_sock = socket(AF_INET, SOCK_DGRAM, 0);
- // TODO: add client address to log
- if (client_entry->server_sock < 0) {
- serror("Failed to create server socket for client");
- free(client_entry);
- return NULL;
- }
-#ifdef __linux__
- // Set "Don't Fragment" flag
- int optval = 1;
- if (setsockopt(client_entry->server_sock, IPPROTO_IP, IP_MTU_DISCOVER, &optval, sizeof(optval)) < 0) {
- serror("Failed to set 'don't fragment' flag for client");
- close(client_entry->server_sock);
- free(client_entry);
- return NULL;
- }
- if (config->fwmark) {
- if (setsockopt(client_entry->server_sock, SOL_SOCKET, SO_MARK, &config->fwmark, sizeof(config->fwmark)) < 0) {
- log(LL_WARN, "Failed to set 'firewall mark' for client: %s", strerror(errno));
- }
- }
-#endif
- // Set the server address to the specified one
- connect(client_entry->server_sock, (struct sockaddr *)forward_addr, sizeof(*forward_addr));
- // Get the assigned port number
- socklen_t our_addr_len = sizeof(client_entry->our_addr);
- if (getsockname(client_entry->server_sock, (struct sockaddr *)&client_entry->our_addr, &our_addr_len) == -1) {
- serror("Failed to get socket port number");
- close(client_entry->server_sock);
- free(client_entry);
- return NULL;
- }
-
-#ifdef USE_EPOLL
- struct epoll_event e = {
- .events = EPOLLIN,
- .data.ptr = client_entry
- };
- if (epoll_ctl(epfd, EPOLL_CTL_ADD, client_entry->server_sock, &e) != 0) {
- serror("epoll_ctl for client socket");
- close(client_entry->server_sock);
- free(client_entry);
- return NULL;
- }
-#endif
-
- HASH_ADD(hh, conn_table, client_addr, sizeof(*client_addr), client_entry);
-
- log(LL_DEBUG, "Added binding: %s:%d:%d",
- inet_ntoa(client_entry->client_addr.sin_addr), ntohs(client_entry->client_addr.sin_port),
- ntohs(client_entry->our_addr.sin_port));
-
- return client_entry;
-}
-
-/**
- * @brief Creates a new static client entry.
- *
- * This function allocates and initializes a new client_entry_t structure
- * using the provided client and forward addresses, as well as the specified local port.
- *
- * @param config Pointer to the obfuscator configuration structure.
- * @param client_addr Pointer to a sockaddr_in structure representing the client's address.
- * @param forward_addr Pointer to a sockaddr_in structure representing the address to forward to.
- * @param local_port The local port number to connect to the server.
- * @param bind_host Original hostname from the configuration, stored if it is not an IPv4 literal.
- * @return Pointer to the newly created client_entry_t structure, or NULL on failure.
- */
-static client_entry_t * new_client_entry_static(obfuscator_config_t *config, struct sockaddr_in *client_addr, struct sockaddr_in *forward_addr, uint16_t local_port, const char *bind_host) {
- if (HASH_COUNT(conn_table) >= config->max_clients) {
- log(LL_ERROR, "Maximum number of clients reached (%d), cannot add new client", config->max_clients);
- return NULL;
- }
-
- // Check if such client already exists
- client_entry_t *existing_entry;
- HASH_FIND(hh, conn_table, client_addr, sizeof(*client_addr), existing_entry);
- if (existing_entry) {
- log(LL_ERROR, "Binding with client %s:%d already exists",
- inet_ntoa(client_addr->sin_addr), ntohs(client_addr->sin_port));
- return NULL;
- }
-
- client_entry_t * client_entry = malloc(sizeof(client_entry_t));
- if (!client_entry) {
- log(LL_ERROR, "Failed to allocate memory for client entry");
- return NULL;
- }
- memset(client_entry, 0, sizeof(client_entry_t));
- // Set default version (latest)
- client_entry->version = OBFUSCATION_VERSION;
- // default masking type
- client_entry->masking_handler = config->masking_handler;
- // Set the client address
- memcpy(&client_entry->client_addr, client_addr, sizeof(client_entry->client_addr));
- // Create a socket for the server connection
- client_entry->server_sock = socket(AF_INET, SOCK_DGRAM, 0);
- if (client_entry->server_sock < 0) {
- serror("Failed to create server socket for client");
- free(client_entry);
- return NULL;
- }
- // Bind the socket to the specified local port
- client_entry->our_addr.sin_family = AF_INET;
- // TODO: ability to bind to a specific address
- client_entry->our_addr.sin_addr.s_addr = INADDR_ANY;
- client_entry->our_addr.sin_port = htons(local_port);
- // Set the local port number
- if (bind(client_entry->server_sock, (struct sockaddr *)&client_entry->our_addr, sizeof(client_entry->our_addr)) < 0) {
- serror("Failed to bind server socket to %s:%d",
- inet_ntoa(client_entry->our_addr.sin_addr), local_port);
- close(client_entry->server_sock);
- free(client_entry);
- return NULL;
- }
-#ifdef __linux__
- // Set "Don't Fragment" flag
- int optval = 1;
- if (setsockopt(client_entry->server_sock, IPPROTO_IP, IP_MTU_DISCOVER, &optval, sizeof(optval)) < 0) {
- serror("Failed to set 'don't fragment' flag for client %s:%d",
- inet_ntoa(client_entry->client_addr.sin_addr), local_port);
- close(client_entry->server_sock);
- free(client_entry);
- return NULL;
- }
- if (config->fwmark) {
- if (setsockopt(client_entry->server_sock, SOL_SOCKET, SO_MARK, &config->fwmark, sizeof(config->fwmark)) < 0) {
- log(LL_WARN, "Failed to set 'firewall mark' for client %s:%d: %s",
- inet_ntoa(client_entry->client_addr.sin_addr), ntohs(client_entry->client_addr.sin_port), strerror(errno));
- }
- }
-
-#endif
- // Set the server address to the specified one
- connect(client_entry->server_sock, (struct sockaddr *)forward_addr, sizeof(*forward_addr));
-
-#ifdef USE_EPOLL
- struct epoll_event e = {
- .events = EPOLLIN,
- .data.ptr = client_entry
- };
- if (epoll_ctl(epfd, EPOLL_CTL_ADD, client_entry->server_sock, &e) != 0) {
- serror("epoll_ctl for client socket");
- close(client_entry->server_sock);
- free(client_entry);
- return NULL;
- }
-#endif
-
- client_entry->is_static = 1;
- if (bind_host && !is_ipv4_literal(bind_host)) {
- strncpy(client_entry->bind_host, bind_host, sizeof(client_entry->bind_host) - 1);
- }
-
- HASH_ADD(hh, conn_table, client_addr, sizeof(*client_addr), client_entry);
-
- return client_entry;
-}
-
-#ifndef USE_EPOLL
-static client_entry_t *find_by_server_sock(int fd) {
- client_entry_t *e, *tmp;
- HASH_ITER(hh, conn_table, e, tmp) {
- if (e->server_sock == fd) return e;
- }
- return NULL;
-}
-#endif
-
-/**
- * @brief Prints the version information of the program.
- *
- * This function outputs the current version of the application to the standard output.
- * Typically used to inform users about the build or release version.
- */
-const char *version_string(void) {
-#ifdef COMMIT
-#ifndef ARCH
- return "WireGuard Obfuscator (commit " COMMIT " @ " WG_OBFUSCATOR_GIT_REPO ")";
-#else
- return "WireGuard Obfuscator (commit " COMMIT " @ " WG_OBFUSCATOR_GIT_REPO ") (" ARCH ")";
-#endif
-#else
-#ifndef ARCH
- return "WireGuard Obfuscator v" WG_OBFUSCATOR_VERSION;
-#else
- return "WireGuard Obfuscator v" WG_OBFUSCATOR_VERSION " (" ARCH ")";
-#endif
-#endif
-}
-
-void print_version(void) {
- fprintf(stderr, "Starting %s\n", version_string());
-}
-
-int main(int argc, char *argv[]) {
- obfuscator_config_t config = {0};
- struct sockaddr_in
- listen_addr, // Address for listening socket, for receiving data from the client
- forward_addr; // Address for forwarding socket, for sending data to the server
- uint8_t full_buffer[BUFFER_SIZE + PREBUFFER_SIZE];
- char target_host[256] = {0};
- int target_port = -1;
- int key_length = 0;
- in_addr_t s_listen_addr_client = INADDR_ANY;
- long now, last_cleanup_time = 0;
- struct addrinfo *addr;
- int err;
- struct addrinfo hints = { // for getaddrinfo
- .ai_family = AF_INET, // IPv4
- .ai_socktype = SOCK_DGRAM, // UDP
- };
-
- print_version();
-
- if (parse_config(argc, argv, &config) != 0) {
- exit(EXIT_FAILURE);
- }
-
- /* Start writing to the log file before validating the rest of the parameters,
- so that configuration errors are logged there too */
- log_init(config.log_file_set ? config.log_file : NULL, config.log_timestamps);
-
-#ifdef USE_EPOLL
- struct epoll_event events[MAX_EVENTS];
-#else
- struct pollfd pollfds[config.max_clients + 2];
-#endif
-
- /* Check the parameters */
- // Check the listening port
- if (!config.listen_port_set) {
- log(LL_ERROR, "'source-lport' is not set in the configuration file");
- exit(EXIT_FAILURE);
- }
-
- // Check the key
- key_length = strlen(config.xor_key);
- if (!config.xor_key_set || key_length == 0) {
- log(LL_ERROR, "'key' is not set in the configuration file");
- exit(EXIT_FAILURE);
- }
-
- // Check the target host and port
- if (!config.forward_host_port_set) {
- log(LL_ERROR, "'target' is not set");
- exit(EXIT_FAILURE);
- } else {
- char *port_delimiter = strchr(config.forward_host_port, ':');
- if (port_delimiter == NULL) {
- log(LL_ERROR, "Invalid target host:port format: %s", config.forward_host_port);
- exit(EXIT_FAILURE);
- }
- *port_delimiter = 0;
- strncpy(target_host, config.forward_host_port, sizeof(target_host) - 1);
- target_host[sizeof(target_host) - 1] = 0; // Ensure null-termination
- target_port = atoi(port_delimiter + 1);
- if (target_port <= 0) {
- log(LL_ERROR, "Invalid target port: %s", port_delimiter + 1);
- exit(EXIT_FAILURE);
- }
- }
-
- // 'allow-clean' is incompatible with static bindings: for a static binding
- // there is no way to know in advance whether the client's traffic must be obfuscated
- if (config.allow_clean && config.static_bindings_set) {
- log(LL_ERROR, "'allow-clean' cannot be used together with 'static-bindings'");
- exit(EXIT_FAILURE);
- }
-
- // Check the client interface
- if (config.client_interface_set) {
- s_listen_addr_client = inet_addr(config.client_interface);
- if (s_listen_addr_client == INADDR_NONE) {
- err = getaddrinfo(config.client_interface, NULL, &hints, &addr);
- if (err != 0 || addr == NULL) {
- log(LL_ERROR, "Invalid source interface '%s': %s", config.client_interface, gai_strerror(err));
- exit(EXIT_FAILURE);
- }
- s_listen_addr_client = ((struct sockaddr_in *)addr->ai_addr)->sin_addr.s_addr;
- freeaddrinfo(addr);
- }
- }
-
- /* Set up signal handlers */
- signal(SIGINT, signal_handler);
- signal(SIGTERM, signal_handler);
-#ifdef SIGHUP
- signal(SIGHUP, sighup_handler);
-#endif
-
- /* Create listening socket */
- if ((listen_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- serror("Can't create source socket to listen");
- exit(EXIT_FAILURE);
- }
-
-#ifdef __linux__
- /* Set "Don't Fragment" flag */
- int optval = 1;
- if (setsockopt(listen_sock, IPPROTO_IP, IP_MTU_DISCOVER, &optval, sizeof(optval)) < 0) {
- serror("Failed to set 'don't fragment' flag for listening socket");
- FAILURE();
- }
- if (config.fwmark) {
- if (setsockopt(listen_sock, SOL_SOCKET, SO_MARK, &config.fwmark, sizeof(config.fwmark)) < 0) {
- log(LL_WARN, "Failed to set 'firewall mark' for listening socket: %s", strerror(errno));
- }
- }
-#endif
-
- /* Bind the listening socket to the specified address and port */
- memset(&listen_addr, 0, sizeof(listen_addr));
- listen_addr.sin_family = AF_INET;
- listen_addr.sin_addr.s_addr = s_listen_addr_client;
- listen_addr.sin_port = htons(config.listen_port);
- if (bind(listen_sock, (struct sockaddr *)&listen_addr, sizeof(listen_addr)) < 0) {
- serror("Failed to bind source socket to %s:%d",
- inet_ntoa(listen_addr.sin_addr), ntohs(listen_addr.sin_port));
- FAILURE();
- }
- log(LL_INFO, "Listening on port %s:%d for source", inet_ntoa(listen_addr.sin_addr), ntohs(listen_addr.sin_port));
-
- if (config.masking_handler_set) {
- log(LL_INFO, "Using masking type: %s", config.masking_handler ? config.masking_handler->name : "none");
- }
-
- if (config.allow_clean) {
- log(LL_INFO, "Non-obfuscated (clean) clients are allowed, their traffic will be forwarded as is");
- }
-
- /* Use epoll for events if enabled */
-#ifdef USE_EPOLL
- epfd = epoll_create1(0);
- if (epfd < 0) {
- serror("epoll_create1");
- FAILURE();
- }
- {
- struct epoll_event ev = {
- .events = EPOLLIN,
- .data.fd = listen_sock
- };
- if (epoll_ctl(epfd, EPOLL_CTL_ADD, listen_sock, &ev) != 0) {
- serror("epoll_ctl for listen_sock");
- FAILURE();
- }
- }
-#endif
-
- /* Set up forward address */
- memset(&forward_addr, 0, sizeof(forward_addr));
- forward_addr.sin_family = AF_INET;
- resolve_interval_ms = config.resolve_interval;
- err = resolve_hostname_startup(target_host, &forward_addr.sin_addr, resolve_interval_ms, "target");
- if (err != 0) {
- log(LL_ERROR, "Can't resolve hostname '%s': %s", target_host, gai_strerror(err));
- FAILURE();
- }
- log(LL_DEBUG, "Resolved target hostname '%s' to %s", target_host, inet_ntoa(forward_addr.sin_addr));
- if (target_port > 65535) {
- log(LL_ERROR, "Invalid target port: %d", target_port);
- FAILURE();
- }
- forward_addr.sin_port = htons(target_port);
- log(LL_INFO, "Target: %s:%d", target_host, target_port);
- strncpy(resolve_target_host, target_host, sizeof(resolve_target_host) - 1);
- resolve_target_is_name = !is_ipv4_literal(target_host);
-
- /* Add static bindings if provided */
- if (config.static_bindings) {
- // Parse static bindings
- char *binding = strtok(config.static_bindings, ",");
- while (binding) {
- // Trim leading and trailing spaces
- binding = trim(binding);
- char *colon1 = strchr(binding, ':');
- if (!colon1) {
- log(LL_ERROR, "Invalid static binding format: %s", binding);
- exit(EXIT_FAILURE);
- }
- char *colon2 = strchr(colon1 + 1, ':');
- if (!colon2) {
- log(LL_ERROR, "Invalid static binding format: %s", binding);
- exit(EXIT_FAILURE);
- }
- *colon1 = 0;
- *colon2 = 0;
-
- struct sockaddr_in client_addr = {0};
- client_addr.sin_family = AF_INET;
- err = resolve_hostname_startup(binding, &client_addr.sin_addr, resolve_interval_ms, "static binding");
- if (err != 0) {
- log(LL_ERROR, "Can't resolve hostname '%s' for static binding '%s:%s:%s': %s",
- binding, binding, colon1 + 1, colon2 + 1, gai_strerror(err));
- FAILURE();
- }
- log(LL_DEBUG, "Resolved static binding hostname '%s' to %s", binding, inet_ntoa(client_addr.sin_addr));
- int remote_port = atoi(colon1 + 1);
- if (remote_port <= 0 || remote_port > 65535) {
- log(LL_ERROR, "Invalid port '%s' for static binding '%s:%s:%s'",
- colon1 + 1, binding, colon1 + 1, colon2 + 1);
- FAILURE();
- }
- int local_port = atoi(colon2 + 1);
- if (local_port <= 0 || local_port > 65535) {
- log(LL_ERROR, "Invalid port '%s' for static binding '%s:%s:%s'",
- colon2 + 1, binding, colon1 + 1, colon2 + 1);
- FAILURE();
- }
- client_addr.sin_port = htons(remote_port);
-
- if (!new_client_entry_static(&config, &client_addr, &forward_addr, local_port, binding)) {
- log(LL_ERROR, "Failed to create static binding: %s:%s:%s",
- binding, colon1 + 1, colon2 + 1);
- FAILURE();
- }
-
- log(LL_INFO, "Added static binding: %s:%d <-> %d:obfuscator:%d <-> %s:%d",
- binding, remote_port, config.listen_port,
- local_port, target_host, target_port);
-
- binding = strtok(NULL, ",");
- }
- free(config.static_bindings);
- config.static_bindings = NULL;
- }
-
- {
- client_entry_t *e, *tmp;
- int n = 0;
- HASH_ITER(hh, conn_table, e, tmp) {
- if (e->is_static && e->bind_host[0]) {
- n++;
- }
- }
- if (n > 0) {
- resolve_bindings = calloc((size_t)n, sizeof(*resolve_bindings));
- if (!resolve_bindings) {
- log(LL_WARN, "Out of memory, static binding hostnames will not be re-resolved");
- } else {
- HASH_ITER(hh, conn_table, e, tmp) {
- if (e->is_static && e->bind_host[0]) {
- resolve_bindings[resolve_bindings_count++] = e;
- }
- }
- }
- }
- resolve_start_thread();
-#ifdef USE_EPOLL
- if (resolve_result_rd >= 0) {
- struct epoll_event ev = {
- .events = EPOLLIN,
- .data.fd = resolve_result_rd
- };
- if (epoll_ctl(epfd, EPOLL_CTL_ADD, resolve_result_rd, &ev) != 0) {
- serror("epoll_ctl for hostname resolver");
- FAILURE();
- }
- }
-#endif
- }
-
- log(LL_INFO, "WireGuard obfuscator successfully started");
-
- /* Main loop */
- while (1) {
- // Reopen the log file after it has been rotated, requested by SIGHUP
- if (log_reopen_pending) {
- log_reopen_pending = 0;
- log_reopen();
- }
-
- // Using epoll or poll to wait for events
-#ifdef USE_EPOLL
- int events_n = epoll_wait(epfd, events, MAX_EVENTS, POLL_TIMEOUT);
- if (events_n < 0) {
- if (errno == EINTR) {
- // Interrupted by a signal, e.g. SIGHUP
- continue;
- }
- serror("epoll_wait");
- FAILURE();
- }
-#else
- int nfds = 0;
- pollfds[nfds].fd = listen_sock;
- pollfds[nfds].events = POLLIN;
- nfds++;
- if (resolve_result_rd >= 0) {
- pollfds[nfds].fd = resolve_result_rd;
- pollfds[nfds].events = POLLIN;
- nfds++;
- }
- client_entry_t *entry, *tmp_entry;
- HASH_ITER(hh, conn_table, entry, tmp_entry) {
- if (nfds >= config.max_clients + 2) {
- log(LL_DEBUG, "Too many clients, cannot add more");
- break;
- }
- pollfds[nfds].fd = entry->server_sock;
- pollfds[nfds].events = POLLIN;
- nfds++;
- }
- int ret = poll(pollfds, nfds, POLL_TIMEOUT);
- if (ret < 0) {
- if (errno == EINTR) {
- // Interrupted by a signal, e.g. SIGHUP
- continue;
- }
- serror("poll");
- FAILURE();
- }
-#endif
-
- // Get the current time
- struct timespec now_ts;
- clock_gettime(CLOCK_MONOTONIC, &now_ts);
- now = now_ts.tv_sec * 1000 + now_ts.tv_nsec / 1000000;
-
-#ifdef USE_EPOLL
- for (int e = 0; e < events_n; e++) {
- struct epoll_event *event = &events[e];
- if (resolve_result_rd >= 0 && event->data.fd == resolve_result_rd) {
- drain_resolve_results(&forward_addr);
- continue;
- }
- if (event->data.fd == listen_sock) {
-#else
- for (int e = 0; e < nfds; e++) if (pollfds[e].revents & POLLIN) {
- if (resolve_result_rd >= 0 && pollfds[e].fd == resolve_result_rd) {
- drain_resolve_results(&forward_addr);
- continue;
- }
- if (pollfds[e].fd == listen_sock) {
-#endif
- /* *** Handle incoming data from the clients *** */
- uint8_t *buffer = full_buffer + PREBUFFER_SIZE;
- struct sockaddr_in sender_addr = {0};
- socklen_t sender_addr_len = sizeof(sender_addr);
- int length = recvfrom(listen_sock, buffer, BUFFER_SIZE, MSG_TRUNC | MSG_DONTWAIT, (struct sockaddr *)&sender_addr, &sender_addr_len);
- if (length < 0) {
- // A readiness notification does not guarantee that there is something
- // to read by the time we get here, so an empty socket is not an error
- if (errno != EAGAIN && errno != EWOULDBLOCK) {
- serror_level(LL_DEBUG, "recvfrom client");
- }
- continue;
- }
- if (length > BUFFER_SIZE) {
- log(LL_DEBUG, "Received packet from %s:%d is too large (%d bytes), while buffer size is %d bytes, ignoring",
- inet_ntoa(sender_addr.sin_addr), ntohs(sender_addr.sin_port), length, BUFFER_SIZE);
- continue;
- }
-
- // Find the client entry if any
- client_entry_t *client_entry;
- HASH_FIND(hh, conn_table, &sender_addr, sizeof(sender_addr), client_entry);
-
- uint8_t obfuscated = length >= 4 && is_obfuscated(buffer);
- // Is it masked packet maybe?
- masking_handler_t *masking_handler = config.masking_handler;
- if (obfuscated) {
- length = masking_unwrap_from_client(&buffer, length, &config, client_entry, listen_sock, &sender_addr, &forward_addr, &masking_handler);
- if (length <= 0) {
- // Nothing to do
- continue;
- }
- }
- // Check the length
- if (length < 4) {
- log(LL_DEBUG, "Received too short packet from %s:%d (%d bytes), ignoring", inet_ntoa(sender_addr.sin_addr), ntohs(sender_addr.sin_port), length);
- continue;
- }
-
- uint8_t version = client_entry ? client_entry->version : OBFUSCATION_VERSION;
-
- if (verbose >= LL_TRACE) {
- log(LL_TRACE, "Received %d bytes from %s:%d to %s:%d (known=%s, obfuscated=%s)",
- length,
- inet_ntoa(sender_addr.sin_addr), ntohs(sender_addr.sin_port),
- target_host, target_port,
- client_entry ? "yes" : "no", obfuscated ? "yes" : "no");
- log_hexdump(LL_TRACE, obfuscated ? "X->: " : "O->: ", buffer, length);
- }
-
- if (obfuscated) {
- // decode
- int original_length = length;
- length = decode(buffer, length, config.xor_key, key_length, &version);
- if (length < 4 || length > original_length) {
- log(LL_DEBUG, "Failed to decode packet from %s:%d (original_length=%d, decoded_length=%d)",
- inet_ntoa(sender_addr.sin_addr), ntohs(sender_addr.sin_port), original_length, length);
- continue;
- }
- }
-
- // Is it handshake?
- if (WG_TYPE(buffer) == WG_TYPE_HANDSHAKE) {
- log(LL_DEBUG, "Received WireGuard handshake from %s:%d to %s:%d (%d bytes, obfuscated=%s)",
- inet_ntoa(sender_addr.sin_addr), ntohs(sender_addr.sin_port),
- target_host, target_port,
- length,
- obfuscated ? "yes" : "no");
-
- if (!client_entry) {
- client_entry = new_client_entry(&config, &sender_addr, &forward_addr);
- if (!client_entry) {
- continue;
- }
- client_entry->last_activity_time = now;
- client_entry->last_incoming_time = 0;
- client_entry->masking_handler = masking_handler;
- }
- if (config.allow_clean) {
- // Remember whether this client speaks plain WireGuard,
- // its traffic will be forwarded as is in both directions
- if (!obfuscated && !client_entry->client_clean) {
- log(LL_INFO, "Client %s:%d is not obfuscated, forwarding its traffic as is",
- inet_ntoa(sender_addr.sin_addr), ntohs(sender_addr.sin_port));
- }
- client_entry->client_clean = !obfuscated;
- if (client_entry->client_clean) {
- // No masking for clean clients
- client_entry->masking_handler = NULL;
- }
- }
- if (!obfuscated && !client_entry->client_clean) {
- masking_on_handshake_req_from_client(&config, client_entry, listen_sock, &sender_addr, &forward_addr);
- }
- client_entry->handshake_direction = DIR_CLIENT_TO_SERVER;
- client_entry->last_handshake_request_time = now;
- }
- // Is it handshake response?
- else if (WG_TYPE(buffer) == WG_TYPE_HANDSHAKE_RESP) {
- if (!client_entry) {
- log(LL_DEBUG, "Received WireGuard handshake response from %s:%d, but no connection entry found for this client",
- inet_ntoa(sender_addr.sin_addr), ntohs(sender_addr.sin_port));
- continue;
- }
-
- log(LL_DEBUG, "Received WireGuard handshake response from %s:%d to %s:%d (%d bytes, obfuscated=%s)",
- inet_ntoa(client_entry->client_addr.sin_addr), ntohs(client_entry->client_addr.sin_port),
- target_host, target_port,
- length, obfuscated ? "yes" : "no");
-
- // Check handshake timeout
- if (now - client_entry->last_handshake_request_time > HANDSHAKE_TIMEOUT) {
- log(LL_DEBUG, "Ignoring WireGuard handshake response, handshake timeout");
- continue;
- }
-
- if (client_entry->handshake_direction != DIR_SERVER_TO_CLIENT) {
- log(LL_DEBUG, "Received handshake response from %s:%d to %s:%d, but the handshake direction is not set to server-to-client",
- inet_ntoa(sender_addr.sin_addr), ntohs(sender_addr.sin_port),
- target_host, target_port);
- continue;;
- }
-
- log(!client_entry->handshaked ? LL_INFO : LL_DEBUG, "Handshake established with %s:%d to %s:%d (reverse)",
- inet_ntoa(sender_addr.sin_addr), ntohs(sender_addr.sin_port),
- target_host, target_port);
- client_entry->handshaked = 1;
- client_entry->client_obfuscated = obfuscated;
- client_entry->server_obfuscated = !obfuscated;
- client_entry->last_handshake_time = now;
- }
- // If it's not a handshake or handshake response, connection is not established yet
- else if (!client_entry || !client_entry->handshaked) {
- log(LL_DEBUG, "Ignoring data (packet type #%u) from %s:%d to %s:%d until the handshake is completed",
- WG_TYPE(buffer),
- inet_ntoa(sender_addr.sin_addr), ntohs(sender_addr.sin_port),
- target_host, target_port);
- continue;
- }
-
- // Version downgrade check
- if (version < client_entry->version) {
- log(LL_WARN, "Client %s:%d uses old obfuscation version, downgrading from %d to %d", inet_ntoa(sender_addr.sin_addr), ntohs(sender_addr.sin_port),
- client_entry->version, version);
- client_entry->version = version;
- }
-
- if (!obfuscated && !client_entry->client_clean) {
- // If the packet is not obfuscated, we need to encode it
- length = encode(buffer, length, config.xor_key, key_length, client_entry->version, config.max_dummy_length_data);
- if (length < 4) {
- log(LL_ERROR, "Failed to encode packet from %s:%d (too short, length=%d)",
- inet_ntoa(sender_addr.sin_addr), ntohs(sender_addr.sin_port), length);
- continue;
- }
- length = masking_data_wrap_to_server(&buffer, length, &config, client_entry, listen_sock, &forward_addr);
- }
-
- log_hexdump(LL_TRACE, (!obfuscated && !client_entry->client_clean) ? "X->: " : "O->: ", buffer, length);
-
- length = send(client_entry->server_sock, buffer, length, 0);
- if (length < 0) {
- serror_level(LL_DEBUG, "sendto %s:%d", target_host, target_port);
- continue;
- }
- client_entry->last_activity_time = now;
- } else { // if (event->data.fd == listen_sock)
- /* *** Handle data from the server *** */
-#ifdef USE_EPOLL
- client_entry_t *client_entry = event->data.ptr;
-#else
- client_entry_t *client_entry = find_by_server_sock(pollfds[e].fd);
-#endif
- uint8_t *buffer = full_buffer + PREBUFFER_SIZE;
- int length = recv(client_entry->server_sock, buffer, BUFFER_SIZE, MSG_TRUNC | MSG_DONTWAIT);
- if (length < 0) {
- if (errno != EAGAIN && errno != EWOULDBLOCK) {
- serror_level(LL_DEBUG, "recv from server");
- }
- continue;
- }
- if (length > BUFFER_SIZE) {
- log(LL_DEBUG, "Received packet from %s:%d is too large (%d bytes), while buffer size is %d bytes, ignoring",
- target_host, target_port, length, BUFFER_SIZE);
- continue;
- }
- uint8_t obfuscated = length >= 4 && is_obfuscated(buffer);
- if (obfuscated) {
- // Is it masked packet maybe?
- length = masking_unwrap_from_server(&buffer, length, &config, client_entry, listen_sock, &forward_addr);
- if (length <= 0) {
- // Nothing to do
- continue;
- }
- }
- // Check the length
- if (length < 4) {
- log(LL_DEBUG, "Received too short packet from %s:%d (%d bytes), ignoring", target_host, target_port, length);
- continue;
- }
-
- uint8_t version = client_entry->version;
-
- if (verbose >= LL_TRACE) {
- log(LL_TRACE, "Received %d bytes from %s:%d to %s:%d (obfuscated=%s)",
- length,
- target_host, target_port,
- inet_ntoa(client_entry->client_addr.sin_addr), ntohs(client_entry->client_addr.sin_port),
- obfuscated ? "yes" : "no");
- log_hexdump(LL_TRACE, obfuscated ? "<-X: " : "<-O: ", buffer, length);
- }
-
- if (obfuscated) {
- // decode
- int original_length = length;
- length = decode(buffer, length, config.xor_key, key_length, &version);
- if (length < 4 || length > original_length) {
- log(LL_DEBUG, "Failed to decode packet from %s:%d (original_length=%d, decoded_length=%d)", target_host, target_port, original_length, length);
- continue;
- }
- }
-
- // Is it handshake?
- if (WG_TYPE(buffer) == WG_TYPE_HANDSHAKE) {
- log(LL_DEBUG, "Received WireGuard handshake from %s:%d to %s:%d (%d bytes, obfuscated=%s)",
- target_host, target_port,
- inet_ntoa(client_entry->client_addr.sin_addr), ntohs(client_entry->client_addr.sin_port),
- length,
- obfuscated ? "yes" : "no");
- if (!obfuscated && !client_entry->client_clean) {
- // Send STUN binding request before the obfuscated handshake
- masking_on_handshake_req_from_server(&config, client_entry, listen_sock, &client_entry->client_addr, &forward_addr);
- }
- client_entry->handshake_direction = DIR_SERVER_TO_CLIENT;
- client_entry->last_handshake_request_time = now;
- }
- // Is it handshake response?
- else if (WG_TYPE(buffer) == WG_TYPE_HANDSHAKE_RESP) {
- log(LL_DEBUG, "Received WireGuard handshake response from %s:%d to %s:%d (%d bytes, obfuscated=%s)",
- target_host, target_port,
- inet_ntoa(client_entry->client_addr.sin_addr), ntohs(client_entry->client_addr.sin_port),
- length, obfuscated ? "yes" : "no");
-
- // Check handshake timeout
- if (now - client_entry->last_handshake_request_time > HANDSHAKE_TIMEOUT) {
- log(LL_DEBUG, "Ignoring WireGuard handshake response, handshake timeout");
- continue;
- }
-
- if (client_entry->handshake_direction != DIR_CLIENT_TO_SERVER) {
- log(LL_DEBUG, "Received handshake response from %s:%d to %s:%d, but the handshake direction is not set to client-to-server",
- target_host, target_port,
- inet_ntoa(client_entry->client_addr.sin_addr), ntohs(client_entry->client_addr.sin_port));
- continue;
- }
-
- log(!client_entry->handshaked ? LL_INFO : LL_DEBUG, "Handshake established with %s:%d to %s:%d (direct)",
- inet_ntoa(client_entry->client_addr.sin_addr), ntohs(client_entry->client_addr.sin_port),
- target_host, target_port);
- if (!client_entry->handshaked && client_entry->masking_handler && !config.masking_handler_set) {
- log(LL_INFO, "Autodetected masking handler for client %s:%d: %s", inet_ntoa(client_entry->client_addr.sin_addr), ntohs(client_entry->client_addr.sin_port), client_entry->masking_handler->name);
- }
- client_entry->handshaked = 1;
- client_entry->client_obfuscated = !obfuscated && !client_entry->client_clean;
- client_entry->server_obfuscated = obfuscated;
- client_entry->last_handshake_time = now;
- }
- // If it's not a handshake or handshake response, connection is not established yet
- else if (!client_entry->handshaked) {
- log(LL_DEBUG, "Ignoring response (packet type #%u) from %s:%d to %s:%d until the handshake is completed",
- WG_TYPE(buffer),
- target_host, target_port,
- inet_ntoa(client_entry->client_addr.sin_addr), ntohs(client_entry->client_addr.sin_port));
- continue;
- }
-
- // Version downgrade check
- if (version < client_entry->version) {
- log(LL_WARN, "Server %s:%d uses old obfuscation version, downgrading from %d to %d",
- target_host, target_port, client_entry->version, version);
- client_entry->version = version;
- }
-
- if (!obfuscated && !client_entry->client_clean) {
- // If the packet is not obfuscated, we need to encode it
- length = encode(buffer, length, config.xor_key, key_length, client_entry->version, config.max_dummy_length_data);
- if (length < 4) {
- log(LL_ERROR, "Failed to encode packet from %s:%d", target_host, target_port);
- continue;
- }
- length = masking_data_wrap_to_client(&buffer, length, &config, client_entry, listen_sock, &forward_addr);
- }
-
- log_hexdump(LL_TRACE, (!obfuscated && !client_entry->client_clean) ? "<-X: " : "<-O: ", buffer, length);
-
- // Send the response back to the original client
- length = sendto(listen_sock, buffer, length, 0, (struct sockaddr *)&client_entry->client_addr, sizeof(client_entry->client_addr));
- if (length < 0) {
- serror_level(LL_DEBUG, "sendto %s:%d", inet_ntoa(client_entry->client_addr.sin_addr), ntohs(client_entry->client_addr.sin_port));
- continue;
- }
- client_entry->last_activity_time = now;
- client_entry->last_incoming_time = now;
- } // if (event->data.fd != listen_sock)
- } // for (int e = 0; e < events_n; e++)
-
- if (now - last_cleanup_time >= ITERATE_INTERVAL) {
- client_entry_t *current_entry, *tmp_current_entry;
- // Iterate over all client entries
- HASH_ITER(hh, conn_table, current_entry, tmp_current_entry) {
- // Check if the entry is idle for too long
- uint8_t idle = now - current_entry->last_activity_time >= config.idle_timeout;
- uint8_t incoming_timeout = config.in_timeout > 0 && now - current_entry->last_incoming_time >= config.in_timeout;
- uint8_t handshake_timeout = !current_entry->handshaked && now - current_entry->last_activity_time >= HANDSHAKE_TIMEOUT;
- if ((idle || incoming_timeout || handshake_timeout) && !current_entry->is_static) { // Do not remove static entries
- // Remove old entry
- if (idle) {
- log(LL_INFO, "Removing idle client %s:%d", inet_ntoa(current_entry->client_addr.sin_addr), ntohs(current_entry->client_addr.sin_port));
- } else if (incoming_timeout) {
- log(LL_INFO, "Removing client %s:%d due to incoming timeout", inet_ntoa(current_entry->client_addr.sin_addr), ntohs(current_entry->client_addr.sin_port));
- } else if (handshake_timeout) {
- log(LL_DEBUG, "Removing client %s:%d due to handshake timeout", inet_ntoa(current_entry->client_addr.sin_addr), ntohs(current_entry->client_addr.sin_port));
- }
-#ifdef USE_EPOLL
- epoll_ctl(epfd, EPOLL_CTL_DEL, current_entry->server_sock, NULL);
-#endif
- close(current_entry->server_sock);
- HASH_DEL(conn_table, current_entry);
- free(current_entry);
- continue;
- }
-
- // Check if we need to call masking timer
- if (current_entry->masking_handler && current_entry->masking_handler->timer_interval_s > 0
- && now - current_entry->last_masking_timer_time >= current_entry->masking_handler->timer_interval_s * 1000) {
- current_entry->last_masking_timer_time = now;
- masking_on_timer(&config, current_entry, listen_sock, &forward_addr);
- }
- }
- // Update the last cleanup time
- last_cleanup_time = now;
- }
- } // while (1)
-
- // You should never reach this point, but just in case
- return 0;
-}
diff --git a/ios/Tunnel/obfuscator/wg-obfuscator.h b/ios/Tunnel/obfuscator/wg-obfuscator.h
deleted file mode 100644
index ca9c7a6..0000000
--- a/ios/Tunnel/obfuscator/wg-obfuscator.h
+++ /dev/null
@@ -1,135 +0,0 @@
-#ifndef _WG_OBFUSCATOR_H_
-#define _WG_OBFUSCATOR_H_
-
-#include
-#include
-#include
-#include
-#include "uthash.h"
-
-// on Linux, use epoll for better performance
-#ifdef __linux__
-#define USE_EPOLL
-#endif
-
-#ifdef USE_EPOLL
-#include
-#define MAX_EVENTS 1024
-#else
-#include
-#endif
-
-#define WG_OBFUSCATOR_VERSION "1.6"
-#define WG_OBFUSCATOR_GIT_REPO "https://github.com/ClusterM/wg-obfuscator"
-
-#define LL_DEFAULT LL_INFO // default logging level
-
-// Main parameters
-// TODO: make these configurable via command line arguments or config file
-#define BUFFER_SIZE 65535 // size of the buffer for receiving data from the clients and server
-#define PREBUFFER_SIZE 1024 // size of the additional buffer size before the main buffer
-#define POLL_TIMEOUT 5000 // in milliseconds
-#define HANDSHAKE_TIMEOUT 5000 // in milliseconds
-#define ITERATE_INTERVAL 1000 // in milliseconds
-#define MAX_DUMMY_LENGTH_TOTAL 1024 // maximum length of a packet after dummy data extension
-#define MAX_DUMMY_LENGTH_HANDSHAKE 512 // maximum length of dummy data for handshake packets
-
-#define MAX_CLIENTS_DEFAULT 1024 // maximum number of clients
-#define IDLE_TIMEOUT_DEFAULT 300000 // in milliseconds
-#define IN_TIMEOUT_DEFAULT 0 // in milliseconds
-#define MAX_DUMMY_LENGTH_DATA_DEFAULT 4 // maximum length of dummy data for data packets
-
-// Default instance name
-#define DEFAULT_INSTANCE_NAME "main"
-
-// Logging levels
-#define LL_ERROR 0
-#define LL_WARN 1
-#define LL_INFO 2
-#define LL_DEBUG 3
-#define LL_TRACE 4
-
-// Maximum length of a single log line, longer hex dumps are split into several lines
-#define LOG_LINE_MAX 16384
-
-#define log(level, fmt, ...) do { if (verbose >= (level)) log_printf((level), fmt, ##__VA_ARGS__); } while (0)
-#define serror_level(level, fmt, ...) log(level, fmt " - %s (%d)", ##__VA_ARGS__, strerror(errno), errno)
-#define serror(fmt, ...) serror_level(LL_ERROR, fmt, ##__VA_ARGS__)
-
-// Direction of... something
-typedef enum {
- DIR_CLIENT_TO_SERVER = 0,
- DIR_SERVER_TO_CLIENT = 1,
-} direction_t;
-
-struct masking_handler; // forward declaration
-typedef struct masking_handler masking_handler_t;
-
-// Structure to hold obfuscator configuration
-typedef struct {
- int listen_port; // Listening port for the obfuscator
- char forward_host_port[256]; // Host and port to forward the data to
- char xor_key[256]; // Key for obfuscation
- char client_interface[256]; // Client interface as a string
- char *static_bindings; // Static bindings as a string
- int max_clients; // Maximum number of clients
- long idle_timeout; // Idle timeout in milliseconds
- long in_timeout; // Incoming timeout in milliseconds
- int max_dummy_length_data; // Maximum length of dummy data for data packets
- uint32_t fwmark; // Firewall mark
- masking_handler_t *masking_handler; // Masking handler to use
- uint8_t allow_clean; // 1 if non-obfuscated (clean) clients are allowed, 0 otherwise
- char log_file[512]; // Path of the log file
- int8_t log_timestamps; // 1 to force timestamps on, 0 to force them off, -1 for auto
- long resolve_interval; // Hostname re-resolve interval in milliseconds, 0 to disable periodic refresh
-
- uint8_t log_file_set; // 1 if the log file is set, 0 otherwise
- uint8_t listen_port_set; // 1 if the listen port is set, 0 otherwise
- uint8_t forward_host_port_set; // 1 if the forward host and port are set, 0 otherwise
- uint8_t xor_key_set; // 1 if the XOR key is set, 0 otherwise
- uint8_t client_interface_set; // 1 if the client interface is set, 0 otherwise
- uint8_t static_bindings_set; // 1 if the static bindings are set, 0 otherwise
- uint8_t masking_handler_set; // 1 if the masking handler is set, 0 otherwise
-} obfuscator_config_t;
-
-// Structure to hold client connection information
-typedef struct {
- struct sockaddr_in client_addr; // client address and port (key for the hash table)
- struct sockaddr_in our_addr; // our address and port on the server connection
- long last_activity_time; // last time we received data from/to this client
- long last_incoming_time; // last time we received data from the remote server
- long last_handshake_request_time; // last time we received a handshake request from/to this client
- long last_handshake_time; // last time we received a handshake response from/to this client
- long last_masking_timer_time; // last time we called the masking timer handler for this client
- int server_sock; // socket for the connection to the server
- uint8_t version; // obfuscation version
- masking_handler_t *masking_handler; // masking handler in use
- uint8_t handshaked : 1; // 1 if the handshake is complete, 0 otherwise
- uint8_t handshake_direction : 1; // 1 if the handshake is from client to server, 0 if from server to client
- uint8_t client_obfuscated : 1; // 1 if the client is obfuscated, 0 otherwise
- uint8_t server_obfuscated : 1; // 1 if the server is obfuscated, 0 otherwise
- uint8_t client_clean : 1; // 1 if the client speaks plain (non-obfuscated) WireGuard, traffic is passed through as is (allow-clean mode)
- uint8_t is_static : 1; // 1 if this is a static binding entry, 0 otherwise
- char bind_host[256]; // Original hostname of a static binding, empty if the address is a literal or the entry is dynamic
- UT_hash_handle hh;
-} client_entry_t;
-
-// Verbosity level
-extern int verbose;
-// Section name (for multiple instances)
-extern char section_name[256];
-
-const char *version_string(void);
-void print_version(void);
-void register_child_instance(pid_t pid);
-
-void log_init(const char *path, int8_t timestamps_mode);
-void log_reopen(void);
-#ifdef __GNUC__
-void log_printf(int level, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
-#else
-void log_printf(int level, const char *fmt, ...);
-#endif
-void log_hexdump(int level, const char *prefix, const uint8_t *data, int length);
-
-#endif
diff --git a/ios/Tunnel/pcarelay.c b/ios/Tunnel/pcarelay.c
deleted file mode 100644
index 013b630..0000000
--- a/ios/Tunnel/pcarelay.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * pcarelay — in-process transport switch for the iOS packet tunnel.
- * wg-obfuscator (one instance, iOS forbids fork) sends to 127.0.0.1:;
- * we forward either over UDP to the server's obfuscator port or over TCP to
- * the server's udptcp (frames: 2-byte length + packet). Switch with pcarelay_use_tcp().
- */
-#include "pcarelay.h"
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-static atomic_int use_tcp = 0;
-static atomic_ullong rx_bytes = 0;
-static char g_host[256], g_udp_port[8], g_tcp_port[8];
-static int g_local_port;
-
-static int dial(int socktype, const char *port) {
- struct addrinfo hints = {0}, *res, *r;
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = socktype;
- if (getaddrinfo(g_host, port, &hints, &res) != 0) return -1;
- int s = -1;
- for (r = res; r; r = r->ai_next) {
- s = socket(r->ai_family, r->ai_socktype, 0);
- if (s < 0) continue;
- if (connect(s, r->ai_addr, r->ai_addrlen) == 0) break;
- close(s); s = -1;
- }
- freeaddrinfo(res);
- if (s >= 0 && socktype == SOCK_STREAM) {
- int one = 1;
- setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &one, sizeof one);
- setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof one);
- setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof one);
- }
- return s;
-}
-
-static int read_full(int fd, unsigned char *b, size_t n) {
- size_t got = 0;
- while (got < n) { ssize_t r = read(fd, b + got, n - got); if (r <= 0) return -1; got += (size_t)r; }
- return 0;
-}
-
-static void *loop(void *arg) {
- (void)arg;
- struct sockaddr_in la = {0};
- la.sin_family = AF_INET;
- la.sin_port = htons((uint16_t)g_local_port);
- la.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- int local = socket(AF_INET, SOCK_DGRAM, 0);
- if (local < 0 || bind(local, (struct sockaddr *)&la, sizeof la) < 0) return NULL;
- int udp = -1, tcp = -1;
- struct sockaddr_storage peer; socklen_t pl = 0;
- unsigned char buf[65537];
- time_t last_dial = 0;
- for (;;) {
- int want_tcp = atomic_load(&use_tcp);
- if (!want_tcp && tcp >= 0) { close(tcp); tcp = -1; }
- if (want_tcp && udp >= 0) { close(udp); udp = -1; }
- if (!want_tcp && udp < 0 && time(NULL) != last_dial) { last_dial = time(NULL); udp = dial(SOCK_DGRAM, g_udp_port); }
- int up = want_tcp ? tcp : udp;
- struct pollfd p[2] = {{local, POLLIN, 0}, {up, POLLIN, 0}};
- poll(p, up >= 0 ? 2 : 1, 1000);
- if (p[0].revents & POLLIN) {
- pl = sizeof peer;
- ssize_t n = recvfrom(local, buf, 65535, 0, (struct sockaddr *)&peer, &pl);
- if (n <= 0) continue;
- if (want_tcp) {
- if (tcp < 0 && time(NULL) != last_dial) { last_dial = time(NULL); tcp = dial(SOCK_STREAM, g_tcp_port); }
- if (tcp >= 0) {
- unsigned char h[2] = {(unsigned char)(n >> 8), (unsigned char)n};
- if (send(tcp, h, 2, 0) != 2 || send(tcp, buf, (size_t)n, 0) != n) { close(tcp); tcp = -1; }
- }
- } else if (udp >= 0) {
- send(udp, buf, (size_t)n, 0);
- }
- }
- if (up >= 0 && (p[1].revents & (POLLIN | POLLHUP | POLLERR))) {
- ssize_t n;
- if (want_tcp) {
- unsigned char h[2];
- if (read_full(tcp, h, 2) < 0) { close(tcp); tcp = -1; continue; }
- n = (h[0] << 8) | h[1];
- if (n == 0 || read_full(tcp, buf, (size_t)n) < 0) { close(tcp); tcp = -1; continue; }
- } else {
- n = recv(udp, buf, 65535, 0);
- if (n <= 0) { close(udp); udp = -1; continue; }
- }
- atomic_fetch_add(&rx_bytes, (unsigned long long)n);
- if (pl) sendto(local, buf, (size_t)n, 0, (struct sockaddr *)&peer, pl);
- }
- }
-}
-
-int pcarelay_start(int local_port, const char *host, int udp_port, int tcp_port) {
- g_local_port = local_port;
- snprintf(g_host, sizeof g_host, "%s", host);
- snprintf(g_udp_port, sizeof g_udp_port, "%d", udp_port);
- snprintf(g_tcp_port, sizeof g_tcp_port, "%d", tcp_port);
- pthread_t t;
- if (pthread_create(&t, NULL, loop, NULL) != 0) return -1;
- pthread_detach(t);
- return 0;
-}
-
-void pcarelay_use_tcp(int on) { atomic_store(&use_tcp, on ? 1 : 0); }
-int pcarelay_is_tcp(void) { return atomic_load(&use_tcp); }
-unsigned long long pcarelay_rx_bytes(void) { return atomic_load(&rx_bytes); }
diff --git a/ios/Tunnel/pcarelay.h b/ios/Tunnel/pcarelay.h
deleted file mode 100644
index d92f4cc..0000000
--- a/ios/Tunnel/pcarelay.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef PCARELAY_H
-#define PCARELAY_H
-
-/* Start the transport switch thread: obfuscator -> 127.0.0.1:local_port -> host via UDP or TCP. */
-int pcarelay_start(int local_port, const char *host, int udp_port, int tcp_port);
-void pcarelay_use_tcp(int on);
-int pcarelay_is_tcp(void);
-/* Bytes received back from the server on any path (auto-detects a dead UDP). */
-unsigned long long pcarelay_rx_bytes(void);
-
-/* wg-obfuscator compiled in with -Dmain=wgobf_main (one instance per process). */
-int wgobf_main(int argc, char **argv);
-
-#endif
diff --git a/ios/Tunnel/ru_bypass.txt b/ios/Tunnel/ru_bypass.txt
deleted file mode 100644
index 9fbcc82..0000000
--- a/ios/Tunnel/ru_bypass.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-# AllowedIPs = Internet minus Russian networks (/20 and larger, ipdeny 2026-10-23) + 10.25.0.0/16
-0.0.0.0/7, 2.0.0.0/11, 2.32.0.0/12, 2.48.0.0/13, 2.56.0.0/14, 2.64.0.0/12, 2.80.0.0/13, 2.88.0.0/14, 2.96.0.0/11, 2.128.0.0/9, 3.0.0.0/8, 4.0.0.0/8, 5.0.0.0/15, 5.2.0.0/19, 5.2.64.0/18, 5.2.128.0/17, 5.4.0.0/14, 5.8.16.0/20, 5.8.32.0/20, 5.8.64.0/18, 5.8.128.0/19, 5.8.176.0/20, 5.8.240.0/20, 5.9.0.0/16, 5.10.0.0/16, 5.11.0.0/18, 5.11.80.0/20, 5.11.96.0/19, 5.11.128.0/17, 5.12.0.0/14, 5.20.0.0/15, 5.22.0.0/16, 5.23.0.0/18, 5.23.64.0/19, 5.23.112.0/20, 5.23.128.0/17, 5.24.0.0/14, 5.28.0.0/20, 5.28.32.0/19, 5.28.64.0/18, 5.28.128.0/17, 5.29.0.0/16, 5.30.0.0/15, 5.32.0.0/15, 5.34.0.0/16, 5.35.32.0/20, 5.35.64.0/20, 5.35.96.0/20, 5.35.160.0/19, 5.35.192.0/18, 5.36.0.0/14, 5.40.0.0/15, 5.42.128.0/17, 5.43.0.0/17, 5.43.160.0/19, 5.43.192.0/18, 5.44.16.0/20, 5.44.32.0/20, 5.44.64.0/18, 5.44.128.0/17, 5.45.0.0/17, 5.45.128.0/18, 5.46.0.0/15, 5.48.0.0/14, 5.52.0.0/16, 5.53.0.0/20, 5.53.32.0/19, 5.53.64.0/18, 5.53.128.0/17, 5.54.0.0/15, 5.56.0.0/13, 5.64.0.0/13, 5.72.0.0/14, 5.76.0.0/16, 5.77.32.0/19, 5.77.64.0/18, 5.77.128.0/17, 5.78.0.0/16, 5.79.0.0/17, 5.80.0.0/12, 5.96.0.0/14, 5.100.0.0/18, 5.100.128.0/17, 5.101.48.0/20, 5.101.96.0/19, 5.101.128.0/18, 5.101.208.0/20, 5.102.0.0/15, 5.104.0.0/19, 5.104.64.0/18, 5.104.128.0/17, 5.105.0.0/16, 5.106.0.0/15, 5.108.0.0/14, 5.112.0.0/12, 5.132.0.0/14, 5.144.0.0/18, 5.144.80.0/20, 5.144.128.0/17, 5.145.0.0/17, 5.145.128.0/18, 5.146.0.0/15, 5.148.0.0/16, 5.149.0.0/17, 5.149.128.0/20, 5.149.160.0/19, 5.149.192.0/20, 5.149.224.0/19, 5.150.0.0/15, 5.152.0.0/16, 5.153.0.0/17, 5.153.192.0/18, 5.154.0.0/15, 5.156.0.0/15, 5.158.0.0/18, 5.158.64.0/19, 5.158.128.0/17, 5.159.0.0/18, 5.159.64.0/19, 5.159.112.0/20, 5.159.128.0/17, 5.160.0.0/14, 5.168.0.0/14, 5.172.32.0/19, 5.172.64.0/18, 5.172.128.0/17, 5.173.0.0/16, 5.174.0.0/16, 5.175.0.0/18, 5.175.64.0/19, 5.175.128.0/17, 5.176.0.0/13, 5.184.0.0/15, 5.186.0.0/16, 5.187.0.0/18, 5.187.96.0/19, 5.187.128.0/17, 5.188.0.0/19, 5.188.32.0/20, 5.188.64.0/18, 5.188.128.0/18, 5.188.208.0/20, 5.188.224.0/19, 5.189.128.0/18, 5.189.192.0/19, 5.190.0.0/15, 5.192.0.0/14, 5.196.0.0/15, 5.198.0.0/16, 5.199.0.0/17, 5.199.128.0/18, 5.199.224.0/19, 5.200.0.0/19, 5.200.64.0/18, 5.200.128.0/17, 5.201.0.0/16, 5.202.0.0/15, 5.204.0.0/15, 5.206.128.0/17, 5.207.0.0/16, 5.208.0.0/12, 5.224.0.0/15, 5.226.0.0/16, 5.229.0.0/16, 5.230.0.0/15, 5.232.0.0/13, 5.240.0.0/13, 5.248.0.0/16, 5.249.0.0/17, 5.249.128.0/18, 5.249.224.0/19, 5.250.0.0/15, 5.252.0.0/15, 5.254.0.0/17, 5.254.128.0/18, 5.254.192.0/19, 5.255.0.0/17, 5.255.128.0/18, 6.0.0.0/7, 8.0.0.0/7, 11.0.0.0/8, 12.0.0.0/6, 16.0.0.0/6, 20.0.0.0/7, 22.0.0.0/8, 23.0.0.0/10, 23.64.0.0/11, 23.96.0.0/13, 23.104.0.0/16, 23.105.0.0/17, 23.105.128.0/18, 23.105.192.0/19, 23.106.0.0/15, 23.108.0.0/15, 23.110.0.0/16, 23.111.0.0/19, 23.111.64.0/19, 23.111.128.0/18, 23.111.224.0/19, 23.112.0.0/12, 23.128.0.0/9, 24.0.0.0/6, 28.0.0.0/7, 30.0.0.0/8, 31.0.0.0/15, 31.2.0.0/16, 31.3.0.0/20, 31.3.32.0/19, 31.3.64.0/18, 31.3.128.0/17, 31.4.0.0/15, 31.6.0.0/18, 31.6.64.0/19, 31.6.128.0/17, 31.7.0.0/17, 31.7.128.0/18, 31.7.192.0/19, 31.7.240.0/20, 31.9.0.0/16, 31.10.0.0/18, 31.10.128.0/17, 31.11.0.0/16, 31.12.0.0/16, 31.13.0.0/19, 31.13.64.0/18, 31.13.128.0/17, 31.14.0.0/16, 31.15.0.0/18, 31.15.64.0/20, 31.15.96.0/19, 31.15.128.0/17, 31.16.0.0/14, 31.20.0.0/15, 31.22.0.0/16, 31.24.0.0/14, 31.28.64.0/19, 31.28.128.0/18, 31.29.0.0/17, 31.30.0.0/16, 31.31.0.0/17, 31.31.128.0/18, 31.31.208.0/20, 31.31.224.0/19, 31.32.0.0/13, 31.40.0.0/19, 31.40.96.0/20, 31.40.192.0/18, 31.41.16.0/20, 31.41.32.0/19, 31.41.64.0/18, 31.41.128.0/17, 31.42.0.0/19, 31.42.48.0/20, 31.42.64.0/19, 31.42.112.0/20, 31.42.128.0/18, 31.43.0.0/17, 31.43.128.0/18, 31.43.224.0/19, 31.44.0.0/19, 31.44.32.0/20, 31.44.64.0/20, 31.44.96.0/19, 31.44.128.0/19, 31.44.160.0/20, 31.44.192.0/19, 31.44.224.0/20, 31.45.0.0/16, 31.46.0.0/16, 31.47.0.0/18, 31.47.64.0/19, 31.47.96.0/20, 31.47.192.0/18, 31.48.0.0/12, 31.64.0.0/10, 31.128.0.0/19, 31.128.48.0/20, 31.128.64.0/18, 31.128.160.0/19, 31.128.224.0/19, 31.129.64.0/19, 31.129.112.0/20, 31.129.160.0/19, 31.129.224.0/19, 31.130.96.0/20, 31.130.160.0/19, 31.130.192.0/18, 31.131.0.0/18, 31.131.80.0/20, 31.131.96.0/19, 31.131.128.0/20, 31.131.160.0/19, 31.131.224.0/19, 31.132.0.0/18, 31.132.64.0/19, 31.132.192.0/20, 31.133.0.0/19, 31.133.80.0/20, 31.133.96.0/19, 31.133.128.0/18, 31.133.192.0/19, 31.134.0.0/20, 31.134.48.0/20, 31.134.64.0/18, 31.134.192.0/19, 31.135.0.0/19, 31.135.128.0/18, 31.135.192.0/19, 31.136.0.0/13, 31.144.0.0/12, 31.160.0.0/15, 31.164.0.0/14, 31.168.0.0/14, 31.172.0.0/17, 31.172.128.0/18, 31.172.224.0/19, 31.174.0.0/15, 31.176.0.0/16, 31.177.0.0/18, 31.177.96.0/19, 31.177.128.0/17, 31.178.0.0/15, 31.182.0.0/15, 31.184.0.0/17, 31.184.128.0/18, 31.184.192.0/20, 31.184.240.0/20, 31.185.0.0/16, 31.186.0.0/18, 31.186.80.0/20, 31.186.96.0/19, 31.186.160.0/19, 31.186.192.0/18, 31.187.0.0/16, 31.188.0.0/14, 31.192.0.0/17, 31.192.192.0/18, 31.193.0.0/16, 31.194.0.0/15, 31.196.0.0/14, 31.200.0.0/17, 31.200.128.0/18, 31.200.208.0/20, 31.200.240.0/20, 31.201.0.0/16, 31.202.0.0/15, 31.204.64.0/19, 31.204.112.0/20, 31.204.128.0/19, 31.204.192.0/18, 31.205.0.0/16, 31.206.0.0/16, 31.207.0.0/18, 31.207.80.0/20, 31.207.96.0/19, 31.208.0.0/15, 31.210.0.0/17, 31.210.128.0/18, 31.210.224.0/19, 31.211.128.0/17, 31.212.0.0/14, 31.216.0.0/17, 31.216.128.0/19, 31.216.176.0/20, 31.216.192.0/18, 31.217.0.0/16, 31.218.0.0/15, 31.220.0.0/17, 31.220.128.0/19, 31.220.192.0/18, 31.221.0.0/16, 31.222.0.0/15, 31.224.0.0/11, 32.0.0.0/6, 36.0.0.0/8, 37.0.0.0/16, 37.1.80.0/20, 37.1.96.0/19, 37.1.144.0/20, 37.1.160.0/19, 37.1.192.0/18, 37.2.0.0/15, 37.4.0.0/14, 37.8.0.0/17, 37.8.128.0/20, 37.8.160.0/19, 37.8.192.0/18, 37.9.16.0/20, 37.9.32.0/19, 37.9.128.0/20, 37.9.160.0/19, 37.9.192.0/18, 37.10.0.0/15, 37.12.0.0/14, 37.16.0.0/15, 37.18.0.0/16, 37.19.0.0/19, 37.19.64.0/18, 37.19.128.0/17, 37.24.0.0/14, 37.28.0.0/17, 37.28.128.0/19, 37.28.192.0/18, 37.29.128.0/17, 37.30.0.0/15, 37.32.0.0/12, 37.48.0.0/16, 37.49.0.0/17, 37.49.128.0/19, 37.49.224.0/19, 37.50.0.0/15, 37.52.0.0/14, 37.56.0.0/14, 37.60.0.0/17, 37.60.128.0/18, 37.60.192.0/20, 37.60.224.0/19, 37.61.0.0/16, 37.62.0.0/15, 37.64.0.0/13, 37.72.0.0/18, 37.72.96.0/19, 37.72.128.0/17, 37.73.0.0/16, 37.74.0.0/16, 37.75.0.0/17, 37.75.128.0/18, 37.75.208.0/20, 37.75.224.0/19, 37.76.0.0/17, 37.76.192.0/18, 37.77.0.0/16, 37.80.0.0/12, 37.96.0.0/15, 37.98.0.0/17, 37.98.128.0/19, 37.98.192.0/19, 37.98.224.0/20, 37.99.0.0/16, 37.100.0.0/14, 37.104.0.0/14, 37.108.0.0/15, 37.110.160.0/19, 37.110.192.0/19, 37.110.240.0/20, 37.111.0.0/16, 37.114.0.0/20, 37.114.32.0/19, 37.114.64.0/18, 37.114.128.0/17, 37.115.0.0/16, 37.116.0.0/14, 37.120.0.0/15, 37.122.128.0/17, 37.123.0.0/16, 37.124.0.0/14, 37.128.0.0/17, 37.128.128.0/18, 37.128.192.0/19, 37.128.224.0/20, 37.129.0.0/16, 37.130.0.0/16, 37.131.0.0/17, 37.131.128.0/18, 37.131.224.0/19, 37.132.0.0/14, 37.136.0.0/15, 37.138.0.0/16, 37.139.0.0/19, 37.139.64.0/19, 37.139.112.0/20, 37.139.128.0/18, 37.140.192.0/18, 37.141.0.0/16, 37.142.0.0/16, 37.143.0.0/20, 37.143.32.0/19, 37.143.64.0/19, 37.143.112.0/20, 37.143.128.0/17, 37.148.0.0/14, 37.152.0.0/16, 37.153.64.0/18, 37.153.128.0/17, 37.154.0.0/15, 37.156.0.0/16, 37.157.0.0/20, 37.157.32.0/19, 37.157.64.0/18, 37.157.128.0/17, 37.158.0.0/15, 37.160.0.0/12, 37.176.0.0/13, 37.184.0.0/14, 37.188.64.0/18, 37.188.128.0/17, 37.189.0.0/16, 37.190.128.0/17, 37.191.0.0/16, 37.196.0.0/14, 37.200.0.0/18, 37.200.80.0/20, 37.200.96.0/19, 37.200.128.0/17, 37.201.0.0/16, 37.202.0.0/15, 37.205.0.0/18, 37.205.96.0/19, 37.205.128.0/17, 37.206.0.0/15, 37.208.0.0/18, 37.208.80.0/20, 37.208.96.0/19, 37.208.128.0/17, 37.209.0.0/17, 37.209.128.0/18, 37.209.192.0/19, 37.209.240.0/20, 37.210.0.0/15, 37.212.0.0/14, 37.216.0.0/14, 37.220.0.0/17, 37.220.128.0/19, 37.220.160.0/20, 37.220.192.0/18, 37.221.0.0/16, 37.222.0.0/15, 37.224.0.0/14, 37.228.0.0/18, 37.228.64.0/20, 37.228.96.0/19, 37.228.128.0/17, 37.229.0.0/16, 37.230.0.0/15, 37.232.0.0/17, 37.233.0.0/16, 37.234.0.0/15, 37.236.0.0/14, 37.240.0.0/12, 38.0.0.0/7, 40.0.0.0/6, 44.0.0.0/7, 46.1.0.0/16, 46.2.0.0/15, 46.4.0.0/14, 46.8.0.0/13, 46.16.0.0/14, 46.20.0.0/18, 46.20.80.0/20, 46.20.96.0/19, 46.20.128.0/19, 46.20.160.0/20, 46.20.192.0/18, 46.21.0.0/18, 46.21.80.0/20, 46.21.96.0/19, 46.21.128.0/17, 46.22.0.0/19, 46.22.32.0/20, 46.22.64.0/18, 46.22.128.0/18, 46.22.192.0/19, 46.22.224.0/20, 46.23.0.0/17, 46.23.128.0/20, 46.23.160.0/20, 46.23.192.0/18, 46.24.0.0/14, 46.28.0.0/15, 46.30.0.0/19, 46.30.48.0/20, 46.30.64.0/18, 46.30.128.0/17, 46.31.0.0/16, 46.32.0.0/18, 46.32.96.0/19, 46.32.128.0/17, 46.33.0.0/16, 46.34.0.0/16, 46.35.0.0/17, 46.35.128.0/18, 46.35.192.0/19, 46.36.32.0/19, 46.36.64.0/18, 46.36.128.0/17, 46.37.0.0/17, 46.37.160.0/19, 46.37.192.0/18, 46.38.64.0/19, 46.38.128.0/17, 46.39.64.0/18, 46.39.128.0/18, 46.39.192.0/19, 46.40.0.0/16, 46.41.0.0/18, 46.41.128.0/17, 46.42.64.0/18, 46.42.192.0/18, 46.43.0.0/17, 46.43.128.0/18, 46.44.64.0/18, 46.44.128.0/17, 46.45.64.0/18, 46.45.128.0/18, 46.46.64.0/18, 46.46.192.0/18, 46.47.64.0/18, 46.47.128.0/18, 46.49.0.0/16, 46.50.0.0/17, 46.51.0.0/16, 46.52.0.0/17, 46.53.0.0/16, 46.54.0.0/15, 46.56.0.0/14, 46.60.0.0/16, 46.62.128.0/17, 46.63.0.0/17, 46.64.0.0/13, 46.74.0.0/15, 46.76.0.0/14, 46.80.0.0/12, 46.96.0.0/13, 46.104.0.0/14, 46.108.0.0/15, 46.110.0.0/16, 46.112.0.0/12, 46.128.0.0/13, 46.136.0.0/15, 46.139.0.0/16, 46.140.0.0/14, 46.144.0.0/15, 46.148.0.0/19, 46.148.32.0/20, 46.148.64.0/19, 46.148.112.0/20, 46.148.144.0/20, 46.148.160.0/20, 46.149.0.0/19, 46.149.48.0/20, 46.149.64.0/18, 46.149.144.0/20, 46.149.160.0/19, 46.149.192.0/19, 46.149.240.0/20, 46.150.0.0/17, 46.150.192.0/19, 46.150.240.0/20, 46.151.16.0/20, 46.151.32.0/19, 46.151.64.0/18, 46.151.128.0/20, 46.151.160.0/19, 46.151.192.0/18, 46.152.0.0/14, 46.156.0.0/15, 46.160.64.0/18, 46.161.64.0/18, 46.161.192.0/18, 46.162.64.0/18, 46.162.128.0/17, 46.163.0.0/17, 46.163.192.0/18, 46.164.0.0/17, 46.164.128.0/18, 46.165.64.0/18, 46.165.128.0/17, 46.166.0.0/18, 46.166.128.0/18, 46.167.0.0/18, 46.167.128.0/17, 46.168.0.0/14, 46.172.64.0/19, 46.172.128.0/19, 46.172.224.0/19, 46.173.16.0/20, 46.173.64.0/18, 46.173.128.0/19, 46.173.160.0/20, 46.173.192.0/20, 46.173.224.0/19, 46.174.0.0/16, 46.175.0.0/17, 46.175.128.0/18, 46.175.224.0/19, 46.176.0.0/14, 46.182.0.0/15, 46.184.0.0/15, 46.186.0.0/16, 46.187.128.0/17, 46.188.128.0/17, 46.189.0.0/16, 46.190.0.0/16, 46.191.0.0/17, 46.192.0.0/11, 46.224.0.0/14, 46.228.16.0/20, 46.228.32.0/19, 46.228.80.0/20, 46.228.128.0/17, 46.229.0.0/18, 46.229.80.0/20, 46.229.112.0/20, 46.229.144.0/20, 46.229.160.0/20, 46.229.192.0/20, 46.229.224.0/19, 46.230.0.0/15, 46.232.0.0/16, 46.233.0.0/17, 46.233.128.0/18, 46.234.0.0/15, 46.236.0.0/17, 46.236.192.0/18, 46.237.64.0/18, 46.237.128.0/17, 46.238.0.0/15, 46.240.0.0/16, 46.241.128.0/17, 46.242.128.0/17, 46.243.0.0/16, 46.244.0.0/14, 46.248.0.0/16, 46.249.32.0/19, 46.249.64.0/18, 46.249.128.0/17, 46.250.0.0/19, 46.250.96.0/19, 46.250.160.0/19, 46.250.192.0/18, 46.251.0.0/18, 46.251.96.0/19, 46.251.128.0/17, 46.252.0.0/18, 46.252.64.0/19, 46.252.96.0/20, 46.252.128.0/19, 46.252.176.0/20, 46.252.192.0/19, 46.252.224.0/20, 46.253.0.0/16, 46.254.0.0/20, 46.254.32.0/19, 46.254.64.0/18, 46.254.128.0/17, 46.255.0.0/16, 47.0.0.0/8, 48.0.0.0/7, 50.0.0.0/8, 51.0.0.0/9, 51.128.0.0/10, 51.192.0.0/11, 51.224.0.0/12, 51.240.0.0/13, 51.248.0.0/15, 51.251.0.0/16, 51.252.0.0/14, 52.0.0.0/6, 56.0.0.0/6, 60.0.0.0/7, 62.0.0.0/14, 62.4.0.0/16, 62.5.0.0/17, 62.6.0.0/15, 62.8.0.0/13, 62.16.0.0/19, 62.16.64.0/19, 62.16.128.0/17, 62.17.0.0/16, 62.18.0.0/15, 62.20.0.0/14, 62.24.0.0/13, 62.32.0.0/16, 62.34.0.0/15, 62.36.0.0/14, 62.40.0.0/13, 62.48.0.0/13, 62.56.0.0/14, 62.60.0.0/16, 62.61.32.0/19, 62.61.64.0/18, 62.61.128.0/17, 62.62.0.0/16, 62.63.0.0/18, 62.63.128.0/17, 62.64.32.0/19, 62.64.64.0/18, 62.64.128.0/17, 62.65.0.0/16, 62.66.0.0/15, 62.68.0.0/17, 62.68.160.0/19, 62.68.192.0/18, 62.69.32.0/19, 62.69.64.0/18, 62.69.128.0/17, 62.70.0.0/15, 62.72.0.0/14, 62.76.224.0/20, 62.77.0.0/16, 62.78.0.0/19, 62.78.64.0/20, 62.78.96.0/19, 62.78.128.0/17, 62.79.0.0/16, 62.80.0.0/14, 62.84.0.0/18, 62.84.64.0/19, 62.84.96.0/20, 62.84.128.0/17, 62.85.0.0/16, 62.86.0.0/15, 62.88.0.0/16, 62.89.0.0/17, 62.89.128.0/18, 62.90.0.0/15, 62.92.0.0/14, 62.96.0.0/13, 62.104.0.0/16, 62.105.64.0/18, 62.105.160.0/19, 62.105.192.0/18, 62.106.0.0/18, 62.106.64.0/19, 62.106.128.0/17, 62.107.0.0/16, 62.108.0.0/16, 62.109.32.0/19, 62.109.64.0/18, 62.109.128.0/19, 62.109.192.0/18, 62.110.0.0/15, 62.112.0.0/18, 62.112.64.0/19, 62.112.128.0/17, 62.113.0.0/19, 62.113.128.0/17, 62.114.0.0/15, 62.116.0.0/16, 62.117.0.0/18, 62.117.128.0/17, 62.119.0.0/16, 62.120.0.0/13, 62.128.0.0/14, 62.132.0.0/16, 62.133.0.0/17, 62.133.128.0/19, 62.133.192.0/18, 62.134.0.0/15, 62.136.0.0/14, 62.140.0.0/17, 62.140.128.0/18, 62.140.192.0/19, 62.141.0.0/18, 62.141.128.0/17, 62.142.0.0/15, 62.144.0.0/14, 62.148.32.0/19, 62.148.64.0/18, 62.148.160.0/19, 62.148.192.0/19, 62.149.0.0/16, 62.150.0.0/15, 62.152.0.0/19, 62.152.96.0/19, 62.152.128.0/18, 62.152.224.0/19, 62.153.0.0/16, 62.154.0.0/15, 62.156.0.0/14, 62.160.0.0/14, 62.164.0.0/16, 62.165.64.0/18, 62.165.128.0/17, 62.166.0.0/15, 62.168.0.0/17, 62.168.128.0/18, 62.168.192.0/19, 62.169.0.0/16, 62.170.0.0/15, 62.172.0.0/16, 62.173.0.0/17, 62.173.160.0/19, 62.173.192.0/18, 62.174.0.0/15, 62.176.32.0/19, 62.176.64.0/18, 62.176.128.0/17, 62.177.0.0/19, 62.177.64.0/18, 62.177.128.0/17, 62.178.0.0/15, 62.180.0.0/16, 62.181.0.0/19, 62.181.64.0/18, 62.181.128.0/17, 62.182.0.0/18, 62.182.80.0/20, 62.182.96.0/19, 62.182.144.0/20, 62.182.160.0/19, 62.182.192.0/18, 62.183.128.0/17, 62.184.0.0/13, 62.192.0.0/19, 62.192.64.0/18, 62.192.128.0/18, 62.192.192.0/19, 62.193.0.0/16, 62.194.0.0/15, 62.196.0.0/14, 62.200.0.0/14, 62.204.0.0/16, 62.205.0.0/17, 62.205.128.0/19, 62.205.192.0/18, 62.206.0.0/15, 62.208.0.0/14, 62.212.0.0/16, 62.213.128.0/17, 62.214.0.0/15, 62.216.0.0/16, 62.217.0.0/17, 62.217.128.0/19, 62.217.192.0/18, 62.218.0.0/15, 62.220.0.0/19, 62.220.64.0/18, 62.220.128.0/17, 62.221.0.0/16, 62.222.0.0/15, 62.224.0.0/14, 62.228.0.0/15, 62.230.0.0/16, 62.231.32.0/19, 62.231.64.0/18, 62.231.128.0/19, 62.231.192.0/18, 62.232.0.0/13, 62.240.0.0/14, 62.244.0.0/16, 62.245.0.0/19, 62.245.64.0/18, 62.245.128.0/17, 62.246.0.0/15, 62.248.0.0/16, 62.249.0.0/17, 62.249.160.0/19, 62.249.192.0/18, 62.250.0.0/15, 62.252.0.0/14, 63.0.0.0/8, 64.0.0.0/5, 72.0.0.0/6, 76.0.0.0/8, 77.0.0.0/11, 77.32.0.0/15, 77.36.0.0/16, 77.37.0.0/17, 77.38.0.0/16, 77.39.128.0/17, 77.40.128.0/17, 77.42.0.0/16, 77.43.0.0/17, 77.44.0.0/16, 77.45.0.0/17, 77.46.0.0/15, 77.48.0.0/15, 77.52.0.0/14, 77.56.0.0/13, 77.64.0.0/15, 77.66.0.0/17, 77.67.0.0/16, 77.68.0.0/14, 77.72.0.0/17, 77.72.128.0/18, 77.72.192.0/19, 77.72.224.0/20, 77.73.0.0/16, 77.74.0.0/16, 77.75.16.0/20, 77.75.32.0/19, 77.75.64.0/18, 77.75.128.0/17, 77.76.0.0/15, 77.78.0.0/16, 77.79.0.0/17, 77.79.192.0/18, 77.80.0.0/15, 77.83.0.0/16, 77.84.0.0/14, 77.88.64.0/18, 77.88.128.0/17, 77.89.0.0/16, 77.90.0.0/15, 77.92.0.0/16, 77.93.0.0/18, 77.93.64.0/19, 77.93.128.0/17, 77.94.0.0/19, 77.94.48.0/20, 77.94.64.0/19, 77.94.128.0/19, 77.94.224.0/19, 77.95.0.0/16, 77.96.0.0/13, 77.104.0.0/16, 77.105.0.0/17, 77.105.128.0/19, 77.105.160.0/20, 77.105.192.0/18, 77.106.128.0/18, 77.107.0.0/16, 77.108.0.0/18, 77.108.128.0/18, 77.109.0.0/16, 77.110.0.0/15, 77.112.0.0/13, 77.120.0.0/16, 77.121.0.0/19, 77.121.64.0/18, 77.121.128.0/17, 77.122.0.0/16, 77.123.0.0/17, 77.123.128.0/18, 77.124.0.0/14, 77.128.0.0/10, 77.192.0.0/12, 77.208.0.0/13, 77.216.0.0/14, 77.220.0.0/19, 77.220.64.0/18, 77.220.192.0/18, 77.221.0.0/17, 77.221.128.0/18, 77.221.224.0/19, 77.222.0.0/19, 77.222.64.0/19, 77.222.128.0/17, 77.223.0.0/18, 77.223.128.0/17, 77.224.0.0/13, 77.232.64.0/18, 77.232.160.0/19, 77.232.192.0/18, 77.233.32.0/19, 77.233.64.0/18, 77.233.128.0/19, 77.233.224.0/19, 77.234.32.0/19, 77.234.64.0/18, 77.234.128.0/18, 77.234.224.0/19, 77.235.0.0/17, 77.235.128.0/18, 77.235.224.0/19, 77.236.0.0/19, 77.236.96.0/19, 77.236.128.0/18, 77.236.192.0/19, 77.237.0.0/16, 77.238.0.0/17, 77.238.160.0/19, 77.238.192.0/18, 77.239.0.0/17, 77.239.128.0/18, 77.239.224.0/19, 77.240.0.0/17, 77.240.128.0/20, 77.240.176.0/20, 77.240.192.0/18, 77.241.0.0/20, 77.241.48.0/20, 77.241.64.0/18, 77.241.128.0/20, 77.241.160.0/19, 77.241.192.0/19, 77.241.224.0/20, 77.242.16.0/20, 77.242.32.0/19, 77.242.64.0/19, 77.242.112.0/20, 77.242.128.0/17, 77.243.16.0/20, 77.243.32.0/19, 77.243.64.0/19, 77.243.128.0/18, 77.243.192.0/19, 77.243.224.0/20, 77.244.0.0/20, 77.244.32.0/19, 77.244.80.0/20, 77.244.96.0/19, 77.244.128.0/19, 77.244.176.0/20, 77.244.192.0/20, 77.244.224.0/19, 77.245.0.0/18, 77.245.64.0/19, 77.245.96.0/20, 77.245.128.0/19, 77.245.176.0/20, 77.245.224.0/19, 77.246.0.0/17, 77.246.128.0/18, 77.246.192.0/19, 77.246.240.0/20, 77.247.0.0/17, 77.247.144.0/20, 77.247.176.0/20, 77.247.192.0/18, 77.248.0.0/13, 78.0.0.0/12, 78.16.0.0/13, 78.24.0.0/16, 78.25.0.0/18, 78.25.192.0/18, 78.26.0.0/15, 78.28.0.0/16, 78.29.128.0/17, 78.30.0.0/17, 78.30.128.0/18, 78.31.0.0/16, 78.32.0.0/14, 78.38.0.0/15, 78.40.0.0/16, 78.41.0.0/18, 78.41.64.0/19, 78.41.112.0/20, 78.41.128.0/17, 78.42.0.0/15, 78.44.0.0/14, 78.48.0.0/12, 78.64.0.0/12, 78.80.0.0/16, 78.82.0.0/15, 78.84.0.0/16, 78.86.0.0/15, 78.88.0.0/13, 78.96.0.0/13, 78.104.0.0/15, 78.108.0.0/18, 78.108.96.0/19, 78.108.128.0/18, 78.108.208.0/20, 78.108.224.0/19, 78.109.0.0/19, 78.109.48.0/20, 78.109.64.0/19, 78.109.96.0/20, 78.109.144.0/20, 78.109.160.0/19, 78.109.192.0/18, 78.110.0.0/19, 78.110.32.0/20, 78.110.64.0/18, 78.110.128.0/20, 78.110.160.0/19, 78.110.192.0/19, 78.110.224.0/20, 78.111.0.0/17, 78.111.128.0/20, 78.111.160.0/19, 78.111.192.0/19, 78.111.224.0/20, 78.112.0.0/12, 78.128.0.0/14, 78.132.0.0/17, 78.133.0.0/16, 78.134.0.0/15, 78.136.0.0/17, 78.136.128.0/18, 78.136.240.0/20, 78.137.0.0/16, 78.138.0.0/17, 78.138.192.0/18, 78.139.0.0/18, 78.139.128.0/18, 78.140.64.0/18, 78.140.128.0/18, 78.140.240.0/20, 78.141.0.0/16, 78.142.0.0/15, 78.144.0.0/13, 78.152.0.0/16, 78.153.32.0/19, 78.153.64.0/18, 78.153.160.0/19, 78.153.192.0/18, 78.154.0.0/16, 78.155.0.0/17, 78.155.128.0/19, 78.155.224.0/19, 78.156.0.0/17, 78.156.128.0/18, 78.156.192.0/19, 78.157.0.0/17, 78.157.128.0/18, 78.157.192.0/19, 78.158.0.0/17, 78.158.128.0/18, 78.158.224.0/19, 78.159.0.0/17, 78.159.128.0/18, 78.159.192.0/19, 78.160.0.0/11, 78.192.0.0/10, 79.0.0.0/10, 79.64.0.0/11, 79.96.0.0/13, 79.106.0.0/15, 79.108.0.0/15, 79.110.0.0/17, 79.110.128.0/18, 79.110.192.0/19, 79.110.224.0/20, 79.112.0.0/13, 79.120.128.0/17, 79.121.0.0/16, 79.122.0.0/17, 79.123.0.0/16, 79.124.0.0/15, 79.126.128.0/17, 79.127.0.0/16, 79.128.0.0/14, 79.132.0.0/18, 79.132.64.0/19, 79.132.128.0/17, 79.133.0.0/18, 79.133.96.0/19, 79.133.160.0/19, 79.133.192.0/18, 79.134.32.0/19, 79.134.96.0/19, 79.134.128.0/18, 79.134.224.0/19, 79.135.0.0/18, 79.135.96.0/19, 79.135.128.0/18, 79.135.192.0/19, 79.136.0.0/17, 79.137.0.0/17, 79.137.160.0/19, 79.138.0.0/16, 79.139.0.0/17, 79.140.0.0/20, 79.140.32.0/19, 79.140.80.0/20, 79.140.112.0/20, 79.140.128.0/18, 79.140.192.0/19, 79.140.224.0/20, 79.141.0.0/19, 79.141.32.0/20, 79.141.80.0/20, 79.141.96.0/19, 79.141.128.0/18, 79.141.192.0/20, 79.141.224.0/19, 79.142.0.0/20, 79.142.32.0/19, 79.142.64.0/19, 79.142.112.0/20, 79.142.128.0/19, 79.142.176.0/20, 79.142.192.0/18, 79.143.16.0/20, 79.143.32.0/19, 79.143.80.0/20, 79.143.96.0/19, 79.143.128.0/18, 79.143.192.0/19, 79.143.240.0/20, 79.144.0.0/12, 79.160.0.0/14, 79.166.0.0/15, 79.168.0.0/14, 79.172.128.0/17, 79.173.0.0/18, 79.173.128.0/17, 79.174.0.0/19, 79.174.96.0/19, 79.174.128.0/17, 79.175.64.0/18, 79.175.128.0/17, 79.176.0.0/12, 79.192.0.0/10, 80.0.0.0/10, 80.64.0.0/18, 80.64.64.0/19, 80.64.112.0/20, 80.64.128.0/19, 80.64.176.0/20, 80.64.192.0/18, 80.65.0.0/20, 80.65.32.0/19, 80.65.64.0/18, 80.65.128.0/17, 80.66.0.0/18, 80.66.96.0/19, 80.66.128.0/20, 80.66.160.0/19, 80.66.192.0/18, 80.67.0.0/19, 80.67.32.0/20, 80.67.64.0/18, 80.67.128.0/18, 80.67.192.0/20, 80.67.224.0/20, 80.68.16.0/20, 80.68.32.0/19, 80.68.80.0/20, 80.68.96.0/19, 80.68.128.0/18, 80.68.192.0/19, 80.68.224.0/20, 80.69.0.0/17, 80.69.128.0/20, 80.69.160.0/20, 80.69.192.0/18, 80.70.0.0/18, 80.70.64.0/19, 80.70.112.0/20, 80.70.128.0/18, 80.70.192.0/19, 80.70.240.0/20, 80.71.0.0/17, 80.71.128.0/19, 80.71.192.0/20, 80.71.224.0/20, 80.72.0.0/18, 80.72.64.0/19, 80.72.96.0/20, 80.72.128.0/18, 80.72.192.0/20, 80.72.240.0/20, 80.73.0.0/20, 80.73.32.0/19, 80.73.96.0/19, 80.73.128.0/19, 80.73.176.0/20, 80.73.208.0/20, 80.73.224.0/19, 80.74.0.0/16, 80.75.0.0/18, 80.75.64.0/20, 80.75.96.0/19, 80.75.144.0/20, 80.75.160.0/19, 80.75.192.0/18, 80.76.0.0/18, 80.76.64.0/19, 80.76.112.0/20, 80.76.144.0/20, 80.76.160.0/20, 80.76.192.0/19, 80.77.0.0/17, 80.77.128.0/19, 80.77.176.0/20, 80.77.192.0/18, 80.78.0.0/18, 80.78.64.0/19, 80.78.128.0/18, 80.78.208.0/20, 80.78.224.0/20, 80.79.0.0/18, 80.79.80.0/20, 80.79.96.0/19, 80.79.128.0/19, 80.79.160.0/20, 80.79.192.0/19, 80.79.224.0/20, 80.80.0.0/18, 80.80.64.0/19, 80.80.128.0/18, 80.80.208.0/20, 80.80.224.0/19, 80.81.0.0/17, 80.81.128.0/18, 80.81.192.0/20, 80.81.224.0/19, 80.82.0.0/19, 80.82.64.0/20, 80.82.96.0/19, 80.82.128.0/19, 80.82.192.0/18, 80.83.0.0/17, 80.83.128.0/18, 80.83.208.0/20, 80.84.0.0/18, 80.84.64.0/19, 80.84.96.0/20, 80.84.128.0/17, 80.85.0.0/17, 80.85.128.0/20, 80.85.160.0/20, 80.85.192.0/18, 80.86.0.0/16, 80.87.0.0/18, 80.87.64.0/19, 80.87.112.0/20, 80.87.128.0/20, 80.87.160.0/19, 80.87.208.0/20, 80.87.224.0/19, 80.88.0.0/19, 80.88.32.0/20, 80.88.64.0/18, 80.88.128.0/17, 80.89.16.0/20, 80.89.32.0/19, 80.89.64.0/18, 80.89.160.0/19, 80.89.208.0/20, 80.89.224.0/19, 80.90.0.0/18, 80.90.80.0/20, 80.90.96.0/20, 80.90.128.0/19, 80.90.160.0/20, 80.90.192.0/19, 80.90.224.0/20, 80.91.0.0/20, 80.91.32.0/19, 80.91.64.0/18, 80.91.128.0/18, 80.91.208.0/20, 80.91.224.0/19, 80.92.48.0/20, 80.92.64.0/19, 80.92.112.0/20, 80.92.128.0/19, 80.92.176.0/20, 80.92.192.0/20, 80.92.224.0/19, 80.93.0.0/19, 80.93.32.0/20, 80.93.64.0/19, 80.93.112.0/20, 80.93.128.0/19, 80.93.160.0/20, 80.93.192.0/18, 80.94.0.0/16, 80.95.0.0/19, 80.95.48.0/20, 80.95.64.0/18, 80.95.128.0/17, 80.96.0.0/12, 80.112.0.0/15, 80.114.0.0/16, 80.115.0.0/17, 80.115.128.0/18, 80.115.224.0/19, 80.116.0.0/14, 80.120.0.0/13, 80.128.0.0/10, 80.192.0.0/11, 80.224.0.0/13, 80.232.0.0/15, 80.234.128.0/17, 80.235.0.0/16, 80.236.0.0/16, 80.237.128.0/17, 80.238.0.0/15, 80.240.0.0/19, 80.240.64.0/18, 80.240.128.0/18, 80.240.192.0/20, 80.240.224.0/20, 80.241.0.0/16, 80.242.0.0/18, 80.242.112.0/20, 80.242.128.0/17, 80.243.16.0/20, 80.243.32.0/19, 80.243.80.0/20, 80.243.96.0/19, 80.243.128.0/17, 80.244.0.0/19, 80.244.48.0/20, 80.244.64.0/18, 80.244.128.0/18, 80.244.192.0/19, 80.244.240.0/20, 80.245.0.0/18, 80.245.64.0/19, 80.245.96.0/20, 80.245.128.0/18, 80.245.192.0/19, 80.245.224.0/20, 80.246.0.0/18, 80.246.96.0/19, 80.246.128.0/18, 80.246.192.0/20, 80.246.224.0/20, 80.247.0.0/19, 80.247.48.0/20, 80.247.64.0/19, 80.247.128.0/19, 80.247.160.0/20, 80.247.192.0/18, 80.248.0.0/19, 80.248.32.0/20, 80.248.64.0/20, 80.248.96.0/19, 80.248.128.0/20, 80.248.160.0/19, 80.248.192.0/18, 80.249.0.0/17, 80.249.128.0/19, 80.249.160.0/20, 80.249.208.0/20, 80.249.224.0/19, 80.250.0.0/18, 80.250.96.0/19, 80.250.128.0/19, 80.250.192.0/20, 80.250.240.0/20, 80.251.0.0/19, 80.251.32.0/20, 80.251.64.0/19, 80.251.96.0/20, 80.251.144.0/20, 80.251.160.0/19, 80.251.192.0/19, 80.251.240.0/20, 80.252.0.0/20, 80.252.32.0/19, 80.252.64.0/18, 80.252.160.0/19, 80.252.192.0/18, 80.253.32.0/19, 80.253.64.0/18, 80.253.128.0/18, 80.253.192.0/19, 80.253.240.0/20, 80.254.0.0/20, 80.254.32.0/20, 80.254.64.0/19, 80.254.128.0/17, 80.255.0.0/20, 80.255.32.0/19, 80.255.64.0/20, 80.255.96.0/19, 80.255.160.0/20, 80.255.192.0/18, 81.0.0.0/16, 81.1.0.0/17, 81.2.64.0/18, 81.2.128.0/17, 81.3.0.0/17, 81.3.192.0/18, 81.4.0.0/17, 81.4.128.0/18, 81.5.0.0/18, 81.5.128.0/17, 81.6.0.0/15, 81.8.0.0/16, 81.9.128.0/17, 81.10.0.0/15, 81.12.0.0/16, 81.13.128.0/17, 81.14.0.0/15, 81.16.0.0/18, 81.16.64.0/20, 81.16.96.0/19, 81.16.128.0/17, 81.17.16.0/20, 81.17.32.0/19, 81.17.64.0/18, 81.17.128.0/20, 81.17.160.0/19, 81.17.192.0/18, 81.18.0.0/18, 81.18.64.0/19, 81.18.96.0/20, 81.18.160.0/19, 81.18.192.0/18, 81.19.0.0/18, 81.19.96.0/19, 81.19.144.0/20, 81.19.160.0/19, 81.19.192.0/18, 81.20.0.0/18, 81.20.64.0/19, 81.20.112.0/20, 81.20.128.0/19, 81.20.176.0/20, 81.20.208.0/20, 81.20.224.0/19, 81.21.0.0/16, 81.22.16.0/20, 81.22.32.0/20, 81.22.64.0/18, 81.22.128.0/17, 81.23.16.0/20, 81.23.32.0/19, 81.23.64.0/19, 81.23.128.0/20, 81.23.208.0/20, 81.23.224.0/19, 81.24.0.0/18, 81.24.64.0/20, 81.24.96.0/20, 81.24.144.0/20, 81.24.160.0/20, 81.24.192.0/18, 81.25.16.0/20, 81.25.32.0/20, 81.25.64.0/18, 81.25.128.0/17, 81.26.0.0/18, 81.26.64.0/20, 81.26.96.0/19, 81.26.144.0/20, 81.26.160.0/20, 81.26.192.0/18, 81.27.0.0/19, 81.27.32.0/20, 81.27.64.0/18, 81.27.128.0/20, 81.27.160.0/19, 81.27.192.0/19, 81.27.224.0/20, 81.28.0.0/17, 81.28.128.0/19, 81.28.192.0/20, 81.28.224.0/19, 81.29.0.0/18, 81.29.64.0/19, 81.29.96.0/20, 81.29.144.0/20, 81.29.160.0/19, 81.29.192.0/18, 81.30.0.0/19, 81.30.32.0/20, 81.30.64.0/19, 81.30.96.0/20, 81.30.128.0/19, 81.30.160.0/20, 81.30.224.0/19, 81.31.0.0/16, 81.32.0.0/11, 81.64.0.0/12, 81.80.0.0/13, 81.88.0.0/18, 81.88.64.0/20, 81.88.96.0/20, 81.88.128.0/18, 81.88.192.0/20, 81.88.224.0/19, 81.89.0.0/18, 81.89.80.0/20, 81.89.96.0/20, 81.89.128.0/19, 81.89.160.0/20, 81.89.192.0/18, 81.90.16.0/20, 81.90.32.0/19, 81.90.64.0/18, 81.90.128.0/18, 81.90.192.0/20, 81.90.224.0/19, 81.91.0.0/19, 81.91.64.0/18, 81.91.128.0/17, 81.92.0.0/15, 81.94.0.0/20, 81.94.48.0/20, 81.94.64.0/18, 81.94.160.0/19, 81.94.192.0/18, 81.95.0.0/20, 81.95.48.0/20, 81.95.64.0/18, 81.95.144.0/20, 81.95.160.0/19, 81.95.192.0/20, 81.95.224.0/19, 81.96.0.0/11, 81.128.0.0/11, 81.160.0.0/16, 81.161.0.0/20, 81.161.48.0/20, 81.161.64.0/18, 81.161.128.0/18, 81.161.192.0/20, 81.161.224.0/19, 81.162.48.0/20, 81.162.64.0/19, 81.162.128.0/17, 81.163.0.0/20, 81.163.64.0/20, 81.163.112.0/20, 81.163.192.0/19, 81.164.0.0/14, 81.168.0.0/13, 81.178.0.0/15, 81.180.0.0/14, 81.184.0.0/13, 81.192.0.0/15, 81.194.0.0/16, 81.196.0.0/14, 81.200.32.0/19, 81.200.64.0/20, 81.200.96.0/20, 81.200.128.0/20, 81.200.160.0/19, 81.200.192.0/20, 81.200.224.0/20, 81.201.0.0/20, 81.201.32.0/19, 81.201.80.0/20, 81.201.96.0/19, 81.201.128.0/18, 81.201.192.0/19, 81.201.224.0/20, 81.202.0.0/15, 81.204.0.0/14, 81.208.0.0/15, 81.210.0.0/16, 81.211.128.0/17, 81.212.0.0/14, 81.216.0.0/14, 81.220.0.0/15, 81.223.0.0/16, 81.224.0.0/11, 82.0.0.0/10, 82.64.0.0/11, 82.96.0.0/17, 82.96.128.0/18, 82.97.0.0/16, 82.98.0.0/15, 82.100.0.0/14, 82.104.0.0/13, 82.112.64.0/18, 82.112.128.0/19, 82.112.160.0/20, 82.112.192.0/18, 82.113.0.0/16, 82.114.32.0/19, 82.114.64.0/19, 82.114.160.0/19, 82.114.192.0/19, 82.115.0.0/16, 82.116.64.0/18, 82.116.128.0/17, 82.117.0.0/18, 82.117.96.0/19, 82.117.128.0/19, 82.117.192.0/18, 82.118.0.0/17, 82.118.160.0/19, 82.118.192.0/18, 82.119.0.0/17, 82.119.160.0/19, 82.119.192.0/18, 82.120.0.0/13, 82.128.0.0/13, 82.136.0.0/16, 82.137.0.0/17, 82.137.192.0/18, 82.138.64.0/18, 82.138.128.0/17, 82.139.0.0/16, 82.140.0.0/18, 82.140.128.0/18, 82.141.0.0/16, 82.142.0.0/17, 82.142.192.0/18, 82.143.0.0/16, 82.144.0.0/18, 82.144.96.0/19, 82.144.128.0/17, 82.145.0.0/16, 82.146.0.0/19, 82.146.64.0/18, 82.146.128.0/17, 82.147.0.0/18, 82.147.128.0/17, 82.148.0.0/20, 82.148.32.0/19, 82.148.64.0/18, 82.148.128.0/17, 82.149.0.0/17, 82.149.160.0/19, 82.149.224.0/19, 82.150.0.0/16, 82.151.0.0/18, 82.151.64.0/19, 82.151.128.0/18, 82.151.224.0/19, 82.152.0.0/13, 82.160.0.0/15, 82.163.0.0/16, 82.164.0.0/14, 82.168.0.0/13, 82.176.0.0/15, 82.178.0.0/16, 82.180.0.0/14, 82.184.0.0/13, 82.192.0.0/16, 82.193.0.0/17, 82.193.160.0/19, 82.193.192.0/18, 82.194.0.0/17, 82.194.128.0/19, 82.194.192.0/19, 82.195.32.0/19, 82.195.64.0/18, 82.195.128.0/17, 82.196.0.0/18, 82.196.96.0/19, 82.196.160.0/19, 82.196.192.0/18, 82.197.0.0/16, 82.198.32.0/19, 82.198.64.0/18, 82.198.128.0/19, 82.198.192.0/18, 82.199.0.0/18, 82.199.64.0/19, 82.199.128.0/17, 82.200.128.0/17, 82.201.0.0/16, 82.202.0.0/17, 82.202.176.0/20, 82.203.0.0/16, 82.204.0.0/17, 82.205.0.0/16, 82.206.0.0/15, 82.208.0.0/18, 82.208.128.0/17, 82.209.0.0/18, 82.209.128.0/17, 82.210.0.0/15, 82.212.0.0/14, 82.216.0.0/13, 82.224.0.0/11, 83.0.0.0/10, 83.64.0.0/14, 83.68.0.0/19, 83.68.64.0/18, 83.68.128.0/17, 83.69.32.0/19, 83.69.128.0/19, 83.70.0.0/15, 83.72.0.0/13, 83.80.0.0/12, 83.96.0.0/14, 83.100.0.0/15, 83.102.0.0/17, 83.103.0.0/16, 83.104.0.0/13, 83.112.0.0/12, 83.128.0.0/13, 83.136.0.0/15, 83.138.0.0/16, 83.139.0.0/17, 83.139.192.0/18, 83.140.0.0/15, 83.142.0.0/16, 83.143.0.0/17, 83.143.128.0/18, 83.143.208.0/20, 83.143.224.0/19, 83.144.0.0/15, 83.146.0.0/18, 83.146.128.0/17, 83.147.0.0/16, 83.148.0.0/16, 83.149.64.0/18, 83.149.128.0/18, 83.150.0.0/16, 83.151.16.0/20, 83.151.32.0/19, 83.151.64.0/18, 83.151.128.0/17, 83.152.0.0/13, 83.160.0.0/14, 83.164.0.0/15, 83.166.0.0/18, 83.166.64.0/19, 83.166.128.0/18, 83.166.192.0/19, 83.167.32.0/19, 83.167.128.0/17, 83.168.0.0/16, 83.169.0.0/17, 83.169.128.0/18, 83.170.0.0/16, 83.171.0.0/18, 83.171.128.0/17, 83.172.64.0/18, 83.172.128.0/17, 83.173.0.0/16, 83.174.0.0/17, 83.174.128.0/18, 83.175.0.0/16, 83.176.0.0/12, 83.192.0.0/12, 83.208.0.0/13, 83.216.0.0/16, 83.217.64.0/18, 83.217.128.0/18, 83.217.224.0/19, 83.218.0.0/16, 83.219.32.0/19, 83.219.64.0/18, 83.219.160.0/19, 83.219.192.0/19, 83.220.0.0/19, 83.220.96.0/19, 83.220.128.0/19, 83.220.192.0/19, 83.221.32.0/19, 83.221.64.0/18, 83.221.128.0/18, 83.221.224.0/19, 83.222.0.0/20, 83.222.32.0/19, 83.222.128.0/18, 83.222.224.0/19, 83.223.0.0/16, 83.224.0.0/14, 83.228.0.0/16, 83.229.0.0/17, 83.230.0.0/15, 83.232.0.0/15, 83.235.0.0/16, 83.236.0.0/16, 83.238.0.0/16, 83.240.0.0/15, 83.242.0.0/17, 83.243.0.0/16, 83.244.0.0/15, 83.246.0.0/17, 83.247.0.0/16, 83.248.0.0/13, 84.0.0.0/12, 84.16.0.0/17, 84.16.160.0/19, 84.16.192.0/18, 84.17.32.0/19, 84.17.64.0/18, 84.17.128.0/18, 84.17.192.0/19, 84.18.0.0/18, 84.18.64.0/19, 84.18.128.0/17, 84.19.0.0/16, 84.20.0.0/16, 84.21.0.0/18, 84.21.96.0/19, 84.21.128.0/18, 84.21.192.0/19, 84.22.0.0/17, 84.22.160.0/19, 84.22.224.0/19, 84.23.0.0/19, 84.23.64.0/18, 84.23.128.0/17, 84.24.0.0/13, 84.32.0.0/14, 84.36.0.0/15, 84.38.0.0/17, 84.38.128.0/19, 84.38.160.0/20, 84.38.192.0/18, 84.39.0.0/17, 84.39.128.0/18, 84.39.192.0/19, 84.39.224.0/20, 84.40.0.0/15, 84.42.128.0/17, 84.43.0.0/16, 84.44.0.0/14, 84.48.0.0/15, 84.50.0.0/16, 84.51.0.0/18, 84.51.128.0/18, 84.51.224.0/19, 84.52.0.0/18, 84.52.128.0/17, 84.53.0.0/17, 84.53.128.0/18, 84.54.0.0/17, 84.54.128.0/18, 84.55.0.0/16, 84.56.0.0/13, 84.64.0.0/10, 84.128.0.0/10, 84.192.0.0/13, 84.200.0.0/16, 84.201.0.0/17, 84.201.192.0/19, 84.201.224.0/20, 84.202.0.0/15, 84.205.0.0/16, 84.206.0.0/15, 84.208.0.0/12, 84.224.0.0/13, 84.232.0.0/14, 84.236.0.0/16, 84.237.128.0/17, 84.238.0.0/15, 84.240.0.0/15, 84.242.0.0/17, 84.242.128.0/18, 84.243.0.0/16, 84.244.64.0/18, 84.244.128.0/17, 84.245.0.0/16, 84.246.0.0/15, 84.248.0.0/14, 84.252.0.0/17, 84.252.144.0/20, 84.252.192.0/18, 84.253.0.0/18, 84.253.128.0/17, 84.254.0.0/17, 84.254.128.0/18, 84.255.0.0/16, 85.0.0.0/13, 85.8.0.0/14, 85.12.0.0/17, 85.12.128.0/18, 85.13.0.0/16, 85.14.0.0/16, 85.15.0.0/18, 85.15.192.0/18, 85.16.0.0/14, 85.20.0.0/16, 85.22.0.0/15, 85.24.0.0/15, 85.26.0.0/17, 85.27.0.0/16, 85.28.64.0/18, 85.28.128.0/18, 85.29.0.0/16, 85.30.0.0/17, 85.30.128.0/18, 85.31.0.0/18, 85.31.64.0/19, 85.31.96.0/20, 85.31.128.0/17, 85.32.0.0/11, 85.64.0.0/12, 85.80.0.0/13, 85.88.0.0/17, 85.88.128.0/19, 85.88.192.0/18, 85.89.0.0/18, 85.89.64.0/19, 85.89.128.0/17, 85.90.0.0/18, 85.90.64.0/19, 85.90.128.0/17, 85.91.0.0/17, 85.91.128.0/18, 85.91.224.0/19, 85.92.32.0/19, 85.92.64.0/18, 85.92.128.0/17, 85.93.0.0/19, 85.93.64.0/18, 85.93.160.0/19, 85.93.192.0/18, 85.94.64.0/18, 85.94.128.0/17, 85.95.0.0/17, 85.95.192.0/18, 85.96.0.0/12, 85.112.0.0/19, 85.112.64.0/19, 85.112.128.0/17, 85.113.0.0/19, 85.113.64.0/18, 85.113.160.0/19, 85.113.224.0/19, 85.114.32.0/19, 85.114.96.0/19, 85.114.128.0/19, 85.114.192.0/18, 85.115.0.0/17, 85.115.128.0/19, 85.115.192.0/19, 85.116.0.0/18, 85.116.64.0/19, 85.116.128.0/17, 85.117.0.0/18, 85.117.96.0/19, 85.117.128.0/17, 85.118.0.0/15, 85.120.0.0/13, 85.128.0.0/13, 85.136.0.0/14, 85.144.0.0/13, 85.152.0.0/14, 85.156.0.0/15, 85.158.0.0/16, 85.159.0.0/19, 85.159.48.0/20, 85.159.64.0/18, 85.159.128.0/17, 85.160.0.0/13, 85.168.0.0/14, 85.176.0.0/12, 85.192.64.0/18, 85.192.192.0/18, 85.193.0.0/18, 85.193.64.0/20, 85.193.96.0/19, 85.193.128.0/17, 85.194.0.0/15, 85.196.0.0/15, 85.198.0.0/18, 85.198.80.0/20, 85.198.112.0/20, 85.198.128.0/17, 85.199.0.0/16, 85.200.0.0/15, 85.202.16.0/20, 85.202.32.0/19, 85.202.64.0/18, 85.202.144.0/20, 85.202.160.0/20, 85.202.192.0/19, 85.203.0.0/16, 85.204.0.0/14, 85.208.0.0/12, 85.224.0.0/13, 85.232.0.0/18, 85.232.64.0/19, 85.232.128.0/17, 85.233.0.0/18, 85.233.96.0/19, 85.233.160.0/19, 85.233.192.0/18, 85.234.64.0/19, 85.234.128.0/17, 85.235.0.0/19, 85.235.64.0/18, 85.235.128.0/19, 85.235.224.0/19, 85.236.32.0/19, 85.236.64.0/18, 85.236.128.0/19, 85.236.192.0/18, 85.237.0.0/19, 85.237.64.0/18, 85.237.128.0/17, 85.238.0.0/16, 85.239.0.0/19, 85.239.64.0/18, 85.239.128.0/17, 85.240.0.0/13, 85.248.0.0/16, 85.250.0.0/15, 85.252.0.0/14, 86.0.0.0/11, 86.32.0.0/12, 86.48.0.0/13, 86.56.0.0/14, 86.60.0.0/15, 86.62.0.0/18, 86.62.128.0/17, 86.63.0.0/16, 86.64.0.0/11, 86.96.0.0/14, 86.100.0.0/15, 86.103.0.0/16, 86.104.0.0/14, 86.108.0.0/16, 86.109.0.0/17, 86.109.128.0/18, 86.109.224.0/19, 86.110.32.0/19, 86.110.64.0/19, 86.110.128.0/19, 86.110.192.0/20, 86.110.224.0/19, 86.111.32.0/19, 86.111.64.0/18, 86.111.128.0/17, 86.112.0.0/12, 86.128.0.0/9, 87.0.0.0/10, 87.64.0.0/13, 87.72.0.0/14, 87.76.16.0/20, 87.76.32.0/19, 87.76.64.0/18, 87.76.128.0/17, 87.77.0.0/16, 87.78.0.0/15, 87.80.0.0/12, 87.96.0.0/14, 87.100.0.0/15, 87.102.0.0/16, 87.103.0.0/17, 87.104.0.0/13, 87.112.0.0/14, 87.116.0.0/16, 87.117.64.0/18, 87.117.192.0/18, 87.118.0.0/17, 87.118.128.0/18, 87.119.0.0/17, 87.119.128.0/18, 87.119.192.0/19, 87.120.0.0/13, 87.128.0.0/10, 87.192.0.0/11, 87.224.0.0/17, 87.225.128.0/17, 87.226.0.0/17, 87.227.0.0/16, 87.228.128.0/17, 87.229.0.0/17, 87.230.0.0/15, 87.232.0.0/14, 87.236.0.0/20, 87.236.32.0/19, 87.236.64.0/18, 87.236.128.0/17, 87.237.0.0/16, 87.238.0.0/15, 87.240.64.0/18, 87.240.192.0/18, 87.241.0.0/17, 87.241.128.0/18, 87.242.0.0/18, 87.242.128.0/17, 87.243.0.0/16, 87.244.64.0/18, 87.244.128.0/17, 87.245.0.0/17, 87.245.208.0/20, 87.245.224.0/19, 87.246.0.0/15, 87.248.0.0/17, 87.248.128.0/18, 87.248.192.0/19, 87.249.64.0/18, 87.249.128.0/18, 87.250.32.0/19, 87.250.64.0/18, 87.250.128.0/18, 87.251.0.0/18, 87.251.128.0/19, 87.251.192.0/18, 87.252.0.0/16, 87.253.32.0/19, 87.253.64.0/18, 87.253.128.0/18, 87.253.224.0/19, 87.254.0.0/17, 87.254.160.0/19, 87.254.192.0/18, 87.255.32.0/19, 87.255.64.0/18, 87.255.128.0/18, 87.255.192.0/19, 88.0.0.0/10, 88.64.0.0/12, 88.80.0.0/19, 88.80.64.0/18, 88.80.128.0/17, 88.81.0.0/19, 88.81.64.0/18, 88.81.128.0/18, 88.81.224.0/19, 88.82.0.0/18, 88.82.96.0/19, 88.82.128.0/19, 88.82.192.0/18, 88.83.0.0/17, 88.83.128.0/18, 88.83.224.0/19, 88.84.0.0/17, 88.84.128.0/18, 88.84.224.0/19, 88.85.0.0/17, 88.85.128.0/19, 88.85.224.0/19, 88.86.0.0/18, 88.86.96.0/19, 88.86.128.0/18, 88.86.224.0/19, 88.87.0.0/18, 88.87.96.0/19, 88.87.128.0/17, 88.88.0.0/13, 88.96.0.0/11, 88.128.0.0/14, 88.132.0.0/15, 88.134.0.0/16, 88.135.16.0/20, 88.135.32.0/20, 88.135.64.0/20, 88.135.96.0/20, 88.135.128.0/17, 88.136.0.0/13, 88.144.0.0/15, 88.146.0.0/16, 88.147.0.0/17, 88.148.0.0/14, 88.152.0.0/13, 88.160.0.0/11, 88.192.0.0/13, 88.200.0.0/17, 88.201.0.0/17, 88.202.0.0/15, 88.204.128.0/17, 88.205.0.0/17, 88.206.128.0/17, 88.207.0.0/16, 88.208.0.0/14, 88.212.0.0/17, 88.212.128.0/18, 88.213.0.0/16, 88.214.0.0/16, 88.215.0.0/17, 88.215.192.0/18, 88.216.0.0/13, 88.224.0.0/11, 89.0.0.0/12, 89.16.0.0/19, 89.16.64.0/19, 89.16.128.0/17, 89.17.0.0/19, 89.17.64.0/18, 89.17.128.0/17, 89.18.0.0/17, 89.18.160.0/19, 89.18.192.0/18, 89.19.0.0/17, 89.19.128.0/19, 89.19.224.0/19, 89.20.48.0/20, 89.20.64.0/19, 89.20.160.0/19, 89.20.192.0/18, 89.21.0.0/17, 89.21.160.0/19, 89.21.192.0/18, 89.22.0.0/20, 89.22.32.0/19, 89.22.64.0/18, 89.22.192.0/19, 89.23.64.0/19, 89.23.112.0/20, 89.23.224.0/19, 89.24.0.0/14, 89.28.0.0/15, 89.30.0.0/16, 89.31.0.0/18, 89.31.64.0/20, 89.31.96.0/19, 89.31.128.0/17, 89.32.0.0/11, 89.64.0.0/11, 89.96.0.0/13, 89.104.0.0/18, 89.104.96.0/19, 89.104.128.0/17, 89.105.0.0/17, 89.105.160.0/19, 89.105.192.0/18, 89.106.0.0/16, 89.107.0.0/18, 89.107.64.0/19, 89.107.96.0/20, 89.107.128.0/18, 89.107.208.0/20, 89.107.224.0/19, 89.108.0.0/18, 89.108.128.0/17, 89.109.64.0/18, 89.110.64.0/18, 89.110.128.0/17, 89.111.0.0/17, 89.111.192.0/18, 89.114.0.0/15, 89.116.0.0/14, 89.120.0.0/13, 89.128.0.0/12, 89.144.0.0/16, 89.145.0.0/17, 89.145.160.0/19, 89.145.192.0/18, 89.146.0.0/15, 89.148.0.0/17, 89.148.128.0/18, 89.149.0.0/16, 89.150.0.0/16, 89.151.0.0/17, 89.151.192.0/18, 89.152.0.0/13, 89.160.0.0/15, 89.162.0.0/16, 89.163.128.0/17, 89.164.0.0/14, 89.168.0.0/16, 89.169.32.0/19, 89.169.96.0/19, 89.170.0.0/15, 89.172.0.0/15, 89.174.0.0/16, 89.176.0.0/15, 89.180.0.0/14, 89.184.32.0/19, 89.184.64.0/18, 89.184.128.0/18, 89.184.192.0/19, 89.185.0.0/18, 89.185.96.0/19, 89.185.128.0/17, 89.186.0.0/17, 89.186.128.0/18, 89.186.192.0/19, 89.187.0.0/16, 89.188.0.0/18, 89.188.64.0/19, 89.188.128.0/19, 89.188.192.0/19, 89.189.32.0/19, 89.189.64.0/19, 89.189.192.0/18, 89.190.0.0/17, 89.190.128.0/18, 89.190.192.0/19, 89.191.0.0/17, 89.191.128.0/18, 89.191.192.0/19, 89.191.224.0/20, 89.192.0.0/13, 89.200.0.0/14, 89.204.128.0/17, 89.205.0.0/16, 89.206.0.0/16, 89.207.0.0/19, 89.207.48.0/20, 89.207.80.0/20, 89.207.96.0/19, 89.207.128.0/17, 89.208.0.0/20, 89.208.48.0/20, 89.208.112.0/20, 89.208.128.0/20, 89.208.176.0/20, 89.208.240.0/20, 89.209.0.0/16, 89.210.0.0/15, 89.212.0.0/14, 89.216.0.0/14, 89.220.0.0/16, 89.221.0.0/20, 89.221.32.0/20, 89.221.64.0/18, 89.221.128.0/18, 89.221.208.0/20, 89.221.224.0/19, 89.222.0.0/17, 89.223.0.0/19, 89.223.80.0/20, 89.223.112.0/20, 89.223.128.0/17, 89.224.0.0/13, 89.232.0.0/18, 89.232.160.0/19, 89.233.0.0/16, 89.234.0.0/16, 89.235.0.0/17, 89.235.192.0/18, 89.236.0.0/16, 89.237.64.0/18, 89.237.128.0/17, 89.238.0.0/16, 89.239.0.0/17, 89.239.192.0/18, 89.240.0.0/13, 89.248.0.0/18, 89.248.64.0/19, 89.248.96.0/20, 89.248.128.0/19, 89.248.160.0/20, 89.248.208.0/20, 89.248.224.0/19, 89.249.0.0/20, 89.249.32.0/19, 89.249.64.0/19, 89.249.96.0/20, 89.249.176.0/20, 89.249.192.0/19, 89.250.32.0/19, 89.250.64.0/18, 89.250.128.0/20, 89.250.176.0/20, 89.250.192.0/20, 89.250.240.0/20, 89.251.0.0/18, 89.251.80.0/20, 89.251.112.0/20, 89.251.128.0/20, 89.251.176.0/20, 89.251.192.0/18, 89.252.0.0/18, 89.252.128.0/17, 89.253.64.0/18, 89.253.128.0/18, 89.254.0.0/17, 89.254.128.0/18, 89.255.0.0/18, 89.255.128.0/17, 90.0.0.0/9, 90.128.0.0/12, 90.144.0.0/14, 90.148.0.0/15, 90.152.0.0/15, 90.154.128.0/17, 90.155.0.0/17, 90.156.0.0/17, 90.156.144.0/20, 90.156.160.0/20, 90.156.192.0/19, 90.157.128.0/17, 90.158.0.0/15, 90.160.0.0/12, 90.176.0.0/13, 90.184.0.0/14, 90.190.0.0/15, 90.192.0.0/10, 91.0.0.0/10, 91.64.0.0/13, 91.72.0.0/14, 91.80.0.0/12, 91.96.0.0/14, 91.100.0.0/15, 91.102.0.0/16, 91.103.0.0/17, 91.103.128.0/18, 91.103.208.0/20, 91.103.224.0/19, 91.104.0.0/16, 91.105.0.0/17, 91.105.192.0/18, 91.106.0.0/16, 91.107.64.0/19, 91.107.128.0/17, 91.108.0.0/16, 91.109.0.0/18, 91.109.96.0/19, 91.109.160.0/19, 91.109.192.0/18, 91.110.0.0/15, 91.112.0.0/13, 91.120.0.0/15, 91.123.0.0/20, 91.123.32.0/19, 91.123.64.0/20, 91.123.96.0/19, 91.123.128.0/17, 91.124.0.0/14, 91.128.0.0/14, 91.132.0.0/16, 91.133.32.0/19, 91.133.64.0/18, 91.133.128.0/17, 91.134.0.0/16, 91.135.0.0/17, 91.135.128.0/20, 91.135.160.0/19, 91.135.192.0/20, 91.135.224.0/19, 91.136.0.0/14, 91.140.0.0/15, 91.142.0.0/18, 91.142.64.0/20, 91.142.96.0/19, 91.142.128.0/20, 91.142.160.0/19, 91.142.192.0/18, 91.143.64.0/18, 91.143.176.0/20, 91.143.192.0/18, 91.144.0.0/17, 91.144.192.0/18, 91.145.0.0/16, 91.146.64.0/18, 91.146.128.0/17, 91.147.64.0/18, 91.147.128.0/17, 91.148.0.0/16, 91.149.0.0/18, 91.149.128.0/17, 91.150.0.0/16, 91.151.0.0/19, 91.151.48.0/20, 91.151.64.0/18, 91.151.128.0/19, 91.151.160.0/20, 91.151.208.0/20, 91.151.224.0/19, 91.152.0.0/13, 91.160.0.0/12, 91.176.0.0/13, 91.184.0.0/17, 91.184.128.0/18, 91.184.192.0/19, 91.184.240.0/20, 91.185.0.0/19, 91.185.96.0/19, 91.185.128.0/18, 91.185.192.0/19, 91.186.0.0/18, 91.186.64.0/19, 91.186.128.0/17, 91.187.0.0/16, 91.188.0.0/17, 91.188.128.0/19, 91.188.192.0/18, 91.189.0.0/16, 91.190.0.0/18, 91.190.80.0/20, 91.190.96.0/20, 91.190.128.0/17, 91.191.0.0/17, 91.191.128.0/18, 91.191.192.0/19, 91.192.0.0/13, 91.200.0.0/14, 91.204.0.0/18, 91.204.64.0/19, 91.204.112.0/20, 91.204.128.0/17, 91.205.0.0/16, 91.206.0.0/15, 91.208.0.0/15, 91.210.0.0/17, 91.210.128.0/18, 91.210.208.0/20, 91.210.224.0/19, 91.211.0.0/16, 91.212.0.0/15, 91.214.0.0/16, 91.215.0.0/17, 91.215.128.0/18, 91.215.208.0/20, 91.215.224.0/19, 91.216.0.0/15, 91.218.0.0/17, 91.218.144.0/20, 91.218.160.0/19, 91.218.192.0/18, 91.219.0.0/16, 91.220.0.0/14, 91.224.0.0/12, 91.240.0.0/16, 91.241.0.0/17, 91.241.160.0/19, 91.241.192.0/18, 91.242.0.0/17, 91.242.128.0/19, 91.242.160.0/20, 91.242.192.0/18, 91.243.0.0/19, 91.243.64.0/19, 91.243.112.0/20, 91.243.128.0/18, 91.243.192.0/19, 91.244.0.0/18, 91.244.64.0/20, 91.244.96.0/19, 91.244.128.0/19, 91.244.176.0/20, 91.244.192.0/18, 91.245.0.0/19, 91.245.64.0/18, 91.245.160.0/19, 91.245.192.0/18, 91.246.0.0/18, 91.246.64.0/19, 91.246.96.0/20, 91.246.128.0/17, 91.247.32.0/19, 91.247.64.0/19, 91.247.144.0/20, 91.247.160.0/19, 91.247.208.0/20, 91.247.224.0/19, 91.248.0.0/13, 92.0.0.0/11, 92.32.0.0/14, 92.36.128.0/17, 92.37.0.0/17, 92.38.0.0/17, 92.38.128.0/18, 92.38.208.0/20, 92.39.0.0/18, 92.39.80.0/20, 92.39.112.0/20, 92.39.144.0/20, 92.39.160.0/19, 92.39.192.0/20, 92.39.240.0/20, 92.40.0.0/13, 92.48.0.0/16, 92.49.0.0/17, 92.49.192.0/18, 92.50.0.0/17, 92.51.48.0/20, 92.51.64.0/18, 92.51.128.0/17, 92.52.0.0/16, 92.53.0.0/18, 92.53.128.0/17, 92.54.0.0/18, 92.54.128.0/17, 92.55.64.0/18, 92.55.128.0/17, 92.56.0.0/14, 92.60.0.0/18, 92.60.64.0/20, 92.60.96.0/19, 92.60.128.0/17, 92.61.0.0/20, 92.61.32.0/19, 92.61.64.0/18, 92.61.128.0/17, 92.62.0.0/17, 92.62.128.0/20, 92.62.160.0/19, 92.62.192.0/18, 92.63.0.0/18, 92.63.80.0/20, 92.63.112.0/20, 92.63.128.0/17, 92.64.0.0/11, 92.96.0.0/14, 92.102.0.0/15, 92.104.0.0/13, 92.112.0.0/13, 92.120.0.0/14, 92.128.0.0/10, 92.192.0.0/11, 92.224.0.0/12, 92.240.0.0/17, 92.240.144.0/20, 92.240.160.0/19, 92.240.224.0/19, 92.241.32.0/19, 92.241.64.0/19, 92.241.128.0/19, 92.241.192.0/19, 92.242.128.0/17, 92.243.0.0/18, 92.243.64.0/19, 92.243.128.0/19, 92.243.192.0/18, 92.244.0.0/17, 92.244.128.0/18, 92.244.192.0/19, 92.245.0.0/19, 92.245.64.0/18, 92.245.128.0/17, 92.246.0.0/17, 92.246.128.0/19, 92.246.224.0/19, 92.247.0.0/16, 92.248.0.0/17, 92.249.0.0/16, 92.250.0.0/15, 92.252.0.0/17, 92.253.0.0/16, 92.254.0.0/16, 92.255.0.0/20, 92.255.32.0/19, 92.255.64.0/19, 93.0.0.0/10, 93.64.0.0/13, 93.72.0.0/14, 93.76.0.0/16, 93.77.0.0/17, 93.77.128.0/19, 93.77.192.0/18, 93.78.0.0/15, 93.82.0.0/15, 93.84.0.0/14, 93.88.16.0/20, 93.88.32.0/19, 93.88.64.0/18, 93.88.144.0/20, 93.88.192.0/20, 93.88.224.0/19, 93.89.0.0/17, 93.89.128.0/19, 93.89.160.0/20, 93.89.192.0/18, 93.90.0.0/19, 93.90.48.0/20, 93.90.64.0/20, 93.90.112.0/20, 93.90.128.0/18, 93.90.192.0/20, 93.91.16.0/20, 93.91.32.0/19, 93.91.64.0/19, 93.91.96.0/20, 93.91.128.0/19, 93.91.176.0/20, 93.91.192.0/19, 93.91.240.0/20, 93.92.0.0/18, 93.92.64.0/20, 93.92.96.0/19, 93.92.128.0/18, 93.92.208.0/20, 93.92.224.0/19, 93.93.0.0/16, 93.94.0.0/17, 93.94.128.0/20, 93.94.160.0/19, 93.94.192.0/18, 93.95.0.0/17, 93.95.128.0/19, 93.95.176.0/20, 93.95.192.0/18, 93.96.0.0/14, 93.101.0.0/16, 93.102.0.0/15, 93.104.0.0/13, 93.112.0.0/13, 93.120.0.0/17, 93.121.0.0/16, 93.122.0.0/16, 93.123.0.0/17, 93.124.128.0/17, 93.125.0.0/16, 93.126.0.0/15, 93.128.0.0/12, 93.144.0.0/13, 93.152.0.0/16, 93.153.0.0/17, 93.154.0.0/15, 93.156.0.0/16, 93.157.0.0/17, 93.157.128.0/19, 93.157.176.0/20, 93.157.192.0/19, 93.157.224.0/20, 93.158.0.0/17, 93.158.192.0/19, 93.158.224.0/20, 93.159.0.0/16, 93.160.0.0/13, 93.168.0.0/14, 93.172.0.0/15, 93.174.0.0/19, 93.174.32.0/20, 93.174.64.0/18, 93.174.128.0/17, 93.175.32.0/19, 93.175.64.0/18, 93.175.128.0/17, 93.176.0.0/16, 93.177.64.0/18, 93.177.128.0/17, 93.178.0.0/18, 93.178.128.0/17, 93.179.0.0/16, 93.180.64.0/18, 93.180.128.0/17, 93.181.0.0/17, 93.181.128.0/18, 93.182.64.0/18, 93.182.128.0/17, 93.183.0.0/18, 93.183.80.0/20, 93.183.96.0/19, 93.183.128.0/17, 93.184.0.0/17, 93.184.128.0/19, 93.184.176.0/20, 93.184.192.0/18, 93.185.0.0/20, 93.185.32.0/19, 93.185.64.0/18, 93.185.128.0/19, 93.185.160.0/20, 93.185.208.0/20, 93.185.224.0/19, 93.186.0.0/19, 93.186.32.0/20, 93.186.64.0/18, 93.186.128.0/18, 93.186.192.0/19, 93.186.240.0/20, 93.187.0.0/17, 93.187.128.0/19, 93.187.160.0/20, 93.187.192.0/18, 93.188.0.0/14, 93.192.0.0/10, 94.0.0.0/12, 94.16.0.0/15, 94.18.0.0/16, 94.20.0.0/14, 94.24.0.0/17, 94.26.0.0/17, 94.26.192.0/19, 94.27.0.0/16, 94.29.128.0/17, 94.30.0.0/16, 94.31.0.0/17, 94.32.0.0/13, 94.40.0.0/16, 94.42.0.0/15, 94.44.0.0/16, 94.45.32.0/19, 94.45.64.0/18, 94.45.128.0/18, 94.45.224.0/19, 94.46.0.0/15, 94.48.0.0/15, 94.52.0.0/14, 94.56.0.0/13, 94.64.0.0/13, 94.72.64.0/18, 94.72.128.0/17, 94.73.0.0/17, 94.73.128.0/18, 94.74.0.0/16, 94.75.64.0/18, 94.75.192.0/18, 94.76.0.0/16, 94.77.192.0/18, 94.78.0.0/17, 94.78.128.0/18, 94.79.64.0/18, 94.79.128.0/17, 94.80.0.0/12, 94.96.0.0/14, 94.100.0.0/18, 94.100.64.0/20, 94.100.96.0/19, 94.100.128.0/19, 94.100.160.0/20, 94.100.208.0/20, 94.100.224.0/19, 94.101.0.0/18, 94.101.80.0/20, 94.101.96.0/19, 94.101.128.0/17, 94.102.0.0/20, 94.102.32.0/19, 94.102.64.0/19, 94.102.96.0/20, 94.102.128.0/19, 94.102.160.0/20, 94.102.192.0/18, 94.103.0.0/17, 94.103.128.0/18, 94.103.192.0/19, 94.103.240.0/20, 94.104.0.0/13, 94.112.0.0/13, 94.120.0.0/14, 94.124.0.0/17, 94.124.128.0/18, 94.124.208.0/20, 94.124.224.0/19, 94.125.16.0/20, 94.125.32.0/19, 94.125.64.0/18, 94.125.128.0/17, 94.126.0.0/16, 94.127.0.0/17, 94.127.128.0/20, 94.127.160.0/19, 94.127.192.0/19, 94.127.224.0/20, 94.128.0.0/13, 94.136.0.0/17, 94.136.128.0/18, 94.136.224.0/19, 94.137.96.0/19, 94.137.128.0/18, 94.138.32.0/19, 94.138.64.0/18, 94.138.160.0/19, 94.138.192.0/18, 94.139.0.0/18, 94.139.64.0/19, 94.139.128.0/18, 94.139.192.0/19, 94.139.224.0/20, 94.140.0.0/17, 94.140.160.0/19, 94.141.0.0/19, 94.141.64.0/19, 94.141.96.0/20, 94.141.128.0/19, 94.141.192.0/18, 94.142.32.0/19, 94.142.64.0/18, 94.142.128.0/17, 94.143.0.0/19, 94.143.32.0/20, 94.143.64.0/18, 94.143.128.0/17, 94.144.0.0/13, 94.152.0.0/15, 94.154.0.0/18, 94.154.96.0/19, 94.154.128.0/17, 94.155.0.0/16, 94.156.0.0/15, 94.158.16.0/20, 94.158.48.0/20, 94.158.64.0/19, 94.158.128.0/19, 94.158.176.0/20, 94.158.208.0/20, 94.158.224.0/19, 94.159.128.0/17, 94.160.0.0/12, 94.176.0.0/14, 94.182.0.0/15, 94.184.0.0/14, 94.188.128.0/17, 94.189.0.0/16, 94.190.128.0/17, 94.191.0.0/16, 94.192.0.0/14, 94.196.0.0/15, 94.198.0.0/16, 94.199.0.0/18, 94.199.80.0/20, 94.199.96.0/19, 94.199.128.0/17, 94.200.0.0/13, 94.208.0.0/12, 94.224.0.0/14, 94.228.0.0/18, 94.228.64.0/19, 94.228.96.0/20, 94.228.128.0/19, 94.228.176.0/20, 94.228.208.0/20, 94.228.224.0/20, 94.229.0.0/20, 94.229.32.0/19, 94.229.64.0/18, 94.229.128.0/18, 94.229.192.0/19, 94.230.16.0/20, 94.230.48.0/20, 94.230.64.0/19, 94.230.96.0/20, 94.230.144.0/20, 94.230.176.0/20, 94.230.192.0/19, 94.230.224.0/20, 94.231.0.0/20, 94.231.32.0/19, 94.231.64.0/19, 94.231.96.0/20, 94.231.176.0/20, 94.231.192.0/18, 94.232.16.0/20, 94.232.32.0/20, 94.232.64.0/18, 94.232.144.0/20, 94.232.160.0/19, 94.232.192.0/18, 94.234.0.0/15, 94.236.0.0/16, 94.237.0.0/17, 94.238.0.0/15, 94.240.0.0/18, 94.240.128.0/17, 94.241.64.0/18, 94.241.128.0/18, 94.242.48.0/20, 94.242.64.0/18, 94.242.192.0/18, 94.243.64.0/18, 94.244.0.0/16, 94.245.0.0/17, 94.245.192.0/18, 94.246.0.0/16, 94.247.0.0/17, 94.247.128.0/18, 94.247.192.0/19, 94.247.224.0/20, 94.248.0.0/15, 94.250.0.0/16, 94.251.128.0/17, 94.252.0.0/16, 94.253.128.0/17, 94.254.0.0/16, 94.255.128.0/17, 95.0.0.0/12, 95.16.0.0/13, 95.33.0.0/16, 95.34.0.0/15, 95.36.0.0/16, 95.38.0.0/15, 95.40.0.0/13, 95.48.0.0/14, 95.56.0.0/13, 95.64.0.0/17, 95.65.0.0/16, 95.66.0.0/17, 95.67.0.0/17, 95.68.0.0/17, 95.69.0.0/16, 95.70.128.0/17, 95.74.0.0/15, 95.76.0.0/15, 95.80.0.0/18, 95.80.128.0/17, 95.81.0.0/17, 95.81.128.0/18, 95.82.0.0/17, 95.82.128.0/18, 95.83.192.0/18, 95.84.64.0/18, 95.85.0.0/16, 95.86.0.0/17, 95.86.128.0/18, 95.87.0.0/16, 95.88.0.0/13, 95.96.0.0/13, 95.104.0.0/17, 95.105.128.0/17, 95.107.128.0/17, 95.108.0.0/17, 95.109.0.0/16, 95.110.128.0/17, 95.111.0.0/16, 95.112.0.0/12, 95.128.0.0/16, 95.129.0.0/17, 95.129.128.0/19, 95.129.176.0/20, 95.129.192.0/18, 95.130.0.0/16, 95.131.16.0/20, 95.131.32.0/19, 95.131.64.0/18, 95.131.128.0/17, 95.132.0.0/14, 95.136.0.0/16, 95.137.128.0/17, 95.138.0.0/17, 95.138.128.0/18, 95.138.192.0/19, 95.140.0.0/20, 95.140.32.0/19, 95.140.64.0/18, 95.140.128.0/20, 95.140.160.0/19, 95.140.192.0/18, 95.141.16.0/20, 95.141.32.0/19, 95.141.64.0/18, 95.141.128.0/19, 95.141.160.0/20, 95.141.208.0/20, 95.141.240.0/20, 95.142.0.0/19, 95.142.48.0/20, 95.142.64.0/18, 95.142.128.0/18, 95.142.208.0/20, 95.142.224.0/19, 95.143.32.0/19, 95.143.64.0/19, 95.143.96.0/20, 95.143.128.0/19, 95.143.160.0/20, 95.143.192.0/20, 95.143.224.0/19, 95.144.0.0/13, 95.152.64.0/18, 95.152.128.0/17, 95.153.0.0/17, 95.154.0.0/18, 95.154.192.0/18, 95.155.0.0/16, 95.156.0.0/18, 95.156.128.0/17, 95.157.0.0/16, 95.158.0.0/17, 95.158.128.0/18, 95.159.0.0/17, 95.159.192.0/18, 95.160.0.0/16, 95.161.0.0/17, 95.161.128.0/20, 95.161.176.0/20, 95.161.192.0/20, 95.161.224.0/19, 95.162.0.0/16, 95.163.144.0/20, 95.163.160.0/20, 95.163.192.0/20, 95.164.0.0/16, 95.166.0.0/16, 95.168.0.0/16, 95.169.0.0/18, 95.169.64.0/19, 95.169.160.0/19, 95.169.192.0/18, 95.170.0.0/18, 95.170.64.0/19, 95.170.192.0/18, 95.171.32.0/19, 95.171.64.0/18, 95.171.128.0/18, 95.171.192.0/19, 95.172.0.0/19, 95.172.64.0/19, 95.172.160.0/19, 95.172.192.0/18, 95.173.0.0/17, 95.173.160.0/19, 95.173.192.0/18, 95.174.0.0/17, 95.174.128.0/18, 95.174.224.0/19, 95.175.0.0/17, 95.175.128.0/18, 95.175.192.0/19, 95.176.0.0/15, 95.178.0.0/16, 95.179.128.0/17, 95.180.0.0/16, 95.181.128.0/19, 95.181.176.0/20, 95.181.208.0/20, 95.181.224.0/19, 95.182.0.0/19, 95.182.64.0/18, 95.182.128.0/17, 95.183.0.0/20, 95.183.48.0/20, 95.183.128.0/17, 95.184.0.0/14, 95.192.0.0/12, 95.208.0.0/14, 95.212.0.0/16, 95.214.0.0/15, 95.216.0.0/14, 95.222.0.0/15, 95.224.0.0/11, 96.0.0.0/6, 100.0.0.0/10, 100.128.0.0/9, 101.0.0.0/8, 102.0.0.0/7, 104.0.0.0/6, 108.0.0.0/8, 109.0.0.0/11, 109.32.0.0/12, 109.48.0.0/13, 109.56.0.0/14, 109.60.0.0/17, 109.61.0.0/17, 109.62.0.0/17, 109.63.0.0/17, 109.64.0.0/14, 109.68.0.0/16, 109.69.0.0/20, 109.69.32.0/19, 109.69.64.0/18, 109.69.128.0/17, 109.70.0.0/16, 109.71.0.0/17, 109.71.128.0/18, 109.71.208.0/20, 109.71.224.0/19, 109.72.0.0/18, 109.72.80.0/20, 109.72.96.0/19, 109.72.144.0/20, 109.72.160.0/19, 109.72.192.0/19, 109.73.16.0/20, 109.73.48.0/20, 109.73.64.0/18, 109.73.128.0/18, 109.73.208.0/20, 109.73.224.0/19, 109.74.0.0/18, 109.74.64.0/19, 109.74.96.0/20, 109.74.144.0/20, 109.74.176.0/20, 109.74.192.0/20, 109.74.224.0/19, 109.75.0.0/17, 109.75.144.0/20, 109.75.160.0/19, 109.75.208.0/20, 109.75.224.0/20, 109.76.0.0/14, 109.80.0.0/13, 109.88.0.0/14, 109.92.0.0/15, 109.94.32.0/19, 109.94.96.0/19, 109.94.128.0/19, 109.94.160.0/20, 109.94.208.0/20, 109.94.224.0/19, 109.95.0.0/18, 109.95.64.0/19, 109.95.112.0/20, 109.95.128.0/18, 109.95.192.0/20, 109.95.224.0/19, 109.96.0.0/13, 109.104.0.0/16, 109.105.0.0/18, 109.105.96.0/19, 109.105.128.0/19, 109.105.192.0/18, 109.106.0.0/17, 109.106.160.0/19, 109.106.224.0/19, 109.107.0.0/16, 109.108.0.0/19, 109.108.64.0/18, 109.108.128.0/17, 109.109.0.0/17, 109.109.128.0/18, 109.109.192.0/20, 109.109.224.0/19, 109.110.0.0/19, 109.110.96.0/19, 109.110.128.0/17, 109.111.32.0/19, 109.111.96.0/19, 109.111.192.0/18, 109.112.0.0/13, 109.120.64.0/18, 109.120.128.0/19, 109.120.176.0/20, 109.120.192.0/18, 109.121.0.0/16, 109.122.0.0/16, 109.123.0.0/17, 109.123.192.0/18, 109.124.128.0/18, 109.125.0.0/16, 109.126.64.0/18, 109.126.128.0/18, 109.127.0.0/17, 109.127.192.0/18, 109.128.0.0/11, 109.160.0.0/16, 109.161.128.0/17, 109.162.0.0/15, 109.164.0.0/16, 109.165.128.0/17, 109.166.0.0/16, 109.167.0.0/17, 109.168.0.0/17, 109.169.0.0/17, 109.170.128.0/17, 109.171.128.0/17, 109.172.0.0/20, 109.172.80.0/20, 109.172.128.0/17, 109.173.128.0/17, 109.174.128.0/17, 109.175.0.0/16, 109.176.0.0/13, 109.185.0.0/16, 109.186.0.0/16, 109.189.0.0/16, 109.190.0.0/16, 109.192.0.0/15, 109.196.0.0/20, 109.196.32.0/19, 109.196.80.0/20, 109.196.96.0/19, 109.196.128.0/18, 109.196.224.0/19, 109.197.0.0/20, 109.197.32.0/19, 109.197.64.0/19, 109.197.96.0/20, 109.197.160.0/19, 109.197.208.0/20, 109.197.224.0/19, 109.198.0.0/18, 109.198.128.0/19, 109.199.0.0/16, 109.200.0.0/18, 109.200.64.0/19, 109.200.160.0/19, 109.200.192.0/18, 109.201.0.0/18, 109.201.128.0/18, 109.201.224.0/19, 109.202.64.0/18, 109.202.128.0/19, 109.202.192.0/18, 109.203.0.0/17, 109.203.128.0/18, 109.203.224.0/19, 109.204.0.0/15, 109.206.0.0/17, 109.206.160.0/19, 109.206.192.0/18, 109.207.16.0/20, 109.207.32.0/19, 109.207.64.0/20, 109.207.96.0/19, 109.207.128.0/19, 109.207.160.0/20, 109.207.192.0/19, 109.207.240.0/20, 109.208.0.0/12, 109.224.0.0/16, 109.225.64.0/18, 109.225.128.0/18, 109.226.0.0/18, 109.226.128.0/18, 109.227.0.0/17, 109.227.128.0/18, 109.228.0.0/16, 109.229.0.0/19, 109.229.160.0/19, 109.229.192.0/19, 109.230.0.0/17, 109.230.192.0/18, 109.231.0.0/16, 109.232.0.0/16, 109.233.0.0/17, 109.233.128.0/18, 109.233.192.0/19, 109.233.240.0/20, 109.234.0.0/16, 109.235.0.0/17, 109.235.128.0/18, 109.235.192.0/20, 109.235.224.0/19, 109.236.0.0/18, 109.236.80.0/20, 109.236.112.0/20, 109.236.128.0/18, 109.236.192.0/20, 109.237.16.0/20, 109.237.32.0/19, 109.237.64.0/19, 109.237.112.0/20, 109.237.128.0/20, 109.237.160.0/19, 109.237.192.0/19, 109.237.240.0/20, 109.238.0.0/18, 109.238.64.0/19, 109.238.112.0/20, 109.238.128.0/18, 109.238.208.0/20, 109.238.224.0/20, 109.239.0.0/17, 109.239.128.0/18, 109.239.192.0/20, 109.239.224.0/19, 109.240.0.0/13, 109.248.0.0/14, 109.253.0.0/16, 109.255.0.0/16, 110.0.0.0/8, 111.0.0.0/10, 111.64.0.0/12, 111.80.0.0/13, 111.88.0.0/18, 111.88.64.0/19, 111.88.128.0/20, 111.88.160.0/19, 111.88.224.0/20, 111.89.0.0/16, 111.90.0.0/15, 111.92.0.0/14, 111.96.0.0/11, 111.128.0.0/9, 112.0.0.0/5, 120.0.0.0/6, 124.0.0.0/7, 126.0.0.0/8, 128.0.0.0/18, 128.0.64.0/20, 128.0.96.0/19, 128.0.144.0/20, 128.0.160.0/19, 128.0.192.0/18, 128.1.0.0/16, 128.2.0.0/15, 128.4.0.0/14, 128.8.0.0/13, 128.16.0.0/12, 128.32.0.0/11, 128.64.0.0/14, 128.76.0.0/14, 128.80.0.0/12, 128.96.0.0/11, 128.128.0.0/13, 128.136.0.0/14, 128.140.0.0/17, 128.140.128.0/19, 128.140.176.0/20, 128.140.192.0/18, 128.141.0.0/16, 128.142.0.0/15, 128.144.0.0/12, 128.160.0.0/11, 128.192.0.0/13, 128.200.0.0/14, 128.204.128.0/19, 128.204.192.0/18, 128.205.0.0/16, 128.206.0.0/15, 128.208.0.0/12, 128.224.0.0/11, 129.0.0.0/10, 129.64.0.0/11, 129.96.0.0/14, 129.100.0.0/16, 129.101.0.0/18, 129.101.96.0/19, 129.101.128.0/17, 129.102.0.0/15, 129.104.0.0/13, 129.112.0.0/12, 129.128.0.0/9, 130.0.0.0/11, 130.32.0.0/12, 130.48.0.0/16, 130.49.0.0/17, 130.49.128.0/19, 130.49.160.0/20, 130.50.0.0/15, 130.52.0.0/14, 130.56.0.0/13, 130.64.0.0/10, 130.128.0.0/10, 130.192.0.0/16, 130.193.0.0/19, 130.193.64.0/18, 130.193.128.0/17, 130.194.0.0/15, 130.196.0.0/14, 130.200.0.0/13, 130.208.0.0/12, 130.224.0.0/12, 130.240.0.0/13, 130.248.0.0/14, 130.252.0.0/15, 130.254.0.0/16, 130.255.0.0/19, 130.255.64.0/18, 130.255.144.0/20, 130.255.160.0/19, 130.255.192.0/18, 131.0.0.0/8, 132.0.0.0/7, 134.0.0.0/18, 134.0.64.0/19, 134.0.112.0/20, 134.0.128.0/17, 134.1.0.0/16, 134.2.0.0/15, 134.4.0.0/14, 134.8.0.0/13, 134.16.0.0/15, 134.18.0.0/16, 134.19.0.0/17, 134.19.128.0/20, 134.19.160.0/19, 134.19.192.0/18, 134.20.0.0/14, 134.24.0.0/13, 134.32.0.0/11, 134.64.0.0/12, 134.80.0.0/13, 134.88.0.0/15, 134.90.0.0/17, 134.90.128.0/19, 134.90.192.0/18, 134.91.0.0/16, 134.92.0.0/14, 134.96.0.0/11, 134.128.0.0/10, 134.192.0.0/11, 134.224.0.0/12, 134.240.0.0/13, 134.248.0.0/14, 134.252.0.0/15, 134.254.0.0/16, 134.255.0.0/17, 134.255.160.0/19, 134.255.192.0/18, 135.0.0.0/10, 135.64.0.0/11, 135.96.0.0/13, 135.104.0.0/15, 135.106.0.0/17, 135.106.128.0/20, 135.107.0.0/16, 135.108.0.0/14, 135.112.0.0/12, 135.128.0.0/9, 136.0.0.0/9, 136.128.0.0/11, 136.160.0.0/13, 136.168.0.0/16, 136.169.0.0/17, 136.170.0.0/15, 136.172.0.0/14, 136.176.0.0/12, 136.192.0.0/11, 136.224.0.0/13, 136.232.0.0/15, 136.234.112.0/20, 136.234.128.0/17, 136.235.0.0/16, 136.236.0.0/14, 136.240.0.0/12, 137.0.0.0/12, 137.16.0.0/14, 137.20.0.0/15, 137.22.0.0/17, 137.22.128.0/20, 137.22.160.0/19, 137.22.192.0/18, 137.23.0.0/16, 137.24.0.0/13, 137.32.0.0/11, 137.64.0.0/10, 137.128.0.0/9, 138.0.0.0/12, 138.16.0.0/17, 138.16.128.0/20, 138.17.0.0/16, 138.18.0.0/15, 138.20.0.0/14, 138.24.0.0/13, 138.32.0.0/11, 138.64.0.0/10, 138.128.0.0/9, 139.0.0.0/11, 139.32.0.0/13, 139.40.0.0/14, 139.44.0.0/16, 139.45.0.0/17, 139.45.128.0/18, 139.45.192.0/19, 139.46.0.0/15, 139.48.0.0/12, 139.64.0.0/11, 139.96.0.0/14, 139.100.0.0/17, 139.100.128.0/19, 139.100.176.0/20, 139.101.0.0/16, 139.102.0.0/15, 139.104.0.0/13, 139.112.0.0/12, 139.128.0.0/9, 140.0.0.0/8, 141.0.0.0/13, 141.8.0.0/17, 141.8.192.0/18, 141.9.0.0/16, 141.10.0.0/15, 141.12.0.0/14, 141.16.0.0/12, 141.32.0.0/11, 141.64.0.0/11, 141.96.0.0/13, 141.104.0.0/16, 141.105.0.0/19, 141.105.48.0/20, 141.105.64.0/18, 141.105.128.0/17, 141.106.0.0/15, 141.108.0.0/14, 141.112.0.0/12, 141.128.0.0/14, 141.132.0.0/16, 141.133.0.0/17, 141.133.128.0/19, 141.133.160.0/20, 141.134.0.0/15, 141.136.0.0/13, 141.144.0.0/12, 141.160.0.0/11, 141.192.0.0/10, 142.0.0.0/7, 144.0.0.0/9, 144.128.0.0/10, 144.192.0.0/13, 144.200.0.0/14, 144.204.0.0/15, 144.207.0.0/16, 144.208.0.0/12, 144.224.0.0/11, 145.0.0.0/9, 145.128.0.0/10, 145.192.0.0/11, 145.224.0.0/12, 145.240.0.0/13, 145.248.0.0/16, 145.250.0.0/15, 145.252.0.0/15, 145.254.0.0/16, 145.255.48.0/20, 145.255.64.0/18, 145.255.128.0/17, 146.0.0.0/10, 146.64.0.0/15, 146.66.0.0/17, 146.66.128.0/19, 146.66.208.0/20, 146.66.224.0/19, 146.67.0.0/16, 146.68.0.0/14, 146.72.0.0/13, 146.80.0.0/12, 146.96.0.0/11, 146.128.0.0/11, 146.160.0.0/12, 146.176.0.0/13, 146.184.0.0/16, 146.185.0.0/17, 146.185.128.0/18, 146.185.208.0/20, 146.185.224.0/19, 146.186.0.0/15, 146.188.0.0/14, 146.192.0.0/11, 146.224.0.0/12, 146.240.0.0/13, 146.248.0.0/14, 146.252.0.0/15, 146.254.0.0/16, 146.255.0.0/17, 146.255.128.0/18, 146.255.224.0/19, 147.0.0.0/11, 147.32.0.0/13, 147.40.0.0/14, 147.44.0.0/16, 147.46.0.0/15, 147.48.0.0/12, 147.64.0.0/10, 147.128.0.0/9, 148.0.0.0/8, 149.0.0.0/11, 149.32.0.0/12, 149.48.0.0/13, 149.56.0.0/14, 149.60.0.0/15, 149.62.32.0/19, 149.62.64.0/18, 149.62.128.0/17, 149.63.0.0/16, 149.64.0.0/10, 149.128.0.0/12, 149.144.0.0/13, 149.152.0.0/15, 149.154.0.0/17, 149.154.144.0/20, 149.154.160.0/19, 149.154.192.0/18, 149.155.0.0/16, 149.156.0.0/14, 149.160.0.0/11, 149.192.0.0/11, 149.224.0.0/12, 149.240.0.0/13, 149.248.0.0/14, 149.252.0.0/15, 149.254.0.0/16, 149.255.32.0/19, 149.255.64.0/18, 149.255.128.0/17, 150.0.0.0/8, 151.0.64.0/18, 151.0.128.0/17, 151.1.0.0/16, 151.2.0.0/15, 151.4.0.0/14, 151.8.0.0/13, 151.16.0.0/12, 151.32.0.0/11, 151.64.0.0/10, 151.128.0.0/10, 151.192.0.0/11, 151.224.0.0/13, 151.232.0.0/14, 151.236.0.0/18, 151.236.128.0/17, 151.237.0.0/16, 151.238.0.0/15, 151.240.0.0/13, 151.248.0.0/18, 151.248.64.0/19, 151.248.96.0/20, 151.248.128.0/17, 151.249.0.0/16, 151.250.0.0/15, 151.252.0.0/18, 151.252.96.0/19, 151.252.128.0/17, 151.253.0.0/16, 151.254.0.0/15, 152.0.0.0/8, 153.0.0.0/11, 153.32.0.0/12, 153.48.0.0/15, 153.50.0.0/16, 153.51.0.0/19, 153.51.128.0/19, 153.51.192.0/18, 153.52.0.0/14, 153.56.0.0/13, 153.64.0.0/13, 153.72.0.0/14, 153.76.0.0/17, 153.76.128.0/19, 153.76.176.0/20, 153.76.192.0/18, 153.77.0.0/16, 153.78.0.0/16, 153.79.0.0/17, 153.79.128.0/19, 153.79.160.0/20, 153.79.192.0/18, 153.80.0.0/17, 153.80.128.0/19, 153.80.160.0/20, 153.80.192.0/19, 153.81.0.0/16, 153.82.0.0/15, 153.84.0.0/14, 153.88.0.0/13, 153.96.0.0/11, 153.128.0.0/9, 154.0.0.0/8, 155.0.0.0/9, 155.128.0.0/10, 155.192.0.0/12, 155.208.0.0/14, 155.212.0.0/17, 155.212.144.0/20, 155.212.208.0/20, 155.212.224.0/19, 155.213.0.0/16, 155.214.0.0/15, 155.216.0.0/13, 155.224.0.0/11, 156.0.0.0/8, 157.0.0.0/12, 157.16.0.0/14, 157.20.0.0/15, 157.22.0.0/17, 157.22.128.0/19, 157.22.208.0/20, 157.22.224.0/19, 157.23.0.0/16, 157.24.0.0/13, 157.32.0.0/11, 157.64.0.0/10, 157.128.0.0/11, 157.160.0.0/12, 157.176.0.0/13, 157.184.0.0/15, 157.187.0.0/16, 157.188.0.0/14, 157.192.0.0/10, 158.0.0.0/11, 158.32.0.0/13, 158.40.0.0/14, 158.44.0.0/15, 158.47.0.0/16, 158.48.0.0/12, 158.64.0.0/10, 158.128.0.0/11, 158.161.0.0/16, 158.162.0.0/15, 158.164.0.0/14, 158.168.0.0/13, 158.176.0.0/12, 158.192.0.0/11, 158.224.0.0/12, 158.240.0.0/13, 158.248.0.0/15, 158.251.0.0/16, 158.252.0.0/15, 158.254.0.0/16, 158.255.0.0/17, 158.255.192.0/18, 159.0.0.0/10, 159.64.0.0/12, 159.80.0.0/13, 159.88.0.0/14, 159.92.0.0/16, 159.94.0.0/15, 159.96.0.0/11, 159.128.0.0/10, 159.192.0.0/15, 159.194.0.0/17, 159.194.128.0/18, 159.194.192.0/20, 159.195.0.0/16, 159.196.0.0/14, 159.200.0.0/17, 159.200.192.0/18, 159.201.0.0/16, 159.202.0.0/15, 159.204.0.0/14, 159.208.0.0/12, 159.224.0.0/12, 159.240.0.0/13, 159.248.0.0/14, 159.252.0.0/15, 159.254.0.0/16, 159.255.32.0/19, 159.255.128.0/17, 160.0.0.0/14, 160.4.0.0/16, 160.5.0.0/17, 160.5.128.0/18, 160.5.192.0/20, 160.5.224.0/19, 160.6.0.0/15, 160.8.0.0/13, 160.16.0.0/12, 160.32.0.0/11, 160.64.0.0/10, 160.128.0.0/9, 161.0.0.0/10, 161.64.0.0/11, 161.96.0.0/13, 161.104.0.0/20, 161.104.64.0/19, 161.104.112.0/20, 161.104.128.0/17, 161.105.0.0/16, 161.106.0.0/15, 161.108.0.0/14, 161.112.0.0/12, 161.128.0.0/9, 162.0.0.0/7, 164.0.0.0/9, 164.128.0.0/10, 164.192.0.0/12, 164.208.0.0/14, 164.212.0.0/15, 164.214.0.0/16, 164.215.0.0/18, 164.215.96.0/19, 164.215.128.0/17, 164.216.0.0/13, 164.224.0.0/11, 165.0.0.0/8, 166.0.0.0/7, 168.0.0.0/10, 168.64.0.0/11, 168.96.0.0/12, 168.112.0.0/16, 168.113.0.0/17, 168.113.208.0/20, 168.113.224.0/20, 168.114.0.0/15, 168.116.0.0/14, 168.120.0.0/13, 168.128.0.0/10, 168.192.0.0/12, 168.208.0.0/13, 168.216.0.0/14, 168.220.0.0/15, 168.222.0.0/17, 168.222.144.0/20, 168.222.160.0/19, 168.222.208.0/20, 168.222.224.0/19, 168.223.0.0/16, 168.224.0.0/11, 169.0.0.0/9, 169.128.0.0/10, 169.192.0.0/11, 169.224.0.0/12, 169.240.0.0/13, 169.248.0.0/14, 169.252.0.0/15, 169.255.0.0/16, 170.0.0.0/7, 172.0.0.0/12, 172.32.0.0/11, 172.64.0.0/10, 172.128.0.0/9, 173.0.0.0/8, 174.0.0.0/7, 176.0.0.0/13, 176.8.0.0/14, 176.12.0.0/18, 176.12.80.0/20, 176.12.96.0/19, 176.12.128.0/17, 176.13.0.0/16, 176.16.0.0/12, 176.32.0.0/17, 176.32.160.0/20, 176.32.192.0/18, 176.33.0.0/16, 176.34.0.0/15, 176.36.0.0/14, 176.40.0.0/13, 176.52.128.0/17, 176.53.0.0/17, 176.53.128.0/18, 176.53.208.0/20, 176.54.0.0/15, 176.56.32.0/19, 176.56.64.0/18, 176.56.128.0/17, 176.57.0.0/17, 176.57.128.0/18, 176.57.192.0/20, 176.57.224.0/19, 176.58.0.0/19, 176.58.64.0/18, 176.58.128.0/17, 176.60.0.0/15, 176.62.0.0/18, 176.62.128.0/19, 176.62.160.0/20, 176.62.192.0/19, 176.62.224.0/20, 176.63.0.0/16, 176.64.0.0/16, 176.65.0.0/19, 176.65.64.0/19, 176.65.128.0/17, 176.66.0.0/15, 176.68.0.0/14, 176.72.0.0/14, 176.76.0.0/16, 176.77.128.0/17, 176.78.0.0/15, 176.80.0.0/12, 176.96.32.0/19, 176.96.64.0/18, 176.96.128.0/17, 176.97.0.0/19, 176.97.48.0/20, 176.97.64.0/19, 176.97.112.0/20, 176.97.128.0/19, 176.97.192.0/18, 176.98.0.0/17, 176.98.160.0/19, 176.98.192.0/18, 176.99.16.0/20, 176.99.32.0/19, 176.100.0.0/18, 176.100.160.0/19, 176.100.192.0/19, 176.100.224.0/20, 176.101.16.0/20, 176.101.32.0/19, 176.101.64.0/19, 176.101.128.0/18, 176.101.192.0/19, 176.102.32.0/19, 176.102.64.0/18, 176.102.128.0/17, 176.103.0.0/18, 176.103.64.0/19, 176.103.112.0/20, 176.103.128.0/17, 176.104.0.0/17, 176.104.176.0/20, 176.104.224.0/19, 176.105.0.0/16, 176.106.0.0/20, 176.106.32.0/19, 176.106.96.0/19, 176.106.128.0/20, 176.106.160.0/19, 176.106.192.0/19, 176.106.224.0/20, 176.107.16.0/20, 176.107.32.0/19, 176.107.64.0/18, 176.107.128.0/18, 176.107.192.0/20, 176.108.0.0/17, 176.108.128.0/20, 176.108.224.0/20, 176.109.48.0/20, 176.109.128.0/20, 176.109.160.0/20, 176.109.192.0/19, 176.110.0.0/18, 176.110.96.0/19, 176.110.144.0/20, 176.110.208.0/20, 176.111.0.0/18, 176.111.80.0/20, 176.111.96.0/19, 176.111.128.0/17, 176.112.0.0/19, 176.112.64.0/19, 176.112.112.0/20, 176.112.144.0/20, 176.112.176.0/20, 176.113.32.0/20, 176.113.64.0/18, 176.113.128.0/18, 176.113.192.0/19, 176.114.0.0/20, 176.114.48.0/20, 176.114.96.0/20, 176.114.224.0/19, 176.115.0.0/19, 176.115.80.0/20, 176.115.96.0/20, 176.115.160.0/19, 176.115.224.0/19, 176.116.0.0/19, 176.116.32.0/20, 176.116.64.0/18, 176.116.128.0/19, 176.116.192.0/20, 176.116.224.0/20, 176.117.48.0/20, 176.117.64.0/19, 176.117.96.0/20, 176.117.160.0/19, 176.118.0.0/20, 176.118.32.0/19, 176.118.80.0/20, 176.118.96.0/20, 176.118.128.0/18, 176.118.192.0/20, 176.119.0.0/17, 176.119.128.0/19, 176.119.192.0/18, 176.120.16.0/20, 176.120.32.0/19, 176.120.64.0/20, 176.120.96.0/19, 176.120.128.0/19, 176.120.160.0/20, 176.121.0.0/17, 176.121.224.0/19, 176.122.0.0/20, 176.122.32.0/20, 176.122.80.0/20, 176.122.96.0/19, 176.122.128.0/17, 176.123.0.0/17, 176.123.176.0/20, 176.123.208.0/20, 176.123.224.0/19, 176.124.32.0/19, 176.124.64.0/18, 176.124.128.0/18, 176.124.224.0/19, 176.125.0.0/18, 176.125.224.0/19, 176.126.32.0/19, 176.126.64.0/18, 176.126.128.0/17, 176.127.0.0/16, 176.128.0.0/10, 176.198.0.0/15, 176.200.0.0/13, 176.216.0.0/14, 176.220.0.0/16, 176.221.32.0/19, 176.221.64.0/18, 176.221.128.0/17, 176.222.0.0/17, 176.222.128.0/18, 176.222.208.0/20, 176.222.224.0/20, 176.223.0.0/16, 176.224.0.0/15, 176.226.0.0/17, 176.227.0.0/17, 176.227.128.0/19, 176.227.160.0/20, 176.227.192.0/18, 176.228.0.0/14, 176.232.0.0/13, 176.240.0.0/16, 176.241.0.0/17, 176.241.128.0/18, 176.241.224.0/19, 176.242.0.0/15, 176.244.0.0/14, 176.248.0.0/13, 177.0.0.0/8, 178.0.0.0/12, 178.16.0.0/18, 178.16.64.0/20, 178.16.96.0/19, 178.16.128.0/17, 178.17.0.0/17, 178.17.144.0/20, 178.17.160.0/20, 178.17.208.0/20, 178.17.224.0/19, 178.18.16.0/20, 178.18.32.0/19, 178.18.64.0/19, 178.18.112.0/20, 178.18.128.0/18, 178.18.192.0/20, 178.18.224.0/19, 178.19.0.0/17, 178.19.128.0/18, 178.19.192.0/19, 178.19.224.0/20, 178.20.0.0/14, 178.24.0.0/13, 178.32.0.0/15, 178.36.0.0/14, 178.40.0.0/14, 178.48.0.0/16, 178.50.0.0/15, 178.52.0.0/14, 178.56.0.0/16, 178.57.64.0/20, 178.57.128.0/18, 178.58.0.0/15, 178.60.0.0/14, 178.72.0.0/18, 178.72.192.0/18, 178.73.0.0/16, 178.74.0.0/18, 178.74.192.0/18, 178.75.128.0/17, 178.76.0.0/17, 178.76.128.0/18, 178.77.0.0/16, 178.78.64.0/18, 178.78.128.0/17, 178.79.0.0/16, 178.80.0.0/12, 178.96.0.0/11, 178.128.0.0/16, 178.130.32.0/20, 178.130.64.0/18, 178.130.144.0/20, 178.130.160.0/19, 178.130.192.0/18, 178.131.0.0/16, 178.132.0.0/14, 178.136.0.0/14, 178.142.0.0/15, 178.144.0.0/13, 178.152.0.0/15, 178.154.0.0/17, 178.155.128.0/17, 178.156.0.0/16, 178.157.0.0/17, 178.157.192.0/18, 178.158.128.0/17, 178.159.0.0/20, 178.159.32.0/20, 178.159.64.0/20, 178.159.96.0/20, 178.159.128.0/17, 178.160.0.0/16, 178.161.0.0/17, 178.162.128.0/17, 178.163.128.0/17, 178.164.0.0/15, 178.166.0.0/17, 178.167.128.0/17, 178.168.0.0/16, 178.169.0.0/19, 178.169.128.0/17, 178.170.0.0/16, 178.171.128.0/17, 178.172.0.0/16, 178.173.128.0/17, 178.174.0.0/15, 178.180.0.0/14, 178.188.0.0/14, 178.192.0.0/13, 178.200.0.0/14, 178.208.0.0/18, 178.208.96.0/19, 178.208.160.0/19, 178.208.192.0/19, 178.209.0.0/18, 178.209.64.0/19, 178.209.128.0/18, 178.210.96.0/19, 178.210.128.0/17, 178.211.32.0/19, 178.211.64.0/18, 178.211.128.0/19, 178.211.192.0/18, 178.212.0.0/16, 178.213.0.0/20, 178.213.32.0/19, 178.213.64.0/18, 178.213.128.0/18, 178.213.208.0/20, 178.213.224.0/20, 178.214.0.0/19, 178.214.64.0/18, 178.214.128.0/19, 178.214.192.0/19, 178.215.0.0/18, 178.215.128.0/20, 178.215.160.0/19, 178.215.192.0/18, 178.216.0.0/18, 178.216.80.0/20, 178.216.96.0/19, 178.216.128.0/17, 178.217.0.0/19, 178.217.32.0/20, 178.217.80.0/20, 178.217.96.0/19, 178.217.128.0/17, 178.218.64.0/20, 178.218.128.0/18, 178.218.192.0/20, 178.218.224.0/19, 178.219.0.0/17, 178.219.128.0/19, 178.219.224.0/20, 178.220.0.0/14, 178.224.0.0/13, 178.232.0.0/15, 178.235.0.0/16, 178.236.0.0/20, 178.236.32.0/19, 178.236.64.0/18, 178.236.144.0/20, 178.236.160.0/19, 178.236.192.0/20, 178.236.224.0/20, 178.237.0.0/20, 178.237.32.0/19, 178.237.64.0/18, 178.237.128.0/19, 178.237.160.0/20, 178.237.208.0/20, 178.237.224.0/20, 178.238.0.0/20, 178.238.32.0/19, 178.238.64.0/19, 178.238.96.0/20, 178.238.128.0/17, 178.239.0.0/16, 178.240.0.0/13, 178.248.0.0/16, 178.249.0.0/18, 178.249.80.0/20, 178.249.96.0/19, 178.249.128.0/17, 178.250.0.0/15, 178.252.0.0/18, 178.252.128.0/18, 178.253.0.0/16, 178.254.0.0/15, 179.0.0.0/8, 180.0.0.0/6, 184.0.0.0/8, 185.0.0.0/10, 185.64.0.0/12, 185.80.0.0/14, 185.84.0.0/15, 185.86.0.0/18, 185.86.64.0/19, 185.86.96.0/20, 185.86.128.0/17, 185.87.0.0/16, 185.88.0.0/13, 185.96.0.0/11, 185.128.0.0/9, 186.0.0.0/7, 188.0.32.0/19, 188.0.64.0/18, 188.0.128.0/19, 188.0.224.0/19, 188.1.0.0/16, 188.2.0.0/15, 188.4.0.0/14, 188.8.0.0/13, 188.20.0.0/14, 188.24.0.0/13, 188.33.0.0/16, 188.34.0.0/16, 188.36.0.0/14, 188.40.0.0/15, 188.42.0.0/16, 188.44.0.0/19, 188.44.64.0/19, 188.44.128.0/17, 188.45.0.0/16, 188.46.0.0/15, 188.48.0.0/12, 188.64.0.0/14, 188.68.0.0/20, 188.68.32.0/19, 188.68.64.0/20, 188.68.160.0/20, 188.68.224.0/19, 188.69.0.0/16, 188.70.0.0/15, 188.72.0.0/16, 188.73.0.0/17, 188.73.192.0/18, 188.74.0.0/16, 188.75.64.0/18, 188.75.128.0/18, 188.76.0.0/14, 188.80.0.0/13, 188.88.0.0/14, 188.92.0.0/16, 188.93.0.0/20, 188.93.32.0/20, 188.93.64.0/18, 188.93.128.0/17, 188.94.0.0/17, 188.94.128.0/19, 188.94.176.0/20, 188.94.192.0/18, 188.95.0.0/16, 188.96.0.0/12, 188.112.0.0/17, 188.112.128.0/18, 188.113.64.0/18, 188.113.192.0/18, 188.114.64.0/18, 188.114.128.0/18, 188.114.224.0/19, 188.115.0.0/16, 188.116.0.0/17, 188.116.192.0/18, 188.117.0.0/16, 188.118.0.0/15, 188.120.0.0/19, 188.120.32.0/20, 188.120.64.0/18, 188.120.128.0/18, 188.120.192.0/19, 188.121.0.0/16, 188.122.0.0/17, 188.122.128.0/19, 188.122.192.0/19, 188.123.0.0/19, 188.123.64.0/18, 188.123.128.0/18, 188.123.192.0/19, 188.124.0.0/19, 188.124.48.0/20, 188.124.64.0/19, 188.124.128.0/17, 188.125.0.0/16, 188.126.0.0/19, 188.126.64.0/18, 188.126.128.0/17, 188.127.0.0/17, 188.127.128.0/18, 188.127.192.0/19, 188.127.240.0/20, 188.128.128.0/17, 188.129.0.0/16, 188.130.0.0/15, 188.132.0.0/16, 188.133.0.0/17, 188.134.128.0/17, 188.135.0.0/16, 188.136.0.0/14, 188.140.0.0/15, 188.142.0.0/16, 188.143.0.0/17, 188.144.0.0/12, 188.160.0.0/15, 188.163.0.0/16, 188.164.0.0/17, 188.164.128.0/19, 188.164.192.0/18, 188.165.0.0/16, 188.166.0.0/15, 188.169.0.0/16, 188.171.0.0/16, 188.172.0.0/14, 188.176.0.0/13, 188.184.0.0/15, 188.188.0.0/15, 188.190.0.0/17, 188.190.160.0/19, 188.190.224.0/19, 188.191.32.0/19, 188.191.64.0/20, 188.191.96.0/20, 188.191.128.0/19, 188.191.176.0/20, 188.191.192.0/18, 188.192.0.0/11, 188.224.0.0/16, 188.225.128.0/17, 188.226.128.0/17, 188.227.48.0/20, 188.227.80.0/20, 188.227.96.0/20, 188.227.128.0/17, 188.228.0.0/14, 188.236.0.0/14, 188.240.0.0/15, 188.244.16.0/20, 188.244.48.0/20, 188.244.64.0/18, 188.245.0.0/16, 188.246.0.0/17, 188.246.128.0/19, 188.246.192.0/18, 188.247.0.0/19, 188.247.64.0/18, 188.247.128.0/17, 188.248.0.0/14, 188.252.0.0/15, 188.254.128.0/17, 188.255.128.0/17, 189.0.0.0/8, 190.0.0.0/7, 192.0.0.0/9, 192.128.0.0/11, 192.160.0.0/13, 192.169.0.0/16, 192.170.0.0/15, 192.172.0.0/14, 192.176.0.0/12, 192.192.0.0/10, 193.0.0.0/9, 193.128.0.0/12, 193.144.0.0/14, 193.148.0.0/15, 193.150.0.0/16, 193.151.0.0/17, 193.151.128.0/18, 193.151.224.0/19, 193.152.0.0/13, 193.160.0.0/11, 193.192.0.0/17, 193.192.160.0/19, 193.192.192.0/18, 193.193.0.0/16, 193.194.0.0/15, 193.196.0.0/14, 193.200.0.0/13, 193.208.0.0/12, 193.224.0.0/13, 193.234.0.0/15, 193.236.0.0/14, 193.240.0.0/12, 194.0.0.0/13, 194.8.0.0/17, 194.8.128.0/19, 194.8.192.0/18, 194.9.0.0/17, 194.9.128.0/18, 194.9.192.0/19, 194.9.240.0/20, 194.10.0.0/15, 194.12.0.0/19, 194.12.32.0/20, 194.12.64.0/19, 194.12.128.0/17, 194.13.0.0/16, 194.14.0.0/15, 194.16.0.0/12, 194.32.0.0/12, 194.48.0.0/13, 194.56.0.0/15, 194.58.0.0/18, 194.58.64.0/19, 194.58.128.0/19, 194.58.192.0/18, 194.59.0.0/16, 194.60.0.0/14, 194.64.0.0/15, 194.66.0.0/16, 194.67.80.0/20, 194.67.192.0/19, 194.68.0.0/14, 194.72.0.0/13, 194.80.0.0/14, 194.85.240.0/20, 194.86.0.0/15, 194.88.0.0/13, 194.96.0.0/13, 194.104.0.0/16, 194.105.0.0/17, 194.105.128.0/18, 194.105.224.0/19, 194.106.0.0/15, 194.108.0.0/14, 194.112.0.0/12, 194.128.0.0/14, 194.132.0.0/15, 194.134.0.0/16, 194.135.0.0/17, 194.135.128.0/18, 194.135.192.0/20, 194.135.240.0/20, 194.136.0.0/13, 194.144.0.0/14, 194.148.0.0/15, 194.150.0.0/17, 194.150.160.0/19, 194.150.192.0/18, 194.151.0.0/16, 194.152.0.0/15, 194.154.0.0/18, 194.154.96.0/19, 194.154.128.0/17, 194.155.0.0/16, 194.156.0.0/14, 194.160.0.0/12, 194.176.0.0/13, 194.184.0.0/15, 194.187.0.0/16, 194.188.0.0/15, 194.191.0.0/16, 194.192.0.0/11, 194.224.0.0/15, 194.227.0.0/16, 194.228.0.0/14, 194.232.0.0/13, 194.240.0.0/14, 194.244.0.0/15, 194.246.0.0/16, 194.247.0.0/17, 194.247.160.0/19, 194.247.192.0/18, 194.248.0.0/13, 195.0.0.0/15, 195.2.0.0/18, 195.2.80.0/20, 195.2.96.0/19, 195.2.128.0/17, 195.3.0.0/16, 195.4.0.0/16, 195.5.0.0/17, 195.5.160.0/19, 195.5.192.0/18, 195.6.0.0/16, 195.7.0.0/17, 195.7.128.0/19, 195.7.192.0/18, 195.8.0.0/16, 195.10.0.0/15, 195.12.0.0/18, 195.12.96.0/19, 195.12.128.0/17, 195.13.0.0/16, 195.14.0.0/19, 195.14.64.0/18, 195.14.128.0/17, 195.15.0.0/16, 195.16.0.0/19, 195.16.64.0/19, 195.16.128.0/17, 195.17.0.0/16, 195.18.0.0/19, 195.18.64.0/18, 195.18.128.0/17, 195.20.0.0/14, 195.24.0.0/15, 195.26.0.0/17, 195.26.128.0/19, 195.26.192.0/18, 195.27.0.0/16, 195.28.0.0/19, 195.28.64.0/18, 195.28.128.0/17, 195.29.0.0/16, 195.30.0.0/15, 195.32.0.0/15, 195.34.64.0/18, 195.34.128.0/18, 195.34.192.0/19, 195.35.0.0/16, 195.36.0.0/15, 195.38.0.0/19, 195.38.64.0/18, 195.38.128.0/17, 195.39.0.0/16, 195.40.0.0/15, 195.42.0.0/18, 195.42.96.0/19, 195.42.128.0/19, 195.42.192.0/18, 195.43.0.0/16, 195.44.0.0/15, 195.46.0.0/18, 195.46.64.0/19, 195.46.128.0/19, 195.46.192.0/18, 195.47.0.0/16, 195.48.0.0/16, 195.49.0.0/17, 195.49.128.0/18, 195.49.208.0/20, 195.49.224.0/19, 195.50.0.0/15, 195.52.0.0/15, 195.54.32.0/19, 195.54.64.0/18, 195.54.128.0/18, 195.54.224.0/19, 195.55.0.0/16, 195.56.0.0/15, 195.58.32.0/19, 195.58.64.0/18, 195.58.128.0/17, 195.59.0.0/16, 195.60.0.0/14, 195.64.0.0/17, 195.64.128.0/18, 195.64.224.0/19, 195.65.0.0/16, 195.66.0.0/15, 195.68.0.0/17, 195.68.192.0/18, 195.69.0.0/16, 195.70.0.0/17, 195.70.128.0/18, 195.70.224.0/19, 195.71.0.0/16, 195.72.0.0/17, 195.72.128.0/18, 195.72.192.0/19, 195.73.0.0/16, 195.74.0.0/15, 195.76.0.0/14, 195.80.0.0/13, 195.88.0.0/15, 195.90.0.0/17, 195.90.192.0/18, 195.91.0.0/17, 195.92.0.0/15, 195.94.0.0/17, 195.94.128.0/18, 195.94.192.0/19, 195.95.0.0/16, 195.96.0.0/18, 195.96.96.0/19, 195.96.128.0/19, 195.96.192.0/18, 195.97.0.0/16, 195.98.0.0/19, 195.98.96.0/19, 195.98.128.0/19, 195.98.192.0/18, 195.99.0.0/16, 195.100.0.0/14, 195.104.0.0/13, 195.112.0.0/18, 195.112.64.0/19, 195.112.128.0/18, 195.112.192.0/19, 195.113.0.0/16, 195.114.0.0/15, 195.116.0.0/14, 195.120.0.0/15, 195.122.0.0/17, 195.122.128.0/18, 195.122.192.0/19, 195.123.0.0/16, 195.124.0.0/14, 195.128.0.0/19, 195.128.32.0/20, 195.128.96.0/19, 195.128.128.0/17, 195.129.0.0/16, 195.130.0.0/16, 195.132.0.0/16, 195.133.0.0/17, 195.133.128.0/18, 195.133.192.0/19, 195.134.0.0/15, 195.136.0.0/13, 195.144.0.0/17, 195.144.128.0/18, 195.145.0.0/16, 195.146.0.0/18, 195.146.96.0/19, 195.146.128.0/17, 195.147.0.0/16, 195.148.0.0/15, 195.150.0.0/16, 195.152.0.0/13, 195.160.0.0/16, 195.162.0.0/19, 195.162.64.0/18, 195.162.128.0/17, 195.163.0.0/16, 195.164.0.0/15, 195.166.0.0/17, 195.166.128.0/19, 195.166.192.0/18, 195.167.0.0/16, 195.168.0.0/15, 195.170.0.0/19, 195.170.64.0/18, 195.170.128.0/18, 195.171.0.0/16, 195.172.0.0/14, 195.176.0.0/15, 195.178.0.0/17, 195.178.128.0/18, 195.178.224.0/19, 195.179.0.0/16, 195.180.0.0/15, 195.182.0.0/17, 195.182.160.0/19, 195.182.192.0/18, 195.183.0.0/16, 195.184.0.0/17, 195.184.128.0/18, 195.184.224.0/19, 195.185.0.0/16, 195.186.0.0/15, 195.188.0.0/15, 195.190.0.0/18, 195.190.64.0/19, 195.190.128.0/17, 195.191.0.0/16, 195.192.0.0/13, 195.200.0.0/14, 195.204.0.0/15, 195.206.0.0/19, 195.206.64.0/18, 195.206.128.0/17, 195.207.0.0/16, 195.210.0.0/17, 195.210.192.0/18, 195.211.0.0/16, 195.212.0.0/14, 195.216.0.0/15, 195.218.0.0/17, 195.219.0.0/16, 195.220.0.0/15, 195.222.0.0/17, 195.222.192.0/18, 195.223.0.0/16, 195.224.0.0/14, 195.228.0.0/15, 195.230.0.0/18, 195.230.96.0/19, 195.230.128.0/17, 195.231.0.0/16, 195.232.0.0/14, 195.236.0.0/15, 195.238.0.0/16, 195.240.0.0/12, 196.0.0.0/6, 200.0.0.0/7, 202.0.0.0/8, 203.0.0.0/10, 203.64.0.0/12, 203.80.0.0/16, 203.81.0.0/17, 203.81.128.0/18, 203.81.192.0/20, 203.81.224.0/19, 203.82.0.0/15, 203.84.0.0/14, 203.88.0.0/13, 203.96.0.0/11, 203.128.0.0/9, 204.0.0.0/6, 208.0.0.0/6, 212.0.0.0/18, 212.0.96.0/19, 212.0.128.0/17, 212.1.0.0/17, 212.1.128.0/18, 212.1.192.0/19, 212.2.0.0/16, 212.3.0.0/17, 212.3.160.0/19, 212.3.192.0/18, 212.4.0.0/16, 212.5.0.0/18, 212.5.128.0/19, 212.5.192.0/19, 212.6.32.0/19, 212.6.64.0/18, 212.6.128.0/17, 212.7.0.0/18, 212.7.64.0/19, 212.7.128.0/18, 212.7.192.0/19, 212.8.0.0/15, 212.10.0.0/16, 212.11.0.0/17, 212.11.160.0/19, 212.11.192.0/18, 212.12.32.0/19, 212.12.96.0/19, 212.12.128.0/17, 212.13.32.0/19, 212.13.64.0/19, 212.13.128.0/17, 212.14.0.0/17, 212.14.128.0/19, 212.14.224.0/19, 212.15.0.0/19, 212.15.64.0/19, 212.15.128.0/17, 212.16.32.0/19, 212.16.64.0/18, 212.16.128.0/18, 212.16.224.0/19, 212.17.32.0/19, 212.17.64.0/18, 212.17.128.0/17, 212.18.0.0/16, 212.19.32.0/19, 212.19.64.0/18, 212.19.128.0/17, 212.20.64.0/18, 212.20.128.0/17, 212.21.32.0/19, 212.21.64.0/18, 212.21.128.0/17, 212.22.0.0/18, 212.22.96.0/19, 212.22.128.0/17, 212.23.0.0/18, 212.23.96.0/19, 212.23.128.0/17, 212.24.0.0/19, 212.24.64.0/18, 212.24.128.0/17, 212.25.0.0/16, 212.26.0.0/17, 212.26.128.0/18, 212.26.192.0/19, 212.27.0.0/16, 212.28.0.0/15, 212.30.0.0/17, 212.30.192.0/18, 212.31.0.0/16, 212.32.0.0/17, 212.32.128.0/18, 212.32.224.0/19, 212.33.32.0/19, 212.33.64.0/18, 212.33.128.0/18, 212.33.192.0/19, 212.34.0.0/19, 212.34.64.0/19, 212.34.128.0/17, 212.35.0.0/17, 212.35.128.0/19, 212.35.192.0/18, 212.36.0.0/17, 212.36.128.0/18, 212.36.192.0/19, 212.37.0.0/16, 212.38.0.0/18, 212.38.64.0/19, 212.38.128.0/17, 212.39.0.0/16, 212.40.0.0/17, 212.40.128.0/18, 212.40.224.0/19, 212.41.64.0/18, 212.41.128.0/17, 212.42.0.0/19, 212.42.64.0/18, 212.42.128.0/17, 212.43.0.0/16, 212.44.0.0/18, 212.44.96.0/19, 212.44.160.0/19, 212.44.192.0/18, 212.45.32.0/19, 212.45.64.0/18, 212.45.128.0/18, 212.45.192.0/19, 212.46.32.0/19, 212.46.64.0/18, 212.46.128.0/18, 212.47.0.0/16, 212.48.0.0/19, 212.48.64.0/18, 212.48.160.0/19, 212.48.240.0/20, 212.49.0.0/18, 212.49.64.0/19, 212.49.128.0/17, 212.50.0.0/15, 212.52.0.0/16, 212.53.0.0/19, 212.53.64.0/18, 212.53.128.0/17, 212.54.0.0/16, 212.55.0.0/18, 212.55.64.0/19, 212.55.128.0/17, 212.56.0.0/16, 212.57.0.0/18, 212.57.64.0/19, 212.57.192.0/18, 212.58.0.0/17, 212.58.128.0/18, 212.58.224.0/19, 212.59.0.0/18, 212.59.64.0/19, 212.59.128.0/17, 212.60.0.0/14, 212.64.0.0/16, 212.65.0.0/18, 212.65.96.0/19, 212.65.128.0/17, 212.66.0.0/19, 212.66.48.0/20, 212.66.64.0/18, 212.66.128.0/17, 212.67.32.0/19, 212.67.64.0/18, 212.67.128.0/17, 212.68.0.0/16, 212.69.0.0/18, 212.69.64.0/19, 212.69.128.0/17, 212.70.0.0/15, 212.72.0.0/16, 212.73.0.0/18, 212.73.64.0/19, 212.73.128.0/17, 212.74.0.0/17, 212.74.128.0/18, 212.75.0.0/17, 212.75.160.0/19, 212.76.0.0/17, 212.76.192.0/18, 212.77.0.0/17, 212.77.160.0/19, 212.77.192.0/18, 212.78.0.0/15, 212.80.0.0/15, 212.82.0.0/16, 212.83.32.0/19, 212.83.64.0/18, 212.83.128.0/17, 212.84.0.0/14, 212.88.0.0/15, 212.90.0.0/16, 212.91.0.0/17, 212.91.128.0/18, 212.91.224.0/19, 212.92.0.0/17, 212.92.192.0/18, 212.93.0.0/16, 212.94.32.0/19, 212.94.64.0/19, 212.94.128.0/17, 212.95.0.0/16, 212.96.0.0/18, 212.96.64.0/19, 212.96.128.0/18, 212.96.224.0/19, 212.97.0.0/16, 212.98.0.0/15, 212.100.0.0/17, 212.100.160.0/19, 212.100.192.0/18, 212.101.0.0/16, 212.102.0.0/16, 212.103.0.0/18, 212.103.64.0/19, 212.103.128.0/17, 212.104.0.0/18, 212.104.96.0/19, 212.104.128.0/17, 212.105.0.0/16, 212.106.0.0/19, 212.106.64.0/18, 212.106.128.0/17, 212.107.0.0/17, 212.107.128.0/18, 212.108.0.0/16, 212.109.32.0/19, 212.109.64.0/18, 212.109.128.0/18, 212.109.224.0/19, 212.110.0.0/16, 212.111.0.0/18, 212.111.80.0/20, 212.111.96.0/19, 212.111.128.0/17, 212.112.0.0/16, 212.113.0.0/18, 212.113.64.0/19, 212.113.128.0/18, 212.113.192.0/19, 212.114.0.0/15, 212.116.0.0/18, 212.116.64.0/19, 212.116.128.0/17, 212.117.0.0/16, 212.118.0.0/16, 212.119.0.0/18, 212.119.64.0/19, 212.119.128.0/19, 212.120.0.0/17, 212.120.128.0/19, 212.120.192.0/18, 212.121.0.0/16, 212.122.32.0/19, 212.122.64.0/18, 212.122.128.0/17, 212.123.0.0/16, 212.124.32.0/19, 212.124.64.0/19, 212.124.128.0/17, 212.125.0.0/16, 212.126.0.0/15, 212.128.0.0/16, 212.129.0.0/18, 212.129.64.0/19, 212.129.128.0/17, 212.130.0.0/15, 212.132.0.0/14, 212.136.0.0/13, 212.144.0.0/13, 212.152.0.0/19, 212.152.64.0/18, 212.152.128.0/17, 212.153.0.0/16, 212.154.0.0/15, 212.156.0.0/15, 212.158.0.0/17, 212.158.128.0/19, 212.158.176.0/20, 212.158.192.0/18, 212.159.0.0/16, 212.160.0.0/14, 212.165.0.0/16, 212.166.0.0/15, 212.168.0.0/13, 212.177.0.0/16, 212.178.0.0/15, 212.180.0.0/14, 212.184.0.0/14, 212.188.128.0/17, 212.189.0.0/16, 212.190.0.0/15, 212.192.0.0/19, 212.192.208.0/20, 212.192.240.0/20, 212.193.0.0/19, 212.194.0.0/15, 212.196.0.0/14, 212.200.0.0/13, 212.208.0.0/13, 212.216.0.0/14, 212.221.0.0/16, 212.222.0.0/15, 212.224.0.0/13, 212.232.16.0/20, 212.232.64.0/18, 212.232.128.0/17, 212.233.0.0/16, 212.234.0.0/15, 212.236.0.0/14, 212.240.0.0/13, 212.248.128.0/17, 212.249.0.0/16, 212.250.0.0/15, 212.252.0.0/14, 213.0.0.0/14, 213.4.0.0/16, 213.5.0.0/18, 213.5.64.0/19, 213.5.112.0/20, 213.5.128.0/17, 213.6.0.0/15, 213.8.0.0/13, 213.16.0.0/13, 213.25.0.0/16, 213.26.0.0/16, 213.27.128.0/17, 213.28.0.0/14, 213.32.0.0/16, 213.33.0.0/17, 213.34.0.0/15, 213.36.0.0/14, 213.40.0.0/13, 213.48.0.0/13, 213.56.0.0/15, 213.58.0.0/16, 213.59.112.0/20, 213.60.0.0/14, 213.64.0.0/13, 213.72.0.0/14, 213.76.0.0/15, 213.78.0.0/16, 213.79.32.0/19, 213.79.128.0/17, 213.80.0.0/17, 213.81.0.0/16, 213.82.0.0/15, 213.84.0.0/16, 213.86.0.0/16, 213.88.128.0/17, 213.89.0.0/16, 213.90.0.0/15, 213.92.0.0/14, 213.96.0.0/13, 213.104.0.0/14, 213.108.0.0/17, 213.108.128.0/18, 213.108.192.0/20, 213.108.224.0/19, 213.109.32.0/20, 213.109.64.0/18, 213.109.128.0/17, 213.110.64.0/18, 213.110.128.0/18, 213.110.224.0/20, 213.111.0.0/16, 213.112.0.0/12, 213.128.32.0/19, 213.128.64.0/18, 213.128.128.0/18, 213.128.224.0/19, 213.129.0.0/19, 213.129.64.0/19, 213.129.128.0/17, 213.130.0.0/16, 213.131.32.0/19, 213.131.64.0/18, 213.131.128.0/17, 213.132.0.0/18, 213.132.96.0/19, 213.132.128.0/17, 213.133.0.0/16, 213.134.0.0/17, 213.134.128.0/18, 213.134.224.0/19, 213.135.0.0/18, 213.135.160.0/19, 213.135.192.0/18, 213.136.0.0/16, 213.137.0.0/17, 213.137.128.0/18, 213.137.192.0/19, 213.138.0.0/18, 213.138.96.0/19, 213.138.128.0/18, 213.138.208.0/20, 213.138.224.0/19, 213.139.0.0/16, 213.140.0.0/18, 213.140.64.0/19, 213.140.128.0/18, 213.140.192.0/19, 213.141.0.0/17, 213.141.160.0/19, 213.141.192.0/19, 213.142.0.0/19, 213.142.64.0/18, 213.142.128.0/18, 213.142.224.0/19, 213.143.0.0/16, 213.144.0.0/16, 213.145.64.0/18, 213.145.128.0/17, 213.146.0.0/16, 213.147.0.0/19, 213.147.64.0/18, 213.147.128.0/18, 213.147.224.0/19, 213.148.0.0/17, 213.148.128.0/19, 213.148.192.0/18, 213.149.32.0/19, 213.149.64.0/18, 213.149.128.0/17, 213.150.0.0/18, 213.150.96.0/19, 213.150.128.0/17, 213.151.32.0/19, 213.151.64.0/18, 213.151.128.0/17, 213.152.0.0/17, 213.152.160.0/19, 213.152.192.0/18, 213.153.0.0/16, 213.154.0.0/17, 213.154.128.0/19, 213.154.192.0/18, 213.155.0.0/17, 213.155.128.0/18, 213.155.224.0/19, 213.156.0.0/17, 213.156.128.0/18, 213.156.224.0/19, 213.157.0.0/16, 213.158.32.0/19, 213.158.64.0/18, 213.158.128.0/17, 213.159.0.0/17, 213.159.128.0/18, 213.159.224.0/19, 213.160.0.0/14, 213.164.0.0/16, 213.165.0.0/17, 213.165.128.0/18, 213.165.224.0/19, 213.166.0.0/16, 213.167.0.0/19, 213.167.64.0/18, 213.167.128.0/18, 213.167.224.0/19, 213.168.0.0/19, 213.168.64.0/18, 213.168.160.0/19, 213.168.192.0/18, 213.169.0.0/16, 213.170.0.0/18, 213.170.128.0/17, 213.171.64.0/18, 213.171.128.0/17, 213.172.32.0/19, 213.172.64.0/18, 213.172.128.0/17, 213.173.0.0/16, 213.174.0.0/15, 213.176.0.0/17, 213.176.128.0/18, 213.176.192.0/19, 213.177.0.0/18, 213.177.64.0/19, 213.177.128.0/17, 213.178.0.0/19, 213.178.64.0/18, 213.178.128.0/17, 213.179.0.0/16, 213.180.0.0/17, 213.180.128.0/18, 213.180.224.0/19, 213.181.32.0/19, 213.181.64.0/18, 213.181.128.0/17, 213.182.0.0/17, 213.182.128.0/19, 213.182.192.0/18, 213.183.0.0/18, 213.183.64.0/19, 213.183.128.0/18, 213.183.192.0/19, 213.184.0.0/17, 213.184.160.0/19, 213.184.192.0/18, 213.185.0.0/16, 213.186.0.0/16, 213.187.0.0/18, 213.187.64.0/19, 213.187.128.0/17, 213.188.0.0/16, 213.189.0.0/17, 213.189.128.0/18, 213.190.0.0/17, 213.190.128.0/18, 213.190.192.0/19, 213.191.32.0/19, 213.191.64.0/18, 213.191.128.0/17, 213.192.0.0/16, 213.193.32.0/19, 213.193.64.0/18, 213.193.128.0/17, 213.194.0.0/15, 213.196.0.0/14, 213.200.0.0/13, 213.208.0.0/17, 213.208.128.0/19, 213.208.160.0/20, 213.208.192.0/18, 213.209.0.0/16, 213.210.0.0/18, 213.210.128.0/17, 213.211.0.0/16, 213.212.0.0/14, 213.216.0.0/15, 213.218.0.0/16, 213.219.0.0/17, 213.219.128.0/18, 213.219.240.0/20, 213.220.0.0/16, 213.221.64.0/18, 213.221.128.0/17, 213.222.0.0/17, 213.222.128.0/18, 213.222.192.0/19, 213.223.0.0/16, 213.224.0.0/14, 213.228.0.0/18, 213.228.128.0/17, 213.229.0.0/16, 213.230.0.0/15, 213.232.0.0/15, 213.234.32.0/19, 213.234.64.0/18, 213.234.128.0/18, 213.235.0.0/16, 213.236.0.0/14, 213.240.0.0/16, 213.241.0.0/17, 213.241.128.0/18, 213.242.64.0/18, 213.242.128.0/18, 213.243.0.0/18, 213.243.128.0/17, 213.244.0.0/15, 213.246.0.0/16, 213.247.0.0/17, 213.248.64.0/18, 213.248.128.0/17, 213.249.0.0/16, 213.250.0.0/16, 213.251.0.0/17, 213.251.128.0/18, 213.252.0.0/18, 213.252.128.0/17, 213.253.0.0/16, 213.254.0.0/15, 214.0.0.0/7, 216.0.0.0/8, 217.0.0.0/13, 217.8.0.0/18, 217.8.64.0/20, 217.8.96.0/19, 217.8.128.0/18, 217.8.192.0/19, 217.8.240.0/20, 217.9.0.0/18, 217.9.64.0/20, 217.9.96.0/19, 217.9.128.0/20, 217.9.160.0/19, 217.9.192.0/18, 217.10.0.0/19, 217.10.48.0/20, 217.10.64.0/18, 217.10.128.0/17, 217.11.0.0/16, 217.12.0.0/19, 217.12.48.0/20, 217.12.80.0/20, 217.12.112.0/20, 217.12.128.0/18, 217.12.192.0/19, 217.12.224.0/20, 217.13.0.0/17, 217.13.128.0/18, 217.13.192.0/20, 217.13.224.0/19, 217.14.0.0/20, 217.14.32.0/20, 217.14.64.0/18, 217.14.128.0/18, 217.14.208.0/20, 217.14.224.0/20, 217.15.0.0/20, 217.15.32.0/20, 217.15.64.0/18, 217.15.160.0/19, 217.15.208.0/20, 217.15.224.0/19, 217.16.0.0/20, 217.16.32.0/19, 217.16.64.0/18, 217.16.128.0/17, 217.17.0.0/18, 217.17.64.0/19, 217.17.96.0/20, 217.17.128.0/19, 217.17.192.0/18, 217.18.0.0/17, 217.18.160.0/19, 217.18.192.0/18, 217.19.0.0/18, 217.19.64.0/19, 217.19.128.0/17, 217.20.0.0/18, 217.20.96.0/19, 217.20.128.0/20, 217.20.160.0/19, 217.20.192.0/18, 217.21.0.0/18, 217.21.64.0/19, 217.21.112.0/20, 217.21.128.0/18, 217.21.192.0/20, 217.21.224.0/19, 217.22.0.0/17, 217.22.128.0/19, 217.22.176.0/20, 217.22.192.0/18, 217.23.0.0/20, 217.23.32.0/19, 217.23.96.0/19, 217.23.144.0/20, 217.23.160.0/20, 217.23.192.0/18, 217.24.0.0/18, 217.24.64.0/19, 217.24.96.0/20, 217.24.128.0/19, 217.24.160.0/20, 217.24.192.0/18, 217.25.0.0/18, 217.25.64.0/20, 217.25.96.0/19, 217.25.128.0/20, 217.25.160.0/19, 217.25.192.0/20, 217.25.240.0/20, 217.26.32.0/19, 217.26.64.0/18, 217.26.128.0/17, 217.27.0.0/17, 217.27.144.0/20, 217.27.160.0/19, 217.27.192.0/18, 217.28.0.0/17, 217.28.128.0/18, 217.28.192.0/20, 217.28.240.0/20, 217.29.0.0/19, 217.29.32.0/20, 217.29.64.0/20, 217.29.96.0/19, 217.29.128.0/19, 217.29.160.0/20, 217.29.192.0/18, 217.30.0.0/17, 217.30.128.0/18, 217.30.192.0/19, 217.30.224.0/20, 217.31.0.0/16, 217.32.0.0/11, 217.64.0.0/17, 217.64.144.0/20, 217.64.160.0/19, 217.64.192.0/18, 217.65.16.0/20, 217.65.32.0/19, 217.65.64.0/20, 217.65.96.0/19, 217.65.128.0/18, 217.65.192.0/20, 217.65.224.0/19, 217.66.0.0/20, 217.66.32.0/19, 217.66.96.0/19, 217.66.128.0/20, 217.66.160.0/19, 217.66.192.0/18, 217.67.16.0/20, 217.67.32.0/19, 217.67.64.0/19, 217.67.96.0/20, 217.67.128.0/19, 217.67.160.0/20, 217.67.192.0/18, 217.68.0.0/16, 217.69.0.0/17, 217.69.144.0/20, 217.69.160.0/19, 217.69.224.0/19, 217.70.0.0/20, 217.70.32.0/19, 217.70.64.0/19, 217.70.128.0/17, 217.71.0.0/17, 217.71.144.0/20, 217.71.176.0/20, 217.71.192.0/19, 217.71.240.0/20, 217.72.0.0/17, 217.72.128.0/20, 217.72.160.0/19, 217.72.192.0/18, 217.73.0.0/18, 217.73.64.0/19, 217.73.96.0/20, 217.73.128.0/18, 217.73.208.0/20, 217.73.224.0/19, 217.74.0.0/19, 217.74.48.0/20, 217.74.64.0/19, 217.74.96.0/20, 217.74.128.0/19, 217.74.176.0/20, 217.74.192.0/19, 217.74.224.0/20, 217.75.0.0/16, 217.76.0.0/19, 217.76.48.0/20, 217.76.64.0/18, 217.76.128.0/19, 217.76.160.0/20, 217.76.192.0/18, 217.77.0.0/19, 217.77.32.0/20, 217.77.64.0/18, 217.77.128.0/17, 217.78.0.0/17, 217.78.128.0/19, 217.78.160.0/20, 217.78.192.0/18, 217.79.32.0/20, 217.79.64.0/18, 217.79.128.0/18, 217.79.192.0/19, 217.79.240.0/20, 217.80.0.0/12, 217.96.0.0/13, 217.104.0.0/15, 217.108.0.0/14, 217.112.48.0/20, 217.112.64.0/18, 217.112.128.0/17, 217.113.0.0/18, 217.113.64.0/19, 217.113.96.0/20, 217.113.128.0/17, 217.114.32.0/19, 217.114.64.0/18, 217.114.128.0/20, 217.114.160.0/20, 217.114.192.0/19, 217.115.0.0/18, 217.115.64.0/20, 217.115.96.0/19, 217.115.128.0/19, 217.115.160.0/20, 217.115.192.0/18, 217.116.0.0/19, 217.116.32.0/20, 217.116.64.0/18, 217.116.160.0/19, 217.116.192.0/18, 217.117.0.0/18, 217.117.64.0/20, 217.117.96.0/20, 217.117.128.0/19, 217.117.160.0/20, 217.117.192.0/19, 217.117.224.0/20, 217.118.0.0/18, 217.118.96.0/19, 217.118.128.0/19, 217.118.160.0/20, 217.118.192.0/18, 217.119.0.0/20, 217.119.32.0/19, 217.119.64.0/20, 217.119.96.0/19, 217.119.128.0/17, 217.120.0.0/13, 217.128.0.0/12, 217.144.0.0/17, 217.144.128.0/19, 217.144.176.0/20, 217.144.192.0/18, 217.145.0.0/20, 217.145.32.0/19, 217.145.64.0/18, 217.145.128.0/20, 217.145.160.0/19, 217.145.192.0/18, 217.146.0.0/19, 217.146.48.0/20, 217.146.64.0/18, 217.146.128.0/17, 217.147.0.0/20, 217.147.32.0/19, 217.147.64.0/18, 217.147.128.0/17, 217.148.0.0/19, 217.148.32.0/20, 217.148.64.0/18, 217.148.128.0/18, 217.148.224.0/19, 217.149.0.0/20, 217.149.32.0/19, 217.149.64.0/18, 217.149.128.0/19, 217.149.160.0/20, 217.149.192.0/18, 217.150.64.0/18, 217.150.128.0/18, 217.150.208.0/20, 217.150.224.0/19, 217.151.0.0/20, 217.151.32.0/19, 217.151.80.0/20, 217.151.96.0/19, 217.151.144.0/20, 217.151.160.0/19, 217.151.192.0/19, 217.151.240.0/20, 217.152.0.0/13, 217.160.0.0/13, 217.168.0.0/18, 217.168.80.0/20, 217.168.96.0/19, 217.168.128.0/17, 217.169.0.0/18, 217.169.64.0/20, 217.169.96.0/19, 217.169.128.0/17, 217.170.0.0/18, 217.170.96.0/20, 217.170.128.0/18, 217.170.192.0/20, 217.170.224.0/19, 217.171.16.0/20, 217.171.32.0/19, 217.171.64.0/18, 217.171.128.0/17, 217.172.0.0/20, 217.172.32.0/19, 217.172.64.0/18, 217.172.128.0/17, 217.173.0.0/20, 217.173.32.0/19, 217.173.80.0/20, 217.173.96.0/19, 217.173.128.0/17, 217.174.16.0/20, 217.174.32.0/19, 217.174.64.0/19, 217.174.112.0/20, 217.174.128.0/19, 217.174.192.0/18, 217.175.48.0/20, 217.175.64.0/18, 217.175.160.0/19, 217.175.192.0/18, 217.176.0.0/12, 217.192.0.0/15, 217.194.0.0/17, 217.194.128.0/18, 217.194.192.0/19, 217.194.224.0/20, 217.195.0.0/18, 217.195.112.0/20, 217.195.128.0/18, 217.195.192.0/20, 217.195.224.0/19, 217.196.0.0/18, 217.196.64.0/19, 217.196.112.0/20, 217.196.128.0/17, 217.197.16.0/20, 217.197.32.0/19, 217.197.64.0/19, 217.197.96.0/20, 217.197.128.0/18, 217.197.208.0/20, 217.198.16.0/20, 217.198.32.0/19, 217.198.64.0/20, 217.198.96.0/19, 217.198.128.0/19, 217.198.176.0/20, 217.198.192.0/18, 217.199.0.0/17, 217.199.128.0/18, 217.199.192.0/20, 217.199.240.0/20, 217.200.0.0/13, 217.208.0.0/12, 217.224.0.0/11, 218.0.0.0/7, 220.0.0.0/6, 10.25.0.0/16
diff --git a/ios/WireGuardGo/iphoneos/libwg-go.a b/ios/WireGuardGo/iphoneos/libwg-go.a
deleted file mode 100644
index 2fef8a5..0000000
Binary files a/ios/WireGuardGo/iphoneos/libwg-go.a and /dev/null differ
diff --git a/ios/WireGuardGo/iphonesimulator/libwg-go.a b/ios/WireGuardGo/iphonesimulator/libwg-go.a
deleted file mode 100644
index 268f2d2..0000000
Binary files a/ios/WireGuardGo/iphonesimulator/libwg-go.a and /dev/null differ
diff --git a/ios/WireGuardKit/COPYING b/ios/WireGuardKit/COPYING
deleted file mode 100644
index af11a81..0000000
--- a/ios/WireGuardKit/COPYING
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright © 2018-2023 WireGuard LLC. All Rights Reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/ios/WireGuardKit/Package.swift b/ios/WireGuardKit/Package.swift
deleted file mode 100644
index 4d4e07d..0000000
--- a/ios/WireGuardKit/Package.swift
+++ /dev/null
@@ -1,15 +0,0 @@
-// swift-tools-version:5.5
-// Vendored WireGuardKit (github.com/WireGuard/wireguard-apple, MIT). libwg-go.a is
-// prebuilt in ../WireGuardGo// — the app target adds it to LIBRARY_SEARCH_PATHS.
-import PackageDescription
-
-let package = Package(
- name: "WireGuardKit",
- platforms: [.iOS(.v15)],
- products: [.library(name: "WireGuardKit", targets: ["WireGuardKit"])],
- targets: [
- .target(name: "WireGuardKit", dependencies: ["WireGuardKitGo", "WireGuardKitC"]),
- .target(name: "WireGuardKitC", publicHeadersPath: "."),
- .target(name: "WireGuardKitGo", publicHeadersPath: ".", linkerSettings: [.linkedLibrary("wg-go")]),
- ]
-)
diff --git a/ios/WireGuardKit/Sources/WireGuardKit/Array+ConcurrentMap.swift b/ios/WireGuardKit/Sources/WireGuardKit/Array+ConcurrentMap.swift
deleted file mode 100644
index 13309c6..0000000
--- a/ios/WireGuardKit/Sources/WireGuardKit/Array+ConcurrentMap.swift
+++ /dev/null
@@ -1,34 +0,0 @@
-// SPDX-License-Identifier: MIT
-// Copyright © 2018-2023 WireGuard LLC. All Rights Reserved.
-
-import Foundation
-
-extension Array {
-
- /// Returns an array containing the results of mapping the given closure over the sequence’s
- /// elements concurrently.
- ///
- /// - Parameters:
- /// - queue: The queue for performing concurrent computations.
- /// If the given queue is serial, the values are mapped in a serial fashion.
- /// Pass `nil` to perform computations on the current queue.
- /// - transform: the block to perform concurrent computations over the given element.
- /// - Returns: an array of concurrently computed values.
- func concurrentMap(queue: DispatchQueue?, _ transform: (Element) -> U) -> [U] {
- var result = [U?](repeating: nil, count: self.count)
- let resultQueue = DispatchQueue(label: "ConcurrentMapQueue")
-
- let execute = queue?.sync ?? { $0() }
-
- execute {
- DispatchQueue.concurrentPerform(iterations: self.count) { index in
- let value = transform(self[index])
- resultQueue.sync {
- result[index] = value
- }
- }
- }
-
- return result.map { $0! }
- }
-}
diff --git a/ios/WireGuardKit/Sources/WireGuardKit/DNSResolver.swift b/ios/WireGuardKit/Sources/WireGuardKit/DNSResolver.swift
deleted file mode 100644
index cf4fde6..0000000
--- a/ios/WireGuardKit/Sources/WireGuardKit/DNSResolver.swift
+++ /dev/null
@@ -1,153 +0,0 @@
-// SPDX-License-Identifier: MIT
-// Copyright © 2018-2023 WireGuard LLC. All Rights Reserved.
-
-import Network
-import Foundation
-
-enum DNSResolver {}
-
-extension DNSResolver {
-
- /// Concurrent queue used for DNS resolutions
- private static let resolverQueue = DispatchQueue(label: "DNSResolverQueue", qos: .default, attributes: .concurrent)
-
- static func resolveSync(endpoints: [Endpoint?]) -> [Result?] {
- let isAllEndpointsAlreadyResolved = endpoints.allSatisfy { maybeEndpoint -> Bool in
- return maybeEndpoint?.hasHostAsIPAddress() ?? true
- }
-
- if isAllEndpointsAlreadyResolved {
- return endpoints.map { endpoint in
- return endpoint.map { .success($0) }
- }
- }
-
- return endpoints.concurrentMap(queue: resolverQueue) { endpoint -> Result? in
- guard let endpoint = endpoint else { return nil }
-
- if endpoint.hasHostAsIPAddress() {
- return .success(endpoint)
- } else {
- return Result { try DNSResolver.resolveSync(endpoint: endpoint) }
- .mapError { error -> DNSResolutionError in
- // swiftlint:disable:next force_cast
- return error as! DNSResolutionError
- }
- }
- }
- }
-
- private static func resolveSync(endpoint: Endpoint) throws -> Endpoint {
- guard case .name(let name, _) = endpoint.host else {
- return endpoint
- }
-
- var hints = addrinfo()
- hints.ai_flags = AI_ALL // We set this to ALL so that we get v4 addresses even on DNS64 networks
- hints.ai_family = AF_UNSPEC
- hints.ai_socktype = SOCK_DGRAM
- hints.ai_protocol = IPPROTO_UDP
-
- var resultPointer: UnsafeMutablePointer?
- defer {
- resultPointer.flatMap { freeaddrinfo($0) }
- }
-
- let errorCode = getaddrinfo(name, "\(endpoint.port)", &hints, &resultPointer)
- if errorCode != 0 {
- throw DNSResolutionError(errorCode: errorCode, address: name)
- }
-
- var ipv4Address: IPv4Address?
- var ipv6Address: IPv6Address?
-
- var next: UnsafeMutablePointer? = resultPointer
- let iterator = AnyIterator { () -> addrinfo? in
- let result = next?.pointee
- next = result?.ai_next
- return result
- }
-
- for addrInfo in iterator {
- if let maybeIpv4Address = IPv4Address(addrInfo: addrInfo) {
- ipv4Address = maybeIpv4Address
- break // If we found an IPv4 address, we can stop
- } else if let maybeIpv6Address = IPv6Address(addrInfo: addrInfo) {
- ipv6Address = maybeIpv6Address
- continue // If we already have an IPv6 address, we can skip this one
- }
- }
-
- // We prefer an IPv4 address over an IPv6 address
- if let ipv4Address = ipv4Address {
- return Endpoint(host: .ipv4(ipv4Address), port: endpoint.port)
- } else if let ipv6Address = ipv6Address {
- return Endpoint(host: .ipv6(ipv6Address), port: endpoint.port)
- } else {
- // Must never happen
- fatalError()
- }
- }
-}
-
-extension Endpoint {
- func withReresolvedIP() throws -> Endpoint {
- #if os(iOS)
- let hostname: String
- switch host {
- case .name(let name, _):
- hostname = name
- case .ipv4(let address):
- hostname = "\(address)"
- case .ipv6(let address):
- hostname = "\(address)"
- @unknown default:
- fatalError()
- }
-
- var hints = addrinfo()
- hints.ai_family = AF_UNSPEC
- hints.ai_socktype = SOCK_DGRAM
- hints.ai_protocol = IPPROTO_UDP
- hints.ai_flags = 0 // We set this to zero so that we actually resolve this using DNS64
-
- var result: UnsafeMutablePointer?
- defer {
- result.flatMap { freeaddrinfo($0) }
- }
-
- let errorCode = getaddrinfo(hostname, "\(self.port)", &hints, &result)
- if errorCode != 0 {
- throw DNSResolutionError(errorCode: errorCode, address: hostname)
- }
-
- let addrInfo = result!.pointee
- if let ipv4Address = IPv4Address(addrInfo: addrInfo) {
- return Endpoint(host: .ipv4(ipv4Address), port: port)
- } else if let ipv6Address = IPv6Address(addrInfo: addrInfo) {
- return Endpoint(host: .ipv6(ipv6Address), port: port)
- } else {
- fatalError()
- }
- #elseif os(macOS)
- return self
- #else
- #error("Unimplemented")
- #endif
- }
-}
-
-/// An error type describing DNS resolution error
-public struct DNSResolutionError: LocalizedError {
- public let errorCode: Int32
- public let address: String
-
- init(errorCode: Int32, address: String) {
- self.errorCode = errorCode
- self.address = address
- }
-
- public var errorDescription: String? {
- return String(cString: gai_strerror(errorCode))
- }
-}
diff --git a/ios/WireGuardKit/Sources/WireGuardKit/DNSServer.swift b/ios/WireGuardKit/Sources/WireGuardKit/DNSServer.swift
deleted file mode 100644
index eaf10f8..0000000
--- a/ios/WireGuardKit/Sources/WireGuardKit/DNSServer.swift
+++ /dev/null
@@ -1,35 +0,0 @@
-// SPDX-License-Identifier: MIT
-// Copyright © 2018-2023 WireGuard LLC. All Rights Reserved.
-
-import Foundation
-import Network
-
-public struct DNSServer {
- public let address: IPAddress
-
- public init(address: IPAddress) {
- self.address = address
- }
-}
-
-extension DNSServer: Equatable {
- public static func == (lhs: DNSServer, rhs: DNSServer) -> Bool {
- return lhs.address.rawValue == rhs.address.rawValue
- }
-}
-
-extension DNSServer {
- public var stringRepresentation: String {
- return "\(address)"
- }
-
- public init?(from addressString: String) {
- if let addr = IPv4Address(addressString) {
- address = addr
- } else if let addr = IPv6Address(addressString) {
- address = addr
- } else {
- return nil
- }
- }
-}
diff --git a/ios/WireGuardKit/Sources/WireGuardKit/Endpoint.swift b/ios/WireGuardKit/Sources/WireGuardKit/Endpoint.swift
deleted file mode 100644
index da49088..0000000
--- a/ios/WireGuardKit/Sources/WireGuardKit/Endpoint.swift
+++ /dev/null
@@ -1,101 +0,0 @@
-// SPDX-License-Identifier: MIT
-// Copyright © 2018-2023 WireGuard LLC. All Rights Reserved.
-
-import Foundation
-import Network
-
-public struct Endpoint {
- public let host: NWEndpoint.Host
- public let port: NWEndpoint.Port
-
- public init(host: NWEndpoint.Host, port: NWEndpoint.Port) {
- self.host = host
- self.port = port
- }
-}
-
-extension Endpoint: Equatable {
- public static func == (lhs: Endpoint, rhs: Endpoint) -> Bool {
- return lhs.host == rhs.host && lhs.port == rhs.port
- }
-}
-
-extension Endpoint: Hashable {
- public func hash(into hasher: inout Hasher) {
- hasher.combine(host)
- hasher.combine(port)
- }
-}
-
-extension Endpoint {
- public var stringRepresentation: String {
- switch host {
- case .name(let hostname, _):
- return "\(hostname):\(port)"
- case .ipv4(let address):
- return "\(address):\(port)"
- case .ipv6(let address):
- return "[\(address)]:\(port)"
- @unknown default:
- fatalError()
- }
- }
-
- public init?(from string: String) {
- // Separation of host and port is based on 'parse_endpoint' function in
- // https://git.zx2c4.com/wireguard-tools/tree/src/config.c
- guard !string.isEmpty else { return nil }
- let startOfPort: String.Index
- let hostString: String
- if string.first! == "[" {
- // Look for IPv6-style endpoint, like [::1]:80
- let startOfHost = string.index(after: string.startIndex)
- guard let endOfHost = string.dropFirst().firstIndex(of: "]") else { return nil }
- let afterEndOfHost = string.index(after: endOfHost)
- if afterEndOfHost == string.endIndex { return nil }
- guard string[afterEndOfHost] == ":" else { return nil }
- startOfPort = string.index(after: afterEndOfHost)
- hostString = String(string[startOfHost ..< endOfHost])
- } else {
- // Look for an IPv4-style endpoint, like 127.0.0.1:80
- guard let endOfHost = string.firstIndex(of: ":") else { return nil }
- startOfPort = string.index(after: endOfHost)
- hostString = String(string[string.startIndex ..< endOfHost])
- }
- guard let endpointPort = NWEndpoint.Port(String(string[startOfPort ..< string.endIndex])) else { return nil }
- let invalidCharacterIndex = hostString.unicodeScalars.firstIndex { char in
- return !CharacterSet.urlHostAllowed.contains(char)
- }
- guard invalidCharacterIndex == nil else { return nil }
- host = NWEndpoint.Host(hostString)
- port = endpointPort
- }
-}
-
-extension Endpoint {
- public func hasHostAsIPAddress() -> Bool {
- switch host {
- case .name:
- return false
- case .ipv4:
- return true
- case .ipv6:
- return true
- @unknown default:
- fatalError()
- }
- }
-
- public func hostname() -> String? {
- switch host {
- case .name(let hostname, _):
- return hostname
- case .ipv4:
- return nil
- case .ipv6:
- return nil
- @unknown default:
- fatalError()
- }
- }
-}
diff --git a/ios/WireGuardKit/Sources/WireGuardKit/IPAddress+AddrInfo.swift b/ios/WireGuardKit/Sources/WireGuardKit/IPAddress+AddrInfo.swift
deleted file mode 100644
index 7fe1fa7..0000000
--- a/ios/WireGuardKit/Sources/WireGuardKit/IPAddress+AddrInfo.swift
+++ /dev/null
@@ -1,29 +0,0 @@
-// SPDX-License-Identifier: MIT
-// Copyright © 2018-2023 WireGuard LLC. All Rights Reserved.
-
-import Foundation
-import Network
-
-extension IPv4Address {
- init?(addrInfo: addrinfo) {
- guard addrInfo.ai_family == AF_INET else { return nil }
-
- let addressData = addrInfo.ai_addr.withMemoryRebound(to: sockaddr_in.self, capacity: 1) { ptr -> Data in
- return Data(bytes: &ptr.pointee.sin_addr, count: MemoryLayout.size)
- }
-
- self.init(addressData)
- }
-}
-
-extension IPv6Address {
- init?(addrInfo: addrinfo) {
- guard addrInfo.ai_family == AF_INET6 else { return nil }
-
- let addressData = addrInfo.ai_addr.withMemoryRebound(to: sockaddr_in6.self, capacity: 1) { ptr -> Data in
- return Data(bytes: &ptr.pointee.sin6_addr, count: MemoryLayout.size)
- }
-
- self.init(addressData)
- }
-}
diff --git a/ios/WireGuardKit/Sources/WireGuardKit/IPAddressRange.swift b/ios/WireGuardKit/Sources/WireGuardKit/IPAddressRange.swift
deleted file mode 100644
index 60430af..0000000
--- a/ios/WireGuardKit/Sources/WireGuardKit/IPAddressRange.swift
+++ /dev/null
@@ -1,115 +0,0 @@
-// SPDX-License-Identifier: MIT
-// Copyright © 2018-2023 WireGuard LLC. All Rights Reserved.
-
-import Foundation
-import Network
-
-public struct IPAddressRange {
- public let address: IPAddress
- public let networkPrefixLength: UInt8
-
- init(address: IPAddress, networkPrefixLength: UInt8) {
- self.address = address
- self.networkPrefixLength = networkPrefixLength
- }
-}
-
-extension IPAddressRange: Equatable {
- public static func == (lhs: IPAddressRange, rhs: IPAddressRange) -> Bool {
- return lhs.address.rawValue == rhs.address.rawValue && lhs.networkPrefixLength == rhs.networkPrefixLength
- }
-}
-
-extension IPAddressRange: Hashable {
- public func hash(into hasher: inout Hasher) {
- hasher.combine(address.rawValue)
- hasher.combine(networkPrefixLength)
- }
-}
-
-extension IPAddressRange {
- public var stringRepresentation: String {
- return "\(address)/\(networkPrefixLength)"
- }
-
- public init?(from string: String) {
- guard let parsed = IPAddressRange.parseAddressString(string) else { return nil }
- address = parsed.0
- networkPrefixLength = parsed.1
- }
-
- private static func parseAddressString(_ string: String) -> (IPAddress, UInt8)? {
- let endOfIPAddress = string.lastIndex(of: "/") ?? string.endIndex
- let addressString = String(string[string.startIndex ..< endOfIPAddress])
- let address: IPAddress
- if let addr = IPv4Address(addressString) {
- address = addr
- } else if let addr = IPv6Address(addressString) {
- address = addr
- } else {
- return nil
- }
-
- let maxNetworkPrefixLength: UInt8 = address is IPv4Address ? 32 : 128
- var networkPrefixLength: UInt8
- if endOfIPAddress < string.endIndex { // "/" was located
- let indexOfNetworkPrefixLength = string.index(after: endOfIPAddress)
- guard indexOfNetworkPrefixLength < string.endIndex else { return nil }
- let networkPrefixLengthSubstring = string[indexOfNetworkPrefixLength ..< string.endIndex]
- guard let npl = UInt8(networkPrefixLengthSubstring) else { return nil }
- networkPrefixLength = min(npl, maxNetworkPrefixLength)
- } else {
- networkPrefixLength = maxNetworkPrefixLength
- }
-
- return (address, networkPrefixLength)
- }
-
- public func subnetMask() -> IPAddress {
- if address is IPv4Address {
- let mask = networkPrefixLength > 0 ? ~UInt32(0) << (32 - networkPrefixLength) : UInt32(0)
- let bytes = Data([
- UInt8(truncatingIfNeeded: mask >> 24),
- UInt8(truncatingIfNeeded: mask >> 16),
- UInt8(truncatingIfNeeded: mask >> 8),
- UInt8(truncatingIfNeeded: mask >> 0)
- ])
- return IPv4Address(bytes)!
- }
- if address is IPv6Address {
- var bytes = Data(repeating: 0, count: 16)
- for i in 0..> 24)
- bytes[i + 1] = UInt8(truncatingIfNeeded: mask >> 16)
- bytes[i + 2] = UInt8(truncatingIfNeeded: mask >> 8)
- bytes[i + 3] = UInt8(truncatingIfNeeded: mask >> 0)
- }
- return IPv6Address(bytes)!
- }
- fatalError()
- }
-
- public func maskedAddress() -> IPAddress {
- let subnet = subnetMask().rawValue
- var masked = Data(address.rawValue)
- if subnet.count != masked.count {
- fatalError()
- }
- for i in 0.. Bool {
- let lhsAddresses = lhs.addresses.filter { $0.address is IPv4Address } + lhs.addresses.filter { $0.address is IPv6Address }
- let rhsAddresses = rhs.addresses.filter { $0.address is IPv4Address } + rhs.addresses.filter { $0.address is IPv6Address }
-
- return lhs.privateKey == rhs.privateKey &&
- lhsAddresses == rhsAddresses &&
- lhs.listenPort == rhs.listenPort &&
- lhs.mtu == rhs.mtu &&
- lhs.dns == rhs.dns &&
- lhs.dnsSearch == rhs.dnsSearch
- }
-}
diff --git a/ios/WireGuardKit/Sources/WireGuardKit/PacketTunnelSettingsGenerator.swift b/ios/WireGuardKit/Sources/WireGuardKit/PacketTunnelSettingsGenerator.swift
deleted file mode 100644
index 3658956..0000000
--- a/ios/WireGuardKit/Sources/WireGuardKit/PacketTunnelSettingsGenerator.swift
+++ /dev/null
@@ -1,183 +0,0 @@
-// SPDX-License-Identifier: MIT
-// Copyright © 2018-2023 WireGuard LLC. All Rights Reserved.
-
-import Foundation
-import Network
-import NetworkExtension
-
-#if SWIFT_PACKAGE
-import WireGuardKitC
-#endif
-
-/// A type alias for `Result` type that holds a tuple with source and resolved endpoint.
-typealias EndpointResolutionResult = Result<(Endpoint, Endpoint), DNSResolutionError>
-
-class PacketTunnelSettingsGenerator {
- let tunnelConfiguration: TunnelConfiguration
- let resolvedEndpoints: [Endpoint?]
-
- init(tunnelConfiguration: TunnelConfiguration, resolvedEndpoints: [Endpoint?]) {
- self.tunnelConfiguration = tunnelConfiguration
- self.resolvedEndpoints = resolvedEndpoints
- }
-
- func endpointUapiConfiguration() -> (String, [EndpointResolutionResult?]) {
- var resolutionResults = [EndpointResolutionResult?]()
- var wgSettings = ""
-
- assert(tunnelConfiguration.peers.count == resolvedEndpoints.count)
- for (peer, resolvedEndpoint) in zip(self.tunnelConfiguration.peers, self.resolvedEndpoints) {
- wgSettings.append("public_key=\(peer.publicKey.hexKey)\n")
-
- let result = resolvedEndpoint.map(Self.reresolveEndpoint)
- if case .success((_, let resolvedEndpoint)) = result {
- if case .name = resolvedEndpoint.host { assert(false, "Endpoint is not resolved") }
- wgSettings.append("endpoint=\(resolvedEndpoint.stringRepresentation)\n")
- }
- resolutionResults.append(result)
- }
-
- return (wgSettings, resolutionResults)
- }
-
- func uapiConfiguration() -> (String, [EndpointResolutionResult?]) {
- var resolutionResults = [EndpointResolutionResult?]()
- var wgSettings = ""
- wgSettings.append("private_key=\(tunnelConfiguration.interface.privateKey.hexKey)\n")
- if let listenPort = tunnelConfiguration.interface.listenPort {
- wgSettings.append("listen_port=\(listenPort)\n")
- }
- if !tunnelConfiguration.peers.isEmpty {
- wgSettings.append("replace_peers=true\n")
- }
- assert(tunnelConfiguration.peers.count == resolvedEndpoints.count)
- for (peer, resolvedEndpoint) in zip(self.tunnelConfiguration.peers, self.resolvedEndpoints) {
- wgSettings.append("public_key=\(peer.publicKey.hexKey)\n")
- if let preSharedKey = peer.preSharedKey?.hexKey {
- wgSettings.append("preshared_key=\(preSharedKey)\n")
- }
-
- let result = resolvedEndpoint.map(Self.reresolveEndpoint)
- if case .success((_, let resolvedEndpoint)) = result {
- if case .name = resolvedEndpoint.host { assert(false, "Endpoint is not resolved") }
- wgSettings.append("endpoint=\(resolvedEndpoint.stringRepresentation)\n")
- }
- resolutionResults.append(result)
-
- let persistentKeepAlive = peer.persistentKeepAlive ?? 0
- wgSettings.append("persistent_keepalive_interval=\(persistentKeepAlive)\n")
- if !peer.allowedIPs.isEmpty {
- wgSettings.append("replace_allowed_ips=true\n")
- peer.allowedIPs.forEach { wgSettings.append("allowed_ip=\($0.stringRepresentation)\n") }
- }
- }
- return (wgSettings, resolutionResults)
- }
-
- func generateNetworkSettings() -> NEPacketTunnelNetworkSettings {
- /* iOS requires a tunnel endpoint, whereas in WireGuard it's valid for
- * a tunnel to have no endpoint, or for there to be many endpoints, in
- * which case, displaying a single one in settings doesn't really
- * make sense. So, we fill it in with this placeholder, which is not
- * a valid IP address that will actually route over the Internet.
- */
- let networkSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "127.0.0.1")
-
- if !tunnelConfiguration.interface.dnsSearch.isEmpty || !tunnelConfiguration.interface.dns.isEmpty {
- let dnsServerStrings = tunnelConfiguration.interface.dns.map { $0.stringRepresentation }
- let dnsSettings = NEDNSSettings(servers: dnsServerStrings)
- dnsSettings.searchDomains = tunnelConfiguration.interface.dnsSearch
- if !tunnelConfiguration.interface.dns.isEmpty {
- dnsSettings.matchDomains = [""] // All DNS queries must first go through the tunnel's DNS
- }
- networkSettings.dnsSettings = dnsSettings
- }
-
- let mtu = tunnelConfiguration.interface.mtu ?? 0
-
- /* 0 means automatic MTU. In theory, we should just do
- * `networkSettings.tunnelOverheadBytes = 80` but in
- * practice there are too many broken networks out there.
- * Instead set it to 1280. Boohoo. Maybe someday we'll
- * add a nob, maybe, or iOS will do probing for us.
- */
- if mtu == 0 {
- #if os(iOS)
- networkSettings.mtu = NSNumber(value: 1280)
- #elseif os(macOS)
- networkSettings.tunnelOverheadBytes = 80
- #else
- #error("Unimplemented")
- #endif
- } else {
- networkSettings.mtu = NSNumber(value: mtu)
- }
-
- let (ipv4Addresses, ipv6Addresses) = addresses()
- let (ipv4IncludedRoutes, ipv6IncludedRoutes) = includedRoutes()
-
- let ipv4Settings = NEIPv4Settings(addresses: ipv4Addresses.map { $0.destinationAddress }, subnetMasks: ipv4Addresses.map { $0.destinationSubnetMask })
- ipv4Settings.includedRoutes = ipv4IncludedRoutes
- networkSettings.ipv4Settings = ipv4Settings
-
- let ipv6Settings = NEIPv6Settings(addresses: ipv6Addresses.map { $0.destinationAddress }, networkPrefixLengths: ipv6Addresses.map { $0.destinationNetworkPrefixLength })
- ipv6Settings.includedRoutes = ipv6IncludedRoutes
- networkSettings.ipv6Settings = ipv6Settings
-
- return networkSettings
- }
-
- private func addresses() -> ([NEIPv4Route], [NEIPv6Route]) {
- var ipv4Routes = [NEIPv4Route]()
- var ipv6Routes = [NEIPv6Route]()
- for addressRange in tunnelConfiguration.interface.addresses {
- if addressRange.address is IPv4Address {
- ipv4Routes.append(NEIPv4Route(destinationAddress: "\(addressRange.address)", subnetMask: "\(addressRange.subnetMask())"))
- } else if addressRange.address is IPv6Address {
- /* Big fat ugly hack for broken iOS networking stack: the smallest prefix that will have
- * any effect on iOS is a /120, so we clamp everything above to /120. This is potentially
- * very bad, if various network parameters were actually relying on that subnet being
- * intentionally small. TODO: talk about this with upstream iOS devs.
- */
- ipv6Routes.append(NEIPv6Route(destinationAddress: "\(addressRange.address)", networkPrefixLength: NSNumber(value: min(120, addressRange.networkPrefixLength))))
- }
- }
- return (ipv4Routes, ipv6Routes)
- }
-
- private func includedRoutes() -> ([NEIPv4Route], [NEIPv6Route]) {
- var ipv4IncludedRoutes = [NEIPv4Route]()
- var ipv6IncludedRoutes = [NEIPv6Route]()
-
- for addressRange in tunnelConfiguration.interface.addresses {
- if addressRange.address is IPv4Address {
- let route = NEIPv4Route(destinationAddress: "\(addressRange.maskedAddress())", subnetMask: "\(addressRange.subnetMask())")
- route.gatewayAddress = "\(addressRange.address)"
- ipv4IncludedRoutes.append(route)
- } else if addressRange.address is IPv6Address {
- let route = NEIPv6Route(destinationAddress: "\(addressRange.maskedAddress())", networkPrefixLength: NSNumber(value: addressRange.networkPrefixLength))
- route.gatewayAddress = "\(addressRange.address)"
- ipv6IncludedRoutes.append(route)
- }
- }
-
- for peer in tunnelConfiguration.peers {
- for addressRange in peer.allowedIPs {
- if addressRange.address is IPv4Address {
- ipv4IncludedRoutes.append(NEIPv4Route(destinationAddress: "\(addressRange.address)", subnetMask: "\(addressRange.subnetMask())"))
- } else if addressRange.address is IPv6Address {
- ipv6IncludedRoutes.append(NEIPv6Route(destinationAddress: "\(addressRange.address)", networkPrefixLength: NSNumber(value: addressRange.networkPrefixLength)))
- }
- }
- }
- return (ipv4IncludedRoutes, ipv6IncludedRoutes)
- }
-
- private class func reresolveEndpoint(endpoint: Endpoint) -> EndpointResolutionResult {
- return Result { (endpoint, try endpoint.withReresolvedIP()) }
- .mapError { error -> DNSResolutionError in
- // swiftlint:disable:next force_cast
- return error as! DNSResolutionError
- }
- }
-}
diff --git a/ios/WireGuardKit/Sources/WireGuardKit/PeerConfiguration.swift b/ios/WireGuardKit/Sources/WireGuardKit/PeerConfiguration.swift
deleted file mode 100644
index bc9276f..0000000
--- a/ios/WireGuardKit/Sources/WireGuardKit/PeerConfiguration.swift
+++ /dev/null
@@ -1,40 +0,0 @@
-// SPDX-License-Identifier: MIT
-// Copyright © 2018-2023 WireGuard LLC. All Rights Reserved.
-
-import Foundation
-
-public struct PeerConfiguration {
- public var publicKey: PublicKey
- public var preSharedKey: PreSharedKey?
- public var allowedIPs = [IPAddressRange]()
- public var endpoint: Endpoint?
- public var persistentKeepAlive: UInt16?
- public var rxBytes: UInt64?
- public var txBytes: UInt64?
- public var lastHandshakeTime: Date?
-
- public init(publicKey: PublicKey) {
- self.publicKey = publicKey
- }
-}
-
-extension PeerConfiguration: Equatable {
- public static func == (lhs: PeerConfiguration, rhs: PeerConfiguration) -> Bool {
- return lhs.publicKey == rhs.publicKey &&
- lhs.preSharedKey == rhs.preSharedKey &&
- Set(lhs.allowedIPs) == Set(rhs.allowedIPs) &&
- lhs.endpoint == rhs.endpoint &&
- lhs.persistentKeepAlive == rhs.persistentKeepAlive
- }
-}
-
-extension PeerConfiguration: Hashable {
- public func hash(into hasher: inout Hasher) {
- hasher.combine(publicKey)
- hasher.combine(preSharedKey)
- hasher.combine(Set(allowedIPs))
- hasher.combine(endpoint)
- hasher.combine(persistentKeepAlive)
-
- }
-}
diff --git a/ios/WireGuardKit/Sources/WireGuardKit/PrivateKey.swift b/ios/WireGuardKit/Sources/WireGuardKit/PrivateKey.swift
deleted file mode 100644
index 79d389d..0000000
--- a/ios/WireGuardKit/Sources/WireGuardKit/PrivateKey.swift
+++ /dev/null
@@ -1,114 +0,0 @@
-// SPDX-License-Identifier: MIT
-// Copyright © 2018-2023 WireGuard LLC. All Rights Reserved.
-
-import Foundation
-
-#if SWIFT_PACKAGE
-import WireGuardKitC
-#endif
-
-/// The class describing a private key used by WireGuard.
-public class PrivateKey: BaseKey {
- /// Derived public key
- public var publicKey: PublicKey {
- return rawValue.withUnsafeBytes { (privateKeyBufferPointer: UnsafeRawBufferPointer) -> PublicKey in
- var publicKeyData = Data(repeating: 0, count: Int(WG_KEY_LEN))
- let privateKeyBytes = privateKeyBufferPointer.baseAddress!.assumingMemoryBound(to: UInt8.self)
-
- publicKeyData.withUnsafeMutableBytes { (publicKeyBufferPointer: UnsafeMutableRawBufferPointer) in
- let publicKeyBytes = publicKeyBufferPointer.baseAddress!.assumingMemoryBound(to: UInt8.self)
- curve25519_derive_public_key(publicKeyBytes, privateKeyBytes)
- }
-
- return PublicKey(rawValue: publicKeyData)!
- }
- }
-
- /// Initialize new private key
- convenience public init() {
- var privateKeyData = Data(repeating: 0, count: Int(WG_KEY_LEN))
- privateKeyData.withUnsafeMutableBytes { (rawBufferPointer: UnsafeMutableRawBufferPointer) in
- let privateKeyBytes = rawBufferPointer.baseAddress!.assumingMemoryBound(to: UInt8.self)
- curve25519_generate_private_key(privateKeyBytes)
- }
- self.init(rawValue: privateKeyData)!
- }
-}
-
-/// The class describing a public key used by WireGuard.
-public class PublicKey: BaseKey {}
-
-/// The class describing a pre-shared key used by WireGuard.
-public class PreSharedKey: BaseKey {}
-
-/// The base key implementation. Should not be used directly.
-public class BaseKey: RawRepresentable, Equatable, Hashable {
- /// Raw key representation
- public let rawValue: Data
-
- /// Hex encoded representation
- public var hexKey: String {
- return rawValue.withUnsafeBytes { (rawBufferPointer: UnsafeRawBufferPointer) -> String in
- let inBytes = rawBufferPointer.baseAddress!.assumingMemoryBound(to: UInt8.self)
- var outBytes = [CChar](repeating: 0, count: Int(WG_KEY_LEN_HEX))
- key_to_hex(&outBytes, inBytes)
- return String(cString: outBytes, encoding: .ascii)!
- }
- }
-
- /// Base64 encoded representation
- public var base64Key: String {
- return rawValue.withUnsafeBytes { (rawBufferPointer: UnsafeRawBufferPointer) -> String in
- let inBytes = rawBufferPointer.baseAddress!.assumingMemoryBound(to: UInt8.self)
- var outBytes = [CChar](repeating: 0, count: Int(WG_KEY_LEN_BASE64))
- key_to_base64(&outBytes, inBytes)
- return String(cString: outBytes, encoding: .ascii)!
- }
- }
-
- /// Initialize the key with existing raw representation
- required public init?(rawValue: Data) {
- if rawValue.count == WG_KEY_LEN {
- self.rawValue = rawValue
- } else {
- return nil
- }
- }
-
- /// Initialize the key with hex representation
- public convenience init?(hexKey: String) {
- var bytes = Data(repeating: 0, count: Int(WG_KEY_LEN))
- let success = bytes.withUnsafeMutableBytes { (bufferPointer: UnsafeMutableRawBufferPointer) -> Bool in
- return key_from_hex(bufferPointer.baseAddress!.assumingMemoryBound(to: UInt8.self), hexKey)
- }
- if success {
- self.init(rawValue: bytes)
- } else {
- return nil
- }
- }
-
- /// Initialize the key with base64 representation
- public convenience init?(base64Key: String) {
- var bytes = Data(repeating: 0, count: Int(WG_KEY_LEN))
- let success = bytes.withUnsafeMutableBytes { (bufferPointer: UnsafeMutableRawBufferPointer) -> Bool in
- return key_from_base64(bufferPointer.baseAddress!.assumingMemoryBound(to: UInt8.self), base64Key)
- }
- if success {
- self.init(rawValue: bytes)
- } else {
- return nil
- }
- }
-
- public static func == (lhs: BaseKey, rhs: BaseKey) -> Bool {
- return lhs.rawValue.withUnsafeBytes { (lhsBytes: UnsafeRawBufferPointer) -> Bool in
- return rhs.rawValue.withUnsafeBytes { (rhsBytes: UnsafeRawBufferPointer) -> Bool in
- return key_eq(
- lhsBytes.baseAddress!.assumingMemoryBound(to: UInt8.self),
- rhsBytes.baseAddress!.assumingMemoryBound(to: UInt8.self)
- )
- }
- }
- }
-}
diff --git a/ios/WireGuardKit/Sources/WireGuardKit/TunnelConfiguration.swift b/ios/WireGuardKit/Sources/WireGuardKit/TunnelConfiguration.swift
deleted file mode 100644
index a59ba2f..0000000
--- a/ios/WireGuardKit/Sources/WireGuardKit/TunnelConfiguration.swift
+++ /dev/null
@@ -1,30 +0,0 @@
-// SPDX-License-Identifier: MIT
-// Copyright © 2018-2023 WireGuard LLC. All Rights Reserved.
-
-import Foundation
-
-public final class TunnelConfiguration {
- public var name: String?
- public var interface: InterfaceConfiguration
- public let peers: [PeerConfiguration]
-
- public init(name: String?, interface: InterfaceConfiguration, peers: [PeerConfiguration]) {
- self.interface = interface
- self.peers = peers
- self.name = name
-
- let peerPublicKeysArray = peers.map { $0.publicKey }
- let peerPublicKeysSet = Set(peerPublicKeysArray)
- if peerPublicKeysArray.count != peerPublicKeysSet.count {
- fatalError("Two or more peers cannot have the same public key")
- }
- }
-}
-
-extension TunnelConfiguration: Equatable {
- public static func == (lhs: TunnelConfiguration, rhs: TunnelConfiguration) -> Bool {
- return lhs.name == rhs.name &&
- lhs.interface == rhs.interface &&
- Set(lhs.peers) == Set(rhs.peers)
- }
-}
diff --git a/ios/WireGuardKit/Sources/WireGuardKit/WireGuardAdapter.swift b/ios/WireGuardKit/Sources/WireGuardKit/WireGuardAdapter.swift
deleted file mode 100644
index f7be19b..0000000
--- a/ios/WireGuardKit/Sources/WireGuardKit/WireGuardAdapter.swift
+++ /dev/null
@@ -1,487 +0,0 @@
-// SPDX-License-Identifier: MIT
-// Copyright © 2018-2023 WireGuard LLC. All Rights Reserved.
-
-import Foundation
-import NetworkExtension
-
-#if SWIFT_PACKAGE
-import WireGuardKitGo
-import WireGuardKitC
-#endif
-
-public enum WireGuardAdapterError: Error {
- /// Failure to locate tunnel file descriptor.
- case cannotLocateTunnelFileDescriptor
-
- /// Failure to perform an operation in such state.
- case invalidState
-
- /// Failure to resolve endpoints.
- case dnsResolution([DNSResolutionError])
-
- /// Failure to set network settings.
- case setNetworkSettings(Error)
-
- /// Failure to start WireGuard backend.
- case startWireGuardBackend(Int32)
-}
-
-/// Enum representing internal state of the `WireGuardAdapter`
-private enum State {
- /// The tunnel is stopped
- case stopped
-
- /// The tunnel is up and running
- case started(_ handle: Int32, _ settingsGenerator: PacketTunnelSettingsGenerator)
-
- /// The tunnel is temporarily shutdown due to device going offline
- case temporaryShutdown(_ settingsGenerator: PacketTunnelSettingsGenerator)
-}
-
-public class WireGuardAdapter {
- public typealias LogHandler = (WireGuardLogLevel, String) -> Void
-
- /// Network routes monitor.
- private var networkMonitor: NWPathMonitor?
-
- /// Packet tunnel provider.
- private weak var packetTunnelProvider: NEPacketTunnelProvider?
-
- /// Log handler closure.
- private let logHandler: LogHandler
-
- /// Private queue used to synchronize access to `WireGuardAdapter` members.
- private let workQueue = DispatchQueue(label: "WireGuardAdapterWorkQueue")
-
- /// Adapter state.
- private var state: State = .stopped
-
- /// Tunnel device file descriptor.
- private var tunnelFileDescriptor: Int32? {
- var ctlInfo = ctl_info()
- withUnsafeMutablePointer(to: &ctlInfo.ctl_name) {
- $0.withMemoryRebound(to: CChar.self, capacity: MemoryLayout.size(ofValue: $0.pointee)) {
- _ = strcpy($0, "com.apple.net.utun_control")
- }
- }
- for fd: Int32 in 0...1024 {
- var addr = sockaddr_ctl()
- var ret: Int32 = -1
- var len = socklen_t(MemoryLayout.size(ofValue: addr))
- withUnsafeMutablePointer(to: &addr) {
- $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
- ret = getpeername(fd, $0, &len)
- }
- }
- if ret != 0 || addr.sc_family != AF_SYSTEM {
- continue
- }
- if ctlInfo.ctl_id == 0 {
- ret = ioctl(fd, CTLIOCGINFO, &ctlInfo)
- if ret != 0 {
- continue
- }
- }
- if addr.sc_id == ctlInfo.ctl_id {
- return fd
- }
- }
- return nil
- }
-
- /// Returns a WireGuard version.
- class var backendVersion: String {
- guard let ver = wgVersion() else { return "unknown" }
- let str = String(cString: ver)
- free(UnsafeMutableRawPointer(mutating: ver))
- return str
- }
-
- /// Returns the tunnel device interface name, or nil on error.
- /// - Returns: String.
- public var interfaceName: String? {
- guard let tunnelFileDescriptor = self.tunnelFileDescriptor else { return nil }
-
- var buffer = [UInt8](repeating: 0, count: Int(IFNAMSIZ))
-
- return buffer.withUnsafeMutableBufferPointer { mutableBufferPointer in
- guard let baseAddress = mutableBufferPointer.baseAddress else { return nil }
-
- var ifnameSize = socklen_t(IFNAMSIZ)
- let result = getsockopt(
- tunnelFileDescriptor,
- 2 /* SYSPROTO_CONTROL */,
- 2 /* UTUN_OPT_IFNAME */,
- baseAddress,
- &ifnameSize)
-
- if result == 0 {
- return String(cString: baseAddress)
- } else {
- return nil
- }
- }
- }
-
- // MARK: - Initialization
-
- /// Designated initializer.
- /// - Parameter packetTunnelProvider: an instance of `NEPacketTunnelProvider`. Internally stored
- /// as a weak reference.
- /// - Parameter logHandler: a log handler closure.
- public init(with packetTunnelProvider: NEPacketTunnelProvider, logHandler: @escaping LogHandler) {
- self.packetTunnelProvider = packetTunnelProvider
- self.logHandler = logHandler
-
- setupLogHandler()
- }
-
- deinit {
- // Force remove logger to make sure that no further calls to the instance of this class
- // can happen after deallocation.
- wgSetLogger(nil, nil)
-
- // Cancel network monitor
- networkMonitor?.cancel()
-
- // Shutdown the tunnel
- if case .started(let handle, _) = self.state {
- wgTurnOff(handle)
- }
- }
-
- // MARK: - Public methods
-
- /// Returns a runtime configuration from WireGuard.
- /// - Parameter completionHandler: completion handler.
- public func getRuntimeConfiguration(completionHandler: @escaping (String?) -> Void) {
- workQueue.async {
- guard case .started(let handle, _) = self.state else {
- completionHandler(nil)
- return
- }
-
- if let settings = wgGetConfig(handle) {
- completionHandler(String(cString: settings))
- free(settings)
- } else {
- completionHandler(nil)
- }
- }
- }
-
- /// Start the tunnel tunnel.
- /// - Parameters:
- /// - tunnelConfiguration: tunnel configuration.
- /// - completionHandler: completion handler.
- public func start(tunnelConfiguration: TunnelConfiguration, completionHandler: @escaping (WireGuardAdapterError?) -> Void) {
- workQueue.async {
- guard case .stopped = self.state else {
- completionHandler(.invalidState)
- return
- }
-
- let networkMonitor = NWPathMonitor()
- networkMonitor.pathUpdateHandler = { [weak self] path in
- self?.didReceivePathUpdate(path: path)
- }
- networkMonitor.start(queue: self.workQueue)
-
- do {
- let settingsGenerator = try self.makeSettingsGenerator(with: tunnelConfiguration)
- try self.setNetworkSettings(settingsGenerator.generateNetworkSettings())
-
- let (wgConfig, resolutionResults) = settingsGenerator.uapiConfiguration()
- self.logEndpointResolutionResults(resolutionResults)
-
- self.state = .started(
- try self.startWireGuardBackend(wgConfig: wgConfig),
- settingsGenerator
- )
- self.networkMonitor = networkMonitor
- completionHandler(nil)
- } catch let error as WireGuardAdapterError {
- networkMonitor.cancel()
- completionHandler(error)
- } catch {
- fatalError()
- }
- }
- }
-
- /// Stop the tunnel.
- /// - Parameter completionHandler: completion handler.
- public func stop(completionHandler: @escaping (WireGuardAdapterError?) -> Void) {
- workQueue.async {
- switch self.state {
- case .started(let handle, _):
- wgTurnOff(handle)
-
- case .temporaryShutdown:
- break
-
- case .stopped:
- completionHandler(.invalidState)
- return
- }
-
- self.networkMonitor?.cancel()
- self.networkMonitor = nil
-
- self.state = .stopped
-
- completionHandler(nil)
- }
- }
-
- /// Update runtime configuration.
- /// - Parameters:
- /// - tunnelConfiguration: tunnel configuration.
- /// - completionHandler: completion handler.
- public func update(tunnelConfiguration: TunnelConfiguration, completionHandler: @escaping (WireGuardAdapterError?) -> Void) {
- workQueue.async {
- if case .stopped = self.state {
- completionHandler(.invalidState)
- return
- }
-
- // Tell the system that the tunnel is going to reconnect using new WireGuard
- // configuration.
- // This will broadcast the `NEVPNStatusDidChange` notification to the GUI process.
- self.packetTunnelProvider?.reasserting = true
- defer {
- self.packetTunnelProvider?.reasserting = false
- }
-
- do {
- let settingsGenerator = try self.makeSettingsGenerator(with: tunnelConfiguration)
- try self.setNetworkSettings(settingsGenerator.generateNetworkSettings())
-
- switch self.state {
- case .started(let handle, _):
- let (wgConfig, resolutionResults) = settingsGenerator.uapiConfiguration()
- self.logEndpointResolutionResults(resolutionResults)
-
- wgSetConfig(handle, wgConfig)
- #if os(iOS)
- wgDisableSomeRoamingForBrokenMobileSemantics(handle)
- #endif
-
- self.state = .started(handle, settingsGenerator)
-
- case .temporaryShutdown:
- self.state = .temporaryShutdown(settingsGenerator)
-
- case .stopped:
- fatalError()
- }
-
- completionHandler(nil)
- } catch let error as WireGuardAdapterError {
- completionHandler(error)
- } catch {
- fatalError()
- }
- }
- }
-
- // MARK: - Private methods
-
- /// Setup WireGuard log handler.
- private func setupLogHandler() {
- let context = Unmanaged.passUnretained(self).toOpaque()
- wgSetLogger(context) { context, logLevel, message in
- guard let context = context, let message = message else { return }
-
- let unretainedSelf = Unmanaged.fromOpaque(context)
- .takeUnretainedValue()
-
- let swiftString = String(cString: message).trimmingCharacters(in: .newlines)
- let tunnelLogLevel = WireGuardLogLevel(rawValue: logLevel) ?? .verbose
-
- unretainedSelf.logHandler(tunnelLogLevel, swiftString)
- }
- }
-
- /// Set network tunnel configuration.
- /// This method ensures that the call to `setTunnelNetworkSettings` does not time out, as in
- /// certain scenarios the completion handler given to it may not be invoked by the system.
- ///
- /// - Parameters:
- /// - networkSettings: an instance of type `NEPacketTunnelNetworkSettings`.
- /// - Throws: an error of type `WireGuardAdapterError`.
- /// - Returns: `PacketTunnelSettingsGenerator`.
- private func setNetworkSettings(_ networkSettings: NEPacketTunnelNetworkSettings) throws {
- var systemError: Error?
- let condition = NSCondition()
-
- // Activate the condition
- condition.lock()
- defer { condition.unlock() }
-
- self.packetTunnelProvider?.setTunnelNetworkSettings(networkSettings) { error in
- systemError = error
- condition.signal()
- }
-
- // Packet tunnel's `setTunnelNetworkSettings` times out in certain
- // scenarios & never calls the given callback.
- let setTunnelNetworkSettingsTimeout: TimeInterval = 5 // seconds
-
- if condition.wait(until: Date().addingTimeInterval(setTunnelNetworkSettingsTimeout)) {
- if let systemError = systemError {
- throw WireGuardAdapterError.setNetworkSettings(systemError)
- }
- } else {
- self.logHandler(.error, "setTunnelNetworkSettings timed out after 5 seconds; proceeding anyway")
- }
- }
-
- /// Resolve peers of the given tunnel configuration.
- /// - Parameter tunnelConfiguration: tunnel configuration.
- /// - Throws: an error of type `WireGuardAdapterError`.
- /// - Returns: The list of resolved endpoints.
- private func resolvePeers(for tunnelConfiguration: TunnelConfiguration) throws -> [Endpoint?] {
- let endpoints = tunnelConfiguration.peers.map { $0.endpoint }
- let resolutionResults = DNSResolver.resolveSync(endpoints: endpoints)
- let resolutionErrors = resolutionResults.compactMap { result -> DNSResolutionError? in
- if case .failure(let error) = result {
- return error
- } else {
- return nil
- }
- }
- assert(endpoints.count == resolutionResults.count)
- guard resolutionErrors.isEmpty else {
- throw WireGuardAdapterError.dnsResolution(resolutionErrors)
- }
-
- let resolvedEndpoints = resolutionResults.map { result -> Endpoint? in
- // swiftlint:disable:next force_try
- return try! result?.get()
- }
-
- return resolvedEndpoints
- }
-
- /// Start WireGuard backend.
- /// - Parameter wgConfig: WireGuard configuration
- /// - Throws: an error of type `WireGuardAdapterError`
- /// - Returns: tunnel handle
- private func startWireGuardBackend(wgConfig: String) throws -> Int32 {
- guard let tunnelFileDescriptor = self.tunnelFileDescriptor else {
- throw WireGuardAdapterError.cannotLocateTunnelFileDescriptor
- }
-
- let handle = wgTurnOn(wgConfig, tunnelFileDescriptor)
- if handle < 0 {
- throw WireGuardAdapterError.startWireGuardBackend(handle)
- }
- #if os(iOS)
- wgDisableSomeRoamingForBrokenMobileSemantics(handle)
- #endif
- return handle
- }
-
- /// Resolves the hostnames in the given tunnel configuration and return settings generator.
- /// - Parameter tunnelConfiguration: an instance of type `TunnelConfiguration`.
- /// - Throws: an error of type `WireGuardAdapterError`.
- /// - Returns: an instance of type `PacketTunnelSettingsGenerator`.
- private func makeSettingsGenerator(with tunnelConfiguration: TunnelConfiguration) throws -> PacketTunnelSettingsGenerator {
- return PacketTunnelSettingsGenerator(
- tunnelConfiguration: tunnelConfiguration,
- resolvedEndpoints: try self.resolvePeers(for: tunnelConfiguration)
- )
- }
-
- /// Log DNS resolution results.
- /// - Parameter resolutionErrors: an array of type `[DNSResolutionError]`.
- private func logEndpointResolutionResults(_ resolutionResults: [EndpointResolutionResult?]) {
- for case .some(let result) in resolutionResults {
- switch result {
- case .success((let sourceEndpoint, let resolvedEndpoint)):
- if sourceEndpoint.host == resolvedEndpoint.host {
- self.logHandler(.verbose, "DNS64: mapped \(sourceEndpoint.host) to itself.")
- } else {
- self.logHandler(.verbose, "DNS64: mapped \(sourceEndpoint.host) to \(resolvedEndpoint.host)")
- }
- case .failure(let resolutionError):
- self.logHandler(.error, "Failed to resolve endpoint \(resolutionError.address): \(resolutionError.errorDescription ?? "(nil)")")
- }
- }
- }
-
- /// Helper method used by network path monitor.
- /// - Parameter path: new network path
- private func didReceivePathUpdate(path: Network.NWPath) {
- self.logHandler(.verbose, "Network change detected with \(path.status) route and interface order \(path.availableInterfaces)")
-
- #if os(macOS)
- if case .started(let handle, _) = self.state {
- wgBumpSockets(handle)
- }
- #elseif os(iOS)
- switch self.state {
- case .started(let handle, let settingsGenerator):
- if path.status.isSatisfiable {
- let (wgConfig, resolutionResults) = settingsGenerator.endpointUapiConfiguration()
- self.logEndpointResolutionResults(resolutionResults)
-
- wgSetConfig(handle, wgConfig)
- wgDisableSomeRoamingForBrokenMobileSemantics(handle)
- wgBumpSockets(handle)
- } else {
- self.logHandler(.verbose, "Connectivity offline, pausing backend.")
-
- self.state = .temporaryShutdown(settingsGenerator)
- wgTurnOff(handle)
- }
-
- case .temporaryShutdown(let settingsGenerator):
- guard path.status.isSatisfiable else { return }
-
- self.logHandler(.verbose, "Connectivity online, resuming backend.")
-
- do {
- try self.setNetworkSettings(settingsGenerator.generateNetworkSettings())
-
- let (wgConfig, resolutionResults) = settingsGenerator.uapiConfiguration()
- self.logEndpointResolutionResults(resolutionResults)
-
- self.state = .started(
- try self.startWireGuardBackend(wgConfig: wgConfig),
- settingsGenerator
- )
- } catch {
- self.logHandler(.error, "Failed to restart backend: \(error.localizedDescription)")
- }
-
- case .stopped:
- // no-op
- break
- }
- #else
- #error("Unsupported")
- #endif
- }
-}
-
-/// A enum describing WireGuard log levels defined in `api-apple.go`.
-public enum WireGuardLogLevel: Int32 {
- case verbose = 0
- case error = 1
-}
-
-private extension Network.NWPath.Status {
- /// Returns `true` if the path is potentially satisfiable.
- var isSatisfiable: Bool {
- switch self {
- case .requiresConnection, .satisfied:
- return true
- case .unsatisfied:
- return false
- @unknown default:
- return true
- }
- }
-}
diff --git a/ios/WireGuardKit/Sources/WireGuardKitC/WireGuardKitC.h b/ios/WireGuardKit/Sources/WireGuardKitC/WireGuardKitC.h
deleted file mode 100644
index 1b8974d..0000000
--- a/ios/WireGuardKit/Sources/WireGuardKitC/WireGuardKitC.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// SPDX-License-Identifier: MIT
-// Copyright © 2018-2023 WireGuard LLC. All Rights Reserved.
-
-#include
-#include "key.h"
-#include "x25519.h"
-
-/* From */
-#define CTLIOCGINFO 0xc0644e03UL
-struct ctl_info {
- u_int32_t ctl_id;
- char ctl_name[96];
-};
-struct sockaddr_ctl {
- u_char sc_len;
- u_char sc_family;
- u_int16_t ss_sysaddr;
- u_int32_t sc_id;
- u_int32_t sc_unit;
- u_int32_t sc_reserved[5];
-};
diff --git a/ios/WireGuardKit/Sources/WireGuardKitC/key.c b/ios/WireGuardKit/Sources/WireGuardKitC/key.c
deleted file mode 100644
index 84e7f16..0000000
--- a/ios/WireGuardKit/Sources/WireGuardKitC/key.c
+++ /dev/null
@@ -1,124 +0,0 @@
-// SPDX-License-Identifier: MIT
-/*
- * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved.
- *
- * This is a specialized constant-time base64/hex implementation that resists side-channel attacks.
- */
-
-#include
-#include "key.h"
-
-static inline void encode_base64(char dest[static 4], const uint8_t src[static 3])
-{
- const uint8_t input[] = { (src[0] >> 2) & 63, ((src[0] << 4) | (src[1] >> 4)) & 63, ((src[1] << 2) | (src[2] >> 6)) & 63, src[2] & 63 };
-
- for (unsigned int i = 0; i < 4; ++i)
- dest[i] = input[i] + 'A'
- + (((25 - input[i]) >> 8) & 6)
- - (((51 - input[i]) >> 8) & 75)
- - (((61 - input[i]) >> 8) & 15)
- + (((62 - input[i]) >> 8) & 3);
-
-}
-
-void key_to_base64(char base64[static WG_KEY_LEN_BASE64], const uint8_t key[static WG_KEY_LEN])
-{
- unsigned int i;
-
- for (i = 0; i < WG_KEY_LEN / 3; ++i)
- encode_base64(&base64[i * 4], &key[i * 3]);
- encode_base64(&base64[i * 4], (const uint8_t[]){ key[i * 3 + 0], key[i * 3 + 1], 0 });
- base64[WG_KEY_LEN_BASE64 - 2] = '=';
- base64[WG_KEY_LEN_BASE64 - 1] = '\0';
-}
-
-static inline int decode_base64(const char src[static 4])
-{
- int val = 0;
-
- for (unsigned int i = 0; i < 4; ++i)
- val |= (-1
- + ((((('A' - 1) - src[i]) & (src[i] - ('Z' + 1))) >> 8) & (src[i] - 64))
- + ((((('a' - 1) - src[i]) & (src[i] - ('z' + 1))) >> 8) & (src[i] - 70))
- + ((((('0' - 1) - src[i]) & (src[i] - ('9' + 1))) >> 8) & (src[i] + 5))
- + ((((('+' - 1) - src[i]) & (src[i] - ('+' + 1))) >> 8) & 63)
- + ((((('/' - 1) - src[i]) & (src[i] - ('/' + 1))) >> 8) & 64)
- ) << (18 - 6 * i);
- return val;
-}
-
-bool key_from_base64(uint8_t key[static WG_KEY_LEN], const char *base64)
-{
- unsigned int i;
- volatile uint8_t ret = 0;
- int val;
-
- if (strlen(base64) != WG_KEY_LEN_BASE64 - 1 || base64[WG_KEY_LEN_BASE64 - 2] != '=')
- return false;
-
- for (i = 0; i < WG_KEY_LEN / 3; ++i) {
- val = decode_base64(&base64[i * 4]);
- ret |= (uint32_t)val >> 31;
- key[i * 3 + 0] = (val >> 16) & 0xff;
- key[i * 3 + 1] = (val >> 8) & 0xff;
- key[i * 3 + 2] = val & 0xff;
- }
- val = decode_base64((const char[]){ base64[i * 4 + 0], base64[i * 4 + 1], base64[i * 4 + 2], 'A' });
- ret |= ((uint32_t)val >> 31) | (val & 0xff);
- key[i * 3 + 0] = (val >> 16) & 0xff;
- key[i * 3 + 1] = (val >> 8) & 0xff;
-
- return 1 & ((ret - 1) >> 8);
-}
-
-void key_to_hex(char hex[static WG_KEY_LEN_HEX], const uint8_t key[static WG_KEY_LEN])
-{
- unsigned int i;
-
- for (i = 0; i < WG_KEY_LEN; ++i) {
- hex[i * 2] = 87U + (key[i] >> 4) + ((((key[i] >> 4) - 10U) >> 8) & ~38U);
- hex[i * 2 + 1] = 87U + (key[i] & 0xf) + ((((key[i] & 0xf) - 10U) >> 8) & ~38U);
- }
- hex[i * 2] = '\0';
-}
-
-bool key_from_hex(uint8_t key[static WG_KEY_LEN], const char *hex)
-{
- uint8_t c, c_acc, c_alpha0, c_alpha, c_num0, c_num, c_val;
- volatile uint8_t ret = 0;
-
- if (strlen(hex) != WG_KEY_LEN_HEX - 1)
- return false;
-
- for (unsigned int i = 0; i < WG_KEY_LEN_HEX - 1; i += 2) {
- c = (uint8_t)hex[i];
- c_num = c ^ 48U;
- c_num0 = (c_num - 10U) >> 8;
- c_alpha = (c & ~32U) - 55U;
- c_alpha0 = ((c_alpha - 10U) ^ (c_alpha - 16U)) >> 8;
- ret |= ((c_num0 | c_alpha0) - 1) >> 8;
- c_val = (c_num0 & c_num) | (c_alpha0 & c_alpha);
- c_acc = c_val * 16U;
-
- c = (uint8_t)hex[i + 1];
- c_num = c ^ 48U;
- c_num0 = (c_num - 10U) >> 8;
- c_alpha = (c & ~32U) - 55U;
- c_alpha0 = ((c_alpha - 10U) ^ (c_alpha - 16U)) >> 8;
- ret |= ((c_num0 | c_alpha0) - 1) >> 8;
- c_val = (c_num0 & c_num) | (c_alpha0 & c_alpha);
- key[i / 2] = c_acc | c_val;
- }
-
- return 1 & ((ret - 1) >> 8);
-}
-
-bool key_eq(const uint8_t key1[static WG_KEY_LEN], const uint8_t key2[static WG_KEY_LEN])
-{
- volatile uint8_t acc = 0;
- for (unsigned int i = 0; i < WG_KEY_LEN; ++i) {
- acc |= key1[i] ^ key2[i];
- asm volatile("" : "=r"(acc) : "0"(acc));
- }
- return 1 & ((acc - 1) >> 8);
-}
diff --git a/ios/WireGuardKit/Sources/WireGuardKitC/key.h b/ios/WireGuardKit/Sources/WireGuardKitC/key.h
deleted file mode 100644
index 5353ade..0000000
--- a/ios/WireGuardKit/Sources/WireGuardKitC/key.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/*
- * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved.
- */
-
-#ifndef KEY_H
-#define KEY_H
-
-#include
-#include
-
-#define WG_KEY_LEN (32)
-#define WG_KEY_LEN_BASE64 (45)
-#define WG_KEY_LEN_HEX (65)
-
-void key_to_base64(char base64[static WG_KEY_LEN_BASE64], const uint8_t key[static WG_KEY_LEN]);
-bool key_from_base64(uint8_t key[static WG_KEY_LEN], const char *base64);
-
-void key_to_hex(char hex[static WG_KEY_LEN_HEX], const uint8_t key[static WG_KEY_LEN]);
-bool key_from_hex(uint8_t key[static WG_KEY_LEN], const char *hex);
-
-bool key_eq(const uint8_t key1[static WG_KEY_LEN], const uint8_t key2[static WG_KEY_LEN]);
-
-#endif
diff --git a/ios/WireGuardKit/Sources/WireGuardKitC/module.modulemap b/ios/WireGuardKit/Sources/WireGuardKitC/module.modulemap
deleted file mode 100644
index 26b45bf..0000000
--- a/ios/WireGuardKit/Sources/WireGuardKitC/module.modulemap
+++ /dev/null
@@ -1,4 +0,0 @@
-module WireGuardKitC {
- umbrella header "WireGuardKitC.h"
- export *
-}
diff --git a/ios/WireGuardKit/Sources/WireGuardKitC/x25519.c b/ios/WireGuardKit/Sources/WireGuardKitC/x25519.c
deleted file mode 100644
index 7793299..0000000
--- a/ios/WireGuardKit/Sources/WireGuardKitC/x25519.c
+++ /dev/null
@@ -1,178 +0,0 @@
-/* SPDX-License-Identifier: MIT
- *
- * Copyright (C) 2015-2019 Jason A. Donenfeld . All Rights Reserved.
- *
- * Curve25519 ECDH functions, based on TweetNaCl but cleaned up.
- */
-
-#include
-#include
-#include
-#include
-
-#include "x25519.h"
-
-typedef int64_t fe[16];
-
-static inline void carry(fe o)
-{
- int i;
-
- for (i = 0; i < 16; ++i) {
- o[(i + 1) % 16] += (i == 15 ? 38 : 1) * (o[i] >> 16);
- o[i] &= 0xffff;
- }
-}
-
-static inline void cswap(fe p, fe q, int b)
-{
- int i;
- int64_t t, c = ~(b - 1);
-
- for (i = 0; i < 16; ++i) {
- t = c & (p[i] ^ q[i]);
- p[i] ^= t;
- q[i] ^= t;
- }
-}
-
-static inline void pack(uint8_t *o, const fe n)
-{
- int i, j, b;
- fe m, t;
-
- memcpy(t, n, sizeof(t));
- carry(t);
- carry(t);
- carry(t);
- for (j = 0; j < 2; ++j) {
- m[0] = t[0] - 0xffed;
- for (i = 1; i < 15; ++i) {
- m[i] = t[i] - 0xffff - ((m[i - 1] >> 16) & 1);
- m[i - 1] &= 0xffff;
- }
- m[15] = t[15] - 0x7fff - ((m[14] >> 16) & 1);
- b = (m[15] >> 16) & 1;
- m[14] &= 0xffff;
- cswap(t, m, 1 - b);
- }
- for (i = 0; i < 16; ++i) {
- o[2 * i] = t[i] & 0xff;
- o[2 * i + 1] = t[i] >> 8;
- }
-}
-
-static inline void unpack(fe o, const uint8_t *n)
-{
- int i;
-
- for (i = 0; i < 16; ++i)
- o[i] = n[2 * i] + ((int64_t)n[2 * i + 1] << 8);
- o[15] &= 0x7fff;
-}
-
-static inline void add(fe o, const fe a, const fe b)
-{
- int i;
-
- for (i = 0; i < 16; ++i)
- o[i] = a[i] + b[i];
-}
-
-static inline void subtract(fe o, const fe a, const fe b)
-{
- int i;
-
- for (i = 0; i < 16; ++i)
- o[i] = a[i] - b[i];
-}
-
-static inline void multmod(fe o, const fe a, const fe b)
-{
- int i, j;
- int64_t t[31] = { 0 };
-
- for (i = 0; i < 16; ++i) {
- for (j = 0; j < 16; ++j)
- t[i + j] += a[i] * b[j];
- }
- for (i = 0; i < 15; ++i)
- t[i] += 38 * t[i + 16];
- memcpy(o, t, sizeof(fe));
- carry(o);
- carry(o);
-}
-
-static inline void invert(fe o, const fe i)
-{
- fe c;
- int a;
-
- memcpy(c, i, sizeof(c));
- for (a = 253; a >= 0; --a) {
- multmod(c, c, c);
- if (a != 2 && a != 4)
- multmod(c, c, i);
- }
- memcpy(o, c, sizeof(fe));
-}
-
-static void curve25519_shared_secret(uint8_t shared_secret[32], const uint8_t private_key[32], const uint8_t public_key[32])
-{
- static const fe a24 = { 0xdb41, 1 };
- uint8_t z[32];
- int64_t r;
- int i;
- fe a = { 1 }, b, c = { 0 }, d = { 1 }, e, f, x;
-
- memcpy(z, private_key, sizeof(z));
-
- z[31] = (z[31] & 127) | 64;
- z[0] &= 248;
-
- unpack(x, public_key);
- memcpy(b, x, sizeof(b));
-
- for (i = 254; i >= 0; --i) {
- r = (z[i >> 3] >> (i & 7)) & 1;
- cswap(a, b, (int)r);
- cswap(c, d, (int)r);
- add(e, a, c);
- subtract(a, a, c);
- add(c, b, d);
- subtract(b, b, d);
- multmod(d, e, e);
- multmod(f, a, a);
- multmod(a, c, a);
- multmod(c, b, e);
- add(e, a, c);
- subtract(a, a, c);
- multmod(b, a, a);
- subtract(c, d, f);
- multmod(a, c, a24);
- add(a, a, d);
- multmod(c, c, a);
- multmod(a, d, f);
- multmod(d, b, x);
- multmod(b, e, e);
- cswap(a, b, (int)r);
- cswap(c, d, (int)r);
- }
- invert(c, c);
- multmod(a, a, c);
- pack(shared_secret, a);
-}
-
-void curve25519_derive_public_key(uint8_t public_key[32], const uint8_t private_key[32])
-{
- static const uint8_t basepoint[32] = { 9 };
-
- curve25519_shared_secret(public_key, private_key, basepoint);
-}
-
-void curve25519_generate_private_key(uint8_t private_key[32])
-{
- assert(CCRandomGenerateBytes(private_key, 32) == kCCSuccess);
- private_key[31] = (private_key[31] & 127) | 64;
- private_key[0] &= 248;
-}
diff --git a/ios/WireGuardKit/Sources/WireGuardKitC/x25519.h b/ios/WireGuardKit/Sources/WireGuardKitC/x25519.h
deleted file mode 100644
index 7d8440d..0000000
--- a/ios/WireGuardKit/Sources/WireGuardKitC/x25519.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef X25519_H
-#define X25519_H
-
-void curve25519_derive_public_key(unsigned char public_key[32], const unsigned char private_key[32]);
-void curve25519_generate_private_key(unsigned char private_key[32]);
-
-#endif
diff --git a/ios/WireGuardKit/Sources/WireGuardKitGo/dummy.c b/ios/WireGuardKit/Sources/WireGuardKitGo/dummy.c
deleted file mode 100644
index d15abba..0000000
--- a/ios/WireGuardKit/Sources/WireGuardKitGo/dummy.c
+++ /dev/null
@@ -1 +0,0 @@
-// Empty
diff --git a/ios/WireGuardKit/Sources/WireGuardKitGo/module.modulemap b/ios/WireGuardKit/Sources/WireGuardKitGo/module.modulemap
deleted file mode 100644
index 2ca3916..0000000
--- a/ios/WireGuardKit/Sources/WireGuardKitGo/module.modulemap
+++ /dev/null
@@ -1,5 +0,0 @@
-module WireGuardKitGo {
- umbrella header "wireguard.h"
- link "wg-go"
- export *
-}
diff --git a/ios/WireGuardKit/Sources/WireGuardKitGo/wireguard.h b/ios/WireGuardKit/Sources/WireGuardKitGo/wireguard.h
deleted file mode 100644
index fdb66c2..0000000
--- a/ios/WireGuardKit/Sources/WireGuardKitGo/wireguard.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* SPDX-License-Identifier: MIT
- *
- * Copyright (C) 2018-2023 WireGuard LLC. All Rights Reserved.
- */
-
-#ifndef WIREGUARD_H
-#define WIREGUARD_H
-
-#include
-#include
-#include
-
-typedef void(*logger_fn_t)(void *context, int level, const char *msg);
-extern void wgSetLogger(void *context, logger_fn_t logger_fn);
-extern int wgTurnOn(const char *settings, int32_t tun_fd);
-extern void wgTurnOff(int handle);
-extern int64_t wgSetConfig(int handle, const char *settings);
-extern char *wgGetConfig(int handle);
-extern void wgBumpSockets(int handle);
-extern void wgDisableSomeRoamingForBrokenMobileSemantics(int handle);
-extern const char *wgVersion();
-
-#endif
diff --git a/ios/project.yml b/ios/project.yml
deleted file mode 100644
index 4c671c5..0000000
--- a/ios/project.yml
+++ /dev/null
@@ -1,79 +0,0 @@
-# xcodegen spec: `xcodegen generate` -> PCAPhobos.xcodeproj
-# Signing: set DEVELOPMENT_TEAM (paid Apple Developer account — Network Extension needs it).
-name: PCAPhobos
-options:
- bundleIdPrefix: com.bobyrev
- deploymentTarget:
- iOS: "16.0"
-packages:
- WireGuardKit:
- path: WireGuardKit
-settings:
- base:
- MARKETING_VERSION: "1.4.1"
- CURRENT_PROJECT_VERSION: "141"
- DEVELOPMENT_TEAM: ""
- CODE_SIGN_STYLE: Automatic
-targets:
- PCAPhobos:
- type: application
- platform: iOS
- sources:
- - App
- - Shared
- resources:
- - App/Assets.xcassets
- dependencies:
- - target: PhobosTunnel
- entitlements:
- path: App/PCAPhobos.entitlements
- properties:
- com.apple.developer.networking.networkextension: [packet-tunnel-provider]
- info:
- path: App/Info.plist
- properties:
- CFBundleDisplayName: PCA Phobos
- UILaunchScreen: {}
- UISupportedInterfaceOrientations: [UIInterfaceOrientationPortrait]
- CFBundleURLTypes:
- - CFBundleURLName: com.bobyrev.pcaphobos.link
- CFBundleURLSchemes: [phobos]
- settings:
- base:
- PRODUCT_BUNDLE_IDENTIFIER: com.bobyrev.pcaphobos
- ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon
- PhobosTunnel:
- type: app-extension
- platform: iOS
- sources:
- - Tunnel/PacketTunnelProvider.swift
- - Tunnel/TunnelConfiguration+WgQuickConfig.swift
- - Tunnel/String+ArrayConversion.swift
- - Tunnel/pcarelay.c
- - Shared
- - path: Tunnel/ru_bypass.txt
- buildPhase: resources
- - path: Tunnel/obfuscator
- compilerFlags: ["-Dmain=wgobf_main", "-w"]
- excludes: ["*.h"]
- dependencies:
- - package: WireGuardKit
- entitlements:
- path: Tunnel/PhobosTunnel.entitlements
- properties:
- com.apple.developer.networking.networkextension: [packet-tunnel-provider]
- info:
- path: Tunnel/Info.plist
- properties:
- CFBundleDisplayName: PhobosTunnel
- NSExtension:
- NSExtensionPointIdentifier: com.apple.networkextension.packet-tunnel
- NSExtensionPrincipalClass: $(PRODUCT_MODULE_NAME).PacketTunnelProvider
- settings:
- base:
- PRODUCT_BUNDLE_IDENTIFIER: com.bobyrev.pcaphobos.tunnel
- SWIFT_OBJC_BRIDGING_HEADER: Tunnel/Tunnel-Bridging-Header.h
- HEADER_SEARCH_PATHS: ["$(PROJECT_DIR)/Tunnel", "$(PROJECT_DIR)/Tunnel/obfuscator"]
- "LIBRARY_SEARCH_PATHS[sdk=iphoneos*]": ["$(PROJECT_DIR)/WireGuardGo/iphoneos"]
- "LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]": ["$(PROJECT_DIR)/WireGuardGo/iphonesimulator"]
- "EXCLUDED_ARCHS[sdk=iphonesimulator*]": x86_64
diff --git a/overlay/3xui.sh b/overlay/3xui.sh
deleted file mode 100755
index cc4edd4..0000000
--- a/overlay/3xui.sh
+++ /dev/null
@@ -1,456 +0,0 @@
-#!/bin/bash
-
-GREEN='\033[92m'
-YELLOW='\033[93m'
-RED='\033[91m'
-BLUE='\033[94m'
-CYAN='\033[96m'
-RESET='\033[0m'
-BOLD='\033[1m'
-
-print_status() {
- local message="$1"
- local status="${2:-info}"
- local prefix=""
- case "$status" in
- success) prefix="${GREEN}[OK]" ;;
- error) prefix="${RED}[ERR]" ;;
- warning) prefix="${YELLOW}[WARN]" ;;
- info) prefix="${BLUE}[INFO]" ;;
- debug) prefix="${CYAN}[DBG]" ;;
- esac
- echo -e "${prefix} ${message}${RESET}"
-}
-
-check_dependencies() {
- local missing=()
- for cmd in jq sqlite3; do
- if ! command -v "$cmd" >/dev/null 2>&1; then
- missing+=("$cmd")
- fi
- done
- if [[ ${#missing[@]} -gt 0 ]]; then
- print_status "Installing missing dependencies: ${missing[*]}" "info"
- if command -v apt-get >/dev/null 2>&1; then
- apt-get update -qq && apt-get install -y -qq "${missing[@]}" >/dev/null 2>&1
- elif command -v yum >/dev/null 2>&1; then
- yum install -y -q "${missing[@]/sqlite3/sqlite}" >/dev/null 2>&1
- elif command -v dnf >/dev/null 2>&1; then
- dnf install -y -q "${missing[@]/sqlite3/sqlite}" >/dev/null 2>&1
- elif command -v apk >/dev/null 2>&1; then
- apk add --quiet "${missing[@]/sqlite3/sqlite}" >/dev/null 2>&1
- fi
- for cmd in "${missing[@]}"; do
- if ! command -v "$cmd" >/dev/null 2>&1; then
- print_status "Failed to install $cmd" "error"
- exit 1
- fi
- done
- print_status "Dependencies installed successfully" "success"
- fi
-}
-
-parse_wireguard_conf() {
- local config_path="$1"
- local section=""
-
- if [[ ! -f "$config_path" ]]; then
- print_status "File $config_path not found" "error"
- exit 1
- fi
-
- INTERFACE_PRIVATEKEY=""
- INTERFACE_ADDRESS=""
- INTERFACE_MTU="1420"
- PEER_PUBLICKEY=""
- PEER_ENDPOINT=""
- PEER_ALLOWEDIPS=""
- PEER_PRESHAREDKEY=""
- PEER_KEEPALIVE="0"
-
- while IFS= read -r line || [[ -n "$line" ]]; do
- line=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
- [[ -z "$line" || "$line" == \#* ]] && continue
-
- if [[ "$line" == "["*"]" ]]; then
- section=$(echo "$line" | tr -d '[]' | tr '[:upper:]' '[:lower:]')
- continue
- fi
-
- if [[ "$line" == *"="* ]]; then
- local key=$(echo "$line" | cut -d'=' -f1 | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
- local value=$(echo "$line" | cut -d'=' -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
-
- if [[ "$section" == "interface" ]]; then
- case "$key" in
- PrivateKey) INTERFACE_PRIVATEKEY="$value" ;;
- Address) INTERFACE_ADDRESS="$value" ;;
- MTU) INTERFACE_MTU="$value" ;;
- esac
- elif [[ "$section" == "peer" ]]; then
- case "$key" in
- PublicKey) PEER_PUBLICKEY="$value" ;;
- Endpoint) PEER_ENDPOINT="$value" ;;
- AllowedIPs) PEER_ALLOWEDIPS="$value" ;;
- PresharedKey|PreSharedKey) PEER_PRESHAREDKEY="$value" ;;
- PersistentKeepalive) PEER_KEEPALIVE="$value" ;;
- esac
- fi
- fi
- done < "$config_path"
-}
-
-extract_endpoint() {
- local endpoint="$1"
- if [[ "$endpoint" == "["*"]:"* ]]; then
- SERVER_ADDRESS=$(echo "$endpoint" | sed 's/^\[\([^]]*\)\]:.*/\1/')
- SERVER_PORT=$(echo "$endpoint" | sed 's/.*\]:\([0-9]*\).*/\1/')
- else
- SERVER_ADDRESS=$(echo "$endpoint" | rev | cut -d':' -f2- | rev)
- SERVER_PORT=$(echo "$endpoint" | rev | cut -d':' -f1 | rev)
- fi
- [[ -z "$SERVER_PORT" ]] && SERVER_PORT="51820"
-}
-
-build_local_addresses() {
- local addresses="$1"
- local result="[]"
-
- IFS=',' read -ra ADDR_ARRAY <<< "$addresses"
- for addr in "${ADDR_ARRAY[@]}"; do
- addr=$(echo "$addr" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
- [[ -z "$addr" ]] && continue
-
- local ip_part="$addr"
- if [[ "$addr" == *"/"* ]]; then
- ip_part=$(echo "$addr" | cut -d'/' -f1)
- fi
-
- if [[ "$ip_part" == *":"* ]]; then
- result=$(echo "$result" | jq --arg ip "${ip_part}/128" '. + [$ip]')
- else
- result=$(echo "$result" | jq --arg ip "${ip_part}/32" '. + [$ip]')
- fi
- done
-
- echo "$result"
-}
-
-build_allowed_ips() {
- local allowed="$1"
- local result="[]"
-
- if [[ -z "$allowed" ]]; then
- echo '["0.0.0.0/0", "::/0"]'
- return
- fi
-
- IFS=',' read -ra IP_ARRAY <<< "$allowed"
- for ip in "${IP_ARRAY[@]}"; do
- ip=$(echo "$ip" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
- [[ -z "$ip" ]] && continue
- result=$(echo "$result" | jq --arg ip "$ip" '. + [$ip]')
- done
-
- if [[ "$result" == "[]" ]]; then
- echo '["0.0.0.0/0", "::/0"]'
- else
- echo "$result"
- fi
-}
-
-convert_to_xray_outbound() {
- local tag="${1:-Phobos}"
-
- extract_endpoint "$PEER_ENDPOINT"
-
- local local_addresses=$(build_local_addresses "$INTERFACE_ADDRESS")
- local allowed_ips=$(build_allowed_ips "$PEER_ALLOWEDIPS")
-
- local peer_config
- peer_config=$(jq -n \
- --arg pubkey "$PEER_PUBLICKEY" \
- --argjson allowed "$allowed_ips" \
- --arg endpoint "${SERVER_ADDRESS}:${SERVER_PORT}" \
- '{
- "publicKey": $pubkey,
- "allowedIPs": $allowed,
- "endpoint": $endpoint
- }')
-
- if [[ -n "$PEER_KEEPALIVE" && "$PEER_KEEPALIVE" != "0" ]]; then
- peer_config=$(echo "$peer_config" | jq --argjson ka "$PEER_KEEPALIVE" '. + {"keepAlive": $ka}')
- fi
-
- if [[ -n "$PEER_PRESHAREDKEY" ]]; then
- peer_config=$(echo "$peer_config" | jq --arg psk "$PEER_PRESHAREDKEY" '. + {"preSharedKey": $psk}')
- fi
-
- local mtu="${INTERFACE_MTU:-1420}"
-
- OUTBOUND_JSON=$(jq -n \
- --arg tag "$tag" \
- --argjson mtu "$mtu" \
- --arg secret "$INTERFACE_PRIVATEKEY" \
- --argjson addresses "$local_addresses" \
- --argjson peer "$peer_config" \
- '{
- "protocol": "wireguard",
- "settings": {
- "mtu": $mtu,
- "secretKey": $secret,
- "address": $addresses,
- "workers": 2,
- "peers": [$peer],
- "noKernelTun": true
- },
- "tag": $tag
- }')
-}
-
-get_default_xray_config() {
- cat <<'XRAY_CONFIG'
-{
- "api": {
- "services": ["HandlerService", "StatsService", "LoggerService"],
- "tag": "api"
- },
- "inbounds": [
- {
- "listen": "127.0.0.1",
- "port": 62789,
- "protocol": "dokodemo-door",
- "settings": {"address": "127.0.0.1"},
- "tag": "api"
- }
- ],
- "outbounds": [
- {"protocol": "freedom", "settings": {}, "tag": "direct"},
- {"protocol": "blackhole", "settings": {}, "tag": "block"}
- ],
- "policy": {
- "levels": {"0": {"statsUserDownlink": true, "statsUserUplink": true}},
- "system": {
- "statsInboundDownlink": true,
- "statsInboundUplink": true,
- "statsOutboundDownlink": true,
- "statsOutboundUplink": true
- }
- },
- "routing": {
- "domainStrategy": "AsIs",
- "rules": [
- {"inboundTag": ["api"], "outboundTag": "api", "type": "field"},
- {"ip": ["geoip:private"], "outboundTag": "block", "type": "field"}
- ]
- },
- "stats": {}
-}
-XRAY_CONFIG
-}
-
-find_database() {
- local paths=(
- "/etc/x-ui/x-ui.db"
- "/usr/local/x-ui/x-ui.db"
- "/opt/x-ui/x-ui.db"
- "./x-ui.db"
- )
-
- for path in "${paths[@]}"; do
- if [[ -f "$path" ]]; then
- print_status "Database found: $path" "success" >&2
- echo "$path"
- return 0
- fi
- done
-
- return 1
-}
-
-diagnose_database() {
- local db_path="$1"
-
- local tables=$(sqlite3 "$db_path" "SELECT name FROM sqlite_master WHERE type='table';" 2>/dev/null)
- print_status "Found tables: $tables" "debug" >&2
-
- if echo "$tables" | grep -q "settings"; then
- local keys=$(sqlite3 "$db_path" "SELECT key FROM settings;" 2>/dev/null)
- print_status "Keys in settings: $keys" "debug" >&2
-
- for key in xrayTemplateConfig xrayConfig xray_config config; do
- local result=$(sqlite3 "$db_path" "SELECT value FROM settings WHERE key = '$key';" 2>/dev/null)
- if [[ -n "$result" ]]; then
- print_status "Found config key: $key" "success" >&2
- echo "$key"
- return 0
- fi
- done
- fi
-
- return 1
-}
-
-write_setting_to_db() {
- local db_path="$1"
- local config_key="$2"
- local config_value="$3"
- local tmp
- tmp=$(mktemp)
- printf '%s' "$config_value" > "$tmp"
- sqlite3 "$db_path" "INSERT OR REPLACE INTO settings (key, value) VALUES ('$config_key', readfile('$tmp'));"
- local ret=$?
- rm -f "$tmp"
- return $ret
-}
-
-import_via_database() {
- local db_path="$1"
-
- print_status "Importing to database..." "info"
-
- if [[ ! -f "$db_path" ]]; then
- print_status "Database not found: $db_path" "error"
- return 1
- fi
-
- local config_key=$(diagnose_database "$db_path")
-
- if [[ -z "$config_key" ]]; then
- print_status "Xray config not found in database, creating new..." "warning"
-
- local base_config=$(get_default_xray_config)
- local new_config=$(echo "$base_config" | jq --argjson ob "$OUTBOUND_JSON" '.outbounds = [$ob] + .outbounds')
-
- if write_setting_to_db "$db_path" "xrayTemplateConfig" "$new_config"; then
- print_status "Base Xray config created with outbound" "success"
- return 0
- else
- print_status "Failed to create config" "error"
- return 1
- fi
- fi
-
- local current_config=$(sqlite3 "$db_path" "SELECT value FROM settings WHERE key = '$config_key';" 2>/dev/null)
-
- if [[ -z "$current_config" ]]; then
- print_status "Xray config not found" "error"
- return 1
- fi
-
- if ! echo "$current_config" | jq . >/dev/null 2>&1; then
- print_status "Invalid JSON in config" "error"
- return 1
- fi
-
- local tag=$(echo "$OUTBOUND_JSON" | jq -r '.tag')
- local existing_tag=$(echo "$current_config" | jq -r --arg t "$tag" '.outbounds[]? | select(.tag == $t) | .tag' 2>/dev/null)
-
- if [[ -n "$existing_tag" ]]; then
- print_status "Outbound '$tag' exists, replacing..." "warning"
- current_config=$(echo "$current_config" | jq --arg t "$tag" '.outbounds = [.outbounds[] | select(.tag != $t)]')
- fi
-
- local new_config=$(echo "$current_config" | jq --argjson ob "$OUTBOUND_JSON" '.outbounds = [$ob] + .outbounds')
-
- if write_setting_to_db "$db_path" "$config_key" "$new_config"; then
- print_status "Outbound added to database" "success"
- return 0
- else
- print_status "Failed to update database" "error"
- return 1
- fi
-}
-
-restart_xui_service() {
- print_status "Restarting x-ui service..." "info"
-
- if systemctl restart x-ui 2>/dev/null; then
- sleep 1
- if systemctl is-active --quiet x-ui; then
- print_status "x-ui service restarted and active" "success"
- return 0
- fi
- fi
-
- for cmd in "service x-ui restart" "/etc/init.d/x-ui restart" "x-ui restart"; do
- if $cmd 2>/dev/null; then
- print_status "Service restarted via: $cmd" "success"
- return 0
- fi
- done
-
- print_status "Failed to restart service automatically" "error"
- print_status "Restart manually: systemctl restart x-ui" "info"
- return 1
-}
-
-main() {
- echo -e "\n${BOLD}=== WireGuard to 3x-ui Auto-Import Tool ===${RESET}\n"
-
- check_dependencies
-
- local config_path="$1"
- if [[ -z "$config_path" ]]; then
- echo -n "Path to wireguard.conf: "
- read config_path
- fi
-
- print_status "Parsing $config_path..." "info"
- parse_wireguard_conf "$config_path"
-
- print_status "Converting to Xray format..." "info"
- convert_to_xray_outbound "Phobos"
-
- echo -e "\n${BOLD}Outbound configuration:${RESET}"
- echo "$OUTBOUND_JSON" | jq .
- echo
-
- local db_path="/etc/x-ui/x-ui.db"
- if [[ ! -f "$db_path" ]]; then
- print_status "Database not found at: $db_path" "warning"
- db_path=$(find_database)
- if [[ -z "$db_path" ]]; then
- print_status "Database not found in standard locations" "error"
- print_status "Make sure 3x-ui is installed" "info"
- exit 1
- fi
- fi
-
- systemctl stop x-ui 2>/dev/null
- if ! import_via_database "$db_path"; then
- systemctl start x-ui 2>/dev/null
- print_status "Database import failed" "error"
- exit 1
- fi
-
- local output_path="${config_path%.*}_3xui_outbound.json"
- echo "$OUTBOUND_JSON" | jq . > "$output_path" 2>/dev/null
- if [[ $? -eq 0 ]]; then
- print_status "JSON saved to: $output_path" "success"
- fi
-
- echo
- local restart_ok=0
- restart_xui_service && restart_ok=1
-
- echo
- print_status "Import completed successfully!" "success"
- echo
- print_status "${BOLD}Info:${RESET}" "info"
- print_status " Outbound 'Phobos' added to config" "info"
- if [[ $restart_ok -eq 1 ]]; then
- print_status " x-ui service restarted" "info"
- else
- print_status " x-ui service needs manual restart" "warning"
- fi
- print_status " JSON config saved to $output_path" "info"
- echo
- print_status "${BOLD}Verification:${RESET}" "info"
- print_status " Open 3x-ui web panel" "info"
- print_status " Go to Outbounds section" "info"
- print_status " Verify 'Phobos' outbound is present" "info"
- echo
-}
-
-main "$@"
diff --git a/overlay/install-obfuscator.sh b/overlay/install-obfuscator.sh
deleted file mode 100755
index 6b8b480..0000000
--- a/overlay/install-obfuscator.sh
+++ /dev/null
@@ -1,248 +0,0 @@
-OBF_BINARY_NAME="wg-obfuscator"
-OBF_CONF_NAME="wg-obfuscator.conf"
-OBF_INIT_NAME="S49wg-obfuscator"
-OBF_SERVICE_NAME="phobos-obfuscator"
-OBF_WG_IFACE="phobos"
-
-resolve_install_names() {
- local binary_dir
- local binary_path
-
- if [ "$ROUTER_PLATFORM" = "openwrt" ]; then
- binary_dir="/usr/bin"
- elif [ "$ROUTER_PLATFORM" = "linux" ]; then
- binary_dir="/usr/local/bin"
- else
- binary_dir="/opt/bin"
- fi
-
- binary_path="${binary_dir}/wg-obfuscator"
-
- if [ ! -f "$binary_path" ] && [ ! -f "$PHOBOS_DIR/wg-obfuscator.conf" ]; then
- return
- fi
-
- if [ -f "$binary_path" ] && [ -f "$PHOBOS_DIR/${CLIENT_NAME}.conf" ]; then
- return
- fi
-
- local idx=1
- while [ -f "${binary_dir}/wg-obfuscator${idx}" ]; do
- idx=$((idx + 1))
- done
-
- local init_num=50
- while [ -f "/opt/etc/init.d/S${init_num}wg-obfuscator" ]; do
- init_num=$((init_num + 1))
- done
-
- OBF_BINARY_NAME="wg-obfuscator${idx}"
- OBF_CONF_NAME="wg-obfuscator${idx}.conf"
- OBF_INIT_NAME="S${init_num}wg-obfuscator"
- OBF_SERVICE_NAME="phobos-obfuscator${idx}"
- OBF_WG_IFACE="phobos${idx}"
-}
-
-install_obfuscator() {
- local arch=$1
-
- log "Установка wg-obfuscator для архитектуры $arch..."
-
- if [ "$OBF_BINARY_NAME" = "wg-obfuscator" ]; then
- if [ -f /opt/etc/init.d/S49wg-obfuscator ]; then
- log "Остановка текущего процесса wg-obfuscator..."
- /opt/etc/init.d/S49wg-obfuscator stop >/dev/null 2>&1 || true
- fi
-
- if [ -f /etc/init.d/phobos-obfuscator ]; then
- log "Остановка текущего процесса wg-obfuscator..."
- /etc/init.d/phobos-obfuscator stop >/dev/null 2>&1 || true
- fi
- fi
-
- local binary_name="wg-obfuscator-$arch"
-
- if [ ! -f "bin/$binary_name" ]; then
- log "Ошибка: бинарник $binary_name не найден в архиве"
- log "Доступные бинарники:"
- ls -1 bin/
- exit 1
- fi
-
- local target_path="/opt/bin/${OBF_BINARY_NAME}"
- if [ "$ROUTER_PLATFORM" = "openwrt" ]; then
- target_path="/usr/bin/${OBF_BINARY_NAME}"
- fi
-
- if [ -f "$target_path" ]; then
- rm "$target_path"
- fi
-
- if [ "$ROUTER_PLATFORM" = "openwrt" ]; then
- mkdir -p /usr/bin
- else
- mkdir -p /opt/bin
- fi
-
- cp "bin/$binary_name" "$target_path"
- chmod +x "$target_path"
-
- log "Бинарник wg-obfuscator установлен в $target_path"
-}
-
-create_init_script() {
- log "Создание init-скрипта для obfuscator..."
-
- cat > /opt/etc/init.d/${OBF_INIT_NAME} </dev/null 2>&1 && pidof ${OBF_BINARY_NAME} >/dev/null 2>&1; then
- process_found=1
- elif command -v pgrep >/dev/null 2>&1 && pgrep -f wg-obfuscator >/dev/null 2>&1; then
- process_found=1
- elif ps w 2>/dev/null | grep -v grep | grep -q "wg-obfuscator\|/opt/bin/wg-obfuscator\|/usr/bin/wg-obfuscator"; then
- process_found=1
- elif ps 2>/dev/null | grep -v grep | grep -q "wg-obfuscator"; then
- process_found=1
- fi
-
- if [ $process_found -eq 0 ]; then
- if [ "$ROUTER_PLATFORM" = "keenetic" ] && [ -f /opt/etc/init.d/${OBF_INIT_NAME} ]; then
- local status_output=$(/opt/etc/init.d/${OBF_INIT_NAME} status 2>&1 || echo "")
- if echo "$status_output" | grep -q "alive"; then
- process_found=1
- fi
- elif [ "$ROUTER_PLATFORM" = "openwrt" ] && [ -f /etc/init.d/${OBF_SERVICE_NAME} ]; then
- if /etc/init.d/${OBF_SERVICE_NAME} status >/dev/null 2>&1; then
- process_found=1
- fi
- fi
- fi
-
- if [ $process_found -eq 1 ]; then
- log "✓ wg-obfuscator успешно запущен"
- else
- log "✗ wg-obfuscator не запущен. Проверьте логи."
- fi
-}
-
-create_procd_init_script() {
- log "Создание procd init-скрипта для obfuscator..."
-
- cat > /etc/init.d/${OBF_SERVICE_NAME} < /etc/systemd/system/${OBF_SERVICE_NAME}.service </dev/null 2>&1; then
- missing="$missing $cmd"
- fi
- done
-
- if [ -n "$missing" ]; then
- log "ВНИМАНИЕ: Отсутствуют необходимые утилиты:$missing"
-
- if [ "$platform" = "linux" ]; then
- log "Устанавливаю недостающие пакеты через apt-get..."
-
- if command -v apt-get >/dev/null 2>&1; then
- if ! apt-get update; then
- log "ОШИБКА: Не удалось обновить список пакетов apt-get"
- return 1
- fi
-
- for cmd in $missing; do
- log "Установка $cmd..."
- if ! apt-get install -y "$cmd" 2>/dev/null; then
- log "ПРЕДУПРЕЖДЕНИЕ: Не удалось установить $cmd через apt-get"
- fi
- done
- else
- log "ОШИБКА: apt-get не найден. Невозможно установить зависимости."
- return 1
- fi
- else
- log "Устанавливаю недостающие пакеты через opkg..."
-
- if command -v opkg >/dev/null 2>&1; then
- if ! opkg update; then
- log "ОШИБКА: Не удалось обновить список пакетов opkg"
- return 1
- fi
-
- for cmd in $missing; do
- log "Установка $cmd..."
- if ! opkg install "$cmd" 2>/dev/null; then
- log "ПРЕДУПРЕЖДЕНИЕ: Не удалось установить $cmd через opkg"
- fi
- done
- else
- log "ОШИБКА: opkg не найден. Невозможно установить зависимости."
- return 1
- fi
- fi
- fi
-
- return 0
-}
-
-setup_configs() {
- log "Настройка конфигураций..."
-
- mkdir -p "$PHOBOS_DIR"
-
- cp wg-obfuscator.conf "$PHOBOS_DIR/${OBF_CONF_NAME}"
- chmod 600 "$PHOBOS_DIR/${OBF_CONF_NAME}"
-
- cp "${CLIENT_NAME}.conf" "$PHOBOS_DIR/${CLIENT_NAME}.conf"
- chmod 600 "$PHOBOS_DIR/${CLIENT_NAME}.conf"
-
- printf '%s' "${CLIENT_NAME}" > "$PHOBOS_DIR/${OBF_CONF_NAME%.conf}.link"
-
- if [ "$OBF_BINARY_NAME" != "wg-obfuscator" ]; then
- local used_ports=""
- for existing_conf in "$PHOBOS_DIR"/wg-obfuscator*.conf; do
- [ -f "$existing_conf" ] || continue
- [ "$(basename "$existing_conf")" = "${OBF_CONF_NAME}" ] && continue
- local port
- port=$(grep 'source-lport' "$existing_conf" 2>/dev/null | tr -d ' ' | cut -d'=' -f2)
- [ -n "$port" ] && used_ports="${used_ports} ${port}"
- done
-
- local new_port=13255
- local port_taken=1
- while [ "$port_taken" -eq 1 ]; do
- port_taken=0
- for p in $used_ports; do
- if [ "$p" = "$new_port" ]; then
- port_taken=1
- new_port=$((new_port + 1))
- break
- fi
- done
- done
-
- sed -i "s/^source-lport = [0-9]*/source-lport = ${new_port}/" "$PHOBOS_DIR/${OBF_CONF_NAME}"
- sed -i "s/^Endpoint = 127\.0\.0\.1:[0-9]*/Endpoint = 127.0.0.1:${new_port}/" "$PHOBOS_DIR/${CLIENT_NAME}.conf"
-
- log " Назначен локальный порт obfuscator: $new_port"
- fi
-
- log "Конфигурации установлены:"
- log " - Obfuscator: $PHOBOS_DIR/${OBF_CONF_NAME}"
- log " - WireGuard: $PHOBOS_DIR/${CLIENT_NAME}.conf"
-}
-
-deploy_lib_client() {
- if [ -f "lib-client.sh" ]; then
- cp "lib-client.sh" "$PHOBOS_DIR/lib-client.sh"
- fi
-}
-
-
-deploy_uninstall_script() {
- log "Развертывание скрипта удаления Phobos..."
-
- if [ -f "phobos-uninstall.sh" ]; then
- cp "phobos-uninstall.sh" "$PHOBOS_DIR/phobos-uninstall.sh"
- chmod +x "$PHOBOS_DIR/phobos-uninstall.sh"
- log "Скрипт удаления установлен: $PHOBOS_DIR/phobos-uninstall.sh"
- else
- log "ПРЕДУПРЕЖДЕНИЕ: phobos-uninstall.sh не найден в архиве"
- fi
-}
-
-deploy_3xui_script() {
- log "Развертывание скрипта 3xui.sh..."
-
- if [ -f "3xui.sh" ]; then
- cp "3xui.sh" "$PHOBOS_DIR/3xui.sh"
- chmod +x "$PHOBOS_DIR/3xui.sh"
- log "Скрипт 3xui.sh установлен: $PHOBOS_DIR/3xui.sh"
- else
- log "ПРЕДУПРЕЖДЕНИЕ: 3xui.sh не найден в архиве"
- fi
-}
-
-run_3xui_integration() {
- log ""
- log "==> Интеграция WireGuard конфигурации в 3x-ui..."
-
- if [ ! -f "$PHOBOS_DIR/3xui.sh" ]; then
- log "ОШИБКА: Скрипт $PHOBOS_DIR/3xui.sh не найден"
- return 1
- fi
-
- for cmd in jq sqlite3; do
- if ! command -v "$cmd" >/dev/null 2>&1; then
- log "Устанавливаю $cmd..."
- if command -v apt-get >/dev/null 2>&1; then
- apt-get update -qq && apt-get install -y -qq "$cmd" >/dev/null 2>&1
- elif command -v yum >/dev/null 2>&1; then
- yum install -y -q "${cmd/sqlite3/sqlite}" >/dev/null 2>&1
- elif command -v dnf >/dev/null 2>&1; then
- dnf install -y -q "${cmd/sqlite3/sqlite}" >/dev/null 2>&1
- elif command -v apk >/dev/null 2>&1; then
- apk add --quiet "${cmd/sqlite3/sqlite}" >/dev/null 2>&1
- fi
- if ! command -v "$cmd" >/dev/null 2>&1; then
- log "ОШИБКА: не удалось установить $cmd"
- return 1
- fi
- fi
- done
-
- local wg_config="$PHOBOS_DIR/${CLIENT_NAME}.conf"
-
- if [ ! -f "$wg_config" ]; then
- log "ОШИБКА: Конфигурация WireGuard не найдена: $wg_config"
- return 1
- fi
-
- log "Запуск интеграции: $PHOBOS_DIR/3xui.sh $wg_config"
-
- if "$PHOBOS_DIR/3xui.sh" "$wg_config"; then
- log "[OK] WireGuard конфигурация успешно интегрирована в 3x-ui"
- log "[OK] Outbound 'Phobos' добавлен в конфигурацию 3x-ui"
- return 0
- else
- log "ОШИБКА: Не удалось интегрировать конфигурацию в 3x-ui"
- return 1
- fi
-}
-
-cleanup_3xui_script() {
- local keep_script="$1"
-
- if [ "$keep_script" = "true" ]; then
- log "Скрипт 3xui.sh сохранен для использования в 3x-ui режиме"
- else
- if [ -f "$PHOBOS_DIR/3xui.sh" ]; then
- rm -f "$PHOBOS_DIR/3xui.sh"
- log "Скрипт 3xui.sh удален (не требуется в обычном режиме)"
- fi
- fi
-}
-
-install_wireguard_openwrt() {
- log "Установка пакетов WireGuard для OpenWRT..."
-
- if ! command -v wg >/dev/null 2>&1; then
- log "Установка kmod-wireguard и wireguard-tools..."
- opkg update
- opkg install kmod-wireguard wireguard-tools luci-proto-wireguard
- else
- log "WireGuard уже установлен"
- fi
-
- log "Установка luci-app-wireguard для веб-интерфейса..."
- opkg install luci-app-wireguard >/dev/null 2>&1 || log "ПРЕДУПРЕЖДЕНИЕ: luci-app-wireguard не удалось установить"
-
- log "✓ Пакеты WireGuard установлены"
-}
-
-configure_wireguard_openwrt() {
- log ""
- log "==> Автоматическая настройка WireGuard через UCI..."
-
- extract_wireguard_params
-
- if [ ! -f "./router-configure-wireguard-openwrt.sh" ]; then
- log "⚠ Скрипт router-configure-wireguard-openwrt.sh не найден"
- log " Используйте ручную настройку через LuCI или UCI"
- return 1
- fi
-
- chmod +x ./router-configure-wireguard-openwrt.sh
-
- if ./router-configure-wireguard-openwrt.sh \
- --client-name "$CLIENT_NAME" \
- --client-private-key "$WG_PRIVATE_KEY" \
- --client-ip "$CLIENT_IP" \
- --client-ipv6 "$CLIENT_IPV6" \
- --server-public-key "$WG_SERVER_PUBKEY" \
- --endpoint-port "$WG_ENDPOINT_PORT" \
- --keepalive 25 \
- --mtu 1420 \
- --fallback-config "$PHOBOS_DIR/${CLIENT_NAME}.conf"; then
-
- return 0
- else
- return 1
- fi
-}
-
-extract_wireguard_params() {
- log "Извлечение параметров WireGuard из конфигурации..."
-
- local config_file="$PHOBOS_DIR/${CLIENT_NAME}.conf"
-
- WG_PRIVATE_KEY=$(grep '^PrivateKey' "$config_file" | cut -d'=' -f2- | tr -d ' \t\n\r')
- WG_ADDRESS=$(grep '^Address' "$config_file" | cut -d'=' -f2- | tr -d ' \t\n\r')
- WG_SERVER_PUBKEY=$(grep '^PublicKey' "$config_file" | cut -d'=' -f2- | tr -d ' \t\n\r')
- WG_ENDPOINT_PORT=$(grep '^Endpoint' "$config_file" | cut -d':' -f2 | tr -d ' \t\n\r')
-
- CLIENT_IP=$(echo "$WG_ADDRESS" | cut -d',' -f1 | tr -d ' ')
- CLIENT_IPV6=$(echo "$WG_ADDRESS" | cut -d',' -f2 | tr -d ' ')
-
- if [ -z "$CLIENT_IPV6" ] || [ "$CLIENT_IPV6" = "$CLIENT_IP" ]; then
- CLIENT_IPV6=$(grep -A 10 '\[Interface\]' "$config_file" | grep '^Address' | grep -o 'fd[0-9a-f:\/]*' | head -1)
- fi
-
- if [ -z "$CLIENT_IPV6" ]; then
- CLIENT_IPV6="none"
- fi
-
- if [ -z "$WG_ENDPOINT_PORT" ]; then
- WG_ENDPOINT_PORT=13255
- fi
-
- log " Private Key: ${WG_PRIVATE_KEY:0:20}..."
- log " IPv4: $CLIENT_IP"
- log " IPv6: $CLIENT_IPV6"
- log " Server PubKey: ${WG_SERVER_PUBKEY:0:20}..."
- log " Endpoint port: $WG_ENDPOINT_PORT"
-}
-
-configure_wireguard_rci() {
- log ""
- log "==> Автоматическая настройка WireGuard через RCI API..."
-
- extract_wireguard_params
-
- if [ ! -f "./router-configure-wireguard.sh" ]; then
- log "⚠ Скрипт router-configure-wireguard.sh не найден"
- log " Используйте ручной импорт (см. инструкции ниже)"
- return 1
- fi
-
- chmod +x ./router-configure-wireguard.sh
-
- if ./router-configure-wireguard.sh \
- --client-name "$CLIENT_NAME" \
- --client-private-key "$WG_PRIVATE_KEY" \
- --client-ip "$CLIENT_IP" \
- --client-ipv6 "$CLIENT_IPV6" \
- --server-public-key "$WG_SERVER_PUBKEY" \
- --endpoint-port "$WG_ENDPOINT_PORT" \
- --keepalive 25 \
- --mtu 1420 \
- --fallback-config "$PHOBOS_DIR/${CLIENT_NAME}.conf"; then
-
- return 0
- else
- return 1
- fi
-}
-
-show_manual_instructions() {
- log ""
- log "╔════════════════════════════════════════════════════════════╗"
- log "║ Требуется ручной импорт WireGuard конфигурации ║"
- log "╚════════════════════════════════════════════════════════════╝"
- log ""
- log "Выполните следующие шаги:"
- log ""
-
- if [ "$ROUTER_PLATFORM" = "keenetic" ]; then
- log "1. Откройте веб-панель администрирования роутера Keenetic"
- log " (http://192.168.1.1 или http://my.keenetic.net)"
- log ""
- log "2. Перейдите в раздел: Интернет → Другие подключения"
- log ""
- log "3. Выберите 'Загрузить конфигурацию из файла' в разделе 'WireGuard'"
- log ""
- log "4. Укажите путь к файлу:"
- log " $PHOBOS_DIR/${CLIENT_NAME}.conf"
- log ""
- log "5. Активируйте подключение"
- elif [ "$ROUTER_PLATFORM" = "openwrt" ]; then
- log "1. Откройте веб-интерфейс LuCI роутера OpenWRT"
- log " (обычно http://192.168.1.1)"
- log ""
- log "2. Перейдите в: Network → Interfaces"
- log ""
- log "3. Создайте новый интерфейс с протоколом WireGuard"
- log ""
- log "4. Используйте параметры из файла:"
- log " $PHOBOS_DIR/${CLIENT_NAME}.conf"
- log ""
- log "5. Настройте файрволл зону для интерфейса"
- fi
-
- log ""
-}
-
-show_final_info() {
- log ""
- log "╔════════════════════════════════════════════════════════════╗"
- log "║ Информация об установке ║"
- log "╚════════════════════════════════════════════════════════════╝"
- log ""
- log "Файлы установки:"
-
- if [ "$ROUTER_PLATFORM" = "keenetic" ]; then
- log " Бинарник: /opt/bin/${OBF_BINARY_NAME}"
- elif [ "$ROUTER_PLATFORM" = "openwrt" ]; then
- log " Бинарник: /usr/bin/${OBF_BINARY_NAME}"
- elif [ "$ROUTER_PLATFORM" = "linux" ]; then
- log " Бинарник: /usr/local/bin/${OBF_BINARY_NAME}"
- fi
-
- log " Конфиг obfuscator: $PHOBOS_DIR/${OBF_CONF_NAME}"
- log " Конфиг WireGuard: $PHOBOS_DIR/${CLIENT_NAME}.conf"
-
- if [ "$ROUTER_PLATFORM" = "keenetic" ] || [ -f /opt/etc/init.d/${OBF_INIT_NAME} ]; then
- log " Init-скрипт: /opt/etc/init.d/${OBF_INIT_NAME}"
- elif [ "$ROUTER_PLATFORM" = "openwrt" ] && [ -f /etc/init.d/${OBF_SERVICE_NAME} ]; then
- log " Init-скрипт: /etc/init.d/${OBF_SERVICE_NAME}"
- elif [ "$ROUTER_PLATFORM" = "linux" ]; then
- log " Systemd service: /etc/systemd/system/${OBF_SERVICE_NAME}.service"
- log " WireGuard конфиг: /etc/wireguard/${OBF_WG_IFACE}.conf"
- fi
-
- log " Uninstall: $PHOBOS_DIR/phobos-uninstall.sh"
- log " Health monitor: $PHOBOS_DIR/phobos-health.sh"
- log " Failover config: $PHOBOS_DIR/failover.conf"
- log ""
- log "Управление:"
-
- if [ "$ROUTER_PLATFORM" = "keenetic" ] || [ -f /opt/etc/init.d/${OBF_INIT_NAME} ]; then
- log " /opt/etc/init.d/${OBF_INIT_NAME} status # Проверить что obfuscator запущен"
- elif [ "$ROUTER_PLATFORM" = "openwrt" ] && [ -f /etc/init.d/${OBF_SERVICE_NAME} ]; then
- log " /etc/init.d/${OBF_SERVICE_NAME} status # Проверить что obfuscator запущен"
- elif [ "$ROUTER_PLATFORM" = "linux" ]; then
- log " systemctl status ${OBF_SERVICE_NAME} # Проверить что obfuscator запущен"
- log " systemctl status wg-quick@${OBF_WG_IFACE} # Проверить что WireGuard запущен"
- fi
-
- log " $PHOBOS_DIR/phobos-uninstall.sh # Удалить Phobos"
- log ""
-}
-
-
-deploy_health_monitor() {
- log "Развертывание монитора здоровья Phobos..."
-
- if [ ! -f "phobos-health.sh" ]; then
- log "ПРЕДУПРЕЖДЕНИЕ: phobos-health.sh не найден в архиве"
- return 0
- fi
-
- cp "phobos-health.sh" "$PHOBOS_DIR/phobos-health.sh"
- chmod +x "$PHOBOS_DIR/phobos-health.sh"
-
- if [ -f "failover.conf" ]; then
- cp "failover.conf" "$PHOBOS_DIR/failover.conf"
- chmod 600 "$PHOBOS_DIR/failover.conf"
- fi
-
- mkdir -p "$PHOBOS_DIR/state"
-
- # --- Phobos pull agent: panel -> router config sync (NAT-friendly) ---
- # Routers behind NAT cannot be reached by the panel over SSH, so they PULL
- # their failover.conf over HTTP. Ships client_id + pull_token from the package.
- if [ -f "phobos-pull.sh" ]; then
- cp "phobos-pull.sh" "$PHOBOS_DIR/phobos-pull.sh"
- chmod +x "$PHOBOS_DIR/phobos-pull.sh"
- echo "{{CLIENT_NAME}}" > "$PHOBOS_DIR/client_id"
- [ -f "pull_token" ] && cp "pull_token" "$PHOBOS_DIR/pull_token"
- [ -f "panel_tunnel_ip" ] && cp "panel_tunnel_ip" "$PHOBOS_DIR/panel_tunnel_ip"
- [ -f "panel_port" ] && cp "panel_port" "$PHOBOS_DIR/panel_port"
- [ -f "panel_scheme" ] && cp "panel_scheme" "$PHOBOS_DIR/panel_scheme"
- [ -f "panel_url" ] && cp "panel_url" "$PHOBOS_DIR/panel_url"
- [ -f "panel_urls" ] && cp "panel_urls" "$PHOBOS_DIR/panel_urls"
- log " Pull-агент установлен (client_id={{CLIENT_NAME}})"
- fi
-
- local cron_line="*/1 * * * * $PHOBOS_DIR/phobos-health.sh"
- local pull_line="*/1 * * * * $PHOBOS_DIR/phobos-pull.sh"
- [ -f "$PHOBOS_DIR/phobos-pull.sh" ] || pull_line=""
-
- if [ "$ROUTER_PLATFORM" = "keenetic" ]; then
- # Install cron if not present (Entware)
- if ! command -v crontab >/dev/null 2>&1 && command -v opkg >/dev/null 2>&1; then
- log " Установка cron через opkg..."
- opkg update >/dev/null 2>&1
- opkg install cron >/dev/null 2>&1
- /opt/etc/init.d/S10cron start >/dev/null 2>&1 || true
- fi
- local cron_file="/opt/etc/crontab"
- # Create crontab file if missing
- if [ ! -f "$cron_file" ]; then
- mkdir -p /opt/etc
- touch "$cron_file"
- fi
- if ! grep -q "phobos-health" "$cron_file" 2>/dev/null; then
- echo "$cron_line" >> "$cron_file"
- log " Cron (health) добавлен в $cron_file"
- fi
- if [ -n "$pull_line" ] && ! grep -q "phobos-pull" "$cron_file" 2>/dev/null; then
- echo "$pull_line" >> "$cron_file"
- log " Cron (pull) добавлен в $cron_file"
- fi
- /opt/etc/init.d/S10cron restart >/dev/null 2>&1 || true
- elif [ "$ROUTER_PLATFORM" = "openwrt" ]; then
- (crontab -l 2>/dev/null | grep -v "phobos-health" | grep -v "phobos-pull"; echo "$cron_line"; [ -n "$pull_line" ] && echo "$pull_line") | crontab -
- log " Cron добавлен через crontab (health + pull)"
- elif [ "$ROUTER_PLATFORM" = "linux" ]; then
- { echo "$cron_line"; [ -n "$pull_line" ] && echo "$pull_line"; } > /etc/cron.d/phobos-health
- chmod 644 /etc/cron.d/phobos-health
- log " Cron добавлен в /etc/cron.d/phobos-health (health + pull)"
- fi
-
- log " Монитор здоровья: $PHOBOS_DIR/phobos-health.sh"
- log " Failover конфиг: $PHOBOS_DIR/failover.conf"
- log " Проверка каждую минуту через cron"
-}
-
-main() {
- ROUTER_PLATFORM=$(detect_router_platform)
- PHOBOS_DIR=$(detect_phobos_dir "$ROUTER_PLATFORM")
- IS_3XUI_MODE=$(detect_3xui_mode "$ROUTER_PLATFORM")
-
- log "==> Определена платформа: $ROUTER_PLATFORM"
- log "==> Директория Phobos: $PHOBOS_DIR"
-
- resolve_install_names
- log "==> Режим установки obfuscator: binary=${OBF_BINARY_NAME}, conf=${OBF_CONF_NAME}, init=${OBF_INIT_NAME}, service=${OBF_SERVICE_NAME}"
-
- if [ "$IS_3XUI_MODE" = "true" ]; then
- log "==> Обнаружен режим установки: 3x-ui"
- log "==> В этом режиме WireGuard не устанавливается"
- log "==> Будет развернут только wg-obfuscator и интеграция с 3x-ui"
- fi
-
- if [ "$ROUTER_PLATFORM" = "unknown" ]; then
- log "ОШИБКА: Неподдерживаемая платформа"
- log "Вывод uname -a: $(uname -a)"
- log ""
- log "Поддерживаемые платформы:"
- log " - Keenetic/Netcraze (определяется по 'Keenetic' или 'Netcraze' в uname)"
- log " - OpenWRT (определяется по 'OpenWrt', 'LEDE' или 'ImmortalWrt' в uname)"
- log " - Linux (Ubuntu/Debian)"
- exit 1
- fi
-
- mkdir -p "$PHOBOS_DIR"
- log "==> Начало установки Phobos на роутер $ROUTER_PLATFORM"
- log "==> Клиент: $CLIENT_NAME"
-
- check_root
-
- if ! check_dependencies "$ROUTER_PLATFORM"; then
- log "ОШИБКА: Не удалось установить зависимости"
- exit 1
- fi
-
- ARCH=$(detect_arch)
- log "Определена архитектура: $ARCH"
-
- if [ "$ARCH" = "unknown" ]; then
- log "Ошибка: неподдерживаемая архитектура"
- log "Вывод uname -m: $(uname -m)"
- exit 1
- fi
-
- install_obfuscator "$ARCH"
- setup_configs
- deploy_lib_client
- deploy_uninstall_script
- deploy_health_monitor
-
- if [ "$IS_3XUI_MODE" = "true" ]; then
- deploy_3xui_script
- fi
-
- if [ "$ROUTER_PLATFORM" = "keenetic" ]; then
- create_init_script
- start_obfuscator
-
- if configure_wireguard_rci; then
- log ""
- log "╔════════════════════════════════════════════════════════════╗"
- log "║ ✓ Установка завершена успешно! ║"
- log "║ ✓ WireGuard настроен автоматически через RCI API ║"
- log "╚════════════════════════════════════════════════════════════╝"
- show_final_info
- else
- log ""
- log "╔════════════════════════════════════════════════════════════╗"
- log "║ ✓ Obfuscator установлен успешно ║"
- log "║ ⚠ WireGuard требует ручной настройки ║"
- log "╚════════════════════════════════════════════════════════════╝"
- show_manual_instructions
- show_final_info
- fi
-
- elif [ "$ROUTER_PLATFORM" = "openwrt" ]; then
- install_wireguard_openwrt
-
- if [ -d "/opt/etc" ]; then
- create_init_script
- else
- create_procd_init_script
- fi
-
- start_obfuscator
-
- if configure_wireguard_openwrt; then
- log ""
- log "╔════════════════════════════════════════════════════════════╗"
- log "║ ✓ Установка завершена успешно! ║"
- log "║ ✓ WireGuard настроен автоматически через UCI ║"
- log "╚════════════════════════════════════════════════════════════╝"
- show_final_info
- else
- log ""
- log "╔════════════════════════════════════════════════════════════╗"
- log "║ ✓ Obfuscator установлен успешно ║"
- log "║ ⚠ WireGuard требует ручной настройки ║"
- log "╚════════════════════════════════════════════════════════════╝"
- show_manual_instructions
- show_final_info
- fi
-
- elif [ "$ROUTER_PLATFORM" = "linux" ]; then
- if [ "$IS_3XUI_MODE" = "true" ]; then
- log ""
- log "╔════════════════════════════════════════════════════════════╗"
- log "║ Режим установки: 3x-ui ║"
- log "╚════════════════════════════════════════════════════════════╝"
- log ""
-
- create_systemd_obfuscator_service
-
- if run_3xui_integration; then
- cleanup_3xui_script "true"
- log ""
- log "╔════════════════════════════════════════════════════════════╗"
- log "║ ✓ Установка в режиме 3x-ui завершена успешно! ║"
- log "║ ✓ Obfuscator настроен через systemd ║"
- log "║ ✓ Outbound 'Phobos' добавлен в конфигурацию 3x-ui ║"
- log "╚════════════════════════════════════════════════════════════╝"
- log ""
- log "Файлы установки:"
- log " Бинарник: /usr/local/bin/wg-obfuscator"
- log " Конфиг obfuscator: $PHOBOS_DIR/wg-obfuscator.conf"
- log " Конфиг WireGuard: $PHOBOS_DIR/${CLIENT_NAME}.conf"
- log " Скрипт 3xui.sh: $PHOBOS_DIR/3xui.sh"
- log " Systemd service: /etc/systemd/system/phobos-obfuscator.service"
- log ""
- log "Управление:"
- log " systemctl status phobos-obfuscator # Проверить что obfuscator запущен"
- log ""
- log "Примечание:"
- log " WireGuard управляется через 3x-ui панель"
- log " Скрипт 3xui.sh сохранен для повторной интеграции при необходимости"
- log ""
- else
- log ""
- log "╔════════════════════════════════════════════════════════════╗"
- log "║ ✗ Установка в режиме 3x-ui завершена с ошибками ║"
- log "╚════════════════════════════════════════════════════════════╝"
- exit 1
- fi
- else
- install_wireguard_linux || {
- log "ОШИБКА: Не удалось установить WireGuard"
- exit 1
- }
-
- create_systemd_obfuscator_service
-
- if configure_wireguard_linux; then
- configure_ufw_linux
- cleanup_3xui_script "false"
- log ""
- log "╔════════════════════════════════════════════════════════════╗"
- log "║ ✓ Установка завершена успешно! ║"
- log "║ ✓ WireGuard и Obfuscator настроены через systemd ║"
- log "╚════════════════════════════════════════════════════════════╝"
- show_final_info
- else
- cleanup_3xui_script "false"
- log ""
- log "╔════════════════════════════════════════════════════════════╗"
- log "║ ⚠ Установка завершена с предупреждениями ║"
- log "║ ⚠ Проверьте статус служб вручную ║"
- log "╚════════════════════════════════════════════════════════════╝"
- show_final_info
- fi
- fi
- fi
-
- log "==> Установка завершена."
-}
-
-main "$@"
diff --git a/overlay/install-wireguard.sh b/overlay/install-wireguard.sh
deleted file mode 100755
index 7448928..0000000
--- a/overlay/install-wireguard.sh
+++ /dev/null
@@ -1,94 +0,0 @@
-install_wireguard_linux() {
- log "Установка WireGuard для Linux..."
-
- if command -v apt-get >/dev/null 2>&1; then
- apt-get update || log "ПРЕДУПРЕЖДЕНИЕ: Не удалось обновить список пакетов"
- apt-get install -y wireguard wireguard-tools resolvconf net-tools || {
- log "ОШИБКА: Не удалось установить WireGuard"
- return 1
- }
- else
- log "ОШИБКА: apt-get не найден. Поддерживаются только Ubuntu/Debian"
- return 1
- fi
-
- log "✓ WireGuard установлен"
- return 0
-}
-
-configure_wireguard_linux() {
- log ""
- log "==> Настройка WireGuard через systemd..."
-
- local wg_interface="${OBF_WG_IFACE}"
- local wg_config_dir="/etc/wireguard"
- mkdir -p "$wg_config_dir"
-
- cp "$PHOBOS_DIR/${CLIENT_NAME}.conf" "$wg_config_dir/${wg_interface}.conf"
- chmod 600 "$wg_config_dir/${wg_interface}.conf"
-
- log "Настройка routing: VPN как запасной интерфейс..."
-
- local client_ip=$(grep '^Address' "$wg_config_dir/${wg_interface}.conf" | cut -d'=' -f2 | tr -d ' ' | cut -d',' -f1 | cut -d'/' -f1)
- local route_target=$(echo "$client_ip" | cut -d'.' -f1-2).0.0/16
-
- sed -i '/^MTU/a Table = off' "$wg_config_dir/${wg_interface}.conf"
- sed -i "/^Table = off/a PostUp = ip route add $route_target dev %i" "$wg_config_dir/${wg_interface}.conf"
- sed -i "/^PostUp/a PostDown = ip route del $route_target dev %i || true" "$wg_config_dir/${wg_interface}.conf"
-
- log "Настройка зависимости WireGuard от obfuscator..."
- mkdir -p "/etc/systemd/system/wg-quick@${wg_interface}.service.d"
- cat > "/etc/systemd/system/wg-quick@${wg_interface}.service.d/override.conf" </dev/null | grep -q "latest handshake"; then
- log "✓ Туннель установлен и работает"
- else
- log " Ожидание установки туннеля..."
- fi
-
- return 0
- else
- log "ПРЕДУПРЕЖДЕНИЕ: WireGuard может быть не запущен, проверьте статус"
- return 1
- fi
-}
-
-configure_ufw_linux() {
- log ""
- log "==> Проверка UFW firewall..."
-
- if ! command -v ufw >/dev/null 2>&1; then
- log "UFW не установлен, пропуск настройки"
- return 0
- fi
-
- log "✓ UFW обнаружен"
- log " Клиентская конфигурация не требует открытия портов:"
- log " - obfuscator слушает на 127.0.0.1:13255 (локальный интерфейс)"
- log " - obfuscator делает исходящие соединения (разрешены по умолчанию)"
-
- if ufw status 2>/dev/null | grep -q "Status: active"; then
- log " UFW активен, клиент будет работать корректно"
- else
- log " UFW неактивен"
- fi
-}
diff --git a/overlay/lib-client.sh b/overlay/lib-client.sh
deleted file mode 100755
index cc31df5..0000000
--- a/overlay/lib-client.sh
+++ /dev/null
@@ -1,93 +0,0 @@
-detect_router_platform() {
- if [ -f /etc/openwrt_release ] || [ -f /etc/openwrt_version ]; then
- echo "openwrt"
- elif [ -f /opt/etc/.entware_install_log ] || [ -d /opt/etc/ndm ]; then
- echo "keenetic"
- elif [ -f /etc/debian_version ]; then
- echo "linux"
- elif [ -d /etc/config ] && command -v uci >/dev/null 2>&1; then
- echo "openwrt"
- elif [ -f /opt/etc/init.d/rc.func ]; then
- echo "keenetic"
- elif [ -d /run/systemd/system ] || pidof systemd >/dev/null 2>&1; then
- echo "linux"
- else
- local uname_output=$(uname -a)
- if echo "$uname_output" | grep -qi "Keenetic\|Netcraze"; then
- echo "keenetic"
- elif echo "$uname_output" | grep -qi "OpenWrt\|LEDE\|ImmortalWrt"; then
- echo "openwrt"
- elif echo "$uname_output" | grep -qi "Linux"; then
- echo "linux"
- else
- echo "unknown"
- fi
- fi
-}
-
-detect_phobos_dir() {
- local platform="$1"
-
- if [ "$platform" = "keenetic" ]; then
- echo "/opt/etc/Phobos"
- elif [ "$platform" = "openwrt" ]; then
- echo "/etc/Phobos"
- elif [ "$platform" = "linux" ]; then
- echo "/opt/Phobos"
- else
- if [ -d "/opt" ] && [ -d "/opt/etc" ]; then
- echo "/opt/etc/Phobos"
- else
- echo "/etc/Phobos"
- fi
- fi
-}
-
-detect_arch() {
- local arch=$(uname -m)
- case "$arch" in
- mips)
- if [ "$(echo -n I | hexdump -o 2>/dev/null | awk 'NR==1{print $2}')" = "000111" ]; then
- echo "mipsel"
- else
- echo "mips"
- fi
- ;;
- aarch64|arm64)
- echo "aarch64"
- ;;
- armv7l|armv6l)
- echo "armv7"
- ;;
- x86_64)
- echo "x86_64"
- ;;
- *)
- echo "unknown"
- ;;
- esac
-}
-
-check_root() {
- if [ "$(id -u)" -ne 0 ]; then
- echo "Этот скрипт требует root привилегии. Запустите: su -c '$0'"
- exit 1
- fi
-}
-
-log() {
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
-}
-
-print_status() {
- local status="$1"
- local message="$2"
-
- if [ "${status}" = "OK" ]; then
- printf "\\033[0;32m✓\\033[0m %s\n" "${message}"
- elif [ "${status}" = "WARN" ]; then
- printf "\\033[1;33m⚠\\033[0m %s\n" "${message}"
- else
- printf "\\033[0;31m✗\\033[0m %s\n" "${message}"
- fi
-}
diff --git a/overlay/lib-core.sh b/overlay/lib-core.sh
deleted file mode 100644
index 2f6eaff..0000000
--- a/overlay/lib-core.sh
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/usr/bin/env bash
-
-set -euo pipefail
-
-PHOBOS_DIR="${PHOBOS_DIR:-/opt/Phobos}"
-SERVER_ENV="${SERVER_ENV:-$PHOBOS_DIR/server/server.env}"
-CLIENTS_DIR="${CLIENTS_DIR:-$PHOBOS_DIR/clients}"
-PACKAGES_DIR="${PACKAGES_DIR:-$PHOBOS_DIR/packages}"
-WWW_DIR="${WWW_DIR:-$PHOBOS_DIR/www}"
-TOKENS_DIR="${TOKENS_DIR:-$PHOBOS_DIR/tokens}"
-TOKENS_FILE="${TOKENS_FILE:-$TOKENS_DIR/tokens.json}"
-REPO_DIR="${REPO_DIR:-$PHOBOS_DIR/repo}"
-WG_CONFIG="${WG_CONFIG:-/etc/wireguard/wg0.conf}"
-TOKEN_TTL="${TOKEN_TTL:-86400}"
-CLIENT_WG_PORT="${CLIENT_WG_PORT:-13255}"
-
-log_info() { echo "[INFO] $*"; }
-log_warn() { echo "[WARN] $*" >&2; }
-log_success() { echo "[OK] $*"; }
-die() { echo "[ERROR] $*" >&2; exit 1; }
-
-check_root() {
- [ "$(id -u)" = "0" ] || die "run as root"
-}
-
-load_env() {
- if [ -f "$SERVER_ENV" ]; then
- while IFS= read -r line || [ -n "$line" ]; do
- case "$line" in
- ''|\#*) continue ;;
- esac
- k="${line%%=*}"
- v="${line#*=}"
- case "$k" in
- ''|\#*) continue ;;
- esac
- export "$k=$v"
- done < "$SERVER_ENV"
- fi
-
- if [ -z "${SERVER_PUBLIC_IP_V4:-}" ]; then
- SERVER_PUBLIC_IP_V4="$(curl -4 -fsS --max-time 6 https://api.ipify.org 2>/dev/null || hostname -I | awk '{print $1}')"
- export SERVER_PUBLIC_IP_V4
- fi
-
- if [ -z "${SERVER_WG_PUBLIC_KEY:-}" ]; then
- SERVER_WG_PUBLIC_KEY="$(wg show wg0 public-key 2>/dev/null || true)"
- export SERVER_WG_PUBLIC_KEY
- fi
-
- if [ -n "${OBFUSCATOR_PORTS:-}" ]; then
- OBFUSCATOR_PORT="$(echo "$OBFUSCATOR_PORTS" | cut -d',' -f1 | tr -d ' ')"
- export OBFUSCATOR_PORT
- fi
-}
-
-ensure_dirs() {
- mkdir -p \
- "$CLIENTS_DIR" \
- "$PACKAGES_DIR" \
- "$WWW_DIR/init" \
- "$WWW_DIR/packages" \
- "$TOKENS_DIR" \
- "$REPO_DIR/server/scripts" \
- "$REPO_DIR/client/templates"
-
- [ -f "$TOKENS_FILE" ] || echo "[]" > "$TOKENS_FILE"
-}
diff --git a/overlay/phobos-client.sh b/overlay/phobos-client.sh
deleted file mode 100755
index cdb52f1..0000000
--- a/overlay/phobos-client.sh
+++ /dev/null
@@ -1,485 +0,0 @@
-#!/usr/bin/env bash
-
-source "$(dirname "${BASH_SOURCE[0]}")/lib-core.sh"
-
-check_root
-load_env
-ensure_dirs
-
-# server.env stores OBFUSCATOR_PORTS (plural, comma list). Client obfuscator
-# must target an ACTUAL listening port. lib-core load_env defaults OBFUSCATOR_PORT
-# to 51821 (NOT listened on) -> handshake failed. Override unconditionally from
-# the real port list when present.
-[ -n "${OBFUSCATOR_PORTS:-}" ] && export OBFUSCATOR_PORT="$(echo "$OBFUSCATOR_PORTS" | cut -d',' -f1)"
-
-CMD="${1:-help}"
-CLIENT_ARG="${2:-}"
-EXTRA_ARG="${3:-}"
-
-resolve_client() {
- local name="$1"
- local id=$(echo "$name" | tr ' ' '-' | tr '[:upper:]' '[:lower:]')
-
- if [[ -d "$CLIENTS_DIR/$id" ]]; then
- echo "$id"
- return 0
- fi
- return 1
-}
-
-action_add() {
- local name="$CLIENT_ARG"
- local manual_ip="$EXTRA_ARG"
-
- if [[ -z "$name" ]]; then die "Использование: $0 add [ip]"; fi
-
- local id=$(echo "$name" | tr ' ' '-' | tr '[:upper:]' '[:lower:]')
- local dir="$CLIENTS_DIR/$id"
-
- if [[ -d "$dir" ]]; then die "Клиент $id уже существует."; fi
-
- if [[ -z "$SERVER_WG_PUBLIC_KEY" ]]; then
- die "Публичный ключ сервера не найден в server.env. Запустите установку."
- fi
-
- local server_pub="$SERVER_WG_PUBLIC_KEY"
- local server_ip_v4="${SERVER_PUBLIC_IP_V4:-}"
- local server_ip_v6="${SERVER_PUBLIC_IP_V6:-}"
- local server_wg_network="${SERVER_WG_IPV4_NETWORK:-10.25.0.0/16}"
-
- local client_ip_v4="$manual_ip"
- local ipv6_prefix_main=$(echo "${SERVER_WG_IPV6_NETWORK:-fd00:10:25::/48}" | cut -d'/' -f1 | sed 's/::.*//')
-
- if [[ -z "$client_ip_v4" ]]; then
- log_info "Поиск свободного IP..."
- local used_ips=""
- for d in "$CLIENTS_DIR"/*; do
- if [[ -d "$d" ]] && [[ -f "$d/metadata.json" ]]; then
- local ip=$(jq -r '.tunnel_ip_v4 // empty' "$d/metadata.json" 2>/dev/null | cut -d/ -f1)
- [[ -n "$ip" ]] && used_ips="${used_ips}${ip}\n"
- fi
- done
-
- client_ip_v4="$(USED_IPS="$(printf "%b" "$used_ips")" python3 - "$server_wg_network" <<'PY'
-import ipaddress
-import os
-import sys
-
-net = ipaddress.ip_network(sys.argv[1], strict=False)
-used = {line.strip() for line in os.environ.get("USED_IPS", "").splitlines() if line.strip()}
-hosts = net.hosts()
-reserved_first = True
-for candidate in hosts:
- ip = str(candidate)
- if reserved_first:
- reserved_first = False
- continue
- if ip not in used:
- print(ip)
- raise SystemExit(0)
-raise SystemExit(1)
-PY
-)" || die "Нет свободных IP в подсети."
- fi
-
- local oct3=$(echo "$client_ip_v4" | cut -d. -f3)
- local oct4=$(echo "$client_ip_v4" | cut -d. -f4)
- local hex_part=$(printf "%x:%x" "$oct3" "$oct4")
- local client_ip_v6=""
- [[ -n "$server_ip_v6" ]] && client_ip_v6="${ipv6_prefix_main}::${hex_part}"
-
- log_info "Назначен IP: $client_ip_v4 $([[ -n $client_ip_v6 ]] && echo "/ $client_ip_v6")"
-
- mkdir -p "$dir"
- umask 077
- wg genkey > "$dir/client_private.key"
- wg pubkey < "$dir/client_private.key" > "$dir/client_public.key"
- local priv_key=$(cat "$dir/client_private.key")
- local pub_key=$(cat "$dir/client_public.key")
-
- local allowed_ips="0.0.0.0/0"
- local addr_str="$client_ip_v4/32"
- if [[ -n "$client_ip_v6" ]]; then
- allowed_ips="0.0.0.0/0, ::/0"
- addr_str="$client_ip_v4/32, $client_ip_v6/128"
- fi
-
- cat > "$dir/${id}.conf" < "$dir/wg-obfuscator.conf" < "$dir/metadata.json" <> "$WG_CONFIG" </dev/null) 2>/dev/null
- log_success "Клиент $name создан."
-
- CLIENT_ARG="$id"
- action_package
- action_link
-}
-
-action_remove() {
- local id=$(resolve_client "$CLIENT_ARG")
- if [[ -z "$id" ]]; then die "Клиент не найден."; fi
- local dir="$CLIENTS_DIR/$id"
-
- log_info "Удаление клиента $id..."
-
- if [[ -f "$dir/client_public.key" ]]; then
- local pub=$(cat "$dir/client_public.key")
- if grep -qF "$pub" "$WG_CONFIG"; then
- awk -v key="$pub" '
- BEGIN {RS=""; ORS="\n\n"}
- index($0, key) == 0 {print $0}
- ' "$WG_CONFIG" > "$WG_CONFIG.tmp" && mv "$WG_CONFIG.tmp" "$WG_CONFIG"
-
- sed -i '/^$/N;/^\n$/D' "$WG_CONFIG"
-
- wg syncconf wg0 <(wg-quick strip wg0 2>/dev/null) 2>/dev/null
- log_success "Peer удален из конфигурации."
- fi
- fi
-
- rm -rf "$dir"
- rm -f "$PACKAGES_DIR/phobos-$id.tar.gz"
-
- if [[ -f "$TOKENS_FILE" ]] && command -v jq >/dev/null; then
- local tokens=$(jq -r ".[] | select(.client == \"$id\") | .token" "$TOKENS_FILE")
- for t in $tokens; do
- rm -f "$WWW_DIR/init/$t.sh"
- rm -rf "$WWW_DIR/packages/$t"
- done
- jq "map(select(.client != \"$id\"))" "$TOKENS_FILE" > "$TOKENS_FILE.tmp" && mv "$TOKENS_FILE.tmp" "$TOKENS_FILE"
- fi
-
- log_success "Клиент $id полностью удален."
-}
-
-action_package() {
- local id=$(resolve_client "$CLIENT_ARG")
- if [[ -z "$id" ]]; then die "Клиент не найден."; fi
-
- log_info "Сборка пакета для $id..."
- local dir="$CLIENTS_DIR/$id"
- local tmp=$(mktemp -d)
- local pkg_root="$tmp/phobos-$id"
-
- mkdir -p "$PHOBOS_DIR/bin"
- mkdir -p "$pkg_root/bin"
-
- cp "$dir/${id}.conf" "$pkg_root/${id}.conf"
- cp "$dir/wg-obfuscator.conf" "$pkg_root/wg-obfuscator.conf"
-
- # Fetch missing router-arch binaries from ClusterM on-demand
- local _tag; _tag=$(curl -fsSL -m10 https://api.github.com/repos/ClusterM/wg-obfuscator/releases/latest 2>/dev/null | grep '"tag_name"' | head -1 | sed 's/.*"tag_name": *"\(.*\)".*/\1/')
- local _cb="https://github.com/ClusterM/wg-obfuscator/releases/download/${_tag}"
- declare -A _am=([aarch64]="linux-arm64" [mipsel]="linux-mipsel-mips32" [mips]="linux-mips-mips32" [armv7]="linux-armv7-hf" [x86_64]="linux-x64")
- for _arch in aarch64 mipsel mips armv7 x86_64; do
- if [[ ! -f "$PHOBOS_DIR/bin/wg-obfuscator-$_arch" ]] && [[ -n "$_tag" ]]; then
- local _t; _t=$(mktemp -d)
- if curl -fsSL -m30 "${_cb}/wg-obfuscator-${_tag}-${_am[$_arch]}.tar.gz" -o "$_t/o.tgz" 2>/dev/null; then
- tar -xzf "$_t/o.tgz" -C "$_t" 2>/dev/null || true
- local _b; _b=$(find "$_t" -name "wg-obfuscator" -type f | head -1)
- [[ -n "$_b" ]] && cp "$_b" "$PHOBOS_DIR/bin/wg-obfuscator-$_arch" && chmod +x "$PHOBOS_DIR/bin/wg-obfuscator-$_arch" && log_info "+wg-obfuscator-$_arch (ClusterM ${_tag})"
- fi
- rm -rf "$_t"
- fi
- [[ -f "$PHOBOS_DIR/bin/wg-obfuscator-$_arch" ]] && cp "$PHOBOS_DIR/bin/wg-obfuscator-$_arch" "$pkg_root/bin/"
- done
-
- local tpl_dir="$REPO_DIR/client/templates"
-
- if [[ -d "$tpl_dir" ]]; then
- for required in install-router.sh.template lib-client.sh install-obfuscator.sh install-wireguard.sh; do
- [[ -f "$tpl_dir/$required" ]] || die "Обязательный шаблон $required не найден в $tpl_dir. Выполни phobos-update и пересоздай пакет."
- done
- cp "$tpl_dir/install-router.sh.template" "$pkg_root/install-router.sh"
- sed -i "s|{{CLIENT_NAME}}|${id}|g" "$pkg_root/install-router.sh"
- chmod +x "$pkg_root/install-router.sh"
- cp "$tpl_dir/lib-client.sh" "$pkg_root/lib-client.sh"
- cp "$tpl_dir/install-obfuscator.sh" "$pkg_root/install-obfuscator.sh"
- cp "$tpl_dir/install-wireguard.sh" "$pkg_root/install-wireguard.sh"
- chmod +x "$pkg_root/lib-client.sh" "$pkg_root/install-obfuscator.sh" "$pkg_root/install-wireguard.sh"
- for f in router-configure-wireguard router-configure-wireguard-openwrt phobos-uninstall 3xui; do
- [[ -f "$tpl_dir/$f.sh" ]] && cp "$tpl_dir/$f.sh" "$pkg_root/$f.sh" && chmod +x "$pkg_root/$f.sh"
- done
- else
- log_warn "Шаблоны не найдены в $tpl_dir"
- fi
-
- echo "Phobos Client Package for $id" > "$pkg_root/README.txt"
- echo "Date: $(date)" >> "$pkg_root/README.txt"
-
- # Health monitor + failover
- if [[ -f "$PHOBOS_DIR/server/phobos-health.sh" ]]; then
- cp "$PHOBOS_DIR/server/phobos-health.sh" "$pkg_root/phobos-health.sh"
- chmod +x "$pkg_root/phobos-health.sh"
- fi
- # Pull agent: panel -> router config sync (NAT-friendly). Token = panel
- # server_api_key (the /api/router-config endpoint accepts it as a fallback).
- for src in "$tpl_dir/phobos-pull.sh" "$PHOBOS_DIR/server/phobos-pull.sh"; do
- if [[ -f "$src" ]]; then cp "$src" "$pkg_root/phobos-pull.sh"; chmod +x "$pkg_root/phobos-pull.sh"; break; fi
- done
- local PULL_TOKEN=""
- command -v jq >/dev/null && PULL_TOKEN=$(jq -r '.server_api_key // empty' /opt/phobos-panel/settings.json 2>/dev/null)
- [[ -n "$PULL_TOKEN" ]] && echo "$PULL_TOKEN" > "$pkg_root/pull_token"
- # Generate failover.conf with current server data
- source "$PHOBOS_DIR/server/server.env"
- local panel_port="${HTTP_PORT:-}"
- if [[ -z "$panel_port" && -f /opt/phobos-panel/.port ]]; then
- panel_port=$(cat /opt/phobos-panel/.port 2>/dev/null || true)
- fi
- panel_port="${panel_port:-8443}"
- local panel_scheme="${PANEL_SCHEME:-}"
- if [[ -z "$panel_scheme" && -f /opt/phobos-panel/.scheme ]]; then
- panel_scheme=$(cat /opt/phobos-panel/.scheme 2>/dev/null || true)
- fi
- case "$panel_scheme" in http|https) ;; *) panel_scheme="http";; esac
- local panel_tunnel_ip=""
- panel_tunnel_ip="$(python3 - "${SERVER_WG_IPV4_ADDRESS:-}" "${SERVER_WG_IPV4_NETWORK:-10.25.0.0/16}" <<'PY'
-import ipaddress, sys
-iface = (sys.argv[1] or "").strip()
-network = (sys.argv[2] or "10.25.0.0/16").strip()
-if iface:
- try:
- print(ipaddress.ip_interface(iface).ip)
- raise SystemExit(0)
- except Exception:
- pass
-net = ipaddress.ip_network(network, strict=False)
-print(next(net.hosts()))
-PY
-)"
- [[ -n "$panel_tunnel_ip" ]] && echo "$panel_tunnel_ip" > "$pkg_root/panel_tunnel_ip"
- echo "$panel_port" > "$pkg_root/panel_port"
- echo "$panel_scheme" > "$pkg_root/panel_scheme"
- echo "${panel_scheme}://${SERVER_PUBLIC_IP_V4}:${panel_port}" > "$pkg_root/panel_url"
- printf 'http://%s:8444 %s://%s:%s %s://%s:%s\n' \
- "$panel_tunnel_ip" "$panel_scheme" "$panel_tunnel_ip" "$panel_port" \
- "$panel_scheme" "$SERVER_PUBLIC_IP_V4" "$panel_port" > "$pkg_root/panel_urls"
- cat > "$pkg_root/failover.conf" < $SERVER_PUBLIC_IP_V4")
- [[ "$client_obf_key" != "$OBFUSCATOR_KEY" ]] && changes+=("Ключ обфускатора: изменен")
- [[ "$client_obf_port" != "$OBFUSCATOR_PORT" ]] && changes+=("Порт обфускатора: $client_obf_port -> $OBFUSCATOR_PORT")
- [[ "$client_obf_dummy" != "$OBFUSCATOR_DUMMY" ]] && changes+=("Max dummy: изменен")
- [[ "$client_obf_idle" != "$OBFUSCATOR_IDLE" ]] && changes+=("Idle таймаут: изменен")
- [[ -n "$client_wg_pubkey" && "$client_wg_pubkey" != "$SERVER_WG_PUBLIC_KEY" ]] && changes+=("Публичный ключ WG: изменен")
-
- if [[ ${#changes[@]} -gt 0 ]]; then
- echo "ИЗМЕНЕНИЯ КОНФИГУРАЦИИ:"
- for c in "${changes[@]}"; do
- echo " - $c"
- done
- return 1
- fi
-
- return 0
-}
-
-action_link() {
- local id=$(resolve_client "$CLIENT_ARG")
- if [[ -z "$id" ]]; then die "Клиент не найден."; fi
- local ttl="${EXTRA_ARG:-$TOKEN_TTL}"
-
- if ! command -v jq >/dev/null; then die "jq не установлен. Установите: apt-get install jq"; fi
-
- local token=$(head -c 16 /dev/urandom | md5sum | cut -d' ' -f1)
- local exp=$(($(date +%s) + ttl))
-
- if [[ ! -f "$TOKENS_FILE" ]]; then
- echo "[]" > "$TOKENS_FILE"
- fi
-
- local clean_json=$(jq "map(select(.client != \"$id\"))" "$TOKENS_FILE")
- echo "$clean_json" | jq ". + [{\"client\": \"$id\", \"token\": \"$token\", \"expires\": $exp}]" > "$TOKENS_FILE.tmp" && mv "$TOKENS_FILE.tmp" "$TOKENS_FILE"
-
- local link_dir="$WWW_DIR/packages/$token"
- rm -rf "$link_dir"
- mkdir -p "$link_dir"
- ln -s "$PACKAGES_DIR/phobos-$id.tar.gz" "$link_dir/phobos-$id.tar.gz"
-
- mkdir -p "$WWW_DIR/init"
- local panel_port="${HTTP_PORT:-}"
- if [[ -z "$panel_port" && -f /opt/phobos-panel/.port ]]; then
- panel_port=$(cat /opt/phobos-panel/.port 2>/dev/null || true)
- fi
- panel_port="${panel_port:-8443}"
- local panel_scheme="${PANEL_SCHEME:-}"
- if [[ -z "$panel_scheme" && -f /opt/phobos-panel/.scheme ]]; then
- panel_scheme=$(cat /opt/phobos-panel/.scheme 2>/dev/null || true)
- fi
- case "$panel_scheme" in http|https) ;; *) panel_scheme="http";; esac
- local primary_url="${panel_scheme}://${SERVER_PUBLIC_IP_V4}:${panel_port}/packages/$token/phobos-$id.tar.gz"
- local fallback_url="http://${SERVER_PUBLIC_IP_V4}:80/packages/$token/phobos-$id.tar.gz"
-
- cat > "$WWW_DIR/init/$token.sh" </dev/null; then
- curl -k -L -s -o "\$dir/package.tar.gz" "\$url" 2>/dev/null || continue
- else
- wget --no-check-certificate -q -O "\$dir/package.tar.gz" "\$url" 2>/dev/null || wget -q -O "\$dir/package.tar.gz" "\$url" 2>/dev/null || continue
- fi
- if grep -qi '/dev/null; then
- echo "Bad response from \$url (HTML/proxy page), trying next..."
- continue
- fi
- tar tzf "\$dir/package.tar.gz" >/dev/null 2>&1 || {
- echo "Bad package from \$url, trying next..."
- continue
- }
- ok=1
- break
-done
-[ "\$ok" = "1" ] || { echo "Download failed: no valid package"; exit 1; }
-cd "\$dir"
-tar xzf package.tar.gz
-cd "phobos-$id"
-chmod +x install-router.sh
-./install-router.sh
-EOF
-
- # nginx (www-data) must read these; the builder runs with a strict root umask
- # (files 600 / dirs 700) which makes the install URL return 403. Fix perms.
- chmod 755 "$WWW_DIR" "$WWW_DIR/init" "$WWW_DIR/packages" "$link_dir" 2>/dev/null
- chmod 644 "$WWW_DIR/init/$token.sh" 2>/dev/null
- chmod 755 "$PACKAGES_DIR" 2>/dev/null
- chmod 644 "$PACKAGES_DIR/phobos-$id.tar.gz" 2>/dev/null
-
- local init_primary="${panel_scheme}://${SERVER_PUBLIC_IP_V4}:${panel_port}/init/$token.sh"
- local init_fallback="http://${SERVER_PUBLIC_IP_V4}:80/init/$token.sh"
- local cmd="p=/tmp/phobos-init-\$\$.sh; ok=0; for u in $init_primary $init_fallback; do rm -f \$p; (wget -q -O \$p \$u || wget --no-check-certificate -q -O \$p \$u || curl -kfsSL -o \$p \$u || curl -fsSL -o \$p \$u) 2>/dev/null || continue; head -c 2 \$p | grep -q \"#!\" || continue; sh \$p && ok=1 && break; done; rm -f \$p; [ \$ok -eq 1 ] || echo ERROR_install_script_download_failed"
-
- echo ""
- echo "=================================================="
- echo "КОМАНДА ДЛЯ УСТАНОВКИ (Действительна $(($ttl / 3600))ч)"
- echo "=================================================="
- echo "$cmd"
- echo "=================================================="
- echo ""
-}
-
-action_list() {
- printf "% -20s % -20s % -20s\n" "CLIENT ID" "IPv4" "CREATED"
- echo "------------------------------------------------------------"
- for d in "$CLIENTS_DIR"/*; do
- if [[ -d "$d" ]]; then
- local id=$(basename "$d")
- local ip="N/A"
- local date="N/A"
- if [[ -f "$d/metadata.json" ]]; then
- ip=$(jq -r '.tunnel_ip_v4 // "N/A"' "$d/metadata.json")
- date=$(jq -r '.created_at // "N/A"' "$d/metadata.json" | cut -d'T' -f1)
- fi
- printf "% -20s % -20s % -20s\n" "$id" "$ip" "$date"
- fi
- done
-}
-
-case "$CMD" in
- add) action_add ;;
- remove) action_remove ;;
- package) action_package ;;
- link) action_link ;;
- check) action_check ;;
- list) action_list ;;
- rebuild)
- action_remove
- action_add
- ;;
- *)
- echo "Usage: $0 {add|remove|list|package|link|check|rebuild}"
- exit 1
- ;;
-esac
diff --git a/overlay/phobos-pull.sh b/overlay/phobos-pull.sh
deleted file mode 100755
index f8df816..0000000
--- a/overlay/phobos-pull.sh
+++ /dev/null
@@ -1,152 +0,0 @@
-#!/bin/sh
-# ============================================================
-# Phobos Config Pull — NAT-friendly management channel.
-# Runs ON the router via cron (every 2 min). OUTBOUND ONLY:
-# fetches this client's failover.conf from the panel over
-# HTTPS/HTTP and applies it. No inbound SSH needed, so it works
-# behind any NAT and regardless of which Phobos server is active.
-#
-# Why pull (not panel->router SSH):
-# - routers sit behind NAT with no public IP (KeenDNS is HTTP-
-# only, no port 22),
-# - WG3 must be security-level PUBLIC for LAN client routing,
-# which blocks inbound SSH on the tunnel,
-# - on failover the router's 10.25.0.2 moves to another server's
-# wg0, so a fixed panel host cannot reach it.
-# Pulling sidesteps all three.
-#
-# Files (written by installer / bootstrap):
-# /opt/etc/Phobos/client_id -> this router's client id (e.g. home)
-# /opt/etc/Phobos/pull_token -> shared secret for the panel endpoint
-# PANEL env or default below -> panel base URL
-# ============================================================
-PHOBOS_DIR="/opt/etc/Phobos"
-CONF="$PHOBOS_DIR/failover.conf"
-HEALTH="$PHOBOS_DIR/phobos-health.sh"
-LOG="$PHOBOS_DIR/health.log"
-# Config sources, tried in order. TUNNEL FIRST: panel_tunnel_ip is the wg0 of
-# whatever server the tunnel currently terminates on, so management rides the
-# same obfuscated channel as data — survives a public-IP ban and follows
-# failover.
-# - panel_tunnel_ip:8444 -> secondary server agent (phobos-api)
-# - panel_tunnel_ip: -> primary server panel
-# - public panel IP -> bootstrap / if tunnel is down
-PANEL_TUNNEL_IP="${PANEL_TUNNEL_IP:-$(cat "$PHOBOS_DIR/panel_tunnel_ip" 2>/dev/null)}"
-[ -n "$PANEL_TUNNEL_IP" ] || PANEL_TUNNEL_IP="10.25.0.1"
-PANEL="${PANEL:-$(cat "$PHOBOS_DIR/panel_url" 2>/dev/null)}"
-PANEL_URLS="${PANEL_URLS:-$(cat "$PHOBOS_DIR/panel_urls" 2>/dev/null)}"
-[ -n "$PANEL_URLS" ] || PANEL_URLS="http://${PANEL_TUNNEL_IP}:8444 $PANEL"
-CLIENT_ID=$(cat "$PHOBOS_DIR/client_id" 2>/dev/null || echo "home")
-TOKEN=$(cat "$PHOBOS_DIR/pull_token" 2>/dev/null)
-TMP="/tmp/failover.conf.pull"
-LOCK="/tmp/phobos-pull.lock"
-
-log() { echo "$(date '+%H:%M:%S') $1" >> "$LOG"; }
-
-# single instance
-if [ -f "$LOCK" ]; then
- pid=$(cat "$LOCK" 2>/dev/null)
- kill -0 "$pid" 2>/dev/null && exit 0
-fi
-echo $$ > "$LOCK"
-trap 'rm -f "$LOCK"' EXIT
-
-[ -z "$TOKEN" ] && exit 0
-
-detect_tunnel_iface() {
- ip route get "$PANEL_TUNNEL_IP" 2>/dev/null | awk '{for(i=1;i/dev/null; then
- curl -k --interface "$iface" -s -m 8 -o "$TMP" "$url" 2>/dev/null && return 0
- fi
- ;;
- esac
- if command -v curl >/dev/null; then
- curl -k -s -m 8 -o "$TMP" "$url" 2>/dev/null && return 0
- fi
- wget --no-check-certificate -q -O "$TMP" "$url" 2>/dev/null || wget -q -O "$TMP" "$url" 2>/dev/null
-}
-
-# One fetch + compare + apply pass. Returns 0 always (best-effort).
-do_pull() {
- # Try each source (tunnel first); accept first that returns a valid conf.
- got=0
- for base in $PANEL_URLS; do
- fetch_config "$base" || continue
- if grep -q "^SERVER_1=" "$TMP" 2>/dev/null; then got=1; break; fi
- done
- [ "$got" = 1 ] || { rm -f "$TMP"; return 0; }
-
- new=$(md5sum "$TMP" 2>/dev/null | cut -d' ' -f1)
- old=$(md5sum "$CONF" 2>/dev/null | cut -d' ' -f1)
- if [ "$new" = "$old" ]; then
- rm -f "$TMP"
- return 0
- fi
-
- old_s1=$(grep "^SERVER_1=" "$CONF" 2>/dev/null | cut -d= -f2- | cut -d: -f1)
- new_s1=$(grep "^SERVER_1=" "$TMP" 2>/dev/null | cut -d= -f2- | cut -d: -f1)
-
- cp "$CONF" "$CONF.prev" 2>/dev/null
- mv "$TMP" "$CONF"
- log "PULL: failover.conf updated (SERVER_1 ${old_s1:-?} -> ${new_s1:-?})"
-
- # apply the new primary now (only if it actually changed)
- if [ "$old_s1" != "$new_s1" ] && [ -f "$HEALTH" ]; then
- sh "$HEALTH" apply-server 1
- fi
-
- apply_obf_params
-}
-
-# Apply obfuscator params (masking/max-dummy/idle) delivered in failover.conf.
-apply_obf_params() {
- M=$(grep "^OBF_MASKING=" "$CONF" 2>/dev/null | cut -d= -f2-)
- [ -z "$M" ] && return 0
- D=$(grep "^OBF_MAX_DUMMY=" "$CONF" 2>/dev/null | cut -d= -f2-)
- I=$(grep "^OBF_IDLE=" "$CONF" 2>/dev/null | cut -d= -f2-)
- changed=0
- for OBF in "$PHOBOS_DIR"/wg-obfuscator*.conf; do
- [ -f "$OBF" ] || continue
- cur=$(grep "^masking = " "$OBF" 2>/dev/null | sed 's/masking = //')
- [ "$cur" != "$M" ] && { sed -i "s/^masking = .*/masking = $M/" "$OBF"; changed=1; }
- if [ -n "$D" ]; then
- cur=$(grep "^max-dummy = " "$OBF" 2>/dev/null | sed 's/max-dummy = //')
- [ "$cur" != "$D" ] && { sed -i "s/^max-dummy = .*/max-dummy = $D/" "$OBF"; changed=1; }
- fi
- if [ -n "$I" ]; then
- cur=$(grep "^idle-timeout = " "$OBF" 2>/dev/null | sed 's/idle-timeout = //')
- [ "$cur" != "$I" ] && { sed -i "s/^idle-timeout = .*/idle-timeout = $I/" "$OBF"; changed=1; }
- fi
- done
- [ "$changed" = 0 ] && return 0
- log "PULL: obf params applied (masking=$M dummy=${D:-} idle=${I:-}), restart obfuscator"
- if ls /opt/etc/init.d/S*obfuscator* >/dev/null 2>&1; then
- for sc in /opt/etc/init.d/S*obfuscator*; do [ -x "$sc" ] && "$sc" restart >/dev/null 2>&1; done
- elif command -v systemctl >/dev/null 2>&1; then
- systemctl restart 'wg-obfuscator*' >/dev/null 2>&1 || true
- else
- killall wg-obfuscator 2>/dev/null; sleep 1
- for OBF in "$PHOBOS_DIR"/wg-obfuscator*.conf; do [ -f "$OBF" ] && wg-obfuscator --config "$OBF" >/dev/null 2>&1 & done
- fi
-}
-
-# Inner loop: cron fires this every 60s, but we poll ~4x per minute so a
-# panel "Set" applies within ~12-15s instead of up to a full minute. The
-# loop stays UNDER 60s and exits so the next cron tick takes over cleanly
-# (the lockfile blocks any overlap). POLL_INTERVAL/POLL_PASSES overridable.
-POLL_INTERVAL="${POLL_INTERVAL:-12}"
-POLL_PASSES="${POLL_PASSES:-4}"
-i=1
-while [ "$i" -le "$POLL_PASSES" ]; do
- do_pull
- [ "$i" -lt "$POLL_PASSES" ] && sleep "$POLL_INTERVAL"
- i=$((i + 1))
-done
diff --git a/overlay/phobos-ttyd.sh b/overlay/phobos-ttyd.sh
deleted file mode 100755
index eb38d98..0000000
--- a/overlay/phobos-ttyd.sh
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/bin/sh
-# ============================================================
-# PCA Phobos — ttyd web-terminal на роутере Keenetic
-#
-# phobos-ttyd.sh [server_tunnel_ip]
-#
-# Ставит ttyd (web pty), открывает порт на WG-интерфейсе ТОЛЬКО для панели
-# (server tunnel IP), создаёт init-сервис (переживает перезагрузку).
-# Панель проксирует терминал к роутеру через WG-туннель (за NAT, без SSH).
-# ============================================================
-CID="${1:?usage: phobos-ttyd.sh [server_ip]}"
-TOKEN="${2:?token required}"
-SRV_IP="${3:-$(cat /opt/etc/Phobos/panel_tunnel_ip 2>/dev/null)}"
-[ -n "$SRV_IP" ] || SRV_IP="10.25.0.1"
-PORT="${TTYD_PORT:-7681}"
-SHELL_BIN="$( [ -x /opt/bin/bash ] && echo /opt/bin/bash || echo sh )"
-
-# WG tunnel netdev (best effort: interface holding RFC1918 or explicit panel route)
-WGDEV=$(ip route get "$SRV_IP" 2>/dev/null | awk '{for(i=1;i/dev/null 2>&1
-opkg install ttyd >/dev/null 2>&1
-opkg install iptables >/dev/null 2>&1
-TTYD_BIN="$(command -v ttyd || echo /opt/bin/ttyd)"
-[ -x "$TTYD_BIN" ] || { echo "ERROR: ttyd not installed"; exit 1; }
-
-mkdir -p /opt/etc/Phobos
-echo "$TOKEN" > /opt/etc/Phobos/ttyd_token
-chmod 600 /opt/etc/Phobos/ttyd_token
-
-# init.d service: opens firewall for panel + runs ttyd (base-path + basic auth)
-cat > /opt/etc/init.d/S51phobos-ttyd </dev/null)
-start() {
- # firewall: allow ONLY the panel (server tunnel IP) to reach ttyd over WG
- iptables -D INPUT -i "\$WGDEV" -s "\$SRV_IP" -p tcp --dport "\$PORT" -j ACCEPT 2>/dev/null
- iptables -I INPUT -i "\$WGDEV" -s "\$SRV_IP" -p tcp --dport "\$PORT" -j ACCEPT
- pkill -f "ttyd -p \$PORT" 2>/dev/null; sleep 1
- # busybox has no setsid/nohup; plain background detaches fine on Entware.
- # no -i flag => ttyd binds all interfaces (0.0.0.0).
- "\$TTYD" -p "\$PORT" -b "/ttyd/\$CID" -c "phobos:\$TOKEN" --writable "\$SH" >/tmp/phobos-ttyd.log 2>&1 &
- sleep 1
- echo "ttyd started on \$PORT (base /ttyd/\$CID, panel-only via \$SRV_IP)"
-}
-stop() {
- pkill -f "ttyd -p \$PORT" 2>/dev/null
- iptables -D INPUT -i "\$WGDEV" -s "\$SRV_IP" -p tcp --dport "\$PORT" -j ACCEPT 2>/dev/null
-}
-case "\$1" in
- start) start ;;
- stop) stop ;;
- restart) stop; sleep 1; start ;;
- *) echo "usage: \$0 {start|stop|restart}" ;;
-esac
-EOF
-chmod +x /opt/etc/init.d/S51phobos-ttyd
-/opt/etc/init.d/S51phobos-ttyd restart
-
-echo "OK: ttyd на роутере, base-path /ttyd/$CID, порт $PORT (только для $SRV_IP по $WGDEV)."
diff --git a/overlay/phobos-uninstall.sh b/overlay/phobos-uninstall.sh
deleted file mode 100755
index 1adafe3..0000000
--- a/overlay/phobos-uninstall.sh
+++ /dev/null
@@ -1,543 +0,0 @@
-#!/bin/sh
-set -e
-
-PHOBOS_DIR=""
-ROUTER_PLATFORM=""
-SELECTED_CONF=""
-IS_FULL_REMOVAL="1"
-OBFUSCATOR_CONFIGS=""
-OBFUSCATOR_CONFIG_COUNT=0
-
-. "$(dirname "$0")/lib-client.sh"
-
-collect_obf_configs() {
- OBFUSCATOR_CONFIGS=""
- OBFUSCATOR_CONFIG_COUNT=0
- [ -d "$PHOBOS_DIR" ] || return
- for f in "$PHOBOS_DIR"/wg-obfuscator*.conf; do
- [ -f "$f" ] || continue
- OBFUSCATOR_CONFIGS="${OBFUSCATOR_CONFIGS}$(basename "$f" .conf) "
- OBFUSCATOR_CONFIG_COUNT=$((OBFUSCATOR_CONFIG_COUNT + 1))
- done
-}
-
-get_config_label() {
- local obf_conf_base="$1"
- local idx_suffix="${obf_conf_base#wg-obfuscator}"
- local wg_iface="phobos${idx_suffix}"
- local addr=""
- if [ -f "/etc/wireguard/${wg_iface}.conf" ]; then
- addr=$(grep '^Address' "/etc/wireguard/${wg_iface}.conf" 2>/dev/null | cut -d'=' -f2 | tr -d ' ' | cut -d'/' -f1 | cut -d',' -f1) || addr=""
- fi
- if [ -n "$addr" ]; then
- printf "%s [интерфейс: %s, адрес: %s]" "$obf_conf_base" "$wg_iface" "$addr"
- else
- printf "%s" "$obf_conf_base"
- fi
-}
-
-select_config_to_remove() {
- collect_obf_configs
-
- if [ "$OBFUSCATOR_CONFIG_COUNT" -eq 0 ]; then
- IS_FULL_REMOVAL="1"
- SELECTED_CONF="all"
- return
- fi
-
- if [ "$OBFUSCATOR_CONFIG_COUNT" -eq 1 ]; then
- SELECTED_CONF=$(echo "$OBFUSCATOR_CONFIGS" | tr -s ' ' '\n' | grep -v '^$' | head -1)
- IS_FULL_REMOVAL="1"
- log "Обнаружена конфигурация: ${SELECTED_CONF}"
- return
- fi
-
- log ""
- log "Обнаружено несколько конфигураций:"
- log ""
-
- local i=1
- for conf_base in $OBFUSCATOR_CONFIGS; do
- local label
- label=$(get_config_label "$conf_base")
- log " ${i}) ${label}"
- i=$((i + 1))
- done
-
- local all_num=$i
- log " ${all_num}) Удалить все"
- log ""
-
- printf "Введите номер конфигурации для удаления: "
- read -r answer || answer=""
-
- case "$answer" in
- ''|*[!0-9]*)
- log "ОШИБКА: Неверный ввод"
- exit 1
- ;;
- esac
-
- if [ "$answer" -eq "$all_num" ]; then
- IS_FULL_REMOVAL="1"
- SELECTED_CONF="all"
- return
- fi
-
- if [ "$answer" -lt 1 ] || [ "$answer" -ge "$all_num" ]; then
- log "ОШИБКА: Номер вне диапазона"
- exit 1
- fi
-
- local selected_i=1
- for conf_base in $OBFUSCATOR_CONFIGS; do
- if [ "$selected_i" -eq "$answer" ]; then
- SELECTED_CONF="$conf_base"
- IS_FULL_REMOVAL="0"
- return
- fi
- selected_i=$((selected_i + 1))
- done
-}
-
-remove_single_obfuscator_instance() {
- local obf_conf_base="$1"
- local idx_suffix="${obf_conf_base#wg-obfuscator}"
- local binary_name="wg-obfuscator${idx_suffix}"
- local service_name="phobos-obfuscator${idx_suffix}"
- local wg_iface="phobos${idx_suffix}"
-
- log "Удаление конфигурации ${obf_conf_base}..."
-
- local link_file="$PHOBOS_DIR/${obf_conf_base}.link"
- local linked_client=""
- if [ -f "$link_file" ]; then
- linked_client=$(cat "$link_file" 2>/dev/null) || linked_client=""
- fi
-
- local privkey_fallback=""
- if [ -z "$linked_client" ] && [ "$ROUTER_PLATFORM" = "linux" ] && [ -f "/etc/wireguard/${wg_iface}.conf" ]; then
- privkey_fallback=$(grep '^PrivateKey' "/etc/wireguard/${wg_iface}.conf" 2>/dev/null | cut -d'=' -f2- | tr -d ' \t') || privkey_fallback=""
- fi
-
- for f in /opt/etc/init.d/S[0-9]*wg-obfuscator*; do
- [ -f "$f" ] || continue
- if grep -q "^PROCS=${binary_name}$" "$f" 2>/dev/null; then
- "$f" stop >/dev/null 2>&1 || true
- rm -f "$f"
- log " ✓ Удален init-скрипт: $f"
- break
- fi
- done
-
- if [ -f "/etc/init.d/${service_name}" ]; then
- /etc/init.d/${service_name} stop >/dev/null 2>&1 || true
- /etc/init.d/${service_name} disable >/dev/null 2>&1 || true
- rm -f "/etc/init.d/${service_name}"
- log " ✓ Удален procd init-скрипт: /etc/init.d/${service_name}"
- fi
-
- if command -v systemctl >/dev/null 2>&1 && [ -f "/etc/systemd/system/${service_name}.service" ]; then
- systemctl stop "${service_name}" >/dev/null 2>&1 || true
- systemctl disable "${service_name}" >/dev/null 2>&1 || true
- rm -f "/etc/systemd/system/${service_name}.service"
- log " ✓ Удален systemd сервис: /etc/systemd/system/${service_name}.service"
- fi
-
- for dir in /opt/bin /usr/bin /usr/local/bin; do
- if [ -f "${dir}/${binary_name}" ]; then
- rm -f "${dir}/${binary_name}"
- log " ✓ Удален бинарник: ${dir}/${binary_name}"
- fi
- done
-
- if [ "$ROUTER_PLATFORM" = "linux" ] && command -v systemctl >/dev/null 2>&1; then
- systemctl stop "wg-quick@${wg_iface}" >/dev/null 2>&1 || true
- systemctl disable "wg-quick@${wg_iface}" >/dev/null 2>&1 || true
- if [ -d "/etc/systemd/system/wg-quick@${wg_iface}.service.d" ]; then
- rm -rf "/etc/systemd/system/wg-quick@${wg_iface}.service.d"
- log " ✓ Удален systemd override: wg-quick@${wg_iface}"
- fi
- if [ -f "/etc/wireguard/${wg_iface}.conf" ]; then
- rm -f "/etc/wireguard/${wg_iface}.conf"
- log " ✓ Удален WireGuard конфиг: /etc/wireguard/${wg_iface}.conf"
- fi
- systemctl daemon-reload >/dev/null 2>&1 || true
- elif [ "$ROUTER_PLATFORM" = "keenetic" ]; then
- if command -v curl >/dev/null 2>&1 && command -v jq >/dev/null 2>&1 && [ -n "$linked_client" ]; then
- local target_desc="Phobos-${linked_client}"
- log " Удаление WireGuard интерфейса Keenetic: ${target_desc}..."
- local iface_list=$(curl -s "http://127.0.0.1:79/rci/show/interface" 2>/dev/null || echo "")
- if [ -n "$iface_list" ] && echo "$iface_list" | jq -e . >/dev/null 2>&1; then
- local iface_id=$(echo "$iface_list" | jq -r --arg desc "$target_desc" 'to_entries[] | select((.value.description? // "") == $desc) | .key' 2>/dev/null)
- if [ -n "$iface_id" ]; then
- local del_json=$(cat </dev/null)
- if echo "$del_result" | jq -e '.status == "error"' >/dev/null 2>&1; then
- local err_msg=$(echo "$del_result" | jq -r '.message // "Unknown error"' 2>/dev/null)
- log " ОШИБКА при удалении ${iface_id}: $err_msg"
- else
- log " ✓ Интерфейс ${iface_id} (${target_desc}) удален"
- curl -s -X POST \
- -H "Content-Type: application/json" \
- -d '{"system":{"configuration":{"save":{}}}}' \
- "http://127.0.0.1:79/rci/" >/dev/null 2>&1
- log " ✓ Конфигурация сохранена"
- fi
- else
- log " Интерфейс с описанием '${target_desc}' не найден"
- fi
- else
- log " RCI API недоступен, пропускаем удаление интерфейса Keenetic"
- fi
- else
- log " curl/jq не доступны или имя клиента не определено, пропускаем удаление интерфейса Keenetic"
- fi
- elif [ "$ROUTER_PLATFORM" = "openwrt" ]; then
- remove_wireguard_interfaces_openwrt
- remove_firewall_zone_openwrt
- fi
-
- if [ -f "$PHOBOS_DIR/${obf_conf_base}.conf" ]; then
- rm -f "$PHOBOS_DIR/${obf_conf_base}.conf"
- log " ✓ Удален конфиг obfuscator: $PHOBOS_DIR/${obf_conf_base}.conf"
- fi
-
- [ -f "$link_file" ] && rm -f "$link_file"
-
- if [ -n "$linked_client" ] && [ -f "$PHOBOS_DIR/${linked_client}.conf" ]; then
- rm -f "$PHOBOS_DIR/${linked_client}.conf"
- log " ✓ Удален конфиг клиента: ${linked_client}.conf"
- elif [ -n "$privkey_fallback" ]; then
- for client_conf in "$PHOBOS_DIR"/*.conf; do
- [ -f "$client_conf" ] || continue
- case "$(basename "$client_conf")" in
- wg-obfuscator*.conf) continue ;;
- esac
- if grep -qF "PrivateKey = ${privkey_fallback}" "$client_conf" 2>/dev/null; then
- rm -f "$client_conf"
- log " ✓ Удален конфиг клиента: $(basename "$client_conf")"
- break
- fi
- done
- fi
-
- local remaining=0
- for f in "$PHOBOS_DIR"/*.conf; do
- [ -f "$f" ] && remaining=$((remaining + 1))
- done
-
- if [ "$remaining" -eq 0 ] && [ -d "$PHOBOS_DIR" ]; then
- rm -rf "$PHOBOS_DIR"
- log " ✓ Удалена директория: $PHOBOS_DIR"
- fi
-}
-
-stop_obfuscator() {
- log "Остановка wg-obfuscator..."
-
- for f in /opt/etc/init.d/S[0-9]*wg-obfuscator*; do
- [ -f "$f" ] && "$f" stop >/dev/null 2>&1 || true
- done
-
- for f in /etc/init.d/phobos-obfuscator*; do
- if [ -f "$f" ]; then
- "$f" stop >/dev/null 2>&1 || true
- "$f" disable >/dev/null 2>&1 || true
- fi
- done
-
- if command -v systemctl >/dev/null 2>&1; then
- systemctl list-units --no-legend --plain 'phobos-obfuscator*.service' | awk '{print $1}' | while read -r unit; do
- systemctl stop "$unit" >/dev/null 2>&1 || true
- systemctl disable "$unit" >/dev/null 2>&1 || true
- done
- fi
-
- if ps | grep -v grep | grep -q wg-obfuscator; then
- log " Принудительное завершение процесса..."
- pkill -f wg-obfuscator >/dev/null 2>&1 || true
- fi
-}
-
-remove_wireguard_interfaces_keenetic() {
- log "Удаление WireGuard интерфейсов Phobos (Keenetic)..."
-
- if ! command -v curl >/dev/null 2>&1 || ! command -v jq >/dev/null 2>&1; then
- log " curl или jq не установлен, пропускаем удаление интерфейсов"
- return 0
- fi
-
- local interfaces=$(curl -s "http://127.0.0.1:79/rci/show/interface" 2>/dev/null || echo "")
-
- if [ -z "$interfaces" ] || ! echo "$interfaces" | jq -e . >/dev/null 2>&1; then
- log " RCI API недоступен или вернул некорректный JSON"
- return 0
- fi
-
- local removed_count=0
-
- local phobos_interfaces=$(echo "$interfaces" | jq -r 'to_entries[] | select(.value.description? // "" | startswith("Phobos-")) | .key' 2>/dev/null)
-
- if [ -z "$phobos_interfaces" ]; then
- log " Интерфейсы Phobos не найдены в системе"
- return 0
- fi
-
- echo "$phobos_interfaces" | while read -r interface_id; do
- if [ -z "$interface_id" ]; then
- continue
- fi
-
- local interface_desc=$(echo "$interfaces" | jq -r --arg id "$interface_id" '.[$id].description // "unknown"' 2>/dev/null)
-
- log " Удаление интерфейса: $interface_id ($interface_desc)"
-
- local delete_json=$(cat </dev/null)
-
- if echo "$result" | jq -e '.status == "error"' >/dev/null 2>&1; then
- local error_msg=$(echo "$result" | jq -r '.message // "Unknown error"' 2>/dev/null)
- log " ОШИБКА при удалении $interface_id: $error_msg"
- else
- log " ✓ Интерфейс $interface_id удален"
- removed_count=$((removed_count + 1))
- fi
- done
-
- local save_result=$(curl -s -X POST \
- -H "Content-Type: application/json" \
- -d '{"system":{"configuration":{"save":{}}}}' \
- "http://127.0.0.1:79/rci/" 2>/dev/null)
-
- if [ $removed_count -gt 0 ]; then
- log "✓ Удалено интерфейсов: $removed_count"
- log "✓ Конфигурация сохранена"
- fi
-}
-
-remove_wireguard_interfaces_openwrt() {
- log "Удаление WireGuard интерфейсов Phobos (OpenWRT)..."
-
- if ! command -v uci >/dev/null 2>&1; then
- log " uci не установлен, пропускаем удаление интерфейсов"
- return 0
- fi
-
- local interface_name="phobos_wg"
-
- if uci -q get network.${interface_name} >/dev/null 2>&1; then
- log " Удаление интерфейса: ${interface_name}"
-
- ifdown ${interface_name} >/dev/null 2>&1 || true
-
- uci -q delete network.${interface_name} || true
-
- local peers=$(uci show network 2>/dev/null | grep "wireguard_${interface_name}" | cut -d'.' -f2 | cut -d'=' -f1 | sort -u)
- for peer in $peers; do
- uci -q delete network.$peer || true
- done
-
- uci commit network
-
- log " ✓ Интерфейс ${interface_name} удален"
- else
- log " Интерфейс ${interface_name} не найден"
- fi
-
- /etc/init.d/network reload >/dev/null 2>&1 || true
-}
-
-remove_firewall_zone_openwrt() {
- log "Удаление файрволл зоны Phobos (OpenWRT)..."
-
- if ! command -v uci >/dev/null 2>&1; then
- log " uci не установлен, пропускаем удаление зоны"
- return 0
- fi
-
- local zone_name="phobos"
-
- if uci -q get firewall.${zone_name} >/dev/null 2>&1; then
- log " Удаление зоны: ${zone_name}"
- uci -q delete firewall.${zone_name} || true
- uci commit firewall
- log " ✓ Зона ${zone_name} удалена"
-
- /etc/init.d/firewall reload >/dev/null 2>&1 || true
- else
- log " Зона ${zone_name} не найдена"
- fi
-}
-
-remove_wireguard_interfaces_linux() {
- log "Удаление WireGuard интерфейсов Phobos (Linux)..."
-
- if ! command -v systemctl >/dev/null 2>&1; then
- log " systemctl не найден, пропускаем удаление интерфейсов"
- return 0
- fi
-
- for wg_conf in /etc/wireguard/phobos*.conf; do
- [ -f "$wg_conf" ] || continue
- local wg_interface
- wg_interface=$(basename "$wg_conf" .conf)
-
- if systemctl is-enabled --quiet wg-quick@${wg_interface} 2>/dev/null || systemctl is-active --quiet wg-quick@${wg_interface} 2>/dev/null; then
- log " Остановка и удаление WireGuard сервиса: wg-quick@${wg_interface}"
- systemctl stop wg-quick@${wg_interface} >/dev/null 2>&1 || true
- systemctl disable wg-quick@${wg_interface} >/dev/null 2>&1 || true
- log " ✓ Сервис wg-quick@${wg_interface} остановлен и отключен"
- fi
-
- if [ -d "/etc/systemd/system/wg-quick@${wg_interface}.service.d" ]; then
- log " Удаление systemd override: /etc/systemd/system/wg-quick@${wg_interface}.service.d"
- rm -rf "/etc/systemd/system/wg-quick@${wg_interface}.service.d"
- log " ✓ Systemd override удален"
- fi
-
- log " Удаление конфигурации: $wg_conf"
- rm -f "$wg_conf"
- log " ✓ Конфигурационный файл WireGuard удален"
- done
-
- systemctl daemon-reload >/dev/null 2>&1 || true
-}
-
-remove_files() {
- log "Удаление файлов Phobos..."
-
- for f in /opt/etc/init.d/S[0-9]*wg-obfuscator*; do
- if [ -f "$f" ]; then
- rm -f "$f"
- log " ✓ Удален init-скрипт: $f"
- fi
- done
-
- for f in /etc/init.d/phobos-obfuscator*; do
- if [ -f "$f" ]; then
- rm -f "$f"
- log " ✓ Удален procd init-скрипт: $f"
- fi
- done
-
- for f in /opt/bin/wg-obfuscator*; do
- if [ -f "$f" ]; then
- rm -f "$f"
- log " ✓ Удален бинарник: $f"
- fi
- done
-
- for f in /usr/bin/wg-obfuscator*; do
- if [ -f "$f" ]; then
- rm -f "$f"
- log " ✓ Удален бинарник: $f"
- fi
- done
-
- for f in /usr/local/bin/wg-obfuscator*; do
- if [ -f "$f" ]; then
- rm -f "$f"
- log " ✓ Удален бинарник: $f"
- fi
- done
-
- local daemon_reload_needed=0
- for f in /etc/systemd/system/phobos-obfuscator*.service; do
- if [ -f "$f" ]; then
- rm -f "$f"
- daemon_reload_needed=1
- log " ✓ Удален systemd сервис: $f"
- fi
- done
-
- if [ $daemon_reload_needed -eq 1 ]; then
- systemctl daemon-reload >/dev/null 2>&1 || true
- fi
-
- if [ -d "$PHOBOS_DIR" ]; then
- rm -rf "$PHOBOS_DIR"
- log " ✓ Удалена директория: $PHOBOS_DIR"
- fi
-}
-
-show_final_info() {
- log ""
- log "╔════════════════════════════════════════════════════════════╗"
- log "║ Phobos успешно удален ║"
- log "╚════════════════════════════════════════════════════════════╝"
- log ""
- log "Удалены компоненты:"
- log " - wg-obfuscator (процесс, init-скрипт/сервис, бинарник)"
- log " - WireGuard интерфейсы Phobos"
- log " - Конфигурационные файлы"
- log ""
-}
-
-main() {
- ROUTER_PLATFORM=$(detect_router_platform)
- PHOBOS_DIR=$(detect_phobos_dir "$ROUTER_PLATFORM")
-
- log "==> Начало удаления Phobos (платформа: $ROUTER_PLATFORM)"
- log "==> Директория: $PHOBOS_DIR"
-
- check_root
-
- select_config_to_remove
-
- if [ "$IS_FULL_REMOVAL" = "1" ]; then
- stop_obfuscator
-
- if [ "$ROUTER_PLATFORM" = "keenetic" ]; then
- remove_wireguard_interfaces_keenetic
- elif [ "$ROUTER_PLATFORM" = "openwrt" ]; then
- remove_wireguard_interfaces_openwrt
- remove_firewall_zone_openwrt
- elif [ "$ROUTER_PLATFORM" = "linux" ]; then
- remove_wireguard_interfaces_linux
- else
- log "ПРЕДУПРЕЖДЕНИЕ: Неизвестная платформа, пропускаем удаление WireGuard интерфейсов"
- fi
-
- remove_files
-
- show_final_info
- else
- log "==> Удаление конфигурации: ${SELECTED_CONF}"
- remove_single_obfuscator_instance "$SELECTED_CONF"
- log ""
- log "╔════════════════════════════════════════════════════════════╗"
- log "║ Конфигурация успешно удалена ║"
- log "╚════════════════════════════════════════════════════════════╝"
- log ""
- fi
-
- log "==> Удаление завершено."
-}
-
-main "$@"
diff --git a/overlay/router-configure-wireguard-openwrt.sh b/overlay/router-configure-wireguard-openwrt.sh
deleted file mode 100755
index 2b32fc6..0000000
--- a/overlay/router-configure-wireguard-openwrt.sh
+++ /dev/null
@@ -1,349 +0,0 @@
-#!/bin/sh
-set -e
-
-CLIENT_NAME=""
-CLIENT_PRIVATE_KEY=""
-CLIENT_IP=""
-CLIENT_IPV6=""
-SERVER_PUBLIC_KEY=""
-ENDPOINT_PORT=13255
-KEEPALIVE=25
-MTU=1420
-FALLBACK_CONFIG=""
-
-log() {
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
-}
-
-error() {
- echo "[ERROR] $*" >&2
- log "ERROR: $*"
-}
-
-usage() {
- cat </dev/null 2>&1; then
- missing="$missing $cmd"
- fi
- done
-
- if [ -n "$missing" ]; then
- error "Missing required utilities:$missing"
- return 1
- fi
-
- return 0
-}
-
-parse_args() {
- while [ $# -gt 0 ]; do
- case "$1" in
- --client-name)
- CLIENT_NAME="$2"
- shift 2
- ;;
- --client-private-key)
- CLIENT_PRIVATE_KEY="$2"
- shift 2
- ;;
- --client-ip)
- CLIENT_IP="$2"
- shift 2
- ;;
- --client-ipv6)
- CLIENT_IPV6="$2"
- shift 2
- ;;
- --server-public-key)
- SERVER_PUBLIC_KEY="$2"
- shift 2
- ;;
- --endpoint-port)
- ENDPOINT_PORT="$2"
- shift 2
- ;;
- --keepalive)
- KEEPALIVE="$2"
- shift 2
- ;;
- --mtu)
- MTU="$2"
- shift 2
- ;;
- --fallback-config)
- FALLBACK_CONFIG="$2"
- shift 2
- ;;
- --help)
- usage
- ;;
- *)
- error "Unknown option: $1"
- usage
- ;;
- esac
- done
-
- if [ -z "${CLIENT_NAME}" ] || [ -z "${CLIENT_PRIVATE_KEY}" ] || \
- [ -z "${CLIENT_IP}" ] || [ -z "${CLIENT_IPV6}" ] || \
- [ -z "${SERVER_PUBLIC_KEY}" ]; then
- error "Missing required parameters"
- usage
- fi
-}
-
-check_existing_interface() {
- local interface_name="phobos_wg"
-
- if uci -q get network.${interface_name} >/dev/null 2>&1; then
- log "Найден существующий интерфейс: ${interface_name}"
- return 0
- else
- log "Существующий интерфейс Phobos не найден"
- return 1
- fi
-}
-
-remove_existing_interface() {
- local interface_name="phobos_wg"
-
- log "Удаление существующего интерфейса ${interface_name}..."
-
- uci -q delete network.${interface_name} || true
-
- local peers=$(uci show network | grep "wireguard_${interface_name}" | cut -d'.' -f2 | cut -d'=' -f1 | sort -u)
- for peer in $peers; do
- uci -q delete network.$peer || true
- done
-
- uci commit network
- log "Существующий интерфейс удален"
-}
-
-configure_wireguard_interface() {
- local interface_name="phobos_wg"
-
- log "Настройка интерфейса ${interface_name} через UCI..."
-
- uci set network.${interface_name}=interface
- uci set network.${interface_name}.proto='wireguard'
- uci set network.${interface_name}.private_key="${CLIENT_PRIVATE_KEY}"
- uci set network.${interface_name}.mtu="${MTU}"
-
- uci add_list network.${interface_name}.addresses="${CLIENT_IP}"
-
- if [ "${CLIENT_IPV6}" != "none" ] && [ -n "${CLIENT_IPV6}" ]; then
- uci add_list network.${interface_name}.addresses="${CLIENT_IPV6}"
- fi
-
- local peer_name="wgpeer_${interface_name}"
- uci add network wireguard_${interface_name}
- uci rename network.@wireguard_${interface_name}[-1]="${peer_name}"
- uci set network.${peer_name}.public_key="${SERVER_PUBLIC_KEY}"
- uci set network.${peer_name}.description="Phobos VPS Server"
- uci set network.${peer_name}.endpoint_host='127.0.0.1'
- uci set network.${peer_name}.endpoint_port="${ENDPOINT_PORT}"
- uci set network.${peer_name}.persistent_keepalive="${KEEPALIVE}"
- uci set network.${peer_name}.route_allowed_ips='0'
-
- uci add_list network.${peer_name}.allowed_ips='0.0.0.0/0'
- uci add_list network.${peer_name}.allowed_ips='::/0'
-
- uci commit network
-
- log "Интерфейс ${interface_name} настроен ✓"
- return 0
-}
-
-configure_firewall_zone() {
- local zone_name="phobos"
- local interface_name="phobos_wg"
-
- log "Настройка файрволла для зоны ${zone_name}..."
-
- if uci -q get firewall.${zone_name} >/dev/null 2>&1; then
- log "Зона ${zone_name} уже существует, обновляем..."
- uci delete firewall.${zone_name}
- fi
-
- uci add firewall zone
- uci rename firewall.@zone[-1]="${zone_name}"
- uci set firewall.${zone_name}.name="${zone_name}"
- uci add_list firewall.${zone_name}.network="${interface_name}"
- uci set firewall.${zone_name}.input='REJECT'
- uci set firewall.${zone_name}.output='ACCEPT'
- uci set firewall.${zone_name}.forward='REJECT'
- uci set firewall.${zone_name}.masq='0'
- uci set firewall.${zone_name}.mtu_fix='1'
-
- uci commit firewall
-
- log "Файрволл зона ${zone_name} настроена ✓"
- return 0
-}
-
-restart_network_services() {
- log "Перезапуск сетевых сервисов..."
-
- /etc/init.d/network reload >/dev/null 2>&1 || true
- sleep 3
-
- ifup phobos_wg >/dev/null 2>&1 || true
- sleep 2
-
- /etc/init.d/firewall reload >/dev/null 2>&1 || true
- sleep 1
-
- log "Сетевые сервисы перезапущены ✓"
-}
-
-verify_interface_created() {
- log "Проверка создания интерфейса WireGuard..."
-
- local max_attempts=5
- local attempt=1
-
- while [ $attempt -le $max_attempts ]; do
- if ip link show phobos_wg >/dev/null 2>&1; then
- log "Интерфейс phobos_wg найден (попытка $attempt/$max_attempts)"
-
- if wg show phobos_wg >/dev/null 2>&1; then
- log "WireGuard интерфейс phobos_wg активен"
-
- if uci -q get network.phobos_wg >/dev/null 2>&1; then
- log "UCI конфигурация phobos_wg найдена"
- return 0
- else
- log "UCI конфигурация phobos_wg не найдена, но интерфейс работает"
- return 0
- fi
- else
- log "Интерфейс найден, но WireGuard не активен (попытка $attempt/$max_attempts)"
- fi
- else
- log "Интерфейс phobos_wg еще не создан (попытка $attempt/$max_attempts)..."
- fi
-
- if [ $attempt -lt $max_attempts ]; then
- sleep 2
- fi
- attempt=$((attempt + 1))
- done
-
- error "Интерфейс phobos_wg не найден после $max_attempts попыток"
- return 1
-}
-
-show_fallback_instructions() {
- cat </dev/null | sed 's/^/ /' || true
- log ""
-
- exit 0
- else
- log ""
- log "Не удалось подтвердить создание интерфейса WireGuard"
- log ""
- log "Проверьте вручную:"
- log " ip link show phobos_wg"
- log " wg show phobos_wg"
- log " uci show network.phobos_wg"
- log ""
- log "Если интерфейс существует (ip link show phobos_wg работает),"
- log "то настройка прошла успешно, несмотря на ошибку проверки."
- log ""
- exit 1
- fi
-}
-
-main "$@"
\ No newline at end of file
diff --git a/overlay/router-configure-wireguard.sh b/overlay/router-configure-wireguard.sh
deleted file mode 100755
index f8bb787..0000000
--- a/overlay/router-configure-wireguard.sh
+++ /dev/null
@@ -1,455 +0,0 @@
-#!/bin/sh
-set -e
-
-RCI_URL="http://localhost:79/rci/"
-MAX_INTERFACE_NUM=9
-
-check_dependencies() {
- local missing=""
-
- for cmd in curl jq date; do
- if ! command -v "$cmd" >/dev/null 2>&1; then
- missing="$missing $cmd"
- fi
- done
-
- if [ -n "$missing" ]; then
- echo "ERROR: Missing required utilities:$missing" >&2
- echo "Please install them using: opkg update && opkg install$missing" >&2
- return 1
- fi
-
- return 0
-}
-
-CLIENT_NAME=""
-CLIENT_PRIVATE_KEY=""
-CLIENT_IP=""
-CLIENT_IPV6=""
-SERVER_PUBLIC_KEY=""
-ENDPOINT_PORT=13255
-KEEPALIVE=25
-MTU=1420
-FALLBACK_CONFIG=""
-
-log() {
- echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
-}
-
-error() {
- echo "[ERROR] $*" >&2
- log "ERROR: $*"
-}
-
-usage() {
- cat <&2
-
- local i
- for i in 0 1 2 3 4 5 6 7 8 9; do
- local interface_json=$(curl -s "${RCI_URL}show/rc/interface/Wireguard${i}" 2>/dev/null)
-
- if [ -n "${interface_json}" ] && echo "${interface_json}" | jq -e . >/dev/null 2>&1; then
- local desc=$(echo "${interface_json}" | jq -r '.description // empty' 2>/dev/null)
- if [ "${desc}" = "${target_desc}" ]; then
- log "Найден существующий интерфейс: Wireguard${i}" >&2
- echo "Wireguard${i}"
- return 0
- fi
- fi
- done
-
- log "Существующий интерфейс Phobos не найден" >&2
- echo ""
- return 0
-}
-
-find_free_wireguard_interface() {
- log "Поиск свободного интерфейса WireGuard..." >&2
-
- local i
- for i in 0 1 2 3 4 5 6 7 8 9; do
- local interface_json=$(curl -s "${RCI_URL}show/interface/Wireguard${i}" 2>/dev/null)
-
- if [ -z "${interface_json}" ] || ! echo "${interface_json}" | jq -e '.id' >/dev/null 2>&1; then
- log "Найден свободный интерфейс: Wireguard${i}" >&2
- echo "Wireguard${i}"
- return 0
- fi
- done
-
- error "Нет свободных интерфейсов WireGuard (0-${MAX_INTERFACE_NUM})"
- return 1
-}
-
-remove_wireguard_interface() {
- local interface_name="$1"
-
- log "Удаление существующего интерфейса: ${interface_name}..."
-
- if command -v ndmc >/dev/null 2>&1; then
- if ndmc -c "no interface ${interface_name}" >/dev/null 2>&1; then
- log "Интерфейс ${interface_name} успешно удален ✓"
- return 0
- else
- log "Предупреждение: не удалось удалить интерфейс через ndmc"
- return 1
- fi
- else
- log "Предупреждение: команда ndmc не найдена"
- return 1
- fi
-}
-
-configure_wireguard_interface() {
- local interface_name="$1"
-
- local description="Phobos-${CLIENT_NAME}"
- local client_ip_addr=$(echo "${CLIENT_IP}" | cut -d'/' -f1)
- local client_ipv6_block="${CLIENT_IPV6}"
- local route_target=$(echo "$client_ip_addr" | cut -d'.' -f1-2).0.0/16
-
- log "Настройка интерфейса ${interface_name}..."
-
- local config_json=$(cat </dev/null)
-
- if echo "${result}" | jq -e '.status == "error"' >/dev/null 2>&1; then
- local error_msg=$(echo "${result}" | jq -r '.message // "Unknown error"' 2>/dev/null)
- error "RCI API отклонил конфигурацию: ${error_msg}"
- log "JSON запрос:"
- log "${config_json}"
- return 1
- fi
-
- # Настраиваем статический маршрут в созданный интерфейс отдельным вызовом RCI
- local route_target_net=$(echo "$client_ip_addr" | cut -d'.' -f1-2).0.0
- log "Настройка маршрута для подсети туннеля (${route_target_net}/16) -> ${interface_name}..."
- local route_json=$(cat </dev/null)
-
- if echo "${route_result}" | jq -e '.status[] | select(.status == "error")' >/dev/null 2>&1; then
- local error_msg=$(echo "${route_result}" | jq -r '.status[] | select(.status == "error") | .message // "Unknown error"' 2>/dev/null)
- error "RCI API отклонил настройку маршрута: ${error_msg}"
- log "JSON запрос:"
- log "${route_json}"
- return 1
- fi
-
- log "Интерфейс ${interface_name} создан ✓"
-
- return 0
-}
-
-save_configuration() {
- log "Сохранение конфигурации..."
-
- local result=$(curl -s -X POST \
- -H "Content-Type: application/json" \
- -d '{"system":{"configuration":{"save":{}}}}' \
- "${RCI_URL}" 2>/dev/null)
-
- if echo "${result}" | grep -q '"status"[[:space:]]*:[[:space:]]*"message"'; then
- log "Конфигурация сохранена ✓"
- return 0
- else
- error "Ошибка сохранения конфигурации"
- return 1
- fi
-}
-
-verify_interface_created() {
- local client_name="$1"
- local interface_description="Phobos-${client_name}"
-
- log "Проверка создания интерфейса WireGuard..."
-
- local interfaces=$(curl -s "http://127.0.0.1:79/rci/show/interface" 2>/dev/null || echo "")
-
- if [ -z "$interfaces" ]; then
- error "Не удалось получить список интерфейсов через RCI API"
- return 1
- fi
-
- if ! echo "$interfaces" | jq -e . >/dev/null 2>&1; then
- error "Некорректный JSON ответ от RCI API"
- return 1
- fi
-
- local found=$(echo "$interfaces" | jq -r "to_entries[] | select(.value.description == \"$interface_description\") | .key" 2>/dev/null)
-
- if [ -n "$found" ]; then
- log "✓ Интерфейс $found (Phobos-${client_name}) успешно создан"
- return 0
- else
- error "Интерфейс с description '$interface_description' не найден"
- return 1
- fi
-}
-
-show_fallback_instructions() {
- cat <&1)
- if echo "${obf_status}" | grep -q "dead"; then
- log "⚠ wg-obfuscator остановлен, перезапускаем..."
- /opt/etc/init.d/S49wg-obfuscator start
- sleep 2
- log "✓ wg-obfuscator перезапущен"
- else
- log "✓ wg-obfuscator работает"
- fi
- fi
-
- log ""
- log "Ожидание применения конфигурации..."
- sleep 5
-
- if verify_interface_created "${CLIENT_NAME}"; then
- log ""
- log "╔════════════════════════════════════════════════════════════╗"
- log "║ WireGuard успешно настроен! ║"
- log "╚════════════════════════════════════════════════════════════╝"
- log ""
- exit 0
- else
- log ""
- log "⚠ Не удалось подтвердить создание интерфейса WireGuard"
- log ""
- log "Проверьте вручную в веб-панели Keenetic:"
- log " Интернет → WireGuard"
- log ""
- exit 1
- fi
-}
-
-main "$@"
diff --git a/phobos-panel.service b/phobos-panel.service
deleted file mode 100644
index 603b17e..0000000
--- a/phobos-panel.service
+++ /dev/null
@@ -1,15 +0,0 @@
-[Unit]
-Description=Phobos VPN Web Panel
-After=network.target wg-quick@wg0.service
-Wants=wg-quick@wg0.service
-
-[Service]
-Type=simple
-WorkingDirectory=/opt/phobos-panel
-ExecStart=/usr/bin/gunicorn -w 1 --threads 20 -b 0.0.0.0:8443 app:app
-Restart=always
-RestartSec=5
-Environment=PYTHONUNBUFFERED=1
-
-[Install]
-WantedBy=multi-user.target
diff --git a/promote.sh b/promote.sh
deleted file mode 100755
index 042de38..0000000
--- a/promote.sh
+++ /dev/null
@@ -1,126 +0,0 @@
-#!/bin/bash
-# ============================================================
-# PCA Phobos — promote / sync каналов (maintainer-инструмент)
-#
-# Каналы и репозитории:
-# stable -> публичный andrey271192/PCA_Phobos ветка main
-# beta -> приватный andrey271192/PCA_Phobos-dev ветка beta
-# dev -> приватный andrey271192/PCA_Phobos-dev ветка dev
-#
-# Поток фич — строго в одну сторону: dev -> beta -> stable
-# Хотфикс в stable -> forward-port в beta и dev (чтоб не потерялся).
-#
-# Использование (GH_TOKEN в env):
-# GH_TOKEN=ghp_xxx ./promote.sh status
-# GH_TOKEN=ghp_xxx ./promote.sh dev2beta
-# GH_TOKEN=ghp_xxx ./promote.sh beta2stable 1.3.0
-# GH_TOKEN=ghp_xxx ./promote.sh forward # main->beta->dev (после хотфикса)
-#
-# Мёрж обычный (без -X). При конфликте — НЕ пушит, оставляет рабочую копию
-# в $WORK для ручного разбора. Версии (VERSION) выставляются по каналу.
-# ============================================================
-set -e
-GH_TOKEN="${GH_TOKEN:-}"
-[ -n "$GH_TOKEN" ] || { echo "Нужен GH_TOKEN (env)."; exit 1; }
-PUB="https://andrey271192:${GH_TOKEN}@github.com/andrey271192/PCA_Phobos.git"
-PRIV="https://andrey271192:${GH_TOKEN}@github.com/andrey271192/PCA_Phobos-dev.git"
-WORK="${PCA_WORK:-/tmp/pca-promote-work}"
-
-repo_for() { case "$1" in main) echo "$PUB";; beta|dev) echo "$PRIV";; esac; }
-
-init_work() {
- rm -rf "$WORK"; mkdir -p "$WORK"
- git -C "$WORK" init -q
- git -C "$WORK" config user.email "maintainer@pca"
- git -C "$WORK" config user.name "PCA promote"
-}
-
-co_branch() { # $1=branch -> checkout local copy of remote branch
- local br="$1" repo; repo=$(repo_for "$br")
- git -C "$WORK" fetch -q "$repo" "$br"
- git -C "$WORK" checkout -q -B "$br" FETCH_HEAD
-}
-
-ver_now() { tr -d ' \r\n' < "$WORK/VERSION" 2>/dev/null; }
-
-do_merge() { # $1=incoming-ref-msg label ; merges FETCH_HEAD into current branch
- if ! git -C "$WORK" merge --no-edit -m "$1" FETCH_HEAD; then
- echo ""
- echo "!!! КОНФЛИКТ. Не запушено. Разрули вручную:"
- echo " cd $WORK && git status # правь файлы, git add, git commit"
- echo " затем git push "
- exit 1
- fi
-}
-
-case "${1:-status}" in
-
- status)
- init_work
- echo "== Версии каналов =="
- for br in main beta dev; do
- co_branch "$br" >/dev/null 2>&1 || { printf " %-7s (нет)\n" "$br"; continue; }
- printf " %-7s %s (%s)\n" "$br" "$(ver_now)" "$(git -C "$WORK" rev-parse --short HEAD)"
- done
- echo "Поток: dev -> beta -> stable. После хотфикса в stable: ./promote.sh forward"
- ;;
-
- dev2beta)
- init_work
- echo "== Промоут dev -> beta =="
- co_branch beta
- git -C "$WORK" fetch -q "$PRIV" dev
- DEVVER=$(git -C "$WORK" show FETCH_HEAD:VERSION | tr -d ' \r\n')
- do_merge "promote: merge dev into beta"
- BETAVER="${DEVVER%-dev}-beta"
- echo "$BETAVER" > "$WORK/VERSION"
- git -C "$WORK" commit -q -am "promote: beta VERSION -> $BETAVER" || true
- git -C "$WORK" push -q "$PRIV" beta:beta
- git -C "$WORK" tag -f "v$BETAVER" >/dev/null; git -C "$WORK" push -fq "$PRIV" "v$BETAVER"
- echo "OK -> beta = $BETAVER (тег v$BETAVER)"
- ;;
-
- beta2stable)
- STABLEVER="${2:-}"
- [ -n "$STABLEVER" ] || { echo "Укажи версию: ./promote.sh beta2stable 1.3.0"; exit 1; }
- init_work
- echo "== Релиз beta -> stable (v$STABLEVER) =="
- co_branch main
- git -C "$WORK" fetch -q "$PRIV" beta
- do_merge "release: merge beta into stable v$STABLEVER"
- echo "$STABLEVER" > "$WORK/VERSION"
- git -C "$WORK" commit -q -am "release: stable VERSION -> $STABLEVER" || true
- git -C "$WORK" push -q "$PUB" main:main
- git -C "$WORK" tag -f "v$STABLEVER" >/dev/null; git -C "$WORK" push -fq "$PUB" "v$STABLEVER"
- echo "OK -> stable = $STABLEVER (тег v$STABLEVER). Дальше: ./promote.sh forward"
- ;;
-
- forward)
- init_work
- echo "== Forward-port stable -> beta -> dev =="
- # main -> beta
- co_branch beta
- BETAVER=$(ver_now)
- git -C "$WORK" fetch -q "$PUB" main
- do_merge "forward: merge stable into beta"
- echo "$BETAVER" > "$WORK/VERSION"; git -C "$WORK" commit -q -am "forward: keep beta VERSION $BETAVER" || true
- git -C "$WORK" push -q "$PRIV" beta:beta
- echo " beta <- stable OK"
- # beta -> dev
- co_branch dev
- DEVVER=$(ver_now)
- git -C "$WORK" fetch -q "$PRIV" beta
- do_merge "forward: merge beta into dev"
- echo "$DEVVER" > "$WORK/VERSION"; git -C "$WORK" commit -q -am "forward: keep dev VERSION $DEVVER" || true
- git -C "$WORK" push -q "$PRIV" dev:dev
- echo " dev <- beta OK. Forward-port завершён."
- ;;
-
- *)
- echo "promote.sh — продвижение каналов PCA Phobos"
- echo " status версии всех каналов"
- echo " dev2beta dev -> beta (кандидат)"
- echo " beta2stable beta -> stable (релиз + тег)"
- echo " forward stable -> beta -> dev (после хотфикса)"
- ;;
-esac
diff --git a/server/api.py b/server/api.py
deleted file mode 100644
index 45dc78f..0000000
--- a/server/api.py
+++ /dev/null
@@ -1,262 +0,0 @@
-#!/usr/bin/env python3
-"""Phobos Secondary Server API — peer management + health."""
-import json, os, subprocess, time, hmac
-from pathlib import Path
-from flask import Flask, request, jsonify
-
-app = Flask(__name__)
-
-def load_env():
- env = {}
- with open("/opt/Phobos/server/server.env") as f:
- for line in f:
- if "=" in line and not line.startswith("#"):
- k, v = line.strip().split("=", 1)
- env[k] = v
- return env
-
-def check_api_key():
- env = load_env()
- key = request.headers.get("X-API-Key", "")
- return hmac.compare_digest(key, env.get("MAIN_API_KEY", ""))
-
-
-def default_iface():
- try:
- out = subprocess.check_output(["ip", "route", "get", "8.8.8.8"], text=True, timeout=4)
- parts = out.split()
- for i, part in enumerate(parts[:-1]):
- if part == "dev":
- return parts[i + 1].strip()
- except Exception:
- pass
- return ""
-
-
-def cpu_percent():
- try:
- with open("/proc/stat") as fh:
- a = fh.readline().split()[1:]
- time.sleep(0.1)
- with open("/proc/stat") as fh:
- b = fh.readline().split()[1:]
- a = [int(x) for x in a]
- b = [int(x) for x in b]
- idle = b[3] - a[3]
- total = sum(b) - sum(a)
- if total <= 0:
- return "?"
- return f"{round(100 - (idle * 100.0 / total), 1)}%"
- except Exception:
- return "?"
-
-def net_bytes():
- try:
- iface = default_iface()
- with open("/proc/net/dev") as fh:
- for line in fh:
- if line.split(":")[0].strip() == iface:
- p = line.split(":")[1].split()
- return {"iface": iface, "rx": int(p[0]), "tx": int(p[8]), "ts": int(time.time())}
- except Exception:
- pass
- return {}
-
-
-@app.route("/api/health")
-def health():
- try:
- out = subprocess.check_output(["wg", "show", "wg0", "dump"], text=True, timeout=5)
- peer_keys = []
- handshakes = {}
- for line in out.strip().split("\n")[1:]:
- parts = line.split("\t")
- if len(parts) >= 4:
- pub = parts[0]
- peer_keys.append(pub)
- try:
- handshakes[pub] = int(parts[4])
- except Exception:
- handshakes[pub] = 0
- peers = len(peer_keys)
- except Exception:
- peers = 0
- peer_keys = []
- handshakes = {}
- cpu = cpu_percent()
- try:
- parts = Path("/proc/meminfo").read_text().splitlines()
- vals = {}
- for line in parts:
- k, v = line.split(":", 1)
- vals[k] = int(v.strip().split()[0])
- total = vals.get("MemTotal", 0) // 1024
- avail = vals.get("MemAvailable", 0) // 1024
- used = max(total - avail, 0)
- mem_str = f"{used}/{total}MB"
- except Exception:
- mem_str = "?"
- return jsonify({"status": "ok", "peers": peers, "peer_keys": peer_keys, "handshakes": handshakes, "cpu": cpu, "mem": mem_str, "net": net_bytes()})
-
-
-@app.route("/api/obf-health")
-def obf_health():
- """Return 200 only when all local wg-obfuscator-* services are active."""
- try:
- listing = subprocess.check_output(
- ["systemctl", "list-units", "--type=service", "--no-legend",
- "wg-obfuscator-*"], text=True, timeout=5)
- names = [ln.split()[0] for ln in listing.splitlines() if ln.strip()]
- except Exception:
- names = []
- if not names:
- env = load_env()
- ports = [p.strip() for p in env.get("OBFUSCATOR_PORTS", "2083,5443,993").split(",") if p.strip()]
- names = [f"wg-obfuscator-{p}.service" for p in ports]
- bad = []
- for name in names:
- status = subprocess.getoutput("systemctl is-active " + name).strip()
- if status != "active":
- bad.append(name + "=" + status)
- if bad:
- return ("obf-down: " + ",".join(bad), 503, {"Content-Type": "text/plain"})
- return ("obf-ok " + str(len(names)), 200, {"Content-Type": "text/plain"})
-
-
-@app.route("/api/peers", methods=["GET"])
-def list_peers():
- if not check_api_key():
- return jsonify({"error": "unauthorized"}), 401
- try:
- out = subprocess.check_output(["wg", "show", "wg0", "allowed-ips"], text=True, timeout=5)
- peers = {}
- for line in out.strip().split("\n"):
- if "\t" in line:
- pub, ips = line.split("\t", 1)
- peers[pub.strip()] = ips.strip()
- return jsonify({"peers": peers})
- except Exception as e:
- return jsonify({"error": str(e)}), 500
-
-
-LIMIT_SCRIPT = "/opt/Phobos/server/phobos-limit.sh"
-
-
-def ensure_script(path):
- """Fetch a helper script from the main panel if this agent predates it."""
- if os.path.exists(path):
- return
- env = load_env()
- url = "%s://%s:%s/server/%s" % (env.get("MAIN_PROTO", "http"), env.get("MAIN_SERVER", ""),
- env.get("MAIN_PORT", ""), os.path.basename(path))
- subprocess.run(["curl", "-kfsSL", "-m", "20", url, "-o", path], timeout=30)
- if os.path.exists(path):
- os.chmod(path, 0o755)
-
-
-@app.route("/api/speedtest", methods=["POST"])
-def speedtest():
- if not check_api_key():
- return jsonify({"error": "unauthorized"}), 401
- path = "/opt/Phobos/server/phobos-speedtest.sh"
- ensure_script(path)
- try:
- r = subprocess.run([path], capture_output=True, text=True, timeout=80)
- return jsonify(json.loads(r.stdout.strip().splitlines()[-1]))
- except Exception as e:
- return jsonify({"error": str(e)}), 500
-
-
-@app.route("/api/limits", methods=["POST"])
-def set_limits():
- """Per-client speed limits pushed by the main panel (" " lines)."""
- if not check_api_key():
- return jsonify({"error": "unauthorized"}), 401
- text = (request.get_json(force=True, silent=True) or {}).get("limits", "")
- Path("/opt/Phobos/server/limits.conf").write_text(text)
- ensure_script(LIMIT_SCRIPT)
- try:
- r = subprocess.run([LIMIT_SCRIPT, "apply"], capture_output=True, text=True, timeout=30)
- return jsonify({"status": "ok" if r.returncode == 0 else "error", "out": (r.stdout + r.stderr)[-500:]})
- except Exception as e:
- return jsonify({"error": str(e)}), 500
-
-@app.route("/api/peers/add", methods=["POST"])
-def add_peer():
- if not check_api_key():
- return jsonify({"error": "unauthorized"}), 401
- data = request.get_json(force=True, silent=True) or {}
- pub_key = data.get("public_key", "")
- allowed_ips = data.get("allowed_ips", "")
- if not pub_key or not allowed_ips:
- return jsonify({"error": "missing public_key or allowed_ips"}), 400
- try:
- subprocess.run(["wg", "set", "wg0", "peer", pub_key, "allowed-ips", allowed_ips], check=True, timeout=5)
- subprocess.run(["wg-quick", "save", "wg0"], timeout=5)
- return jsonify({"status": "ok"})
- except Exception as e:
- return jsonify({"error": str(e)}), 500
-
-@app.route("/api/peers/remove", methods=["POST"])
-def remove_peer():
- if not check_api_key():
- return jsonify({"error": "unauthorized"}), 401
- data = request.get_json(force=True, silent=True) or {}
- pub_key = data.get("public_key", "")
- if not pub_key:
- return jsonify({"error": "missing public_key"}), 400
- try:
- subprocess.run(["wg", "set", "wg0", "peer", pub_key, "remove"], check=True, timeout=5)
- subprocess.run(["wg-quick", "save", "wg0"], timeout=5)
- return jsonify({"status": "ok"})
- except Exception as e:
- return jsonify({"error": str(e)}), 500
-
-@app.route("/api/info")
-def info():
- if not check_api_key():
- return jsonify({"error": "unauthorized"}), 401
- env = load_env()
- return jsonify({
- "ip": env.get("SERVER_PUBLIC_IP_V4"),
- "wg_public_key": env.get("SERVER_WG_PUBLIC_KEY"),
- "obfuscator_key": env.get("OBFUSCATOR_KEY"),
- "ports": env.get("OBFUSCATOR_PORTS", "2083").split(","),
- "role": "secondary"
- })
-
-ROUTER_CONFIGS_DIR = "/opt/Phobos/server/router-configs"
-
-
-@app.route("/api/router-config/")
-def router_config(client_id):
- """Serve a client's failover.conf so routers can PULL via the tunnel
- (http://:8444/...). Token via ?token= or X-API-Key."""
- token = request.args.get("token", "") or request.headers.get("X-API-Key", "")
- if token != load_env().get("MAIN_API_KEY", ""):
- return ("forbidden", 403)
- path = os.path.join(ROUTER_CONFIGS_DIR, client_id + ".conf")
- if not os.path.exists(path):
- return ("not found", 404)
- with open(path) as fh:
- return (fh.read(), 200, {"Content-Type": "text/plain; charset=utf-8"})
-
-
-@app.route("/api/router-config-set", methods=["POST"])
-def router_config_set():
- """Panel fan-out: store a client's failover.conf on this server."""
- if not check_api_key():
- return jsonify({"status": "error", "msg": "unauthorized"}), 403
- data = request.get_json(force=True, silent=True) or {}
- cid = data.get("client_id", "")
- conf = data.get("conf", "")
- if not cid or "SERVER_1=" not in conf:
- return jsonify({"status": "error", "msg": "bad payload"}), 400
- os.makedirs(ROUTER_CONFIGS_DIR, exist_ok=True)
- with open(os.path.join(ROUTER_CONFIGS_DIR, cid + ".conf"), "w") as fh:
- fh.write(conf)
- return jsonify({"status": "ok"})
-
-
-if __name__ == "__main__":
- app.run(host="0.0.0.0", port=8444)
diff --git a/server/data/ru-aggregated.zone b/server/data/ru-aggregated.zone
deleted file mode 100644
index 208d9fa..0000000
--- a/server/data/ru-aggregated.zone
+++ /dev/null
@@ -1,8664 +0,0 @@
-2.56.24.0/22
-2.56.88.0/22
-2.56.180.0/22
-2.56.240.0/23
-2.57.0.0/24
-2.57.36.0/22
-2.57.52.0/22
-2.57.80.0/22
-2.57.112.0/22
-2.57.184.0/22
-2.58.68.0/22
-2.58.98.0/24
-2.58.124.0/22
-2.58.212.0/24
-2.59.51.0/24
-2.59.76.0/22
-2.59.80.0/22
-2.59.160.0/22
-2.59.216.0/22
-2.59.240.0/22
-2.60.0.0/14
-2.92.0.0/14
-5.1.41.0/24
-5.1.48.0/21
-5.2.32.0/19
-5.3.0.0/16
-5.8.0.0/20
-5.8.16.0/21
-5.8.28.0/22
-5.8.36.0/22
-5.8.42.0/23
-5.8.44.0/22
-5.8.48.0/20
-5.8.64.0/22
-5.8.69.0/24
-5.8.72.0/21
-5.8.80.0/21
-5.8.88.0/22
-5.8.160.0/20
-5.8.176.0/21
-5.8.192.0/19
-5.8.224.0/20
-5.11.60.0/22
-5.11.64.0/20
-5.16.0.0/14
-5.23.48.0/21
-5.23.96.0/20
-5.28.16.0/20
-5.32.144.0/21
-5.35.0.0/19
-5.35.40.0/22
-5.35.48.0/20
-5.35.64.0/22
-5.35.72.0/21
-5.35.80.0/20
-5.35.96.0/21
-5.35.112.0/20
-5.35.128.0/19
-5.39.160.0/21
-5.42.0.0/17
-5.42.215.0/24
-5.43.128.0/19
-5.43.240.0/21
-5.44.0.0/20
-5.44.40.0/22
-5.44.45.0/24
-5.44.46.0/23
-5.44.48.0/20
-5.44.168.0/21
-5.45.192.0/18
-5.53.16.0/20
-5.53.120.0/21
-5.56.136.0/21
-5.57.212.0/24
-5.57.216.0/21
-5.57.232.0/21
-5.61.8.0/21
-5.61.16.0/21
-5.61.232.0/21
-5.63.152.0/21
-5.77.0.0/19
-5.79.128.0/17
-5.100.64.0/18
-5.100.244.0/22
-5.101.0.0/19
-5.101.32.0/20
-5.101.48.0/22
-5.101.60.0/22
-5.101.64.0/19
-5.101.128.0/21
-5.101.152.0/21
-5.101.192.0/20
-5.101.208.0/21
-5.101.218.0/24
-5.101.224.0/19
-5.102.152.0/21
-5.104.32.0/19
-5.104.200.0/21
-5.128.0.0/14
-5.133.76.0/22
-5.134.216.0/21
-5.136.0.0/13
-5.144.64.0/20
-5.144.96.0/19
-5.145.160.0/21
-5.145.192.0/18
-5.149.144.0/20
-5.149.200.0/21
-5.149.208.0/20
-5.153.128.0/18
-5.158.96.0/19
-5.158.232.0/21
-5.159.96.0/20
-5.159.112.0/21
-5.164.0.0/14
-5.172.0.0/19
-5.172.178.0/24
-5.175.88.0/21
-5.175.96.0/19
-5.178.24.0/21
-5.178.80.0/21
-5.180.92.0/22
-5.180.101.0/24
-5.180.174.0/23
-5.180.240.0/22
-5.181.0.0/22
-5.181.12.0/24
-5.181.60.0/22
-5.181.108.0/22
-5.181.168.0/22
-5.181.208.0/22
-5.181.252.0/22
-5.182.4.0/22
-5.182.36.0/22
-5.182.52.0/22
-5.182.64.0/22
-5.182.84.0/22
-5.182.92.0/22
-5.182.224.0/22
-5.183.28.0/22
-5.183.64.0/21
-5.183.144.0/22
-5.183.156.0/22
-5.183.180.0/22
-5.183.188.0/22
-5.183.232.0/22
-5.183.252.0/22
-5.187.40.0/21
-5.187.64.0/19
-5.188.2.0/23
-5.188.7.0/24
-5.188.8.0/22
-5.188.24.0/21
-5.188.35.0/24
-5.188.37.0/24
-5.188.38.0/23
-5.188.40.0/21
-5.188.48.0/20
-5.188.68.0/23
-5.188.72.0/21
-5.188.80.0/21
-5.188.88.0/22
-5.188.96.0/21
-5.188.104.0/22
-5.188.112.0/21
-5.188.121.0/24
-5.188.128.0/22
-5.188.136.0/21
-5.188.144.0/22
-5.188.149.0/24
-5.188.150.0/24
-5.188.156.0/22
-5.188.160.0/21
-5.188.170.0/23
-5.188.176.0/22
-5.188.184.0/22
-5.188.192.0/20
-5.188.208.0/22
-5.188.212.0/24
-5.188.216.0/21
-5.188.224.0/24
-5.188.229.0/24
-5.188.232.0/22
-5.188.236.0/23
-5.189.0.0/17
-5.189.192.0/21
-5.189.201.0/24
-5.189.205.0/24
-5.189.208.0/21
-5.189.216.0/22
-5.189.223.0/24
-5.189.224.0/19
-5.199.192.0/19
-5.200.32.0/19
-5.206.0.0/17
-5.226.152.0/21
-5.227.0.0/16
-5.228.0.0/16
-5.249.192.0/19
-5.250.168.0/21
-5.250.232.0/21
-5.252.20.0/22
-5.252.28.0/22
-5.252.64.0/22
-5.252.172.0/22
-5.252.188.0/22
-5.252.192.0/22
-5.253.60.0/23
-5.253.62.0/24
-5.253.100.0/22
-5.253.144.0/22
-5.253.164.0/22
-5.254.176.0/21
-5.254.224.0/19
-5.255.192.0/18
-23.105.224.0/19
-23.111.32.0/19
-23.111.96.0/19
-23.111.192.0/19
-31.3.16.0/20
-31.6.96.0/19
-31.7.224.0/20
-31.8.0.0/16
-31.10.0.0/23
-31.10.2.0/24
-31.10.4.0/24
-31.10.6.0/23
-31.10.8.0/21
-31.10.64.0/18
-31.12.75.0/24
-31.13.16.0/21
-31.13.32.0/19
-31.13.128.0/21
-31.13.144.0/21
-31.13.176.0/21
-31.15.20.0/22
-31.15.80.0/20
-31.22.32.0/21
-31.23.0.0/16
-31.24.24.0/21
-31.24.87.0/24
-31.25.24.0/21
-31.25.200.0/21
-31.25.240.0/21
-31.28.0.0/18
-31.28.96.0/19
-31.28.192.0/18
-31.29.128.0/17
-31.31.64.0/21
-31.31.192.0/20
-31.40.8.0/21
-31.40.32.0/19
-31.40.64.0/19
-31.40.96.0/21
-31.40.112.0/20
-31.40.128.0/18
-31.40.200.0/24
-31.40.208.0/22
-31.40.248.0/23
-31.40.252.0/22
-31.41.0.0/20
-31.41.40.0/21
-31.41.56.0/21
-31.41.96.0/21
-31.41.120.0/21
-31.41.152.0/21
-31.41.160.0/21
-31.41.184.0/21
-31.41.192.0/21
-31.41.224.0/21
-31.41.240.0/21
-31.42.32.0/20
-31.42.96.0/20
-31.42.192.0/18
-31.43.192.0/19
-31.44.8.0/21
-31.44.48.0/20
-31.44.80.0/20
-31.44.176.0/20
-31.44.240.0/20
-31.47.112.0/20
-31.47.128.0/18
-31.128.32.0/20
-31.128.48.0/21
-31.128.56.0/22
-31.128.61.0/24
-31.128.62.0/23
-31.128.128.0/19
-31.128.192.0/19
-31.129.0.0/18
-31.129.96.0/20
-31.129.122.0/23
-31.129.124.0/24
-31.129.126.0/23
-31.129.128.0/19
-31.129.192.0/19
-31.130.0.0/18
-31.130.64.0/19
-31.130.112.0/20
-31.130.128.0/19
-31.130.192.0/21
-31.130.248.0/21
-31.131.64.0/20
-31.131.80.0/21
-31.131.92.0/22
-31.131.140.0/22
-31.131.144.0/20
-31.131.184.0/22
-31.131.190.0/23
-31.131.192.0/19
-31.131.248.0/21
-31.132.32.0/22
-31.132.96.0/19
-31.132.128.0/18
-31.132.208.0/20
-31.132.224.0/19
-31.133.32.0/19
-31.133.64.0/20
-31.133.104.0/21
-31.133.120.0/21
-31.133.200.0/21
-31.133.224.0/19
-31.134.16.0/20
-31.134.32.0/20
-31.134.128.0/18
-31.134.192.0/21
-31.134.224.0/19
-31.135.8.0/21
-31.135.32.0/19
-31.135.64.0/18
-31.135.184.0/21
-31.135.224.0/19
-31.162.0.0/15
-31.170.32.0/21
-31.170.112.0/21
-31.170.168.0/21
-31.170.184.0/21
-31.171.192.0/21
-31.172.128.0/21
-31.172.192.0/19
-31.173.0.0/16
-31.177.64.0/19
-31.177.104.0/21
-31.180.0.0/15
-31.184.192.0/21
-31.184.200.0/22
-31.184.204.0/23
-31.184.208.0/20
-31.184.224.0/20
-31.184.240.0/22
-31.184.248.0/21
-31.185.8.0/21
-31.186.56.0/21
-31.186.64.0/20
-31.186.96.0/21
-31.186.128.0/19
-31.187.96.0/21
-31.192.104.0/21
-31.192.128.0/18
-31.192.232.0/21
-31.193.120.0/21
-31.200.192.0/20
-31.200.216.0/21
-31.200.224.0/20
-31.200.248.0/21
-31.204.0.0/18
-31.204.96.0/20
-31.204.160.0/19
-31.207.64.0/20
-31.207.128.0/17
-31.210.136.0/24
-31.210.138.0/23
-31.210.168.0/24
-31.210.192.0/19
-31.211.0.0/17
-31.216.160.0/20
-31.216.176.0/21
-31.217.253.0/24
-31.217.255.0/24
-31.220.152.0/21
-31.220.160.0/19
-31.222.32.0/21
-31.222.227.0/24
-31.222.241.0/24
-37.0.120.0/21
-37.1.0.0/18
-37.1.64.0/20
-37.1.80.0/21
-37.1.128.0/20
-37.8.144.0/20
-37.9.0.0/20
-37.9.36.0/22
-37.9.40.0/21
-37.9.48.0/21
-37.9.64.0/18
-37.9.128.0/21
-37.9.144.0/20
-37.9.240.0/21
-37.16.73.0/24
-37.16.80.0/21
-37.16.90.0/24
-37.18.2.0/23
-37.18.8.0/23
-37.18.10.0/24
-37.18.22.0/24
-37.18.27.0/24
-37.18.28.0/22
-37.18.32.0/23
-37.18.34.0/24
-37.18.72.0/22
-37.18.76.0/23
-37.18.83.0/24
-37.18.84.0/24
-37.18.88.0/22
-37.18.100.0/23
-37.18.102.0/24
-37.18.107.0/24
-37.18.108.0/22
-37.18.112.0/21
-37.18.120.0/23
-37.18.122.0/24
-37.18.152.0/21
-37.18.248.0/21
-37.19.0.0/21
-37.19.32.0/19
-37.19.72.0/21
-37.20.0.0/14
-37.26.232.0/21
-37.28.160.0/19
-37.29.0.0/17
-37.32.101.0/24
-37.44.40.0/21
-37.44.192.0/22
-37.44.196.0/23
-37.44.198.0/24
-37.44.252.0/22
-37.46.52.0/22
-37.46.56.0/21
-37.46.128.0/21
-37.48.248.0/21
-37.49.160.0/19
-37.49.192.0/19
-37.58.32.0/21
-37.60.16.0/21
-37.60.176.0/21
-37.60.208.0/20
-37.61.176.0/21
-37.72.64.0/19
-37.72.140.0/24
-37.72.176.0/21
-37.75.0.0/21
-37.75.192.0/20
-37.75.216.0/21
-37.75.248.0/21
-37.76.128.0/18
-37.77.104.0/21
-37.77.129.0/24
-37.77.130.0/23
-37.77.132.0/22
-37.77.150.0/24
-37.78.0.0/15
-37.98.160.0/19
-37.98.240.0/20
-37.99.216.0/21
-37.110.0.0/17
-37.110.128.0/19
-37.110.224.0/20
-37.110.240.0/21
-37.112.0.0/15
-37.114.0.0/21
-37.114.16.0/20
-37.122.0.0/17
-37.123.216.0/21
-37.128.164.0/22
-37.128.240.0/20
-37.130.192.0/21
-37.131.192.0/19
-37.139.32.0/19
-37.139.80.0/21
-37.139.96.0/20
-37.139.192.0/18
-37.140.0.0/17
-37.140.128.0/18
-37.140.192.0/21
-37.140.241.0/24
-37.140.248.0/24
-37.143.8.0/21
-37.143.16.0/20
-37.143.96.0/20
-37.144.0.0/14
-37.153.0.0/18
-37.153.64.0/21
-37.157.16.0/20
-37.157.232.0/21
-37.188.0.0/18
-37.190.0.0/17
-37.192.0.0/14
-37.200.64.0/20
-37.200.88.0/21
-37.200.120.0/21
-37.202.8.0/21
-37.203.200.0/21
-37.203.240.0/21
-37.204.0.0/16
-37.205.16.0/21
-37.205.48.0/21
-37.205.64.0/19
-37.208.64.0/20
-37.208.96.0/21
-37.208.120.0/21
-37.209.224.0/20
-37.209.240.0/21
-37.220.80.0/21
-37.220.152.0/21
-37.220.160.0/21
-37.220.176.0/20
-37.221.64.0/22
-37.221.184.0/21
-37.221.200.0/23
-37.221.203.0/24
-37.221.204.0/23
-37.221.206.0/24
-37.228.80.0/20
-37.228.112.0/21
-37.230.112.0/21
-37.230.139.0/24
-37.230.152.0/22
-37.230.168.0/23
-37.230.172.0/22
-37.230.179.0/24
-37.230.180.0/23
-37.230.184.0/23
-37.230.186.0/24
-37.230.188.0/22
-37.230.192.0/21
-37.230.201.0/24
-37.230.212.0/23
-37.230.224.0/24
-37.230.233.0/24
-37.230.248.0/24
-37.232.128.0/17
-37.233.80.0/21
-37.233.112.0/21
-37.235.64.0/21
-37.252.16.0/21
-45.8.96.0/22
-45.8.107.0/24
-45.8.108.0/22
-45.8.124.0/22
-45.8.144.0/22
-45.8.248.0/22
-45.9.24.0/22
-45.9.40.0/22
-45.9.88.0/22
-45.9.140.0/22
-45.9.164.0/22
-45.9.192.0/22
-45.9.212.0/22
-45.9.216.0/22
-45.10.40.0/22
-45.10.52.0/22
-45.10.140.0/22
-45.10.164.0/22
-45.10.216.0/22
-45.10.240.0/21
-45.11.4.0/22
-45.11.92.0/22
-45.11.112.0/22
-45.12.4.0/22
-45.12.16.0/22
-45.12.64.0/22
-45.12.72.0/22
-45.12.124.0/22
-45.12.228.0/22
-45.12.236.0/22
-45.14.20.0/22
-45.14.223.0/24
-45.15.64.0/22
-45.15.112.0/22
-45.15.156.0/22
-45.15.252.0/23
-45.15.254.0/24
-45.66.12.0/22
-45.66.116.0/22
-45.66.168.0/22
-45.66.208.0/22
-45.66.250.0/23
-45.67.24.0/22
-45.67.32.0/22
-45.67.56.0/22
-45.67.192.0/22
-45.67.212.0/23
-45.80.44.0/22
-45.80.64.0/21
-45.80.128.0/22
-45.80.204.0/22
-45.80.216.0/22
-45.80.228.0/22
-45.80.240.0/22
-45.81.164.0/22
-45.81.200.0/22
-45.81.253.0/24
-45.81.255.0/24
-45.82.12.0/22
-45.82.216.0/22
-45.82.224.0/22
-45.83.16.0/22
-45.83.92.0/22
-45.83.180.0/22
-45.84.0.0/22
-45.84.12.0/22
-45.84.60.0/22
-45.84.68.0/22
-45.84.84.0/22
-45.84.128.0/22
-45.84.152.0/22
-45.84.224.0/22
-45.85.24.0/22
-45.85.68.0/22
-45.85.140.0/22
-45.85.212.0/22
-45.86.38.0/23
-45.86.86.0/24
-45.86.180.0/22
-45.87.104.0/22
-45.87.140.0/22
-45.87.144.0/22
-45.87.152.0/22
-45.87.244.0/22
-45.88.52.0/22
-45.88.100.0/22
-45.88.252.0/22
-45.89.16.0/22
-45.89.22.0/24
-45.89.24.0/22
-45.89.52.0/22
-45.89.188.0/22
-45.89.224.0/22
-45.90.32.0/22
-45.90.45.0/24
-45.90.244.0/22
-45.91.64.0/22
-45.91.240.0/22
-45.92.174.0/24
-45.92.176.0/22
-45.93.4.0/22
-45.93.8.0/22
-45.93.13.0/24
-45.93.60.0/22
-45.93.81.0/24
-45.93.132.0/22
-45.93.156.0/22
-45.93.203.0/24
-45.93.212.0/22
-45.94.23.0/24
-45.94.76.0/22
-45.94.104.0/22
-45.94.116.0/22
-45.94.120.0/22
-45.94.140.0/22
-45.95.56.0/22
-45.95.128.0/22
-45.95.136.0/22
-45.95.232.0/22
-45.128.184.0/22
-45.128.204.0/24
-45.128.206.0/23
-45.129.76.0/23
-45.129.142.0/23
-45.129.152.0/22
-45.129.184.0/23
-45.129.187.0/24
-45.129.200.0/22
-45.130.8.0/22
-45.130.40.0/22
-45.130.145.0/24
-45.130.168.0/21
-45.130.188.0/22
-45.130.212.0/22
-45.131.40.0/22
-45.131.56.0/22
-45.131.96.0/22
-45.132.1.0/24
-45.132.176.0/22
-45.132.184.0/22
-45.133.96.0/22
-45.133.148.0/22
-45.133.234.0/24
-45.133.243.0/24
-45.134.60.0/22
-45.134.64.0/22
-45.134.124.0/22
-45.134.156.0/22
-45.134.180.0/22
-45.135.80.0/22
-45.135.92.0/22
-45.135.212.0/22
-45.136.20.0/22
-45.136.146.0/23
-45.136.180.0/22
-45.136.208.0/22
-45.137.112.0/22
-45.137.188.0/24
-45.137.252.0/22
-45.138.100.0/22
-45.138.160.0/22
-45.139.16.0/22
-45.139.24.0/22
-45.139.29.0/24
-45.139.40.0/22
-45.139.76.0/22
-45.139.144.0/22
-45.139.152.0/22
-45.139.184.0/22
-45.139.236.0/22
-45.140.52.0/22
-45.140.76.0/22
-45.140.80.0/22
-45.140.92.0/22
-45.140.176.0/22
-45.141.76.0/22
-45.141.84.0/22
-45.141.208.0/22
-45.141.219.0/24
-45.142.32.0/22
-45.142.208.0/22
-45.143.20.0/22
-45.143.84.0/22
-45.143.136.0/22
-45.143.152.0/22
-45.143.164.0/23
-45.143.200.0/22
-45.143.236.0/22
-45.144.1.0/24
-45.144.40.0/21
-45.144.176.0/22
-45.144.220.0/22
-45.145.4.0/22
-45.145.64.0/22
-45.145.116.0/22
-45.145.163.0/24
-45.145.168.0/24
-45.145.188.0/22
-45.146.64.0/22
-45.146.152.0/22
-45.146.164.0/22
-45.147.80.0/22
-45.147.120.0/22
-45.147.144.0/21
-45.147.162.0/23
-45.147.176.0/22
-45.147.195.0/24
-45.148.124.0/22
-45.148.164.0/24
-45.148.167.0/24
-45.148.244.0/22
-45.149.40.0/22
-45.149.244.0/22
-45.150.8.0/22
-45.150.36.0/22
-45.150.110.0/23
-45.150.148.0/24
-45.150.188.0/22
-45.150.204.0/22
-45.151.30.0/23
-45.151.60.0/22
-45.151.96.0/22
-45.151.108.0/22
-45.151.136.0/22
-45.151.228.0/22
-45.151.232.0/22
-45.152.24.0/22
-45.152.84.0/22
-45.152.112.0/22
-45.152.120.0/22
-45.152.168.0/22
-45.152.220.0/22
-45.153.12.0/22
-45.153.28.0/22
-45.153.44.0/22
-45.153.72.0/22
-45.153.188.0/22
-45.153.196.0/22
-45.154.0.0/22
-45.154.184.0/22
-45.155.6.0/24
-45.155.60.0/24
-45.155.92.0/22
-45.155.104.0/22
-45.155.144.0/22
-45.155.204.0/23
-45.155.236.0/22
-45.156.0.0/22
-45.156.20.0/22
-45.156.24.0/22
-45.156.212.0/22
-45.157.140.0/22
-45.157.160.0/22
-45.157.212.0/22
-45.158.188.0/22
-45.158.232.0/22
-45.159.0.0/22
-45.159.16.0/22
-45.159.104.0/22
-45.159.124.0/22
-45.159.136.0/22
-45.159.200.0/22
-45.159.208.0/22
-45.159.248.0/22
-46.0.0.0/16
-46.16.8.0/21
-46.16.24.0/21
-46.16.34.0/24
-46.16.36.0/24
-46.16.64.0/21
-46.16.96.0/21
-46.16.176.0/21
-46.16.224.0/21
-46.17.40.0/21
-46.17.48.0/21
-46.17.200.0/21
-46.18.200.0/21
-46.19.64.0/21
-46.19.112.0/21
-46.20.64.0/20
-46.20.176.0/20
-46.21.64.0/20
-46.21.80.0/22
-46.21.244.0/22
-46.21.248.0/23
-46.21.252.0/22
-46.22.48.0/20
-46.22.240.0/20
-46.23.144.0/20
-46.23.176.0/20
-46.28.16.0/21
-46.28.88.0/21
-46.28.128.0/21
-46.28.224.0/21
-46.29.8.0/21
-46.29.37.0/24
-46.29.38.0/24
-46.29.72.0/21
-46.29.112.0/21
-46.29.152.0/21
-46.29.160.0/21
-46.29.192.0/21
-46.29.208.0/21
-46.29.232.0/21
-46.30.32.0/20
-46.30.152.0/21
-46.31.0.0/21
-46.31.24.0/21
-46.31.67.0/24
-46.31.152.0/21
-46.32.64.0/19
-46.34.128.0/23
-46.34.132.0/22
-46.34.136.0/21
-46.34.144.0/23
-46.34.148.0/22
-46.34.152.0/21
-46.35.224.0/19
-46.36.0.0/19
-46.37.128.0/19
-46.38.0.0/18
-46.38.96.0/19
-46.39.0.0/18
-46.39.224.0/19
-46.41.64.0/18
-46.42.0.0/18
-46.42.128.0/18
-46.43.192.0/18
-46.44.0.0/18
-46.45.0.0/18
-46.45.192.0/18
-46.46.0.0/18
-46.46.128.0/18
-46.47.0.0/18
-46.47.192.0/18
-46.48.0.0/16
-46.50.128.0/17
-46.52.128.0/17
-46.61.0.0/16
-46.62.0.0/17
-46.63.128.0/17
-46.72.0.0/15
-46.102.191.0/24
-46.111.0.0/16
-46.138.0.0/16
-46.146.0.0/15
-46.148.48.0/20
-46.148.96.0/20
-46.148.128.0/20
-46.148.176.0/20
-46.148.192.0/18
-46.149.32.0/20
-46.149.64.0/23
-46.149.99.0/24
-46.149.101.0/24
-46.149.110.0/24
-46.149.128.0/20
-46.149.164.0/22
-46.149.175.0/24
-46.149.224.0/20
-46.150.128.0/18
-46.150.224.0/20
-46.151.0.0/20
-46.151.40.0/21
-46.151.48.0/21
-46.151.64.0/21
-46.151.88.0/21
-46.151.104.0/21
-46.151.144.0/20
-46.151.168.0/21
-46.151.240.0/21
-46.158.0.0/15
-46.160.0.0/18
-46.160.128.0/17
-46.161.0.0/18
-46.161.128.0/18
-46.162.0.0/18
-46.163.128.0/18
-46.164.192.0/18
-46.165.0.0/18
-46.166.64.0/18
-46.166.192.0/18
-46.167.64.0/18
-46.172.0.0/18
-46.172.96.0/19
-46.172.160.0/19
-46.172.192.0/19
-46.173.0.0/20
-46.173.16.0/21
-46.173.24.0/22
-46.173.28.0/23
-46.173.32.0/19
-46.173.176.0/20
-46.173.208.0/20
-46.174.8.0/21
-46.174.40.0/21
-46.174.48.0/21
-46.174.80.0/21
-46.174.104.0/21
-46.174.112.0/21
-46.174.248.0/21
-46.175.12.0/24
-46.175.24.0/21
-46.175.32.0/21
-46.175.96.0/21
-46.175.120.0/21
-46.175.192.0/19
-46.180.0.0/15
-46.182.24.0/21
-46.182.128.0/21
-46.183.0.0/21
-46.183.80.0/21
-46.183.128.0/21
-46.183.160.0/21
-46.183.176.0/21
-46.187.0.0/17
-46.188.0.0/17
-46.191.128.0/17
-46.226.64.0/21
-46.226.96.0/21
-46.226.122.0/24
-46.226.224.0/21
-46.226.240.0/21
-46.227.24.0/21
-46.227.160.0/22
-46.227.164.0/24
-46.227.166.0/23
-46.227.208.0/21
-46.228.0.0/20
-46.228.64.0/20
-46.228.96.0/19
-46.229.64.0/20
-46.229.96.0/20
-46.229.128.0/20
-46.229.176.0/20
-46.229.208.0/20
-46.231.168.0/21
-46.231.208.0/21
-46.232.160.0/21
-46.232.200.0/21
-46.232.216.0/21
-46.232.240.0/21
-46.233.192.0/18
-46.235.48.0/21
-46.235.64.0/21
-46.235.78.0/23
-46.235.160.0/21
-46.235.184.0/21
-46.235.216.0/21
-46.235.248.0/21
-46.236.128.0/18
-46.237.0.0/18
-46.241.0.0/17
-46.242.0.0/17
-46.243.8.0/21
-46.243.60.0/22
-46.243.141.0/24
-46.243.142.0/23
-46.243.172.0/24
-46.243.180.0/22
-46.243.184.0/22
-46.243.201.0/24
-46.243.205.0/24
-46.243.206.0/24
-46.243.209.0/24
-46.243.210.0/23
-46.243.212.0/24
-46.243.218.0/23
-46.243.226.0/23
-46.243.244.0/23
-46.243.254.0/24
-46.245.128.0/21
-46.245.168.0/21
-46.245.234.0/24
-46.249.0.0/19
-46.250.32.0/19
-46.250.64.0/19
-46.250.128.0/19
-46.251.64.0/19
-46.252.112.0/20
-46.252.160.0/20
-46.252.240.0/20
-46.253.132.0/24
-46.253.143.0/24
-46.254.16.0/20
-46.254.80.0/21
-46.254.92.0/22
-46.254.160.0/21
-46.254.216.0/21
-46.254.240.0/21
-46.255.25.0/24
-46.255.96.0/21
-46.255.136.0/21
-51.250.0.0/16
-62.3.34.0/24
-62.3.63.0/24
-62.5.128.0/17
-62.16.32.0/19
-62.16.96.0/19
-62.32.64.0/21
-62.32.72.0/22
-62.32.76.0/23
-62.32.79.0/24
-62.32.80.0/22
-62.32.86.0/23
-62.32.88.0/22
-62.32.94.0/23
-62.33.0.0/16
-62.61.0.0/19
-62.63.64.0/18
-62.64.0.0/19
-62.68.128.0/19
-62.69.0.0/19
-62.76.0.0/17
-62.76.128.0/18
-62.76.192.0/19
-62.76.240.0/20
-62.78.32.0/19
-62.78.80.0/20
-62.84.104.0/21
-62.84.112.0/20
-62.89.192.0/18
-62.105.0.0/18
-62.105.128.0/19
-62.106.76.0/24
-62.106.96.0/19
-62.109.0.0/19
-62.109.160.0/19
-62.112.96.0/19
-62.113.32.0/19
-62.113.64.0/18
-62.117.64.0/18
-62.118.0.0/16
-62.122.48.0/21
-62.122.88.0/21
-62.122.96.0/21
-62.122.128.0/21
-62.122.144.0/21
-62.122.176.0/21
-62.122.192.0/21
-62.122.208.0/21
-62.122.240.0/21
-62.133.60.0/22
-62.133.160.0/19
-62.140.224.0/19
-62.141.64.0/18
-62.148.0.0/19
-62.148.128.0/19
-62.148.224.0/19
-62.152.32.0/19
-62.152.64.0/19
-62.152.192.0/19
-62.165.0.0/18
-62.168.224.0/19
-62.173.128.0/19
-62.176.0.0/19
-62.177.32.0/19
-62.181.32.0/19
-62.182.8.0/21
-62.182.24.0/21
-62.182.48.0/21
-62.182.64.0/20
-62.182.88.0/21
-62.182.128.0/20
-62.182.156.0/22
-62.182.200.0/21
-62.183.0.0/17
-62.192.32.0/19
-62.192.224.0/19
-62.204.32.0/24
-62.204.57.0/24
-62.205.160.0/19
-62.213.0.0/17
-62.217.160.0/19
-62.220.32.0/19
-62.231.0.0/19
-62.231.160.0/19
-62.233.39.0/24
-62.233.42.0/23
-62.245.32.0/19
-62.249.128.0/19
-77.34.0.0/15
-77.37.128.0/17
-77.39.0.0/17
-77.40.0.0/17
-77.41.0.0/16
-77.43.128.0/17
-77.45.128.0/17
-77.50.0.0/15
-77.66.128.0/17
-77.72.120.0/21
-77.72.136.0/21
-77.72.240.0/20
-77.73.24.0/21
-77.73.48.0/21
-77.73.88.0/21
-77.73.136.0/21
-77.73.232.0/21
-77.74.8.0/21
-77.74.24.0/21
-77.74.72.0/21
-77.74.184.0/21
-77.75.0.0/20
-77.75.128.0/21
-77.75.152.0/21
-77.75.168.0/21
-77.79.128.0/18
-77.81.5.0/24
-77.82.0.0/16
-77.83.0.0/24
-77.83.8.0/22
-77.83.16.0/22
-77.83.52.0/22
-77.83.72.0/24
-77.83.116.0/22
-77.83.152.0/22
-77.83.244.0/22
-77.87.64.0/21
-77.87.80.0/21
-77.87.96.0/21
-77.87.112.0/21
-77.87.124.0/24
-77.87.168.0/21
-77.87.200.0/21
-77.87.208.0/21
-77.88.0.0/18
-77.91.64.0/21
-77.91.72.0/22
-77.91.78.0/23
-77.91.84.0/22
-77.91.88.0/21
-77.91.192.0/21
-77.91.208.0/24
-77.91.224.0/21
-77.93.96.0/19
-77.94.32.0/20
-77.94.48.0/21
-77.94.96.0/19
-77.94.160.0/19
-77.94.192.0/19
-77.95.8.0/21
-77.95.20.0/22
-77.95.88.0/21
-77.95.128.0/21
-77.95.169.0/24
-77.95.170.0/24
-77.95.200.0/21
-77.105.145.0/24
-77.105.146.0/23
-77.105.148.0/22
-77.105.152.0/21
-77.105.165.0/24
-77.105.166.0/23
-77.105.168.0/21
-77.105.176.0/20
-77.106.0.0/17
-77.106.192.0/18
-77.108.64.0/18
-77.108.192.0/18
-77.120.56.0/22
-77.121.14.0/24
-77.121.32.0/19
-77.123.192.0/18
-77.220.32.0/19
-77.220.128.0/18
-77.220.192.0/22
-77.220.208.0/22
-77.220.216.0/21
-77.221.128.0/22
-77.221.192.0/19
-77.222.32.0/19
-77.222.96.0/19
-77.223.64.0/18
-77.232.0.0/18
-77.232.128.0/19
-77.232.160.0/21
-77.232.184.0/21
-77.233.0.0/19
-77.233.160.0/19
-77.233.192.0/19
-77.234.0.0/19
-77.234.192.0/19
-77.235.192.0/19
-77.236.32.0/19
-77.236.64.0/19
-77.236.224.0/19
-77.238.96.0/21
-77.238.128.0/19
-77.239.192.0/19
-77.240.144.0/20
-77.240.160.0/20
-77.241.16.0/20
-77.241.32.0/20
-77.241.144.0/20
-77.241.240.0/20
-77.242.0.0/20
-77.242.96.0/20
-77.243.0.0/20
-77.243.96.0/19
-77.243.240.0/20
-77.244.16.0/20
-77.244.64.0/20
-77.244.160.0/20
-77.244.208.0/20
-77.245.112.0/20
-77.245.160.0/20
-77.245.192.0/19
-77.246.144.0/21
-77.246.156.0/22
-77.246.224.0/20
-77.246.248.0/21
-77.247.128.0/20
-77.247.160.0/20
-77.247.184.0/21
-77.247.208.0/21
-77.247.232.0/21
-77.247.240.0/21
-78.24.0.0/21
-78.24.24.0/21
-78.24.40.0/21
-78.24.56.0/21
-78.24.92.0/22
-78.24.100.0/22
-78.24.152.0/21
-78.24.176.0/21
-78.24.204.0/24
-78.24.216.0/21
-78.24.224.0/21
-78.25.64.0/18
-78.25.128.0/18
-78.29.0.0/17
-78.30.192.0/18
-78.31.0.0/21
-78.31.16.0/21
-78.31.72.0/21
-78.31.96.0/21
-78.31.160.0/23
-78.31.177.0/24
-78.31.178.0/23
-78.31.180.0/22
-78.31.210.0/24
-78.31.216.0/21
-78.31.240.0/21
-78.36.0.0/15
-78.40.24.0/21
-78.40.80.0/21
-78.40.116.0/22
-78.40.184.0/21
-78.40.216.0/21
-78.41.32.0/21
-78.41.84.0/22
-78.41.88.0/21
-78.41.96.0/20
-78.41.142.0/24
-78.41.176.0/21
-78.41.192.0/21
-78.81.0.0/16
-78.85.0.0/16
-78.106.0.0/15
-78.108.64.0/19
-78.108.192.0/20
-78.109.32.0/20
-78.109.112.0/20
-78.109.128.0/20
-78.110.48.0/20
-78.110.144.0/20
-78.110.240.0/20
-78.111.80.0/22
-78.111.92.0/22
-78.111.144.0/20
-78.111.240.0/20
-78.132.128.0/17
-78.136.192.0/19
-78.136.224.0/20
-78.136.240.0/21
-78.136.248.0/22
-78.136.252.0/23
-78.137.104.0/21
-78.138.128.0/18
-78.139.64.0/18
-78.139.192.0/18
-78.140.0.0/18
-78.140.192.0/19
-78.140.224.0/20
-78.140.240.0/21
-78.140.248.0/22
-78.142.220.0/22
-78.142.232.0/22
-78.153.0.0/19
-78.153.128.0/19
-78.155.160.0/19
-78.155.192.0/19
-78.156.224.0/19
-78.157.224.0/19
-78.158.192.0/19
-78.159.224.0/19
-79.98.8.0/21
-79.98.88.0/21
-79.98.136.0/21
-79.98.184.0/22
-79.98.200.0/21
-79.98.208.0/21
-79.98.248.0/21
-79.99.16.0/21
-79.99.48.0/21
-79.99.104.0/21
-79.99.216.0/21
-79.99.240.0/21
-79.104.0.0/15
-79.110.188.0/22
-79.110.226.0/24
-79.110.240.0/20
-79.111.0.0/16
-79.120.0.0/17
-79.122.128.0/17
-79.126.0.0/17
-79.132.96.0/19
-79.133.64.0/19
-79.133.127.0/24
-79.133.128.0/19
-79.133.160.0/21
-79.133.172.0/22
-79.133.176.0/23
-79.133.181.0/24
-79.133.182.0/23
-79.134.0.0/19
-79.134.64.0/19
-79.134.192.0/19
-79.135.64.0/19
-79.135.224.0/19
-79.136.128.0/17
-79.137.128.0/19
-79.137.160.0/21
-79.137.168.0/23
-79.137.172.0/22
-79.137.180.0/22
-79.137.184.0/21
-79.137.192.0/18
-79.139.128.0/17
-79.140.16.0/20
-79.140.64.0/20
-79.140.96.0/20
-79.140.240.0/20
-79.141.48.0/20
-79.141.64.0/20
-79.141.208.0/20
-79.142.16.0/20
-79.142.80.0/21
-79.142.88.0/22
-79.142.92.0/24
-79.142.96.0/20
-79.142.160.0/20
-79.143.0.0/20
-79.143.24.0/21
-79.143.64.0/20
-79.143.224.0/20
-79.164.0.0/15
-79.170.24.0/21
-79.170.136.0/21
-79.170.152.0/21
-79.170.160.0/21
-79.171.8.0/21
-79.171.112.0/22
-79.171.116.0/24
-79.171.152.0/24
-79.171.168.0/21
-79.171.208.0/21
-79.172.0.0/17
-79.173.64.0/18
-79.174.12.0/22
-79.174.32.0/19
-79.174.64.0/19
-79.174.184.0/21
-79.175.0.0/18
-80.64.96.0/20
-80.64.160.0/20
-80.65.16.0/20
-80.66.64.0/19
-80.66.144.0/20
-80.67.40.0/22
-80.67.48.0/20
-80.67.208.0/20
-80.67.240.0/20
-80.68.0.0/20
-80.68.64.0/20
-80.68.240.0/20
-80.69.144.0/20
-80.69.176.0/20
-80.70.96.0/20
-80.70.224.0/20
-80.71.154.0/24
-80.71.156.0/24
-80.71.160.0/19
-80.71.208.0/20
-80.71.240.0/20
-80.72.28.0/22
-80.72.112.0/20
-80.72.208.0/20
-80.72.224.0/20
-80.73.16.0/20
-80.73.64.0/19
-80.73.160.0/20
-80.73.192.0/20
-80.75.80.0/20
-80.75.128.0/20
-80.75.223.0/24
-80.76.40.0/22
-80.76.96.0/20
-80.76.128.0/20
-80.76.176.0/20
-80.76.224.0/19
-80.77.160.0/20
-80.78.96.0/19
-80.78.192.0/20
-80.78.240.0/20
-80.79.64.0/20
-80.79.176.0/20
-80.79.240.0/20
-80.80.96.0/19
-80.80.192.0/20
-80.81.208.0/20
-80.82.32.0/19
-80.82.80.0/20
-80.82.160.0/19
-80.83.192.0/20
-80.83.224.0/19
-80.84.112.0/20
-80.85.144.0/20
-80.85.176.0/20
-80.85.240.0/22
-80.85.248.0/21
-80.87.96.0/20
-80.87.144.0/20
-80.87.192.0/20
-80.88.48.0/20
-80.89.0.0/20
-80.89.128.0/19
-80.89.192.0/20
-80.90.64.0/20
-80.90.112.0/20
-80.90.176.0/20
-80.90.240.0/20
-80.91.16.0/20
-80.91.192.0/20
-80.92.0.0/19
-80.92.32.0/20
-80.92.96.0/20
-80.92.160.0/20
-80.92.207.0/24
-80.92.208.0/20
-80.93.48.0/20
-80.93.96.0/20
-80.93.176.0/20
-80.94.84.0/22
-80.95.32.0/20
-80.115.192.0/19
-80.234.0.0/17
-80.237.0.0/17
-80.240.32.0/19
-80.240.100.0/24
-80.240.102.0/24
-80.240.110.0/24
-80.240.208.0/20
-80.240.240.0/20
-80.242.48.0/22
-80.242.64.0/19
-80.242.96.0/20
-80.243.0.0/20
-80.243.64.0/20
-80.244.0.0/24
-80.244.5.0/24
-80.244.32.0/20
-80.244.224.0/20
-80.245.112.0/20
-80.245.240.0/20
-80.246.16.0/21
-80.246.24.0/22
-80.246.64.0/19
-80.246.208.0/20
-80.246.240.0/20
-80.247.32.0/20
-80.247.96.0/19
-80.247.176.0/20
-80.248.48.0/20
-80.248.80.0/20
-80.248.144.0/20
-80.249.129.0/24
-80.249.131.0/24
-80.249.135.0/24
-80.249.136.0/24
-80.249.144.0/21
-80.249.176.0/20
-80.249.192.0/20
-80.250.64.0/19
-80.250.160.0/19
-80.250.208.0/20
-80.250.224.0/20
-80.251.48.0/20
-80.251.112.0/20
-80.251.128.0/20
-80.251.144.0/21
-80.251.154.0/23
-80.251.156.0/22
-80.251.224.0/20
-80.252.16.0/20
-80.252.128.0/19
-80.253.0.0/19
-80.253.224.0/20
-80.254.16.0/20
-80.254.48.0/20
-80.254.96.0/19
-80.255.16.0/20
-80.255.80.0/20
-80.255.128.0/19
-80.255.176.0/20
-81.1.128.0/17
-81.2.0.0/18
-81.3.128.0/18
-81.4.192.0/18
-81.5.64.0/18
-81.9.0.0/17
-81.13.0.0/17
-81.16.80.0/20
-81.16.208.0/22
-81.17.0.0/20
-81.17.144.0/20
-81.18.112.0/20
-81.18.128.0/19
-81.19.64.0/19
-81.19.128.0/20
-81.20.96.0/20
-81.20.160.0/20
-81.20.192.0/20
-81.22.0.0/20
-81.22.46.0/23
-81.22.48.0/20
-81.22.192.0/22
-81.22.200.0/21
-81.22.208.0/21
-81.23.0.0/20
-81.23.96.0/19
-81.23.144.0/20
-81.23.160.0/19
-81.23.192.0/20
-81.24.80.0/20
-81.24.112.0/20
-81.24.128.0/20
-81.24.176.0/20
-81.25.0.0/20
-81.25.48.0/20
-81.25.64.0/22
-81.26.80.0/20
-81.26.128.0/20
-81.26.144.0/21
-81.26.152.0/22
-81.26.157.0/24
-81.26.176.0/20
-81.27.48.0/20
-81.27.144.0/20
-81.27.240.0/20
-81.28.0.0/22
-81.28.160.0/19
-81.28.208.0/20
-81.28.244.0/22
-81.29.112.0/20
-81.29.128.0/20
-81.30.48.0/20
-81.30.112.0/20
-81.30.176.0/20
-81.30.192.0/19
-81.88.80.0/20
-81.88.112.0/20
-81.88.208.0/20
-81.89.64.0/20
-81.89.80.0/21
-81.89.112.0/20
-81.89.176.0/20
-81.90.0.0/20
-81.90.180.0/22
-81.90.208.0/20
-81.91.32.0/19
-81.91.189.0/24
-81.94.16.0/20
-81.94.32.0/20
-81.94.128.0/19
-81.95.16.0/20
-81.95.32.0/20
-81.95.128.0/20
-81.95.208.0/20
-81.161.16.0/20
-81.161.32.0/20
-81.161.63.0/24
-81.161.98.0/23
-81.161.114.0/24
-81.161.116.0/22
-81.161.120.0/21
-81.161.208.0/20
-81.162.0.0/19
-81.162.32.0/20
-81.162.48.0/22
-81.162.52.0/23
-81.162.56.0/21
-81.162.96.0/19
-81.163.16.0/20
-81.163.32.0/19
-81.163.64.0/21
-81.163.80.0/20
-81.163.96.0/20
-81.163.128.0/18
-81.163.224.0/19
-81.176.0.0/15
-81.195.0.0/16
-81.200.0.0/19
-81.200.80.0/20
-81.200.112.0/20
-81.200.144.0/20
-81.200.208.0/20
-81.200.240.0/20
-81.201.16.0/20
-81.201.64.0/20
-81.201.240.0/20
-81.211.0.0/17
-81.222.0.0/16
-82.96.192.0/18
-82.97.194.0/23
-82.97.198.0/24
-82.97.201.0/24
-82.97.202.0/24
-82.97.207.0/24
-82.112.0.0/18
-82.112.176.0/20
-82.114.0.0/19
-82.114.96.0/19
-82.114.128.0/19
-82.114.224.0/19
-82.116.0.0/18
-82.117.64.0/19
-82.117.160.0/19
-82.118.128.0/19
-82.119.128.0/19
-82.137.128.0/18
-82.138.0.0/18
-82.140.64.0/18
-82.140.192.0/18
-82.142.128.0/18
-82.144.64.0/19
-82.146.32.0/19
-82.147.64.0/18
-82.148.8.0/21
-82.148.16.0/20
-82.149.128.0/19
-82.149.192.0/19
-82.151.96.0/19
-82.151.192.0/19
-82.162.0.0/16
-82.179.0.0/16
-82.193.128.0/19
-82.194.160.0/19
-82.194.224.0/19
-82.195.0.0/19
-82.196.64.0/19
-82.196.128.0/19
-82.198.0.0/19
-82.198.160.0/19
-82.199.96.0/19
-82.200.0.0/17
-82.202.128.0/19
-82.202.160.0/20
-82.202.176.0/21
-82.202.186.0/23
-82.202.188.0/22
-82.202.192.0/18
-82.204.128.0/17
-82.208.64.0/18
-82.209.64.0/18
-83.68.32.0/19
-83.69.0.0/19
-83.69.64.0/18
-83.69.160.0/19
-83.69.192.0/18
-83.97.0.0/21
-83.97.104.0/21
-83.102.128.0/17
-83.136.24.0/21
-83.136.112.0/21
-83.136.222.0/24
-83.136.232.0/22
-83.136.236.0/24
-83.136.238.0/23
-83.136.240.0/21
-83.137.48.0/21
-83.137.216.0/21
-83.138.59.0/24
-83.139.128.0/18
-83.142.8.0/21
-83.142.160.0/21
-83.143.32.0/21
-83.143.48.0/21
-83.143.64.0/22
-83.143.152.0/21
-83.143.192.0/20
-83.146.64.0/18
-83.149.0.0/18
-83.149.192.0/18
-83.151.0.0/20
-83.166.96.0/19
-83.166.224.0/19
-83.167.0.0/19
-83.167.64.0/18
-83.169.192.0/18
-83.171.64.0/18
-83.171.224.0/22
-83.171.240.0/22
-83.171.252.0/22
-83.172.0.0/18
-83.174.192.0/18
-83.217.0.0/18
-83.217.192.0/19
-83.219.0.0/19
-83.219.128.0/19
-83.219.224.0/19
-83.220.32.0/19
-83.220.64.0/19
-83.220.160.0/19
-83.220.224.0/19
-83.221.0.0/19
-83.221.192.0/19
-83.222.0.0/22
-83.222.4.0/23
-83.222.8.0/21
-83.222.16.0/20
-83.222.64.0/18
-83.222.192.0/19
-83.229.14.0/24
-83.229.25.0/24
-83.229.128.0/17
-83.234.0.0/16
-83.237.0.0/16
-83.239.0.0/16
-83.242.96.0/22
-83.242.102.0/23
-83.242.104.0/21
-83.242.128.0/17
-83.243.72.0/21
-83.246.128.0/17
-84.16.128.0/19
-84.17.0.0/19
-84.17.224.0/19
-84.18.96.0/19
-84.21.64.0/19
-84.21.164.0/22
-84.21.224.0/19
-84.22.128.0/19
-84.22.192.0/19
-84.23.32.0/19
-84.38.0.0/24
-84.38.2.0/23
-84.38.6.0/23
-84.38.176.0/20
-84.39.128.0/21
-84.39.240.0/20
-84.42.0.0/17
-84.47.128.0/22
-84.47.134.0/23
-84.47.136.0/21
-84.47.144.0/23
-84.47.147.0/24
-84.47.148.0/22
-84.47.152.0/23
-84.47.156.0/22
-84.47.160.0/22
-84.47.164.0/23
-84.47.168.0/21
-84.47.176.0/23
-84.47.178.0/24
-84.47.181.0/24
-84.47.182.0/23
-84.47.186.0/23
-84.47.188.0/24
-84.47.190.0/23
-84.51.64.0/18
-84.51.192.0/19
-84.52.64.0/18
-84.53.192.0/18
-84.54.28.0/22
-84.54.36.0/22
-84.54.44.0/22
-84.54.55.0/24
-84.54.56.0/22
-84.54.192.0/18
-84.201.128.0/18
-84.201.240.0/20
-84.204.0.0/16
-84.234.104.0/22
-84.237.0.0/17
-84.242.0.0/21
-84.242.192.0/18
-84.244.0.0/18
-84.246.105.0/24
-84.252.128.0/20
-84.252.144.0/21
-84.252.152.0/22
-84.252.160.0/19
-84.253.64.0/18
-84.254.192.0/18
-85.8.155.0/24
-85.8.194.0/24
-85.8.201.0/24
-85.8.215.0/24
-85.12.192.0/18
-85.15.64.0/18
-85.15.128.0/18
-85.21.0.0/16
-85.26.128.0/17
-85.28.0.0/18
-85.28.192.0/18
-85.30.192.0/18
-85.31.36.0/22
-85.31.112.0/20
-85.31.176.0/21
-85.88.160.0/19
-85.89.96.0/19
-85.90.96.0/19
-85.91.96.0/21
-85.91.104.0/24
-85.91.106.0/24
-85.91.112.0/22
-85.91.118.0/23
-85.91.120.0/23
-85.91.122.0/24
-85.91.192.0/19
-85.92.0.0/19
-85.92.108.0/22
-85.92.116.0/23
-85.92.118.0/24
-85.93.32.0/19
-85.93.128.0/19
-85.94.0.0/18
-85.95.128.0/18
-85.112.32.0/19
-85.112.96.0/19
-85.113.32.0/19
-85.113.128.0/19
-85.113.192.0/19
-85.114.0.0/19
-85.114.64.0/19
-85.114.160.0/19
-85.115.160.0/19
-85.115.200.0/22
-85.115.224.0/19
-85.116.96.0/19
-85.117.64.0/19
-85.117.234.0/23
-85.118.136.0/21
-85.118.176.0/21
-85.118.224.0/21
-85.119.72.0/21
-85.119.144.0/21
-85.140.0.0/14
-85.158.48.0/21
-85.158.88.0/21
-85.159.32.0/20
-85.159.116.0/24
-85.159.224.0/21
-85.172.0.0/14
-85.192.0.0/18
-85.192.128.0/18
-85.193.64.0/21
-85.193.72.0/22
-85.193.80.0/20
-85.198.64.0/20
-85.198.80.0/21
-85.198.92.0/22
-85.198.96.0/20
-85.198.112.0/21
-85.202.0.0/20
-85.202.128.0/20
-85.202.176.0/20
-85.202.224.0/19
-85.204.240.0/24
-85.208.85.0/24
-85.208.86.0/23
-85.208.209.0/24
-85.208.210.0/23
-85.208.220.0/22
-85.209.68.0/22
-85.209.144.0/22
-85.209.149.0/24
-85.209.150.0/23
-85.209.196.0/22
-85.209.212.0/22
-85.232.96.0/19
-85.233.64.0/19
-85.233.128.0/19
-85.234.0.0/18
-85.234.96.0/19
-85.235.32.0/19
-85.235.82.0/23
-85.235.160.0/19
-85.235.192.0/19
-85.236.0.0/19
-85.236.160.0/19
-85.237.32.0/19
-85.239.32.0/19
-85.249.0.0/16
-85.255.184.0/21
-86.62.4.0/22
-86.62.12.0/22
-86.62.48.0/22
-86.62.64.0/18
-86.102.0.0/16
-86.109.192.0/19
-86.110.0.0/19
-86.110.96.0/19
-86.110.160.0/19
-86.110.192.0/21
-86.110.200.0/22
-86.110.208.0/20
-86.111.0.0/19
-87.76.0.0/20
-87.103.128.0/17
-87.117.0.0/18
-87.117.128.0/18
-87.118.192.0/18
-87.119.224.0/19
-87.224.128.0/17
-87.225.0.0/17
-87.226.128.0/17
-87.228.0.0/17
-87.229.128.0/17
-87.236.8.0/21
-87.236.16.0/20
-87.236.37.0/24
-87.236.40.0/21
-87.236.80.0/21
-87.236.184.0/21
-87.237.40.0/21
-87.237.112.0/21
-87.237.136.0/21
-87.238.96.0/21
-87.238.232.0/21
-87.239.0.0/21
-87.239.24.0/21
-87.239.32.0/21
-87.239.104.0/21
-87.239.144.0/21
-87.240.0.0/18
-87.240.128.0/18
-87.241.192.0/18
-87.242.64.0/18
-87.244.0.0/18
-87.245.128.0/18
-87.245.192.0/20
-87.247.132.0/22
-87.248.224.0/19
-87.249.0.0/18
-87.249.192.0/18
-87.250.0.0/19
-87.250.192.0/18
-87.251.64.0/18
-87.251.160.0/19
-87.253.0.0/19
-87.253.192.0/19
-87.254.128.0/19
-87.255.0.0/19
-87.255.224.0/19
-88.80.32.0/19
-88.81.32.0/19
-88.81.192.0/19
-88.82.64.0/19
-88.82.160.0/19
-88.83.192.0/19
-88.84.192.0/19
-88.85.160.0/19
-88.85.192.0/19
-88.86.64.0/19
-88.86.192.0/19
-88.87.64.0/19
-88.135.0.0/20
-88.135.48.0/20
-88.135.80.0/20
-88.135.112.0/20
-88.147.128.0/17
-88.151.88.0/21
-88.151.104.0/21
-88.151.114.0/24
-88.151.184.0/21
-88.151.200.0/21
-88.151.248.0/21
-88.200.128.0/17
-88.201.128.0/17
-88.204.0.0/17
-88.205.128.0/17
-88.206.0.0/17
-88.210.0.0/23
-88.210.2.0/24
-88.210.4.0/23
-88.210.7.0/24
-88.210.8.0/24
-88.210.15.0/24
-88.210.16.0/22
-88.210.22.0/23
-88.210.24.0/21
-88.210.32.0/22
-88.210.40.0/21
-88.210.48.0/21
-88.210.56.0/22
-88.212.192.0/18
-88.214.32.0/22
-88.215.128.0/18
-88.218.56.0/21
-88.218.65.0/24
-88.218.66.0/23
-88.218.168.0/22
-88.218.212.0/22
-88.218.216.0/22
-88.218.244.0/22
-89.16.32.0/19
-89.16.96.0/19
-89.17.32.0/19
-89.18.128.0/19
-89.19.56.0/22
-89.19.160.0/19
-89.19.192.0/19
-89.20.0.0/19
-89.20.32.0/20
-89.20.52.0/22
-89.20.56.0/21
-89.20.96.0/19
-89.20.128.0/19
-89.21.128.0/19
-89.22.16.0/20
-89.22.52.0/22
-89.22.56.0/21
-89.22.128.0/18
-89.22.216.0/21
-89.22.224.0/19
-89.23.0.0/18
-89.23.96.0/20
-89.23.112.0/21
-89.23.120.0/22
-89.23.126.0/24
-89.23.128.0/18
-89.23.192.0/19
-89.28.160.0/21
-89.28.192.0/21
-89.28.248.0/21
-89.31.16.0/21
-89.31.32.0/21
-89.31.80.0/20
-89.31.104.0/21
-89.31.112.0/21
-89.31.184.0/21
-89.31.220.0/22
-89.40.204.0/24
-89.40.233.0/24
-89.104.64.0/19
-89.104.96.0/22
-89.104.103.0/24
-89.104.104.0/22
-89.104.108.0/23
-89.104.112.0/21
-89.104.120.0/24
-89.104.124.0/22
-89.105.128.0/19
-89.106.168.0/21
-89.106.192.0/21
-89.106.248.0/21
-89.107.11.0/24
-89.107.32.0/21
-89.107.80.0/21
-89.107.112.0/20
-89.107.136.0/21
-89.107.192.0/20
-89.108.64.0/18
-89.109.0.0/18
-89.109.128.0/17
-89.110.0.0/18
-89.111.128.0/18
-89.112.0.0/15
-89.145.128.0/19
-89.148.192.0/18
-89.151.128.0/18
-89.163.0.0/17
-89.169.0.0/19
-89.169.36.0/22
-89.169.40.0/21
-89.169.48.0/22
-89.169.56.0/21
-89.169.64.0/19
-89.169.128.0/17
-89.175.0.0/16
-89.178.0.0/15
-89.184.0.0/19
-89.184.224.0/19
-89.185.64.0/19
-89.186.224.0/19
-89.188.96.0/19
-89.188.160.0/19
-89.188.224.0/19
-89.189.0.0/19
-89.189.96.0/19
-89.189.128.0/18
-89.190.224.0/19
-89.191.224.0/21
-89.191.232.0/23
-89.191.235.0/24
-89.191.236.0/22
-89.191.240.0/20
-89.200.176.0/21
-89.204.0.0/17
-89.207.32.0/20
-89.207.64.0/20
-89.207.88.0/21
-89.207.96.0/21
-89.207.158.0/24
-89.207.216.0/21
-89.208.8.0/21
-89.208.16.0/20
-89.208.32.0/20
-89.208.48.0/22
-89.208.64.0/19
-89.208.96.0/20
-89.208.112.0/21
-89.208.120.0/23
-89.208.122.0/24
-89.208.124.0/22
-89.208.136.0/21
-89.208.144.0/20
-89.208.160.0/20
-89.208.176.0/22
-89.208.184.0/21
-89.208.192.0/19
-89.208.224.0/20
-89.221.16.0/20
-89.221.48.0/20
-89.221.192.0/20
-89.221.226.0/23
-89.221.228.0/22
-89.221.232.0/21
-89.222.128.0/17
-89.223.1.0/24
-89.223.5.0/24
-89.223.6.0/23
-89.223.8.0/23
-89.223.10.0/24
-89.223.12.0/23
-89.223.16.0/23
-89.223.20.0/23
-89.223.24.0/21
-89.223.32.0/19
-89.223.64.0/20
-89.223.80.0/21
-89.223.96.0/20
-89.223.120.0/21
-89.232.64.0/18
-89.232.128.0/19
-89.232.160.0/21
-89.232.168.0/22
-89.232.176.0/21
-89.232.188.0/22
-89.232.192.0/18
-89.235.128.0/18
-89.237.0.0/18
-89.239.128.0/18
-89.248.112.0/20
-89.248.176.0/20
-89.248.192.0/20
-89.248.224.0/23
-89.248.226.0/24
-89.248.228.0/22
-89.248.232.0/21
-89.249.16.0/20
-89.249.48.0/24
-89.249.50.0/24
-89.249.52.0/22
-89.249.112.0/20
-89.249.128.0/19
-89.249.160.0/20
-89.249.224.0/19
-89.250.0.0/19
-89.250.144.0/20
-89.250.160.0/20
-89.250.208.0/20
-89.250.224.0/20
-89.251.64.0/20
-89.251.96.0/20
-89.251.144.0/20
-89.251.160.0/20
-89.252.64.0/18
-89.253.0.0/18
-89.253.192.0/18
-89.254.192.0/18
-89.255.64.0/18
-90.150.0.0/15
-90.154.0.0/17
-90.155.128.0/17
-90.156.128.0/20
-90.156.148.0/22
-90.156.152.0/21
-90.156.168.0/21
-90.156.176.0/20
-90.156.200.0/21
-90.156.208.0/21
-90.156.216.0/22
-90.156.224.0/19
-90.157.0.0/17
-90.188.0.0/15
-91.76.0.0/14
-91.90.32.0/21
-91.90.198.0/23
-91.90.209.0/24
-91.90.210.0/23
-91.90.212.0/22
-91.90.220.0/23
-91.92.244.0/23
-91.102.72.0/21
-91.102.152.0/21
-91.102.200.0/21
-91.102.216.0/21
-91.103.72.0/21
-91.103.110.0/23
-91.103.140.0/24
-91.103.142.0/24
-91.103.192.0/20
-91.103.208.0/21
-91.103.224.0/21
-91.105.128.0/18
-91.105.194.0/23
-91.105.196.0/22
-91.105.232.0/21
-91.106.112.0/21
-91.106.200.0/21
-91.106.232.0/21
-91.107.0.0/18
-91.107.64.0/21
-91.107.80.0/21
-91.107.96.0/19
-91.108.168.0/21
-91.108.187.0/24
-91.109.64.0/19
-91.109.128.0/19
-91.109.200.0/21
-91.109.224.0/21
-91.122.0.0/16
-91.123.16.0/20
-91.123.80.0/20
-91.132.20.0/22
-91.132.96.0/22
-91.132.104.0/22
-91.132.188.0/22
-91.132.196.0/22
-91.132.216.0/22
-91.132.228.0/22
-91.133.0.0/19
-91.135.144.0/20
-91.135.208.0/20
-91.142.72.0/21
-91.142.80.0/20
-91.142.129.0/24
-91.142.135.0/24
-91.142.138.0/24
-91.142.141.0/24
-91.142.144.0/20
-91.143.0.0/18
-91.143.128.0/19
-91.143.160.0/20
-91.144.128.0/18
-91.146.0.0/18
-91.147.0.0/18
-91.149.64.0/18
-91.151.32.0/20
-91.151.176.0/20
-91.151.192.0/20
-91.184.224.0/20
-91.184.240.0/21
-91.184.254.0/23
-91.185.32.0/19
-91.185.64.0/19
-91.185.224.0/19
-91.186.96.0/19
-91.188.160.0/19
-91.188.196.0/22
-91.188.223.0/24
-91.188.245.0/24
-91.188.246.0/23
-91.189.48.0/21
-91.189.80.0/21
-91.189.112.0/21
-91.189.160.0/21
-91.189.232.0/21
-91.189.240.0/21
-91.190.64.0/20
-91.190.80.0/21
-91.190.112.0/20
-91.190.156.0/24
-91.190.176.0/21
-91.190.232.0/21
-91.191.224.0/19
-91.192.20.0/22
-91.192.60.0/22
-91.192.68.0/22
-91.192.72.0/22
-91.192.96.0/22
-91.192.148.0/22
-91.192.168.0/21
-91.192.188.0/22
-91.192.244.0/22
-91.193.25.0/24
-91.193.36.0/22
-91.193.88.0/23
-91.193.110.0/23
-91.193.140.0/22
-91.193.148.0/22
-91.193.168.0/22
-91.193.176.0/22
-91.193.212.0/22
-91.193.216.0/21
-91.193.224.0/21
-91.193.236.0/22
-91.193.240.0/22
-91.194.2.0/23
-91.194.12.0/23
-91.194.16.0/23
-91.194.58.0/23
-91.194.64.0/23
-91.194.112.0/23
-91.194.120.0/23
-91.194.162.0/23
-91.194.164.0/23
-91.194.172.0/22
-91.194.184.0/23
-91.194.190.0/23
-91.194.206.0/23
-91.194.212.0/23
-91.194.226.0/23
-91.194.238.0/23
-91.194.244.0/22
-91.194.252.0/23
-91.195.16.0/23
-91.195.20.0/23
-91.195.30.0/23
-91.195.60.0/23
-91.195.86.0/23
-91.195.100.0/23
-91.195.114.0/23
-91.195.124.0/22
-91.195.128.0/22
-91.195.136.0/23
-91.195.148.0/23
-91.195.170.0/23
-91.195.178.0/23
-91.195.204.0/23
-91.195.210.0/23
-91.195.230.0/23
-91.196.4.0/24
-91.196.32.0/22
-91.196.60.0/22
-91.196.72.0/22
-91.196.84.0/22
-91.196.236.0/22
-91.196.244.0/22
-91.196.248.0/21
-91.197.0.0/22
-91.197.8.0/22
-91.197.20.0/22
-91.197.52.0/23
-91.197.54.0/24
-91.197.57.0/24
-91.197.64.0/22
-91.197.76.0/22
-91.197.96.0/22
-91.197.104.0/22
-91.197.124.0/22
-91.197.132.0/22
-91.197.156.0/22
-91.197.160.0/22
-91.197.172.0/22
-91.197.176.0/21
-91.197.188.0/22
-91.197.192.0/22
-91.197.204.0/22
-91.197.212.0/22
-91.197.236.0/22
-91.198.14.0/24
-91.198.33.0/24
-91.198.39.0/24
-91.198.46.0/24
-91.198.54.0/24
-91.198.68.0/23
-91.198.71.0/24
-91.198.75.0/24
-91.198.85.0/24
-91.198.98.0/24
-91.198.104.0/24
-91.198.130.0/24
-91.198.149.0/24
-91.198.153.0/24
-91.198.155.0/24
-91.198.175.0/24
-91.198.184.0/24
-91.198.208.0/24
-91.198.210.0/23
-91.198.212.0/23
-91.198.215.0/24
-91.198.218.0/24
-91.198.221.0/24
-91.198.225.0/24
-91.198.231.0/24
-91.198.254.0/24
-91.199.4.0/24
-91.199.10.0/24
-91.199.16.0/24
-91.199.26.0/24
-91.199.34.0/24
-91.199.37.0/24
-91.199.46.0/24
-91.199.62.0/24
-91.199.67.0/24
-91.199.80.0/24
-91.199.114.0/23
-91.199.133.0/24
-91.199.143.0/24
-91.199.149.0/24
-91.199.153.0/24
-91.199.156.0/24
-91.199.171.0/24
-91.199.174.0/24
-91.199.178.0/24
-91.199.196.0/23
-91.199.199.0/24
-91.199.205.0/24
-91.199.224.0/24
-91.199.229.0/24
-91.199.230.0/24
-91.199.232.0/24
-91.199.244.0/24
-91.199.251.0/24
-91.200.28.0/22
-91.200.44.0/22
-91.200.62.0/24
-91.200.84.0/22
-91.200.148.0/22
-91.200.160.0/22
-91.200.224.0/21
-91.201.0.0/22
-91.201.8.0/23
-91.201.11.0/24
-91.201.24.0/24
-91.201.26.0/23
-91.201.40.0/22
-91.201.48.0/21
-91.201.72.0/22
-91.201.84.0/23
-91.201.86.0/24
-91.201.108.0/22
-91.201.116.0/22
-91.201.176.0/22
-91.201.184.0/22
-91.201.204.0/22
-91.201.208.0/22
-91.201.228.0/22
-91.201.236.0/22
-91.201.248.0/21
-91.202.8.0/21
-91.202.16.0/21
-91.202.24.0/22
-91.202.36.0/22
-91.202.44.0/22
-91.202.68.0/22
-91.202.76.0/22
-91.202.84.0/22
-91.202.92.0/22
-91.202.140.0/22
-91.202.148.0/22
-91.202.164.0/22
-91.202.180.0/22
-91.202.184.0/22
-91.202.196.0/22
-91.202.204.0/22
-91.202.216.0/21
-91.202.232.0/22
-91.202.252.0/22
-91.203.0.0/22
-91.203.8.0/22
-91.203.36.0/22
-91.203.44.0/22
-91.203.64.0/22
-91.203.80.0/21
-91.203.105.0/24
-91.203.124.0/22
-91.203.152.0/22
-91.203.168.0/22
-91.203.176.0/21
-91.203.188.0/22
-91.203.192.0/21
-91.203.208.0/22
-91.203.224.0/23
-91.203.226.0/24
-91.203.232.0/21
-91.203.240.0/22
-91.203.252.0/22
-91.204.16.0/21
-91.204.56.0/22
-91.204.68.0/22
-91.204.96.0/20
-91.204.128.0/22
-91.204.136.0/22
-91.204.144.0/21
-91.204.164.0/22
-91.204.176.0/21
-91.204.184.0/22
-91.204.200.0/22
-91.204.228.0/22
-91.204.232.0/22
-91.204.240.0/22
-91.204.252.0/22
-91.205.0.0/22
-91.205.8.0/22
-91.205.24.0/22
-91.205.44.0/22
-91.205.52.0/22
-91.205.84.0/22
-91.205.120.0/22
-91.205.128.0/22
-91.205.144.0/22
-91.205.160.0/21
-91.205.168.0/22
-91.205.176.0/21
-91.205.188.0/22
-91.205.200.0/22
-91.205.208.0/22
-91.205.224.0/22
-91.205.236.0/22
-91.205.240.0/22
-91.205.252.0/22
-91.206.12.0/22
-91.206.16.0/22
-91.206.22.0/23
-91.206.54.0/23
-91.206.56.0/23
-91.206.58.0/24
-91.206.62.0/23
-91.206.66.0/23
-91.206.72.0/23
-91.206.88.0/23
-91.206.100.0/23
-91.206.110.0/23
-91.206.116.0/23
-91.206.120.0/23
-91.206.126.0/23
-91.206.146.0/23
-91.206.148.0/23
-91.206.166.0/24
-91.206.196.0/23
-91.206.212.0/23
-91.206.216.0/23
-91.206.222.0/23
-91.206.240.0/22
-91.206.248.0/23
-91.207.4.0/22
-91.207.9.0/24
-91.207.24.0/22
-91.207.30.0/23
-91.207.40.0/22
-91.207.58.0/23
-91.207.71.0/24
-91.207.76.0/23
-91.207.78.0/24
-91.207.82.0/23
-91.207.84.0/22
-91.207.96.0/22
-91.207.106.0/23
-91.207.108.0/23
-91.207.114.0/23
-91.207.132.0/23
-91.207.136.0/23
-91.207.140.0/22
-91.207.146.0/23
-91.207.170.0/23
-91.207.180.0/23
-91.207.183.0/24
-91.207.224.0/23
-91.207.238.0/23
-91.207.246.0/23
-91.207.252.0/23
-91.208.20.0/24
-91.208.23.0/24
-91.208.29.0/24
-91.208.33.0/24
-91.208.35.0/24
-91.208.39.0/24
-91.208.42.0/23
-91.208.84.0/24
-91.208.119.0/24
-91.208.121.0/24
-91.208.126.0/24
-91.208.132.0/24
-91.208.134.0/24
-91.208.136.0/24
-91.208.149.0/24
-91.208.161.0/24
-91.208.166.0/24
-91.208.171.0/24
-91.208.183.0/24
-91.208.185.0/24
-91.208.187.0/24
-91.208.205.0/24
-91.208.210.0/24
-91.208.216.0/24
-91.208.232.0/24
-91.208.238.0/24
-91.208.248.0/23
-91.208.253.0/24
-91.208.254.0/24
-91.209.9.0/24
-91.209.17.0/24
-91.209.54.0/24
-91.209.59.0/24
-91.209.65.0/24
-91.209.67.0/24
-91.209.69.0/24
-91.209.72.0/24
-91.209.76.0/23
-91.209.80.0/24
-91.209.85.0/24
-91.209.91.0/24
-91.209.94.0/24
-91.209.119.0/24
-91.209.122.0/24
-91.209.124.0/24
-91.209.127.0/24
-91.209.128.0/23
-91.209.130.0/24
-91.209.135.0/24
-91.209.140.0/24
-91.209.147.0/24
-91.209.148.0/24
-91.209.208.0/24
-91.209.218.0/24
-91.209.233.0/24
-91.210.0.0/21
-91.210.24.0/22
-91.210.44.0/22
-91.210.52.0/22
-91.210.84.0/22
-91.210.92.0/22
-91.210.96.0/22
-91.210.104.0/22
-91.210.112.0/22
-91.210.132.0/22
-91.210.148.0/22
-91.210.152.0/24
-91.210.156.0/22
-91.210.160.0/22
-91.210.168.0/22
-91.210.176.0/22
-91.210.184.0/22
-91.210.192.0/20
-91.210.216.0/22
-91.210.228.0/22
-91.210.252.0/22
-91.211.2.0/24
-91.211.4.0/22
-91.211.16.0/21
-91.211.26.0/24
-91.211.28.0/22
-91.211.36.0/22
-91.211.44.0/22
-91.211.52.0/22
-91.211.56.0/21
-91.211.76.0/22
-91.211.80.0/22
-91.211.92.0/22
-91.211.104.0/22
-91.211.113.0/24
-91.211.115.0/24
-91.211.124.0/22
-91.211.128.0/22
-91.211.140.0/22
-91.211.148.0/22
-91.211.172.0/22
-91.211.180.0/22
-91.211.184.0/22
-91.211.192.0/22
-91.211.208.0/22
-91.211.216.0/22
-91.211.228.0/22
-91.211.236.0/22
-91.212.7.0/24
-91.212.47.0/24
-91.212.50.0/24
-91.212.57.0/24
-91.212.60.0/24
-91.212.64.0/24
-91.212.68.0/24
-91.212.81.0/24
-91.212.97.0/24
-91.212.118.0/24
-91.212.137.0/24
-91.212.146.0/24
-91.212.150.0/23
-91.212.158.0/24
-91.212.171.0/24
-91.212.179.0/24
-91.212.197.0/24
-91.212.198.0/24
-91.212.201.0/24
-91.212.217.0/24
-91.212.218.0/24
-91.212.220.0/24
-91.212.226.0/24
-91.212.239.0/24
-91.212.248.0/24
-91.213.5.0/24
-91.213.14.0/24
-91.213.23.0/24
-91.213.44.0/24
-91.213.48.0/24
-91.213.51.0/24
-91.213.67.0/24
-91.213.87.0/24
-91.213.104.0/24
-91.213.109.0/24
-91.213.113.0/24
-91.213.114.0/24
-91.213.117.0/24
-91.213.125.0/24
-91.213.130.0/24
-91.213.138.0/23
-91.213.141.0/24
-91.213.142.0/24
-91.213.144.0/24
-91.213.158.0/24
-91.213.163.0/24
-91.213.166.0/24
-91.213.168.0/23
-91.213.176.0/24
-91.213.184.0/24
-91.213.196.0/24
-91.213.213.0/24
-91.213.240.0/24
-91.213.243.0/24
-91.213.244.0/24
-91.213.248.0/23
-91.214.40.0/23
-91.214.48.0/22
-91.214.56.0/22
-91.214.68.0/22
-91.214.76.0/23
-91.214.80.0/22
-91.214.96.0/22
-91.214.116.0/24
-91.214.120.0/22
-91.214.128.0/22
-91.214.140.0/22
-91.214.144.0/22
-91.214.160.0/22
-91.214.172.0/24
-91.214.175.0/24
-91.214.184.0/22
-91.214.196.0/22
-91.214.204.0/22
-91.214.212.0/22
-91.214.220.0/22
-91.214.224.0/22
-91.214.240.0/22
-91.215.16.0/21
-91.215.28.0/22
-91.215.36.0/22
-91.215.40.0/22
-91.215.60.0/22
-91.215.76.0/22
-91.215.84.0/23
-91.215.88.0/22
-91.215.108.0/22
-91.215.112.0/22
-91.215.120.0/22
-91.215.128.0/22
-91.215.140.0/22
-91.215.168.0/21
-91.215.188.0/22
-91.215.192.0/20
-91.215.208.0/21
-91.215.220.0/22
-91.215.224.0/22
-91.215.232.0/22
-91.215.244.0/22
-91.215.248.0/21
-91.216.46.0/24
-91.216.48.0/23
-91.216.50.0/24
-91.216.53.0/24
-91.216.66.0/24
-91.216.68.0/23
-91.216.72.0/24
-91.216.81.0/24
-91.216.96.0/24
-91.216.114.0/24
-91.216.121.0/24
-91.216.123.0/24
-91.216.126.0/24
-91.216.129.0/24
-91.216.130.0/24
-91.216.147.0/24
-91.216.164.0/24
-91.216.167.0/24
-91.216.175.0/24
-91.216.186.0/23
-91.216.198.0/24
-91.216.205.0/24
-91.216.208.0/24
-91.216.211.0/24
-91.216.212.0/24
-91.216.240.0/24
-91.217.2.0/23
-91.217.4.0/23
-91.217.8.0/22
-91.217.16.0/23
-91.217.20.0/23
-91.217.34.0/23
-91.217.42.0/23
-91.217.46.0/23
-91.217.62.0/23
-91.217.70.0/23
-91.217.74.0/23
-91.217.78.0/23
-91.217.102.0/23
-91.217.108.0/22
-91.217.125.0/24
-91.217.129.0/24
-91.217.136.0/23
-91.217.143.0/24
-91.217.156.0/24
-91.217.163.0/24
-91.217.178.0/24
-91.217.180.0/24
-91.217.184.0/24
-91.217.190.0/24
-91.217.194.0/24
-91.217.196.0/24
-91.217.202.0/24
-91.217.220.0/24
-91.217.227.0/24
-91.217.233.0/24
-91.217.244.0/24
-91.218.8.0/22
-91.218.16.0/22
-91.218.24.0/21
-91.218.40.0/22
-91.218.84.0/22
-91.218.92.0/22
-91.218.100.0/22
-91.218.108.0/22
-91.218.112.0/21
-91.218.128.0/20
-91.218.144.0/22
-91.218.176.0/22
-91.218.220.0/22
-91.218.228.0/22
-91.218.244.0/22
-91.218.248.0/22
-91.219.4.0/22
-91.219.12.0/22
-91.219.23.0/24
-91.219.24.0/22
-91.219.32.0/21
-91.219.48.0/22
-91.219.56.0/22
-91.219.64.0/22
-91.219.72.0/22
-91.219.88.0/22
-91.219.96.0/21
-91.219.117.0/24
-91.219.124.0/22
-91.219.136.0/22
-91.219.148.0/22
-91.219.156.0/22
-91.219.160.0/21
-91.219.176.0/21
-91.219.188.0/22
-91.219.192.0/22
-91.219.200.0/21
-91.219.228.0/22
-91.219.248.0/22
-91.220.1.0/24
-91.220.5.0/24
-91.220.11.0/24
-91.220.12.0/24
-91.220.31.0/24
-91.220.33.0/24
-91.220.38.0/24
-91.220.46.0/24
-91.220.57.0/24
-91.220.69.0/24
-91.220.76.0/24
-91.220.87.0/24
-91.220.92.0/23
-91.220.109.0/24
-91.220.112.0/24
-91.220.120.0/24
-91.220.124.0/24
-91.220.133.0/24
-91.220.135.0/24
-91.220.137.0/24
-91.220.145.0/24
-91.220.146.0/24
-91.220.152.0/24
-91.220.155.0/24
-91.220.163.0/24
-91.220.166.0/24
-91.220.169.0/24
-91.220.170.0/24
-91.220.181.0/24
-91.220.186.0/24
-91.220.188.0/24
-91.220.211.0/24
-91.220.215.0/24
-91.220.218.0/23
-91.220.220.0/24
-91.220.233.0/24
-91.221.0.0/23
-91.221.16.0/22
-91.221.24.0/23
-91.221.28.0/22
-91.221.34.0/23
-91.221.36.0/23
-91.221.42.0/23
-91.221.48.0/23
-91.221.56.0/23
-91.221.68.0/24
-91.221.70.0/23
-91.221.90.0/23
-91.221.98.0/24
-91.221.102.0/23
-91.221.108.0/23
-91.221.132.0/23
-91.221.136.0/23
-91.221.140.0/23
-91.221.156.0/23
-91.221.162.0/23
-91.221.164.0/23
-91.221.174.0/23
-91.221.176.0/23
-91.221.180.0/23
-91.221.188.0/23
-91.221.194.0/23
-91.221.198.0/23
-91.221.200.0/23
-91.221.242.0/23
-91.221.246.0/23
-91.221.248.0/23
-91.221.252.0/23
-91.222.28.0/22
-91.222.120.0/22
-91.222.128.0/22
-91.222.156.0/22
-91.222.164.0/22
-91.222.208.0/22
-91.222.216.0/22
-91.222.228.0/22
-91.222.236.0/22
-91.222.240.0/22
-91.223.1.0/24
-91.223.15.0/24
-91.223.18.0/24
-91.223.25.0/24
-91.223.28.0/24
-91.223.32.0/24
-91.223.37.0/24
-91.223.44.0/24
-91.223.48.0/24
-91.223.63.0/24
-91.223.70.0/24
-91.223.75.0/24
-91.223.89.0/24
-91.223.90.0/24
-91.223.93.0/24
-91.223.98.0/24
-91.223.105.0/24
-91.223.108.0/23
-91.223.118.0/24
-91.223.120.0/24
-91.223.128.0/24
-91.223.137.0/24
-91.223.138.0/24
-91.223.144.0/24
-91.223.153.0/24
-91.223.170.0/24
-91.223.176.0/24
-91.223.181.0/24
-91.223.188.0/24
-91.223.217.0/24
-91.223.224.0/24
-91.223.226.0/24
-91.223.239.0/24
-91.223.242.0/24
-91.223.244.0/24
-91.223.246.0/24
-91.223.251.0/24
-91.223.252.0/24
-91.223.254.0/24
-91.224.14.0/23
-91.224.18.0/23
-91.224.30.0/23
-91.224.32.0/22
-91.224.52.0/23
-91.224.76.0/23
-91.224.80.0/22
-91.224.86.0/23
-91.224.98.0/23
-91.224.102.0/23
-91.224.106.0/23
-91.224.124.0/22
-91.224.130.0/23
-91.224.132.0/23
-91.224.136.0/22
-91.224.154.0/23
-91.224.166.0/23
-91.224.168.0/23
-91.224.182.0/23
-91.224.194.0/23
-91.224.204.0/22
-91.224.208.0/23
-91.224.218.0/23
-91.224.232.0/22
-91.224.254.0/23
-91.225.20.0/22
-91.225.24.0/23
-91.225.27.0/24
-91.225.40.0/22
-91.225.72.0/21
-91.225.88.0/22
-91.225.100.0/22
-91.225.112.0/22
-91.225.124.0/24
-91.225.127.0/24
-91.225.148.0/22
-91.225.192.0/22
-91.225.208.0/21
-91.225.216.0/24
-91.225.228.0/22
-91.225.236.0/22
-91.225.252.0/22
-91.226.10.0/23
-91.226.14.0/23
-91.226.30.0/23
-91.226.48.0/23
-91.226.60.0/22
-91.226.64.0/22
-91.226.73.0/24
-91.226.80.0/22
-91.226.92.0/22
-91.226.104.0/22
-91.226.116.0/24
-91.226.120.0/22
-91.226.128.0/21
-91.226.136.0/23
-91.226.140.0/22
-91.226.148.0/22
-91.226.152.0/22
-91.226.161.0/24
-91.226.164.0/22
-91.226.171.0/24
-91.226.172.0/22
-91.226.178.0/24
-91.226.185.0/24
-91.226.186.0/24
-91.226.188.0/23
-91.226.200.0/24
-91.226.204.0/23
-91.226.208.0/22
-91.226.222.0/23
-91.226.234.0/24
-91.226.250.0/24
-91.227.8.0/22
-91.227.12.0/23
-91.227.16.0/22
-91.227.23.0/24
-91.227.28.0/22
-91.227.32.0/24
-91.227.34.0/23
-91.227.44.0/22
-91.227.50.0/23
-91.227.52.0/23
-91.227.54.0/24
-91.227.68.0/24
-91.227.79.0/24
-91.227.91.0/24
-91.227.92.0/22
-91.227.112.0/23
-91.227.136.0/24
-91.227.140.0/22
-91.227.148.0/23
-91.227.152.0/23
-91.227.154.0/24
-91.227.160.0/22
-91.227.169.0/24
-91.227.172.0/22
-91.227.188.0/22
-91.227.195.0/24
-91.227.198.0/24
-91.227.210.0/23
-91.227.228.0/24
-91.227.242.0/23
-91.227.244.0/24
-91.228.26.0/23
-91.228.30.0/23
-91.228.40.0/23
-91.228.48.0/22
-91.228.54.0/23
-91.228.57.0/24
-91.228.62.0/23
-91.228.76.0/23
-91.228.96.0/22
-91.228.102.0/23
-91.228.116.0/23
-91.228.118.0/24
-91.228.120.0/23
-91.228.124.0/24
-91.228.148.0/24
-91.228.161.0/24
-91.228.177.0/24
-91.228.178.0/23
-91.228.180.0/22
-91.228.184.0/24
-91.228.205.0/24
-91.228.208.0/22
-91.228.220.0/22
-91.228.224.0/23
-91.228.226.0/24
-91.228.228.0/24
-91.228.230.0/24
-91.228.238.0/23
-91.228.246.0/23
-91.228.250.0/24
-91.229.2.0/24
-91.229.8.0/22
-91.229.48.0/24
-91.229.50.0/23
-91.229.59.0/24
-91.229.74.0/23
-91.229.90.0/23
-91.229.96.0/22
-91.229.100.0/24
-91.229.108.0/22
-91.229.112.0/23
-91.229.128.0/23
-91.229.146.0/24
-91.229.154.0/24
-91.229.176.0/23
-91.229.189.0/24
-91.229.190.0/23
-91.229.196.0/22
-91.229.200.0/24
-91.229.208.0/23
-91.229.211.0/24
-91.229.221.0/24
-91.229.233.0/24
-91.229.234.0/23
-91.229.237.0/24
-91.229.239.0/24
-91.230.10.0/23
-91.230.18.0/23
-91.230.20.0/23
-91.230.23.0/24
-91.230.26.0/24
-91.230.50.0/24
-91.230.52.0/23
-91.230.54.0/24
-91.230.60.0/22
-91.230.65.0/24
-91.230.72.0/24
-91.230.84.0/24
-91.230.91.0/24
-91.230.94.0/23
-91.230.100.0/23
-91.230.107.0/24
-91.230.133.0/24
-91.230.135.0/24
-91.230.136.0/22
-91.230.146.0/24
-91.230.150.0/24
-91.230.152.0/22
-91.230.182.0/23
-91.230.184.0/22
-91.230.191.0/24
-91.230.196.0/23
-91.230.208.0/22
-91.230.215.0/24
-91.230.218.0/24
-91.230.224.0/24
-91.230.226.0/23
-91.230.228.0/23
-91.230.251.0/24
-91.230.252.0/23
-91.231.8.0/24
-91.231.16.0/23
-91.231.94.0/23
-91.231.96.0/24
-91.231.112.0/22
-91.231.128.0/21
-91.231.136.0/23
-91.231.141.0/24
-91.231.145.0/24
-91.231.146.0/24
-91.231.161.0/24
-91.231.162.0/23
-91.231.176.0/23
-91.231.180.0/24
-91.231.196.0/22
-91.231.213.0/24
-91.231.214.0/23
-91.231.218.0/23
-91.231.233.0/24
-91.231.234.0/23
-91.231.236.0/22
-91.232.6.0/23
-91.232.8.0/21
-91.232.34.0/24
-91.232.39.0/24
-91.232.70.0/24
-91.232.80.0/24
-91.232.92.0/22
-91.232.108.0/22
-91.232.113.0/24
-91.232.116.0/22
-91.232.120.0/22
-91.232.126.0/24
-91.232.131.0/24
-91.232.132.0/22
-91.232.144.0/22
-91.232.162.0/24
-91.232.168.0/22
-91.232.172.0/23
-91.232.188.0/23
-91.232.196.0/23
-91.232.202.0/23
-91.232.204.0/22
-91.232.216.0/23
-91.232.225.0/24
-91.232.230.0/23
-91.232.243.0/24
-91.232.244.0/23
-91.232.246.0/24
-91.232.252.0/23
-91.233.4.0/24
-91.233.28.0/22
-91.233.40.0/21
-91.233.55.0/24
-91.233.63.0/24
-91.233.65.0/24
-91.233.82.0/24
-91.233.88.0/24
-91.233.92.0/22
-91.233.132.0/22
-91.233.144.0/22
-91.233.148.0/23
-91.233.164.0/22
-91.233.168.0/22
-91.233.172.0/23
-91.233.175.0/24
-91.233.188.0/23
-91.233.212.0/23
-91.233.216.0/21
-91.233.226.0/24
-91.233.230.0/23
-91.233.238.0/23
-91.233.240.0/22
-91.233.246.0/23
-91.234.11.0/24
-91.234.16.0/24
-91.234.48.0/24
-91.234.54.0/24
-91.234.60.0/22
-91.234.64.0/23
-91.234.68.0/22
-91.234.80.0/22
-91.234.96.0/22
-91.234.108.0/22
-91.234.116.0/22
-91.234.152.0/22
-91.234.164.0/22
-91.234.170.0/24
-91.234.172.0/22
-91.234.177.0/24
-91.234.178.0/24
-91.234.180.0/22
-91.234.188.0/24
-91.234.224.0/23
-91.235.7.0/24
-91.235.12.0/22
-91.235.26.0/23
-91.235.28.0/22
-91.235.32.0/23
-91.235.42.0/24
-91.235.66.0/24
-91.235.72.0/22
-91.235.80.0/23
-91.235.88.0/21
-91.235.101.0/24
-91.235.103.0/24
-91.235.106.0/24
-91.235.112.0/24
-91.235.127.0/24
-91.235.136.0/23
-91.235.144.0/22
-91.235.148.0/24
-91.235.156.0/23
-91.235.169.0/24
-91.235.175.0/24
-91.235.180.0/23
-91.235.184.0/21
-91.235.196.0/22
-91.235.203.0/24
-91.235.213.0/24
-91.235.220.0/23
-91.235.233.0/24
-91.235.241.0/24
-91.235.244.0/22
-91.236.2.0/23
-91.236.10.0/23
-91.236.12.0/24
-91.236.14.0/23
-91.236.22.0/23
-91.236.24.0/24
-91.236.29.0/24
-91.236.30.0/23
-91.236.48.0/22
-91.236.60.0/22
-91.236.80.0/23
-91.236.92.0/22
-91.236.100.0/22
-91.236.104.0/24
-91.236.108.0/22
-91.236.112.0/22
-91.236.118.0/23
-91.236.124.0/24
-91.236.134.0/23
-91.236.136.0/24
-91.236.140.0/22
-91.236.148.0/22
-91.236.164.0/22
-91.236.171.0/24
-91.236.176.0/22
-91.236.180.0/23
-91.236.196.0/22
-91.236.200.0/24
-91.236.204.0/23
-91.236.213.0/24
-91.236.234.0/23
-91.236.238.0/24
-91.236.246.0/23
-91.236.252.0/23
-91.237.0.0/22
-91.237.20.0/24
-91.237.32.0/24
-91.237.37.0/24
-91.237.53.0/24
-91.237.54.0/23
-91.237.76.0/24
-91.237.82.0/23
-91.237.94.0/24
-91.237.97.0/24
-91.237.144.0/22
-91.237.148.0/24
-91.237.163.0/24
-91.237.178.0/23
-91.237.181.0/24
-91.237.182.0/23
-91.237.186.0/23
-91.237.188.0/23
-91.237.192.0/24
-91.237.199.0/24
-91.237.200.0/22
-91.237.209.0/24
-91.237.213.0/24
-91.237.220.0/22
-91.237.249.0/24
-91.237.252.0/23
-91.238.2.0/23
-91.238.10.0/23
-91.238.24.0/22
-91.238.28.0/23
-91.238.34.0/23
-91.238.44.0/22
-91.238.48.0/23
-91.238.64.0/22
-91.238.68.0/23
-91.238.74.0/23
-91.238.79.0/24
-91.238.80.0/23
-91.238.86.0/23
-91.238.88.0/22
-91.238.96.0/22
-91.238.108.0/22
-91.238.115.0/24
-91.238.120.0/23
-91.238.122.0/24
-91.238.127.0/24
-91.238.128.0/23
-91.238.133.0/24
-91.238.136.0/22
-91.238.140.0/24
-91.238.156.0/22
-91.238.168.0/22
-91.238.182.0/23
-91.238.184.0/23
-91.238.188.0/22
-91.238.200.0/23
-91.238.202.0/24
-91.238.210.0/23
-91.238.222.0/23
-91.238.224.0/24
-91.238.227.0/24
-91.238.228.0/22
-91.238.244.0/23
-91.238.248.0/23
-91.238.252.0/23
-91.239.4.0/23
-91.239.16.0/22
-91.239.23.0/24
-91.239.26.0/23
-91.239.40.0/23
-91.239.42.0/24
-91.239.44.0/23
-91.239.60.0/24
-91.239.63.0/24
-91.239.68.0/22
-91.239.88.0/23
-91.239.94.0/24
-91.239.98.0/23
-91.239.102.0/23
-91.239.112.0/24
-91.239.121.0/24
-91.239.126.0/23
-91.239.131.0/24
-91.239.132.0/22
-91.239.140.0/22
-91.239.158.0/23
-91.239.172.0/24
-91.239.176.0/24
-91.239.184.0/24
-91.239.190.0/23
-91.239.215.0/24
-91.239.228.0/23
-91.239.239.0/24
-91.240.16.0/24
-91.240.25.0/24
-91.240.36.0/24
-91.240.38.0/23
-91.240.45.0/24
-91.240.71.0/24
-91.240.74.0/23
-91.240.84.0/22
-91.240.90.0/23
-91.240.102.0/23
-91.240.110.0/23
-91.240.112.0/22
-91.240.119.0/24
-91.240.120.0/21
-91.240.144.0/24
-91.240.162.0/24
-91.240.168.0/22
-91.240.172.0/24
-91.240.179.0/24
-91.240.190.0/23
-91.240.208.0/22
-91.240.218.0/23
-91.240.220.0/24
-91.240.222.0/24
-91.240.225.0/24
-91.240.242.0/23
-91.241.4.0/24
-91.241.12.0/23
-91.241.16.0/22
-91.241.22.0/24
-91.241.43.0/24
-91.241.45.0/24
-91.241.46.0/23
-91.241.54.0/24
-91.241.58.0/24
-91.241.68.0/23
-91.241.84.0/23
-91.241.88.0/22
-91.241.128.0/19
-91.241.160.0/21
-91.241.182.0/23
-91.241.184.0/21
-91.242.32.0/21
-91.242.40.0/22
-91.242.161.0/24
-91.242.164.0/22
-91.242.168.0/22
-91.242.176.0/20
-91.242.208.0/22
-91.242.213.0/24
-91.242.255.0/24
-91.243.32.0/19
-91.243.80.0/24
-91.243.82.0/23
-91.243.84.0/24
-91.243.86.0/24
-91.243.88.0/21
-91.243.96.0/20
-91.243.112.0/23
-91.243.120.0/23
-91.243.124.0/23
-91.243.190.0/23
-91.243.224.0/19
-91.244.64.0/22
-91.244.72.0/21
-91.244.80.0/20
-91.244.112.0/22
-91.244.160.0/20
-91.244.176.0/22
-91.244.183.0/24
-91.244.232.0/22
-91.244.240.0/22
-91.244.244.0/24
-91.244.252.0/22
-91.245.32.0/19
-91.245.64.0/21
-91.245.128.0/19
-91.245.210.0/23
-91.246.0.0/22
-91.246.16.0/21
-91.246.24.0/23
-91.246.112.0/20
-91.246.160.0/21
-91.246.219.0/24
-91.247.0.0/19
-91.247.32.0/22
-91.247.68.0/22
-91.247.96.0/19
-91.247.128.0/20
-91.247.148.0/22
-91.247.152.0/21
-91.247.190.0/24
-91.247.192.0/20
-91.247.208.0/21
-91.247.216.0/22
-91.247.220.0/24
-91.247.222.0/23
-91.247.232.0/21
-91.247.248.0/22
-91.247.254.0/23
-92.36.0.0/17
-92.37.128.0/17
-92.38.128.0/22
-92.38.136.0/22
-92.38.152.0/23
-92.38.156.0/24
-92.38.188.0/22
-92.38.192.0/20
-92.38.212.0/22
-92.38.216.0/21
-92.38.224.0/19
-92.39.64.0/20
-92.39.96.0/20
-92.39.128.0/20
-92.39.208.0/20
-92.39.224.0/20
-92.42.6.0/24
-92.42.8.0/21
-92.42.24.0/21
-92.42.40.0/22
-92.42.88.0/21
-92.42.96.0/24
-92.42.128.0/21
-92.42.160.0/21
-92.42.208.0/21
-92.43.0.0/21
-92.43.152.0/21
-92.43.166.0/23
-92.43.184.0/21
-92.49.128.0/18
-92.50.128.0/17
-92.51.0.0/19
-92.51.32.0/20
-92.51.48.0/21
-92.53.64.0/18
-92.53.224.0/21
-92.54.64.0/18
-92.55.0.0/18
-92.60.80.0/20
-92.61.16.0/20
-92.61.64.0/22
-92.61.68.0/23
-92.62.112.0/22
-92.62.116.0/24
-92.62.144.0/20
-92.63.64.0/20
-92.63.96.0/20
-92.63.184.0/22
-92.63.192.0/21
-92.63.200.0/22
-92.100.0.0/15
-92.118.64.0/22
-92.118.84.0/22
-92.118.88.0/21
-92.118.112.0/21
-92.118.124.0/22
-92.118.132.0/22
-92.118.140.0/22
-92.118.168.0/22
-92.118.196.0/22
-92.118.200.0/22
-92.119.200.0/22
-92.119.216.0/22
-92.124.0.0/14
-92.223.4.0/23
-92.223.6.0/24
-92.223.8.0/23
-92.223.14.0/24
-92.223.32.0/22
-92.223.36.0/24
-92.223.38.0/24
-92.223.41.0/24
-92.223.43.0/24
-92.223.49.0/24
-92.223.60.0/24
-92.223.64.0/23
-92.223.67.0/24
-92.223.72.0/24
-92.223.80.0/24
-92.223.87.0/24
-92.223.91.0/24
-92.223.103.0/24
-92.223.106.0/24
-92.223.108.0/22
-92.223.114.0/23
-92.223.122.0/23
-92.240.128.0/20
-92.240.192.0/19
-92.241.0.0/19
-92.241.96.0/19
-92.241.160.0/19
-92.241.224.0/19
-92.242.0.0/17
-92.243.96.0/19
-92.243.160.0/19
-92.244.224.0/19
-92.245.32.0/19
-92.246.148.0/22
-92.246.152.0/22
-92.246.160.0/19
-92.246.192.0/19
-92.248.128.0/17
-92.249.0.0/22
-92.249.4.0/24
-92.252.128.0/17
-92.255.1.0/24
-92.255.2.0/23
-92.255.4.0/22
-92.255.8.0/21
-92.255.16.0/20
-92.255.40.0/21
-92.255.48.0/22
-92.255.53.0/24
-92.255.54.0/23
-92.255.58.0/23
-92.255.60.0/22
-92.255.65.0/24
-92.255.66.0/23
-92.255.72.0/21
-92.255.88.0/21
-92.255.96.0/19
-92.255.128.0/17
-93.77.160.0/19
-93.80.0.0/15
-93.88.0.0/20
-93.88.76.0/22
-93.88.128.0/20
-93.88.160.0/19
-93.88.208.0/20
-93.89.176.0/20
-93.90.32.0/20
-93.90.80.0/20
-93.90.96.0/20
-93.90.208.0/20
-93.90.224.0/19
-93.91.0.0/20
-93.91.112.0/20
-93.91.160.0/20
-93.91.224.0/20
-93.92.32.0/21
-93.92.64.0/21
-93.92.80.0/20
-93.92.136.0/21
-93.92.176.0/21
-93.92.192.0/20
-93.92.216.0/21
-93.93.88.0/21
-93.93.136.0/21
-93.93.172.0/22
-93.94.144.0/20
-93.94.176.0/21
-93.94.232.0/21
-93.95.29.0/24
-93.95.96.0/21
-93.95.136.0/21
-93.95.152.0/21
-93.95.160.0/20
-93.95.192.0/21
-93.100.0.0/16
-93.114.142.0/24
-93.120.128.0/17
-93.123.128.0/17
-93.124.0.0/17
-93.153.128.0/17
-93.157.8.0/22
-93.157.16.0/21
-93.157.40.0/21
-93.157.56.0/23
-93.157.59.0/24
-93.157.60.0/22
-93.157.106.0/24
-93.157.120.0/21
-93.157.144.0/21
-93.157.160.0/20
-93.157.186.0/24
-93.157.202.0/23
-93.157.205.0/24
-93.157.206.0/24
-93.157.208.0/21
-93.157.232.0/21
-93.157.240.0/20
-93.158.128.0/18
-93.158.192.0/21
-93.158.224.0/21
-93.158.240.0/20
-93.159.216.0/21
-93.159.232.0/21
-93.159.240.0/21
-93.174.48.0/20
-93.174.72.0/21
-93.174.112.0/21
-93.174.128.0/21
-93.174.224.0/21
-93.174.240.0/21
-93.175.0.0/19
-93.177.0.0/18
-93.177.116.0/22
-93.177.126.0/24
-93.178.64.0/18
-93.179.104.0/21
-93.180.0.0/18
-93.180.136.0/21
-93.181.192.0/18
-93.182.0.0/18
-93.183.64.0/20
-93.183.80.0/22
-93.183.92.0/22
-93.183.104.0/21
-93.183.112.0/21
-93.184.160.0/20
-93.185.16.0/20
-93.185.164.0/22
-93.185.172.0/22
-93.185.176.0/20
-93.185.192.0/20
-93.186.48.0/20
-93.186.224.0/20
-93.187.72.0/21
-93.187.96.0/21
-93.187.120.0/21
-93.187.152.0/21
-93.187.176.0/20
-93.188.16.0/21
-93.188.40.0/21
-93.188.120.0/21
-93.188.152.0/23
-93.188.154.0/24
-93.188.156.0/22
-93.188.184.0/21
-93.188.200.0/21
-93.188.208.0/21
-93.189.8.0/21
-93.189.16.0/21
-93.189.40.0/21
-93.189.48.0/21
-93.189.72.0/21
-93.189.80.0/21
-93.189.144.0/21
-93.189.200.0/21
-93.189.216.0/21
-93.189.226.0/23
-93.189.228.0/22
-93.189.248.0/21
-93.190.16.0/21
-93.190.104.0/21
-93.190.176.0/21
-93.190.200.0/21
-93.190.224.0/21
-93.191.8.0/21
-93.191.16.0/21
-93.191.56.0/21
-93.191.72.0/21
-94.19.0.0/16
-94.24.128.0/17
-94.25.0.0/16
-94.26.128.0/18
-94.26.224.0/19
-94.28.0.0/16
-94.29.0.0/17
-94.31.128.0/17
-94.41.0.0/16
-94.45.0.0/19
-94.45.192.0/19
-94.50.0.0/15
-94.72.0.0/18
-94.73.192.0/18
-94.75.0.0/18
-94.75.128.0/18
-94.77.0.0/17
-94.77.128.0/18
-94.78.192.0/18
-94.79.0.0/18
-94.100.80.0/20
-94.100.176.0/20
-94.100.192.0/20
-94.101.64.0/20
-94.101.96.0/23
-94.101.105.0/24
-94.101.110.0/24
-94.102.16.0/20
-94.102.88.0/23
-94.102.112.0/20
-94.102.176.0/20
-94.103.0.0/22
-94.103.83.0/24
-94.103.84.0/22
-94.103.88.0/22
-94.103.92.0/23
-94.103.188.0/24
-94.103.224.0/20
-94.124.114.0/24
-94.124.168.0/21
-94.124.192.0/20
-94.124.224.0/21
-94.124.240.0/21
-94.125.0.0/20
-94.125.40.0/21
-94.125.48.0/21
-94.125.88.0/21
-94.125.184.0/21
-94.125.240.0/21
-94.126.24.0/21
-94.126.88.0/21
-94.126.152.0/21
-94.126.200.0/24
-94.126.202.0/23
-94.126.204.0/22
-94.127.88.0/21
-94.127.136.0/21
-94.127.144.0/20
-94.127.168.0/21
-94.127.176.0/21
-94.127.200.0/21
-94.127.216.0/21
-94.127.240.0/20
-94.131.23.0/24
-94.136.192.0/19
-94.137.0.0/18
-94.137.64.0/19
-94.137.192.0/18
-94.138.0.0/19
-94.138.128.0/19
-94.139.96.0/19
-94.139.240.0/20
-94.140.128.0/19
-94.140.192.0/18
-94.141.32.0/19
-94.141.104.0/21
-94.141.112.0/20
-94.141.160.0/19
-94.141.244.0/22
-94.141.252.0/22
-94.142.0.0/19
-94.142.128.0/24
-94.142.248.0/24
-94.143.32.0/21
-94.143.48.0/20
-94.143.128.0/21
-94.143.144.0/21
-94.143.160.0/21
-94.143.240.0/21
-94.154.11.0/24
-94.154.64.0/19
-94.158.0.0/20
-94.158.16.0/22
-94.158.22.0/23
-94.158.32.0/20
-94.158.96.0/19
-94.158.160.0/20
-94.158.192.0/20
-94.158.216.0/24
-94.158.220.0/23
-94.158.222.0/24
-94.159.0.0/17
-94.180.0.0/15
-94.188.0.0/17
-94.190.0.0/17
-94.198.0.0/21
-94.198.16.0/21
-94.198.32.0/21
-94.198.50.0/23
-94.198.52.0/22
-94.198.104.0/21
-94.198.128.0/21
-94.198.192.0/21
-94.198.216.0/21
-94.198.232.0/21
-94.199.4.0/24
-94.199.64.0/20
-94.199.104.0/21
-94.199.216.0/21
-94.228.112.0/20
-94.228.160.0/20
-94.228.192.0/20
-94.228.240.0/20
-94.229.16.0/20
-94.229.224.0/19
-94.230.0.0/20
-94.230.32.0/20
-94.230.112.0/20
-94.230.128.0/20
-94.230.160.0/20
-94.230.240.0/20
-94.231.16.0/20
-94.231.112.0/20
-94.231.128.0/19
-94.231.160.0/20
-94.231.212.0/24
-94.231.216.0/21
-94.232.0.0/20
-94.232.16.0/21
-94.232.31.0/24
-94.232.48.0/20
-94.232.64.0/21
-94.232.88.0/21
-94.232.104.0/21
-94.232.128.0/20
-94.232.184.0/21
-94.232.200.0/21
-94.232.232.0/21
-94.233.0.0/16
-94.237.128.0/17
-94.240.64.0/18
-94.241.0.0/18
-94.241.192.0/18
-94.242.0.0/19
-94.242.32.0/20
-94.242.128.0/18
-94.243.0.0/18
-94.243.128.0/17
-94.245.128.0/18
-94.247.16.0/21
-94.247.56.0/21
-94.247.104.0/21
-94.247.120.0/21
-94.247.137.0/24
-94.247.140.0/24
-94.247.208.0/22
-94.247.212.0/24
-94.247.240.0/20
-94.250.248.0/21
-94.251.0.0/17
-94.253.0.0/17
-94.255.0.0/17
-95.24.0.0/13
-95.32.0.0/16
-95.37.0.0/16
-95.52.0.0/14
-95.64.128.0/17
-95.66.128.0/17
-95.67.128.0/17
-95.68.128.0/17
-95.70.0.0/17
-95.71.0.0/16
-95.72.0.0/15
-95.78.0.0/15
-95.80.64.0/18
-95.81.72.0/22
-95.81.88.0/22
-95.81.96.0/21
-95.81.192.0/18
-95.82.192.0/18
-95.83.0.0/17
-95.83.128.0/18
-95.84.0.0/18
-95.84.128.0/17
-95.85.88.0/24
-95.86.192.0/18
-95.104.128.0/17
-95.105.0.0/17
-95.106.0.0/16
-95.107.0.0/17
-95.108.128.0/17
-95.110.0.0/17
-95.128.136.0/21
-95.128.160.0/21
-95.128.176.0/21
-95.128.224.0/21
-95.128.240.0/21
-95.129.56.0/21
-95.129.72.0/21
-95.129.88.0/21
-95.129.136.0/21
-95.129.144.0/21
-95.129.160.0/20
-95.129.176.0/21
-95.129.232.0/21
-95.130.128.0/21
-95.130.176.0/21
-95.130.229.0/24
-95.130.230.0/24
-95.131.0.0/20
-95.131.24.0/21
-95.131.72.0/21
-95.131.88.0/21
-95.131.144.0/21
-95.131.176.0/21
-95.131.204.0/24
-95.131.208.0/21
-95.131.224.0/21
-95.137.0.0/17
-95.138.224.0/19
-95.139.0.0/16
-95.140.16.0/20
-95.140.144.0/20
-95.141.0.0/20
-95.141.176.0/20
-95.141.192.0/20
-95.141.224.0/20
-95.142.32.0/20
-95.142.192.0/20
-95.143.0.0/19
-95.143.105.0/24
-95.143.108.0/24
-95.143.110.0/24
-95.143.112.0/20
-95.143.176.0/20
-95.143.208.0/20
-95.152.0.0/18
-95.153.128.0/17
-95.154.64.0/18
-95.154.128.0/18
-95.156.64.0/18
-95.156.251.0/24
-95.158.192.0/18
-95.159.128.0/18
-95.161.140.0/22
-95.161.144.0/20
-95.161.160.0/20
-95.161.176.0/21
-95.161.188.0/22
-95.161.192.0/22
-95.161.200.0/21
-95.161.208.0/20
-95.161.228.0/22
-95.161.232.0/21
-95.163.0.0/17
-95.163.128.0/20
-95.163.144.0/24
-95.163.146.0/23
-95.163.152.0/21
-95.163.176.0/20
-95.163.208.0/20
-95.163.224.0/19
-95.165.0.0/16
-95.167.0.0/16
-95.169.96.0/19
-95.169.128.0/19
-95.170.96.0/19
-95.170.128.0/18
-95.171.0.0/19
-95.171.224.0/19
-95.172.32.0/19
-95.172.96.0/19
-95.172.128.0/19
-95.173.128.0/19
-95.174.88.0/21
-95.174.192.0/19
-95.175.224.0/19
-95.179.0.0/17
-95.181.0.0/17
-95.181.128.0/21
-95.181.148.0/22
-95.181.152.0/21
-95.181.160.0/20
-95.181.176.0/21
-95.181.184.0/22
-95.181.192.0/20
-95.181.224.0/21
-95.181.248.0/21
-95.182.32.0/19
-95.183.8.0/21
-95.183.16.0/20
-95.183.32.0/20
-95.183.64.0/18
-95.188.0.0/14
-95.213.0.0/16
-95.214.56.0/21
-95.214.116.0/22
-95.215.0.0/22
-95.215.12.0/22
-95.215.48.0/22
-95.215.68.0/22
-95.215.84.0/22
-95.215.96.0/21
-95.215.108.0/22
-95.215.112.0/21
-95.215.124.0/22
-95.215.148.0/22
-95.215.152.0/22
-95.215.176.0/21
-95.215.208.0/22
-95.215.228.0/22
-95.215.238.0/23
-95.215.240.0/22
-95.215.248.0/21
-95.220.0.0/15
-103.58.41.0/24
-103.76.52.0/22
-103.228.2.0/24
-109.60.128.0/17
-109.61.128.0/17
-109.62.128.0/17
-109.63.128.0/17
-109.68.16.0/21
-109.68.72.0/21
-109.68.112.0/21
-109.68.136.0/21
-109.68.168.0/21
-109.68.184.0/21
-109.68.200.0/21
-109.68.208.0/21
-109.69.16.0/20
-109.69.72.0/21
-109.70.24.0/21
-109.70.75.0/24
-109.70.184.0/21
-109.70.248.0/21
-109.71.8.0/21
-109.71.158.0/24
-109.71.176.0/21
-109.71.192.0/20
-109.71.240.0/21
-109.72.64.0/20
-109.72.128.0/20
-109.72.224.0/19
-109.73.0.0/20
-109.73.32.0/20
-109.73.192.0/20
-109.74.112.0/20
-109.74.128.0/20
-109.74.160.0/20
-109.74.208.0/20
-109.75.128.0/20
-109.75.192.0/20
-109.75.240.0/20
-109.94.0.0/19
-109.94.64.0/19
-109.94.176.0/20
-109.94.192.0/20
-109.94.211.0/24
-109.94.220.0/22
-109.95.16.0/21
-109.95.72.0/21
-109.95.80.0/21
-109.95.96.0/20
-109.95.120.0/22
-109.95.160.0/21
-109.95.192.0/21
-109.95.208.0/20
-109.95.224.0/21
-109.95.248.0/21
-109.105.64.0/19
-109.105.160.0/19
-109.106.20.0/22
-109.106.128.0/19
-109.106.192.0/19
-109.107.146.0/24
-109.107.160.0/22
-109.107.168.0/22
-109.107.180.0/22
-109.107.188.0/22
-109.108.32.0/19
-109.109.208.0/20
-109.110.32.0/19
-109.110.64.0/19
-109.111.0.0/19
-109.111.64.0/19
-109.111.128.0/18
-109.120.0.0/18
-109.120.160.0/20
-109.120.180.0/22
-109.120.188.0/22
-109.122.192.0/21
-109.123.128.0/18
-109.124.0.0/17
-109.124.192.0/18
-109.126.0.0/18
-109.126.192.0/18
-109.127.128.0/18
-109.161.0.0/17
-109.163.216.0/21
-109.163.240.0/21
-109.165.0.0/17
-109.167.128.0/17
-109.168.128.0/17
-109.169.128.0/17
-109.170.0.0/17
-109.171.0.0/17
-109.172.0.0/21
-109.172.10.0/23
-109.172.12.0/22
-109.172.16.0/20
-109.172.32.0/19
-109.172.64.0/20
-109.172.80.0/21
-109.172.88.0/22
-109.172.94.0/23
-109.172.96.0/19
-109.173.0.0/17
-109.174.0.0/17
-109.184.0.0/16
-109.187.0.0/16
-109.188.0.0/16
-109.191.0.0/16
-109.194.0.0/15
-109.196.16.0/20
-109.196.64.0/20
-109.196.165.0/24
-109.196.167.0/24
-109.196.192.0/19
-109.197.8.0/21
-109.197.16.0/20
-109.197.48.0/21
-109.197.72.0/21
-109.197.88.0/21
-109.197.112.0/20
-109.197.128.0/19
-109.197.162.0/23
-109.197.192.0/20
-109.197.224.0/21
-109.197.248.0/21
-109.198.64.0/18
-109.198.160.0/19
-109.198.192.0/18
-109.200.96.0/19
-109.200.128.0/19
-109.201.64.0/18
-109.201.192.0/19
-109.202.0.0/18
-109.202.160.0/19
-109.203.192.0/19
-109.205.57.0/24
-109.205.80.0/21
-109.205.144.0/21
-109.205.248.0/21
-109.206.128.0/19
-109.207.0.0/20
-109.207.80.0/20
-109.207.160.0/21
-109.207.176.0/20
-109.207.224.0/20
-109.225.0.0/18
-109.225.192.0/18
-109.226.64.0/18
-109.226.192.0/18
-109.227.192.0/18
-109.229.32.0/19
-109.229.64.0/18
-109.229.128.0/19
-109.229.224.0/19
-109.230.128.0/18
-109.232.104.0/21
-109.232.184.0/21
-109.232.248.0/21
-109.233.168.0/21
-109.233.200.0/22
-109.233.208.0/21
-109.233.224.0/20
-109.233.240.0/21
-109.234.8.0/21
-109.234.24.0/21
-109.234.32.0/24
-109.234.128.0/21
-109.234.152.0/21
-109.235.24.0/21
-109.235.88.0/21
-109.235.160.0/21
-109.235.184.0/21
-109.235.208.0/20
-109.236.52.0/22
-109.236.56.0/22
-109.236.64.0/20
-109.236.96.0/20
-109.236.208.0/20
-109.236.224.0/19
-109.237.0.0/20
-109.237.96.0/20
-109.237.144.0/20
-109.237.224.0/20
-109.238.80.0/21
-109.238.88.0/22
-109.238.92.0/23
-109.238.96.0/20
-109.238.192.0/20
-109.238.240.0/20
-109.239.208.0/20
-109.252.0.0/16
-109.254.0.0/16
-111.88.78.0/24
-111.88.96.0/19
-111.88.128.0/21
-111.88.144.0/20
-111.88.160.0/21
-111.88.172.0/22
-111.88.176.0/21
-111.88.192.0/19
-111.88.224.0/21
-111.88.240.0/20
-128.0.24.0/21
-128.0.66.0/23
-128.0.80.0/20
-128.0.106.0/24
-128.0.128.0/20
-128.0.160.0/21
-128.65.136.0/21
-128.68.0.0/14
-128.72.0.0/14
-128.140.160.0/20
-128.140.192.0/21
-128.204.0.0/17
-128.204.160.0/19
-129.101.64.0/19
-130.0.216.0/21
-130.49.128.0/23
-130.49.132.0/22
-130.49.136.0/21
-130.49.144.0/21
-130.49.152.0/23
-130.49.154.0/24
-130.49.156.0/22
-130.49.164.0/22
-130.49.172.0/22
-130.49.176.0/20
-130.49.192.0/18
-130.193.32.0/19
-130.193.64.0/21
-130.193.73.0/24
-130.255.8.0/21
-130.255.32.0/19
-130.255.80.0/21
-130.255.128.0/20
-131.117.216.0/21
-131.222.134.0/23
-131.222.202.0/24
-132.243.176.0/21
-132.243.184.0/24
-132.243.190.0/23
-134.0.96.0/20
-134.0.112.0/21
-134.19.128.0/21
-134.19.144.0/20
-134.90.152.0/21
-134.90.160.0/19
-134.90.208.0/21
-134.255.128.0/19
-135.106.128.0/22
-135.106.132.0/23
-135.106.136.0/21
-135.106.144.0/20
-135.106.160.0/19
-135.106.192.0/18
-136.169.128.0/17
-136.234.0.0/18
-136.234.64.0/19
-136.234.96.0/20
-136.234.112.0/21
-136.234.120.0/22
-136.234.124.0/23
-136.234.126.0/24
-137.22.144.0/20
-138.16.128.0/21
-138.16.136.0/23
-138.16.140.0/22
-138.16.144.0/20
-138.16.160.0/19
-138.16.192.0/18
-139.28.52.0/22
-139.28.72.0/22
-139.28.168.0/22
-139.28.180.0/22
-139.45.224.0/19
-139.100.160.0/20
-139.100.192.0/18
-141.0.176.0/21
-141.8.128.0/18
-141.8.192.0/21
-141.98.28.0/22
-141.98.84.0/22
-141.98.168.0/22
-141.98.232.0/22
-141.101.151.0/24
-141.101.152.0/24
-141.101.201.0/24
-141.101.204.0/24
-141.101.228.0/24
-141.101.231.0/24
-141.105.24.0/21
-141.105.32.0/20
-141.105.48.0/21
-141.105.64.0/21
-141.133.128.0/22
-141.133.136.0/22
-141.133.176.0/20
-141.133.192.0/18
-141.136.112.0/21
-144.206.0.0/16
-145.249.0.0/16
-145.255.0.0/19
-145.255.32.0/20
-145.255.136.0/21
-145.255.232.0/21
-145.255.248.0/21
-146.19.13.0/24
-146.19.27.0/24
-146.19.58.0/23
-146.19.73.0/24
-146.19.78.0/24
-146.19.84.0/24
-146.19.91.0/24
-146.19.98.0/24
-146.19.115.0/24
-146.19.124.0/24
-146.19.142.0/24
-146.19.209.0/24
-146.19.211.0/24
-146.19.213.0/24
-146.19.233.0/24
-146.19.234.0/24
-146.19.242.0/24
-146.19.244.0/24
-146.19.253.0/24
-146.66.8.0/21
-146.66.160.0/19
-146.66.192.0/20
-146.185.192.0/20
-146.185.208.0/22
-146.185.212.0/23
-146.185.215.0/24
-146.185.218.0/24
-146.185.222.0/23
-146.185.224.0/21
-146.185.232.0/22
-146.185.238.0/23
-146.185.240.0/21
-146.185.252.0/22
-146.247.0.0/21
-146.247.32.0/21
-146.255.188.0/24
-146.255.192.0/19
-147.45.0.0/16
-147.78.8.0/22
-147.78.180.0/22
-147.78.188.0/22
-149.62.0.0/19
-149.62.48.0/21
-149.62.160.0/21
-149.126.16.0/21
-149.126.96.0/21
-149.126.168.0/21
-149.154.64.0/21
-149.154.104.0/21
-149.154.112.0/21
-149.154.128.0/20
-149.255.0.0/19
-149.255.112.0/21
-149.255.132.0/22
-149.255.160.0/21
-151.0.0.0/18
-151.236.64.0/18
-151.237.168.0/21
-151.237.240.0/21
-151.248.112.0/20
-151.252.64.0/19
-151.252.104.0/21
-152.89.108.0/22
-152.89.132.0/22
-152.89.196.0/24
-152.89.216.0/22
-153.51.32.0/19
-153.51.64.0/18
-153.51.160.0/19
-153.76.160.0/20
-153.76.178.0/23
-153.79.176.0/20
-153.80.172.0/22
-153.80.176.0/20
-153.80.224.0/19
-155.212.128.0/20
-155.212.144.0/21
-155.212.152.0/23
-155.212.156.0/22
-155.212.160.0/19
-155.212.192.0/20
-155.212.208.0/22
-155.212.214.0/23
-155.212.216.0/21
-155.212.224.0/21
-155.212.234.0/23
-155.212.236.0/22
-155.212.245.0/24
-155.212.246.0/23
-155.212.248.0/21
-157.22.152.0/22
-157.22.158.0/23
-157.22.160.0/19
-157.22.192.0/20
-157.22.216.0/22
-157.22.220.0/23
-157.22.224.0/21
-157.22.240.0/21
-157.22.248.0/22
-157.22.252.0/23
-157.22.254.0/24
-157.186.0.0/16
-157.228.73.0/24
-157.228.76.0/22
-157.228.96.0/23
-158.46.0.0/16
-158.58.128.0/21
-158.160.0.0/16
-158.250.0.0/16
-158.255.0.0/21
-158.255.48.0/21
-158.255.73.0/24
-158.255.75.0/24
-158.255.80.0/21
-158.255.128.0/18
-159.93.0.0/16
-159.194.192.0/24
-159.194.196.0/22
-159.194.200.0/21
-159.194.208.0/20
-159.194.224.0/19
-159.200.128.0/18
-159.200.200.0/23
-159.253.120.0/24
-159.253.168.0/21
-159.255.0.0/19
-159.255.64.0/18
-160.5.208.0/20
-160.20.156.0/22
-161.104.16.0/20
-161.104.32.0/19
-161.104.92.0/22
-161.104.96.0/20
-164.40.232.0/24
-164.138.32.0/21
-164.138.88.0/21
-164.138.100.0/22
-164.177.176.0/21
-164.215.48.0/21
-164.215.64.0/19
-168.113.128.0/18
-168.113.192.0/20
-168.113.208.0/21
-168.113.232.0/21
-168.113.240.0/20
-168.222.128.0/20
-168.222.176.0/22
-168.222.192.0/20
-168.222.224.0/21
-171.22.72.0/22
-171.22.180.0/22
-171.22.212.0/22
-171.22.236.0/22
-171.22.242.0/24
-171.25.164.0/22
-171.25.172.0/22
-171.25.177.0/24
-171.25.184.0/22
-171.25.188.0/23
-171.25.190.0/24
-171.25.194.0/23
-171.25.202.0/23
-171.25.212.0/22
-171.25.232.0/22
-171.25.242.0/23
-171.25.244.0/22
-171.25.248.0/21
-171.33.244.0/22
-171.33.248.0/21
-176.10.91.0/24
-176.10.93.0/24
-176.12.64.0/20
-176.12.96.0/21
-176.14.0.0/15
-176.28.64.0/21
-176.32.32.0/21
-176.32.128.0/19
-176.32.176.0/20
-176.32.240.0/21
-176.48.0.0/14
-176.52.0.0/17
-176.53.132.0/24
-176.53.146.0/23
-176.53.148.0/22
-176.53.152.0/22
-176.53.180.0/22
-176.53.192.0/20
-176.53.208.0/21
-176.53.224.0/19
-176.56.0.0/19
-176.56.32.0/24
-176.56.48.0/21
-176.57.64.0/22
-176.57.72.0/21
-176.57.208.0/20
-176.58.32.0/19
-176.59.0.0/16
-176.62.64.0/18
-176.62.176.0/20
-176.62.216.0/21
-176.62.240.0/20
-176.65.32.0/19
-176.65.96.0/19
-176.67.48.0/21
-176.67.240.0/21
-176.74.8.0/21
-176.74.200.0/21
-176.77.0.0/17
-176.96.0.0/19
-176.96.64.0/21
-176.96.80.0/21
-176.96.184.0/21
-176.97.32.0/20
-176.97.96.0/20
-176.97.128.0/21
-176.97.160.0/19
-176.97.193.0/24
-176.97.194.0/24
-176.98.48.0/21
-176.98.128.0/19
-176.98.168.0/21
-176.99.0.0/20
-176.99.56.0/21
-176.99.64.0/18
-176.99.128.0/17
-176.100.64.0/18
-176.100.128.0/19
-176.100.216.0/21
-176.100.240.0/20
-176.101.0.0/20
-176.101.64.0/21
-176.101.88.0/21
-176.101.96.0/19
-176.101.184.0/21
-176.101.224.0/19
-176.102.0.0/19
-176.102.68.0/22
-176.102.160.0/21
-176.103.96.0/20
-176.103.208.0/22
-176.104.120.0/21
-176.104.128.0/19
-176.104.160.0/20
-176.104.192.0/19
-176.105.234.0/24
-176.106.8.0/21
-176.106.16.0/20
-176.106.64.0/19
-176.106.128.0/21
-176.106.144.0/20
-176.106.232.0/21
-176.106.240.0/20
-176.107.0.0/20
-176.107.80.0/21
-176.107.96.0/21
-176.107.160.0/21
-176.107.200.0/21
-176.107.208.0/20
-176.107.224.0/19
-176.108.48.0/21
-176.108.144.0/20
-176.108.160.0/19
-176.108.192.0/19
-176.108.240.0/20
-176.109.0.0/19
-176.109.32.0/20
-176.109.64.0/18
-176.109.144.0/20
-176.109.176.0/20
-176.109.224.0/19
-176.110.64.0/19
-176.110.120.0/22
-176.110.127.0/24
-176.110.128.0/20
-176.110.160.0/19
-176.110.192.0/20
-176.110.208.0/21
-176.110.224.0/19
-176.111.8.0/21
-176.111.64.0/20
-176.111.96.0/21
-176.111.174.0/24
-176.111.208.0/21
-176.111.248.0/21
-176.112.32.0/19
-176.112.64.0/21
-176.112.88.0/21
-176.112.96.0/20
-176.112.128.0/20
-176.112.160.0/20
-176.112.192.0/18
-176.113.0.0/19
-176.113.32.0/21
-176.113.48.0/20
-176.113.88.0/22
-176.113.114.0/24
-176.113.117.0/24
-176.113.119.0/24
-176.113.120.0/21
-176.113.224.0/19
-176.114.16.0/20
-176.114.32.0/20
-176.114.48.0/21
-176.114.64.0/19
-176.114.112.0/20
-176.114.128.0/18
-176.114.192.0/19
-176.114.224.0/21
-176.115.32.0/19
-176.115.64.0/20
-176.115.88.0/21
-176.115.104.0/21
-176.115.112.0/20
-176.115.128.0/19
-176.115.160.0/21
-176.115.192.0/19
-176.116.0.0/24
-176.116.48.0/20
-176.116.136.0/21
-176.116.146.0/23
-176.116.160.0/19
-176.116.208.0/20
-176.116.240.0/20
-176.117.0.0/19
-176.117.32.0/20
-176.117.48.0/21
-176.117.112.0/20
-176.117.128.0/19
-176.117.192.0/18
-176.118.0.0/22
-176.118.8.0/21
-176.118.16.0/20
-176.118.32.0/24
-176.118.37.0/24
-176.118.64.0/20
-176.118.112.0/20
-176.118.128.0/21
-176.118.208.0/20
-176.118.224.0/19
-176.119.0.0/21
-176.119.16.0/21
-176.119.143.0/24
-176.119.147.0/24
-176.119.160.0/19
-176.119.197.0/24
-176.119.218.0/24
-176.119.240.0/21
-176.120.0.0/20
-176.120.21.0/24
-176.120.22.0/24
-176.120.68.0/22
-176.120.76.0/22
-176.120.80.0/20
-176.120.176.0/20
-176.120.192.0/18
-176.121.16.0/21
-176.121.48.0/22
-176.121.60.0/22
-176.121.128.0/18
-176.121.192.0/19
-176.122.16.0/20
-176.122.48.0/20
-176.122.64.0/20
-176.122.200.0/21
-176.122.247.0/24
-176.122.248.0/21
-176.123.49.0/24
-176.123.56.0/24
-176.123.128.0/19
-176.123.160.0/20
-176.123.188.0/22
-176.123.192.0/20
-176.123.216.0/22
-176.124.0.0/19
-176.124.116.0/22
-176.124.120.0/21
-176.124.136.0/23
-176.124.144.0/22
-176.124.150.0/23
-176.124.152.0/21
-176.124.160.0/21
-176.124.168.0/22
-176.124.188.0/23
-176.124.192.0/19
-176.124.226.0/23
-176.124.248.0/24
-176.125.64.0/18
-176.125.128.0/18
-176.125.192.0/19
-176.125.240.0/22
-176.126.0.0/19
-176.126.32.0/22
-176.126.36.0/24
-176.126.40.0/21
-176.126.48.0/21
-176.192.0.0/14
-176.196.0.0/15
-176.208.0.0/13
-176.221.0.0/19
-176.222.16.0/21
-176.222.192.0/20
-176.222.216.0/21
-176.222.240.0/20
-176.226.128.0/17
-176.227.176.0/20
-176.241.96.0/21
-176.241.192.0/19
-176.241.224.0/21
-178.16.80.0/20
-178.16.144.0/21
-178.16.152.0/22
-178.16.156.0/24
-178.16.158.0/23
-178.17.128.0/20
-178.17.176.0/20
-178.17.192.0/20
-178.18.0.0/20
-178.18.96.0/20
-178.18.208.0/20
-178.19.240.0/20
-178.20.40.0/21
-178.20.128.0/21
-178.20.232.0/21
-178.21.8.0/21
-178.21.24.0/21
-178.21.64.0/21
-178.22.24.0/24
-178.22.31.0/24
-178.22.40.0/21
-178.22.48.0/21
-178.22.88.0/21
-178.22.192.0/21
-178.23.0.0/21
-178.23.144.0/21
-178.23.224.0/21
-178.34.0.0/15
-178.44.0.0/14
-178.49.0.0/16
-178.57.0.0/18
-178.57.64.0/24
-178.57.69.0/24
-178.57.70.0/24
-178.57.72.0/21
-178.57.80.0/20
-178.57.96.0/19
-178.57.192.0/18
-178.64.0.0/13
-178.72.64.0/18
-178.72.128.0/18
-178.74.64.0/18
-178.74.128.0/18
-178.75.0.0/17
-178.76.192.0/18
-178.78.0.0/18
-178.129.0.0/16
-178.130.0.0/19
-178.130.32.0/21
-178.130.44.0/22
-178.130.48.0/20
-178.130.128.0/20
-178.132.96.0/21
-178.132.200.0/21
-178.140.0.0/15
-178.154.128.0/17
-178.155.0.0/17
-178.157.128.0/18
-178.158.0.0/17
-178.159.16.0/20
-178.159.32.0/23
-178.159.36.0/24
-178.159.40.0/23
-178.159.48.0/20
-178.159.80.0/20
-178.159.112.0/20
-178.159.248.0/21
-178.161.128.0/17
-178.162.0.0/17
-178.163.0.0/17
-178.166.128.0/17
-178.167.0.0/17
-178.169.32.0/19
-178.169.64.0/18
-178.170.164.0/23
-178.170.191.0/24
-178.170.192.0/22
-178.170.196.0/23
-178.170.198.0/24
-178.170.217.0/24
-178.170.218.0/23
-178.170.220.0/22
-178.170.224.0/23
-178.170.229.0/24
-178.170.242.0/24
-178.171.0.0/17
-178.173.0.0/17
-178.175.168.0/21
-178.176.0.0/14
-178.184.0.0/14
-178.204.0.0/14
-178.208.64.0/19
-178.208.128.0/19
-178.208.224.0/19
-178.209.88.0/21
-178.209.96.0/19
-178.209.192.0/18
-178.210.0.0/18
-178.210.64.0/19
-178.211.0.0/19
-178.211.153.0/24
-178.211.160.0/19
-178.212.8.0/21
-178.212.36.0/22
-178.212.64.0/21
-178.212.80.0/21
-178.212.128.0/21
-178.212.176.0/21
-178.212.208.0/21
-178.212.248.0/22
-178.213.8.0/21
-178.213.16.0/20
-178.213.32.0/21
-178.213.78.0/23
-178.213.80.0/21
-178.213.112.0/21
-178.213.144.0/21
-178.213.192.0/20
-178.213.208.0/21
-178.213.224.0/21
-178.213.240.0/20
-178.214.32.0/19
-178.214.160.0/19
-178.214.224.0/19
-178.215.64.0/18
-178.215.144.0/20
-178.215.232.0/22
-178.216.64.0/20
-178.216.96.0/21
-178.216.120.0/21
-178.216.152.0/21
-178.216.160.0/21
-178.216.172.0/23
-178.216.174.0/24
-178.216.176.0/21
-178.216.216.0/21
-178.216.232.0/21
-178.217.0.0/21
-178.217.24.0/21
-178.217.40.0/21
-178.217.48.0/20
-178.217.64.0/20
-178.217.96.0/22
-178.217.100.0/23
-178.217.103.0/24
-178.217.104.0/21
-178.217.120.0/21
-178.217.152.0/21
-178.217.160.0/21
-178.217.176.0/21
-178.217.200.0/21
-178.217.224.0/21
-178.218.0.0/18
-178.218.80.0/20
-178.218.96.0/19
-178.218.156.0/22
-178.218.208.0/20
-178.219.36.0/22
-178.219.40.0/21
-178.219.144.0/21
-178.219.152.0/23
-178.219.156.0/23
-178.219.158.0/24
-178.219.160.0/19
-178.219.192.0/19
-178.219.240.0/20
-178.234.0.0/16
-178.236.16.0/20
-178.236.128.0/20
-178.236.208.0/20
-178.236.240.0/20
-178.237.16.0/20
-178.237.60.0/22
-178.237.176.0/20
-178.237.192.0/20
-178.237.240.0/20
-178.238.16.0/20
-178.238.112.0/20
-178.248.64.0/21
-178.248.80.0/21
-178.248.232.0/21
-178.249.56.0/21
-178.249.64.0/20
-178.249.128.0/21
-178.249.240.0/21
-178.250.152.0/21
-178.250.240.0/21
-178.251.96.0/21
-178.251.136.0/21
-178.251.216.0/21
-178.252.64.0/18
-178.252.192.0/18
-178.255.120.0/21
-178.255.232.0/21
-178.255.248.0/21
-185.0.12.0/22
-185.0.44.0/22
-185.1.0.0/24
-185.1.13.0/24
-185.1.19.0/24
-185.1.23.0/24
-185.1.41.0/24
-185.1.64.0/24
-185.1.67.0/24
-185.1.72.0/24
-185.1.76.0/24
-185.1.81.0/24
-185.1.117.0/24
-185.1.118.0/24
-185.1.162.0/24
-185.1.165.0/24
-185.2.72.0/22
-185.2.88.0/22
-185.2.104.0/22
-185.2.124.0/22
-185.2.184.0/22
-185.3.16.0/22
-185.3.32.0/22
-185.3.68.0/22
-185.3.140.0/22
-185.3.172.0/22
-185.3.180.0/22
-185.3.240.0/22
-185.4.56.0/22
-185.4.108.0/22
-185.4.144.0/22
-185.4.204.0/22
-185.5.16.0/22
-185.5.136.0/21
-185.5.148.0/22
-185.5.160.0/22
-185.5.192.0/22
-185.5.204.0/23
-185.6.44.0/22
-185.6.80.0/22
-185.6.116.0/22
-185.6.124.0/22
-185.6.164.0/22
-185.6.172.0/22
-185.6.216.0/22
-185.6.228.0/22
-185.6.236.0/22
-185.6.244.0/22
-185.6.248.0/22
-185.7.28.0/22
-185.7.40.0/22
-185.7.48.0/22
-185.7.84.0/22
-185.7.92.0/22
-185.7.116.0/22
-185.7.144.0/22
-185.7.152.0/22
-185.7.180.0/22
-185.7.200.0/22
-185.7.232.0/22
-185.8.4.0/22
-185.8.20.0/22
-185.8.124.0/22
-185.8.156.0/22
-185.8.200.0/22
-185.8.216.0/21
-185.9.72.0/21
-185.9.80.0/21
-185.9.144.0/22
-185.9.160.0/22
-185.9.200.0/21
-185.9.228.0/22
-185.10.0.0/22
-185.10.44.0/22
-185.10.60.0/22
-185.10.94.0/24
-185.10.128.0/22
-185.10.152.0/22
-185.10.172.0/22
-185.10.180.0/22
-185.10.184.0/22
-185.11.4.0/22
-185.11.32.0/22
-185.11.48.0/22
-185.11.72.0/22
-185.11.132.0/22
-185.11.148.0/22
-185.11.196.0/22
-185.11.228.0/22
-185.11.244.0/22
-185.12.28.0/22
-185.12.52.0/22
-185.12.68.0/22
-185.12.84.0/22
-185.12.92.0/22
-185.12.124.0/22
-185.12.152.0/22
-185.12.208.0/22
-185.12.224.0/21
-185.12.252.0/22
-185.13.0.0/22
-185.13.24.0/22
-185.13.44.0/22
-185.13.84.0/24
-185.13.112.0/21
-185.13.120.0/22
-185.13.132.0/22
-185.13.136.0/22
-185.13.160.0/22
-185.13.176.0/22
-185.14.4.0/22
-185.14.16.0/22
-185.14.32.0/22
-185.14.40.0/22
-185.14.46.0/24
-185.14.68.0/22
-185.15.36.0/22
-185.15.60.0/22
-185.15.84.0/22
-185.15.88.0/22
-185.15.96.0/22
-185.15.116.0/22
-185.15.172.0/22
-185.15.188.0/22
-185.16.8.0/22
-185.16.28.0/22
-185.16.56.0/22
-185.16.64.0/22
-185.16.100.0/22
-185.16.104.0/22
-185.16.116.0/22
-185.16.136.0/22
-185.16.148.0/22
-185.16.176.0/22
-185.16.212.0/22
-185.16.244.0/22
-185.17.8.0/22
-185.17.16.0/22
-185.17.28.0/22
-185.17.36.0/22
-185.17.76.0/22
-185.17.84.0/22
-185.17.88.0/22
-185.17.120.0/22
-185.17.128.0/21
-185.17.140.0/22
-185.17.152.0/22
-185.17.168.0/22
-185.17.200.0/22
-185.18.4.0/22
-185.18.20.0/22
-185.18.44.0/22
-185.18.88.0/22
-185.18.108.0/22
-185.18.112.0/21
-185.18.124.0/22
-185.18.200.0/22
-185.19.20.0/22
-185.19.204.0/22
-185.20.44.0/22
-185.20.76.0/22
-185.20.80.0/22
-185.20.132.0/22
-185.20.176.0/21
-185.20.224.0/22
-185.21.49.0/24
-185.21.64.0/22
-185.21.156.0/22
-185.22.24.0/22
-185.22.60.0/22
-185.22.152.0/22
-185.22.180.0/22
-185.22.204.0/22
-185.22.232.0/22
-185.23.8.0/22
-185.23.32.0/22
-185.23.64.0/22
-185.23.80.0/22
-185.23.228.0/22
-185.24.40.0/21
-185.24.52.0/22
-185.24.56.0/22
-185.24.92.0/22
-185.24.108.0/22
-185.24.112.0/22
-185.24.176.0/21
-185.24.212.0/22
-185.24.244.0/22
-185.25.4.0/22
-185.25.8.0/22
-185.25.16.0/22
-185.25.60.0/22
-185.25.68.0/22
-185.25.88.0/22
-185.25.152.0/22
-185.25.176.0/22
-185.26.28.0/22
-185.26.40.0/22
-185.26.52.0/22
-185.26.100.0/22
-185.26.112.0/22
-185.26.120.0/22
-185.26.168.0/22
-185.26.192.0/22
-185.26.204.0/22
-185.26.212.0/23
-185.26.216.0/22
-185.27.48.0/22
-185.27.80.0/22
-185.27.100.0/22
-185.27.148.0/22
-185.27.160.0/22
-185.27.192.0/22
-185.27.208.0/22
-185.28.108.0/22
-185.28.236.0/22
-185.29.52.0/22
-185.29.56.0/22
-185.29.124.0/22
-185.29.128.0/22
-185.30.12.0/22
-185.30.16.0/22
-185.30.40.0/22
-185.30.96.0/22
-185.30.104.0/22
-185.30.116.0/22
-185.30.176.0/22
-185.30.192.0/22
-185.30.220.0/22
-185.30.228.0/22
-185.31.11.0/24
-185.31.108.0/22
-185.31.112.0/21
-185.31.132.0/22
-185.31.160.0/21
-185.31.192.0/22
-185.31.201.0/24
-185.32.56.0/22
-185.32.84.0/22
-185.32.120.0/22
-185.32.132.0/22
-185.32.164.0/22
-185.32.184.0/22
-185.32.248.0/22
-185.33.120.0/22
-185.33.140.0/22
-185.33.160.0/22
-185.33.172.0/22
-185.33.196.0/22
-185.33.200.0/22
-185.33.228.0/22
-185.33.236.0/22
-185.33.244.0/22
-185.34.20.0/22
-185.34.152.0/22
-185.34.180.0/22
-185.34.240.0/21
-185.35.0.0/21
-185.35.36.0/22
-185.35.40.0/21
-185.35.116.0/22
-185.35.120.0/22
-185.35.128.0/22
-185.35.160.0/22
-185.35.168.0/22
-185.35.192.0/22
-185.36.23.0/24
-185.36.60.0/22
-185.36.100.0/24
-185.36.104.0/22
-185.36.156.0/22
-185.36.172.0/22
-185.37.48.0/22
-185.37.56.0/21
-185.37.128.0/22
-185.37.164.0/22
-185.37.188.0/22
-185.38.16.0/22
-185.38.84.0/22
-185.38.160.0/22
-185.38.204.0/22
-185.39.4.0/22
-185.39.80.0/22
-185.39.112.0/21
-185.39.132.0/22
-185.39.192.0/22
-185.39.204.0/22
-185.40.0.0/22
-185.40.28.0/22
-185.40.40.0/22
-185.40.76.0/22
-185.40.105.0/24
-185.40.128.0/22
-185.40.152.0/22
-185.41.40.0/22
-185.41.100.0/22
-185.41.112.0/22
-185.41.120.0/22
-185.41.160.0/22
-185.41.168.0/22
-185.41.184.0/22
-185.41.196.0/22
-185.41.204.0/22
-185.42.24.0/22
-185.42.40.0/22
-185.42.48.0/22
-185.42.60.0/22
-185.42.76.0/22
-185.42.80.0/22
-185.42.88.0/21
-185.42.108.0/22
-185.42.124.0/22
-185.42.144.0/22
-185.42.156.0/22
-185.42.163.0/24
-185.42.164.0/22
-185.42.180.0/22
-185.42.228.0/22
-185.43.4.0/22
-185.43.84.0/22
-185.43.92.0/22
-185.43.100.0/22
-185.43.144.0/23
-185.43.196.0/22
-185.44.0.0/22
-185.44.8.0/21
-185.44.68.0/22
-185.44.120.0/22
-185.44.164.0/22
-185.44.236.0/22
-185.45.60.0/22
-185.45.80.0/22
-185.45.100.0/22
-185.45.144.0/22
-185.46.8.0/21
-185.46.16.0/22
-185.46.44.0/22
-185.46.48.0/22
-185.46.96.0/22
-185.46.152.0/22
-185.46.196.0/22
-185.47.36.0/22
-185.47.52.0/22
-185.47.154.0/23
-185.47.165.0/24
-185.47.204.0/22
-185.48.16.0/22
-185.48.36.0/22
-185.48.56.0/22
-185.48.72.0/22
-185.48.112.0/22
-185.48.236.0/22
-185.49.64.0/22
-185.49.108.0/22
-185.49.240.0/22
-185.50.7.0/24
-185.50.8.0/22
-185.50.24.0/22
-185.50.80.0/22
-185.50.136.0/22
-185.50.156.0/22
-185.50.200.0/22
-185.50.216.0/22
-185.51.21.0/24
-185.51.124.0/22
-185.51.140.0/22
-185.51.156.0/22
-185.51.208.0/22
-185.52.28.0/22
-185.52.56.0/22
-185.52.68.0/22
-185.52.72.0/21
-185.52.132.0/22
-185.52.140.0/22
-185.52.152.0/22
-185.53.20.0/22
-185.53.104.0/22
-185.53.232.0/22
-185.53.251.0/24
-185.54.20.0/22
-185.54.40.0/22
-185.54.48.0/22
-185.54.136.0/22
-185.54.176.0/22
-185.54.236.0/22
-185.54.244.0/22
-185.55.0.0/22
-185.55.40.0/22
-185.55.56.0/22
-185.55.172.0/22
-185.56.116.0/22
-185.57.28.0/22
-185.57.236.0/22
-185.57.248.0/22
-185.58.112.0/22
-185.58.124.0/22
-185.58.152.0/22
-185.58.188.0/22
-185.58.216.0/21
-185.58.248.0/21
-185.59.56.0/22
-185.59.136.0/21
-185.59.172.0/22
-185.59.192.0/22
-185.59.216.0/23
-185.59.218.0/24
-185.59.232.0/22
-185.59.244.0/22
-185.60.12.0/22
-185.60.44.0/22
-185.60.48.0/22
-185.60.132.0/22
-185.60.152.0/22
-185.60.212.0/22
-185.61.24.0/22
-185.61.36.0/22
-185.61.76.0/22
-185.61.92.0/22
-185.61.128.0/22
-185.61.172.0/22
-185.61.192.0/22
-185.61.216.0/21
-185.61.244.0/22
-185.61.252.0/22
-185.62.100.0/22
-185.62.192.0/22
-185.62.200.0/22
-185.62.229.0/24
-185.63.60.0/22
-185.63.188.0/22
-185.63.196.0/22
-185.63.216.0/22
-185.64.7.0/24
-185.64.44.0/22
-185.64.52.0/22
-185.64.76.0/24
-185.64.208.0/22
-185.64.228.0/22
-185.65.12.0/22
-185.65.16.0/21
-185.65.138.0/23
-185.65.148.0/22
-185.65.200.0/22
-185.66.12.0/22
-185.66.28.0/22
-185.66.84.0/22
-185.66.216.0/22
-185.67.52.0/22
-185.67.92.0/22
-185.67.160.0/21
-185.67.168.0/22
-185.67.244.0/22
-185.68.80.0/22
-185.68.92.0/22
-185.68.100.0/22
-185.68.116.0/22
-185.68.144.0/22
-185.68.152.0/22
-185.68.184.0/22
-185.68.244.0/22
-185.69.80.0/22
-185.69.124.0/22
-185.69.132.0/22
-185.69.220.0/22
-185.70.104.0/22
-185.70.128.0/22
-185.70.164.0/22
-185.71.52.0/22
-185.71.64.0/21
-185.71.76.0/22
-185.71.80.0/22
-185.71.96.0/22
-185.71.144.0/22
-185.71.196.0/22
-185.71.212.0/22
-185.72.144.0/22
-185.72.188.0/22
-185.72.224.0/21
-185.73.16.0/22
-185.73.180.0/22
-185.73.192.0/22
-185.73.212.0/22
-185.73.216.0/22
-185.74.104.0/22
-185.74.228.0/22
-185.75.4.0/22
-185.75.44.0/22
-185.75.64.0/22
-185.75.84.0/22
-185.75.88.0/22
-185.75.132.0/22
-185.75.180.0/22
-185.75.188.0/22
-185.75.220.0/23
-185.75.248.0/22
-185.76.80.0/22
-185.76.108.0/22
-185.76.144.0/22
-185.76.220.0/22
-185.76.232.0/22
-185.76.240.0/22
-185.76.252.0/22
-185.77.8.0/22
-185.77.16.0/22
-185.77.136.0/22
-185.77.148.0/22
-185.77.204.0/22
-185.77.216.0/21
-185.77.228.0/22
-185.77.232.0/21
-185.77.240.0/22
-185.78.28.0/22
-185.78.32.0/22
-185.78.76.0/22
-185.78.92.0/22
-185.78.108.0/22
-185.78.112.0/21
-185.78.236.0/22
-185.79.48.0/22
-185.79.68.0/22
-185.79.76.0/22
-185.79.100.0/22
-185.79.116.0/22
-185.79.132.0/22
-185.79.136.0/22
-185.79.236.0/22
-185.80.28.0/24
-185.80.148.0/22
-185.80.204.0/22
-185.80.228.0/22
-185.80.248.0/22
-185.81.24.0/22
-185.81.64.0/22
-185.81.144.0/22
-185.81.172.0/22
-185.81.184.0/22
-185.81.220.0/22
-185.81.248.0/22
-185.82.12.0/22
-185.82.24.0/22
-185.82.176.0/22
-185.82.196.0/22
-185.82.244.0/22
-185.83.240.0/22
-185.84.32.0/22
-185.84.40.0/22
-185.84.108.0/22
-185.84.172.0/22
-185.84.184.0/21
-185.84.244.0/22
-185.85.160.0/22
-185.85.216.0/22
-185.86.112.0/20
-185.86.132.0/22
-185.86.144.0/22
-185.87.192.0/21
-185.88.36.0/22
-185.88.96.0/21
-185.88.124.0/22
-185.88.156.0/22
-185.88.160.0/22
-185.88.208.0/22
-185.89.8.0/21
-185.89.40.0/22
-185.89.99.0/24
-185.89.104.0/21
-185.90.100.0/22
-185.90.144.0/22
-185.90.224.0/22
-185.91.52.0/22
-185.91.125.0/24
-185.91.176.0/21
-185.91.252.0/22
-185.92.32.0/22
-185.92.136.0/21
-185.92.144.0/22
-185.92.184.0/22
-185.93.40.0/22
-185.93.108.0/22
-185.93.208.0/22
-185.93.252.0/22
-185.94.31.0/24
-185.94.32.0/22
-185.94.108.0/22
-185.94.152.0/22
-185.94.172.0/22
-185.94.182.0/24
-185.94.212.0/22
-185.94.224.0/22
-185.95.66.0/24
-185.95.100.0/22
-185.95.104.0/22
-185.95.228.0/22
-185.96.0.0/22
-185.96.36.0/22
-185.96.80.0/21
-185.96.132.0/22
-185.97.0.0/22
-185.97.76.0/22
-185.97.164.0/22
-185.97.200.0/22
-185.97.252.0/22
-185.98.40.0/22
-185.98.80.0/21
-185.99.4.0/22
-185.99.8.0/21
-185.99.140.0/23
-185.99.152.0/21
-185.99.160.0/22
-185.99.168.0/22
-185.100.24.0/22
-185.100.100.0/22
-185.100.104.0/22
-185.100.156.0/22
-185.101.24.0/22
-185.101.137.0/24
-185.101.200.0/21
-185.102.8.0/22
-185.102.112.0/22
-185.102.120.0/22
-185.102.180.0/22
-185.103.24.0/22
-185.103.60.0/22
-185.103.68.0/22
-185.103.100.0/22
-185.103.132.0/22
-185.103.160.0/21
-185.103.200.0/24
-185.104.4.0/22
-185.104.92.0/22
-185.104.104.0/22
-185.104.112.0/22
-185.104.148.0/22
-185.104.212.0/22
-185.105.44.0/22
-185.105.48.0/22
-185.105.108.0/22
-185.105.168.0/22
-185.105.224.0/22
-185.106.40.0/22
-185.106.56.0/22
-185.106.104.0/23
-185.106.107.0/24
-185.106.116.0/24
-185.106.172.0/22
-185.106.196.0/22
-185.107.72.0/22
-185.107.124.0/22
-185.107.128.0/22
-185.107.136.0/22
-185.107.156.0/22
-185.107.164.0/22
-185.107.240.0/22
-185.107.252.0/22
-185.108.0.0/21
-185.108.16.0/21
-185.108.88.0/22
-185.108.160.0/22
-185.108.192.0/21
-185.108.208.0/21
-185.108.220.0/22
-185.109.112.0/22
-185.109.160.0/24
-185.109.204.0/22
-185.109.208.0/22
-185.110.44.0/22
-185.110.56.0/22
-185.110.128.0/22
-185.110.168.0/22
-185.110.208.0/22
-185.111.24.0/22
-185.111.48.0/22
-185.111.84.0/22
-185.111.100.0/22
-185.111.164.0/22
-185.111.216.0/22
-185.112.56.0/22
-185.112.75.0/24
-185.112.120.0/22
-185.112.140.0/22
-185.112.224.0/22
-185.112.236.0/22
-185.112.250.0/24
-185.113.72.0/21
-185.113.108.0/22
-185.113.116.0/22
-185.113.136.0/22
-185.113.200.0/22
-185.113.208.0/22
-185.113.244.0/22
-185.114.244.0/22
-185.115.92.0/22
-185.115.96.0/22
-185.115.140.0/22
-185.115.156.0/22
-185.116.119.0/24
-185.116.196.0/22
-185.116.200.0/22
-185.116.228.0/22
-185.117.28.0/22
-185.117.100.0/22
-185.117.140.0/22
-185.117.144.0/22
-185.117.156.0/22
-185.117.232.0/22
-185.117.244.0/22
-185.118.64.0/22
-185.118.126.0/24
-185.118.164.0/22
-185.119.0.0/22
-185.119.56.0/22
-185.119.64.0/22
-185.120.56.0/22
-185.120.88.0/22
-185.120.184.0/21
-185.121.72.0/22
-185.121.84.0/22
-185.121.244.0/22
-185.122.28.0/22
-185.122.204.0/24
-185.123.12.0/22
-185.123.40.0/21
-185.123.64.0/22
-185.123.76.0/22
-185.123.164.0/22
-185.123.172.0/22
-185.123.192.0/22
-185.124.12.0/22
-185.124.64.0/24
-185.124.152.0/22
-185.124.164.0/22
-185.124.176.0/22
-185.124.188.0/22
-185.124.208.0/22
-185.124.228.0/22
-185.125.16.0/22
-185.125.44.0/22
-185.125.56.0/22
-185.125.72.0/22
-185.125.100.0/22
-185.125.112.0/22
-185.125.140.0/24
-185.125.200.0/22
-185.126.84.0/22
-185.126.92.0/22
-185.126.128.0/22
-185.126.180.0/22
-185.126.192.0/22
-185.127.148.0/22
-185.127.224.0/22
-185.127.244.0/22
-185.128.4.0/22
-185.128.84.0/22
-185.128.196.0/22
-185.129.56.0/22
-185.129.96.0/21
-185.129.128.0/22
-185.129.144.0/22
-185.129.204.0/22
-185.130.80.0/22
-185.130.112.0/22
-185.130.212.0/22
-185.130.232.0/22
-185.130.248.0/22
-185.131.68.0/22
-185.131.172.0/22
-185.132.20.0/22
-185.132.28.0/22
-185.132.196.0/22
-185.132.240.0/22
-185.133.0.0/22
-185.133.40.0/22
-185.134.32.0/21
-185.134.72.0/22
-185.134.120.0/22
-185.134.148.0/22
-185.134.204.0/22
-185.134.232.0/22
-185.135.44.0/24
-185.135.80.0/22
-185.135.148.0/22
-185.135.172.0/22
-185.135.180.0/22
-185.135.232.0/22
-185.136.76.0/22
-185.136.184.0/22
-185.137.76.0/22
-185.137.160.0/22
-185.137.176.0/22
-185.137.232.0/22
-185.138.8.0/22
-185.138.76.0/22
-185.138.88.0/22
-185.138.128.0/22
-185.138.160.0/22
-185.138.180.0/22
-185.138.200.0/21
-185.138.252.0/22
-185.139.108.0/22
-185.139.212.0/22
-185.140.132.0/22
-185.140.148.0/22
-185.140.175.0/24
-185.141.40.0/22
-185.141.76.0/22
-185.141.92.0/22
-185.141.124.0/22
-185.141.180.0/22
-185.141.224.0/22
-185.141.232.0/21
-185.142.64.0/22
-185.142.96.0/22
-185.142.128.0/23
-185.143.108.0/22
-185.143.172.0/22
-185.143.236.0/24
-185.144.28.0/22
-185.144.60.0/22
-185.144.114.0/24
-185.144.136.0/22
-185.144.200.0/22
-185.145.56.0/22
-185.145.124.0/22
-185.145.140.0/22
-185.146.72.0/22
-185.146.116.0/22
-185.146.156.0/22
-185.146.168.0/22
-185.146.212.0/22
-185.147.39.0/24
-185.147.80.0/22
-185.148.36.0/22
-185.148.80.0/22
-185.148.104.0/22
-185.148.208.0/22
-185.148.216.0/21
-185.149.48.0/22
-185.149.64.0/22
-185.149.96.0/22
-185.149.124.0/22
-185.149.144.0/22
-185.149.160.0/22
-185.149.194.0/24
-185.149.196.0/22
-185.149.240.0/21
-185.150.12.0/22
-185.150.152.0/22
-185.151.120.0/22
-185.151.128.0/22
-185.151.240.0/22
-185.152.80.0/22
-185.152.92.0/22
-185.152.132.0/22
-185.152.184.0/22
-185.153.44.0/22
-185.153.92.0/22
-185.153.132.0/22
-185.153.240.0/22
-185.154.20.0/22
-185.154.52.0/22
-185.154.72.0/22
-185.154.120.0/21
-185.154.192.0/22
-185.154.200.0/22
-185.155.16.0/22
-185.155.112.0/22
-185.155.118.0/24
-185.156.0.0/22
-185.156.72.0/22
-185.156.176.0/21
-185.157.96.0/22
-185.157.120.0/24
-185.157.124.0/22
-185.157.188.0/22
-185.157.252.0/22
-185.158.112.0/22
-185.158.152.0/22
-185.159.44.0/22
-185.159.64.0/22
-185.159.111.0/24
-185.159.128.0/22
-185.159.148.0/22
-185.159.164.0/22
-185.159.172.0/22
-185.160.36.0/22
-185.160.136.0/22
-185.160.188.0/22
-185.160.216.0/22
-185.161.32.0/22
-185.161.52.0/22
-185.161.60.0/22
-185.161.64.0/22
-185.161.180.0/22
-185.161.196.0/22
-185.161.251.0/24
-185.162.12.0/22
-185.162.32.0/22
-185.162.92.0/22
-185.162.188.0/22
-185.162.204.0/22
-185.162.232.0/23
-185.162.235.0/24
-185.163.156.0/22
-185.163.176.0/22
-185.163.236.0/22
-185.163.240.0/22
-185.164.148.0/23
-185.164.150.0/24
-185.164.162.0/24
-185.164.172.0/24
-185.165.112.0/22
-185.165.120.0/22
-185.165.160.0/22
-185.165.200.0/22
-185.165.216.0/22
-185.165.224.0/22
-185.166.2.0/24
-185.166.16.0/22
-185.166.72.0/22
-185.166.196.0/22
-185.166.240.0/22
-185.167.120.0/22
-185.167.224.0/22
-185.168.60.0/22
-185.168.184.0/22
-185.168.208.0/22
-185.168.236.0/22
-185.169.100.0/22
-185.169.152.0/22
-185.169.216.0/22
-185.170.0.0/22
-185.170.10.0/24
-185.170.52.0/22
-185.170.204.0/22
-185.171.12.0/22
-185.171.80.0/22
-185.171.100.0/22
-185.171.192.0/22
-185.171.203.0/24
-185.172.136.0/22
-185.173.0.0/22
-185.173.36.0/22
-185.173.72.0/22
-185.173.80.0/22
-185.173.92.0/22
-185.173.112.0/22
-185.173.176.0/22
-185.174.128.0/22
-185.174.164.0/22
-185.174.192.0/22
-185.175.16.0/22
-185.175.44.0/22
-185.175.72.0/22
-185.175.116.0/22
-185.175.128.0/22
-185.175.156.0/22
-185.175.172.0/22
-185.175.224.0/22
-185.176.24.0/22
-185.177.96.0/22
-185.177.108.0/22
-185.177.112.0/22
-185.177.216.0/21
-185.177.236.0/22
-185.178.44.0/22
-185.178.128.0/22
-185.178.204.0/22
-185.178.208.0/22
-185.178.244.0/22
-185.179.0.0/21
-185.179.36.0/22
-185.179.72.0/22
-185.179.84.0/22
-185.179.144.0/22
-185.179.160.0/22
-185.179.172.0/22
-185.179.188.0/22
-185.179.196.0/24
-185.179.224.0/22
-185.180.40.0/22
-185.180.56.0/22
-185.180.108.0/22
-185.180.124.0/22
-185.180.160.0/22
-185.180.176.0/22
-185.180.188.0/22
-185.180.200.0/22
-185.180.212.0/22
-185.180.236.0/22
-185.180.248.0/22
-185.181.200.0/22
-185.181.244.0/22
-185.182.16.0/22
-185.182.104.0/24
-185.182.108.0/22
-185.182.128.0/22
-185.183.12.0/22
-185.183.48.0/22
-185.183.76.0/22
-185.183.160.0/22
-185.183.172.0/22
-185.183.196.0/22
-185.184.54.0/23
-185.184.76.0/24
-185.184.79.0/24
-185.184.128.0/22
-185.184.232.0/22
-185.185.0.0/22
-185.185.20.0/22
-185.185.56.0/22
-185.185.68.0/22
-185.185.104.0/22
-185.185.120.0/22
-185.185.136.0/21
-185.185.144.0/21
-185.185.180.0/22
-185.186.2.0/23
-185.186.140.0/22
-185.186.184.0/22
-185.186.192.0/22
-185.186.232.0/22
-185.187.63.0/24
-185.187.89.0/24
-185.187.90.0/23
-185.187.112.0/22
-185.187.188.0/22
-185.187.199.0/24
-185.188.96.0/22
-185.189.16.0/22
-185.189.100.0/22
-185.189.132.0/22
-185.189.164.0/24
-185.189.167.0/24
-185.189.195.0/24
-185.190.0.0/21
-185.190.40.0/22
-185.190.104.0/22
-185.190.116.0/22
-185.190.120.0/22
-185.190.164.0/22
-185.190.180.0/22
-185.190.184.0/21
-185.191.32.0/22
-185.191.56.0/22
-185.191.196.0/22
-185.192.108.0/24
-185.192.111.0/24
-185.193.20.0/22
-185.193.46.0/24
-185.193.88.0/22
-185.193.136.0/24
-185.193.139.0/24
-185.193.141.0/24
-185.193.196.0/22
-185.193.204.0/22
-185.193.248.0/22
-185.194.32.0/22
-185.194.107.0/24
-185.195.144.0/22
-185.195.152.0/22
-185.195.169.0/24
-185.195.170.0/23
-185.195.188.0/22
-185.195.243.0/24
-185.196.31.0/24
-185.196.116.0/24
-185.196.119.0/24
-185.196.168.0/22
-185.196.184.0/22
-185.196.236.0/22
-185.196.244.0/22
-185.197.12.0/22
-185.197.32.0/22
-185.197.72.0/22
-185.197.232.0/22
-185.198.40.0/22
-185.198.69.0/24
-185.198.152.0/24
-185.199.4.0/22
-185.199.8.0/22
-185.199.144.0/22
-185.199.160.0/22
-185.200.16.0/22
-185.200.120.0/24
-185.200.140.0/22
-185.200.152.0/22
-185.200.160.0/22
-185.200.168.0/23
-185.200.171.0/24
-185.200.216.0/22
-185.200.240.0/22
-185.201.44.0/23
-185.201.47.0/24
-185.201.52.0/22
-185.201.88.0/22
-185.202.0.0/22
-185.202.12.0/22
-185.202.109.0/24
-185.202.212.0/22
-185.203.72.0/22
-185.203.96.0/22
-185.203.144.0/22
-185.204.20.0/22
-185.204.110.0/24
-185.204.124.0/22
-185.204.156.0/22
-185.205.64.0/22
-185.205.76.0/22
-185.205.128.0/22
-185.205.236.0/22
-185.206.100.0/22
-185.206.164.0/22
-185.206.204.0/22
-185.207.0.0/23
-185.207.2.0/24
-185.207.22.0/24
-185.207.24.0/22
-185.207.64.0/22
-185.207.88.0/22
-185.207.252.0/22
-185.208.72.0/22
-185.208.157.0/24
-185.208.192.0/22
-185.209.24.0/21
-185.209.44.0/22
-185.209.112.0/22
-185.209.240.0/24
-185.210.44.0/22
-185.210.56.0/22
-185.210.140.0/22
-185.210.240.0/22
-185.211.0.0/22
-185.211.112.0/22
-185.211.156.0/22
-185.211.164.0/22
-185.211.224.0/22
-185.211.240.0/21
-185.212.0.0/22
-185.212.28.0/22
-185.212.88.0/22
-185.212.112.0/24
-185.212.116.0/23
-185.213.28.0/22
-185.213.136.0/22
-185.213.156.0/22
-185.213.212.0/22
-185.214.56.0/21
-185.214.76.0/22
-185.214.160.0/22
-185.214.184.0/22
-185.214.244.0/22
-185.214.252.0/22
-185.215.4.0/24
-185.215.60.0/22
-185.215.176.0/22
-185.216.16.0/22
-185.216.60.0/22
-185.216.80.0/22
-185.216.100.0/22
-185.216.192.0/22
-185.216.204.0/22
-185.216.244.0/22
-185.217.7.0/24
-185.217.128.0/24
-185.217.167.0/24
-185.218.8.0/22
-185.218.68.0/22
-185.218.108.0/22
-185.218.180.0/22
-185.218.205.0/24
-185.219.4.0/24
-185.219.40.0/22
-185.220.32.0/21
-185.220.40.0/22
-185.221.44.0/22
-185.221.116.0/22
-185.221.120.0/22
-185.221.152.0/22
-185.221.164.0/22
-185.221.196.0/22
-185.221.212.0/22
-185.222.52.0/22
-185.222.152.0/22
-185.222.236.0/22
-185.223.116.0/22
-185.223.212.0/24
-185.224.8.0/22
-185.224.31.0/24
-185.224.96.0/22
-185.224.212.0/24
-185.224.228.0/22
-185.225.32.0/22
-185.225.152.0/22
-185.225.176.0/22
-185.225.200.0/23
-185.226.52.0/22
-185.226.128.0/22
-185.226.244.0/22
-185.227.36.0/22
-185.227.84.0/22
-185.228.48.0/22
-185.228.112.0/22
-185.228.132.0/22
-185.228.232.0/22
-185.228.248.0/24
-185.229.8.0/22
-185.229.122.0/23
-185.229.184.0/22
-185.229.192.0/22
-185.229.205.0/24
-185.229.232.0/22
-185.230.140.0/22
-185.230.188.0/22
-185.231.48.0/22
-185.231.56.0/24
-185.231.152.0/22
-185.231.204.0/22
-185.231.232.0/24
-185.231.244.0/22
-185.232.16.0/22
-185.232.28.0/22
-185.232.47.0/24
-185.232.60.0/22
-185.232.104.0/22
-185.232.136.0/22
-185.232.208.0/22
-185.232.228.0/22
-185.232.233.0/24
-185.232.235.0/24
-185.233.0.0/22
-185.233.92.0/22
-185.233.185.0/24
-185.233.186.0/23
-185.233.192.0/22
-185.233.236.0/22
-185.234.9.0/24
-185.234.11.0/24
-185.234.116.0/22
-185.234.120.0/22
-185.234.216.0/24
-185.234.228.0/22
-185.235.9.0/24
-185.235.11.0/24
-185.235.28.0/22
-185.235.64.0/22
-185.235.72.0/22
-185.235.92.0/22
-185.235.230.0/23
-185.236.20.0/22
-185.236.28.0/22
-185.236.54.0/24
-185.236.64.0/21
-185.236.131.0/24
-185.236.156.0/22
-185.236.208.0/22
-185.236.216.0/22
-185.237.186.0/24
-185.237.236.0/22
-185.237.248.0/22
-185.238.76.0/22
-185.238.88.0/22
-185.238.104.0/22
-185.238.138.0/24
-185.238.152.0/22
-185.238.196.0/22
-185.238.200.0/22
-185.238.208.0/22
-185.239.48.0/22
-185.239.76.0/22
-185.239.88.0/22
-185.239.116.0/22
-185.239.120.0/22
-185.239.128.0/21
-185.240.48.0/22
-185.240.102.0/23
-185.241.57.0/24
-185.241.68.0/23
-185.241.111.0/24
-185.241.176.0/22
-185.241.192.0/22
-185.242.16.0/22
-185.242.116.0/22
-185.242.120.0/22
-185.243.84.0/22
-185.243.220.0/22
-185.244.4.0/22
-185.244.20.0/22
-185.244.44.0/22
-185.244.51.0/24
-185.244.76.0/22
-185.244.163.0/24
-185.244.180.0/22
-185.245.23.0/24
-185.245.36.0/22
-185.245.148.0/22
-185.245.184.0/22
-185.246.32.0/22
-185.246.64.0/22
-185.246.88.0/22
-185.246.116.0/22
-185.246.124.0/22
-185.246.180.0/22
-185.246.192.0/22
-185.246.216.0/22
-185.247.16.0/22
-185.247.80.0/22
-185.247.140.0/23
-185.247.142.0/24
-185.247.184.0/22
-185.247.192.0/22
-185.248.16.0/22
-185.248.100.0/22
-185.249.11.0/24
-185.250.0.0/22
-185.250.44.0/24
-185.250.46.0/23
-185.250.48.0/22
-185.250.60.0/22
-185.250.128.0/22
-185.250.228.0/22
-185.251.22.0/24
-185.251.88.0/22
-185.251.148.0/22
-185.251.216.0/21
-185.251.240.0/22
-185.252.60.0/22
-185.252.228.0/22
-185.252.248.0/22
-185.253.2.0/23
-185.253.20.0/22
-185.253.24.0/22
-185.253.32.0/22
-185.253.40.0/22
-185.253.55.0/24
-185.253.100.0/22
-185.253.104.0/22
-185.253.128.0/24
-185.253.136.0/22
-185.253.180.0/22
-185.253.184.0/22
-185.254.188.0/22
-185.254.212.0/22
-185.255.176.0/22
-188.0.0.0/19
-188.0.40.0/21
-188.0.160.0/19
-188.0.192.0/19
-188.16.0.0/14
-188.32.0.0/16
-188.35.0.0/16
-188.43.0.0/16
-188.44.32.0/19
-188.44.96.0/19
-188.64.112.0/21
-188.64.128.0/21
-188.64.136.0/23
-188.64.144.0/21
-188.64.160.0/23
-188.64.163.0/24
-188.64.164.0/22
-188.64.168.0/21
-188.64.216.0/21
-188.65.8.0/21
-188.65.48.0/21
-188.65.104.0/21
-188.65.128.0/21
-188.65.208.0/21
-188.65.232.0/21
-188.65.240.0/21
-188.66.32.0/21
-188.68.8.0/21
-188.68.16.0/20
-188.68.80.0/20
-188.68.96.0/19
-188.68.128.0/19
-188.68.160.0/22
-188.68.168.0/21
-188.68.176.0/20
-188.68.192.0/19
-188.72.76.0/23
-188.72.96.0/24
-188.72.103.0/24
-188.72.104.0/21
-188.72.112.0/23
-188.72.117.0/24
-188.72.118.0/24
-188.73.128.0/18
-188.75.0.0/18
-188.75.192.0/18
-188.92.24.0/24
-188.92.104.0/21
-188.92.176.0/21
-188.92.192.0/21
-188.92.216.0/21
-188.92.240.0/21
-188.93.16.0/20
-188.93.48.0/20
-188.93.64.0/22
-188.93.104.0/21
-188.93.128.0/21
-188.93.208.0/21
-188.93.240.0/21
-188.94.32.0/21
-188.94.48.0/21
-188.94.88.0/21
-188.94.160.0/20
-188.94.208.0/21
-188.94.224.0/21
-188.95.71.0/24
-188.95.104.0/21
-188.95.184.0/21
-188.112.192.0/18
-188.113.0.0/18
-188.113.128.0/18
-188.114.0.0/18
-188.114.192.0/19
-188.116.128.0/18
-188.119.76.0/22
-188.119.120.0/21
-188.120.48.0/20
-188.120.224.0/19
-188.122.160.0/19
-188.122.224.0/19
-188.123.32.0/19
-188.123.224.0/19
-188.124.32.0/20
-188.124.48.0/21
-188.124.96.0/19
-188.124.224.0/21
-188.124.240.0/22
-188.124.248.0/21
-188.126.32.0/19
-188.127.224.0/20
-188.127.240.0/22
-188.127.244.0/23
-188.127.248.0/22
-188.127.253.0/24
-188.127.254.0/23
-188.128.0.0/17
-188.133.128.0/17
-188.134.0.0/17
-188.143.128.0/17
-188.162.0.0/16
-188.164.136.0/21
-188.164.160.0/19
-188.164.208.0/21
-188.168.0.0/16
-188.170.0.0/16
-188.186.0.0/15
-188.190.116.0/22
-188.190.128.0/19
-188.190.192.0/19
-188.191.0.0/19
-188.191.80.0/20
-188.191.112.0/20
-188.191.160.0/20
-188.191.184.0/21
-188.191.192.0/21
-188.191.240.0/21
-188.225.0.0/17
-188.226.0.0/17
-188.227.0.0/19
-188.227.32.0/20
-188.227.48.0/21
-188.227.60.0/22
-188.227.64.0/20
-188.227.80.0/22
-188.227.88.0/21
-188.227.96.0/21
-188.227.104.0/23
-188.227.108.0/22
-188.227.112.0/20
-188.232.0.0/14
-188.240.17.0/24
-188.242.0.0/15
-188.244.0.0/20
-188.244.32.0/20
-188.244.128.0/17
-188.246.160.0/19
-188.246.224.0/21
-188.246.232.0/22
-188.247.32.0/19
-188.254.0.0/17
-188.255.0.0/17
-192.54.76.0/23
-192.54.186.0/23
-192.70.196.0/22
-192.86.11.0/24
-192.94.221.0/24
-192.94.233.0/24
-192.101.4.0/24
-192.102.229.0/24
-192.109.98.0/24
-192.109.214.0/23
-192.109.224.0/23
-192.109.243.0/24
-192.109.248.0/24
-192.109.250.0/24
-192.109.253.0/24
-192.124.174.0/24
-192.124.208.0/24
-192.124.210.0/23
-192.124.212.0/22
-192.124.217.0/24
-192.124.218.0/23
-192.136.61.0/24
-192.144.12.0/22
-192.144.28.0/24
-192.144.40.0/22
-192.144.56.0/22
-192.145.0.0/22
-192.145.12.0/22
-192.145.16.0/22
-192.145.96.0/22
-192.146.140.0/23
-192.148.166.0/24
-192.150.205.0/24
-192.160.10.0/24
-192.160.224.0/24
-192.160.233.0/24
-192.162.0.0/22
-192.162.8.0/22
-192.162.20.0/22
-192.162.36.0/22
-192.162.40.0/22
-192.162.56.0/22
-192.162.64.0/22
-192.162.88.0/22
-192.162.120.0/21
-192.162.180.0/22
-192.162.188.0/22
-192.162.192.0/22
-192.162.212.0/22
-192.162.240.0/21
-192.162.249.0/24
-192.162.250.0/23
-192.162.252.0/22
-192.166.12.0/22
-192.166.100.0/22
-192.166.116.0/22
-192.166.123.0/24
-192.166.124.0/22
-192.166.144.0/23
-192.166.232.0/21
-192.175.1.0/24
-192.188.116.0/24
-192.188.187.0/24
-192.188.189.0/24
-192.195.8.0/24
-192.203.80.0/24
-193.0.130.0/23
-193.0.132.0/22
-193.0.145.0/24
-193.0.148.0/22
-193.0.152.0/22
-193.0.166.0/23
-193.0.168.0/22
-193.0.178.0/23
-193.0.185.0/24
-193.0.214.0/23
-193.3.17.0/24
-193.3.40.0/24
-193.3.42.0/24
-193.3.136.0/24
-193.3.179.0/24
-193.3.184.0/23
-193.3.188.0/24
-193.3.230.0/24
-193.7.160.0/21
-193.7.216.0/22
-193.8.0.0/24
-193.8.201.0/24
-193.8.208.0/22
-193.9.17.0/24
-193.9.22.0/24
-193.9.60.0/22
-193.9.156.0/23
-193.9.240.0/21
-193.9.251.0/24
-193.16.40.0/23
-193.16.208.0/23
-193.16.210.0/24
-193.16.232.0/24
-193.17.52.0/24
-193.17.92.0/23
-193.17.170.0/24
-193.17.213.0/24
-193.19.66.0/23
-193.19.68.0/22
-193.19.82.0/23
-193.19.100.0/22
-193.19.110.0/23
-193.19.116.0/22
-193.19.126.0/23
-193.19.132.0/22
-193.19.168.0/22
-193.22.6.0/24
-193.22.88.0/24
-193.22.148.0/22
-193.22.242.0/24
-193.22.244.0/24
-193.23.3.0/24
-193.23.50.0/24
-193.23.55.0/24
-193.23.122.0/24
-193.23.142.0/24
-193.23.144.0/22
-193.24.8.0/22
-193.24.122.0/23
-193.24.196.0/22
-193.24.228.0/22
-193.25.8.0/21
-193.25.120.0/23
-193.25.188.0/22
-193.25.210.0/23
-193.25.221.0/24
-193.26.16.0/24
-193.26.18.0/23
-193.26.122.0/24
-193.26.127.0/24
-193.26.133.0/24
-193.26.135.0/24
-193.26.208.0/24
-193.26.214.0/24
-193.26.217.0/24
-193.27.36.0/22
-193.27.41.0/24
-193.27.90.0/24
-193.27.214.0/23
-193.27.222.0/23
-193.27.228.0/22
-193.27.236.0/22
-193.27.240.0/22
-193.28.6.0/24
-193.28.44.0/24
-193.28.46.0/24
-193.28.186.0/24
-193.28.234.0/24
-193.29.19.0/24
-193.29.32.0/22
-193.30.39.0/24
-193.30.108.0/24
-193.30.236.0/22
-193.31.0.0/24
-193.31.192.0/21
-193.32.20.0/24
-193.32.60.0/22
-193.32.176.0/22
-193.32.190.0/23
-193.32.196.0/22
-193.32.200.0/22
-193.32.216.0/22
-193.33.10.0/23
-193.33.26.0/23
-193.33.62.0/23
-193.33.68.0/23
-193.33.74.0/23
-193.33.80.0/22
-193.33.84.0/23
-193.33.88.0/23
-193.33.100.0/23
-193.33.122.0/23
-193.33.124.0/24
-193.33.132.0/23
-193.33.144.0/23
-193.33.153.0/24
-193.33.160.0/23
-193.33.166.0/24
-193.33.184.0/23
-193.33.192.0/23
-193.33.208.0/24
-193.33.226.0/23
-193.33.230.0/23
-193.33.232.0/23
-193.33.240.0/23
-193.34.8.0/21
-193.34.124.0/22
-193.34.128.0/23
-193.34.160.0/23
-193.34.164.0/23
-193.34.184.0/23
-193.34.190.0/23
-193.34.200.128/25
-193.34.203.0/25
-193.34.208.0/22
-193.35.32.0/22
-193.35.38.0/23
-193.35.42.0/23
-193.35.48.0/22
-193.35.96.0/23
-193.35.100.0/24
-193.35.109.0/24
-193.35.227.0/24
-193.36.35.0/24
-193.36.41.0/24
-193.36.56.0/22
-193.37.36.0/24
-193.37.68.0/22
-193.37.134.0/24
-193.37.137.0/24
-193.37.141.0/24
-193.37.155.0/24
-193.37.157.0/24
-193.37.224.0/24
-193.37.229.0/24
-193.38.228.0/22
-193.38.232.0/22
-193.39.116.0/24
-193.39.160.0/22
-193.39.168.0/22
-193.39.220.0/22
-193.39.248.0/23
-193.41.76.0/22
-193.41.93.0/24
-193.41.140.0/22
-193.41.203.0/24
-193.42.116.0/23
-193.42.124.0/22
-193.42.142.0/24
-193.42.145.0/24
-193.43.8.0/22
-193.43.41.0/24
-193.43.72.0/24
-193.43.78.0/23
-193.43.91.0/24
-193.43.94.0/24
-193.43.127.0/24
-193.43.146.0/23
-193.43.180.0/24
-193.43.182.0/24
-193.43.232.0/22
-193.43.248.0/23
-193.43.252.0/22
-193.46.2.0/24
-193.46.56.0/23
-193.46.60.0/24
-193.46.65.0/24
-193.46.77.0/24
-193.46.88.0/24
-193.46.207.0/24
-193.46.208.0/24
-193.46.213.0/24
-193.46.244.0/22
-193.47.35.0/24
-193.47.41.0/24
-193.47.42.0/23
-193.47.44.0/22
-193.47.87.0/24
-193.47.146.0/24
-193.47.148.0/24
-193.47.154.0/24
-193.47.166.0/24
-193.47.240.0/22
-193.56.30.0/24
-193.56.64.0/22
-193.56.72.0/22
-193.56.188.0/24
-193.56.190.0/24
-193.56.202.0/24
-193.57.136.0/22
-193.58.179.0/24
-193.58.251.0/24
-193.84.8.0/24
-193.84.31.0/24
-193.84.71.0/24
-193.84.76.0/24
-193.84.78.0/24
-193.84.85.0/24
-193.84.88.0/24
-193.84.90.0/24
-193.84.113.0/24
-193.84.180.0/24
-193.84.187.0/24
-193.84.244.0/24
-193.93.28.0/22
-193.93.60.0/23
-193.93.120.0/22
-193.93.192.0/22
-193.93.232.0/21
-193.93.244.0/22
-193.104.11.0/24
-193.104.14.0/24
-193.104.24.0/24
-193.104.28.0/24
-193.104.59.0/24
-193.104.64.0/24
-193.104.69.0/24
-193.104.70.0/24
-193.104.87.0/24
-193.104.97.0/24
-193.104.102.0/24
-193.104.127.0/24
-193.104.128.0/24
-193.104.139.0/24
-193.104.145.0/24
-193.104.149.0/24
-193.104.191.0/24
-193.104.195.0/24
-193.104.207.0/24
-193.104.224.0/22
-193.104.230.0/24
-193.104.234.0/24
-193.104.237.0/24
-193.104.241.0/24
-193.104.243.0/24
-193.104.248.0/24
-193.105.4.0/24
-193.105.11.0/24
-193.105.27.0/24
-193.105.37.0/24
-193.105.39.0/24
-193.105.40.0/24
-193.105.53.0/24
-193.105.59.0/24
-193.105.65.0/24
-193.105.92.0/23
-193.105.94.0/24
-193.105.100.0/24
-193.105.107.0/24
-193.105.114.0/24
-193.105.118.0/24
-193.105.126.0/24
-193.105.131.0/24
-193.105.156.0/24
-193.105.169.0/24
-193.105.175.0/24
-193.105.194.0/24
-193.105.198.0/24
-193.105.213.0/24
-193.105.222.0/24
-193.105.235.0/24
-193.105.236.0/24
-193.105.255.0/24
-193.106.0.0/21
-193.106.40.0/22
-193.106.68.0/22
-193.106.72.0/22
-193.106.88.0/21
-193.106.96.0/23
-193.106.108.0/22
-193.106.112.0/22
-193.106.132.0/22
-193.106.150.0/23
-193.106.160.0/22
-193.106.168.0/21
-193.106.184.0/22
-193.106.191.0/24
-193.106.212.0/22
-193.106.232.0/22
-193.106.236.0/23
-193.106.240.0/22
-193.107.0.0/22
-193.107.52.0/22
-193.107.60.0/22
-193.107.92.0/22
-193.107.100.0/22
-193.107.140.0/22
-193.107.148.0/22
-193.107.152.0/22
-193.107.180.0/22
-193.107.188.0/22
-193.107.192.0/22
-193.107.228.0/22
-193.107.232.0/21
-193.108.182.0/23
-193.108.198.0/24
-193.108.208.0/24
-193.108.211.0/24
-193.109.60.0/24
-193.109.70.0/23
-193.109.76.0/23
-193.109.89.0/24
-193.109.114.0/24
-193.109.160.0/22
-193.109.217.0/24
-193.110.0.0/22
-193.110.72.0/22
-193.110.91.0/24
-193.110.93.0/24
-193.110.131.0/24
-193.110.136.0/24
-193.110.141.0/24
-193.110.174.0/23
-193.110.236.0/22
-193.111.2.0/23
-193.111.45.0/24
-193.111.80.0/24
-193.111.86.0/24
-193.111.156.0/22
-193.111.160.0/24
-193.111.176.0/22
-193.111.251.0/24
-193.111.252.0/22
-193.124.48.0/24
-193.124.54.0/24
-193.124.64.0/22
-193.124.116.0/24
-193.124.128.0/22
-193.124.134.0/24
-193.135.12.0/23
-193.138.70.0/24
-193.138.79.0/24
-193.138.82.0/24
-193.138.84.0/24
-193.138.89.0/24
-193.138.128.0/22
-193.138.148.0/22
-193.138.176.0/22
-193.138.232.0/22
-193.141.53.0/24
-193.141.230.0/23
-193.142.20.0/23
-193.142.30.0/23
-193.142.56.0/23
-193.142.114.0/24
-193.142.144.0/24
-193.142.148.0/24
-193.142.152.0/24
-193.142.156.0/24
-193.142.218.0/24
-193.142.246.0/24
-193.143.0.0/23
-193.143.64.0/22
-193.143.92.0/24
-193.143.96.0/23
-193.143.119.0/24
-193.143.250.0/23
-193.148.15.0/24
-193.148.44.0/24
-193.148.52.0/22
-193.148.62.0/24
-193.150.0.0/23
-193.150.20.0/24
-193.150.32.0/23
-193.150.52.0/22
-193.150.65.0/24
-193.150.70.0/23
-193.150.80.0/22
-193.150.92.0/22
-193.150.100.0/22
-193.150.105.0/24
-193.150.107.0/24
-193.150.108.0/22
-193.150.114.0/23
-193.150.116.0/22
-193.150.124.0/23
-193.151.0.0/22
-193.151.24.0/22
-193.151.108.0/22
-193.151.168.0/22
-193.151.192.0/19
-193.151.225.0/24
-193.151.227.0/24
-193.151.228.0/22
-193.151.232.0/21
-193.151.245.0/24
-193.160.12.0/23
-193.160.158.0/24
-193.160.204.0/23
-193.160.228.0/22
-193.160.255.0/24
-193.161.193.0/24
-193.161.204.0/23
-193.161.212.0/22
-193.161.246.0/23
-193.162.30.0/24
-193.162.130.0/24
-193.162.139.0/24
-193.163.3.0/24
-193.163.55.0/24
-193.163.94.0/24
-193.163.175.0/24
-193.163.197.0/24
-193.163.205.0/24
-193.164.16.0/22
-193.164.130.0/24
-193.164.146.0/24
-193.164.149.0/24
-193.164.150.0/24
-193.164.152.0/24
-193.164.194.0/23
-193.164.200.0/23
-193.164.204.0/23
-193.164.214.0/23
-193.168.3.0/24
-193.168.46.0/23
-193.168.48.0/23
-193.168.128.0/23
-193.168.130.0/24
-193.168.136.0/22
-193.168.176.0/22
-193.168.188.0/22
-193.168.217.0/24
-193.169.0.0/23
-193.169.4.0/23
-193.169.22.0/23
-193.169.24.0/23
-193.169.28.0/23
-193.169.32.0/21
-193.169.44.0/23
-193.169.52.0/23
-193.169.60.0/22
-193.169.96.0/23
-193.169.102.0/23
-193.169.110.0/23
-193.169.118.0/23
-193.169.122.0/23
-193.169.128.0/23
-193.169.172.0/23
-193.169.176.0/22
-193.169.202.0/23
-193.169.213.0/24
-193.169.220.0/22
-193.169.226.0/23
-193.169.228.0/23
-193.169.248.0/23
-193.176.76.0/22
-193.176.80.0/22
-193.176.92.0/22
-193.176.145.0/24
-193.176.153.0/24
-193.176.154.0/23
-193.176.156.0/23
-193.176.158.0/24
-193.176.179.0/24
-193.176.190.0/24
-193.176.227.0/24
-193.176.233.0/24
-193.178.118.0/24
-193.178.120.0/22
-193.178.131.0/24
-193.178.135.0/24
-193.178.158.0/23
-193.178.170.0/24
-193.178.210.0/24
-193.178.215.0/24
-193.186.14.0/24
-193.186.34.0/24
-193.187.73.0/24
-193.187.80.0/22
-193.187.96.0/24
-193.187.156.0/22
-193.187.172.0/22
-193.187.192.0/22
-193.188.20.0/22
-193.188.200.0/24
-193.188.251.0/24
-193.188.252.0/24
-193.188.254.0/24
-193.189.68.0/23
-193.189.120.0/23
-193.189.138.0/24
-193.189.145.0/24
-193.192.36.0/23
-193.192.128.0/19
-193.193.160.0/24
-193.193.186.0/23
-193.194.96.0/22
-193.194.100.0/23
-193.194.105.0/24
-193.194.153.0/24
-193.194.154.0/24
-193.200.10.0/24
-193.200.12.0/23
-193.200.18.0/24
-193.200.21.0/24
-193.200.22.0/24
-193.200.34.0/23
-193.200.54.0/23
-193.200.72.0/22
-193.200.88.0/23
-193.200.94.0/23
-193.200.129.0/24
-193.200.161.0/24
-193.200.168.0/24
-193.200.183.0/24
-193.200.189.0/24
-193.200.211.0/24
-193.200.239.0/24
-193.200.250.0/24
-193.201.8.0/24
-193.201.30.0/23
-193.201.88.0/22
-193.201.98.0/24
-193.201.111.0/24
-193.201.115.0/24
-193.201.118.0/23
-193.201.152.0/25
-193.201.156.0/25
-193.201.228.0/22
-193.203.40.0/22
-193.203.100.0/22
-193.203.112.0/23
-193.203.124.0/23
-193.218.136.0/22
-193.218.180.0/22
-193.218.189.0/24
-193.218.190.0/23
-193.219.104.0/24
-193.219.117.0/24
-193.219.125.0/24
-193.219.127.0/24
-193.221.200.0/22
-193.221.212.0/22
-193.222.48.0/23
-193.222.58.0/24
-193.222.109.0/24
-193.222.191.0/24
-193.222.251.0/24
-193.223.68.0/23
-193.223.103.0/24
-193.223.108.0/24
-193.227.98.0/24
-193.227.134.0/24
-193.227.232.0/23
-193.227.240.0/23
-193.227.252.0/23
-193.228.108.0/22
-193.228.128.0/24
-193.228.132.0/22
-193.228.146.0/24
-193.228.158.0/23
-193.228.160.0/21
-193.228.226.0/24
-193.228.231.0/24
-193.228.235.0/24
-193.232.0.0/15
-193.238.45.0/24
-193.238.46.0/23
-193.238.48.0/22
-193.238.72.0/22
-193.238.108.0/22
-193.238.116.0/22
-193.238.128.0/22
-193.238.176.0/22
-193.238.192.0/22
-193.239.24.0/22
-193.239.133.0/24
-193.239.229.0/24
-193.239.233.0/24
-193.239.242.0/23
-193.242.99.0/24
-193.242.105.0/24
-193.242.106.0/24
-193.242.109.0/24
-193.242.128.0/22
-193.242.132.0/23
-193.242.135.0/24
-193.242.145.0/24
-193.242.148.0/22
-193.242.153.0/24
-193.242.170.0/23
-193.242.173.0/24
-193.242.176.0/22
-193.242.190.0/23
-193.242.193.0/24
-193.242.200.0/21
-193.243.138.0/23
-193.243.161.0/24
-193.243.166.0/24
-193.243.172.0/22
-193.243.182.0/24
-193.246.51.0/24
-193.246.144.0/24
-193.246.150.0/24
-193.246.153.0/24
-193.246.159.0/24
-193.246.162.0/24
-193.246.167.0/24
-193.246.206.0/24
-193.246.245.0/24
-193.247.73.0/24
-193.247.213.0/24
-193.247.216.0/24
-193.247.236.0/23
-193.254.0.0/24
-193.254.3.0/24
-193.254.16.0/23
-193.254.208.0/23
-193.254.224.0/22
-193.254.248.0/23
-194.0.68.0/22
-194.0.112.0/22
-194.0.120.0/22
-194.0.144.0/23
-194.0.162.0/24
-194.0.209.0/24
-194.0.219.0/24
-194.1.145.0/24
-194.1.156.0/24
-194.1.161.0/24
-194.1.168.0/24
-194.1.170.0/23
-194.1.198.0/24
-194.1.202.0/24
-194.1.213.0/24
-194.1.214.0/24
-194.1.232.0/21
-194.1.240.0/22
-194.1.248.0/22
-194.4.48.0/22
-194.4.148.0/22
-194.5.60.0/23
-194.5.78.0/23
-194.5.92.0/22
-194.6.196.0/22
-194.6.216.0/21
-194.8.47.0/24
-194.8.55.0/24
-194.8.70.0/23
-194.8.72.0/23
-194.8.84.0/23
-194.8.128.0/22
-194.8.136.0/22
-194.8.152.0/22
-194.8.160.0/19
-194.8.224.0/23
-194.8.228.0/22
-194.8.232.0/22
-194.8.246.0/23
-194.9.26.0/23
-194.9.38.0/23
-194.9.69.0/24
-194.9.171.0/24
-194.9.224.0/20
-194.11.28.0/23
-194.12.48.0/20
-194.12.96.0/19
-194.13.143.0/24
-194.15.116.0/22
-194.15.126.0/23
-194.24.172.0/23
-194.24.190.0/23
-194.24.240.0/23
-194.26.17.0/24
-194.26.25.0/24
-194.26.27.0/24
-194.26.29.0/24
-194.26.67.0/24
-194.26.69.0/24
-194.26.116.0/24
-194.26.207.0/24
-194.26.209.0/24
-194.26.210.0/24
-194.26.228.0/23
-194.28.20.0/22
-194.28.28.0/22
-194.28.36.0/22
-194.28.56.0/21
-194.28.72.0/22
-194.28.88.0/21
-194.28.140.0/22
-194.28.152.0/22
-194.28.160.0/22
-194.28.184.0/22
-194.28.192.0/22
-194.28.206.0/23
-194.28.208.0/21
-194.28.216.0/22
-194.28.224.0/22
-194.28.236.0/22
-194.28.240.0/22
-194.30.190.0/24
-194.31.9.0/24
-194.31.12.0/23
-194.31.66.0/23
-194.31.109.0/24
-194.31.152.0/22
-194.31.172.0/22
-194.32.86.0/23
-194.32.156.0/22
-194.32.243.0/24
-194.32.252.0/22
-194.33.15.0/24
-194.33.20.0/22
-194.33.79.0/24
-194.33.81.0/24
-194.33.84.0/22
-194.33.92.0/22
-194.33.97.0/24
-194.33.110.0/24
-194.34.96.0/22
-194.34.237.0/24
-194.34.239.0/24
-194.35.44.0/22
-194.35.48.0/22
-194.35.114.0/23
-194.35.116.0/22
-194.36.16.0/23
-194.36.148.0/22
-194.36.161.0/24
-194.36.170.0/23
-194.36.196.0/22
-194.36.208.0/23
-194.37.1.0/24
-194.37.254.0/24
-194.38.0.0/22
-194.38.8.0/22
-194.39.99.0/24
-194.39.101.0/24
-194.39.249.0/24
-194.41.52.0/22
-194.48.94.0/24
-194.48.96.0/22
-194.48.218.0/24
-194.49.50.0/23
-194.49.120.0/22
-194.49.127.0/24
-194.50.6.0/24
-194.50.9.0/24
-194.50.10.0/24
-194.50.12.0/22
-194.50.24.0/24
-194.50.72.0/24
-194.50.87.0/24
-194.50.103.0/24
-194.50.104.0/24
-194.50.116.0/24
-194.50.120.0/24
-194.50.127.0/24
-194.50.128.0/22
-194.50.139.0/24
-194.50.141.0/24
-194.50.142.0/23
-194.50.148.0/23
-194.50.150.0/24
-194.50.152.0/24
-194.50.169.0/24
-194.50.170.0/23
-194.50.180.0/24
-194.50.190.0/24
-194.50.255.0/24
-194.53.175.0/24
-194.53.184.0/22
-194.54.12.0/22
-194.54.64.0/22
-194.54.132.0/22
-194.54.148.0/22
-194.54.152.0/22
-194.54.176.0/22
-194.55.140.0/22
-194.55.161.0/24
-194.55.163.0/24
-194.55.164.0/22
-194.55.168.0/24
-194.55.171.0/24
-194.55.234.0/23
-194.55.236.0/22
-194.55.244.0/23
-194.58.62.0/23
-194.58.78.0/23
-194.58.88.0/21
-194.58.96.0/19
-194.58.160.0/19
-194.59.184.0/24
-194.59.186.0/24
-194.60.236.0/22
-194.60.242.0/24
-194.60.246.0/23
-194.60.248.0/23
-194.61.24.0/23
-194.61.60.0/22
-194.61.67.0/24
-194.62.0.0/24
-194.63.156.0/22
-194.67.0.0/18
-194.67.64.0/20
-194.67.84.0/22
-194.67.88.0/21
-194.67.96.0/19
-194.67.128.0/18
-194.67.224.0/19
-194.76.36.0/23
-194.76.46.0/23
-194.76.220.0/23
-194.76.236.0/23
-194.79.4.0/22
-194.79.32.0/22
-194.79.44.0/22
-194.79.250.0/23
-194.79.255.0/24
-194.84.0.0/16
-194.85.0.0/17
-194.85.128.0/18
-194.85.192.0/19
-194.85.224.0/20
-194.85.240.0/21
-194.85.252.0/22
-194.88.14.0/23
-194.88.138.0/23
-194.88.140.0/23
-194.88.198.0/23
-194.88.200.0/23
-194.88.204.0/23
-194.88.208.0/22
-194.99.116.0/24
-194.104.8.0/22
-194.104.224.0/23
-194.105.130.0/23
-194.105.148.0/24
-194.105.156.0/23
-194.105.192.0/19
-194.106.194.0/23
-194.107.17.0/24
-194.107.21.0/24
-194.107.23.0/24
-194.107.80.0/24
-194.107.124.0/24
-194.107.200.0/24
-194.110.8.0/22
-194.110.18.0/24
-194.110.52.0/23
-194.110.66.0/24
-194.110.71.0/24
-194.110.80.0/22
-194.110.152.0/23
-194.110.202.0/23
-194.110.223.0/24
-194.110.246.0/23
-194.110.253.0/24
-194.113.34.0/23
-194.113.104.0/22
-194.113.139.0/24
-194.113.140.0/24
-194.113.142.0/24
-194.113.155.0/24
-194.113.209.0/24
-194.113.219.0/24
-194.113.232.0/21
-194.113.245.0/24
-194.114.128.0/22
-194.116.162.0/23
-194.116.169.0/24
-194.116.172.0/23
-194.116.190.0/23
-194.116.194.0/23
-194.116.214.0/23
-194.116.216.0/23
-194.117.50.128/25
-194.117.65.0/24
-194.117.70.0/24
-194.117.89.0/24
-194.117.250.0/23
-194.120.24.0/24
-194.120.104.0/23
-194.120.116.0/24
-194.124.36.0/22
-194.125.224.0/22
-194.125.236.0/22
-194.125.254.0/23
-194.126.160.0/22
-194.126.168.0/22
-194.126.203.0/24
-194.127.112.0/22
-194.135.4.0/22
-194.135.8.0/21
-194.135.21.0/24
-194.135.40.0/22
-194.135.52.0/22
-194.135.60.0/22
-194.135.64.0/21
-194.135.72.0/22
-194.135.96.0/22
-194.135.100.0/24
-194.135.103.0/24
-194.135.108.0/22
-194.135.112.0/22
-194.135.120.0/22
-194.135.135.0/24
-194.135.136.0/21
-194.135.144.0/21
-194.135.192.0/22
-194.135.208.0/20
-194.135.224.0/20
-194.135.240.0/21
-194.140.228.0/24
-194.140.247.0/24
-194.143.138.0/23
-194.143.148.0/22
-194.145.158.0/24
-194.145.168.0/22
-194.146.113.0/24
-194.146.119.0/24
-194.146.200.0/22
-194.146.240.0/22
-194.147.32.0/22
-194.147.48.0/22
-194.147.114.0/23
-194.147.148.0/23
-194.147.224.0/24
-194.147.246.0/23
-194.147.249.0/24
-194.149.64.0/21
-194.149.90.0/24
-194.149.95.0/24
-194.149.224.0/22
-194.149.234.0/23
-194.149.242.0/24
-194.150.88.0/22
-194.150.128.0/19
-194.150.174.0/23
-194.150.179.0/24
-194.150.202.0/23
-194.150.214.0/23
-194.150.222.0/23
-194.150.234.0/23
-194.150.254.0/23
-194.152.34.0/23
-194.152.62.0/23
-194.153.112.0/24
-194.153.158.128/25
-194.154.64.0/19
-194.156.100.0/22
-194.156.116.0/22
-194.156.122.0/24
-194.156.124.0/23
-194.156.166.0/23
-194.156.184.0/23
-194.156.200.0/23
-194.156.204.0/23
-194.165.0.0/23
-194.165.18.0/23
-194.165.20.0/22
-194.165.30.0/23
-194.165.50.0/24
-194.165.57.0/24
-194.165.61.0/24
-194.169.56.0/22
-194.169.192.0/24
-194.169.247.0/24
-194.169.250.0/24
-194.169.255.0/24
-194.176.100.0/24
-194.176.114.0/24
-194.176.118.0/24
-194.177.20.0/22
-194.180.226.192/26
-194.186.0.0/16
-194.187.29.0/24
-194.187.120.0/22
-194.187.148.0/22
-194.187.196.0/22
-194.187.204.0/22
-194.190.0.0/16
-194.213.12.0/24
-194.213.21.0/24
-194.213.96.0/23
-194.213.102.0/23
-194.213.110.0/23
-194.213.116.0/23
-194.213.122.0/23
-194.226.0.0/16
-194.242.4.0/22
-194.242.8.0/23
-194.242.26.0/23
-194.242.30.0/23
-194.242.120.0/21
-194.246.80.0/24
-194.246.92.0/22
-194.246.112.0/23
-194.247.14.0/23
-194.247.20.0/22
-194.247.24.0/23
-194.247.33.0/24
-194.247.40.0/24
-194.247.51.0/24
-194.247.53.0/24
-194.247.54.0/23
-194.247.128.0/19
-194.247.168.0/23
-194.247.184.0/23
-194.247.190.0/23
-195.2.64.0/20
-195.2.80.0/22
-195.2.84.0/23
-195.2.87.0/24
-195.2.88.0/22
-195.2.94.0/23
-195.2.192.0/22
-195.2.198.0/23
-195.2.204.0/22
-195.2.210.0/23
-195.2.214.0/23
-195.2.216.0/23
-195.2.226.0/23
-195.2.232.0/23
-195.2.238.0/23
-195.2.240.0/23
-195.3.132.0/22
-195.3.140.0/22
-195.3.180.0/24
-195.3.182.0/23
-195.3.216.0/22
-195.3.240.0/21
-195.3.252.0/22
-195.5.105.0/24
-195.5.108.0/23
-195.5.128.0/19
-195.5.178.0/24
-195.7.160.0/19
-195.8.34.0/23
-195.8.36.0/22
-195.8.44.0/23
-195.8.56.0/23
-195.9.0.0/16
-195.10.193.0/24
-195.10.198.0/24
-195.10.205.0/24
-195.10.214.0/24
-195.12.64.0/19
-195.13.50.0/24
-195.14.12.0/24
-195.14.32.0/19
-195.14.96.0/23
-195.14.100.0/23
-195.14.106.0/23
-195.14.108.0/23
-195.14.114.0/23
-195.16.32.0/19
-195.16.92.0/23
-195.16.95.0/24
-195.16.96.0/19
-195.18.12.0/22
-195.18.20.0/22
-195.18.26.0/24
-195.18.32.0/19
-195.19.0.0/16
-195.20.18.0/23
-195.20.28.0/22
-195.20.102.0/23
-195.20.118.0/23
-195.20.128.0/24
-195.20.135.0/24
-195.20.140.0/24
-195.20.194.0/23
-195.20.196.0/23
-195.22.104.0/22
-195.22.123.0/24
-195.22.148.0/23
-195.22.152.0/23
-195.24.64.0/21
-195.24.228.0/23
-195.24.254.0/23
-195.26.30.0/23
-195.26.80.0/22
-195.26.160.0/19
-195.28.14.0/23
-195.28.32.0/19
-195.34.0.0/18
-195.34.192.0/22
-195.34.224.0/19
-195.35.68.0/22
-195.35.116.0/23
-195.38.23.0/24
-195.38.32.0/19
-195.39.206.0/23
-195.39.210.0/23
-195.39.228.0/23
-195.39.248.0/23
-195.42.64.0/19
-195.42.96.0/23
-195.42.118.0/23
-195.42.122.0/23
-195.42.146.0/23
-195.42.154.0/23
-195.42.156.0/23
-195.42.160.0/19
-195.43.32.0/22
-195.43.68.0/23
-195.43.76.0/23
-195.43.90.0/23
-195.43.92.0/22
-195.43.134.0/23
-195.43.144.0/24
-195.46.96.0/19
-195.46.160.0/19
-195.47.192.0/24
-195.47.196.0/24
-195.47.204.0/24
-195.49.168.0/22
-195.49.184.0/22
-195.49.192.0/20
-195.54.0.0/19
-195.54.32.0/23
-195.54.40.0/22
-195.54.176.0/23
-195.54.192.0/19
-195.58.0.0/19
-195.60.220.0/22
-195.60.244.0/22
-195.62.0.0/22
-195.62.6.0/23
-195.62.34.0/24
-195.62.38.0/23
-195.62.48.0/23
-195.62.52.0/22
-195.62.58.0/23
-195.62.60.0/22
-195.62.70.0/23
-195.62.78.0/23
-195.62.92.0/23
-195.64.101.0/24
-195.64.117.0/24
-195.64.140.0/22
-195.64.156.0/23
-195.64.192.0/19
-195.66.67.0/24
-195.66.71.0/24
-195.66.72.0/24
-195.66.77.0/24
-195.66.78.0/24
-195.66.84.0/24
-195.66.89.0/24
-195.66.108.0/24
-195.66.117.0/24
-195.66.126.0/24
-195.66.138.0/23
-195.68.128.0/18
-195.68.240.0/23
-195.68.245.0/24
-195.68.252.0/23
-195.69.64.0/22
-195.69.79.0/24
-195.69.136.0/22
-195.69.151.0/24
-195.69.156.0/22
-195.69.160.0/24
-195.69.168.0/22
-195.69.200.0/21
-195.69.216.0/22
-195.69.236.0/22
-195.69.248.0/22
-195.70.192.0/19
-195.72.140.0/22
-195.72.224.0/19
-195.74.62.0/23
-195.74.74.0/24
-195.74.82.0/24
-195.74.84.0/24
-195.74.95.0/24
-195.78.60.0/23
-195.78.72.0/23
-195.78.96.0/23
-195.78.104.0/23
-195.78.116.0/23
-195.78.126.0/23
-195.80.48.0/22
-195.80.56.0/22
-195.80.136.0/24
-195.80.139.0/24
-195.80.144.0/22
-195.80.224.0/24
-195.80.228.0/24
-195.82.134.0/23
-195.82.136.0/23
-195.82.140.0/22
-195.82.144.0/23
-195.82.154.0/23
-195.82.156.0/23
-195.85.206.0/24
-195.85.213.0/24
-195.85.231.0/24
-195.85.234.0/23
-195.85.236.0/24
-195.85.238.0/24
-195.88.0.0/23
-195.88.14.0/23
-195.88.16.0/23
-195.88.22.0/23
-195.88.40.0/23
-195.88.52.0/23
-195.88.58.0/23
-195.88.62.0/23
-195.88.68.0/23
-195.88.92.0/23
-195.88.102.0/23
-195.88.112.0/23
-195.88.120.0/23
-195.88.126.0/23
-195.88.132.0/22
-195.88.170.0/23
-195.88.178.0/23
-195.88.184.0/23
-195.88.192.0/23
-195.88.196.0/24
-195.88.198.0/23
-195.88.200.0/23
-195.88.224.0/23
-195.88.240.0/23
-195.88.248.0/23
-195.88.252.0/23
-195.90.122.0/23
-195.90.128.0/18
-195.91.128.0/17
-195.93.128.0/23
-195.93.144.0/23
-195.93.148.0/22
-195.93.160.0/23
-195.93.164.0/23
-195.93.180.0/23
-195.93.186.0/23
-195.93.188.0/23
-195.93.206.0/23
-195.93.228.0/23
-195.93.240.0/23
-195.93.244.0/24
-195.93.246.0/23
-195.93.248.0/23
-195.93.252.0/23
-195.94.224.0/19
-195.95.133.0/24
-195.95.212.0/22
-195.95.218.0/24
-195.95.252.0/23
-195.96.40.0/21
-195.96.64.0/19
-195.96.160.0/19
-195.98.32.0/19
-195.98.64.0/19
-195.98.160.0/19
-195.110.6.0/23
-195.110.32.0/23
-195.110.46.0/23
-195.110.52.0/23
-195.110.62.0/23
-195.112.96.0/19
-195.112.224.0/19
-195.114.2.0/23
-195.114.20.0/23
-195.114.104.0/23
-195.114.112.0/24
-195.114.116.0/22
-195.114.122.0/23
-195.122.224.0/19
-195.128.48.0/20
-195.128.64.0/19
-195.128.96.0/22
-195.128.120.0/21
-195.128.133.0/24
-195.128.137.0/24
-195.128.152.0/23
-195.128.157.0/24
-195.128.158.0/23
-195.128.244.0/23
-195.130.209.0/24
-195.130.214.0/24
-195.130.216.0/24
-195.131.0.0/16
-195.133.56.0/23
-195.133.60.0/23
-195.133.216.0/22
-195.133.224.0/19
-195.135.204.0/22
-195.135.212.0/22
-195.135.232.0/21
-195.135.240.0/22
-195.137.171.0/24
-195.137.187.0/24
-195.137.200.0/23
-195.138.206.0/24
-195.138.210.0/24
-195.138.232.0/21
-195.140.144.0/22
-195.140.180.0/22
-195.140.204.0/22
-195.140.216.0/24
-195.144.0.0/23
-195.144.6.0/24
-195.144.29.0/24
-195.144.192.0/18
-195.146.64.0/19
-195.149.89.0/24
-195.149.104.0/23
-195.149.110.0/23
-195.149.196.0/23
-195.149.200.0/21
-195.151.0.0/16
-195.158.220.0/22
-195.158.224.0/23
-195.158.228.0/23
-195.158.232.0/23
-195.158.250.0/23
-195.158.254.0/23
-195.160.164.0/23
-195.160.244.0/22
-195.161.0.0/16
-195.162.6.0/23
-195.162.8.0/22
-195.162.22.0/23
-195.162.32.0/19
-195.162.78.0/23
-195.166.160.0/19
-195.170.32.0/19
-195.170.174.0/24
-195.170.192.0/18
-195.177.104.0/22
-195.177.120.0/22
-195.177.194.0/23
-195.177.204.0/23
-195.177.226.0/23
-195.178.2.0/23
-195.178.16.0/23
-195.178.20.0/22
-195.178.24.0/23
-195.178.98.0/24
-195.178.108.0/23
-195.178.192.0/19
-195.182.3.0/24
-195.182.20.0/24
-195.182.28.0/24
-195.182.32.0/24
-195.182.57.0/24
-195.182.128.0/19
-195.184.78.0/23
-195.184.192.0/19
-195.189.16.0/22
-195.189.44.0/22
-195.189.100.0/22
-195.189.108.0/22
-195.189.134.0/23
-195.189.136.0/23
-195.189.180.0/23
-195.189.218.0/23
-195.189.222.0/23
-195.189.238.0/23
-195.190.12.0/23
-195.190.14.0/24
-195.190.96.0/19
-195.190.132.0/24
-195.191.4.0/23
-195.191.7.0/24
-195.191.10.0/23
-195.191.18.0/23
-195.191.32.0/23
-195.191.36.0/23
-195.191.50.0/23
-195.191.64.0/24
-195.191.76.0/22
-195.191.82.0/23
-195.191.88.0/23
-195.191.130.0/23
-195.191.136.0/23
-195.191.146.0/23
-195.191.158.0/23
-195.191.166.0/23
-195.191.174.0/23
-195.191.182.0/23
-195.191.190.0/23
-195.191.192.0/22
-195.191.208.0/23
-195.191.220.0/23
-195.191.226.0/23
-195.191.236.0/22
-195.191.242.0/23
-195.191.246.0/23
-195.200.203.0/24
-195.200.209.0/24
-195.200.213.0/24
-195.200.216.0/24
-195.200.223.0/24
-195.200.226.0/23
-195.200.236.0/23
-195.200.248.0/23
-195.206.32.0/19
-195.206.122.0/23
-195.206.226.0/23
-195.206.237.0/24
-195.206.240.0/23
-195.206.244.0/23
-195.206.254.0/23
-195.208.0.0/15
-195.210.2.0/23
-195.210.9.0/24
-195.210.20.0/23
-195.210.30.0/23
-195.210.128.0/18
-195.211.4.0/22
-195.211.20.0/22
-195.211.28.0/22
-195.211.36.0/22
-195.211.42.0/23
-195.211.64.0/22
-195.211.76.0/22
-195.211.80.0/22
-195.211.88.0/22
-195.211.100.0/22
-195.211.104.0/22
-195.211.112.0/22
-195.211.120.0/22
-195.211.128.0/22
-195.211.160.0/22
-195.211.192.0/21
-195.211.204.0/22
-195.211.216.0/22
-195.211.232.0/21
-195.211.244.0/22
-195.211.248.0/23
-195.211.251.0/24
-195.214.236.0/22
-195.216.194.0/23
-195.216.200.0/23
-195.216.210.0/23
-195.216.212.0/23
-195.216.216.0/23
-195.216.241.0/24
-195.216.244.0/24
-195.218.128.0/17
-195.222.128.0/18
-195.225.38.0/23
-195.225.56.0/23
-195.225.96.0/24
-195.225.108.0/22
-195.225.160.0/22
-195.225.233.0/24
-195.226.203.0/24
-195.226.204.0/24
-195.226.209.0/24
-195.226.222.0/24
-195.230.64.0/19
-195.230.99.0/24
-195.230.101.0/24
-195.230.109.0/24
-195.230.111.0/24
-195.230.112.0/24
-195.234.2.0/23
-195.234.52.0/24
-195.234.56.0/24
-195.234.90.0/23
-195.234.96.0/23
-195.234.130.0/24
-195.234.140.0/24
-195.234.143.0/24
-195.234.154.0/24
-195.234.170.0/24
-195.234.190.0/24
-195.234.200.0/22
-195.234.208.0/22
-195.238.72.0/23
-195.238.100.0/22
-195.238.112.0/22
-195.238.230.0/24
-195.238.239.0/24
-195.238.246.0/24
-195.238.250.0/24
-195.239.0.0/16
-195.242.82.0/23
-195.242.142.0/23
-195.242.144.0/23
-195.242.147.0/24
-195.242.216.0/23
-195.244.4.0/23
-195.244.24.0/23
-195.245.76.0/23
-195.245.205.0/24
-195.245.206.0/24
-195.245.211.0/24
-195.245.214.0/24
-195.245.232.0/24
-195.245.244.0/24
-195.245.249.0/24
-195.246.106.0/23
-195.246.118.0/23
-195.246.122.0/23
-195.246.124.0/23
-195.246.218.0/24
-195.246.246.0/23
-195.246.248.0/23
-195.246.254.0/23
-195.248.69.0/24
-195.248.71.0/24
-195.248.81.0/24
-195.248.82.0/24
-195.248.94.0/24
-195.248.232.0/23
-195.248.236.0/23
-195.248.244.0/23
-195.248.248.0/23
-195.250.42.0/24
-195.250.51.0/24
-195.250.56.0/24
-195.254.188.0/23
-196.1.5.0/24
-203.81.208.0/20
-212.0.64.0/19
-212.1.224.0/19
-212.3.128.0/19
-212.5.64.0/18
-212.5.160.0/19
-212.5.224.0/19
-212.6.0.0/19
-212.6.56.0/24
-212.7.96.0/19
-212.7.224.0/19
-212.8.224.0/22
-212.8.228.0/23
-212.8.232.0/21
-212.8.247.0/24
-212.11.128.0/19
-212.12.0.0/19
-212.12.64.0/19
-212.13.0.0/19
-212.13.96.0/19
-212.14.160.0/19
-212.14.192.0/19
-212.15.32.0/19
-212.15.96.0/19
-212.16.0.0/19
-212.16.192.0/19
-212.17.0.0/19
-212.18.96.0/24
-212.18.117.0/24
-212.18.118.0/24
-212.19.0.0/19
-212.20.0.0/18
-212.21.0.0/19
-212.22.64.0/19
-212.23.64.0/19
-212.24.32.0/19
-212.24.115.0/24
-212.26.224.0/19
-212.30.128.0/18
-212.32.192.0/19
-212.33.0.0/19
-212.33.224.0/19
-212.34.32.0/19
-212.34.96.0/19
-212.35.160.0/19
-212.36.224.0/19
-212.38.96.0/19
-212.40.192.0/19
-212.41.0.0/18
-212.42.32.0/19
-212.44.64.0/19
-212.44.128.0/19
-212.45.0.0/19
-212.45.224.0/19
-212.46.0.0/19
-212.46.47.0/24
-212.46.54.0/24
-212.46.192.0/18
-212.47.32.0/24
-212.48.32.0/19
-212.48.128.0/19
-212.48.192.0/19
-212.48.224.0/20
-212.49.96.0/19
-212.53.32.0/19
-212.55.96.0/19
-212.57.96.0/19
-212.57.128.0/18
-212.58.192.0/19
-212.59.96.0/19
-212.60.20.0/22
-212.65.64.0/19
-212.66.32.0/20
-212.66.56.0/21
-212.67.0.0/19
-212.69.96.0/19
-212.73.96.0/19
-212.74.192.0/18
-212.75.128.0/19
-212.75.192.0/18
-212.76.128.0/18
-212.77.128.0/19
-212.83.0.0/19
-212.86.99.0/24
-212.90.96.0/22
-212.91.192.0/19
-212.92.96.0/22
-212.92.100.0/23
-212.92.128.0/18
-212.94.0.0/19
-212.94.96.0/19
-212.96.96.0/19
-212.96.192.0/19
-212.100.128.0/19
-212.103.96.0/19
-212.104.64.0/19
-212.104.131.0/24
-212.106.32.0/19
-212.107.192.0/18
-212.108.109.0/24
-212.109.0.0/19
-212.109.168.0/21
-212.109.192.0/19
-212.110.156.0/22
-212.111.64.0/20
-212.111.83.0/24
-212.111.90.0/23
-212.111.92.0/22
-212.113.96.0/19
-212.113.224.0/19
-212.115.51.0/24
-212.115.56.0/22
-212.116.96.0/19
-212.118.32.0/22
-212.118.44.0/22
-212.118.48.0/22
-212.118.56.0/24
-212.118.60.0/24
-212.118.62.0/23
-212.119.96.0/19
-212.119.160.0/19
-212.119.192.0/18
-212.120.160.0/19
-212.122.0.0/19
-212.124.0.0/19
-212.124.96.0/19
-212.129.96.0/19
-212.152.32.0/19
-212.158.160.0/20
-212.162.136.0/22
-212.164.0.0/16
-212.176.0.0/16
-212.188.0.0/17
-212.192.32.0/19
-212.192.64.0/18
-212.192.128.0/18
-212.192.192.0/20
-212.192.224.0/20
-212.192.246.0/23
-212.192.248.0/23
-212.193.10.0/23
-212.193.14.0/23
-212.193.32.0/19
-212.193.64.0/18
-212.193.128.0/17
-212.220.0.0/16
-212.232.0.0/20
-212.232.32.0/19
-212.233.64.0/21
-212.233.80.0/21
-212.233.100.0/22
-212.233.104.0/21
-212.233.112.0/21
-212.233.124.0/22
-212.248.0.0/17
-213.5.16.0/22
-213.5.24.0/21
-213.5.48.0/21
-213.5.73.0/24
-213.5.74.0/23
-213.5.76.0/22
-213.5.80.0/21
-213.5.96.0/20
-213.5.120.0/21
-213.5.135.0/24
-213.5.160.0/21
-213.5.216.0/21
-213.5.224.0/23
-213.5.227.0/24
-213.5.228.0/22
-213.5.240.0/21
-213.24.0.0/16
-213.27.0.0/17
-213.33.128.0/17
-213.59.0.0/18
-213.59.64.0/19
-213.59.96.0/20
-213.59.128.0/17
-213.79.0.0/19
-213.79.64.0/18
-213.80.128.0/17
-213.85.0.0/16
-213.87.0.0/16
-213.88.0.0/17
-213.108.0.0/22
-213.108.16.0/22
-213.108.32.0/21
-213.108.128.0/23
-213.108.130.0/24
-213.108.132.0/23
-213.108.135.0/24
-213.108.136.0/21
-213.108.144.0/21
-213.108.168.0/21
-213.108.184.0/21
-213.108.200.0/21
-213.108.208.0/20
-213.108.248.0/21
-213.109.0.0/19
-213.109.48.0/20
-213.109.72.0/24
-213.109.74.0/23
-213.109.78.0/23
-213.109.145.0/24
-213.109.201.0/24
-213.109.203.0/24
-213.110.0.0/18
-213.110.192.0/19
-213.110.224.0/22
-213.110.228.0/23
-213.110.232.0/22
-213.110.236.0/23
-213.110.240.0/20
-213.128.0.0/19
-213.128.192.0/19
-213.129.32.0/19
-213.129.96.0/19
-213.130.80.0/21
-213.131.0.0/19
-213.132.64.0/19
-213.134.6.0/24
-213.134.8.0/24
-213.134.18.0/24
-213.134.192.0/19
-213.135.64.0/18
-213.135.128.0/19
-213.137.224.0/19
-213.138.64.0/19
-213.138.192.0/20
-213.138.208.0/21
-213.138.220.0/22
-213.139.208.0/22
-213.139.229.0/24
-213.139.248.0/22
-213.140.96.0/19
-213.140.224.0/19
-213.141.128.0/19
-213.141.224.0/19
-213.142.32.0/19
-213.142.138.0/23
-213.142.192.0/19
-213.145.0.0/18
-213.147.32.0/19
-213.147.192.0/19
-213.148.160.0/19
-213.149.0.0/19
-213.150.64.0/19
-213.151.0.0/19
-213.152.128.0/19
-213.154.160.0/19
-213.155.192.0/19
-213.156.128.0/22
-213.156.192.0/19
-213.158.0.0/19
-213.159.192.0/19
-213.165.192.0/19
-213.166.76.0/22
-213.167.32.0/19
-213.167.192.0/19
-213.168.32.0/19
-213.168.128.0/19
-213.170.64.0/18
-213.170.220.0/22
-213.171.0.0/18
-213.172.0.0/19
-213.176.224.0/19
-213.177.96.0/19
-213.177.183.0/24
-213.177.191.0/24
-213.178.32.0/19
-213.178.153.0/24
-213.178.154.0/24
-213.180.192.0/19
-213.181.0.0/19
-213.182.160.0/19
-213.183.96.0/19
-213.183.224.0/19
-213.184.128.0/19
-213.187.96.0/19
-213.189.192.0/18
-213.190.224.0/19
-213.191.0.0/19
-213.193.0.0/19
-213.208.160.0/21
-213.208.168.0/23
-213.208.170.0/24
-213.208.172.0/22
-213.208.176.0/20
-213.210.64.0/18
-213.217.0.0/23
-213.219.192.0/19
-213.219.224.0/20
-213.219.240.0/21
-213.219.248.0/22
-213.221.0.0/18
-213.222.224.0/19
-213.226.80.0/22
-213.228.64.0/18
-213.232.120.0/22
-213.232.192.0/24
-213.232.194.0/23
-213.232.199.0/24
-213.232.207.0/24
-213.232.208.0/21
-213.232.227.0/24
-213.232.228.0/23
-213.232.233.0/24
-213.232.235.0/24
-213.232.240.0/24
-213.232.249.0/24
-213.232.250.0/23
-213.232.254.0/24
-213.234.0.0/19
-213.234.192.0/18
-213.241.192.0/18
-213.242.0.0/18
-213.242.192.0/18
-213.243.64.0/18
-213.247.128.0/17
-213.248.0.0/18
-213.251.192.0/18
-213.252.64.0/18
-217.8.80.0/20
-217.8.124.0/22
-217.8.224.0/20
-217.9.80.0/20
-217.9.144.0/20
-217.10.32.0/20
-217.12.32.0/20
-217.12.64.0/20
-217.12.96.0/20
-217.12.240.0/20
-217.13.208.0/20
-217.14.16.0/20
-217.14.48.0/20
-217.14.192.0/20
-217.14.240.0/20
-217.15.16.0/20
-217.15.48.0/20
-217.15.128.0/19
-217.15.192.0/20
-217.16.16.0/20
-217.17.112.0/20
-217.17.160.0/19
-217.18.49.0/24
-217.18.50.0/24
-217.18.60.0/22
-217.18.128.0/19
-217.19.96.0/19
-217.20.64.0/19
-217.20.144.0/20
-217.21.96.0/20
-217.21.208.0/20
-217.22.9.0/24
-217.22.160.0/20
-217.23.16.0/20
-217.23.64.0/19
-217.23.128.0/20
-217.23.144.0/22
-217.23.148.0/24
-217.23.150.0/23
-217.23.152.0/21
-217.23.176.0/20
-217.24.112.0/20
-217.24.176.0/20
-217.25.80.0/20
-217.25.144.0/20
-217.25.208.0/20
-217.25.224.0/20
-217.26.0.0/19
-217.26.217.0/24
-217.27.128.0/20
-217.28.72.0/21
-217.28.131.0/24
-217.28.208.0/20
-217.28.224.0/20
-217.29.48.0/20
-217.29.80.0/20
-217.29.176.0/20
-217.30.240.0/20
-217.64.128.0/20
-217.64.144.0/22
-217.65.0.0/20
-217.65.79.0/24
-217.65.80.0/20
-217.65.208.0/20
-217.66.16.0/20
-217.66.64.0/19
-217.66.144.0/20
-217.67.0.0/20
-217.67.112.0/20
-217.67.176.0/20
-217.69.128.0/20
-217.69.192.0/19
-217.70.5.0/24
-217.70.16.0/20
-217.70.96.0/19
-217.71.128.0/20
-217.71.160.0/20
-217.71.224.0/20
-217.72.0.0/21
-217.72.8.0/22
-217.72.144.0/20
-217.73.56.0/21
-217.73.112.0/20
-217.73.192.0/20
-217.74.32.0/20
-217.74.112.0/20
-217.74.160.0/20
-217.74.240.0/20
-217.76.32.0/20
-217.76.176.0/20
-217.77.48.0/20
-217.77.96.0/22
-217.77.100.0/24
-217.77.102.0/24
-217.77.104.0/21
-217.78.176.0/20
-217.78.224.0/22
-217.78.228.0/24
-217.78.230.0/23
-217.78.232.0/23
-217.78.236.0/24
-217.79.0.0/19
-217.79.48.0/20
-217.79.224.0/20
-217.106.0.0/15
-217.112.0.0/19
-217.112.32.0/20
-217.113.112.0/20
-217.114.0.0/19
-217.114.144.0/20
-217.114.176.0/20
-217.114.224.0/19
-217.115.80.0/20
-217.115.176.0/20
-217.116.48.0/20
-217.116.128.0/19
-217.117.80.0/20
-217.117.112.0/20
-217.117.176.0/20
-217.117.240.0/20
-217.118.64.0/19
-217.118.176.0/20
-217.119.16.0/20
-217.119.80.0/20
-217.119.139.0/24
-217.144.96.0/21
-217.144.160.0/20
-217.145.16.0/20
-217.145.144.0/20
-217.145.224.0/22
-217.146.32.0/20
-217.147.8.0/22
-217.147.16.0/20
-217.148.48.0/20
-217.148.192.0/19
-217.149.16.0/20
-217.149.176.0/20
-217.150.0.0/18
-217.150.72.0/21
-217.150.192.0/20
-217.151.16.0/20
-217.151.64.0/20
-217.151.128.0/20
-217.151.224.0/20
-217.168.64.0/20
-217.168.240.0/21
-217.169.80.0/20
-217.170.64.0/19
-217.170.112.0/20
-217.170.208.0/20
-217.171.0.0/20
-217.171.146.0/23
-217.171.152.0/21
-217.172.16.0/20
-217.173.16.0/20
-217.173.64.0/20
-217.174.0.0/20
-217.174.96.0/20
-217.174.160.0/19
-217.175.0.0/19
-217.175.32.0/20
-217.175.128.0/19
-217.194.240.0/20
-217.195.64.0/19
-217.195.96.0/20
-217.195.208.0/20
-217.196.96.0/20
-217.197.0.0/20
-217.197.107.0/24
-217.197.112.0/20
-217.197.172.0/22
-217.197.192.0/20
-217.197.224.0/19
-217.198.0.0/20
-217.198.80.0/20
-217.198.160.0/20
-217.199.208.0/20
-217.199.224.0/20
-217.199.240.0/21
-217.199.248.0/22
-217.199.252.0/23
-217.199.254.0/24
diff --git a/server/phobos-backup.sh b/server/phobos-backup.sh
deleted file mode 100755
index 4f7fc1d..0000000
--- a/server/phobos-backup.sh
+++ /dev/null
@@ -1,93 +0,0 @@
-#!/bin/bash
-# ============================================================
-# PCA Phobos — полный бэкап / восстановление сервера
-#
-# phobos-backup create # создать бэкап -> /opt/Phobos/backups/*.tar.gz
-# phobos-backup restore # восстановить из бэкапа
-# phobos-backup list # список бэкапов
-#
-# В бэкап входит ВСЁ состояние (НЕ бинарники/пакеты):
-# WireGuard ключ сервера (wg0.conf), server.env (OBF/WG ключи),
-# обфускатор-конфиги, все клиенты+ключи, токены, settings.json панели
-# (router_access, метки, назначения, токен подписчика, версия/канал/порт).
-#
-# ⚠ Бэкап содержит ПРИВАТНЫЕ КЛЮЧИ — храни в защищённом месте.
-#
-# Disaster recovery на чистом VPS:
-# 1) поставить turnkey: bash <(curl -fsSL .../install.sh) (ставит бинарники/сервисы)
-# 2) залить бэкап и: phobos-backup restore phobos-backup-*.tar.gz
-# Ключ сервера восстановится — клиенты переподключатся без пересоздания.
-# ============================================================
-set -u
-PHOBOS_DIR=/opt/Phobos
-PANEL_DIR=/opt/phobos-panel
-BACKUP_DIR="$PHOBOS_DIR/backups"
-
-panel_service_name() {
- for name in phobos-dev-test phobos-panel; do
- systemctl status "$name" >/dev/null 2>&1 && { echo "$name"; return; }
- done
- echo phobos-panel
-}
-
-PATHS=(
- /etc/wireguard/wg0.conf
- "$PHOBOS_DIR/server/server.env"
- "$PHOBOS_DIR/clients"
- "$PHOBOS_DIR/tokens"
- "$PHOBOS_DIR/server/warp"
- "$PANEL_DIR/settings.json"
- "$PANEL_DIR/servers.json"
- "$PANEL_DIR/.version"
- "$PANEL_DIR/.channel"
- "$PANEL_DIR/.port"
- "$PANEL_DIR/.scheme"
- "$PANEL_DIR/.gh_token"
-)
-
-case "${1:-}" in
- create)
- mkdir -p "$BACKUP_DIR"
- OUT="$BACKUP_DIR/phobos-backup-$(hostname -s 2>/dev/null || echo srv)-$(date +%Y%m%d-%H%M%S).tar.gz"
- # -P: absolute paths (restore lands in original locations). obfuscator confs by glob.
- EXIST=()
- for p in "${PATHS[@]}"; do [ -e "$p" ] && EXIST+=("$p"); done
- for f in "$PHOBOS_DIR"/server/wg-obfuscator-*.conf; do [ -e "$f" ] && EXIST+=("$f"); done
- tar -czf "$OUT" -P --ignore-failed-read "${EXIST[@]}" 2>/dev/null
- chmod 600 "$OUT"
- echo "$OUT"
- ;;
- restore)
- FILE="${2:-}"
- [ -f "$FILE" ] || { echo "Файл не найден: $FILE"; exit 1; }
- # sanity: must be a phobos backup (contains server.env or wg0.conf)
- if ! tar -tzf "$FILE" 2>/dev/null | grep -qE 'server\.env|wg0\.conf'; then
- echo "Не похоже на бэкап PCA Phobos (нет server.env/wg0.conf). Отмена."; exit 1
- fi
- # safety snapshot before overwrite
- PRE="$BACKUP_DIR/pre-restore-$(date +%Y%m%d-%H%M%S).tar.gz"
- mkdir -p "$BACKUP_DIR"
- PEX=()
- for p in "${PATHS[@]}"; do [ -e "$p" ] && PEX+=("$p"); done
- for f in "$PHOBOS_DIR"/server/wg-obfuscator-*.conf; do [ -e "$f" ] && PEX+=("$f"); done
- [ ${#PEX[@]} -gt 0 ] && tar -czf "$PRE" -P --ignore-failed-read "${PEX[@]}" 2>/dev/null && echo "Снимок до восстановления: $PRE"
- tar -xzf "$FILE" -P
- chmod 600 /etc/wireguard/wg0.conf 2>/dev/null || true
- systemctl restart wg-quick@wg0 2>/dev/null || true
- for s in $(systemctl list-units --all --plain --no-legend 'wg-obfuscator-*' 2>/dev/null | awk '{print $1}'); do
- systemctl restart "$s" 2>/dev/null || true
- done
- systemctl restart "$(panel_service_name)" 2>/dev/null || true
- echo "Восстановлено из $FILE. Сервисы перезапущены."
- ;;
- list)
- echo "Бэкапы в $BACKUP_DIR:"
- ls -lht "$BACKUP_DIR"/phobos-backup-*.tar.gz 2>/dev/null | awk '{print " "$9" ("$5")"}' || echo " нет"
- ;;
- *)
- echo "phobos-backup — бэкап/восстановление сервера PCA Phobos"
- echo " create создать бэкап"
- echo " restore восстановить"
- echo " list список бэкапов"
- ;;
-esac
diff --git a/server/phobos-cascade.sh b/server/phobos-cascade.sh
deleted file mode 100755
index 7e4c168..0000000
--- a/server/phobos-cascade.sh
+++ /dev/null
@@ -1,93 +0,0 @@
-#!/usr/bin/env bash
-# PCA Phobos — cascade relay. Run on an ENTRY VPS (e.g. in Russia, "white" IP):
-# clients connect to this server, UDP obfuscator ports are forwarded to the EXIT
-# Phobos server abroad. The entry box needs no Phobos, no keys, no panel.
-# bash <(curl -fsSL .../server/phobos-cascade.sh) enable [ports]
-# phobos-cascade.sh disable | status | apply
-# Then in the exit server panel: Settings -> "Адрес для клиентов" -> entry IP/domain.
-set -uo pipefail
-STATE=/etc/phobos-cascade.env
-BIN=/usr/local/sbin/phobos-cascade
-SELF_URL="${SELF_URL:-https://git.bobyrev.com/PCA/PCA_Phobos/raw/branch/main/server/phobos-cascade.sh}"
-TAG="phobos-cascade"
-
-clear_rules() {
- local t
- for t in nat filter; do
- iptables -t $t -S 2>/dev/null | grep -- "--comment $TAG" | sed 's/^-A /-D /' | \
- while read -r rule; do eval iptables -t $t $rule 2>/dev/null; done
- done
-}
-
-apply() {
- [ -f "$STATE" ] || { echo "cascade: not configured"; return 0; }
- . "$STATE"
- local ip p
- ip=$(getent ahostsv4 "$EXIT_HOST" | awk 'NR==1{print $1}')
- [ -n "$ip" ] || { echo "cascade: cannot resolve $EXIT_HOST" >&2; return 1; }
- sysctl -qw net.ipv4.ip_forward=1
- clear_rules
- for p in ${PORTS//,/ }; do
- iptables -t nat -A PREROUTING -p udp --dport "$p" -m comment --comment $TAG -j DNAT --to-destination "$ip:$p"
- iptables -t nat -A POSTROUTING -p udp -d "$ip" --dport "$p" -m comment --comment $TAG -j MASQUERADE
- iptables -I FORWARD -p udp -d "$ip" --dport "$p" -m comment --comment $TAG -j ACCEPT
- iptables -I FORWARD -p udp -s "$ip" --sport "$p" -m comment --comment $TAG -j ACCEPT
- done
- echo "cascade: udp ${PORTS} -> ${EXIT_HOST} (${ip})"
-}
-
-enable() {
- local host="${1:-}" ports="${2:-2083,5443,993}"
- [ -n "$host" ] || { echo "usage: $0 enable [ports]" >&2; exit 2; }
- [[ "$ports" =~ ^[0-9]+(,[0-9]+)*$ ]] || { echo "bad ports: $ports" >&2; exit 2; }
- command -v iptables >/dev/null || DEBIAN_FRONTEND=noninteractive apt-get install -y -qq iptables >/dev/null
- printf 'EXIT_HOST=%s\nPORTS=%s\n' "$host" "$ports" > "$STATE"
- # bash <(curl ...) gives a pipe as $0 -> fetch a real copy for the systemd unit
- if [ "$(readlink -f "$0")" != "$BIN" ]; then
- if [ -f "$0" ]; then cp "$0" "$BIN"; else curl -kfsSL -m30 "$SELF_URL" -o "$BIN" || { echo "cannot save $BIN" >&2; exit 1; }; fi
- chmod +x "$BIN"
- fi
- cat > /etc/systemd/system/phobos-cascade.service </dev/null 2>&1
- systemctl restart phobos-cascade.service
- apply >/dev/null
- status
-}
-
-disable() {
- systemctl disable --now phobos-cascade.service >/dev/null 2>&1 || true
- clear_rules
- rm -f /etc/systemd/system/phobos-cascade.service "$STATE"
- systemctl daemon-reload
- echo "cascade: disabled"
-}
-
-status() {
- local host="" ports="" rules
- [ -f "$STATE" ] && . "$STATE" && host="$EXIT_HOST" && ports="$PORTS"
- rules=$(iptables -t nat -S PREROUTING 2>/dev/null | grep -c -- "--comment $TAG")
- printf '{"enabled": %s, "exit_host": "%s", "ports": "%s", "rules": %s}\n' \
- "$([ "$rules" -gt 0 ] && echo true || echo false)" "$host" "$ports" "$rules"
-}
-
-case "${1:-status}" in
- enable) enable "${2:-}" "${3:-}" ;;
- apply) apply ;;
- stop) clear_rules ;;
- disable) disable ;;
- status) status ;;
- *) echo "usage: $0 enable [ports]|disable|status"; exit 2 ;;
-esac
diff --git a/server/phobos-domain.sh b/server/phobos-domain.sh
deleted file mode 100755
index 678321b..0000000
--- a/server/phobos-domain.sh
+++ /dev/null
@@ -1,105 +0,0 @@
-#!/usr/bin/env bash
-# PCA Phobos — panel domain: https:/// via nginx + Let's Encrypt.
-# The panel keeps listening on its old http port, so routers/secondaries that
-# already know http://IP:PORT keep working; the domain is an extra entrance.
-# phobos-domain.sh set [email] (SELF_SIGNED=1 for LAN tests)
-# phobos-domain.sh remove | status
-set -uo pipefail
-PANEL_DIR=/opt/phobos-panel
-SITE=/etc/nginx/sites-available/phobos-domain
-WEBROOT=/var/www/phobos-acme
-SS_DIR=/etc/phobos-domain
-
-panel_port() { cat "$PANEL_DIR/.port" 2>/dev/null || echo 8443; }
-panel_scheme() { cat "$PANEL_DIR/.scheme" 2>/dev/null || echo http; }
-
-write_site() { # $1=domain $2=cert $3=key ($2 empty -> http only, for ACME)
- local d="$1" up
- up="$(panel_scheme)://127.0.0.1:$(panel_port)"
- {
- echo "server {"
- echo " listen 80;"
- echo " listen [::]:80;"
- echo " server_name $d;"
- echo " location /.well-known/acme-challenge/ { root $WEBROOT; }"
- [ -n "$2" ] && echo " location / { return 301 https://\$host\$request_uri; }"
- echo "}"
- if [ -n "$2" ]; then
- cat < "$SITE"
- ln -sf "$SITE" /etc/nginx/sites-enabled/phobos-domain
- # nginx < 1.25 has no "http2 on;" -> fall back to the old listen flag
- nginx -t >/dev/null 2>&1 || sed -i -e '/http2 on;/d' -e 's/listen 443 ssl;/listen 443 ssl http2;/' -e 's/listen \[::\]:443 ssl;/listen [::]:443 ssl http2;/' "$SITE"
- nginx -t >/dev/null 2>&1 || { nginx -t; return 1; }
- systemctl reload nginx
-}
-
-set_domain() {
- local d="${1:-}" email="${2:-}" cert key
- [[ "$d" =~ ^[A-Za-z0-9]([A-Za-z0-9.-]*[A-Za-z0-9])?\.[A-Za-z]{2,}$ ]] || { echo "bad domain: $d" >&2; exit 2; }
- command -v nginx >/dev/null || { echo "nginx not installed" >&2; exit 1; }
- mkdir -p "$WEBROOT"
- write_site "$d" "" "" || exit 1
- if [ "${SELF_SIGNED:-0}" = 1 ]; then
- mkdir -p "$SS_DIR"
- openssl req -x509 -nodes -newkey rsa:2048 -days 825 -subj "/CN=$d" \
- -keyout "$SS_DIR/$d.key" -out "$SS_DIR/$d.crt" >/dev/null 2>&1
- cert="$SS_DIR/$d.crt"; key="$SS_DIR/$d.key"
- else
- command -v certbot >/dev/null || DEBIAN_FRONTEND=noninteractive apt-get install -y -qq certbot >/dev/null
- local mail_args=(--register-unsafely-without-email)
- [ -n "$email" ] && mail_args=(-m "$email")
- certbot certonly --webroot -w "$WEBROOT" -d "$d" --agree-tos -n "${mail_args[@]}" \
- --deploy-hook "systemctl reload nginx" || {
- echo "certbot failed: check that $d points to this server and port 80 is open" >&2
- rm -f /etc/nginx/sites-enabled/phobos-domain; systemctl reload nginx; exit 1; }
- cert="/etc/letsencrypt/live/$d/fullchain.pem"; key="/etc/letsencrypt/live/$d/privkey.pem"
- fi
- write_site "$d" "$cert" "$key" || exit 1
- echo "$d" > "$PANEL_DIR/.domain"
- echo "domain: https://$d/ -> panel $(panel_scheme)://127.0.0.1:$(panel_port)"
-}
-
-remove() {
- rm -f /etc/nginx/sites-enabled/phobos-domain "$SITE" "$PANEL_DIR/.domain"
- nginx -t >/dev/null 2>&1 && systemctl reload nginx
- echo "domain: removed (certificate kept in /etc/letsencrypt)"
-}
-
-status() {
- local d exp=""
- d=$(cat "$PANEL_DIR/.domain" 2>/dev/null)
- if [ -n "$d" ]; then
- exp=$(echo | timeout 5 openssl s_client -connect 127.0.0.1:443 -servername "$d" 2>/dev/null | openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
- fi
- printf '{"domain": "%s", "cert_expires": "%s"}\n' "$d" "$exp"
-}
-
-case "${1:-status}" in
- set) set_domain "${2:-}" "${3:-}" ;;
- remove) remove ;;
- status) status ;;
- *) echo "usage: $0 set [email]|remove|status"; exit 2 ;;
-esac
diff --git a/server/phobos-guard.sh b/server/phobos-guard.sh
deleted file mode 100755
index 7311d2b..0000000
--- a/server/phobos-guard.sh
+++ /dev/null
@@ -1,113 +0,0 @@
-#!/usr/bin/env bash
-# PCA Phobos — guard: drop RKN probes / scanner subnets before they reach the server.
-# Idea and IP list: github.com/Loorrr293/Auto_IPtables (list: Loorrr293/blocklist).
-# We only download the IP list (data), never third-party code.
-# phobos-guard.sh enable [list_url] install nft table + daily timer
-# phobos-guard.sh update refresh the list now
-# phobos-guard.sh disable remove table + timer
-# phobos-guard.sh status JSON
-set -uo pipefail
-STATE=/etc/phobos-guard.env
-DEFAULT_URL="https://raw.githubusercontent.com/Loorrr293/blocklist/main/blocklist.txt"
-TABLE="inet phobos_guard"
-SELF="$(readlink -f "$0")"
-
-list_url() { [ -f "$STATE" ] && . "$STATE"; echo "${GUARD_URL:-$DEFAULT_URL}"; }
-
-ensure_nft() {
- command -v nft >/dev/null 2>&1 && return 0
- DEBIAN_FRONTEND=noninteractive apt-get install -y -qq nftables >/dev/null 2>&1
-}
-
-update_list() {
- local url tmp nf
- url="$(list_url)"
- tmp="$(mktemp)"; nf="$(mktemp)"
- curl -fsSL -m60 "$url" -o "$tmp" || { rm -f "$tmp" "$nf"; echo "download failed: $url" >&2; return 1; }
- nft add table $TABLE 2>/dev/null || true
- nft add set $TABLE v4 '{ type ipv4_addr; flags interval; auto-merge; }' 2>/dev/null || true
- nft add set $TABLE v6 '{ type ipv6_addr; flags interval; auto-merge; }' 2>/dev/null || true
- nft add chain $TABLE input '{ type filter hook input priority raw; policy accept; }' 2>/dev/null || true
- nft list chain $TABLE input | grep -q '@v4' || nft add rule $TABLE input ip saddr @v4 counter drop
- nft list chain $TABLE input | grep -q '@v6' || nft add rule $TABLE input ip6 saddr @v6 counter drop
- # collapse + skip private/loopback so a bad list can never cut LAN/tunnel/admin
- python3 - "$tmp" > "$nf" <<'PY'
-import ipaddress, sys
-v4, v6 = [], []
-for line in open(sys.argv[1], encoding="utf-8", errors="ignore"):
- for tok in line.split("#", 1)[0].split():
- try:
- n = ipaddress.ip_network(tok, strict=False)
- except ValueError:
- continue
- if n.is_private or n.is_loopback or n.is_link_local or n.prefixlen == 0:
- continue
- (v6 if n.version == 6 else v4).append(n)
-print("flush set inet phobos_guard v4")
-print("flush set inet phobos_guard v6")
-for name, nets in (("v4", v4), ("v6", v6)):
- nets = list(ipaddress.collapse_addresses(nets))
- for i in range(0, len(nets), 2000):
- print("add element inet phobos_guard %s { %s }" % (name, ", ".join(map(str, nets[i:i + 2000]))))
-PY
- local rc=0
- nft -f "$nf" || rc=1
- rm -f "$tmp" "$nf"
- [ "$rc" = 0 ] && echo "guard: list loaded from $url"
- return "$rc"
-}
-
-enable() {
- ensure_nft || { echo "nftables install failed" >&2; exit 1; }
- [ -n "${1:-}" ] && echo "GUARD_URL=$1" > "$STATE" || touch "$STATE"
- cat > /etc/systemd/system/phobos-guard.service < /etc/systemd/system/phobos-guard.timer <<'EOF'
-[Unit]
-Description=Refresh PCA Phobos guard list daily
-[Timer]
-OnBootSec=1min
-OnCalendar=daily
-RandomizedDelaySec=1h
-Persistent=true
-[Install]
-WantedBy=timers.target
-EOF
- systemctl daemon-reload
- systemctl enable --now phobos-guard.timer >/dev/null 2>&1
- update_list
-}
-
-disable() {
- systemctl disable --now phobos-guard.timer >/dev/null 2>&1 || true
- rm -f /etc/systemd/system/phobos-guard.service /etc/systemd/system/phobos-guard.timer "$STATE"
- systemctl daemon-reload
- nft delete table $TABLE 2>/dev/null || true
- echo "guard: disabled"
-}
-
-status() {
- local on=false n4=0 drops=0
- if nft list table $TABLE >/dev/null 2>&1; then
- on=true
- n4=$(nft list set $TABLE v4 2>/dev/null | grep -o '[0-9.]*/[0-9]*\|[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*' | wc -l)
- drops=$(nft list chain $TABLE input 2>/dev/null | grep -o 'packets [0-9]*' | awk '{s+=$2} END {print s+0}')
- fi
- printf '{"enabled": %s, "networks": %s, "dropped_packets": %s, "timer": "%s", "url": "%s"}\n' \
- "$on" "$n4" "$drops" "$(systemctl is-active phobos-guard.timer 2>/dev/null)" "$(list_url)"
-}
-
-case "${1:-status}" in
- enable) enable "${2:-}" ;;
- update) update_list ;;
- disable) disable ;;
- status) status ;;
- *) echo "usage: $0 enable [url]|update|disable|status"; exit 2 ;;
-esac
diff --git a/server/phobos-health.sh b/server/phobos-health.sh
deleted file mode 100755
index a02064c..0000000
--- a/server/phobos-health.sh
+++ /dev/null
@@ -1,458 +0,0 @@
-#!/bin/sh
-# ============================================================
-# Phobos Health Monitor v2 — Keenetic Edition
-# Uses ndmc/RCI instead of wg-tools. Connectivity-based failover.
-# Runs via cron every 60 seconds
-# ============================================================
-
-PHOBOS_DIR="/opt/etc/Phobos"
-CONF="$PHOBOS_DIR/failover.conf"
-STATE="$PHOBOS_DIR/state"
-LOG="$PHOBOS_DIR/health.log"
-OBF_CONF="$PHOBOS_DIR/wg-obfuscator.conf"
-LOCKFILE="/tmp/phobos-health.lock"
-WG_IF="Wireguard3"
-
-MAX_LOG_LINES=200
-# Thresholds (seconds)
-HANDSHAKE_WARN=150
-HANDSHAKE_PORT_HOP=300
-HANDSHAKE_SERVER_SWITCH=600
-PRIMARY_CHECK_INTERVAL=300
-# Primary-alive probe: servers block ICMP and busybox `nc -z` is unreliable,
-# so reachability is tested with curl against the panel's obfuscator-health
-# endpoint on the primary VPS. It returns http 200 ONLY when all
-# wg-obfuscator-* services are active — the bare panel port stays up even
-# when the tunnel path is dead, so we must NOT switch back on panel liveness
-# alone (that caused premature switchback to a dead primary).
-PRIMARY_PROBE_SCHEME="${PRIMARY_PROBE_SCHEME:-$(cat "$PHOBOS_DIR/panel_scheme" 2>/dev/null)}"
-PRIMARY_PROBE_SCHEME="${PRIMARY_PROBE_SCHEME:-http}"
-PRIMARY_PROBE_PORT="${PRIMARY_PROBE_PORT:-$(cat "$PHOBOS_DIR/panel_port" 2>/dev/null)}"
-PRIMARY_PROBE_PORT="${PRIMARY_PROBE_PORT:-8443}"
-PRIMARY_PROBE_PATH="/api/obf-health"
-# Connectivity check targets (logged for context only)
-CHECK_HOST_1="8.8.8.8"
-CHECK_HOST_2="1.1.1.1"
-
-log() {
- echo "$(date '+%H:%M:%S') $1" >> "$LOG"
- if [ "$(wc -l < "$LOG" 2>/dev/null)" -gt "$MAX_LOG_LINES" ]; then
- tail -n 100 "$LOG" > "$LOG.tmp" && mv "$LOG.tmp" "$LOG"
- fi
-}
-
-# Prevent concurrent runs
-if [ -f "$LOCKFILE" ]; then
- pid=$(cat "$LOCKFILE" 2>/dev/null)
- if kill -0 "$pid" 2>/dev/null; then
- exit 0
- fi
-fi
-echo $$ > "$LOCKFILE"
-trap 'rm -f "$LOCKFILE"' EXIT
-
-mkdir -p "$STATE"
-
-# ── Detect WG interface ──
-detect_wg_interface() {
- for i in 0 1 2 3 4 5 6 7 8 9; do
- desc=$(ndmc -c "show interface Wireguard${i}" 2>/dev/null | grep description | head -1)
- if echo "$desc" | grep -qi phobos; then
- WG_IF="Wireguard${i}"
- return 0
- fi
- done
- return 1
-}
-
-# ── Read failover config ──
-if [ ! -f "$CONF" ]; then
- log "ERROR: no failover.conf"
- exit 1
-fi
-
-SERVER_COUNT=0
-idx=1
-while true; do
- val=$(grep "^SERVER_${idx}=" "$CONF" 2>/dev/null | cut -d= -f2-)
- [ -z "$val" ] && break
- eval "SERVER_${idx}_HOST=$(echo "$val" | cut -d: -f1)"
- eval "SERVER_${idx}_PORTS=$(echo "$val" | cut -d: -f2-)"
- eval "SERVER_${idx}_KEY=$(grep "^KEY_${idx}=" "$CONF" 2>/dev/null | cut -d= -f2-)"
- eval "SERVER_${idx}_WGKEY=$(grep "^WGKEY_${idx}=" "$CONF" 2>/dev/null | cut -d= -f2-)"
- SERVER_COUNT=$idx
- idx=$((idx + 1))
-done
-
-if [ "$SERVER_COUNT" -eq 0 ]; then
- log "ERROR: no servers in failover.conf"
- exit 1
-fi
-
-# Read state
-CURRENT_SERVER=$(cat "$STATE/current_server" 2>/dev/null || echo "1")
-CURRENT_PORT_IDX=$(cat "$STATE/current_port_idx" 2>/dev/null || echo "0")
-FAIL_COUNT=$(cat "$STATE/fail_count" 2>/dev/null || echo "0")
-PRIMARY_CHECK_TS=$(cat "$STATE/primary_check_ts" 2>/dev/null || echo "0")
-
-# ── Detect Phobos WG interface (non-fatal, fallback to Wireguard3) ──
-detect_wg_interface || {
- log "WARN: detect failed, using default $WG_IF"
-}
-
-# ── Get handshake age via ndmc ──
-# A peer switch can leave the removed peer's stale handshake listed in ndmc
-# output (often a huge sentinel like 2147483647). Take the FRESHEST (minimum
-# positive, sane) handshake across all peers — that is the live tunnel.
-get_handshake_age() {
- hs=$(ndmc -c "show interface $WG_IF" 2>/dev/null \
- | grep "last-handshake" \
- | awk '{v=$2} v>0 && v<86400 {print v}' \
- | sort -n | head -1)
- if [ -z "$hs" ]; then
- echo "9999"
- else
- echo "$hs"
- fi
-}
-
-# ── Check real connectivity ──
-check_connectivity() {
- ping -c 1 -W 3 "$CHECK_HOST_1" >/dev/null 2>&1 && return 0
- ping -c 1 -W 3 "$CHECK_HOST_2" >/dev/null 2>&1 && return 0
- return 1
-}
-
-# ── Get port by index ──
-get_port() {
- server_idx=$1; port_idx=$2
- eval "ports=\$SERVER_${server_idx}_PORTS"
- echo "$ports" | tr ',' '\n' | sed -n "$((port_idx + 1))p"
-}
-
-get_port_count() {
- server_idx=$1
- eval "ports=\$SERVER_${server_idx}_PORTS"
- echo "$ports" | tr ',' '\n' | wc -l
-}
-
-# ── Keys currently on the interface (includes the interface's OWN key) ──
-# WG public keys are 43 base64 chars + '='. The interface's own public-key is
-# also matched here — callers must only act on KNOWN server WGKEYs so the
-# local key is never touched.
-list_iface_keys() {
- ndmc -c "show interface $WG_IF" 2>/dev/null \
- | grep -oE '[A-Za-z0-9+/]{43}=' | sort -u
-}
-
-# Count how many KNOWN server WGKEYs are currently attached as peers.
-count_server_peers() {
- present=$(list_iface_keys)
- n=0
- i=1
- while [ "$i" -le "$SERVER_COUNT" ]; do
- eval "wk=\$SERVER_${i}_WGKEY"
- if [ -n "$wk" ] && echo "$present" | grep -q "^${wk}$"; then
- n=$((n + 1))
- fi
- i=$((i + 1))
- done
- echo "$n"
-}
-
-# ── Switch WG peer so EXACTLY ONE server peer (new_key) remains ──
-# Failover adds a new peer; the RCI "remove" is unreliable on Keenetic and
-# leaves dead peers behind. Multiple peers each with allow-ips 0.0.0.0/0 make
-# egress routing ambiguous. We hard-purge every OTHER known server key via the
-# ndmc CLI (reliable) — never the interface's own key — then ensure new_key.
-switch_wg_peer() {
- new_key=$1
-
- if [ -z "$new_key" ]; then
- log "WARN: no WGKEY for target server, skip peer switch"
- return 1
- fi
-
- present=$(list_iface_keys)
-
- # Purge any OTHER known server key that is attached
- i=1
- while [ "$i" -le "$SERVER_COUNT" ]; do
- eval "wk=\$SERVER_${i}_WGKEY"
- if [ -n "$wk" ] && [ "$wk" != "$new_key" ] && echo "$present" | grep -q "^${wk}$"; then
- log "WG PEER purge: $wk"
- ndmc -c "interface $WG_IF no wireguard peer $wk" >/dev/null 2>&1
- fi
- i=$((i + 1))
- done
-
- # Add the target peer if it is not already present
- if ! echo "$present" | grep -q "^${new_key}$"; then
- log "WG PEER add: $new_key"
- curl -s -X POST "http://localhost:79/rci/" \
- -H "Content-Type: application/json" \
- -d "{\"interface\":{\"${WG_IF}\":{\"wireguard\":{\"peer\":{\"key\":\"${new_key}\",\"comment\":\"Phobos VPS Server\",\"endpoint\":{\"address\":\"127.0.0.1:13255\"},\"keepalive-interval\":{\"interval\":25},\"allow-ips\":[{\"address\":\"0.0.0.0\",\"mask\":\"0.0.0.0\"},{\"address\":\"::\",\"mask\":\"0\"}]}}}}}" >/dev/null 2>&1
- fi
-
- # Persist config
- ndmc -c "system configuration save" >/dev/null 2>&1
- return 0
-}
-
-# ── Switch to specific server:port ──
-switch_endpoint() {
- server_idx=$1
- port_idx=$2
-
- eval "host=\$SERVER_${server_idx}_HOST"
- eval "obf_key=\$SERVER_${server_idx}_KEY"
- eval "wg_key=\$SERVER_${server_idx}_WGKEY"
- port=$(get_port "$server_idx" "$port_idx")
-
- if [ -z "$host" ] || [ -z "$port" ]; then
- log "ERROR: invalid server $server_idx port_idx $port_idx"
- return 1
- fi
-
- log "SWITCH → server $server_idx ($host:$port)"
-
- # 1. Switch WG peer key if different server
- switch_wg_peer "$wg_key"
-
- # 2. Update obfuscator config
- if [ -f "$OBF_CONF" ]; then
- sed -i "s|^target = .*|target = ${host}:${port}|" "$OBF_CONF"
- if [ -n "$obf_key" ]; then
- sed -i "s|^key = .*|key = ${obf_key}|" "$OBF_CONF"
- fi
- fi
-
- # 3. Restart obfuscator
- if [ -f /opt/etc/init.d/S49wg-obfuscator ]; then
- /opt/etc/init.d/S49wg-obfuscator restart >/dev/null 2>&1
- else
- killall wg-obfuscator 2>/dev/null
- sleep 1
- wg-obfuscator --config "$OBF_CONF" &
- fi
-
- # 4. Save state (fail_count is managed by the caller, NOT reset here —
- # resetting on a port-hop would prevent escalation to server failover)
- echo "$server_idx" > "$STATE/current_server"
- echo "$port_idx" > "$STATE/current_port_idx"
-}
-
-# ── Try next port on current server ──
-try_next_port() {
- port_count=$(get_port_count "$CURRENT_SERVER")
- next_idx=$(( (CURRENT_PORT_IDX + 1) % port_count ))
- [ "$next_idx" -eq 0 ] && return 1
-
- log "PORT HOP → port idx $next_idx on server $CURRENT_SERVER"
- switch_endpoint "$CURRENT_SERVER" "$next_idx"
- return 0
-}
-
-# ── Try next server ──
-try_next_server() {
- next=$((CURRENT_SERVER + 1))
- [ "$next" -gt "$SERVER_COUNT" ] && next=1
- [ "$next" -eq "$CURRENT_SERVER" ] && return 1
-
- log "FAILOVER → server $next"
- switch_endpoint "$next" "0"
- return 0
-}
-
-# ── Check if primary is back ──
-check_primary() {
- [ "$CURRENT_SERVER" -eq 1 ] && return
-
- now=$(date +%s)
- elapsed=$((now - PRIMARY_CHECK_TS))
- [ "$elapsed" -lt "$PRIMARY_CHECK_INTERVAL" ] && return
- echo "$now" > "$STATE/primary_check_ts"
-
- eval "host=\$SERVER_1_HOST"
- # Probe the obfuscator-health endpoint: http 200 ONLY when the primary's
- # obfuscator path is actually up. Anything else (000 no-response, 503
- # obf-down, redirects) means the tunnel path is NOT viable → stay put.
- ok_url=""
- last_code=""
- for url in "${PRIMARY_PROBE_SCHEME}://${host}:${PRIMARY_PROBE_PORT}${PRIMARY_PROBE_PATH}" "http://${host}:8444${PRIMARY_PROBE_PATH}"; do
- code=$(curl -k -s -m 4 -o /dev/null -w '%{http_code}' "$url" 2>/dev/null)
- last_code="$code"
- if [ "$code" = "200" ]; then
- ok_url="$url"
- break
- fi
- done
- if [ -n "$ok_url" ]; then
- log "PRIMARY ($ok_url http=200) alive, switching back"
- switch_endpoint 1 0
- echo "0" > "$STATE/fail_count"
- else
- log "PRIMARY still down (obf-health http=${last_code:-none}), staying on server $CURRENT_SERVER"
- fi
-}
-
-# ── LAN routing self-heal ──────────────────────
-# A router REBOOT silently drops the per-device `ip hotspot host