diff --git a/web/src/api/ipfix.ts b/web/src/api/ipfix.ts index b34f668ff..18e36b70a 100644 --- a/web/src/api/ipfix.ts +++ b/web/src/api/ipfix.ts @@ -1,6 +1,7 @@ /* eslint-disable max-len */ import { TFunction } from 'i18next'; import { RecordType } from '../model/flow-query'; +import { NetworkEvent } from '../model/network-events'; // Please keep this file documented: it is used in doc generation // To regenerate doc, run `make generate-doc` - and also check this page: @@ -18,7 +19,7 @@ export const getRecordValue = (record: Record, fieldOrLabel: string, defaultValu * This is mandatory to ensure fields types */ if (record.fields[fieldOrLabel as keyof Fields] !== undefined) { - return record.fields[fieldOrLabel as keyof Fields]; + return record.fields[fieldOrLabel as keyof Fields] as string | number | string[] | undefined; } // check if label exists if (record.labels[fieldOrLabel as keyof Labels] !== undefined) { @@ -116,7 +117,7 @@ export interface Fields { /** Flow direction array from the network interface observation point */ IfDirections?: IfDirection[]; /** Network Events */ - NetworkEvents?: string[]; + NetworkEvents?: NetworkEvent[]; /** Logical OR combination of unique TCP flags comprised in the flow, as per RFC-9293, with additional custom flags to represent the following per-packet combinations: SYN+ACK (0x100), FIN+ACK (0x200) and RST+ACK (0x400). */ Flags?: number; /** Number of packets */ diff --git a/web/src/components/drawer/record/record-field.tsx b/web/src/components/drawer/record/record-field.tsx index aadb3b473..53ef24217 100644 --- a/web/src/components/drawer/record/record-field.tsx +++ b/web/src/components/drawer/record/record-field.tsx @@ -24,6 +24,7 @@ import { formatProtocol, getProtocolDocUrl } from '../../../utils/protocol'; import { decomposeTCPFlagsBitfield, getTCPFlagsDocUrl } from '../../../utils/tcp-flags'; import { Size } from '../../dropdowns/table-display-dropdown'; import './record-field.css'; +import { networkEventToString } from '../../../model/network-events'; export type RecordFieldFilter = { type: 'filter' | 'switch'; @@ -647,6 +648,16 @@ export const RecordField: React.FC = ({ : emptyText() ); } + case ColumnsId.networkEvents: { + if (flow.fields.NetworkEvents && flow.fields.NetworkEvents.length > 0) { + const asStrings = flow.fields.NetworkEvents.map(networkEventToString); + if (asStrings.length === 2) { + return doubleContainer(simpleTextWithTooltip(asStrings[0]), simpleTextWithTooltip(asStrings[1])); + } + // else we will show values as single joigned string + return singleContainer(simpleTextWithTooltip(asStrings.join(', '))); + } + } default: if (Array.isArray(value) && value.length) { // we can only show two values properly with containers diff --git a/web/src/model/network-events.ts b/web/src/model/network-events.ts new file mode 100644 index 000000000..91da0d6b8 --- /dev/null +++ b/web/src/model/network-events.ts @@ -0,0 +1,64 @@ + +export interface NetworkEvent { + Feature?: string; + Type?: string; + Action?: string; + Name?: string; + Namespace?: string; + Direction?: string; + Message?: string; +} + +export const networkEventToString = (event: NetworkEvent) => { + if (event.Feature === 'acl') { + let action: string; + switch (event.Action) { + case 'allow': + case 'allow-related': + case 'allow-stateless': + action = "Allowed"; + break; + case 'drop': + action = "Dropped"; + break; + case 'pass': + action = "Delegated to network policy"; + break; + default: + action = "Action " + event.Action + break; + } + let msg: string = ''; + switch (event.Type) { + case 'AdminNetworkPolicy': + msg = `admin network policy ${event.Name}, direction ${event.Direction}`; + break; + case 'BaselineAdminNetworkPolicy': + msg = `baseline admin network policy ${event.Name}, direction ${event.Direction}`; + break; + case 'MulticastNS': + msg = `multicast in namespace ${event.Namespace}, direction ${event.Direction}`; + break; + case 'MulticastCluster': + msg = `cluster multicast policy, direction ${event.Direction}`; + break; + case 'NetpolNode': + msg = `default allow from local node policy, direction ${event.Direction}`; + break; + case 'NetworkPolicy': + msg = `network policy ${event.Name}, direction ${event.Direction}`; + break; + case 'NetpolNamespace': + msg = `network policies isolation in namespace ${event.Namespace}, direction ${event.Direction}`; + break; + case 'EgressFirewall': + msg = `egress firewall in namespace ${event.Namespace}`; + break; + case 'UDNIsolation': + msg = `UDN isolation of type ${event.Name}`; + break; + } + return `${action} by ${msg}`; + } + return event.Message; +} diff --git a/web/src/utils/columns.ts b/web/src/utils/columns.ts index 2e568a1ed..14270cc4a 100644 --- a/web/src/utils/columns.ts +++ b/web/src/utils/columns.ts @@ -80,7 +80,8 @@ export enum ColumnsId { packetsab = 'Packets_AB', packetsba = 'Packets_BA', isfirst = 'IsFirst', - numflow = 'numFlowLogs' + numflow = 'numFlowLogs', + networkEvents = 'NetworkEvents' } export interface ColumnConfigDef {