From 1ddb51312c3550b5133a300f79ecacd2995003c3 Mon Sep 17 00:00:00 2001 From: Anton Afanasyeu Date: Mon, 8 Jun 2026 20:53:37 +0200 Subject: [PATCH] sync --- .../remoteaccess/RemoteAccessVpnService.java | 28 ++- docs/OPEN_TASKS_GRAPH.md | 171 +++++++++++------- .../backend/config/config.example.php | 19 +- .../backend/scripts/ra_udp_debug.sh | 4 +- .../backend/src/RemoteAccessRepository.php | 15 +- .../backend/src/WireGuardAddressPool.php | 25 +++ .../backend/src/WireGuardPeerProvisioner.php | 29 ++- .../crash_reporter/backend/src/bootstrap.php | 1 + examples/wireguard/BE_alpine/wg0.conf | 6 +- examples/wireguard/FE_wireguard_dnat.sh | 43 +++++ examples/wireguard/alpine-be-sudoers-wg | 6 + .../wireguard/install_be_remote_access.sh | 47 +++++ examples/wireguard/router_wireguard_dnat.sh | 13 ++ 13 files changed, 302 insertions(+), 105 deletions(-) create mode 100644 examples/crash_reporter/backend/src/WireGuardAddressPool.php create mode 100755 examples/wireguard/FE_wireguard_dnat.sh create mode 100644 examples/wireguard/alpine-be-sudoers-wg create mode 100755 examples/wireguard/install_be_remote_access.sh create mode 100644 examples/wireguard/router_wireguard_dnat.sh diff --git a/app/src/main/java/com/foxx/androidcast/remoteaccess/RemoteAccessVpnService.java b/app/src/main/java/com/foxx/androidcast/remoteaccess/RemoteAccessVpnService.java index d1ac8fc..4192593 100644 --- a/app/src/main/java/com/foxx/androidcast/remoteaccess/RemoteAccessVpnService.java +++ b/app/src/main/java/com/foxx/androidcast/remoteaccess/RemoteAccessVpnService.java @@ -85,10 +85,13 @@ public final class RemoteAccessVpnService extends VpnService { String[] parts = address.split("/"); b.addAddress(InetAddress.getByName(parts[0]), parts.length > 1 ? Integer.parseInt(parts[1]) : 32); - } else { - b.addAddress("10.66.66.2", 32); } - b.addRoute("10.66.66.0", 24); + for (String route : parseAllowedRoutes(wgConfig)) { + String[] rp = route.split("/"); + if (rp.length >= 2) { + b.addRoute(rp[0], Integer.parseInt(rp[1])); + } + } b.setMtu(1280); tun = b.establish(); Log.i(TAG, "VPN interface established"); @@ -105,6 +108,25 @@ public final class RemoteAccessVpnService extends VpnService { return m.find() ? m.group(1).trim() : null; } + /** Routes from AllowedIPs= lines (split tunnel — typically server wg /32). */ + private static String[] parseAllowedRoutes(String wgConfig) { + if (wgConfig == null) { + return new String[0]; + } + Matcher m = Pattern.compile("(?m)^AllowedIPs\\s*=\\s*(.+)$").matcher(wgConfig); + if (!m.find()) { + return new String[0]; + } + String[] parts = m.group(1).trim().split("\\s*,\\s*"); + java.util.ArrayList out = new java.util.ArrayList<>(); + for (String p : parts) { + if (!p.isEmpty()) { + out.add(p.trim()); + } + } + return out.toArray(new String[0]); + } + private void tearDown() { if (tun != null) { try { diff --git a/docs/OPEN_TASKS_GRAPH.md b/docs/OPEN_TASKS_GRAPH.md index 51244fe..d15e9e3 100644 --- a/docs/OPEN_TASKS_GRAPH.md +++ b/docs/OPEN_TASKS_GRAPH.md @@ -1,6 +1,6 @@ # Open tasks — dependency graph -_Last synced: 2026-06-08. Renumbered per [20260608_ALPHA_PRIORITIES.md](20260608_ALPHA_PRIORITIES.md)._ +_Last synced: 2026-06-04. **2.1–2.3 postponed** (developer DNS path deferred). Renumbered per [20260608_ALPHA_PRIORITIES.md](20260608_ALPHA_PRIORITIES.md)._ **Documentation index:** [README.md](README.md) @@ -9,25 +9,53 @@ _Last synced: 2026-06-08. Renumbered per [20260608_ALPHA_PRIORITIES.md](20260608 ## Table of contents -- [Priority tiers](#priority-tiers) +- [Removed from graph (done)](#removed-from-graph-done) +- [Postponed (off graph)](#postponed-off-graph) +- [Priority tiers (open only)](#priority-tiers-open-only) - [Dependency graph](#dependency-graph) -- [Task index](#task-index) +- [Task index (open)](#task-index-open) - [Critical path](#critical-path) --- -## Priority tiers +## Removed from graph (done) + +| ID | Note | +|----|------| +| **0.1** | Stream dump — `StreamDumpWriter` + dev setting | +| **3.x** | Register + verify + TOTP + migration `008` (BE + views) | +| **4.x** | RSSH alpha — BE bastion, Android mode, JSch tunnel | +| **4.wg** | WG lab — BE `wg0`, FE DNAT via `xen_firewall.sh`, prod API smoke OK | +| **RBAC** (core) | Admin panel + lockout clear; **5.5 validate** still open | + +--- + +## Postponed (off graph) + +| ID | Owner | Note | +|----|-------|------| +| **2.1** | Developer | DNS MX/SPF — deferred | +| **2.2** | Developer | Forward addresses — deferred | +| **2.3** | Developer | Inbound verify — deferred | +| **2.4** | Developer | Gmail filters — optional; with 2.x | +| **2.5** | Agent | SMTP outbound — frozen until 2.1 resumes | +| **5.4** (mail) | Agent | G2–G6 **email** legs — frozen until 2.5; UI/TOTP can be tested without mail | + +Checklist when resumed: [tmp/20260608_help_request.md](../tmp/20260608_help_request.md) + +--- + +## Priority tiers (open only) | Tier | IDs | Alpha blocker | |------|-----|---------------| -| P0 debug | **0.1** stream dump | No (feeds 6.5/6.6) | -| P1 | **1** graphs | No | -| P2 | **2.1–2.4** dev, **2.5** + **3.x** agent, RBAC | **Yes** (auth) | -| P3 | **4.x** RSSH | **Yes** | -| P4 | **5.x** backend validation | **Yes** | -| P5 | **6.x** app LAN | LAN alpha | -| P9 | **9.x** landing | No | +| **WIP / QA** | Browser JS, reachability | **Yes** (blocks BE sign-off) | +| **P1** | **1.1 / 1.2** graphs | No | +| **P4** | **5.1–5.3, 5.5** validation + OTA/URLs | **Yes** (auth mail path **deferred**) | +| **P5** | **6.1–6.6** app LAN | LAN alpha | +| **P9** | **9.x** landing | No | +| **Infra** | Router WG DNAT persist | No (lab only) | --- @@ -35,87 +63,90 @@ _Last synced: 2026-06-08. Renumbered per [20260608_ALPHA_PRIORITIES.md](20260608 ```mermaid flowchart TB - S01["0.1 stream dump
agent · P0"] - G1["1.x graphs
agent · P1"] + subgraph WIP["WIP — QA / deploy"] + BR["Browser checks
JS SyntaxError · views"] + REACH["Services reachability
OTA/crash URLs"] + end - D21["2.1 DNS
DEV"] - D22["2.2 forward
DEV"] - D23["2.3 inbound test
DEV"] - A25["2.5 SMTP
agent"] - A3["3.x 2FA
agent"] - RBAC["RBAC
agent"] + subgraph P1["P1 graphs"] + G11["1.1 pending fixes"] + G12["1.2 pending FRs"] + end - R4["4.x RSSH
agent · P3"] + subgraph P4["P4 backend alpha"] + B51["5.1 OTA channel
50/50"] + B52["5.2 device URLs
50/50"] + B53["5.3 RSSH validate"] + B55["5.5 RBAC validate"] + end - B51["5.1 OTA
50/50"] - B52["5.2 URLs
50/50"] - B53["5.3 RSSH validate"] - B54["5.4 auth validate"] - B55["5.5 RBAC validate"] + subgraph P5["P5 app LAN — dev"] + A61["6.1 Opus/Speex"] + A62["6.2 LAN soak"] + A63["6.3 lifecycle"] + A64["6.4 rotation"] + A65["6.5 audio lag"] + A66["6.6 stream analysis
uses 0.1 dumps"] + end - A61["6.1 Opus"] - A62["6.2 LAN soak"] - A63["6.3 lifecycle"] - A64["6.4 rotation"] - A65["6.5 audio lag"] + subgraph P9["P9 landing"] + L9["9.x hub / globe"] + end - L9["9.x landing
LOW"] + subgraph INFRA["Infra — non-alpha"] + RDNAT["Router WG DNAT
f0xx.org persist"] + end - FULL["FULL_ALPHA"] + FULL["FULL_ALPHA
mail path deferred"] - S01 -.-> A65 & A64 - D21 --> D22 --> D23 - D21 --> A25 --> A3 --> RBAC - A3 --> B54 --> FULL - RBAC --> B55 + BR --> G11 & G12 + BR --> B55 + REACH --> B51 & B52 - R4 --> B53 --> FULL - B51 & B52 --> FULL + B53 --> FULL + B55 --> FULL + B51 --> FULL + B52 --> FULL A62 --> FULL - A63 <--> A64 - G1 -.-> L9 - L9 -.-> RBAC + A63 <--> A64 + A65 --> A66 + G11 -.-> L9 style FULL fill:#1e3a5f,color:#fff - style D21 fill:#b45309,color:#fff - style D22 fill:#b45309,color:#fff - style D23 fill:#b45309,color:#fff - style R4 fill:#7c2d12,color:#fff - style A3 fill:#7c2d12,color:#fff + style BR fill:#991b1b,color:#fff ``` --- -## Task index +## Task index (open) -| ID | Owner | Depends on | -|----|-------|------------| -| **0.1** | Agent | — | -| **1 / 1.1 / 1.2** | Agent | BE deploy soft | -| **2.1–2.4** | **Developer** | DNS UI access | -| **2.5** | Agent | 2.1 | -| **3.x** | Agent | 2.5 | -| **RBAC** | Agent | 3.x, stable pages | -| **4.x** | Agent | BE deploy | -| **5.1–5.2** | 50/50 | deploy | -| **5.3** | Agent | 4.x | -| **5.4–5.5** | Agent | 3.x, RBAC | -| **6.1–6.6** | Developer (~99%) | 0.1 ↔ 6.6 | -| **9.x** | Agent (low) | — | +| ID | Owner | Depends on | Status | +|----|-------|------------|--------| +| **Browser** | Agent | BE deploy | WIP — `SyntaxError` on crashes/graphs/tickets | +| **Reachability** | 50/50 | deploy | WIP — OTA path, crash URL host | +| **1.1** | Agent | browser OK | Open | +| **1.2** | Agent | 1.1 soft | Open | +| **5.1** | 50/50 | reachability | Open | +| **5.2** | 50/50 | reachability | Open | +| **5.3** | Agent | 4.x ✓ | Validate E2E RSSH | +| **5.5** | Agent | RBAC ✓, browser | Validate admin flows | +| **6.1–6.6** | Developer (~99%) | 0.1 ✓ for 6.6 | Open | +| **9.x** | Agent (low) | bandwidth | Open | +| **Router DNAT** | Agent | — | Open — `router_wireguard_dnat.sh` | --- ## Critical path ```text -DEV: 2.1 → 2.2 → 2.3 -AGENT: 2.5 → 3.x → 5.4 ──┐ -AGENT: 4.x → 5.3 ─────────┼──► FULL_ALPHA -SHARED: 5.1 OTA, 5.2 URLs ─┤ -DEV: 6.2 LAN soak ────────┘ +BLOCKER: Browser JS fix + deploy ──► 1.x, 5.5 UI validation -Parallel: 0.1, 1.x, 6.1/6.3–6.5, 9.x +AGENT: 5.3 RSSH validate (4.x done) ──┐ +SHARED: 5.1 OTA, 5.2 URLs ─────────────┼──► FULL_ALPHA (LAN + RSSH + RBAC) +DEV: 6.2 LAN soak ─────────────────┘ + +Deferred (not on graph): 2.1 → 2.2 → 2.3 → 2.5 → 5.4 mail E2E + +Parallel: 6.1/6.3–6.6, 9.x, router WG DNAT, Android APK rebuild (WG route fix) ``` - -**Developer blocked checklist:** [tmp/20260608_help_request.md](../tmp/20260608_help_request.md) diff --git a/examples/crash_reporter/backend/config/config.example.php b/examples/crash_reporter/backend/config/config.example.php index 6a8c2ea..309fc02 100644 --- a/examples/crash_reporter/backend/config/config.example.php +++ b/examples/crash_reporter/backend/config/config.example.php @@ -47,15 +47,20 @@ return [ ], // On-demand remote access (WireGuard v1) — see docs/REMOTE_ACCESS_IMPL.md 'remote_access' => [ - // Public UDP endpoint shown to devices (FE DNAT → BE wg0) - 'wg_endpoint' => 'ra.apps.f0xx.org:51820', - // Server WG public key (wg show wg0 public-key on BE) - 'wg_server_public_key' => '', + // Public UDP endpoint (FE DNAT → BE wg0 ListenPort) + 'wg_endpoint' => 'ra.apps.f0xx.org:45340', + // wg show wg0 public-key on BE — REQUIRED for production connect + 'wg_server_public_key' => 'EV2nnwHH7xe3jA5J46Rjtl8ao+ybZinibKg2Hy83GBw=', 'wg_interface' => 'wg0', - // Run `wg set wg0 peer …` when device receives connect (requires wireguard-tools on BE) + // Client / server addresses (must match wg0 Address subnet on BE) + 'wg_server_allowed_ips' => '172.200.2.1/32', + 'wg_client_ip_prefix' => '172.200.2.', + 'wg_client_ip_min' => 10, + 'wg_client_ip_max' => 250, + // Prefix for `wg set` when PHP-FPM runs as nobody (see examples/wireguard/alpine-be-sudoers-wg) + 'wg_set_prefix' => 'sudo -n ', 'provision_peers' => true, - // Reject connect if wg genkey/pubkey unavailable (set true on production BE) - 'require_wg_tools' => false, + 'require_wg_tools' => true, 'session_ttl_s' => 3600, 'min_poll_interval_s' => 45, // Reverse SSH (alpha): outbound -R from device; no VpnService on phone diff --git a/examples/crash_reporter/backend/scripts/ra_udp_debug.sh b/examples/crash_reporter/backend/scripts/ra_udp_debug.sh index 52e0817..5c2dd6d 100755 --- a/examples/crash_reporter/backend/scripts/ra_udp_debug.sh +++ b/examples/crash_reporter/backend/scripts/ra_udp_debug.sh @@ -9,8 +9,8 @@ ROOT="$(cd "$(dirname "$0")/.." && pwd)" source "$ROOT/scripts/ra_lib.sh" WG_HOST="${WG_HOST:-ra.apps.f0xx.org}" -WG_PORT="${WG_PORT:-51820}" -BE_WG_IP="${BE_WG_IP:-10.66.66.1}" +WG_PORT="${WG_PORT:-45340}" +BE_WG_IP="${BE_WG_IP:-172.200.2.1}" DEVICE_ID="${RA_DEVICE_ID:-ra-udp-$(hostname -s | tr ' ' '-')}" CONF="/tmp/ra-udp-${DEVICE_ID}.conf" APPLY="${RA_UDP_APPLY:-0}" diff --git a/examples/crash_reporter/backend/src/RemoteAccessRepository.php b/examples/crash_reporter/backend/src/RemoteAccessRepository.php index 3a8183c..224265e 100644 --- a/examples/crash_reporter/backend/src/RemoteAccessRepository.php +++ b/examples/crash_reporter/backend/src/RemoteAccessRepository.php @@ -336,7 +336,7 @@ final class RemoteAccessRepository { && (bool) cfg('remote_access.require_wg_tools', false)) { return self::raEnvelope('deny', ['reason' => 'wg_tools_required']); } - $endpoint = (string) ($session['endpoint'] ?? cfg('remote_access.wg_endpoint', 'ra.apps.f0xx.org:51820')); + $endpoint = (string) ($session['endpoint'] ?? WireGuardAddressPool::defaultEndpoint()); $expiresAt = (int) ($session['expires_at'] ?? (time() + 3600)); self::markSessionActive($sessionId); @@ -435,7 +435,7 @@ final class RemoteAccessRepository { 'client_public' => $pub, 'client_address' => $addr, 'server_public' => $serverPub, - 'allowed_ips' => $allowed !== '' ? $allowed : '10.66.66.1/32', + 'allowed_ips' => $allowed !== '' ? $allowed : WireGuardAddressPool::serverAllowedIps(), ]; } $pair = self::generateWireGuardKeyPair(); @@ -444,13 +444,13 @@ final class RemoteAccessRepository { if ($pub === '' || str_starts_with($pub, 'dev-placeholder-pub-')) { $pub = WireGuardPeerProvisioner::publicKeyFromPrivate($priv); } - $clientIp = self::allocateClientAddress($sessionId); + $clientIp = WireGuardAddressPool::allocateClientAddress($sessionId); $serverPub = (string) cfg('remote_access.wg_server_public_key', ''); if ($serverPub === '') { $serverPair = self::generateWireGuardKeyPair(); $serverPub = $serverPair['public']; } - $allowed = '10.66.66.1/32'; + $allowed = WireGuardAddressPool::serverAllowedIps(); Database::pdo()->prepare( 'UPDATE remote_access_sessions SET wg_client_private_key = ?, wg_client_public_key = ?, wg_client_address = ?, wg_server_public_key = ?, wg_peer_allowed_ips = ? WHERE session_id = ?' )->execute([$priv, $pub, $clientIp, $serverPub, $allowed, $sessionId]); @@ -468,11 +468,6 @@ final class RemoteAccessRepository { ]; } - private static function allocateClientAddress(string $sessionId): string { - $n = abs(crc32($sessionId)) % 200 + 2; - return '10.66.66.' . $n . '/32'; - } - /** @return array{private:string,public:string} */ public static function generateWireGuardKeyPair(): array { $priv = trim((string) @shell_exec('wg genkey 2>/dev/null') ?: ''); @@ -552,7 +547,7 @@ final class RemoteAccessRepository { $port = (int) cfg('remote_access.rssh.bastion_port', 443); $endpoint = $port === 443 ? $host : $host . ':' . $port; } else { - $endpoint = (string) cfg('remote_access.wg_endpoint', 'ra.apps.f0xx.org:51820'); + $endpoint = WireGuardAddressPool::defaultEndpoint(); } $expiresAt = time() + (int) cfg('remote_access.session_ttl_s', 3600); $now = self::nowSql(); diff --git a/examples/crash_reporter/backend/src/WireGuardAddressPool.php b/examples/crash_reporter/backend/src/WireGuardAddressPool.php new file mode 100644 index 0000000..8abaeca --- /dev/null +++ b/examples/crash_reporter/backend/src/WireGuardAddressPool.php @@ -0,0 +1,25 @@ +&1', $out, $code); + if ($code !== 0) { + error_log('WireGuardPeerProvisioner: ' . $cmd . ' failed: ' . implode(' ', $out)); + } + return $code; } } diff --git a/examples/crash_reporter/backend/src/bootstrap.php b/examples/crash_reporter/backend/src/bootstrap.php index 75e4010..e78ff3a 100644 --- a/examples/crash_reporter/backend/src/bootstrap.php +++ b/examples/crash_reporter/backend/src/bootstrap.php @@ -65,6 +65,7 @@ require_once __DIR__ . '/TicketRepository.php'; require_once __DIR__ . '/GraphRepository.php'; require_once __DIR__ . '/RemoteAccessRepository.php'; require_once __DIR__ . '/WireGuardPeerProvisioner.php'; +require_once __DIR__ . '/WireGuardAddressPool.php'; require_once __DIR__ . '/RsshSessionProvisioner.php'; require_once __DIR__ . '/AnalyticsHead.php'; diff --git a/examples/wireguard/BE_alpine/wg0.conf b/examples/wireguard/BE_alpine/wg0.conf index 6bf198f..2c87b01 100644 --- a/examples/wireguard/BE_alpine/wg0.conf +++ b/examples/wireguard/BE_alpine/wg0.conf @@ -7,6 +7,6 @@ PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE;iptables -D FORWARD -o %i -j ACCEPT; ip6tables -D FORWARD -i %i -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE;ip6tables -D FORWARD -o %i -j ACCEPT [Peer] -# obtained from client device via wireguard connection setup process -PublicKey = EV2nnwHH7xe3jA5J46Rjtl8ao+ybZinibKg2Hy83GBw= -AllowedIPs = 172.200.2.2/16, fddd::1/128 +# Static lab peer only — remote-access clients are added dynamically via wg set (PHP). +# PublicKey = +# AllowedIPs = 172.200.2.2/32 diff --git a/examples/wireguard/FE_wireguard_dnat.sh b/examples/wireguard/FE_wireguard_dnat.sh new file mode 100755 index 0000000..28b75a9 --- /dev/null +++ b/examples/wireguard/FE_wireguard_dnat.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# FE (f0xx-monstro): DNAT public UDP → BE wg0. Matches existing rules to 10.7.16.128 (8088, etc.). +# Invoked from xen_firewall.sh start/stop; also: wireguard_fe_dnat.sh [start|stop] +set -euo pipefail + +BE_IP="${BE_IP:-10.7.16.128}" +WG_PORT="${WG_PORT:-45340}" + +function start() { + if iptables -t nat -C PREROUTING -p udp --dport "$WG_PORT" -j DNAT --to-destination "${BE_IP}:${WG_PORT}" 2>/dev/null; then + echo "DNAT rule already present for udp/${WG_PORT}" + else + iptables -t nat -A PREROUTING -p udp --dport "$WG_PORT" -j DNAT --to-destination "${BE_IP}:${WG_PORT}" + echo "Added PREROUTING DNAT udp/${WG_PORT} -> ${BE_IP}:${WG_PORT}" + fi + + if iptables -C FORWARD -p udp -d "${BE_IP}" --dport "$WG_PORT" -j ACCEPT 2>/dev/null; then + echo "FORWARD rule already present" + else + iptables -A FORWARD -p udp -d "${BE_IP}" --dport "$WG_PORT" -j ACCEPT + echo "Added FORWARD udp -> ${BE_IP}:${WG_PORT}" + fi +} + +function stop() { + if iptables -t nat -C PREROUTING -p udp --dport "$WG_PORT" -j DNAT --to-destination "${BE_IP}:${WG_PORT}" 2>/dev/null; then + iptables -t nat -D PREROUTING -p udp --dport "$WG_PORT" -j DNAT --to-destination "${BE_IP}:${WG_PORT}" + echo "Removed PREROUTING DNAT udp/${WG_PORT}" + else + echo "DNAT rule not present for udp/${WG_PORT}" + fi + + if iptables -C FORWARD -p udp -d "${BE_IP}" --dport "$WG_PORT" -j ACCEPT 2>/dev/null; then + iptables -D FORWARD -p udp -d "${BE_IP}" --dport "$WG_PORT" -j ACCEPT + echo "Removed FORWARD udp -> ${BE_IP}:${WG_PORT}" + else + echo "FORWARD rule not present" + fi +} + +cmd=$1 +cmd=${cmd:-start} +[ "$cmd" = "start" ] && start || stop diff --git a/examples/wireguard/alpine-be-sudoers-wg b/examples/wireguard/alpine-be-sudoers-wg new file mode 100644 index 0000000..bb513be --- /dev/null +++ b/examples/wireguard/alpine-be-sudoers-wg @@ -0,0 +1,6 @@ +# Install on Alpine BE: /etc/sudoers.d/androidcast-wg (chmod 440) +# PHP-FPM pool user is nginx (see /etc/php81/php-fpm.d/www.conf). +Defaults:nobody !requiretty +Defaults:nginx !requiretty +nobody ALL=(root) NOPASSWD: /usr/bin/wg set wg0 peer * +nginx ALL=(root) NOPASSWD: /usr/bin/wg set wg0 peer * diff --git a/examples/wireguard/install_be_remote_access.sh b/examples/wireguard/install_be_remote_access.sh new file mode 100755 index 0000000..40856ab --- /dev/null +++ b/examples/wireguard/install_be_remote_access.sh @@ -0,0 +1,47 @@ +#!/bin/bash +# Run on alpine-be as root after syncing backend tree. +set -euo pipefail + +ROOT="${1:-/var/www/localhost/htdocs/apps/app/androidcast_project/android_cast/examples/crash_reporter/backend}" +CFG="$ROOT/config/config.php" +SUDOERS_DST="/etc/sudoers.d/androidcast-wg" +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" + +if [[ ! -f "$CFG" ]]; then + echo "Missing $CFG" >&2 + exit 1 +fi + +php81 -r ' +$path = $argv[1]; +$c = require $path; +if (!is_array($c)) { fwrite(STDERR, "config.php must return array\n"); exit(1); } +if (isset($c["remote_access"]) && is_array($c["remote_access"]) && ($c["remote_access"]["wg_server_public_key"] ?? "") !== "") { + echo "remote_access already configured\n"; + exit(0); +} +$c["remote_access"] = array_merge($c["remote_access"] ?? [], [ + "wg_endpoint" => "ra.apps.f0xx.org:45340", + "wg_server_public_key" => "EV2nnwHH7xe3jA5J46Rjtl8ao+ybZinibKg2Hy83GBw=", + "wg_interface" => "wg0", + "wg_server_allowed_ips" => "172.200.2.1/32", + "wg_client_ip_prefix" => "172.200.2.", + "wg_client_ip_min" => 10, + "wg_client_ip_max" => 250, + "wg_set_prefix" => "sudo ", + "provision_peers" => true, + "require_wg_tools" => true, + "session_ttl_s" => 3600, + "min_poll_interval_s" => 45, +]); +$export = var_export($c, true); +file_put_contents($path, "/dev/null || rc-service php-fpm restart 2>/dev/null || true +echo "Restarted PHP-FPM" diff --git a/examples/wireguard/router_wireguard_dnat.sh b/examples/wireguard/router_wireguard_dnat.sh new file mode 100644 index 0000000..5e968be --- /dev/null +++ b/examples/wireguard/router_wireguard_dnat.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# Raspberry Pi router (f0xx.org): WAN UDP 45340 → FE (10.7.0.10). Persist via your firewall save. +set -euo pipefail +FE_IP="${FE_IP:-10.7.0.10}" +WG_PORT="${WG_PORT:-45340}" +WAN_IF="${WAN_IF:-eth0}" + +if iptables -t nat -C PREROUTING -i "$WAN_IF" -p udp --dport "$WG_PORT" -j DNAT --to-destination "${FE_IP}:${WG_PORT}" 2>/dev/null; then + echo "Router DNAT already present" +else + iptables -t nat -A PREROUTING -i "$WAN_IF" -p udp --dport "$WG_PORT" -j DNAT --to-destination "${FE_IP}:${WG_PORT}" + echo "Added router PREROUTING udp/${WG_PORT} -> ${FE_IP}:${WG_PORT}" +fi