feat: enhance Proxmox Firewall log view with detailed IP and port information, including modals for geolocation and protocol descriptions, improving user interaction and data accessibility
This commit is contained in:
@@ -1152,6 +1152,49 @@ class Firewall extends Component
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch IP location data from ip-api.com
|
||||
*/
|
||||
public function fetchIPLocation(string $ip): array
|
||||
{
|
||||
try {
|
||||
// Validate IP address
|
||||
if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
|
||||
return [
|
||||
'status' => 'fail',
|
||||
'message' => 'Invalid or private IP address'
|
||||
];
|
||||
}
|
||||
|
||||
// Fetch location data from ip-api.com (HTTP endpoint)
|
||||
$response = Http::timeout(5)->get("http://ip-api.com/json/{$ip}");
|
||||
|
||||
if ($response->successful()) {
|
||||
$data = $response->json();
|
||||
|
||||
// Check if the API returned success
|
||||
if (isset($data['status']) && $data['status'] === 'success') {
|
||||
return $data;
|
||||
} else {
|
||||
return [
|
||||
'status' => 'fail',
|
||||
'message' => $data['message'] ?? 'Unable to fetch location data'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'status' => 'fail',
|
||||
'message' => 'Failed to fetch location data (HTTP ' . $response->status() . ')'
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
return [
|
||||
'status' => 'fail',
|
||||
'message' => 'Error: ' . $e->getMessage()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('proxmox::firewall')->layoutData([
|
||||
|
||||
@@ -537,18 +537,350 @@
|
||||
<tbody>
|
||||
<template x-for="(log, index) in paginatedLogs" :key="log.index || index">
|
||||
<tr class="border-b border-neutral/20 hover:bg-background-secondary/50">
|
||||
<!-- Timestamp -->
|
||||
<td class="py-3 px-4 text-sm" x-text="log.timestamp_display || '-' "></td>
|
||||
|
||||
<!-- Level -->
|
||||
<td class="py-3 px-4 text-sm">
|
||||
<span class="px-2 py-1 rounded text-xs font-semibold uppercase" :class="log.level_badge_class" x-text="log.level_label || '-' "></span>
|
||||
</td>
|
||||
|
||||
<!-- Action -->
|
||||
<td class="py-3 px-4 text-sm">
|
||||
<span class="px-2 py-1 rounded text-xs font-semibold" :class="log.action_badge_class" x-text="log.action || '-' "></span>
|
||||
</td>
|
||||
<td class="py-3 px-4 text-sm" x-text="log.protocol || '-' "></td>
|
||||
<td class="py-3 px-4 text-sm font-mono" x-text="log.source || '-' "></td>
|
||||
<td class="py-3 px-4 text-sm" x-text="log.source_port || '-' "></td>
|
||||
<td class="py-3 px-4 text-sm font-mono" x-text="log.destination || '-' "></td>
|
||||
<td class="py-3 px-4 text-sm" x-text="log.destination_port || '-' "></td>
|
||||
|
||||
<!-- Protocol with info modal -->
|
||||
<td class="py-3 px-4 text-sm">
|
||||
<div class="flex items-center gap-1">
|
||||
<span x-text="log.protocol || '-' "></span>
|
||||
<template x-if="log.protocol && log.protocol !== '-'">
|
||||
<div class="relative" x-data="{ open: false }" x-cloak>
|
||||
<button type="button" @click="open = true" class="text-base/50 hover:text-primary transition-colors">
|
||||
<x-ri-information-line class="size-3" />
|
||||
</button>
|
||||
<!-- Modal Backdrop -->
|
||||
<div x-show="open"
|
||||
x-transition:enter="transition ease-out duration-200"
|
||||
x-transition:enter-start="opacity-0"
|
||||
x-transition:enter-end="opacity-100"
|
||||
x-transition:leave="transition ease-in duration-150"
|
||||
x-transition:leave-start="opacity-100"
|
||||
x-transition:leave-end="opacity-0"
|
||||
@click="open = false"
|
||||
@keydown.escape.window="open = false"
|
||||
class="fixed inset-0 z-50 bg-black/50 backdrop-blur-sm"
|
||||
style="display: none;">
|
||||
</div>
|
||||
<!-- Modal -->
|
||||
<div x-show="open"
|
||||
x-transition:enter="transition ease-out duration-200"
|
||||
x-transition:enter-start="opacity-0 scale-95"
|
||||
x-transition:enter-end="opacity-100 scale-100"
|
||||
x-transition:leave="transition ease-in duration-150"
|
||||
x-transition:leave-start="opacity-100 scale-100"
|
||||
x-transition:leave-end="opacity-0 scale-95"
|
||||
@click.away="open = false"
|
||||
@keydown.escape.window="open = false"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
<div class="relative w-full max-w-2xl bg-background-secondary rounded-xl border border-neutral/20 shadow-2xl p-6 max-h-[80vh] overflow-y-auto">
|
||||
<button @click="open = false" class="absolute top-4 right-4 text-base/50 hover:text-base transition-colors">
|
||||
<x-ri-close-line class="size-5" />
|
||||
</button>
|
||||
<div class="pr-8">
|
||||
<div class="flex items-center gap-2 mb-4">
|
||||
<x-ri-information-line class="size-6 text-primary" />
|
||||
<h3 class="text-lg font-semibold" x-text="`${log.protocol} Protocol`"></h3>
|
||||
</div>
|
||||
<div class="text-sm text-base/90" x-html="window.getProtocolDescription(log.protocol)"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<!-- Source IP with location lookup -->
|
||||
<td class="py-3 px-4 text-sm">
|
||||
<div class="flex items-center gap-1">
|
||||
<span class="font-mono text-xs" x-text="log.source || '-' "></span>
|
||||
<template x-if="log.source && log.source !== '-' && window.isPublicIP(log.source)">
|
||||
<div class="relative" x-data="{ open: false, loading: false, ipData: null }" x-cloak>
|
||||
<button type="button" @click="
|
||||
if (!ipData && !loading) {
|
||||
loading = true;
|
||||
open = true;
|
||||
window.fetchIPLocation(log.source).then(data => {
|
||||
ipData = data;
|
||||
loading = false;
|
||||
}).catch(err => {
|
||||
ipData = { status: 'error', message: 'Failed to load location data' };
|
||||
loading = false;
|
||||
});
|
||||
} else {
|
||||
open = true;
|
||||
}
|
||||
" class="text-base/50 hover:text-primary transition-colors" title="View IP Location">
|
||||
<x-ri-map-pin-line class="size-3" />
|
||||
</button>
|
||||
<!-- Modal Backdrop -->
|
||||
<div x-show="open"
|
||||
x-transition:enter="transition ease-out duration-200"
|
||||
x-transition:enter-start="opacity-0"
|
||||
x-transition:enter-end="opacity-100"
|
||||
x-transition:leave="transition ease-in duration-150"
|
||||
x-transition:leave-start="opacity-100"
|
||||
x-transition:leave-end="opacity-0"
|
||||
@click="open = false"
|
||||
@keydown.escape.window="open = false"
|
||||
class="fixed inset-0 z-50 bg-black/50 backdrop-blur-sm"
|
||||
style="display: none;">
|
||||
</div>
|
||||
<!-- Modal -->
|
||||
<div x-show="open"
|
||||
x-transition:enter="transition ease-out duration-200"
|
||||
x-transition:enter-start="opacity-0 scale-95"
|
||||
x-transition:enter-end="opacity-100 scale-100"
|
||||
x-transition:leave="transition ease-in duration-150"
|
||||
x-transition:leave-start="opacity-100 scale-100"
|
||||
x-transition:leave-end="opacity-0 scale-95"
|
||||
@click.away="open = false"
|
||||
@keydown.escape.window="open = false"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
<div class="relative w-full max-w-md bg-background-secondary rounded-xl border border-neutral/20 shadow-2xl p-6">
|
||||
<button @click="open = false" class="absolute top-4 right-4 text-base/50 hover:text-base transition-colors">
|
||||
<x-ri-close-line class="size-5" />
|
||||
</button>
|
||||
<div class="pr-8">
|
||||
<div class="flex items-center gap-2 mb-4">
|
||||
<x-ri-map-pin-line class="size-6 text-primary" />
|
||||
<h3 class="text-lg font-semibold">IP Location</h3>
|
||||
</div>
|
||||
<template x-if="loading">
|
||||
<div class="flex items-center justify-center py-8">
|
||||
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-primary"></div>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="!loading && ipData">
|
||||
<div>
|
||||
<template x-if="ipData.status === 'success'">
|
||||
<div class="space-y-3 text-sm">
|
||||
<div><span class="font-semibold">IP:</span> <span class="font-mono" x-text="log.source"></span></div>
|
||||
<div><span class="font-semibold">Country:</span> <span x-text="ipData.country"></span></div>
|
||||
<div><span class="font-semibold">Region:</span> <span x-text="ipData.regionName"></span></div>
|
||||
<div><span class="font-semibold">City:</span> <span x-text="ipData.city"></span></div>
|
||||
<div><span class="font-semibold">ISP:</span> <span x-text="ipData.isp"></span></div>
|
||||
<div><span class="font-semibold">Organization:</span> <span x-text="ipData.org"></span></div>
|
||||
<div><span class="font-semibold">Timezone:</span> <span x-text="ipData.timezone"></span></div>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="ipData.status !== 'success'">
|
||||
<p class="text-sm text-warning" x-text="ipData.message || 'Failed to load location data'"></p>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<!-- Source Port with description -->
|
||||
<td class="py-3 px-4 text-sm">
|
||||
<div class="flex items-center gap-1">
|
||||
<span x-text="log.source_port || '-' "></span>
|
||||
<template x-if="log.source_port && log.source_port !== '-'">
|
||||
<div class="relative" x-data="{ open: false }" x-cloak>
|
||||
<button type="button" @click="open = true" class="text-base/50 hover:text-primary transition-colors">
|
||||
<x-ri-information-line class="size-3" />
|
||||
</button>
|
||||
<!-- Modal Backdrop -->
|
||||
<div x-show="open"
|
||||
x-transition:enter="transition ease-out duration-200"
|
||||
x-transition:enter-start="opacity-0"
|
||||
x-transition:enter-end="opacity-100"
|
||||
x-transition:leave="transition ease-in duration-150"
|
||||
x-transition:leave-start="opacity-100"
|
||||
x-transition:leave-end="opacity-0"
|
||||
@click="open = false"
|
||||
@keydown.escape.window="open = false"
|
||||
class="fixed inset-0 z-50 bg-black/50 backdrop-blur-sm"
|
||||
style="display: none;">
|
||||
</div>
|
||||
<!-- Modal -->
|
||||
<div x-show="open"
|
||||
x-transition:enter="transition ease-out duration-200"
|
||||
x-transition:enter-start="opacity-0 scale-95"
|
||||
x-transition:enter-end="opacity-100 scale-100"
|
||||
x-transition:leave="transition ease-in duration-150"
|
||||
x-transition:leave-start="opacity-100 scale-100"
|
||||
x-transition:leave-end="opacity-0 scale-95"
|
||||
@click.away="open = false"
|
||||
@keydown.escape.window="open = false"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
<div class="relative w-full max-w-md bg-background-secondary rounded-xl border border-neutral/20 shadow-2xl p-6">
|
||||
<button @click="open = false" class="absolute top-4 right-4 text-base/50 hover:text-base transition-colors">
|
||||
<x-ri-close-line class="size-5" />
|
||||
</button>
|
||||
<div class="pr-8">
|
||||
<div class="flex items-center gap-2 mb-4">
|
||||
<x-ri-information-line class="size-6 text-primary" />
|
||||
<h3 class="text-lg font-semibold">Port <span x-text="log.source_port"></span></h3>
|
||||
</div>
|
||||
<p class="text-sm text-base/90" x-text="window.getPortDescription(parseInt(log.source_port) || 0)"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<!-- Destination IP with location lookup -->
|
||||
<td class="py-3 px-4 text-sm">
|
||||
<div class="flex items-center gap-1">
|
||||
<span class="font-mono text-xs" x-text="log.destination || '-' "></span>
|
||||
<template x-if="log.destination && log.destination !== '-' && window.isPublicIP(log.destination)">
|
||||
<div class="relative" x-data="{ open: false, loading: false, ipData: null }" x-cloak>
|
||||
<button type="button" @click="
|
||||
if (!ipData && !loading) {
|
||||
loading = true;
|
||||
open = true;
|
||||
window.fetchIPLocation(log.destination).then(data => {
|
||||
ipData = data;
|
||||
loading = false;
|
||||
}).catch(err => {
|
||||
ipData = { status: 'error', message: 'Failed to load location data' };
|
||||
loading = false;
|
||||
});
|
||||
} else {
|
||||
open = true;
|
||||
}
|
||||
" class="text-base/50 hover:text-primary transition-colors" title="View IP Location">
|
||||
<x-ri-map-pin-line class="size-3" />
|
||||
</button>
|
||||
<!-- Modal Backdrop -->
|
||||
<div x-show="open"
|
||||
x-transition:enter="transition ease-out duration-200"
|
||||
x-transition:enter-start="opacity-0"
|
||||
x-transition:enter-end="opacity-100"
|
||||
x-transition:leave="transition ease-in duration-150"
|
||||
x-transition:leave-start="opacity-100"
|
||||
x-transition:leave-end="opacity-0"
|
||||
@click="open = false"
|
||||
@keydown.escape.window="open = false"
|
||||
class="fixed inset-0 z-50 bg-black/50 backdrop-blur-sm"
|
||||
style="display: none;">
|
||||
</div>
|
||||
<!-- Modal -->
|
||||
<div x-show="open"
|
||||
x-transition:enter="transition ease-out duration-200"
|
||||
x-transition:enter-start="opacity-0 scale-95"
|
||||
x-transition:enter-end="opacity-100 scale-100"
|
||||
x-transition:leave="transition ease-in duration-150"
|
||||
x-transition:leave-start="opacity-100 scale-100"
|
||||
x-transition:leave-end="opacity-0 scale-95"
|
||||
@click.away="open = false"
|
||||
@keydown.escape.window="open = false"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
<div class="relative w-full max-w-md bg-background-secondary rounded-xl border border-neutral/20 shadow-2xl p-6">
|
||||
<button @click="open = false" class="absolute top-4 right-4 text-base/50 hover:text-base transition-colors">
|
||||
<x-ri-close-line class="size-5" />
|
||||
</button>
|
||||
<div class="pr-8">
|
||||
<div class="flex items-center gap-2 mb-4">
|
||||
<x-ri-map-pin-line class="size-6 text-primary" />
|
||||
<h3 class="text-lg font-semibold">IP Location</h3>
|
||||
</div>
|
||||
<template x-if="loading">
|
||||
<div class="flex items-center justify-center py-8">
|
||||
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-primary"></div>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="!loading && ipData">
|
||||
<div>
|
||||
<template x-if="ipData.status === 'success'">
|
||||
<div class="space-y-3 text-sm">
|
||||
<div><span class="font-semibold">IP:</span> <span class="font-mono" x-text="log.destination"></span></div>
|
||||
<div><span class="font-semibold">Country:</span> <span x-text="ipData.country"></span></div>
|
||||
<div><span class="font-semibold">Region:</span> <span x-text="ipData.regionName"></span></div>
|
||||
<div><span class="font-semibold">City:</span> <span x-text="ipData.city"></span></div>
|
||||
<div><span class="font-semibold">ISP:</span> <span x-text="ipData.isp"></span></div>
|
||||
<div><span class="font-semibold">Organization:</span> <span x-text="ipData.org"></span></div>
|
||||
<div><span class="font-semibold">Timezone:</span> <span x-text="ipData.timezone"></span></div>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="ipData.status !== 'success'">
|
||||
<p class="text-sm text-warning" x-text="ipData.message || 'Failed to load location data'"></p>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<!-- Destination Port with description -->
|
||||
<td class="py-3 px-4 text-sm">
|
||||
<div class="flex items-center gap-1">
|
||||
<span x-text="log.destination_port || '-' "></span>
|
||||
<template x-if="log.destination_port && log.destination_port !== '-'">
|
||||
<div class="relative" x-data="{ open: false }" x-cloak>
|
||||
<button type="button" @click="open = true" class="text-base/50 hover:text-primary transition-colors">
|
||||
<x-ri-information-line class="size-3" />
|
||||
</button>
|
||||
<!-- Modal Backdrop -->
|
||||
<div x-show="open"
|
||||
x-transition:enter="transition ease-out duration-200"
|
||||
x-transition:enter-start="opacity-0"
|
||||
x-transition:enter-end="opacity-100"
|
||||
x-transition:leave="transition ease-in duration-150"
|
||||
x-transition:leave-start="opacity-100"
|
||||
x-transition:leave-end="opacity-0"
|
||||
@click="open = false"
|
||||
@keydown.escape.window="open = false"
|
||||
class="fixed inset-0 z-50 bg-black/50 backdrop-blur-sm"
|
||||
style="display: none;">
|
||||
</div>
|
||||
<!-- Modal -->
|
||||
<div x-show="open"
|
||||
x-transition:enter="transition ease-out duration-200"
|
||||
x-transition:enter-start="opacity-0 scale-95"
|
||||
x-transition:enter-end="opacity-100 scale-100"
|
||||
x-transition:leave="transition ease-in duration-150"
|
||||
x-transition:leave-start="opacity-100 scale-100"
|
||||
x-transition:leave-end="opacity-0 scale-95"
|
||||
@click.away="open = false"
|
||||
@keydown.escape.window="open = false"
|
||||
class="fixed inset-0 z-50 flex items-center justify-center p-4"
|
||||
style="display: none;">
|
||||
<div class="relative w-full max-w-md bg-background-secondary rounded-xl border border-neutral/20 shadow-2xl p-6">
|
||||
<button @click="open = false" class="absolute top-4 right-4 text-base/50 hover:text-base transition-colors">
|
||||
<x-ri-close-line class="size-5" />
|
||||
</button>
|
||||
<div class="pr-8">
|
||||
<div class="flex items-center gap-2 mb-4">
|
||||
<x-ri-information-line class="size-6 text-primary" />
|
||||
<h3 class="text-lg font-semibold">Port <span x-text="log.destination_port"></span></h3>
|
||||
</div>
|
||||
<p class="text-sm text-base/90" x-text="window.getPortDescription(parseInt(log.destination_port) || 0)"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
@@ -854,4 +1186,198 @@
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@script
|
||||
<script>
|
||||
// Check if an IP address is public (not private/localhost)
|
||||
window.isPublicIP = function(ip) {
|
||||
if (!ip || ip === '—' || ip === '-' || typeof ip !== 'string') return false;
|
||||
|
||||
ip = ip.trim();
|
||||
|
||||
// Check for localhost
|
||||
if (ip === 'localhost' || ip === '127.0.0.1' || ip === '::1') return false;
|
||||
|
||||
// Check for IPv4 private ranges
|
||||
const ipv4PrivateRanges = [
|
||||
/^10\./, // 10.0.0.0/8
|
||||
/^172\.(1[6-9]|2[0-9]|3[0-1])\./, // 172.16.0.0/12
|
||||
/^192\.168\./, // 192.168.0.0/16
|
||||
/^169\.254\./, // 169.254.0.0/16 (link-local)
|
||||
/^127\./, // 127.0.0.0/8
|
||||
/^0\./ // 0.0.0.0/8
|
||||
];
|
||||
|
||||
// Check if it's IPv4
|
||||
const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
|
||||
if (ipv4Regex.test(ip)) {
|
||||
// Check against private ranges
|
||||
if (ipv4PrivateRanges.some(range => range.test(ip))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if it's IPv6
|
||||
if (ip.includes(':')) {
|
||||
// Check for IPv6 private ranges
|
||||
// Link-local (fe80::/10)
|
||||
if (/^fe[89ab][0-9a-fA-F]:/i.test(ip)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Unique Local Address - ULA (fc00::/7)
|
||||
if (/^f[cd][0-9a-fA-F]/i.test(ip)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// IPv4-mapped IPv6 (::ffff:x.x.x.x)
|
||||
if (ip.startsWith('::ffff:')) {
|
||||
const ipv4Part = ip.substring(7);
|
||||
return window.isPublicIP(ipv4Part);
|
||||
}
|
||||
|
||||
// If it's a valid-looking IPv6 and not in private ranges, consider it public
|
||||
const ipv6Regex = /^([0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}$/;
|
||||
return ipv6Regex.test(ip);
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
// Fetch IP geolocation data
|
||||
window.fetchIPLocation = async function(ip) {
|
||||
if (!window.isPublicIP(ip)) {
|
||||
return { status: 'fail', message: 'Not a public IP address' };
|
||||
}
|
||||
|
||||
ip = ip.trim();
|
||||
|
||||
try {
|
||||
// Use Livewire to call server-side method
|
||||
const data = await @this.call('fetchIPLocation', ip);
|
||||
return data || { status: 'fail', message: 'No data returned' };
|
||||
} catch (error) {
|
||||
console.error('Error fetching IP location:', error);
|
||||
return { status: 'fail', message: 'Failed to fetch location data: ' + (error.message || 'Unknown error') };
|
||||
}
|
||||
};
|
||||
|
||||
// Helper function to format descriptions with sections
|
||||
const formatDescription = (overview, meaning, scenarios, notes = null) => {
|
||||
let html = '<div class="space-y-4">';
|
||||
if (overview) {
|
||||
html += `<div><h4 class="font-semibold text-base mb-2">Overview</h4><p>${overview}</p></div>`;
|
||||
}
|
||||
if (meaning) {
|
||||
html += `<div><h4 class="font-semibold text-base mb-2">What This Means</h4><p>${meaning}</p></div>`;
|
||||
}
|
||||
if (scenarios) {
|
||||
html += `<div><h4 class="font-semibold text-base mb-2">Common Scenarios</h4>${scenarios}</div>`;
|
||||
}
|
||||
if (notes) {
|
||||
html += `<div><h4 class="font-semibold text-base mb-2">Additional Notes</h4><p>${notes}</p></div>`;
|
||||
}
|
||||
html += '</div>';
|
||||
return html;
|
||||
};
|
||||
|
||||
// Protocol descriptions mapping
|
||||
window.getProtocolDescription = function(protocol) {
|
||||
if (!protocol || typeof protocol !== 'string') {
|
||||
return formatDescription('Unknown protocol', '', '');
|
||||
}
|
||||
|
||||
const protocolUpper = protocol.toUpperCase();
|
||||
const protocolDescriptions = {
|
||||
'TCP': formatDescription(
|
||||
'TCP (Transmission Control Protocol) is a connection-oriented protocol that provides reliable, ordered, and error-checked delivery of data between applications.',
|
||||
'TCP establishes a connection before data transfer and ensures data integrity through acknowledgments and retransmissions. It guarantees that data is delivered in order and without errors.',
|
||||
'<p>Common uses include:</p><ul class="list-disc list-inside space-y-1 ml-2 mt-2"><li>Web browsing (HTTP/HTTPS)</li><li>Email (SMTP, IMAP, POP3)</li><li>File transfers (FTP)</li><li>Remote access (SSH, RDP)</li><li>Database connections</li><li>API communications</li></ul>',
|
||||
'TCP is the most commonly used transport protocol on the Internet and provides reliable communication at the cost of slightly higher overhead compared to UDP.'
|
||||
),
|
||||
'UDP': formatDescription(
|
||||
'UDP (User Datagram Protocol) is a connectionless protocol that provides fast, low-overhead data transmission without guarantees of delivery, ordering, or duplicate protection.',
|
||||
'UDP does not establish connections before sending data and does not provide reliability features like acknowledgments or retransmissions. It prioritizes speed over reliability.',
|
||||
'<p>Common uses include:</p><ul class="list-disc list-inside space-y-1 ml-2 mt-2"><li>DNS queries</li><li>Video streaming</li><li>Online gaming</li><li>VoIP (Voice over IP)</li><li>Real-time applications</li><li>DHCP (Dynamic Host Configuration Protocol)</li></ul>',
|
||||
'UDP is ideal for applications where speed is more important than reliability, or where occasional packet loss is acceptable.'
|
||||
),
|
||||
'ICMP': formatDescription(
|
||||
'ICMP (Internet Control Message Protocol) is a network layer protocol used for diagnostic and control purposes.',
|
||||
'ICMP is used by network devices to send error messages and operational information. It is essential for network troubleshooting and does not carry application data.',
|
||||
'<p>Common uses include:</p><ul class="list-disc list-inside space-y-1 ml-2 mt-2"><li>Ping (echo request/reply) for connectivity testing</li><li>Traceroute for path discovery</li><li>Error reporting (destination unreachable, time exceeded)</li><li>Network diagnostics</li></ul>',
|
||||
'ICMP is a stateless protocol and does not use connection states like TCP or UDP. It operates at the network layer alongside IP.'
|
||||
),
|
||||
'ICMPV6': formatDescription(
|
||||
'ICMPv6 (Internet Control Message Protocol version 6) is the IPv6 equivalent of ICMP, used for error reporting and diagnostic functions in IPv6 networks.',
|
||||
'ICMPv6 includes additional features beyond what ICMP provides for IPv4, including integrated support for address configuration and network discovery.',
|
||||
'<p>Key features include:</p><ul class="list-disc list-inside space-y-1 ml-2 mt-2"><li>Neighbor Discovery Protocol (NDP) for IPv6</li><li>Path MTU Discovery for IPv6</li><li>Router discovery and configuration</li><li>Error reporting and diagnostics</li></ul>',
|
||||
'ICMPv6 is essential for IPv6 network operation and provides functions that in IPv4 are handled by multiple protocols (ARP, ICMP, etc.).'
|
||||
),
|
||||
};
|
||||
|
||||
return protocolDescriptions[protocolUpper] || formatDescription(
|
||||
`The protocol "${protocol}" is a network protocol identifier that defines the rules and format for data communication between network devices.`,
|
||||
'Network protocols specify how data is formatted, transmitted, and received over a network.',
|
||||
''
|
||||
);
|
||||
};
|
||||
|
||||
// Port descriptions mapping
|
||||
window.getPortDescription = function(port) {
|
||||
const portDescriptions = {
|
||||
20: 'FTP Data Transfer - File Transfer Protocol data connection',
|
||||
21: 'FTP Control - File Transfer Protocol control connection',
|
||||
22: 'SSH - Secure Shell, used for secure remote login and command execution',
|
||||
23: 'Telnet - Unencrypted remote terminal access (insecure)',
|
||||
25: 'SMTP - Simple Mail Transfer Protocol for sending email',
|
||||
53: 'DNS - Domain Name System for resolving domain names to IP addresses',
|
||||
67: 'DHCP Server - Dynamic Host Configuration Protocol server',
|
||||
68: 'DHCP Client - Dynamic Host Configuration Protocol client',
|
||||
69: 'TFTP - Trivial File Transfer Protocol',
|
||||
80: 'HTTP - Hypertext Transfer Protocol for web traffic',
|
||||
88: 'Kerberos - Network authentication protocol',
|
||||
110: 'POP3 - Post Office Protocol version 3 for receiving email',
|
||||
119: 'NNTP - Network News Transfer Protocol',
|
||||
123: 'NTP - Network Time Protocol for time synchronization',
|
||||
135: 'MSRPC - Microsoft Remote Procedure Call',
|
||||
139: 'NetBIOS - Network Basic Input/Output System',
|
||||
143: 'IMAP - Internet Message Access Protocol for email',
|
||||
161: 'SNMP - Simple Network Management Protocol',
|
||||
162: 'SNMP Trap - Simple Network Management Protocol trap',
|
||||
389: 'LDAP - Lightweight Directory Access Protocol',
|
||||
443: 'HTTPS - Hypertext Transfer Protocol Secure (encrypted web traffic)',
|
||||
445: 'SMB - Server Message Block for file sharing (Windows)',
|
||||
465: 'SMTPS - SMTP over SSL/TLS',
|
||||
514: 'Syslog - System logging protocol',
|
||||
515: 'LPD/LPR - Line Printer Daemon/Line Printer Remote',
|
||||
587: 'SMTP Submission - Mail submission port',
|
||||
636: 'LDAPS - LDAP over SSL/TLS',
|
||||
993: 'IMAPS - IMAP over SSL/TLS',
|
||||
995: 'POP3S - POP3 over SSL/TLS',
|
||||
1433: 'MSSQL - Microsoft SQL Server database',
|
||||
1521: 'Oracle Database - Oracle database listener',
|
||||
3306: 'MySQL - MySQL database server',
|
||||
3389: 'RDP - Remote Desktop Protocol (Windows)',
|
||||
5432: 'PostgreSQL - PostgreSQL database server',
|
||||
5900: 'VNC - Virtual Network Computing remote desktop',
|
||||
6379: 'Redis - Redis in-memory data store',
|
||||
8080: 'HTTP Alternate - Alternative HTTP port, often used for web proxies',
|
||||
8443: 'HTTPS Alternate - Alternative HTTPS port',
|
||||
27017: 'MongoDB - MongoDB database server',
|
||||
27018: 'MongoDB Shard - MongoDB sharding port',
|
||||
27019: 'MongoDB Config - MongoDB configuration server',
|
||||
};
|
||||
|
||||
// Check for common port ranges
|
||||
if (port >= 1024 && port <= 49151) {
|
||||
return 'Registered/User Port - Port in the registered range, commonly used by applications';
|
||||
} else if (port >= 49152 && port <= 65535) {
|
||||
return 'Dynamic/Private Port - Ephemeral port range used for temporary connections';
|
||||
}
|
||||
|
||||
return portDescriptions[port] || 'Unknown Port - No standard service associated with this port number';
|
||||
};
|
||||
</script>
|
||||
@endscript
|
||||
|
||||
</x-proxmox::layout>
|
||||
|
||||
Reference in New Issue
Block a user