153 lines
4.2 KiB
PHP
153 lines
4.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Domovoy\Tests\Discovery;
|
|
|
|
use Domovoy\Models\DiscoveredHost;
|
|
use Domovoy\Models\NetworkRange;
|
|
use Domovoy\Repositories\DiscoveredHostRepository;
|
|
use Domovoy\Services\Discovery\ArpTableReader;
|
|
use Domovoy\Services\Discovery\HostFingerprintService;
|
|
use Domovoy\Services\Discovery\NetworkScanner;
|
|
use Domovoy\Services\Discovery\PingScanner;
|
|
use Domovoy\Services\Discovery\TcpPortScanner;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
final class NetworkScannerTest extends TestCase
|
|
{
|
|
public function testScanEnumeratesUsableHostsForThirtyBitCidr(): void
|
|
{
|
|
$repository = new InMemoryDiscoveredHostRepository();
|
|
$scanner = new NetworkScanner(
|
|
new AlwaysAlivePingScanner(),
|
|
new EmptyTcpPortScanner(),
|
|
new EmptyArpTableReader(),
|
|
new StableFingerprintService(),
|
|
$repository
|
|
);
|
|
|
|
$range = new NetworkRange();
|
|
$range->cidr = '192.168.1.0/30';
|
|
|
|
$hosts = $scanner->scan($range, 123);
|
|
|
|
self::assertSame(['192.168.1.1', '192.168.1.2'], array_map(
|
|
static fn (DiscoveredHost $host): string => $host->ipAddress,
|
|
$hosts
|
|
));
|
|
self::assertSame([123, 123], array_map(
|
|
static fn (DiscoveredHost $host): ?int => $host->scanJobId,
|
|
$repository->saved
|
|
));
|
|
}
|
|
|
|
public function testScanRejectsRangesLargerThanTwentyFourForMvp(): void
|
|
{
|
|
$scanner = new NetworkScanner(
|
|
new AlwaysAlivePingScanner(),
|
|
new EmptyTcpPortScanner(),
|
|
new EmptyArpTableReader(),
|
|
new StableFingerprintService(),
|
|
new InMemoryDiscoveredHostRepository()
|
|
);
|
|
|
|
$range = new NetworkRange();
|
|
$range->cidr = '192.168.0.0/23';
|
|
|
|
$this->expectException(\InvalidArgumentException::class);
|
|
$this->expectExceptionMessage('larger than /24');
|
|
|
|
$scanner->scan($range, 321);
|
|
}
|
|
|
|
public function testResumableScanStartsAtSavedIndexAndReportsProgress(): void
|
|
{
|
|
$repository = new InMemoryDiscoveredHostRepository();
|
|
$scanner = new NetworkScanner(
|
|
new AlwaysAlivePingScanner(),
|
|
new EmptyTcpPortScanner(),
|
|
new EmptyArpTableReader(),
|
|
new StableFingerprintService(),
|
|
$repository
|
|
);
|
|
|
|
$range = new NetworkRange();
|
|
$range->cidr = '192.168.1.0/30';
|
|
$progress = [];
|
|
|
|
$result = $scanner->scanResumable(
|
|
$range,
|
|
456,
|
|
1,
|
|
static fn (): bool => false,
|
|
static function (array $state) use (&$progress): void {
|
|
$progress[] = $state;
|
|
}
|
|
);
|
|
|
|
self::assertSame(['192.168.1.2'], array_map(
|
|
static fn (DiscoveredHost $host): string => $host->ipAddress,
|
|
$result['hosts']
|
|
));
|
|
self::assertTrue($result['completed']);
|
|
self::assertSame(2, $result['next_ip_index']);
|
|
self::assertSame(2, $result['total_ips']);
|
|
self::assertSame(1, $result['scanned_count']);
|
|
self::assertSame(1, $progress[0]['next_ip_index']);
|
|
self::assertSame(2, $progress[1]['next_ip_index']);
|
|
}
|
|
}
|
|
|
|
final class AlwaysAlivePingScanner extends PingScanner
|
|
{
|
|
public function ping(string $ip, int $timeoutMs = 500): bool
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
final class EmptyTcpPortScanner extends TcpPortScanner
|
|
{
|
|
public function scan(string $ip, array $ports, int $timeoutMs = 200, int $maxConcurrency = 50): array
|
|
{
|
|
return [];
|
|
}
|
|
}
|
|
|
|
final class EmptyArpTableReader extends ArpTableReader
|
|
{
|
|
public function read(): array
|
|
{
|
|
return [];
|
|
}
|
|
}
|
|
|
|
final class StableFingerprintService extends HostFingerprintService
|
|
{
|
|
public function guessVendor(array $openPorts, ?string $hostname = null): ?string
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public function calculateConfidence(int $openPortCount, bool $hasHostname): int
|
|
{
|
|
return 50;
|
|
}
|
|
}
|
|
|
|
final class InMemoryDiscoveredHostRepository extends DiscoveredHostRepository
|
|
{
|
|
/** @var DiscoveredHost[] */
|
|
public array $saved = [];
|
|
|
|
public function __construct()
|
|
{
|
|
}
|
|
|
|
public function save(DiscoveredHost $host): void
|
|
{
|
|
$this->saved[] = $host;
|
|
}
|
|
}
|