From cede10240c93a70b390cf223b01856784d435dbd Mon Sep 17 00:00:00 2001 From: Andrea Leardini Date: Wed, 20 Nov 2024 15:50:17 +0100 Subject: [PATCH] fix(monitoring): show wan public ip address (#438) --- .../monitoring/ConnectivityMonitor.vue | 84 +++++++++++++++---- .../connectivity/WanConnectionsCard.vue | 8 +- src/i18n/en/translation.json | 3 +- src/lib/standalone/network.ts | 5 ++ 4 files changed, 78 insertions(+), 22 deletions(-) diff --git a/src/components/standalone/monitoring/ConnectivityMonitor.vue b/src/components/standalone/monitoring/ConnectivityMonitor.vue index 99a46048..5586fb45 100644 --- a/src/components/standalone/monitoring/ConnectivityMonitor.vue +++ b/src/components/standalone/monitoring/ConnectivityMonitor.vue @@ -13,14 +13,21 @@ import { NeInlineNotification, sortByProperty } from '@nethesis/vue-components' -import { computed, onMounted, ref } from 'vue' +import { computed, onMounted, ref, watchEffect } from 'vue' import { useI18n } from 'vue-i18n' import WanEventsCard from './connectivity/WanEventsCard.vue' import { isEmpty } from 'lodash-es' import type { Policy } from '@/composables/useMwan' import WanConnectionsCard from './connectivity/WanConnectionsCard.vue' import { useNetworkDevices } from '@/composables/useNetworkDevices' -import { getIpv4Addresses, getIpv6Addresses, getName, isDeviceUp } from '@/lib/standalone/network' +import { + getIpv4Addresses, + getIpv6Addresses, + getName, + isDeviceUp, + isIpv6Enabled, + type DeviceOrIface +} from '@/lib/standalone/network' import { useUciNetworkConfig } from '@/composables/useUciNetworkConfig' import InterfaceTrafficCard from './connectivity/InterfaceTrafficCard.vue' import { useLatencyAndQualityReport } from '@/composables/useLatencyAndQualityReport' @@ -32,8 +39,7 @@ export type Wan = { iface: string device: string status?: string - ip4Addresses?: string[] - ip6Addresses?: string[] + ipAddresses?: string[] } export type WanEvent = { @@ -56,6 +62,7 @@ const router = useRouter() const wans = ref([]) const mwanEvents = ref>({}) const mwanPolicies = ref([]) +const wanConnections = ref([]) const { latencyAndQualityCharts, @@ -76,7 +83,9 @@ let error = ref({ getMwanReport: '', getMwanReportDetails: '', getMwanPolicies: '', - getMwanPoliciesDetails: '' + getMwanPoliciesDetails: '', + getPublicIpAddresses: '', + getPublicIpAddressesDetails: '' }) const loadingData = computed(() => { @@ -89,7 +98,7 @@ const loadingData = computed(() => { ) }) -const wanConnections = computed(() => { +watchEffect(async () => { const wanData: Wan[] = [] for (const wan of wans.value) { @@ -112,14 +121,17 @@ const wanConnections = computed(() => { if (policyMember.interface == wan.iface) { const devFound = allDevices.value.find((dev) => getName(dev) === wan.device) - wanData.push({ - ...wan, - status: policyMember.status, - ip4Addresses: devFound ? getIpv4Addresses(devFound, networkConfig.value) : [], - ip6Addresses: devFound ? getIpv6Addresses(devFound, networkConfig.value) : [] - }) - statusFound = true - break + if (devFound) { + const publicIpAddresses = await retrievePublicIpAddresses(devFound) + + wanData.push({ + ...wan, + status: policyMember.status, + ipAddresses: publicIpAddresses + }) + statusFound = true + break + } } } } @@ -130,16 +142,17 @@ const wanConnections = computed(() => { const devFound = allDevices.value.find((dev) => getName(dev) === wan.device) if (devFound) { + const publicIpAddresses = await retrievePublicIpAddresses(devFound) + wanData.push({ ...wan, status: isDeviceUp(devFound, allDevices.value) ? 'online' : 'offline', - ip4Addresses: getIpv4Addresses(devFound, networkConfig.value), - ip6Addresses: getIpv6Addresses(devFound, networkConfig.value) + ipAddresses: publicIpAddresses }) } } } - return wanData.sort(sortByProperty('iface')) + wanConnections.value = wanData.sort(sortByProperty('iface')) }) onMounted(() => { @@ -150,6 +163,27 @@ onMounted(() => { getNetworkConfig() }) +async function retrievePublicIpAddresses(device: DeviceOrIface) { + let ipAddresses = [] + let publicIpAddresses: string[] = [] + + if (isIpv6Enabled(device)) { + ipAddresses = getIpv6Addresses(device, networkConfig.value).concat( + getIpv4Addresses(device, networkConfig.value) + ) + } else { + ipAddresses = getIpv4Addresses(device, networkConfig.value) + } + const ipAddr = ipAddresses[0].split('/')[0] + publicIpAddresses = await getPublicIpAddresses(ipAddr) + + if (publicIpAddresses.length == 0 || publicIpAddresses[0] == '') { + // cannot retrieve public IP address, using interface IP address as fallback + publicIpAddresses = ipAddresses + } + return publicIpAddresses +} + async function listWans() { loading.value.listWans = true error.value.listWans = '' @@ -197,6 +231,22 @@ async function getMwanReport() { } } +async function getPublicIpAddresses(privateIpAddr: string) { + error.value.getPublicIpAddresses = '' + error.value.getPublicIpAddressesDetails = '' + + try { + const res = await ubusCall('ns.report', 'get-public-ip-addresses', { + ip_address: privateIpAddr + }) + return res.data.public_ip_addresses + } catch (err: any) { + console.error(err) + error.value.getPublicIpAddresses = t(getAxiosErrorMessage(err)) + error.value.getPublicIpAddressesDetails = err.toString() + } +} + async function getMwanPolicies() { loading.value.getMwanPolicies = true error.value.getMwanPolicies = '' diff --git a/src/components/standalone/monitoring/connectivity/WanConnectionsCard.vue b/src/components/standalone/monitoring/connectivity/WanConnectionsCard.vue index 77325b75..9ac623aa 100644 --- a/src/components/standalone/monitoring/connectivity/WanConnectionsCard.vue +++ b/src/components/standalone/monitoring/connectivity/WanConnectionsCard.vue @@ -90,7 +90,7 @@ function getQosRule(item: Wan) { {{ t('standalone.real_time_monitor.interface') }} {{ t('standalone.real_time_monitor.device') }} {{ t('common.status') }} - {{ t('common.ip_address') }} + {{ t('standalone.real_time_monitor.public_ip_address') }} {{ t('standalone.qos.title_short') }} @@ -120,9 +120,9 @@ function getQosRule(item: Wan) { }} - - - {{ (item.ip4Addresses || []).concat(item.ip6Addresses || []).join(', ') }} + + + {{ item.ipAddresses.join(', ') }} - diff --git a/src/i18n/en/translation.json b/src/i18n/en/translation.json index 75b0264a..3ccd7c20 100644 --- a/src/i18n/en/translation.json +++ b/src/i18n/en/translation.json @@ -1962,7 +1962,8 @@ "ping_host_latency": "Latency to {pingHost}", "ping_host_packet_delivery_rate": "Packet delivery rate to {pingHost}", "latency_and_packet_delivery_rate": "Latency and packet delivery rate", - "no_hosts_configured_for_monitoring": "No hosts configured for monitoring" + "no_hosts_configured_for_monitoring": "No hosts configured for monitoring", + "public_ip_address": "Public IP address" }, "ping_latency_monitor": { "title": "Ping latency monitor", diff --git a/src/lib/standalone/network.ts b/src/lib/standalone/network.ts index c56c9d76..3651e7e2 100644 --- a/src/lib/standalone/network.ts +++ b/src/lib/standalone/network.ts @@ -484,3 +484,8 @@ export function getVlanParent(bridgeDevice: DeviceOrIface, allDevices: DeviceOrI const deviceFound = allDevices.find((dev) => dev.name === parentDevice) return deviceFound } + +export function isIpv6Enabled(device: DeviceOrIface) { + const iface = getInterface(device) + return device.ipv6 === '1' || (iface.proto === 'pppoe' && device.ipv6 === 'auto') +}