mirror of
git://f0xx.org/android_cast
synced 2026-07-29 03:57:50 +03:00
be sync - preparing for sfu integration, login hopefully fixed
This commit is contained in:
@@ -80,6 +80,12 @@ return [
|
||||
'max_attempts' => 8,
|
||||
'lockout_window_minutes' => 15,
|
||||
],
|
||||
// SFU / WebRTC relay (post-alpha) — hidden until owner spec; see examples/sfu/README.md
|
||||
'sfu' => [
|
||||
'enabled' => false,
|
||||
'signaling_url' => '', // e.g. wss://apps.f0xx.org/sfu/signal
|
||||
'janus_url' => '', // lab only — port 8089 is a separate stack (INFRA.md)
|
||||
],
|
||||
'mail' => [
|
||||
'transport' => 'smtp', // smtp | sendmail
|
||||
// Alpha: use apex if apps.f0xx.org has CNAME (no MX on subdomain) — see tmp/20260608_help_request.md
|
||||
|
||||
18
examples/crash_reporter/backend/public/api/sfu_health.php
Normal file
18
examples/crash_reporter/backend/public/api/sfu_health.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
require_once __DIR__ . '/../../src/bootstrap.php';
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
$sfu = cfg('sfu', []);
|
||||
$enabled = (bool) ($sfu['enabled'] ?? false);
|
||||
|
||||
echo json_encode([
|
||||
'ok' => true,
|
||||
'sfu' => [
|
||||
'enabled' => $enabled,
|
||||
'status' => $enabled ? 'preview' : 'disabled',
|
||||
'signaling_url' => $enabled ? (string) ($sfu['signaling_url'] ?? '') : '',
|
||||
'janus_url' => $enabled ? (string) ($sfu['janus_url'] ?? '') : '',
|
||||
],
|
||||
], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
@@ -40,6 +40,17 @@ a { color: var(--accent); text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
.shell { display: flex; min-height: calc(100vh - 40px); flex: 1 0 auto; }
|
||||
.shell.single .main-pane { max-width: 1100px; margin: 0 auto; padding: 24px; }
|
||||
.shell.shell--graphs-full .main-pane {
|
||||
max-width: none;
|
||||
width: 100%;
|
||||
padding: 20px 24px 32px;
|
||||
}
|
||||
.shell.shell--graphs-full .graph-detail-body {
|
||||
max-width: none;
|
||||
}
|
||||
.shell.shell--graphs-full .graph-detail-table {
|
||||
max-width: none;
|
||||
}
|
||||
.nav-pane {
|
||||
width: 56px;
|
||||
background: var(--surface);
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/**
|
||||
* File infra validation findings as tickets (tag 20260608-validation).
|
||||
*
|
||||
* Usage:
|
||||
* php scripts/ingest_validation_findings_20260608.php [--url=BASE] [--dry-run]
|
||||
*/
|
||||
declare(strict_types=1);
|
||||
|
||||
$opts = getopt('', ['url::', 'dry-run']);
|
||||
$base = rtrim($opts['url'] ?? 'https://apps.f0xx.org/app/androidcast_project/crashes', '/');
|
||||
$dryRun = isset($opts['dry-run']);
|
||||
$uploadUrl = $base . '/api/ticket_upload.php';
|
||||
|
||||
function val_tags(string $kind): array {
|
||||
$base = [
|
||||
['id' => 'ticket', 'label' => 'ticket', 'bg' => '#6366f1'],
|
||||
['id' => '20260608-validation', 'label' => '20260608-validation', 'bg' => '#f59e0b'],
|
||||
['id' => 'infra', 'label' => 'infra', 'bg' => '#0ea5e9'],
|
||||
];
|
||||
if ($kind === 'issue') {
|
||||
$base[] = ['id' => 'issue', 'label' => 'issue', 'bg' => '#94a3b8'];
|
||||
}
|
||||
return $base;
|
||||
}
|
||||
|
||||
$tasks = [
|
||||
[
|
||||
'key' => 'SVC-OTA',
|
||||
'kind' => 'ticket',
|
||||
'text' => 'ISSUE SVC-OTA: OTA channel HTTP 400 on apps.f0xx.org — wire /v0/ota/ on apps vhost or align device ota.base_url. See docs/20260608_BE_SERVICES_and_infra.md',
|
||||
],
|
||||
[
|
||||
'key' => 'SVC-URL',
|
||||
'kind' => 'ticket',
|
||||
'text' => 'ISSUE SVC-URL: Legacy f0xx.org crash upload URL 404 — production base should be apps.f0xx.org. Update settings.json / dev defaults.',
|
||||
],
|
||||
[
|
||||
'key' => 'SVC-DIAG',
|
||||
'kind' => 'issue',
|
||||
'text' => 'ISSUE SVC-DIAG: diag.php returns 403 at public edge — acceptable; devices use upload.php + heartbeat.php. Documented in BE services map.',
|
||||
],
|
||||
[
|
||||
'key' => 'SFU-SPEC',
|
||||
'kind' => 'issue',
|
||||
'text' => 'PLANNING SFU-SPEC: Janus/mediasoup relay post-alpha — branch feature/sfu-relay (hidden). Await owner spec. Gray section in docs/20260608_BE_SERVICES_and_infra.md',
|
||||
],
|
||||
[
|
||||
'key' => 'graphs-5.1',
|
||||
'kind' => 'ticket',
|
||||
'status' => 'closed',
|
||||
'text' => 'CLOSED 5.1: Graph brick drill-down — full overlay, axes, legend, hover implemented in graphs.js (2026-06-08).',
|
||||
],
|
||||
[
|
||||
'key' => 'graphs-5.2',
|
||||
'kind' => 'ticket',
|
||||
'status' => 'closed',
|
||||
'text' => 'CLOSED 5.2: Graph columns 1/2/4, clickable bricks, full-width shell--graphs-full CSS (2026-06-08).',
|
||||
],
|
||||
[
|
||||
'key' => 'browser-js',
|
||||
'kind' => 'ticket',
|
||||
'status' => 'closed',
|
||||
'text' => 'CLOSED: Browser SyntaxError on console JS — deployed assets pass node --check; validate_be_services.sh added.',
|
||||
],
|
||||
];
|
||||
|
||||
$device = ['manufacturer' => 'validation', 'model' => 'infra', 'sdk_int' => 34, 'release' => '14'];
|
||||
$app = ['package' => 'com.foxx.androidcast', 'version_name' => 'validation', 'version_code' => 1];
|
||||
$now = (int) round(microtime(true) * 1000);
|
||||
|
||||
foreach ($tasks as $task) {
|
||||
$text = trim($task['text']);
|
||||
$key = $task['key'];
|
||||
$status = $task['status'] ?? 'open';
|
||||
$tags = val_tags($task['kind']);
|
||||
if ($status === 'closed') {
|
||||
$tags[] = ['id' => 'closed', 'label' => 'closed', 'bg' => '#6b7280'];
|
||||
} else {
|
||||
$tags[] = ['id' => 'open', 'label' => 'open', 'bg' => '#22c55e'];
|
||||
}
|
||||
$payload = [
|
||||
'schema_version' => 1,
|
||||
'ingest_kind' => 'ticket',
|
||||
'ticket_id' => 'validation-20260608-' . preg_replace('/[^a-z0-9.-]+/i', '-', $key),
|
||||
'title' => mb_substr($text, 0, 256),
|
||||
'brief' => mb_substr($text, 0, 512),
|
||||
'body' => $text,
|
||||
'opened_at_epoch_ms' => $now,
|
||||
'rating' => $status === 'closed' ? 1 : 3,
|
||||
'owner' => 'admin',
|
||||
'tags' => $tags,
|
||||
'device' => $device,
|
||||
'app' => $app,
|
||||
];
|
||||
if ($dryRun) {
|
||||
echo "DRY {$key}\n";
|
||||
continue;
|
||||
}
|
||||
$ch = curl_init($uploadUrl);
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
|
||||
CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
|
||||
CURLOPT_TIMEOUT => 30,
|
||||
]);
|
||||
$resp = curl_exec($ch);
|
||||
$code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
if ($code >= 200 && $code < 300) {
|
||||
echo "OK {$key} HTTP {$code}\n";
|
||||
} else {
|
||||
echo "FAIL {$key} HTTP {$code} {$resp}\n";
|
||||
}
|
||||
}
|
||||
@@ -34,10 +34,16 @@ ra_ra_post() {
|
||||
local device_id="$2"
|
||||
local random="${3:-}"
|
||||
local app_version="${4:-cli-sim}"
|
||||
local caps='["wireguard","files_app_home"]'
|
||||
local mode="${RA_TUNNEL_MODE:-wireguard}"
|
||||
local caps
|
||||
if [[ "$mode" == "rssh" ]]; then
|
||||
caps='["rssh","shell"]'
|
||||
else
|
||||
caps='["wireguard","files_app_home"]'
|
||||
fi
|
||||
local body
|
||||
body=$(printf '{"heartbeat":{"type":"ra","status":"%s","device_id":"%s","random":"%s","app_version":"%s","tunnel_mode":"wireguard","capabilities":%s}}' \
|
||||
"$status" "$device_id" "$random" "$app_version" "$caps")
|
||||
body=$(printf '{"heartbeat":{"type":"ra","status":"%s","device_id":"%s","random":"%s","app_version":"%s","tunnel_mode":"%s","capabilities":%s}}' \
|
||||
"$status" "$device_id" "$random" "$app_version" "$mode" "$caps")
|
||||
local url body_tmp code
|
||||
url="$(ra_heartbeat_url)"
|
||||
body_tmp="$(mktemp)"
|
||||
|
||||
30
examples/crash_reporter/backend/scripts/test_rssh_api.sh
Executable file
30
examples/crash_reporter/backend/scripts/test_rssh_api.sh
Executable file
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env bash
|
||||
# RSSH control-plane smoke: whitelist → open session → connect payload with bastion fields.
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
# shellcheck source=ra_lib.sh
|
||||
source "$ROOT/scripts/ra_lib.sh"
|
||||
|
||||
BASE="$(ra_base)"
|
||||
DEVICE_ID="${RA_DEVICE_ID:-rssh-smoke-$(date +%s)}"
|
||||
COOKIE_JAR="$(mktemp)"
|
||||
trap 'rm -f "$COOKIE_JAR"' EXIT
|
||||
|
||||
ra_admin_login "$COOKIE_JAR"
|
||||
|
||||
body=$(printf '{"heartbeat":{"type":"ra","status":"enable","device_id":"%s","random":"r0","tunnel_mode":"rssh","capabilities":["rssh","shell"]}}' "$DEVICE_ID")
|
||||
code=$(curl -sS -o /tmp/rssh-hb.json -w '%{http_code}' -X POST -H 'Content-Type: application/json' -d "$body" "$(ra_heartbeat_url)")
|
||||
[[ "$code" == "200" ]] || { echo "FAIL heartbeat enable HTTP $code"; cat /tmp/rssh-hb.json; exit 1; }
|
||||
grep -q '"action":"wait"' /tmp/rssh-hb.json && echo OK wait
|
||||
|
||||
ra_admin_post "$COOKIE_JAR" whitelist "$(printf '{"device_id":"%s","whitelisted":true}' "$DEVICE_ID")" >/dev/null
|
||||
ra_admin_post "$COOKIE_JAR" open_session "$(printf '{"device_id":"%s"}' "$DEVICE_ID")" >/dev/null
|
||||
|
||||
body=$(printf '{"heartbeat":{"type":"ra","status":"enable","device_id":"%s","random":"r1","tunnel_mode":"rssh","capabilities":["rssh","shell"]}}' "$DEVICE_ID")
|
||||
curl -sf -X POST -H 'Content-Type: application/json' -d "$body" "$(ra_heartbeat_url)" > /tmp/rssh-connect.json
|
||||
grep -q '"action":"connect"' /tmp/rssh-connect.json && echo OK connect
|
||||
grep -q 'bastion_host' /tmp/rssh-connect.json && echo OK bastion fields
|
||||
grep -q 'remote_port' /tmp/rssh-connect.json && echo OK remote_port
|
||||
|
||||
echo "All RSSH API checks passed."
|
||||
116
examples/crash_reporter/backend/scripts/validate_be_services.sh
Executable file
116
examples/crash_reporter/backend/scripts/validate_be_services.sh
Executable file
@@ -0,0 +1,116 @@
|
||||
#!/usr/bin/env bash
|
||||
# Reachability smoke for mobile-app + console services (public or CRASHES_BASE).
|
||||
# Exit 0 when all required checks pass; prints FAIL lines for ticket triage.
|
||||
set -uo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
PUBLIC="${PUBLIC_BASE:-https://apps.f0xx.org}"
|
||||
CRASHES="${CRASHES_BASE:-${PUBLIC}/app/androidcast_project/crashes}"
|
||||
GRAPH="${GRAPH_BASE:-${PUBLIC}/app/androidcast_project/graphs}"
|
||||
HUB="${HUB_BASE:-${PUBLIC}/app/androidcast_project/}"
|
||||
BUILD="${BUILD_BASE:-${PUBLIC}/app/androidcast_project/build/}"
|
||||
OTA="${OTA_CHANNEL:-${PUBLIC}/v0/ota/channel/stable.json}"
|
||||
|
||||
fail=0
|
||||
ok() { echo "OK $*"; }
|
||||
bad() { echo "FAIL $*"; fail=1; }
|
||||
note() { echo "WARN $*"; }
|
||||
|
||||
http_code() {
|
||||
curl -sS -o /dev/null -w '%{http_code}' --max-time "${CURL_TIMEOUT:-15}" "$1" 2>/dev/null || echo "000"
|
||||
}
|
||||
|
||||
js_syntax() {
|
||||
local url="$1"
|
||||
local tmp
|
||||
tmp="$(mktemp --suffix=.js)"
|
||||
if ! curl -sSLf --max-time "${CURL_TIMEOUT:-15}" "$url" -o "$tmp" 2>/dev/null; then
|
||||
rm -f "$tmp"
|
||||
echo "fetch"
|
||||
return 1
|
||||
fi
|
||||
if node --check "$tmp" 2>/dev/null; then
|
||||
rm -f "$tmp"
|
||||
echo "ok"
|
||||
return 0
|
||||
fi
|
||||
rm -f "$tmp"
|
||||
echo "syntax"
|
||||
return 1
|
||||
}
|
||||
|
||||
echo "== Android Cast service reachability =="
|
||||
echo "PUBLIC=$PUBLIC"
|
||||
echo
|
||||
|
||||
# Hub
|
||||
code="$(http_code "$HUB")"
|
||||
[[ "$code" =~ ^(200|301|302)$ ]] && ok "hub $HUB HTTP $code" || bad "hub $HUB HTTP $code"
|
||||
|
||||
# Crashes console (login redirect OK)
|
||||
code="$(http_code "$CRASHES/")"
|
||||
[[ "$code" =~ ^(200|302)$ ]] && ok "crashes $CRASHES/ HTTP $code" || bad "crashes $CRASHES/ HTTP $code"
|
||||
|
||||
# Graphs
|
||||
code="$(http_code "$GRAPH/")"
|
||||
[[ "$code" =~ ^(200|302)$ ]] && ok "graphs $GRAPH/ HTTP $code" || bad "graphs $GRAPH/ HTTP $code"
|
||||
|
||||
# Builder
|
||||
code="$(http_code "$BUILD")"
|
||||
[[ "$code" =~ ^(200|302)$ ]] && ok "build $BUILD HTTP $code" || bad "build $BUILD HTTP $code"
|
||||
|
||||
# OTA channel (may 404 until wired — warn only)
|
||||
code="$(http_code "$OTA")"
|
||||
if [[ "$code" == "200" ]]; then
|
||||
ok "ota $OTA HTTP $code"
|
||||
elif [[ "$code" == "404" ]]; then
|
||||
note "ota $OTA HTTP 404 — not wired on apps vhost yet"
|
||||
else
|
||||
bad "ota $OTA HTTP $code"
|
||||
fi
|
||||
|
||||
# Device APIs (no session) — 403 on public edge is OK if upload/heartbeat work
|
||||
code="$(http_code "$CRASHES/api/diag.php")"
|
||||
if [[ "$code" == "200" ]]; then
|
||||
ok "diag API HTTP $code"
|
||||
elif [[ "$code" == "403" ]]; then
|
||||
note "diag API HTTP 403 (edge block; use upload/heartbeat for device path)"
|
||||
else
|
||||
bad "diag API HTTP $code"
|
||||
fi
|
||||
code="$(http_code "$CRASHES/api/heartbeat.php")"
|
||||
[[ "$code" =~ ^(200|400|405)$ ]] && ok "heartbeat API reachable HTTP $code" || bad "heartbeat API HTTP $code"
|
||||
|
||||
# JS assets
|
||||
for pair in \
|
||||
"crashes-app:${CRASHES}/assets/js/app.js" \
|
||||
"graphs-js:${GRAPH}/assets/js/graphs.js" \
|
||||
"tickets-js:${CRASHES}/assets/js/tickets.js" \
|
||||
"i18n-js:${CRASHES}/assets/js/i18n.js"; do
|
||||
name="${pair%%:*}"
|
||||
url="${pair#*:}"
|
||||
st="$(js_syntax "$url" || true)"
|
||||
[[ "$st" == "ok" ]] && ok "js $name syntax" || bad "js $name ($st) $url"
|
||||
done
|
||||
|
||||
# Authenticated API smoke (optional)
|
||||
if [[ "${RUN_API_SMOKE:-1}" == "1" ]] && command -v bash >/dev/null 2>&1; then
|
||||
if CRASHES_BASE="$CRASHES" bash "$ROOT/scripts/test_remote_access_api.sh" >/dev/null 2>&1; then
|
||||
ok "remote_access API smoke"
|
||||
else
|
||||
bad "remote_access API smoke"
|
||||
fi
|
||||
if CRASHES_BASE="$CRASHES" bash "$ROOT/scripts/test_rbac_api.sh" >/dev/null 2>&1; then
|
||||
ok "rbac API smoke"
|
||||
else
|
||||
bad "rbac API smoke"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo
|
||||
if [[ "$fail" -eq 0 ]]; then
|
||||
echo "All required service checks passed."
|
||||
else
|
||||
echo "Some checks failed — file tickets via ingest or Issues dashboard."
|
||||
fi
|
||||
exit "$fail"
|
||||
@@ -3,20 +3,28 @@ declare(strict_types=1);
|
||||
|
||||
/** Migration 008 — email registration + 2FA tables (SQLite dev + MariaDB ALTER). */
|
||||
final class AuthEmailSchema {
|
||||
private static bool $ensured = false;
|
||||
|
||||
private function __construct() {
|
||||
}
|
||||
|
||||
public static function ensure(PDO $pdo): void {
|
||||
if (self::$ensured) {
|
||||
return;
|
||||
}
|
||||
if (!Database::tableExists($pdo, 'users')) {
|
||||
self::$ensured = true;
|
||||
return;
|
||||
}
|
||||
self::ensureUserColumns($pdo);
|
||||
self::ensureAuthTokens($pdo);
|
||||
self::ensureAuthFactors($pdo);
|
||||
self::ensureAuthAttempts($pdo);
|
||||
self::$ensured = true;
|
||||
}
|
||||
|
||||
private static function ensureUserColumns(PDO $pdo): void {
|
||||
$existing = Database::columnNames($pdo, 'users');
|
||||
$cols = [
|
||||
'email_normalized' => Database::isMysql() ? 'VARCHAR(254) NULL' : 'TEXT NULL',
|
||||
'email_verified_at' => Database::isMysql() ? 'TIMESTAMP NULL' : 'TEXT NULL',
|
||||
@@ -26,14 +34,11 @@ final class AuthEmailSchema {
|
||||
'recovery_email_normalized' => Database::isMysql() ? 'VARCHAR(254) NULL' : 'TEXT NULL',
|
||||
];
|
||||
foreach ($cols as $name => $ddl) {
|
||||
try {
|
||||
$pdo->exec('ALTER TABLE users ADD COLUMN ' . $name . ' ' . $ddl);
|
||||
} catch (PDOException $e) {
|
||||
$msg = strtolower($e->getMessage());
|
||||
if (!str_contains($msg, 'duplicate') && !str_contains($msg, 'already exists')) {
|
||||
throw $e;
|
||||
}
|
||||
if (in_array($name, $existing, true)) {
|
||||
continue;
|
||||
}
|
||||
$pdo->exec('ALTER TABLE users ADD COLUMN ' . $name . ' ' . $ddl);
|
||||
$existing[] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
<?= Rbac::can('remote_access_admin') ? ' data-can-ra-admin="1"' : '' ?>
|
||||
<?= Rbac::isRoot() ? ' data-can-rbac-root="1"' : '' ?>>
|
||||
<header class="top-menu" hidden aria-hidden="true"></header>
|
||||
<div class="shell">
|
||||
<div class="shell<?= ($view ?? '') === 'graphs' ? ' shell--graphs-full' : '' ?>">
|
||||
<nav class="nav-pane" id="nav-pane" aria-label="Console navigation">
|
||||
<button type="button" class="nav-handle" id="nav-handle" data-i18n-aria="nav.toggle" data-i18n-title="nav.toggle" aria-label="Toggle navigation" title="Navigation">
|
||||
<span class="nav-icon nav-icon--menu" aria-hidden="true"></span>
|
||||
|
||||
21
examples/sfu/README.md
Normal file
21
examples/sfu/README.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# SFU relay (Janus-class) — hidden preview
|
||||
|
||||
**Not in alpha.** Implementation branch: `feature/sfu-relay`. User-visible UI remains off until owner spec is merged.
|
||||
|
||||
## Layout
|
||||
|
||||
| Path | Role |
|
||||
|------|------|
|
||||
| `examples/sfu/README.md` | This file |
|
||||
| `backend/public/api/sfu_health.php` | Health stub (`enabled: false`) |
|
||||
| `config.example.php` → `sfu` | BE feature gate |
|
||||
| `app/.../sfu/SfuRelayGate.java` | Compile-time preview gate |
|
||||
|
||||
## Next steps (when spec lands)
|
||||
|
||||
1. Signaling API + room lifecycle tied to cast session IDs / RBAC.
|
||||
2. Janus or mediasoup on dedicated port (see INFRA — **not** androidcast `:80` vhost).
|
||||
3. Android: enable `TRANSPORT_WEBRTC` behind `SfuRelayGate` + dev setting only.
|
||||
4. FE nginx: UDP/TCP ports + TLS for WebRTC (separate from hub/crashes).
|
||||
|
||||
See [20260608_BE_SERVICES_and_infra.md](../../docs/20260608_BE_SERVICES_and_infra.md) § Planned SFU.
|
||||
@@ -1,13 +1,44 @@
|
||||
#!/bin/bash
|
||||
# Raspberry Pi router (f0xx.org): WAN UDP 45340 → FE (10.7.0.10). Persist via your firewall save.
|
||||
# Raspberry Pi router (f0xx.org): WAN UDP 45340 → FE (10.7.0.10).
|
||||
# Invoked at boot or from iodine_warmup_helper; also: router_wireguard_dnat.sh [start|stop]
|
||||
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
|
||||
function start() {
|
||||
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 for udp/${WG_PORT}"
|
||||
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
|
||||
|
||||
if iptables -C FORWARD -p udp -d "${FE_IP}" --dport "$WG_PORT" -j ACCEPT 2>/dev/null; then
|
||||
echo "Router FORWARD rule already present"
|
||||
else
|
||||
iptables -A FORWARD -p udp -d "${FE_IP}" --dport "$WG_PORT" -j ACCEPT
|
||||
echo "Added router FORWARD udp -> ${FE_IP}:${WG_PORT}"
|
||||
fi
|
||||
}
|
||||
|
||||
function stop() {
|
||||
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
|
||||
iptables -t nat -D PREROUTING -i "$WAN_IF" -p udp --dport "$WG_PORT" -j DNAT --to-destination "${FE_IP}:${WG_PORT}"
|
||||
echo "Removed router PREROUTING DNAT udp/${WG_PORT}"
|
||||
else
|
||||
echo "Router DNAT rule not present for udp/${WG_PORT}"
|
||||
fi
|
||||
|
||||
if iptables -C FORWARD -p udp -d "${FE_IP}" --dport "$WG_PORT" -j ACCEPT 2>/dev/null; then
|
||||
iptables -D FORWARD -p udp -d "${FE_IP}" --dport "$WG_PORT" -j ACCEPT
|
||||
echo "Removed router FORWARD udp -> ${FE_IP}:${WG_PORT}"
|
||||
else
|
||||
echo "Router FORWARD rule not present"
|
||||
fi
|
||||
}
|
||||
|
||||
cmd=$1
|
||||
cmd=${cmd:-start}
|
||||
[ "$cmd" = "start" ] && start || stop
|
||||
|
||||
Reference in New Issue
Block a user