mirror of
git://f0xx.org/android_cast
synced 2026-07-29 04:38:53 +03:00
sync
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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}"
|
||||
|
||||
@@ -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();
|
||||
|
||||
25
examples/crash_reporter/backend/src/WireGuardAddressPool.php
Normal file
25
examples/crash_reporter/backend/src/WireGuardAddressPool.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/** WG client IPs + server AllowedIPs from config (matches live wg0 on BE). */
|
||||
final class WireGuardAddressPool {
|
||||
private function __construct() {
|
||||
}
|
||||
|
||||
public static function defaultEndpoint(): string {
|
||||
return (string) cfg('remote_access.wg_endpoint', 'ra.apps.f0xx.org:45340');
|
||||
}
|
||||
|
||||
public static function serverAllowedIps(): string {
|
||||
return (string) cfg('remote_access.wg_server_allowed_ips', '172.200.2.1/32');
|
||||
}
|
||||
|
||||
public static function allocateClientAddress(string $sessionId): string {
|
||||
$prefix = (string) cfg('remote_access.wg_client_ip_prefix', '172.200.2.');
|
||||
$min = max(2, (int) cfg('remote_access.wg_client_ip_min', 10));
|
||||
$max = max($min, (int) cfg('remote_access.wg_client_ip_max', 250));
|
||||
$span = $max - $min + 1;
|
||||
$host = $min + (abs(crc32($sessionId)) % $span);
|
||||
return $prefix . $host . '/32';
|
||||
}
|
||||
}
|
||||
@@ -33,15 +33,13 @@ final class WireGuardPeerProvisioner {
|
||||
$iface = self::interfaceName();
|
||||
$allowed = trim($clientAddressCidr);
|
||||
if ($allowed === '') {
|
||||
$allowed = '10.66.66.2/32';
|
||||
$allowed = WireGuardAddressPool::allocateClientAddress('default');
|
||||
}
|
||||
$cmd = 'wg set ' . escapeshellarg($iface)
|
||||
$code = self::runWg(
|
||||
'set ' . escapeshellarg($iface)
|
||||
. ' peer ' . escapeshellarg($pub)
|
||||
. ' allowed-ips ' . escapeshellarg($allowed);
|
||||
exec($cmd, $out, $code);
|
||||
if ($code !== 0) {
|
||||
error_log('WireGuardPeerProvisioner add failed: ' . implode(' ', $out));
|
||||
}
|
||||
. ' allowed-ips ' . escapeshellarg($allowed)
|
||||
);
|
||||
return $code === 0;
|
||||
}
|
||||
|
||||
@@ -54,9 +52,20 @@ final class WireGuardPeerProvisioner {
|
||||
return;
|
||||
}
|
||||
$iface = self::interfaceName();
|
||||
$cmd = 'wg set ' . escapeshellarg($iface)
|
||||
self::runWg(
|
||||
'set ' . escapeshellarg($iface)
|
||||
. ' peer ' . escapeshellarg($pub)
|
||||
. ' remove';
|
||||
exec($cmd);
|
||||
. ' remove'
|
||||
);
|
||||
}
|
||||
|
||||
private static function runWg(string $args): int {
|
||||
$prefix = rtrim((string) cfg('remote_access.wg_set_prefix', ''), " \t");
|
||||
$cmd = ($prefix !== '' ? $prefix . ' ' : '') . 'wg ' . $args;
|
||||
exec($cmd . ' 2>&1', $out, $code);
|
||||
if ($code !== 0) {
|
||||
error_log('WireGuardPeerProvisioner: ' . $cmd . ' failed: ' . implode(' ', $out));
|
||||
}
|
||||
return $code;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user