LAN WOL 대상 판정 정리

This commit is contained in:
seo committed 2026-08-29 02:29:52 +09:00
1 parent c22f84e430
commit 4fb9af695c
4 files changed
+218 -45

No files matched your search

+161 -40
View File
@@ -3346,18 +3346,154 @@ function lan_link_speed_label(string $iface = 'eth1'): string
return $mbps . ' Mbps';
}
function observed_lan_macs(array $leases): array
function lan_client_display_row(
string $mac,
array $lease,
array $aliases,
string $iface,
string $linkSpeed,
bool $isOnline,
string $presence
): array {
$leaseHostname = (string)($lease['hostname'] ?? 'N/A');
$aliasHostname = $aliases[$mac] ?? null;
$hostname = $aliasHostname ?: $leaseHostname;
$hostnameSource = $aliasHostname ? 'alias' : ($leaseHostname === 'N/A' ? 'generated' : 'lease');
return [
'band' => 'LAN',
'iface' => $iface,
'mac' => $mac,
'ip' => $lease['ip'] ?? 'N/A',
'hostname' => $hostname === 'N/A' ? '기기-' . strtoupper(substr(str_replace(':', '', $mac), -6)) : $hostname,
'hostname_source' => $hostnameSource,
'name' => $hostname === 'N/A' ? $mac : $hostname,
'signal' => '-',
'tx_bitrate' => $linkSpeed,
'rx_bitrate' => '-',
'signal_source' => 'lan',
'tx_bitrate_source' => 'lan_link',
'rx_bitrate_source' => 'lan',
'connected_time' => $isOnline ? 'N/A' : '-',
'inactive_time' => '-',
'presence' => $presence,
'wol_available' => !$isOnline,
'rx_bytes' => 0,
'tx_bytes' => 0,
'rx_packets' => 0,
'tx_packets' => 0,
'tx_failed' => 0,
];
}
function remember_lan_wol_clients(array $rows): void
{
if ($rows === []) {
return;
}
try {
$pdo = db();
$stmt = $pdo->prepare("
INSERT INTO lan_wol_clients
(mac, iface, last_ip, hostname, first_seen_at, last_seen_at)
VALUES
(:mac, :iface, :last_ip, :hostname, NOW(3), NOW(3))
ON DUPLICATE KEY UPDATE
iface = VALUES(iface),
last_ip = VALUES(last_ip),
hostname = VALUES(hostname),
last_seen_at = NOW(3)
");
foreach ($rows as $row) {
$mac = strtolower((string)($row['mac'] ?? ''));
if (!wifi_valid_mac($mac) || (string)($row['presence'] ?? '') !== 'fdb') {
continue;
}
$stmt->execute([
':mac' => $mac,
':iface' => (string)($row['iface'] ?? 'eth1'),
':last_ip' => ($row['ip'] ?? 'N/A') === 'N/A' ? null : (string)$row['ip'],
':hostname' => ($row['hostname'] ?? 'N/A') === 'N/A' ? null : (string)$row['hostname'],
]);
}
} catch (Throwable) {
}
}
function seed_lan_wol_clients_from_observed(array $leases, array $aliases = [], string $iface = 'eth1'): void
{
if ($leases === []) {
return;
}
try {
$pdo = db();
$rows = $pdo->query("
SELECT mac, last_ip, hostname, last_seen_at
FROM wifi_observed_sessions
WHERE band = 'LAN'
")->fetchAll();
if ($rows === []) {
return;
}
$upsert = $pdo->prepare("
INSERT INTO lan_wol_clients
(mac, iface, last_ip, hostname, first_seen_at, last_seen_at)
VALUES
(:mac, :iface, :last_ip, :hostname, :last_seen_at, :last_seen_at)
ON DUPLICATE KEY UPDATE
iface = VALUES(iface),
last_ip = COALESCE(VALUES(last_ip), last_ip),
hostname = COALESCE(VALUES(hostname), hostname),
last_seen_at = GREATEST(last_seen_at, VALUES(last_seen_at))
");
foreach ($rows as $row) {
$mac = strtolower((string)($row['mac'] ?? ''));
if (!wifi_valid_mac($mac) || !isset($leases[$mac])) {
continue;
}
$lease = $leases[$mac];
$leaseHostname = (string)($lease['hostname'] ?? 'N/A');
$hostname = $aliases[$mac] ?? ($leaseHostname === 'N/A' ? (string)($row['hostname'] ?? '') : $leaseHostname);
$lastSeenAt = (string)($row['last_seen_at'] ?? '');
if ($lastSeenAt === '') {
$lastSeenAt = date('Y-m-d H:i:s.v');
}
$upsert->execute([
':mac' => $mac,
':iface' => $iface,
':last_ip' => (string)($lease['ip'] ?? ($row['last_ip'] ?? '')),
':hostname' => $hostname === '' || $hostname === 'N/A' ? null : $hostname,
':last_seen_at' => $lastSeenAt,
]);
}
} catch (Throwable) {
}
}
function lan_wol_candidate_macs(array $leases, string $iface = 'eth1'): array
{
if ($leases === []) {
return [];
}
seed_lan_wol_clients_from_observed($leases, [], $iface);
try {
$stmt = db()->query("
$stmt = db()->prepare("
SELECT mac
FROM wifi_observed_sessions
WHERE band = 'LAN'
FROM lan_wol_clients
WHERE iface = :iface
ORDER BY last_seen_at DESC
");
$stmt->execute([':iface' => $iface]);
} catch (Throwable) {
return [];
}
@@ -3380,7 +3516,7 @@ function lan_client_rows(array $leases, array $aliases, array $wifiMacs = [], st
$lanFdbList = lan_fdb_macs($iface);
$lanFdbMacs = array_fill_keys($lanFdbList, true);
$wifiMacs = array_fill_keys(array_map('strtolower', $wifiMacs), true);
$lanMacs = array_values(array_unique(array_merge($lanFdbList, observed_lan_macs($leases))));
$lanMacs = array_values(array_unique($lanFdbList));
foreach ($lanMacs as $mac) {
$mac = strtolower((string)$mac);
@@ -3388,37 +3524,18 @@ function lan_client_rows(array $leases, array $aliases, array $wifiMacs = [], st
continue;
}
$lease = $leases[$mac] ?? [];
$leaseHostname = (string)($lease['hostname'] ?? 'N/A');
$aliasHostname = $aliases[$mac] ?? null;
$hostname = $aliasHostname ?: $leaseHostname;
$hostnameSource = $aliasHostname ? 'alias' : ($leaseHostname === 'N/A' ? 'generated' : 'lease');
$isFdbVisible = isset($lanFdbMacs[$mac]);
$rows[] = lan_client_display_row($mac, $leases[$mac] ?? [], $aliases, $iface, $linkSpeed, true, 'fdb');
}
$rows[] = [
'band' => 'LAN',
'iface' => $iface,
'mac' => $mac,
'ip' => $lease['ip'] ?? 'N/A',
'hostname' => $hostname === 'N/A' ? '기기-' . strtoupper(substr(str_replace(':', '', $mac), -6)) : $hostname,
'hostname_source' => $hostnameSource,
'name' => $hostname === 'N/A' ? $mac : $hostname,
'signal' => '-',
'tx_bitrate' => $linkSpeed,
'rx_bitrate' => '-',
'signal_source' => 'lan',
'tx_bitrate_source' => 'lan_link',
'rx_bitrate_source' => 'lan',
'connected_time' => $isFdbVisible ? 'N/A' : '-',
'inactive_time' => '-',
'presence' => $isFdbVisible ? 'fdb' : 'lease',
'wol_available' => !$isFdbVisible,
'rx_bytes' => 0,
'tx_bytes' => 0,
'rx_packets' => 0,
'tx_packets' => 0,
'tx_failed' => 0,
];
remember_lan_wol_clients($rows);
$wolMacs = array_values(array_unique(lan_wol_candidate_macs($leases, $iface)));
foreach ($wolMacs as $mac) {
$mac = strtolower((string)$mac);
if (!wifi_valid_mac($mac) || isset($wifiMacs[$mac]) || isset($lanFdbMacs[$mac])) {
continue;
}
$rows[] = lan_client_display_row($mac, $leases[$mac] ?? [], $aliases, $iface, $linkSpeed, false, 'wol');
}
return $rows;
@@ -3441,8 +3558,8 @@ function send_wake_on_lan(string $mac, string $broadcast = '192.168.50.255', int
throw new InvalidArgumentException('device_already_online');
}
$lanMacs = array_fill_keys(array_merge(array_keys($activeLanMacs), observed_lan_macs($leases)), true);
if (!isset($lanMacs[$mac])) {
$lanMacs = array_fill_keys(lan_wol_candidate_macs($leases), true);
if (!isset($lanMacs[$mac]) && !isset($leases[$mac])) {
throw new InvalidArgumentException('not_lan_client');
}
@@ -3485,8 +3602,8 @@ function wake_lan_status(string $mac): array
$leases = dnsmasq_leases();
$activeLanMacs = array_fill_keys(lan_fdb_macs(), true);
$observedLanMacs = array_fill_keys(observed_lan_macs($leases), true);
$known = isset($leases[$mac]) || isset($activeLanMacs[$mac]) || isset($observedLanMacs[$mac]);
$wolCandidateMacs = array_fill_keys(lan_wol_candidate_macs($leases), true);
$known = isset($activeLanMacs[$mac]) || isset($wolCandidateMacs[$mac]) || isset($leases[$mac]);
if (!$known) {
throw new InvalidArgumentException('unknown_dhcp_client');
@@ -3500,7 +3617,7 @@ function wake_lan_status(string $mac): array
'ip' => $lease['ip'] ?? null,
'hostname' => $lease['hostname'] ?? null,
'state' => $isOnline ? 'on' : 'off',
'presence' => $isOnline ? 'fdb' : (isset($observedLanMacs[$mac]) ? 'observed' : 'lease'),
'presence' => $isOnline ? 'fdb' : (isset($wolCandidateMacs[$mac]) ? 'wol' : 'lease'),
'wol_available' => !$isOnline,
];
}
@@ -3743,6 +3860,9 @@ function observed_wifi_duration_seconds(array $clients): array
if (!in_array($band, ['5G', 'LAN'], true) || !wifi_valid_mac($mac)) {
continue;
}
if ($band === 'LAN' && (string)($client['presence'] ?? '') !== 'fdb') {
continue;
}
$visibleMacsByBand[$band][] = $mac;
@@ -3833,6 +3953,7 @@ function apply_observed_wifi_connected_time(array $clients): array
$mac = strtolower((string)($client['mac'] ?? ''));
if (!in_array((string)($client['band'] ?? ''), ['5G', 'LAN'], true)
|| ((string)($client['band'] ?? '') === 'LAN' && (string)($client['presence'] ?? '') !== 'fdb')
|| !wifi_connected_time_missing($client['connected_time'] ?? null)
|| !array_key_exists($mac, $observedSeconds)
) {