Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions web/locales/en/plugin__netobserv-plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"Show related documentation": "Show related documentation",
"Value": "Value",
"Examples": "Examples",
"The flow contains packets with various flags: ": "The flow contains packets with various flags: ",
"ICMP type provided but protocol is {{proto}}": "ICMP type provided but protocol is {{proto}}",
"ICMP code provided but protocol is {{proto}}": "ICMP code provided but protocol is {{proto}}",
"Invalid data provided. Check JSON for details.": "Invalid data provided. Check JSON for details.",
Expand Down
28 changes: 15 additions & 13 deletions web/src/components/drawer/record/record-field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,7 @@ import {
import { dropCausesNames, getDropCauseDescription, getDropCauseDocUrl } from '../../../utils/pkt-drop';
import { formatPort } from '../../../utils/port';
import { formatProtocol, getProtocolDocUrl } from '../../../utils/protocol';
import {
getTCPFlagsDocUrl,
gettcpFlagsServiceClassDescription,
gettcpFlagsServiceClassName
} from '../../../utils/tcp_flags';
import { decomposeTCPFlagsBitfield, getTCPFlagsDocUrl } from '../../../utils/tcp-flags';
import { Size } from '../../dropdowns/table-display-dropdown';
import './record-field.css';

Expand Down Expand Up @@ -478,15 +474,21 @@ export const RecordField: React.FC<RecordFieldProps> = ({
case ColumnsId.tcpflags: {
let child = emptyText();
if (typeof value === 'number' && !isNaN(value)) {
const serviceClassName = gettcpFlagsServiceClassName(value);
if (serviceClassName && detailed) {
child = clickableContent(
serviceClassName,
`${t('Value')}: ${value} ${t('Examples')}: ${gettcpFlagsServiceClassDescription(value)}`,
getTCPFlagsDocUrl()
);
const flags = decomposeTCPFlagsBitfield(value);
const name = flags.length > 0 ? flags.map(f => f.name).join(', ') : String(value);
if (detailed) {
let description = `${t('Value')}: ${value}`;
if (flags.length === 1) {
description += '. ' + flags[0].description;
} else if (flags.length > 1) {
description +=
'. ' +
t('The flow contains packets with various flags: ') +
flags.map(f => f.name + ' (' + f.description + ')').join('; ');
}
child = clickableContent(name, description, getTCPFlagsDocUrl());
} else {
child = simpleTextWithTooltip(serviceClassName || String(value))!;
child = simpleTextWithTooltip(name)!;
}
}
return singleContainer(child);
Expand Down
17 changes: 17 additions & 0 deletions web/src/utils/__tests__/tcp-flags.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { decomposeTCPFlagsBitfield } from '../tcp-flags';

describe('TCP flags', () => {
it('should decompose', () => {
const flags528 = decomposeTCPFlagsBitfield(528);
expect(flags528).toHaveLength(2);
expect(flags528.map(f => f.name)).toEqual(['ACK', 'FIN_ACK']);

const flags256 = decomposeTCPFlagsBitfield(256);
expect(flags256).toHaveLength(1);
expect(flags256.map(f => f.name)).toEqual(['SYN_ACK']);

const flags666 = decomposeTCPFlagsBitfield(666);
expect(flags666).toHaveLength(5);
expect(flags666.map(f => f.name)).toEqual(['SYN', 'PSH', 'ACK', 'CWR', 'FIN_ACK']);
});
});
8 changes: 4 additions & 4 deletions web/src/utils/filter-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { dnsErrors, dnsRCodes } from './dns';
import { DSCP_VALUES } from './dscp';
import { dropCauses, dropStates } from './pkt-drop';
import { getPort, getService } from './port';
import { TCPFlags_VALUES } from './tcp_flags';
import { tcpFlagsList } from './tcp-flags';

export const noOption: (value: string) => Promise<FilterOption[]> = () => Promise.resolve([]);

Expand Down Expand Up @@ -172,9 +172,9 @@ export const getDSCPOptions = (value: string): Promise<FilterOption[]> => {

export const getTCPFlagsOptions = (value: string): Promise<FilterOption[]> => {
return Promise.resolve(
TCPFlags_VALUES.filter(
opt => String(opt.value).includes(value) || opt.name.toLowerCase().includes(value.toLowerCase())
).map(v => ({ name: v.name, value: String(v.value) }))
tcpFlagsList
.filter(opt => String(opt.value).includes(value) || opt.name.toLowerCase().includes(value.toLowerCase()))
.map(v => ({ name: v.name, value: String(v.value) }))
);
};

Expand Down
29 changes: 29 additions & 0 deletions web/src/utils/tcp-flags.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { ReadOnlyValue, ReadOnlyValues } from './values';

export const getTCPFlagsDocUrl = () => {
return 'https://www.rfc-editor.org/rfc/rfc9293';
};

export const tcpFlagsList: ReadOnlyValues = [
{ value: 1, name: 'FIN', description: 'No more data from sender' },
{ value: 2, name: 'SYN', description: 'Synchronize sequence numbers' },
{ value: 4, name: 'RST', description: 'Reset the connection' },
{ value: 8, name: 'PSH', description: 'Push function' },
{ value: 16, name: 'ACK', description: 'Acknowledgement field is significant' },
{ value: 32, name: 'URG', description: 'Urgent pointer field is significant' },
{ value: 64, name: 'ECE', description: 'ECN-Echo' },
{ value: 128, name: 'CWR', description: 'Congestion Window Reduced' },
{ value: 256, name: 'SYN_ACK', description: 'Acknowledgement of SYN (custom flag)' },
{ value: 512, name: 'FIN_ACK', description: 'Acknowledgement of FIN (custom flag)' },
{ value: 1024, name: 'RST_ACK', description: 'Acknowledgement of RST (custom flag)' }
] as const;

export const decomposeTCPFlagsBitfield = (bitfield: number): ReadOnlyValues => {
const values: ReadOnlyValue[] = [];
tcpFlagsList.forEach(flag => {
if (bitfield & flag.value) {
values.push(flag);
}
});
return values;
};
37 changes: 0 additions & 37 deletions web/src/utils/tcp_flags.ts

This file was deleted.

Loading