fix(engine): parse WireGuard CIDR for address allocation (any prefix length)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>feat/portal-design
parent
b65fe69088
commit
8a392bfd06
|
|
@ -4,7 +4,6 @@ namespace App\Services\Wireguard;
|
|||
|
||||
use App\Models\Host;
|
||||
use Illuminate\Support\Facades\Process;
|
||||
use Illuminate\Support\Str;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
|
|
@ -17,12 +16,19 @@ class LocalWireguardHub implements WireguardHub
|
|||
{
|
||||
public function allocateIp(): string
|
||||
{
|
||||
$used = Host::query()->whereNotNull('wg_ip')->pluck('wg_ip')->all();
|
||||
$prefix = Str::beforeLast(config('provisioning.wireguard.subnet', '10.66.0.0/24'), '.');
|
||||
$used = array_flip(Host::query()->whereNotNull('wg_ip')->pluck('wg_ip')->all());
|
||||
$hubIp = (string) config('provisioning.wireguard.hub_ip');
|
||||
|
||||
for ($octet = 2; $octet <= 254; $octet++) {
|
||||
$ip = "{$prefix}.{$octet}";
|
||||
if (! in_array($ip, $used, true)) {
|
||||
[$network, $bits] = explode('/', config('provisioning.wireguard.subnet', '10.66.0.0/24'));
|
||||
$bits = (int) $bits;
|
||||
$hostBits = 32 - $bits;
|
||||
$size = 2 ** $hostBits;
|
||||
$base = ip2long($network) & (0xFFFFFFFF << $hostBits) & 0xFFFFFFFF;
|
||||
|
||||
// Skip the network address (offset 0) and broadcast (offset size-1).
|
||||
for ($offset = 1; $offset < $size - 1; $offset++) {
|
||||
$ip = long2ip($base + $offset);
|
||||
if ($ip !== $hubIp && ! isset($used[$ip])) {
|
||||
return $ip;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use App\Services\Proxmox\FakeProxmoxClient;
|
|||
use App\Services\Ssh\CommandResult;
|
||||
use App\Services\Ssh\FakeRemoteShell;
|
||||
use App\Services\Wireguard\FakeWireguardHub;
|
||||
use App\Services\Wireguard\LocalWireguardHub;
|
||||
|
||||
it('scripts remote command output and records calls (FakeRemoteShell)', function () {
|
||||
$shell = new FakeRemoteShell;
|
||||
|
|
@ -34,6 +35,23 @@ it('allocates ips and tracks peers (FakeWireguardHub)', function () {
|
|||
expect($hub->peers())->toBe([]);
|
||||
});
|
||||
|
||||
it('allocates addresses within a /24 subnet, skipping hub and used (LocalWireguardHub)', function () {
|
||||
config()->set('provisioning.wireguard.subnet', '10.66.0.0/24');
|
||||
config()->set('provisioning.wireguard.hub_ip', '10.66.0.1');
|
||||
Host::factory()->create(['wg_ip' => '10.66.0.2']);
|
||||
|
||||
// .0 network, .1 hub, .2 used → first free is .3
|
||||
expect((new LocalWireguardHub)->allocateIp())->toBe('10.66.0.3');
|
||||
});
|
||||
|
||||
it('respects a non-/24 subnet (LocalWireguardHub)', function () {
|
||||
config()->set('provisioning.wireguard.subnet', '10.66.5.128/25');
|
||||
config()->set('provisioning.wireguard.hub_ip', '10.66.5.129');
|
||||
|
||||
// network .128, hub .129 → first free is .130
|
||||
expect((new LocalWireguardHub)->allocateIp())->toBe('10.66.5.130');
|
||||
});
|
||||
|
||||
it('reports node capacity for a host (FakeProxmoxClient)', function () {
|
||||
$host = Host::factory()->create(['wg_ip' => '10.66.0.5']);
|
||||
$client = (new FakeProxmoxClient)->forHost($host);
|
||||
|
|
|
|||
Loading…
Reference in New Issue