diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/index.tsx
index 9758477a4ee2a..40460f81fa83c 100644
--- a/x-pack/legacy/plugins/siem/public/components/page/network/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/page/network/index.tsx
@@ -6,4 +6,6 @@
export { IpOverview } from './ip_overview';
export { KpiNetworkComponent } from './kpi_network';
+export { NetworkDnsTable } from './network_dns_table';
+export { NetworkTopCountriesTable } from './network_top_countries_table';
export { NetworkTopNFlowTable } from './network_top_n_flow_table';
diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/__snapshots__/index.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/__snapshots__/index.test.tsx.snap
new file mode 100644
index 0000000000000..1127528c776b7
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/__snapshots__/index.test.tsx.snap
@@ -0,0 +1,291 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`NetworkTopCountries Table Component rendering it renders the IP Details NetworkTopCountries table 1`] = `
+
+`;
+
+exports[`NetworkTopCountries Table Component rendering it renders the default NetworkTopCountries table 1`] = `
+
+`;
diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/columns.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/columns.tsx
new file mode 100644
index 0000000000000..290891def3da8
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/columns.tsx
@@ -0,0 +1,176 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { get } from 'lodash/fp';
+import numeral from '@elastic/numeral';
+import React from 'react';
+import { StaticIndexPattern } from 'ui/index_patterns';
+
+import { CountryFlagAndName } from '../../../source_destination/country_flag';
+import {
+ FlowTargetSourceDest,
+ NetworkTopCountriesEdges,
+ TopNetworkTablesEcsField,
+} from '../../../../graphql/types';
+import { networkModel } from '../../../../store';
+import { DragEffects, DraggableWrapper } from '../../../drag_and_drop/draggable_wrapper';
+import { escapeDataProviderId } from '../../../drag_and_drop/helpers';
+import { getEmptyTagValue } from '../../../empty_value';
+import { Columns } from '../../../paginated_table';
+import { IS_OPERATOR } from '../../../timeline/data_providers/data_provider';
+import { Provider } from '../../../timeline/data_providers/provider';
+import * as i18n from './translations';
+import { PreferenceFormattedBytes } from '../../../formatted_bytes';
+
+export type NetworkTopCountriesColumns = [
+ Columns,
+ Columns,
+ Columns,
+ Columns,
+ Columns,
+ Columns
+];
+
+export type NetworkTopCountriesColumnsIpDetails = [
+ Columns,
+ Columns,
+ Columns,
+ Columns,
+ Columns
+];
+
+export const getNetworkTopCountriesColumns = (
+ indexPattern: StaticIndexPattern,
+ flowTarget: FlowTargetSourceDest,
+ type: networkModel.NetworkType,
+ tableId: string
+): NetworkTopCountriesColumns => [
+ {
+ name: i18n.COUNTRY,
+ render: ({ node }) => {
+ const geo = get(`${flowTarget}.country`, node);
+ const geoAttr = `${flowTarget}.geo.country_iso_code`;
+ const id = escapeDataProviderId(`${tableId}-table-${flowTarget}-country-${geo}`);
+ if (geo != null) {
+ return (
+
+ snapshot.isDragging ? (
+
+
+
+ ) : (
+ <>
+
+ >
+ )
+ }
+ />
+ );
+ } else {
+ return getEmptyTagValue();
+ }
+ },
+ width: '20%',
+ },
+ {
+ align: 'right',
+ field: 'node.network.bytes_in',
+ name: i18n.BYTES_IN,
+ sortable: true,
+ render: bytes => {
+ if (bytes != null) {
+ return ;
+ } else {
+ return getEmptyTagValue();
+ }
+ },
+ },
+ {
+ align: 'right',
+ field: 'node.network.bytes_out',
+ name: i18n.BYTES_OUT,
+ sortable: true,
+ render: bytes => {
+ if (bytes != null) {
+ return ;
+ } else {
+ return getEmptyTagValue();
+ }
+ },
+ },
+ {
+ align: 'right',
+ field: `node.${flowTarget}.flows`,
+ name: i18n.FLOWS,
+ sortable: true,
+ render: flows => {
+ if (flows != null) {
+ return numeral(flows).format('0,000');
+ } else {
+ return getEmptyTagValue();
+ }
+ },
+ },
+ {
+ align: 'right',
+ field: `node.${flowTarget}.${flowTarget}_ips`,
+ name: flowTarget === FlowTargetSourceDest.source ? i18n.SOURCE_IPS : i18n.DESTINATION_IPS,
+ sortable: true,
+ render: ips => {
+ if (ips != null) {
+ return numeral(ips).format('0,000');
+ } else {
+ return getEmptyTagValue();
+ }
+ },
+ },
+ {
+ align: 'right',
+ field: `node.${flowTarget}.${getOppositeField(flowTarget)}_ips`,
+ name: flowTarget === FlowTargetSourceDest.source ? i18n.SOURCE_IPS : i18n.DESTINATION_IPS,
+ sortable: true,
+ render: ips => {
+ if (ips != null) {
+ return numeral(ips).format('0,000');
+ } else {
+ return getEmptyTagValue();
+ }
+ },
+ },
+];
+
+export const getCountriesColumnsCurated = (
+ indexPattern: StaticIndexPattern,
+ flowTarget: FlowTargetSourceDest,
+ type: networkModel.NetworkType,
+ tableId: string
+): NetworkTopCountriesColumns | NetworkTopCountriesColumnsIpDetails => {
+ const columns = getNetworkTopCountriesColumns(indexPattern, flowTarget, type, tableId);
+
+ // Columns to exclude from host details pages
+ if (type === networkModel.NetworkType.details) {
+ columns.pop();
+ return columns;
+ }
+
+ return columns;
+};
+
+const getOppositeField = (flowTarget: FlowTargetSourceDest): FlowTargetSourceDest =>
+ flowTarget === FlowTargetSourceDest.source
+ ? FlowTargetSourceDest.destination
+ : FlowTargetSourceDest.source;
diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/index.test.tsx
new file mode 100644
index 0000000000000..4fa1bceac9888
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/index.test.tsx
@@ -0,0 +1,150 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { mount, shallow } from 'enzyme';
+import toJson from 'enzyme-to-json';
+import { getOr } from 'lodash/fp';
+import * as React from 'react';
+import { MockedProvider } from 'react-apollo/test-utils';
+import { Provider as ReduxStoreProvider } from 'react-redux';
+
+import { FlowTargetSourceDest } from '../../../../graphql/types';
+import {
+ apolloClientObservable,
+ mockGlobalState,
+ mockIndexPattern,
+ TestProviders,
+} from '../../../../mock';
+import { createStore, networkModel, State } from '../../../../store';
+
+import { NetworkTopCountriesTable } from '.';
+import { mockData } from './mock';
+jest.mock('../../../../lib/settings/use_kibana_ui_setting');
+describe('NetworkTopCountries Table Component', () => {
+ const loadPage = jest.fn();
+ const state: State = mockGlobalState;
+
+ let store = createStore(state, apolloClientObservable);
+
+ beforeEach(() => {
+ store = createStore(state, apolloClientObservable);
+ });
+
+ describe('rendering', () => {
+ test('it renders the default NetworkTopCountries table', () => {
+ const wrapper = shallow(
+
+
+
+ );
+
+ expect(toJson(wrapper)).toMatchSnapshot();
+ });
+ test('it renders the IP Details NetworkTopCountries table', () => {
+ const wrapper = shallow(
+
+
+
+ );
+
+ expect(toJson(wrapper)).toMatchSnapshot();
+ });
+ });
+
+ describe('Sorting on Table', () => {
+ test('when you click on the column header, you should show the sorting icon', () => {
+ const wrapper = mount(
+
+
+
+
+
+ );
+ expect(store.getState().network.page.queries.topCountriesSource.topCountriesSort).toEqual({
+ direction: 'desc',
+ field: 'bytes_out',
+ });
+
+ wrapper
+ .find('.euiTable thead tr th button')
+ .at(1)
+ .simulate('click');
+
+ wrapper.update();
+
+ expect(store.getState().network.page.queries.topCountriesSource.topCountriesSort).toEqual({
+ direction: 'asc',
+ field: 'bytes_out',
+ });
+ expect(
+ wrapper
+ .find('.euiTable thead tr th button')
+ .first()
+ .text()
+ ).toEqual('Bytes inClick to sort in ascending order');
+ expect(
+ wrapper
+ .find('.euiTable thead tr th button')
+ .at(1)
+ .text()
+ ).toEqual('Bytes outClick to sort in descending order');
+ expect(
+ wrapper
+ .find('.euiTable thead tr th button')
+ .at(1)
+ .find('svg')
+ ).toBeTruthy();
+ });
+ });
+});
diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/index.tsx
new file mode 100644
index 0000000000000..3972bb80b760b
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/index.tsx
@@ -0,0 +1,206 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { isEqual, last } from 'lodash/fp';
+import React from 'react';
+import { connect } from 'react-redux';
+import { ActionCreator } from 'typescript-fsa';
+import { StaticIndexPattern } from 'ui/index_patterns';
+
+import { networkActions } from '../../../../store/actions';
+import {
+ Direction,
+ FlowTargetSourceDest,
+ NetworkTopCountriesEdges,
+ NetworkTopTablesFields,
+ NetworkTopTablesSortField,
+} from '../../../../graphql/types';
+import { networkModel, networkSelectors, State } from '../../../../store';
+import { Criteria, ItemsPerRow, PaginatedTable } from '../../../paginated_table';
+
+import { getCountriesColumnsCurated } from './columns';
+import * as i18n from './translations';
+
+interface OwnProps {
+ data: NetworkTopCountriesEdges[];
+ fakeTotalCount: number;
+ flowTargeted: FlowTargetSourceDest;
+ id: string;
+ indexPattern: StaticIndexPattern;
+ ip?: string;
+ isInspect: boolean;
+ loading: boolean;
+ loadPage: (newActivePage: number) => void;
+ showMorePagesIndicator: boolean;
+ totalCount: number;
+ type: networkModel.NetworkType;
+}
+
+interface NetworkTopCountriesTableReduxProps {
+ activePage: number;
+ limit: number;
+ topCountriesSort: NetworkTopTablesSortField;
+}
+
+interface NetworkTopCountriesTableDispatchProps {
+ updateIpDetailsTableActivePage: ActionCreator<{
+ activePage: number;
+ tableType: networkModel.IpDetailsTableType;
+ }>;
+ updateNetworkPageTableActivePage: ActionCreator<{
+ activePage: number;
+ tableType: networkModel.NetworkTableType;
+ }>;
+ updateTopCountriesLimit: ActionCreator<{
+ limit: number;
+ networkType: networkModel.NetworkType;
+ tableType: networkModel.TopCountriesTableType;
+ }>;
+ updateTopCountriesSort: ActionCreator<{
+ topCountriesSort: NetworkTopTablesSortField;
+ networkType: networkModel.NetworkType;
+ tableType: networkModel.TopCountriesTableType;
+ }>;
+}
+
+type NetworkTopCountriesTableProps = OwnProps &
+ NetworkTopCountriesTableReduxProps &
+ NetworkTopCountriesTableDispatchProps;
+
+const rowItems: ItemsPerRow[] = [
+ {
+ text: i18n.ROWS_5,
+ numberOfRow: 5,
+ },
+ {
+ text: i18n.ROWS_10,
+ numberOfRow: 10,
+ },
+];
+
+export const NetworkTopCountriesTableId = 'networkTopCountries-top-talkers';
+
+const NetworkTopCountriesTableComponent = React.memo(
+ ({
+ activePage,
+ data,
+ fakeTotalCount,
+ flowTargeted,
+ id,
+ indexPattern,
+ isInspect,
+ limit,
+ loading,
+ loadPage,
+ showMorePagesIndicator,
+ topCountriesSort,
+ totalCount,
+ type,
+ updateIpDetailsTableActivePage,
+ updateTopCountriesLimit,
+ updateTopCountriesSort,
+ updateNetworkPageTableActivePage,
+ }) => {
+ const onChange = (criteria: Criteria, tableType: networkModel.TopCountriesTableType) => {
+ if (criteria.sort != null) {
+ const splitField = criteria.sort.field.split('.');
+ const field = last(splitField);
+ const newSortDirection =
+ field !== topCountriesSort.field ? Direction.desc : criteria.sort.direction; // sort by desc on init click
+ const newTopCountriesSort: NetworkTopTablesSortField = {
+ field: field as NetworkTopTablesFields,
+ direction: newSortDirection,
+ };
+ if (!isEqual(newTopCountriesSort, topCountriesSort)) {
+ updateTopCountriesSort({
+ topCountriesSort: newTopCountriesSort,
+ networkType: type,
+ tableType,
+ });
+ }
+ }
+ };
+
+ let tableType: networkModel.TopCountriesTableType;
+ const headerTitle: string =
+ flowTargeted === FlowTargetSourceDest.source
+ ? i18n.SOURCE_COUNTRIES
+ : i18n.DESTINATION_COUNTRIES;
+
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ let updateTableActivePage: any;
+ if (type === networkModel.NetworkType.page) {
+ tableType =
+ flowTargeted === FlowTargetSourceDest.source
+ ? networkModel.NetworkTableType.topCountriesSource
+ : networkModel.NetworkTableType.topCountriesDestination;
+ updateTableActivePage = updateNetworkPageTableActivePage;
+ } else {
+ tableType =
+ flowTargeted === FlowTargetSourceDest.source
+ ? networkModel.IpDetailsTableType.topCountriesSource
+ : networkModel.IpDetailsTableType.topCountriesDestination;
+ updateTableActivePage = updateIpDetailsTableActivePage;
+ }
+
+ const field =
+ topCountriesSort.field === NetworkTopTablesFields.bytes_out ||
+ topCountriesSort.field === NetworkTopTablesFields.bytes_in
+ ? `node.network.${topCountriesSort.field}`
+ : `node.${flowTargeted}.${topCountriesSort.field}`;
+
+ return (
+ loadPage(newActivePage)}
+ onChange={criteria => onChange(criteria, tableType)}
+ pageOfItems={data}
+ showMorePagesIndicator={showMorePagesIndicator}
+ sorting={{ field, direction: topCountriesSort.direction }}
+ totalCount={fakeTotalCount}
+ updateActivePage={newPage =>
+ updateTableActivePage({
+ activePage: newPage,
+ tableType,
+ })
+ }
+ updateLimitPagination={newLimit =>
+ updateTopCountriesLimit({ limit: newLimit, networkType: type, tableType })
+ }
+ />
+ );
+ }
+);
+
+NetworkTopCountriesTableComponent.displayName = 'NetworkTopCountriesTableComponent';
+
+const mapStateToProps = (state: State, ownProps: OwnProps) =>
+ networkSelectors.topCountriesSelector(ownProps.flowTargeted, ownProps.type);
+
+export const NetworkTopCountriesTable = connect(
+ mapStateToProps,
+ {
+ updateTopCountriesLimit: networkActions.updateTopCountriesLimit,
+ updateTopCountriesSort: networkActions.updateTopCountriesSort,
+ updateNetworkPageTableActivePage: networkActions.updateNetworkPageTableActivePage,
+ updateIpDetailsTableActivePage: networkActions.updateIpDetailsTableActivePage,
+ }
+)(NetworkTopCountriesTableComponent);
diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/mock.ts b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/mock.ts
new file mode 100644
index 0000000000000..42b933c7fba6d
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/mock.ts
@@ -0,0 +1,56 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { NetworkTopCountriesData } from '../../../../graphql/types';
+
+export const mockData: { NetworkTopCountries: NetworkTopCountriesData } = {
+ NetworkTopCountries: {
+ totalCount: 524,
+ edges: [
+ {
+ node: {
+ source: {
+ country: 'DE',
+ destination_ips: 12,
+ flows: 12345,
+ source_ips: 55,
+ },
+ destination: null,
+ network: {
+ bytes_in: 3826633497,
+ bytes_out: 1083495734,
+ },
+ },
+ cursor: {
+ value: '8.8.8.8',
+ },
+ },
+ {
+ node: {
+ source: {
+ flows: 12345,
+ destination_ips: 12,
+ source_ips: 55,
+ country: 'US',
+ },
+ destination: null,
+ network: {
+ bytes_in: 3826633497,
+ bytes_out: 1083495734,
+ },
+ },
+ cursor: {
+ value: '9.9.9.9',
+ },
+ },
+ ],
+ pageInfo: {
+ activePage: 1,
+ fakeTotalCount: 50,
+ showMorePagesIndicator: true,
+ },
+ },
+};
diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/translations.ts b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/translations.ts
new file mode 100644
index 0000000000000..2fad2687daf1e
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_countries_table/translations.ts
@@ -0,0 +1,67 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { i18n } from '@kbn/i18n';
+
+export const UNIT = (totalCount: number) =>
+ i18n.translate('xpack.siem.networkTopCountriesTable.heading.unit', {
+ values: { totalCount },
+ defaultMessage: `{totalCount, plural, =1 {Country} other {Countries}}`,
+ });
+
+export const COUNTRY = i18n.translate('xpack.siem.networkTopCountriesTable.column.countryTitle', {
+ defaultMessage: 'Country',
+});
+
+export const BYTES_IN = i18n.translate('xpack.siem.networkTopCountriesTable.column.bytesInTitle', {
+ defaultMessage: 'Bytes in',
+});
+
+export const BYTES_OUT = i18n.translate(
+ 'xpack.siem.networkTopCountriesTable.column.bytesOutTitle',
+ {
+ defaultMessage: 'Bytes out',
+ }
+);
+
+export const FLOWS = i18n.translate('xpack.siem.networkTopCountriesTable.column.flows', {
+ defaultMessage: 'Flows',
+});
+
+export const DESTINATION_COUNTRIES = i18n.translate(
+ 'xpack.siem.networkTopCountriesTable.heading.destinationCountries',
+ {
+ defaultMessage: 'Top Destination Countries',
+ }
+);
+
+export const SOURCE_COUNTRIES = i18n.translate(
+ 'xpack.siem.networkTopCountriesTable.heading.sourceCountries',
+ {
+ defaultMessage: 'Top Source Countries',
+ }
+);
+
+export const DESTINATION_IPS = i18n.translate(
+ 'xpack.siem.networkTopCountriesTable.column.destinationIps',
+ {
+ defaultMessage: 'Destination IPs',
+ }
+);
+
+export const SOURCE_IPS = i18n.translate('xpack.siem.networkTopCountriesTable.column.sourceIps', {
+ defaultMessage: 'Source IPs',
+});
+
+export const ROWS_5 = i18n.translate('xpack.siem.networkTopCountriesTable.rows', {
+ values: { numRows: 5 },
+ defaultMessage: '{numRows} {numRows, plural, =0 {rows} =1 {row} other {rows}}',
+});
+
+export const ROWS_10 = i18n.translate('xpack.siem.networkTopCountriesTable.rows', {
+ values: { numRows: 10 },
+ defaultMessage: '{numRows} {numRows, plural, =0 {rows} =1 {row} other {rows}}',
+});
diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/columns.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/columns.tsx
index bdb57a3323d4e..abb4d9ac29f1b 100644
--- a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/columns.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/columns.tsx
@@ -14,7 +14,7 @@ import {
AutonomousSystemItem,
FlowTargetSourceDest,
NetworkTopNFlowEdges,
- TopNFlowNetworkEcsField,
+ TopNetworkTablesEcsField,
} from '../../../../graphql/types';
import { networkModel } from '../../../../store';
import { DragEffects, DraggableWrapper } from '../../../drag_and_drop/draggable_wrapper';
@@ -32,8 +32,8 @@ export type NetworkTopNFlowColumns = [
Columns,
Columns,
Columns,
- Columns,
- Columns,
+ Columns,
+ Columns,
Columns,
Columns
];
@@ -42,8 +42,8 @@ export type NetworkTopNFlowColumnsIpDetails = [
Columns,
Columns,
Columns,
- Columns,
- Columns,
+ Columns,
+ Columns,
Columns
];
diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/index.tsx
index 507f8b75b842a..9e6e3cf844119 100644
--- a/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/page/network/network_top_n_flow_table/index.tsx
@@ -3,11 +3,9 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
-import { EuiFlexItem } from '@elastic/eui';
import { isEqual, last } from 'lodash/fp';
import React from 'react';
import { connect } from 'react-redux';
-import styled from 'styled-components';
import { ActionCreator } from 'typescript-fsa';
import { StaticIndexPattern } from 'ui/index_patterns';
@@ -16,8 +14,8 @@ import {
Direction,
FlowTargetSourceDest,
NetworkTopNFlowEdges,
- NetworkTopNFlowFields,
- NetworkTopNFlowSortField,
+ NetworkTopTablesFields,
+ NetworkTopTablesSortField,
} from '../../../../graphql/types';
import { networkModel, networkSelectors, State } from '../../../../store';
import { Criteria, ItemsPerRow, PaginatedTable } from '../../../paginated_table';
@@ -42,7 +40,7 @@ interface OwnProps {
interface NetworkTopNFlowTableReduxProps {
activePage: number;
limit: number;
- topNFlowSort: NetworkTopNFlowSortField;
+ topNFlowSort: NetworkTopTablesSortField;
}
interface NetworkTopNFlowTableDispatchProps {
@@ -60,7 +58,7 @@ interface NetworkTopNFlowTableDispatchProps {
tableType: networkModel.TopNTableType;
}>;
updateTopNFlowSort: ActionCreator<{
- topNFlowSort: NetworkTopNFlowSortField;
+ topNFlowSort: NetworkTopTablesSortField;
networkType: networkModel.NetworkType;
tableType: networkModel.TopNTableType;
}>;
@@ -110,8 +108,8 @@ const NetworkTopNFlowTableComponent = React.memo(
const field = last(splitField);
const newSortDirection =
field !== topNFlowSort.field ? Direction.desc : criteria.sort.direction; // sort by desc on init click
- const newTopNFlowSort: NetworkTopNFlowSortField = {
- field: field as NetworkTopNFlowFields,
+ const newTopNFlowSort: NetworkTopTablesSortField = {
+ field: field as NetworkTopTablesFields,
direction: newSortDirection,
};
if (!isEqual(newTopNFlowSort, topNFlowSort)) {
@@ -145,8 +143,8 @@ const NetworkTopNFlowTableComponent = React.memo(
}
const field =
- topNFlowSort.field === NetworkTopNFlowFields.bytes_out ||
- topNFlowSort.field === NetworkTopNFlowFields.bytes_in
+ topNFlowSort.field === NetworkTopTablesFields.bytes_out ||
+ topNFlowSort.field === NetworkTopTablesFields.bytes_in
? `node.network.${topNFlowSort.field}`
: `node.${flowTargeted}.${topNFlowSort.field}`;
@@ -197,9 +195,3 @@ export const NetworkTopNFlowTable = connect(
updateIpDetailsTableActivePage: networkActions.updateIpDetailsTableActivePage,
}
)(NetworkTopNFlowTableComponent);
-
-const SelectTypeItem = styled(EuiFlexItem)`
- min-width: 180px;
-`;
-
-SelectTypeItem.displayName = 'SelectTypeItem';
diff --git a/x-pack/legacy/plugins/siem/public/components/paginated_table/index.tsx b/x-pack/legacy/plugins/siem/public/components/paginated_table/index.tsx
index 1529648b7133e..4de64c6b32aa9 100644
--- a/x-pack/legacy/plugins/siem/public/components/paginated_table/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/paginated_table/index.tsx
@@ -27,6 +27,10 @@ import {
NetworkTopNFlowColumns,
NetworkTopNFlowColumnsIpDetails,
} from '../page/network/network_top_n_flow_table/columns';
+import {
+ NetworkTopCountriesColumns,
+ NetworkTopCountriesColumnsIpDetails,
+} from '../page/network/network_top_countries_table/columns';
import { TlsColumns } from '../page/network/tls_table/columns';
import { UncommonProcessTableColumns } from '../page/hosts/uncommon_process_table';
import { UsersColumns } from '../page/network/users_table/columns';
@@ -68,6 +72,8 @@ declare type BasicTableColumns =
| HostsTableColumns
| HostsTableColumnsTest
| NetworkDnsColumns
+ | NetworkTopCountriesColumns
+ | NetworkTopCountriesColumnsIpDetails
| NetworkTopNFlowColumns
| NetworkTopNFlowColumnsIpDetails
| TlsColumns
diff --git a/x-pack/legacy/plugins/siem/public/components/source_destination/country_flag.tsx b/x-pack/legacy/plugins/siem/public/components/source_destination/country_flag.tsx
index 98639e0d38514..4de678f7f636e 100644
--- a/x-pack/legacy/plugins/siem/public/components/source_destination/country_flag.tsx
+++ b/x-pack/legacy/plugins/siem/public/components/source_destination/country_flag.tsx
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import React, { memo, useEffect } from 'react';
+import React, { memo, useEffect, useState } from 'react';
import { isEmpty } from 'lodash/fp';
import { EuiToolTip } from '@elastic/eui';
import countries from 'i18n-iso-countries';
@@ -22,7 +22,7 @@ export const getFlag = (countryCode: string): string | null =>
.replace(/./g, c => String.fromCharCode(55356, 56741 + c.charCodeAt(0)))
: null;
-/** Renders an emjoi flag for the specified country code */
+/** Renders an emoji flag for the specified country code */
export const CountryFlag = memo<{
countryCode: string;
displayCountryNameOnHover?: boolean;
@@ -47,3 +47,32 @@ export const CountryFlag = memo<{
});
CountryFlag.displayName = 'CountryFlag';
+
+/** Renders an emjoi flag with country name for the specified country code */
+export const CountryFlagAndName = memo<{
+ countryCode: string;
+ displayCountryNameOnHover?: boolean;
+}>(({ countryCode, displayCountryNameOnHover = false }) => {
+ const [localesLoaded, setLocalesLoaded] = useState(false);
+ useEffect(() => {
+ if (isEmpty(countries.getNames('en'))) {
+ countries.registerLocale(countryJson);
+ }
+ setLocalesLoaded(true);
+ }, []);
+
+ const flag = getFlag(countryCode);
+
+ if (flag !== null && localesLoaded) {
+ return displayCountryNameOnHover ? (
+
+ {flag}
+
+ ) : (
+ {`${flag} ${countries.getName(countryCode, 'en')}`}
+ );
+ }
+ return null;
+});
+
+CountryFlagAndName.displayName = 'CountryFlagAndName';
diff --git a/x-pack/legacy/plugins/siem/public/containers/network_top_countries/index.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/network_top_countries/index.gql_query.ts
new file mode 100644
index 0000000000000..5850246ceecec
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/containers/network_top_countries/index.gql_query.ts
@@ -0,0 +1,68 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import gql from 'graphql-tag';
+
+export const networkTopCountriesQuery = gql`
+ query GetNetworkTopCountriesQuery(
+ $sourceId: ID!
+ $ip: String
+ $filterQuery: String
+ $pagination: PaginationInputPaginated!
+ $sort: NetworkTopTablesSortField!
+ $flowTarget: FlowTargetSourceDest!
+ $timerange: TimerangeInput!
+ $defaultIndex: [String!]!
+ $inspect: Boolean!
+ ) {
+ source(id: $sourceId) {
+ id
+ NetworkTopCountries(
+ filterQuery: $filterQuery
+ flowTarget: $flowTarget
+ ip: $ip
+ pagination: $pagination
+ sort: $sort
+ timerange: $timerange
+ defaultIndex: $defaultIndex
+ ) {
+ totalCount
+ edges {
+ node {
+ source {
+ country
+ destination_ips
+ flows
+ source_ips
+ }
+ destination {
+ country
+ destination_ips
+ flows
+ source_ips
+ }
+ network {
+ bytes_in
+ bytes_out
+ }
+ }
+ cursor {
+ value
+ }
+ }
+ pageInfo {
+ activePage
+ fakeTotalCount
+ showMorePagesIndicator
+ }
+ inspect @include(if: $inspect) {
+ dsl
+ response
+ }
+ }
+ }
+ }
+`;
diff --git a/x-pack/legacy/plugins/siem/public/containers/network_top_countries/index.tsx b/x-pack/legacy/plugins/siem/public/containers/network_top_countries/index.tsx
new file mode 100644
index 0000000000000..8e3804ab77478
--- /dev/null
+++ b/x-pack/legacy/plugins/siem/public/containers/network_top_countries/index.tsx
@@ -0,0 +1,156 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { getOr } from 'lodash/fp';
+import React from 'react';
+import { Query } from 'react-apollo';
+import { connect } from 'react-redux';
+
+import chrome from 'ui/chrome';
+import { DEFAULT_INDEX_KEY } from '../../../common/constants';
+import {
+ FlowTargetSourceDest,
+ GetNetworkTopCountriesQuery,
+ NetworkTopCountriesEdges,
+ NetworkTopTablesSortField,
+ PageInfoPaginated,
+} from '../../graphql/types';
+import { inputsModel, inputsSelectors, networkModel, networkSelectors, State } from '../../store';
+import { generateTablePaginationOptions } from '../../components/paginated_table/helpers';
+import { createFilter, getDefaultFetchPolicy } from '../helpers';
+import { QueryTemplatePaginated, QueryTemplatePaginatedProps } from '../query_template_paginated';
+import { networkTopCountriesQuery } from './index.gql_query';
+
+const ID = 'networkTopCountriesQuery';
+
+export interface NetworkTopCountriesArgs {
+ id: string;
+ ip?: string;
+ inspect: inputsModel.InspectQuery;
+ isInspected: boolean;
+ loading: boolean;
+ loadPage: (newActivePage: number) => void;
+ networkTopCountries: NetworkTopCountriesEdges[];
+ pageInfo: PageInfoPaginated;
+ refetch: inputsModel.Refetch;
+ totalCount: number;
+}
+
+export interface OwnProps extends QueryTemplatePaginatedProps {
+ children: (args: NetworkTopCountriesArgs) => React.ReactNode;
+ flowTarget: FlowTargetSourceDest;
+ ip?: string;
+ type: networkModel.NetworkType;
+}
+
+export interface NetworkTopCountriesComponentReduxProps {
+ activePage: number;
+ isInspected: boolean;
+ limit: number;
+ topCountriesSort: NetworkTopTablesSortField;
+}
+
+type NetworkTopCountriesProps = OwnProps & NetworkTopCountriesComponentReduxProps;
+
+class NetworkTopCountriesComponentQuery extends QueryTemplatePaginated<
+ NetworkTopCountriesProps,
+ GetNetworkTopCountriesQuery.Query,
+ GetNetworkTopCountriesQuery.Variables
+> {
+ public render() {
+ const {
+ activePage,
+ children,
+ endDate,
+ flowTarget,
+ filterQuery,
+ id = `${ID}-${flowTarget}`,
+ ip,
+ isInspected,
+ limit,
+ skip,
+ sourceId,
+ startDate,
+ topCountriesSort,
+ } = this.props;
+ const variables: GetNetworkTopCountriesQuery.Variables = {
+ defaultIndex: chrome.getUiSettingsClient().get(DEFAULT_INDEX_KEY),
+ filterQuery: createFilter(filterQuery),
+ flowTarget,
+ inspect: isInspected,
+ ip,
+ pagination: generateTablePaginationOptions(activePage, limit),
+ sort: topCountriesSort,
+ sourceId,
+ timerange: {
+ interval: '12h',
+ from: startDate!,
+ to: endDate!,
+ },
+ };
+ return (
+
+ fetchPolicy={getDefaultFetchPolicy()}
+ notifyOnNetworkStatusChange
+ query={networkTopCountriesQuery}
+ skip={skip}
+ variables={variables}
+ >
+ {({ data, loading, fetchMore, networkStatus, refetch }) => {
+ const networkTopCountries = getOr([], `source.NetworkTopCountries.edges`, data);
+ this.setFetchMore(fetchMore);
+ this.setFetchMoreOptions((newActivePage: number) => ({
+ variables: {
+ pagination: generateTablePaginationOptions(newActivePage, limit),
+ },
+ updateQuery: (prev, { fetchMoreResult }) => {
+ if (!fetchMoreResult) {
+ return prev;
+ }
+ return {
+ ...fetchMoreResult,
+ source: {
+ ...fetchMoreResult.source,
+ NetworkTopCountries: {
+ ...fetchMoreResult.source.NetworkTopCountries,
+ edges: [...fetchMoreResult.source.NetworkTopCountries.edges],
+ },
+ },
+ };
+ },
+ }));
+ const isLoading = this.isItAValidLoading(loading, variables, networkStatus);
+ return children({
+ id,
+ inspect: getOr(null, 'source.NetworkTopCountries.inspect', data),
+ isInspected,
+ loading: isLoading,
+ loadPage: this.wrappedLoadMore,
+ networkTopCountries,
+ pageInfo: getOr({}, 'source.NetworkTopCountries.pageInfo', data),
+ refetch: this.memoizedRefetchQuery(variables, limit, refetch),
+ totalCount: getOr(-1, 'source.NetworkTopCountries.totalCount', data),
+ });
+ }}
+
+ );
+ }
+}
+
+const mapStateToProps = (
+ state: State,
+ { flowTarget, id = `${ID}-${flowTarget}`, type }: OwnProps
+) => {
+ const getNetworkTopCountriesSelector = networkSelectors.topCountriesSelector(flowTarget, type);
+ const getQuery = inputsSelectors.globalQueryByIdSelector();
+ const { isInspected } = getQuery(state, id);
+ return {
+ ...getNetworkTopCountriesSelector(state),
+ isInspected,
+ };
+};
+
+export const NetworkTopCountriesQuery = connect(mapStateToProps)(NetworkTopCountriesComponentQuery);
diff --git a/x-pack/legacy/plugins/siem/public/containers/network_top_n_flow/index.gql_query.ts b/x-pack/legacy/plugins/siem/public/containers/network_top_n_flow/index.gql_query.ts
index 81a94bc94652b..a73f9ff9256ff 100644
--- a/x-pack/legacy/plugins/siem/public/containers/network_top_n_flow/index.gql_query.ts
+++ b/x-pack/legacy/plugins/siem/public/containers/network_top_n_flow/index.gql_query.ts
@@ -12,7 +12,7 @@ export const networkTopNFlowQuery = gql`
$ip: String
$filterQuery: String
$pagination: PaginationInputPaginated!
- $sort: NetworkTopNFlowSortField!
+ $sort: NetworkTopTablesSortField!
$flowTarget: FlowTargetSourceDest!
$timerange: TimerangeInput!
$defaultIndex: [String!]!
diff --git a/x-pack/legacy/plugins/siem/public/containers/network_top_n_flow/index.tsx b/x-pack/legacy/plugins/siem/public/containers/network_top_n_flow/index.tsx
index eba9c5640fb58..32629853480a0 100644
--- a/x-pack/legacy/plugins/siem/public/containers/network_top_n_flow/index.tsx
+++ b/x-pack/legacy/plugins/siem/public/containers/network_top_n_flow/index.tsx
@@ -15,7 +15,7 @@ import {
FlowTargetSourceDest,
GetNetworkTopNFlowQuery,
NetworkTopNFlowEdges,
- NetworkTopNFlowSortField,
+ NetworkTopTablesSortField,
PageInfoPaginated,
} from '../../graphql/types';
import { inputsModel, inputsSelectors, networkModel, networkSelectors, State } from '../../store';
@@ -50,7 +50,7 @@ export interface NetworkTopNFlowComponentReduxProps {
activePage: number;
isInspected: boolean;
limit: number;
- topNFlowSort: NetworkTopNFlowSortField;
+ topNFlowSort: NetworkTopTablesSortField;
}
type NetworkTopNFlowProps = OwnProps & NetworkTopNFlowComponentReduxProps;
diff --git a/x-pack/legacy/plugins/siem/public/graphql/introspection.json b/x-pack/legacy/plugins/siem/public/graphql/introspection.json
index b8bdf27bed7fa..c012af5fd667f 100644
--- a/x-pack/legacy/plugins/siem/public/graphql/introspection.json
+++ b/x-pack/legacy/plugins/siem/public/graphql/introspection.json
@@ -1542,9 +1542,106 @@
"isDeprecated": false,
"deprecationReason": null
},
+ {
+ "name": "NetworkTopCountries",
+ "description": "",
+ "args": [
+ {
+ "name": "id",
+ "description": "",
+ "type": { "kind": "SCALAR", "name": "String", "ofType": null },
+ "defaultValue": null
+ },
+ {
+ "name": "filterQuery",
+ "description": "",
+ "type": { "kind": "SCALAR", "name": "String", "ofType": null },
+ "defaultValue": null
+ },
+ {
+ "name": "ip",
+ "description": "",
+ "type": { "kind": "SCALAR", "name": "String", "ofType": null },
+ "defaultValue": null
+ },
+ {
+ "name": "flowTarget",
+ "description": "",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "ENUM", "name": "FlowTargetSourceDest", "ofType": null }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "pagination",
+ "description": "",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "PaginationInputPaginated",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "sort",
+ "description": "",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "NetworkTopTablesSortField",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "timerange",
+ "description": "",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "INPUT_OBJECT", "name": "TimerangeInput", "ofType": null }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "defaultIndex",
+ "description": "",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "SCALAR", "name": "String", "ofType": null }
+ }
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "OBJECT", "name": "NetworkTopCountriesData", "ofType": null }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
{
"name": "NetworkTopNFlow",
- "description": "Gets Hosts based on timerange and specified criteria, or all events in the timerange if no criteria is specified",
+ "description": "",
"args": [
{
"name": "id",
@@ -1596,7 +1693,7 @@
"name": null,
"ofType": {
"kind": "INPUT_OBJECT",
- "name": "NetworkTopNFlowSortField",
+ "name": "NetworkTopTablesSortField",
"ofType": null
}
},
@@ -7204,7 +7301,7 @@
},
{
"kind": "INPUT_OBJECT",
- "name": "NetworkTopNFlowSortField",
+ "name": "NetworkTopTablesSortField",
"description": "",
"fields": null,
"inputFields": [
@@ -7214,7 +7311,7 @@
"type": {
"kind": "NON_NULL",
"name": null,
- "ofType": { "kind": "ENUM", "name": "NetworkTopNFlowFields", "ofType": null }
+ "ofType": { "kind": "ENUM", "name": "NetworkTopTablesFields", "ofType": null }
},
"defaultValue": null
},
@@ -7235,7 +7332,7 @@
},
{
"kind": "ENUM",
- "name": "NetworkTopNFlowFields",
+ "name": "NetworkTopTablesFields",
"description": "",
"fields": null,
"inputFields": null,
@@ -7271,7 +7368,7 @@
},
{
"kind": "OBJECT",
- "name": "NetworkTopNFlowData",
+ "name": "NetworkTopCountriesData",
"description": "",
"fields": [
{
@@ -7287,7 +7384,7 @@
"ofType": {
"kind": "NON_NULL",
"name": null,
- "ofType": { "kind": "OBJECT", "name": "NetworkTopNFlowEdges", "ofType": null }
+ "ofType": { "kind": "OBJECT", "name": "NetworkTopCountriesEdges", "ofType": null }
}
}
},
@@ -7334,7 +7431,7 @@
},
{
"kind": "OBJECT",
- "name": "NetworkTopNFlowEdges",
+ "name": "NetworkTopCountriesEdges",
"description": "",
"fields": [
{
@@ -7344,7 +7441,7 @@
"type": {
"kind": "NON_NULL",
"name": null,
- "ofType": { "kind": "OBJECT", "name": "NetworkTopNFlowItem", "ofType": null }
+ "ofType": { "kind": "OBJECT", "name": "NetworkTopCountriesItem", "ofType": null }
},
"isDeprecated": false,
"deprecationReason": null
@@ -7369,7 +7466,7 @@
},
{
"kind": "OBJECT",
- "name": "NetworkTopNFlowItem",
+ "name": "NetworkTopCountriesItem",
"description": "",
"fields": [
{
@@ -7384,7 +7481,7 @@
"name": "source",
"description": "",
"args": [],
- "type": { "kind": "OBJECT", "name": "TopNFlowItemSource", "ofType": null },
+ "type": { "kind": "OBJECT", "name": "TopCountriesItemSource", "ofType": null },
"isDeprecated": false,
"deprecationReason": null
},
@@ -7392,7 +7489,7 @@
"name": "destination",
"description": "",
"args": [],
- "type": { "kind": "OBJECT", "name": "TopNFlowItemDestination", "ofType": null },
+ "type": { "kind": "OBJECT", "name": "TopCountriesItemDestination", "ofType": null },
"isDeprecated": false,
"deprecationReason": null
},
@@ -7400,7 +7497,7 @@
"name": "network",
"description": "",
"args": [],
- "type": { "kind": "OBJECT", "name": "TopNFlowNetworkEcsField", "ofType": null },
+ "type": { "kind": "OBJECT", "name": "TopNetworkTablesEcsField", "ofType": null },
"isDeprecated": false,
"deprecationReason": null
}
@@ -7412,38 +7509,30 @@
},
{
"kind": "OBJECT",
- "name": "TopNFlowItemSource",
+ "name": "TopCountriesItemSource",
"description": "",
"fields": [
{
- "name": "autonomous_system",
+ "name": "country",
"description": "",
"args": [],
- "type": { "kind": "OBJECT", "name": "AutonomousSystemItem", "ofType": null },
+ "type": { "kind": "SCALAR", "name": "String", "ofType": null },
"isDeprecated": false,
"deprecationReason": null
},
{
- "name": "domain",
+ "name": "destination_ips",
"description": "",
"args": [],
- "type": {
- "kind": "LIST",
- "name": null,
- "ofType": {
- "kind": "NON_NULL",
- "name": null,
- "ofType": { "kind": "SCALAR", "name": "String", "ofType": null }
- }
- },
+ "type": { "kind": "SCALAR", "name": "Float", "ofType": null },
"isDeprecated": false,
"deprecationReason": null
},
{
- "name": "ip",
+ "name": "flows",
"description": "",
"args": [],
- "type": { "kind": "SCALAR", "name": "String", "ofType": null },
+ "type": { "kind": "SCALAR", "name": "Float", "ofType": null },
"isDeprecated": false,
"deprecationReason": null
},
@@ -7456,12 +7545,58 @@
"deprecationReason": null
},
{
- "name": "flows",
+ "name": "source_ips",
"description": "",
"args": [],
"type": { "kind": "SCALAR", "name": "Float", "ofType": null },
"isDeprecated": false,
"deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "GeoItem",
+ "description": "",
+ "fields": [
+ {
+ "name": "geo",
+ "description": "",
+ "args": [],
+ "type": { "kind": "OBJECT", "name": "GeoEcsFields", "ofType": null },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "flowTarget",
+ "description": "",
+ "args": [],
+ "type": { "kind": "ENUM", "name": "FlowTargetSourceDest", "ofType": null },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "TopCountriesItemDestination",
+ "description": "",
+ "fields": [
+ {
+ "name": "country",
+ "description": "",
+ "args": [],
+ "type": { "kind": "SCALAR", "name": "String", "ofType": null },
+ "isDeprecated": false,
+ "deprecationReason": null
},
{
"name": "destination_ips",
@@ -7470,6 +7605,30 @@
"type": { "kind": "SCALAR", "name": "Float", "ofType": null },
"isDeprecated": false,
"deprecationReason": null
+ },
+ {
+ "name": "flows",
+ "description": "",
+ "args": [],
+ "type": { "kind": "SCALAR", "name": "Float", "ofType": null },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "location",
+ "description": "",
+ "args": [],
+ "type": { "kind": "OBJECT", "name": "GeoItem", "ofType": null },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "source_ips",
+ "description": "",
+ "args": [],
+ "type": { "kind": "SCALAR", "name": "Float", "ofType": null },
+ "isDeprecated": false,
+ "deprecationReason": null
}
],
"inputFields": null,
@@ -7479,19 +7638,19 @@
},
{
"kind": "OBJECT",
- "name": "AutonomousSystemItem",
+ "name": "TopNetworkTablesEcsField",
"description": "",
"fields": [
{
- "name": "name",
+ "name": "bytes_in",
"description": "",
"args": [],
- "type": { "kind": "SCALAR", "name": "String", "ofType": null },
+ "type": { "kind": "SCALAR", "name": "Float", "ofType": null },
"isDeprecated": false,
"deprecationReason": null
},
{
- "name": "number",
+ "name": "bytes_out",
"description": "",
"args": [],
"type": { "kind": "SCALAR", "name": "Float", "ofType": null },
@@ -7506,22 +7665,58 @@
},
{
"kind": "OBJECT",
- "name": "GeoItem",
+ "name": "NetworkTopNFlowData",
"description": "",
"fields": [
{
- "name": "geo",
+ "name": "edges",
"description": "",
"args": [],
- "type": { "kind": "OBJECT", "name": "GeoEcsFields", "ofType": null },
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "OBJECT", "name": "NetworkTopNFlowEdges", "ofType": null }
+ }
+ }
+ },
"isDeprecated": false,
"deprecationReason": null
},
{
- "name": "flowTarget",
+ "name": "totalCount",
"description": "",
"args": [],
- "type": { "kind": "ENUM", "name": "FlowTargetSourceDest", "ofType": null },
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "OBJECT", "name": "PageInfoPaginated", "ofType": null }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "inspect",
+ "description": "",
+ "args": [],
+ "type": { "kind": "OBJECT", "name": "Inspect", "ofType": null },
"isDeprecated": false,
"deprecationReason": null
}
@@ -7533,7 +7728,85 @@
},
{
"kind": "OBJECT",
- "name": "TopNFlowItemDestination",
+ "name": "NetworkTopNFlowEdges",
+ "description": "",
+ "fields": [
+ {
+ "name": "node",
+ "description": "",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "OBJECT", "name": "NetworkTopNFlowItem", "ofType": null }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "cursor",
+ "description": "",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "OBJECT", "name": "CursorType", "ofType": null }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "NetworkTopNFlowItem",
+ "description": "",
+ "fields": [
+ {
+ "name": "_id",
+ "description": "",
+ "args": [],
+ "type": { "kind": "SCALAR", "name": "String", "ofType": null },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "source",
+ "description": "",
+ "args": [],
+ "type": { "kind": "OBJECT", "name": "TopNFlowItemSource", "ofType": null },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "destination",
+ "description": "",
+ "args": [],
+ "type": { "kind": "OBJECT", "name": "TopNFlowItemDestination", "ofType": null },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "network",
+ "description": "",
+ "args": [],
+ "type": { "kind": "OBJECT", "name": "TopNetworkTablesEcsField", "ofType": null },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "TopNFlowItemSource",
"description": "",
"fields": [
{
@@ -7585,7 +7858,7 @@
"deprecationReason": null
},
{
- "name": "source_ips",
+ "name": "destination_ips",
"description": "",
"args": [],
"type": { "kind": "SCALAR", "name": "Float", "ofType": null },
@@ -7600,19 +7873,86 @@
},
{
"kind": "OBJECT",
- "name": "TopNFlowNetworkEcsField",
+ "name": "AutonomousSystemItem",
"description": "",
"fields": [
{
- "name": "bytes_in",
+ "name": "name",
+ "description": "",
+ "args": [],
+ "type": { "kind": "SCALAR", "name": "String", "ofType": null },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "number",
"description": "",
"args": [],
"type": { "kind": "SCALAR", "name": "Float", "ofType": null },
"isDeprecated": false,
"deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "TopNFlowItemDestination",
+ "description": "",
+ "fields": [
+ {
+ "name": "autonomous_system",
+ "description": "",
+ "args": [],
+ "type": { "kind": "OBJECT", "name": "AutonomousSystemItem", "ofType": null },
+ "isDeprecated": false,
+ "deprecationReason": null
},
{
- "name": "bytes_out",
+ "name": "domain",
+ "description": "",
+ "args": [],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": { "kind": "SCALAR", "name": "String", "ofType": null }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "ip",
+ "description": "",
+ "args": [],
+ "type": { "kind": "SCALAR", "name": "String", "ofType": null },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "location",
+ "description": "",
+ "args": [],
+ "type": { "kind": "OBJECT", "name": "GeoItem", "ofType": null },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "flows",
+ "description": "",
+ "args": [],
+ "type": { "kind": "SCALAR", "name": "Float", "ofType": null },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "source_ips",
"description": "",
"args": [],
"type": { "kind": "SCALAR", "name": "Float", "ofType": null },
diff --git a/x-pack/legacy/plugins/siem/public/graphql/types.ts b/x-pack/legacy/plugins/siem/public/graphql/types.ts
index 7514259caa2a7..b8ed6f2ad47fe 100644
--- a/x-pack/legacy/plugins/siem/public/graphql/types.ts
+++ b/x-pack/legacy/plugins/siem/public/graphql/types.ts
@@ -79,8 +79,8 @@ export interface UsersSortField {
direction: Direction;
}
-export interface NetworkTopNFlowSortField {
- field: NetworkTopNFlowFields;
+export interface NetworkTopTablesSortField {
+ field: NetworkTopTablesFields;
direction: Direction;
}
@@ -260,7 +260,7 @@ export enum FlowTargetSourceDest {
source = 'source',
}
-export enum NetworkTopNFlowFields {
+export enum NetworkTopTablesFields {
bytes_in = 'bytes_in',
bytes_out = 'bytes_out',
flows = 'flows',
@@ -426,7 +426,9 @@ export interface Source {
KpiHosts: KpiHostsData;
KpiHostDetails: KpiHostDetailsData;
- /** Gets Hosts based on timerange and specified criteria, or all events in the timerange if no criteria is specified */
+
+ NetworkTopCountries: NetworkTopCountriesData;
+
NetworkTopNFlow: NetworkTopNFlowData;
NetworkDns: NetworkDnsData;
@@ -1456,6 +1458,68 @@ export interface KpiHostDetailsData {
inspect?: Maybe;
}
+export interface NetworkTopCountriesData {
+ edges: NetworkTopCountriesEdges[];
+
+ totalCount: number;
+
+ pageInfo: PageInfoPaginated;
+
+ inspect?: Maybe;
+}
+
+export interface NetworkTopCountriesEdges {
+ node: NetworkTopCountriesItem;
+
+ cursor: CursorType;
+}
+
+export interface NetworkTopCountriesItem {
+ _id?: Maybe;
+
+ source?: Maybe;
+
+ destination?: Maybe;
+
+ network?: Maybe;
+}
+
+export interface TopCountriesItemSource {
+ country?: Maybe;
+
+ destination_ips?: Maybe;
+
+ flows?: Maybe;
+
+ location?: Maybe;
+
+ source_ips?: Maybe;
+}
+
+export interface GeoItem {
+ geo?: Maybe;
+
+ flowTarget?: Maybe;
+}
+
+export interface TopCountriesItemDestination {
+ country?: Maybe;
+
+ destination_ips?: Maybe;
+
+ flows?: Maybe;
+
+ location?: Maybe;
+
+ source_ips?: Maybe;
+}
+
+export interface TopNetworkTablesEcsField {
+ bytes_in?: Maybe;
+
+ bytes_out?: Maybe;
+}
+
export interface NetworkTopNFlowData {
edges: NetworkTopNFlowEdges[];
@@ -1479,7 +1543,7 @@ export interface NetworkTopNFlowItem {
destination?: Maybe;
- network?: Maybe;
+ network?: Maybe;
}
export interface TopNFlowItemSource {
@@ -1502,12 +1566,6 @@ export interface AutonomousSystemItem {
number?: Maybe;
}
-export interface GeoItem {
- geo?: Maybe;
-
- flowTarget?: Maybe;
-}
-
export interface TopNFlowItemDestination {
autonomous_system?: Maybe;
@@ -1522,12 +1580,6 @@ export interface TopNFlowItemDestination {
source_ips?: Maybe;
}
-export interface TopNFlowNetworkEcsField {
- bytes_in?: Maybe;
-
- bytes_out?: Maybe;
-}
-
export interface NetworkDnsData {
edges: NetworkDnsEdges[];
@@ -2061,6 +2113,23 @@ export interface KpiHostDetailsSourceArgs {
defaultIndex: string[];
}
+export interface NetworkTopCountriesSourceArgs {
+ id?: Maybe;
+
+ filterQuery?: Maybe;
+
+ ip?: Maybe;
+
+ flowTarget: FlowTargetSourceDest;
+
+ pagination: PaginationInputPaginated;
+
+ sort: NetworkTopTablesSortField;
+
+ timerange: TimerangeInput;
+
+ defaultIndex: string[];
+}
export interface NetworkTopNFlowSourceArgs {
id?: Maybe;
@@ -2072,7 +2141,7 @@ export interface NetworkTopNFlowSourceArgs {
pagination: PaginationInputPaginated;
- sort: NetworkTopNFlowSortField;
+ sort: NetworkTopTablesSortField;
timerange: TimerangeInput;
@@ -3071,13 +3140,127 @@ export namespace GetNetworkDnsQuery {
};
}
+export namespace GetNetworkTopCountriesQuery {
+ export type Variables = {
+ sourceId: string;
+ ip?: Maybe;
+ filterQuery?: Maybe;
+ pagination: PaginationInputPaginated;
+ sort: NetworkTopTablesSortField;
+ flowTarget: FlowTargetSourceDest;
+ timerange: TimerangeInput;
+ defaultIndex: string[];
+ inspect: boolean;
+ };
+
+ export type Query = {
+ __typename?: 'Query';
+
+ source: Source;
+ };
+
+ export type Source = {
+ __typename?: 'Source';
+
+ id: string;
+
+ NetworkTopCountries: NetworkTopCountries;
+ };
+
+ export type NetworkTopCountries = {
+ __typename?: 'NetworkTopCountriesData';
+
+ totalCount: number;
+
+ edges: Edges[];
+
+ pageInfo: PageInfo;
+
+ inspect: Maybe;
+ };
+
+ export type Edges = {
+ __typename?: 'NetworkTopCountriesEdges';
+
+ node: Node;
+
+ cursor: Cursor;
+ };
+
+ export type Node = {
+ __typename?: 'NetworkTopCountriesItem';
+
+ source: Maybe<_Source>;
+
+ destination: Maybe;
+
+ network: Maybe;
+ };
+
+ export type _Source = {
+ __typename?: 'TopCountriesItemSource';
+
+ country: Maybe;
+
+ destination_ips: Maybe;
+
+ flows: Maybe;
+
+ source_ips: Maybe;
+ };
+
+ export type Destination = {
+ __typename?: 'TopCountriesItemDestination';
+
+ country: Maybe;
+
+ destination_ips: Maybe;
+
+ flows: Maybe;
+
+ source_ips: Maybe;
+ };
+
+ export type Network = {
+ __typename?: 'TopNetworkTablesEcsField';
+
+ bytes_in: Maybe;
+
+ bytes_out: Maybe;
+ };
+
+ export type Cursor = {
+ __typename?: 'CursorType';
+
+ value: Maybe;
+ };
+
+ export type PageInfo = {
+ __typename?: 'PageInfoPaginated';
+
+ activePage: number;
+
+ fakeTotalCount: number;
+
+ showMorePagesIndicator: boolean;
+ };
+
+ export type Inspect = {
+ __typename?: 'Inspect';
+
+ dsl: string[];
+
+ response: string[];
+ };
+}
+
export namespace GetNetworkTopNFlowQuery {
export type Variables = {
sourceId: string;
ip?: Maybe;
filterQuery?: Maybe;
pagination: PaginationInputPaginated;
- sort: NetworkTopNFlowSortField;
+ sort: NetworkTopTablesSortField;
flowTarget: FlowTargetSourceDest;
timerange: TimerangeInput;
defaultIndex: string[];
@@ -3225,7 +3408,7 @@ export namespace GetNetworkTopNFlowQuery {
};
export type Network = {
- __typename?: 'TopNFlowNetworkEcsField';
+ __typename?: 'TopNetworkTablesEcsField';
bytes_in: Maybe;
diff --git a/x-pack/legacy/plugins/siem/public/mock/global_state.ts b/x-pack/legacy/plugins/siem/public/mock/global_state.ts
index 78315e0d3ddfb..ac6dfbf08ca95 100644
--- a/x-pack/legacy/plugins/siem/public/mock/global_state.ts
+++ b/x-pack/legacy/plugins/siem/public/mock/global_state.ts
@@ -10,7 +10,7 @@ import {
FlowTarget,
HostsFields,
NetworkDnsFields,
- NetworkTopNFlowFields,
+ NetworkTopTablesFields,
TlsFields,
UsersFields,
} from '../graphql/types';
@@ -65,15 +65,25 @@ export const mockGlobalState: State = {
network: {
page: {
queries: {
+ [networkModel.NetworkTableType.topCountriesDestination]: {
+ activePage: 0,
+ limit: 10,
+ topCountriesSort: { field: NetworkTopTablesFields.bytes_out, direction: Direction.desc },
+ },
+ [networkModel.NetworkTableType.topCountriesSource]: {
+ activePage: 0,
+ limit: 10,
+ topCountriesSort: { field: NetworkTopTablesFields.bytes_out, direction: Direction.desc },
+ },
[networkModel.NetworkTableType.topNFlowSource]: {
activePage: 0,
limit: 10,
- topNFlowSort: { field: NetworkTopNFlowFields.bytes_out, direction: Direction.desc },
+ topNFlowSort: { field: NetworkTopTablesFields.bytes_out, direction: Direction.desc },
},
[networkModel.NetworkTableType.topNFlowDestination]: {
activePage: 0,
limit: 10,
- topNFlowSort: { field: NetworkTopNFlowFields.bytes_out, direction: Direction.desc },
+ topNFlowSort: { field: NetworkTopTablesFields.bytes_out, direction: Direction.desc },
},
[networkModel.NetworkTableType.dns]: {
activePage: 0,
@@ -86,15 +96,25 @@ export const mockGlobalState: State = {
details: {
flowTarget: FlowTarget.source,
queries: {
+ [networkModel.IpDetailsTableType.topCountriesDestination]: {
+ activePage: 0,
+ limit: 10,
+ topCountriesSort: { field: NetworkTopTablesFields.bytes_out, direction: Direction.desc },
+ },
+ [networkModel.IpDetailsTableType.topCountriesSource]: {
+ activePage: 0,
+ limit: 10,
+ topCountriesSort: { field: NetworkTopTablesFields.bytes_out, direction: Direction.desc },
+ },
[networkModel.IpDetailsTableType.topNFlowSource]: {
activePage: 0,
limit: 10,
- topNFlowSort: { field: NetworkTopNFlowFields.bytes_out, direction: Direction.desc },
+ topNFlowSort: { field: NetworkTopTablesFields.bytes_out, direction: Direction.desc },
},
[networkModel.IpDetailsTableType.topNFlowDestination]: {
activePage: 0,
limit: 10,
- topNFlowSort: { field: NetworkTopNFlowFields.bytes_out, direction: Direction.desc },
+ topNFlowSort: { field: NetworkTopTablesFields.bytes_out, direction: Direction.desc },
},
[networkModel.IpDetailsTableType.tls]: {
activePage: 0,
diff --git a/x-pack/legacy/plugins/siem/public/pages/network/ip_details.tsx b/x-pack/legacy/plugins/siem/public/pages/network/ip_details.tsx
index 77364fa3a17b3..27d88e8475a65 100644
--- a/x-pack/legacy/plugins/siem/public/pages/network/ip_details.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/network/ip_details.tsx
@@ -40,6 +40,8 @@ import { setAbsoluteRangeDatePicker as dispatchAbsoluteRangeDatePicker } from '.
import { setIpDetailsTablesActivePageToZero as dispatchIpDetailsTablesActivePageToZero } from '../../store/network/actions';
import { SpyRoute } from '../../utils/route/spy_routes';
import { NetworkEmptyPage } from './network_empty_page';
+import { NetworkTopCountriesQuery } from '../../containers/network_top_countries';
+import { NetworkTopCountriesTable } from '../../components/page/network/network_top_countries_table';
import * as i18n from './translations';
import { IPDetailsComponentProps } from './types';
@@ -47,6 +49,7 @@ const TlsTableManage = manageQuery(TlsTable);
const UsersTableManage = manageQuery(UsersTable);
const IpOverviewManage = manageQuery(IpOverview);
const NetworkTopNFlowTableManage = manageQuery(NetworkTopNFlowTable);
+const NetworkTopCountriesTableManage = manageQuery(NetworkTopCountriesTable);
export const IPDetailsComponent = React.memo(
({
@@ -222,6 +225,94 @@ export const IPDetailsComponent = React.memo(
+
+
+
+ {({
+ id,
+ inspect,
+ isInspected,
+ loading,
+ loadPage,
+ networkTopCountries,
+ pageInfo,
+ refetch,
+ totalCount,
+ }) => (
+
+ )}
+
+
+
+
+
+ {({
+ id,
+ inspect,
+ isInspected,
+ loading,
+ loadPage,
+ networkTopCountries,
+ pageInfo,
+ refetch,
+ totalCount,
+ }) => (
+
+ )}
+
+
+
+
+
+
(
+
+ {({
+ id,
+ inspect,
+ isInspected,
+ loading,
+ loadPage,
+ networkTopCountries,
+ pageInfo,
+ refetch,
+ totalCount,
+ }) => (
+
+ )}
+
+);
+
+CountriesQueryTabBody.displayName = 'CountriesQueryTabBody';
diff --git a/x-pack/legacy/plugins/siem/public/pages/network/navigation/nav_tabs.tsx b/x-pack/legacy/plugins/siem/public/pages/network/navigation/nav_tabs.tsx
index c77eafe759752..d3a3feecc0d9d 100644
--- a/x-pack/legacy/plugins/siem/public/pages/network/navigation/nav_tabs.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/network/navigation/nav_tabs.tsx
@@ -19,6 +19,13 @@ export const navTabsNetwork = (hasMlUserPermissions: boolean): NetworkNavTab =>
disabled: false,
urlKey: 'network',
},
+ [NetworkRouteType.countries]: {
+ id: NetworkRouteType.countries,
+ name: i18n.NAVIGATION_COUNTRIES_TITLE,
+ href: getTabsOnNetworkUrl(NetworkRouteType.countries),
+ disabled: false,
+ urlKey: 'network',
+ },
[NetworkRouteType.dns]: {
id: NetworkRouteType.dns,
name: i18n.NAVIGATION_DNS_TITLE,
diff --git a/x-pack/legacy/plugins/siem/public/pages/network/navigation/network_routes.tsx b/x-pack/legacy/plugins/siem/public/pages/network/navigation/network_routes.tsx
index 0ed652804cc8e..cddd2d7aafed8 100644
--- a/x-pack/legacy/plugins/siem/public/pages/network/navigation/network_routes.tsx
+++ b/x-pack/legacy/plugins/siem/public/pages/network/navigation/network_routes.tsx
@@ -12,6 +12,7 @@ import { FlowTargetSourceDest } from '../../../graphql/types';
import { scoreIntervalToDateTime } from '../../../components/ml/score/score_interval_to_datetime';
import { IPsQueryTabBody } from './ips_query_tab_body';
+import { CountriesQueryTabBody } from './countries_query_tab_body';
import { AnomaliesQueryTabBody } from './anomalies_query_tab_body';
import { DnsQueryTabBody } from './dns_query_tab_body';
import { ConditionalFlexGroup } from './conditional_flex_group';
@@ -79,6 +80,20 @@ export const NetworkRoutes = ({
)}
/>
+ (
+
+
+
+
+
+
+
+
+
+ )}
+ />
}
diff --git a/x-pack/legacy/plugins/siem/public/pages/network/navigation/types.ts b/x-pack/legacy/plugins/siem/public/pages/network/navigation/types.ts
index bcdc0ef7aa790..3d36193b7ea12 100644
--- a/x-pack/legacy/plugins/siem/public/pages/network/navigation/types.ts
+++ b/x-pack/legacy/plugins/siem/public/pages/network/navigation/types.ts
@@ -41,7 +41,9 @@ export type NetworkRoutesProps = GlobalTimeArgs & {
setAbsoluteRangeDatePicker: SetAbsoluteRangeDatePicker;
};
-export type KeyNetworkNavTabWithoutMlPermission = NetworkRouteType.ips & NetworkRouteType.dns;
+export type KeyNetworkNavTabWithoutMlPermission = NetworkRouteType.countries &
+ NetworkRouteType.dns &
+ NetworkRouteType.ips;
type KeyNetworkNavTabWithMlPermission = KeyNetworkNavTabWithoutMlPermission &
NetworkRouteType.anomalies;
@@ -52,6 +54,7 @@ export type NetworkNavTab = Record;
export enum NetworkRouteType {
ips = 'ips',
+ countries = 'countries',
dns = 'dns',
anomalies = 'anomalies',
}
diff --git a/x-pack/legacy/plugins/siem/public/pages/network/navigation/utils.ts b/x-pack/legacy/plugins/siem/public/pages/network/navigation/utils.ts
index 9203c9d376db2..d6ad28757aee1 100644
--- a/x-pack/legacy/plugins/siem/public/pages/network/navigation/utils.ts
+++ b/x-pack/legacy/plugins/siem/public/pages/network/navigation/utils.ts
@@ -12,13 +12,14 @@ export const getNetworkRoutePath: GetNetworkRoutePath = (
hasMlUserPermission
) => {
if (capabilitiesFetched && !hasMlUserPermission) {
- return `${pagePath}/:tabName(${NetworkRouteType.ips}|${NetworkRouteType.dns})`;
+ return `${pagePath}/:tabName(${NetworkRouteType.ips}|${NetworkRouteType.dns}|${NetworkRouteType.countries})`;
}
return (
`${pagePath}/:tabName(` +
`${NetworkRouteType.ips}|` +
`${NetworkRouteType.dns}|` +
+ `${NetworkRouteType.countries}|` +
`${NetworkRouteType.anomalies})`
);
};
diff --git a/x-pack/legacy/plugins/siem/public/pages/network/translations.ts b/x-pack/legacy/plugins/siem/public/pages/network/translations.ts
index ad60e3df86b9a..14a74f5666f0e 100644
--- a/x-pack/legacy/plugins/siem/public/pages/network/translations.ts
+++ b/x-pack/legacy/plugins/siem/public/pages/network/translations.ts
@@ -27,16 +27,23 @@ export const EMPTY_ACTION_SECONDARY = i18n.translate('xpack.siem.network.emptyAc
defaultMessage: 'Go to documentation',
});
-export const NAVIGATION_IPS_TITLE = i18n.translate('xpack.siem.netowork.navigation.ipsTitle', {
+export const NAVIGATION_IPS_TITLE = i18n.translate('xpack.siem.network.navigation.ipsTitle', {
defaultMessage: 'IPs',
});
-export const NAVIGATION_DNS_TITLE = i18n.translate('xpack.siem.netowork.navigation.dnsTitle', {
+export const NAVIGATION_COUNTRIES_TITLE = i18n.translate(
+ 'xpack.siem.network.navigation.countriesTitle',
+ {
+ defaultMessage: 'Top Countries',
+ }
+);
+
+export const NAVIGATION_DNS_TITLE = i18n.translate('xpack.siem.network.navigation.dnsTitle', {
defaultMessage: 'DNS',
});
export const NAVIGATION_ANOMALIES_TITLE = i18n.translate(
- 'xpack.siem.netowork.navigation.anomaliesTitle',
+ 'xpack.siem.network.navigation.anomaliesTitle',
{
defaultMessage: 'Anomalies',
}
diff --git a/x-pack/legacy/plugins/siem/public/store/network/actions.ts b/x-pack/legacy/plugins/siem/public/store/network/actions.ts
index 17d0dd2c5695c..3688e257344fa 100644
--- a/x-pack/legacy/plugins/siem/public/store/network/actions.ts
+++ b/x-pack/legacy/plugins/siem/public/store/network/actions.ts
@@ -9,7 +9,7 @@ import actionCreatorFactory from 'typescript-fsa';
import {
FlowTarget,
NetworkDnsSortField,
- NetworkTopNFlowSortField,
+ NetworkTopTablesSortField,
TlsSortField,
UsersSortField,
} from '../../graphql/types';
@@ -57,12 +57,23 @@ export const updateTopNFlowLimit = actionCreator<{
}>('UPDATE_TOP_N_FLOW_LIMIT');
export const updateTopNFlowSort = actionCreator<{
- topNFlowSort: NetworkTopNFlowSortField;
+ topNFlowSort: NetworkTopTablesSortField;
networkType: networkModel.NetworkType;
tableType: networkModel.TopNTableType;
}>('UPDATE_TOP_N_FLOW_SORT');
-// IP Details Actions
+export const updateTopCountriesLimit = actionCreator<{
+ limit: number;
+ networkType: networkModel.NetworkType;
+ tableType: networkModel.TopCountriesTableType;
+}>('UPDATE_TOP_COUNTRIES_LIMIT');
+
+export const updateTopCountriesSort = actionCreator<{
+ topCountriesSort: NetworkTopTablesSortField;
+ networkType: networkModel.NetworkType;
+ tableType: networkModel.TopCountriesTableType;
+}>('UPDATE_TOP_COUNTRIES_SORT');
+
export const updateIpDetailsFlowTarget = actionCreator<{
flowTarget: FlowTarget;
}>('UPDATE_IP_DETAILS_TARGET');
diff --git a/x-pack/legacy/plugins/siem/public/store/network/helpers.test.ts b/x-pack/legacy/plugins/siem/public/store/network/helpers.test.ts
index f76939c5d3e3d..31db0cea80dc9 100644
--- a/x-pack/legacy/plugins/siem/public/store/network/helpers.test.ts
+++ b/x-pack/legacy/plugins/siem/public/store/network/helpers.test.ts
@@ -6,7 +6,7 @@
import {
Direction,
- NetworkTopNFlowFields,
+ NetworkTopTablesFields,
NetworkDnsFields,
TlsFields,
UsersFields,
@@ -19,11 +19,27 @@ import { setNetworkQueriesActivePageToZero } from './helpers';
export const mockNetworkState: NetworkModel = {
page: {
queries: {
+ [NetworkTableType.topCountriesSource]: {
+ activePage: 7,
+ limit: DEFAULT_TABLE_LIMIT,
+ topCountriesSort: {
+ field: NetworkTopTablesFields.bytes_out,
+ direction: Direction.desc,
+ },
+ },
+ [NetworkTableType.topCountriesDestination]: {
+ activePage: 3,
+ limit: DEFAULT_TABLE_LIMIT,
+ topCountriesSort: {
+ field: NetworkTopTablesFields.bytes_out,
+ direction: Direction.desc,
+ },
+ },
[NetworkTableType.topNFlowSource]: {
activePage: 7,
limit: DEFAULT_TABLE_LIMIT,
topNFlowSort: {
- field: NetworkTopNFlowFields.bytes_out,
+ field: NetworkTopTablesFields.bytes_out,
direction: Direction.desc,
},
},
@@ -31,7 +47,7 @@ export const mockNetworkState: NetworkModel = {
activePage: 3,
limit: DEFAULT_TABLE_LIMIT,
topNFlowSort: {
- field: NetworkTopNFlowFields.bytes_out,
+ field: NetworkTopTablesFields.bytes_out,
direction: Direction.desc,
},
},
@@ -48,11 +64,27 @@ export const mockNetworkState: NetworkModel = {
},
details: {
queries: {
+ [IpDetailsTableType.topCountriesSource]: {
+ activePage: 7,
+ limit: DEFAULT_TABLE_LIMIT,
+ topCountriesSort: {
+ field: NetworkTopTablesFields.bytes_out,
+ direction: Direction.desc,
+ },
+ },
+ [IpDetailsTableType.topCountriesDestination]: {
+ activePage: 3,
+ limit: DEFAULT_TABLE_LIMIT,
+ topCountriesSort: {
+ field: NetworkTopTablesFields.bytes_out,
+ direction: Direction.desc,
+ },
+ },
[IpDetailsTableType.topNFlowSource]: {
activePage: 7,
limit: DEFAULT_TABLE_LIMIT,
topNFlowSort: {
- field: NetworkTopNFlowFields.bytes_out,
+ field: NetworkTopTablesFields.bytes_out,
direction: Direction.desc,
},
},
@@ -60,7 +92,7 @@ export const mockNetworkState: NetworkModel = {
activePage: 3,
limit: DEFAULT_TABLE_LIMIT,
topNFlowSort: {
- field: NetworkTopNFlowFields.bytes_out,
+ field: NetworkTopTablesFields.bytes_out,
direction: Direction.desc,
},
},
@@ -87,7 +119,7 @@ export const mockNetworkState: NetworkModel = {
describe('Network redux store', () => {
describe('#setNetworkQueriesActivePageToZero', () => {
- test('set activePage to zero for all queries in hosts page ', () => {
+ test('set activePage to zero for all queries in network page', () => {
expect(setNetworkQueriesActivePageToZero(mockNetworkState, NetworkType.page)).toEqual({
[NetworkTableType.topNFlowSource]: {
activePage: 0,
@@ -105,10 +137,26 @@ describe('Network redux store', () => {
dnsSortField: { field: 'uniqueDomains', direction: 'desc' },
isPtrIncluded: false,
},
+ [NetworkTableType.topCountriesDestination]: {
+ activePage: 0,
+ limit: 10,
+ topCountriesSort: {
+ direction: 'desc',
+ field: 'bytes_out',
+ },
+ },
+ [NetworkTableType.topCountriesSource]: {
+ activePage: 0,
+ limit: 10,
+ topCountriesSort: {
+ direction: 'desc',
+ field: 'bytes_out',
+ },
+ },
});
});
- test('set activePage to zero for all queries in host details ', () => {
+ test('set activePage to zero for all queries in ip details ', () => {
expect(setNetworkQueriesActivePageToZero(mockNetworkState, NetworkType.details)).toEqual({
[IpDetailsTableType.topNFlowSource]: {
activePage: 0,
@@ -120,6 +168,22 @@ describe('Network redux store', () => {
limit: 10,
topNFlowSort: { field: 'bytes_out', direction: 'desc' },
},
+ [IpDetailsTableType.topCountriesDestination]: {
+ activePage: 0,
+ limit: 10,
+ topCountriesSort: {
+ direction: 'desc',
+ field: 'bytes_out',
+ },
+ },
+ [IpDetailsTableType.topCountriesSource]: {
+ activePage: 0,
+ limit: 10,
+ topCountriesSort: {
+ direction: 'desc',
+ field: 'bytes_out',
+ },
+ },
[IpDetailsTableType.tls]: {
activePage: 0,
limit: 10,
diff --git a/x-pack/legacy/plugins/siem/public/store/network/helpers.ts b/x-pack/legacy/plugins/siem/public/store/network/helpers.ts
index b9876457625fb..60f4d6d1b4106 100644
--- a/x-pack/legacy/plugins/siem/public/store/network/helpers.ts
+++ b/x-pack/legacy/plugins/siem/public/store/network/helpers.ts
@@ -16,6 +16,14 @@ import { DEFAULT_TABLE_ACTIVE_PAGE } from '../constants';
export const setNetworkPageQueriesActivePageToZero = (state: NetworkModel): NetworkQueries => ({
...state.page.queries,
+ [NetworkTableType.topCountriesSource]: {
+ ...state.page.queries[NetworkTableType.topCountriesSource],
+ activePage: DEFAULT_TABLE_ACTIVE_PAGE,
+ },
+ [NetworkTableType.topCountriesDestination]: {
+ ...state.page.queries[NetworkTableType.topCountriesDestination],
+ activePage: DEFAULT_TABLE_ACTIVE_PAGE,
+ },
[NetworkTableType.topNFlowSource]: {
...state.page.queries[NetworkTableType.topNFlowSource],
activePage: DEFAULT_TABLE_ACTIVE_PAGE,
@@ -34,6 +42,14 @@ export const setNetworkDetailsQueriesActivePageToZero = (
state: NetworkModel
): IpOverviewQueries => ({
...state.details.queries,
+ [IpDetailsTableType.topCountriesSource]: {
+ ...state.details.queries[IpDetailsTableType.topCountriesSource],
+ activePage: DEFAULT_TABLE_ACTIVE_PAGE,
+ },
+ [IpDetailsTableType.topCountriesDestination]: {
+ ...state.details.queries[IpDetailsTableType.topCountriesDestination],
+ activePage: DEFAULT_TABLE_ACTIVE_PAGE,
+ },
[IpDetailsTableType.topNFlowSource]: {
...state.details.queries[IpDetailsTableType.topNFlowSource],
activePage: DEFAULT_TABLE_ACTIVE_PAGE,
diff --git a/x-pack/legacy/plugins/siem/public/store/network/model.ts b/x-pack/legacy/plugins/siem/public/store/network/model.ts
index deaca981b1e0d..294177bd426b2 100644
--- a/x-pack/legacy/plugins/siem/public/store/network/model.ts
+++ b/x-pack/legacy/plugins/siem/public/store/network/model.ts
@@ -7,7 +7,7 @@
import {
FlowTarget,
NetworkDnsSortField,
- NetworkTopNFlowSortField,
+ NetworkTopTablesSortField,
TlsSortField,
UsersSortField,
} from '../../graphql/types';
@@ -19,20 +19,30 @@ export enum NetworkType {
export enum NetworkTableType {
dns = 'dns',
- topNFlowSource = 'topNFlowSource',
+ topCountriesDestination = 'topCountriesDestination',
+ topCountriesSource = 'topCountriesSource',
topNFlowDestination = 'topNFlowDestination',
+ topNFlowSource = 'topNFlowSource',
}
export type TopNTableType =
- | NetworkTableType.topNFlowDestination
- | NetworkTableType.topNFlowSource
| IpDetailsTableType.topNFlowDestination
- | IpDetailsTableType.topNFlowSource;
+ | IpDetailsTableType.topNFlowSource
+ | NetworkTableType.topNFlowDestination
+ | NetworkTableType.topNFlowSource;
+
+export type TopCountriesTableType =
+ | IpDetailsTableType.topCountriesDestination
+ | IpDetailsTableType.topCountriesSource
+ | NetworkTableType.topCountriesDestination
+ | NetworkTableType.topCountriesSource;
export enum IpDetailsTableType {
- topNFlowSource = 'topNFlowSourceIp',
- topNFlowDestination = 'topNFlowDestinationIp',
tls = 'tls',
+ topCountriesDestination = 'topCountriesDestinationIp',
+ topCountriesSource = 'topCountriesSourceIp',
+ topNFlowDestination = 'topNFlowDestinationIp',
+ topNFlowSource = 'topNFlowSourceIp',
users = 'users',
}
@@ -43,7 +53,11 @@ export interface BasicQueryPaginated {
// Network Page Models
export interface TopNFlowQuery extends BasicQueryPaginated {
- topNFlowSort: NetworkTopNFlowSortField;
+ topNFlowSort: NetworkTopTablesSortField;
+}
+
+export interface TopCountriesQuery extends BasicQueryPaginated {
+ topCountriesSort: NetworkTopTablesSortField;
}
export interface DnsQuery extends BasicQueryPaginated {
@@ -53,8 +67,10 @@ export interface DnsQuery extends BasicQueryPaginated {
export interface NetworkQueries {
[NetworkTableType.dns]: DnsQuery;
- [NetworkTableType.topNFlowSource]: TopNFlowQuery;
+ [NetworkTableType.topCountriesDestination]: TopCountriesQuery;
+ [NetworkTableType.topCountriesSource]: TopCountriesQuery;
[NetworkTableType.topNFlowDestination]: TopNFlowQuery;
+ [NetworkTableType.topNFlowSource]: TopNFlowQuery;
}
export interface NetworkPageModel {
@@ -72,9 +88,11 @@ export interface UsersQuery extends BasicQueryPaginated {
}
export interface IpOverviewQueries {
- [IpDetailsTableType.topNFlowSource]: TopNFlowQuery;
- [IpDetailsTableType.topNFlowDestination]: TopNFlowQuery;
[IpDetailsTableType.tls]: TlsQuery;
+ [IpDetailsTableType.topCountriesDestination]: TopCountriesQuery;
+ [IpDetailsTableType.topCountriesSource]: TopCountriesQuery;
+ [IpDetailsTableType.topNFlowDestination]: TopNFlowQuery;
+ [IpDetailsTableType.topNFlowSource]: TopNFlowQuery;
[IpDetailsTableType.users]: UsersQuery;
}
diff --git a/x-pack/legacy/plugins/siem/public/store/network/reducer.ts b/x-pack/legacy/plugins/siem/public/store/network/reducer.ts
index 74281bc2a4a5a..6a7c014707cbb 100644
--- a/x-pack/legacy/plugins/siem/public/store/network/reducer.ts
+++ b/x-pack/legacy/plugins/siem/public/store/network/reducer.ts
@@ -10,7 +10,7 @@ import {
Direction,
FlowTarget,
NetworkDnsFields,
- NetworkTopNFlowFields,
+ NetworkTopTablesFields,
TlsFields,
UsersFields,
} from '../../graphql/types';
@@ -24,6 +24,8 @@ import {
updateIpDetailsTableActivePage,
updateIsPtrIncluded,
updateNetworkPageTableActivePage,
+ updateTopCountriesLimit,
+ updateTopCountriesSort,
updateTlsLimit,
updateTlsSort,
updateTopNFlowLimit,
@@ -46,7 +48,7 @@ export const initialNetworkState: NetworkState = {
activePage: DEFAULT_TABLE_ACTIVE_PAGE,
limit: DEFAULT_TABLE_LIMIT,
topNFlowSort: {
- field: NetworkTopNFlowFields.bytes_out,
+ field: NetworkTopTablesFields.bytes_out,
direction: Direction.desc,
},
},
@@ -54,7 +56,7 @@ export const initialNetworkState: NetworkState = {
activePage: DEFAULT_TABLE_ACTIVE_PAGE,
limit: DEFAULT_TABLE_LIMIT,
topNFlowSort: {
- field: NetworkTopNFlowFields.bytes_out,
+ field: NetworkTopTablesFields.bytes_out,
direction: Direction.desc,
},
},
@@ -67,15 +69,47 @@ export const initialNetworkState: NetworkState = {
},
isPtrIncluded: false,
},
+ [NetworkTableType.topCountriesSource]: {
+ activePage: DEFAULT_TABLE_ACTIVE_PAGE,
+ limit: DEFAULT_TABLE_LIMIT,
+ topCountriesSort: {
+ field: NetworkTopTablesFields.bytes_out,
+ direction: Direction.desc,
+ },
+ },
+ [NetworkTableType.topCountriesDestination]: {
+ activePage: DEFAULT_TABLE_ACTIVE_PAGE,
+ limit: DEFAULT_TABLE_LIMIT,
+ topCountriesSort: {
+ field: NetworkTopTablesFields.bytes_out,
+ direction: Direction.desc,
+ },
+ },
},
},
details: {
queries: {
+ [IpDetailsTableType.topCountriesSource]: {
+ activePage: DEFAULT_TABLE_ACTIVE_PAGE,
+ limit: DEFAULT_TABLE_LIMIT,
+ topCountriesSort: {
+ field: NetworkTopTablesFields.bytes_out,
+ direction: Direction.desc,
+ },
+ },
+ [IpDetailsTableType.topCountriesDestination]: {
+ activePage: DEFAULT_TABLE_ACTIVE_PAGE,
+ limit: DEFAULT_TABLE_LIMIT,
+ topCountriesSort: {
+ field: NetworkTopTablesFields.bytes_out,
+ direction: Direction.desc,
+ },
+ },
[IpDetailsTableType.topNFlowSource]: {
activePage: DEFAULT_TABLE_ACTIVE_PAGE,
limit: DEFAULT_TABLE_LIMIT,
topNFlowSort: {
- field: NetworkTopNFlowFields.bytes_out,
+ field: NetworkTopTablesFields.bytes_out,
direction: Direction.desc,
},
},
@@ -83,7 +117,7 @@ export const initialNetworkState: NetworkState = {
activePage: DEFAULT_TABLE_ACTIVE_PAGE,
limit: DEFAULT_TABLE_LIMIT,
topNFlowSort: {
- field: NetworkTopNFlowFields.bytes_out,
+ field: NetworkTopTablesFields.bytes_out,
direction: Direction.desc,
},
},
@@ -263,6 +297,84 @@ export const networkReducer = reducerWithInitialState(initialNetworkState)
}
return state;
})
+ .case(updateTopCountriesLimit, (state, { limit, networkType, tableType }) => {
+ if (
+ networkType === NetworkType.page &&
+ (tableType === NetworkTableType.topCountriesSource ||
+ tableType === NetworkTableType.topCountriesDestination)
+ ) {
+ return {
+ ...state,
+ [networkType]: {
+ ...state[networkType],
+ queries: {
+ ...state[networkType].queries,
+ [tableType]: {
+ ...state[networkType].queries[tableType],
+ limit,
+ },
+ },
+ },
+ };
+ } else if (
+ tableType === IpDetailsTableType.topCountriesDestination ||
+ tableType === IpDetailsTableType.topCountriesSource
+ ) {
+ return {
+ ...state,
+ [NetworkType.details]: {
+ ...state[NetworkType.details],
+ queries: {
+ ...state[NetworkType.details].queries,
+ [tableType]: {
+ ...state[NetworkType.details].queries[tableType],
+ limit,
+ },
+ },
+ },
+ };
+ }
+ return state;
+ })
+ .case(updateTopCountriesSort, (state, { topCountriesSort, networkType, tableType }) => {
+ if (
+ networkType === NetworkType.page &&
+ (tableType === NetworkTableType.topCountriesSource ||
+ tableType === NetworkTableType.topCountriesDestination)
+ ) {
+ return {
+ ...state,
+ [networkType]: {
+ ...state[networkType],
+ queries: {
+ ...state[networkType].queries,
+ [tableType]: {
+ ...state[networkType].queries[tableType],
+ topCountriesSort,
+ },
+ },
+ },
+ };
+ } else if (
+ tableType === IpDetailsTableType.topCountriesDestination ||
+ tableType === IpDetailsTableType.topCountriesSource
+ ) {
+ return {
+ ...state,
+ [NetworkType.details]: {
+ ...state[NetworkType.details],
+ queries: {
+ ...state[NetworkType.details].queries,
+ [tableType]: {
+ ...state[NetworkType.details].queries[tableType],
+ topCountriesSort,
+ },
+ },
+ },
+ };
+ }
+ return state;
+ })
.case(updateIpDetailsFlowTarget, (state, { flowTarget }) => ({
...state,
[NetworkType.details]: {
diff --git a/x-pack/legacy/plugins/siem/public/store/network/selectors.ts b/x-pack/legacy/plugins/siem/public/store/network/selectors.ts
index 9987d4d4044b3..8f86cad3da2e2 100644
--- a/x-pack/legacy/plugins/siem/public/store/network/selectors.ts
+++ b/x-pack/legacy/plugins/siem/public/store/network/selectors.ts
@@ -23,8 +23,10 @@ export const dnsSelector = () =>
);
export enum NetworkTableType {
dns = 'dns',
- topNFlowSource = 'topNFlowSource',
+ topCountriesDestination = 'topCountriesDestination',
+ topCountriesSource = 'topCountriesSource',
topNFlowDestination = 'topNFlowDestination',
+ topNFlowSource = 'topNFlowSource',
}
export const topNFlowSelector = (flowTarget: FlowTargetSourceDest, networkType: NetworkType) => {
if (networkType === NetworkType.page) {
@@ -45,6 +47,28 @@ export const topNFlowSelector = (flowTarget: FlowTargetSourceDest, networkType:
);
};
+export const topCountriesSelector = (
+ flowTarget: FlowTargetSourceDest,
+ networkType: NetworkType
+) => {
+ if (networkType === NetworkType.page) {
+ return createSelector(
+ selectNetworkPage,
+ network =>
+ flowTarget === FlowTargetSourceDest.source
+ ? network.queries[NetworkTableType.topCountriesSource]
+ : network.queries[NetworkTableType.topCountriesDestination]
+ );
+ }
+ return createSelector(
+ selectNetworkDetails,
+ network =>
+ flowTarget === FlowTargetSourceDest.source
+ ? network.queries[IpDetailsTableType.topCountriesSource]
+ : network.queries[IpDetailsTableType.topCountriesDestination]
+ );
+};
+
// IP Details Selectors
export const ipDetailsFlowTargetSelector = () =>
createSelector(
diff --git a/x-pack/legacy/plugins/siem/server/graphql/network/resolvers.ts b/x-pack/legacy/plugins/siem/server/graphql/network/resolvers.ts
index 23a8d4694ccae..7ce88ba4880be 100644
--- a/x-pack/legacy/plugins/siem/server/graphql/network/resolvers.ts
+++ b/x-pack/legacy/plugins/siem/server/graphql/network/resolvers.ts
@@ -10,6 +10,11 @@ import { Network } from '../../lib/network';
import { createOptionsPaginated } from '../../utils/build_query/create_options';
import { QuerySourceResolver } from '../sources/resolvers';
+type QueryNetworkTopCountriesResolver = ChildResolverOf<
+ AppResolverOf,
+ QuerySourceResolver
+>;
+
type QueryNetworkTopNFlowResolver = ChildResolverOf<
AppResolverOf,
QuerySourceResolver
@@ -28,11 +33,21 @@ export const createNetworkResolvers = (
libs: NetworkResolversDeps
): {
Source: {
+ NetworkTopCountries: QueryNetworkTopCountriesResolver;
NetworkTopNFlow: QueryNetworkTopNFlowResolver;
NetworkDns: QueryDnsResolver;
};
} => ({
Source: {
+ async NetworkTopCountries(source, args, { req }, info) {
+ const options = {
+ ...createOptionsPaginated(source, args, info),
+ flowTarget: args.flowTarget,
+ networkTopCountriesSort: args.sort,
+ ip: args.ip,
+ };
+ return libs.network.getNetworkTopCountries(req, options);
+ },
async NetworkTopNFlow(source, args, { req }, info) {
const options = {
...createOptionsPaginated(source, args, info),
diff --git a/x-pack/legacy/plugins/siem/server/graphql/network/schema.gql.ts b/x-pack/legacy/plugins/siem/server/graphql/network/schema.gql.ts
index acd19b6efc0ed..36b57ec9368ab 100644
--- a/x-pack/legacy/plugins/siem/server/graphql/network/schema.gql.ts
+++ b/x-pack/legacy/plugins/siem/server/graphql/network/schema.gql.ts
@@ -18,7 +18,7 @@ export const networkSchema = gql`
unknown
}
- type TopNFlowNetworkEcsField {
+ type TopNetworkTablesEcsField {
bytes_in: Float
bytes_out: Float
}
@@ -33,6 +33,41 @@ export const networkSchema = gql`
number: Float
}
+ type TopCountriesItemSource {
+ country: String
+ destination_ips: Float
+ flows: Float
+ location: GeoItem
+ source_ips: Float
+ }
+
+ type TopCountriesItemDestination {
+ country: String
+ destination_ips: Float
+ flows: Float
+ location: GeoItem
+ source_ips: Float
+ }
+
+ type NetworkTopCountriesItem {
+ _id: String
+ source: TopCountriesItemSource
+ destination: TopCountriesItemDestination
+ network: TopNetworkTablesEcsField
+ }
+
+ type NetworkTopCountriesEdges {
+ node: NetworkTopCountriesItem!
+ cursor: CursorType!
+ }
+
+ type NetworkTopCountriesData {
+ edges: [NetworkTopCountriesEdges!]!
+ totalCount: Float!
+ pageInfo: PageInfoPaginated!
+ inspect: Inspect
+ }
+
type TopNFlowItemSource {
autonomous_system: AutonomousSystemItem
domain: [String!]
@@ -51,7 +86,7 @@ export const networkSchema = gql`
source_ips: Float
}
- enum NetworkTopNFlowFields {
+ enum NetworkTopTablesFields {
bytes_in
bytes_out
flows
@@ -59,8 +94,8 @@ export const networkSchema = gql`
source_ips
}
- input NetworkTopNFlowSortField {
- field: NetworkTopNFlowFields!
+ input NetworkTopTablesSortField {
+ field: NetworkTopTablesFields!
direction: Direction!
}
@@ -68,7 +103,7 @@ export const networkSchema = gql`
_id: String
source: TopNFlowItemSource
destination: TopNFlowItemDestination
- network: TopNFlowNetworkEcsField
+ network: TopNetworkTablesEcsField
}
type NetworkTopNFlowEdges {
@@ -118,14 +153,23 @@ export const networkSchema = gql`
}
extend type Source {
- "Gets Hosts based on timerange and specified criteria, or all events in the timerange if no criteria is specified"
+ NetworkTopCountries(
+ id: String
+ filterQuery: String
+ ip: String
+ flowTarget: FlowTargetSourceDest!
+ pagination: PaginationInputPaginated!
+ sort: NetworkTopTablesSortField!
+ timerange: TimerangeInput!
+ defaultIndex: [String!]!
+ ): NetworkTopCountriesData!
NetworkTopNFlow(
id: String
filterQuery: String
ip: String
flowTarget: FlowTargetSourceDest!
pagination: PaginationInputPaginated!
- sort: NetworkTopNFlowSortField!
+ sort: NetworkTopTablesSortField!
timerange: TimerangeInput!
defaultIndex: [String!]!
): NetworkTopNFlowData!
diff --git a/x-pack/legacy/plugins/siem/server/graphql/types.ts b/x-pack/legacy/plugins/siem/server/graphql/types.ts
index 8505d3efc4341..bce1f0139c49e 100644
--- a/x-pack/legacy/plugins/siem/server/graphql/types.ts
+++ b/x-pack/legacy/plugins/siem/server/graphql/types.ts
@@ -81,8 +81,8 @@ export interface UsersSortField {
direction: Direction;
}
-export interface NetworkTopNFlowSortField {
- field: NetworkTopNFlowFields;
+export interface NetworkTopTablesSortField {
+ field: NetworkTopTablesFields;
direction: Direction;
}
@@ -262,7 +262,7 @@ export enum FlowTargetSourceDest {
source = 'source',
}
-export enum NetworkTopNFlowFields {
+export enum NetworkTopTablesFields {
bytes_in = 'bytes_in',
bytes_out = 'bytes_out',
flows = 'flows',
@@ -428,7 +428,9 @@ export interface Source {
KpiHosts: KpiHostsData;
KpiHostDetails: KpiHostDetailsData;
- /** Gets Hosts based on timerange and specified criteria, or all events in the timerange if no criteria is specified */
+
+ NetworkTopCountries: NetworkTopCountriesData;
+
NetworkTopNFlow: NetworkTopNFlowData;
NetworkDns: NetworkDnsData;
@@ -1458,6 +1460,68 @@ export interface KpiHostDetailsData {
inspect?: Maybe;
}
+export interface NetworkTopCountriesData {
+ edges: NetworkTopCountriesEdges[];
+
+ totalCount: number;
+
+ pageInfo: PageInfoPaginated;
+
+ inspect?: Maybe;
+}
+
+export interface NetworkTopCountriesEdges {
+ node: NetworkTopCountriesItem;
+
+ cursor: CursorType;
+}
+
+export interface NetworkTopCountriesItem {
+ _id?: Maybe;
+
+ source?: Maybe;
+
+ destination?: Maybe;
+
+ network?: Maybe;
+}
+
+export interface TopCountriesItemSource {
+ country?: Maybe;
+
+ destination_ips?: Maybe;
+
+ flows?: Maybe;
+
+ location?: Maybe;
+
+ source_ips?: Maybe;
+}
+
+export interface GeoItem {
+ geo?: Maybe;
+
+ flowTarget?: Maybe;
+}
+
+export interface TopCountriesItemDestination {
+ country?: Maybe;
+
+ destination_ips?: Maybe;
+
+ flows?: Maybe;
+
+ location?: Maybe;
+
+ source_ips?: Maybe;
+}
+
+export interface TopNetworkTablesEcsField {
+ bytes_in?: Maybe;
+
+ bytes_out?: Maybe;
+}
+
export interface NetworkTopNFlowData {
edges: NetworkTopNFlowEdges[];
@@ -1481,7 +1545,7 @@ export interface NetworkTopNFlowItem {
destination?: Maybe;
- network?: Maybe;
+ network?: Maybe;
}
export interface TopNFlowItemSource {
@@ -1504,12 +1568,6 @@ export interface AutonomousSystemItem {
number?: Maybe;
}
-export interface GeoItem {
- geo?: Maybe;
-
- flowTarget?: Maybe;
-}
-
export interface TopNFlowItemDestination {
autonomous_system?: Maybe;
@@ -1524,12 +1582,6 @@ export interface TopNFlowItemDestination {
source_ips?: Maybe;
}
-export interface TopNFlowNetworkEcsField {
- bytes_in?: Maybe;
-
- bytes_out?: Maybe;
-}
-
export interface NetworkDnsData {
edges: NetworkDnsEdges[];
@@ -2063,6 +2115,23 @@ export interface KpiHostDetailsSourceArgs {
defaultIndex: string[];
}
+export interface NetworkTopCountriesSourceArgs {
+ id?: Maybe;
+
+ filterQuery?: Maybe;
+
+ ip?: Maybe;
+
+ flowTarget: FlowTargetSourceDest;
+
+ pagination: PaginationInputPaginated;
+
+ sort: NetworkTopTablesSortField;
+
+ timerange: TimerangeInput;
+
+ defaultIndex: string[];
+}
export interface NetworkTopNFlowSourceArgs {
id?: Maybe;
@@ -2074,7 +2143,7 @@ export interface NetworkTopNFlowSourceArgs {
pagination: PaginationInputPaginated;
- sort: NetworkTopNFlowSortField;
+ sort: NetworkTopTablesSortField;
timerange: TimerangeInput;
@@ -2542,7 +2611,13 @@ export namespace SourceResolvers {
KpiHosts?: KpiHostsResolver;
KpiHostDetails?: KpiHostDetailsResolver;
- /** Gets Hosts based on timerange and specified criteria, or all events in the timerange if no criteria is specified */
+
+ NetworkTopCountries?: NetworkTopCountriesResolver<
+ NetworkTopCountriesData,
+ TypeParent,
+ TContext
+ >;
+
NetworkTopNFlow?: NetworkTopNFlowResolver;
NetworkDns?: NetworkDnsResolver;
@@ -2802,6 +2877,29 @@ export namespace SourceResolvers {
defaultIndex: string[];
}
+ export type NetworkTopCountriesResolver<
+ R = NetworkTopCountriesData,
+ Parent = Source,
+ TContext = SiemContext
+ > = Resolver;
+ export interface NetworkTopCountriesArgs {
+ id?: Maybe;
+
+ filterQuery?: Maybe;
+
+ ip?: Maybe;
+
+ flowTarget: FlowTargetSourceDest;
+
+ pagination: PaginationInputPaginated;
+
+ sort: NetworkTopTablesSortField;
+
+ timerange: TimerangeInput;
+
+ defaultIndex: string[];
+ }
+
export type NetworkTopNFlowResolver<
R = NetworkTopNFlowData,
Parent = Source,
@@ -2818,7 +2916,7 @@ export namespace SourceResolvers {
pagination: PaginationInputPaginated;
- sort: NetworkTopNFlowSortField;
+ sort: NetworkTopTablesSortField;
timerange: TimerangeInput;
@@ -6305,6 +6403,209 @@ export namespace KpiHostDetailsDataResolvers {
> = Resolver;
}
+export namespace NetworkTopCountriesDataResolvers {
+ export interface Resolvers {
+ edges?: EdgesResolver;
+
+ totalCount?: TotalCountResolver;
+
+ pageInfo?: PageInfoResolver;
+
+ inspect?: InspectResolver, TypeParent, TContext>;
+ }
+
+ export type EdgesResolver<
+ R = NetworkTopCountriesEdges[],
+ Parent = NetworkTopCountriesData,
+ TContext = SiemContext
+ > = Resolver;
+ export type TotalCountResolver<
+ R = number,
+ Parent = NetworkTopCountriesData,
+ TContext = SiemContext
+ > = Resolver;
+ export type PageInfoResolver<
+ R = PageInfoPaginated,
+ Parent = NetworkTopCountriesData,
+ TContext = SiemContext
+ > = Resolver;
+ export type InspectResolver<
+ R = Maybe,
+ Parent = NetworkTopCountriesData,
+ TContext = SiemContext
+ > = Resolver;
+}
+
+export namespace NetworkTopCountriesEdgesResolvers {
+ export interface Resolvers {
+ node?: NodeResolver;
+
+ cursor?: CursorResolver;
+ }
+
+ export type NodeResolver<
+ R = NetworkTopCountriesItem,
+ Parent = NetworkTopCountriesEdges,
+ TContext = SiemContext
+ > = Resolver;
+ export type CursorResolver<
+ R = CursorType,
+ Parent = NetworkTopCountriesEdges,
+ TContext = SiemContext
+ > = Resolver;
+}
+
+export namespace NetworkTopCountriesItemResolvers {
+ export interface Resolvers {
+ _id?: _IdResolver, TypeParent, TContext>;
+
+ source?: SourceResolver, TypeParent, TContext>;
+
+ destination?: DestinationResolver, TypeParent, TContext>;
+
+ network?: NetworkResolver, TypeParent, TContext>;
+ }
+
+ export type _IdResolver<
+ R = Maybe,
+ Parent = NetworkTopCountriesItem,
+ TContext = SiemContext
+ > = Resolver;
+ export type SourceResolver<
+ R = Maybe,
+ Parent = NetworkTopCountriesItem,
+ TContext = SiemContext
+ > = Resolver;
+ export type DestinationResolver<
+ R = Maybe,
+ Parent = NetworkTopCountriesItem,
+ TContext = SiemContext
+ > = Resolver;
+ export type NetworkResolver<
+ R = Maybe,
+ Parent = NetworkTopCountriesItem,
+ TContext = SiemContext
+ > = Resolver;
+}
+
+export namespace TopCountriesItemSourceResolvers {
+ export interface Resolvers {
+ country?: CountryResolver, TypeParent, TContext>;
+
+ destination_ips?: DestinationIpsResolver, TypeParent, TContext>;
+
+ flows?: FlowsResolver, TypeParent, TContext>;
+
+ location?: LocationResolver, TypeParent, TContext>;
+
+ source_ips?: SourceIpsResolver, TypeParent, TContext>;
+ }
+
+ export type CountryResolver<
+ R = Maybe,
+ Parent = TopCountriesItemSource,
+ TContext = SiemContext
+ > = Resolver;
+ export type DestinationIpsResolver<
+ R = Maybe,
+ Parent = TopCountriesItemSource,
+ TContext = SiemContext
+ > = Resolver;
+ export type FlowsResolver<
+ R = Maybe,
+ Parent = TopCountriesItemSource,
+ TContext = SiemContext
+ > = Resolver;
+ export type LocationResolver<
+ R = Maybe,
+ Parent = TopCountriesItemSource,
+ TContext = SiemContext
+ > = Resolver;
+ export type SourceIpsResolver<
+ R = Maybe,
+ Parent = TopCountriesItemSource,
+ TContext = SiemContext
+ > = Resolver;
+}
+
+export namespace GeoItemResolvers {
+ export interface Resolvers {
+ geo?: GeoResolver, TypeParent, TContext>;
+
+ flowTarget?: FlowTargetResolver, TypeParent, TContext>;
+ }
+
+ export type GeoResolver<
+ R = Maybe,
+ Parent = GeoItem,
+ TContext = SiemContext
+ > = Resolver;
+ export type FlowTargetResolver<
+ R = Maybe,
+ Parent = GeoItem,
+ TContext = SiemContext
+ > = Resolver;
+}
+
+export namespace TopCountriesItemDestinationResolvers {
+ export interface Resolvers {
+ country?: CountryResolver, TypeParent, TContext>;
+
+ destination_ips?: DestinationIpsResolver, TypeParent, TContext>;
+
+ flows?: FlowsResolver, TypeParent, TContext>;
+
+ location?: LocationResolver, TypeParent, TContext>;
+
+ source_ips?: SourceIpsResolver, TypeParent, TContext>;
+ }
+
+ export type CountryResolver<
+ R = Maybe,
+ Parent = TopCountriesItemDestination,
+ TContext = SiemContext
+ > = Resolver;
+ export type DestinationIpsResolver<
+ R = Maybe,
+ Parent = TopCountriesItemDestination,
+ TContext = SiemContext
+ > = Resolver;
+ export type FlowsResolver<
+ R = Maybe,
+ Parent = TopCountriesItemDestination,
+ TContext = SiemContext
+ > = Resolver;
+ export type LocationResolver<
+ R = Maybe,
+ Parent = TopCountriesItemDestination,
+ TContext = SiemContext
+ > = Resolver;
+ export type SourceIpsResolver<
+ R = Maybe,
+ Parent = TopCountriesItemDestination,
+ TContext = SiemContext
+ > = Resolver;
+}
+
+export namespace TopNetworkTablesEcsFieldResolvers {
+ export interface Resolvers {
+ bytes_in?: BytesInResolver, TypeParent, TContext>;
+
+ bytes_out?: BytesOutResolver, TypeParent, TContext>;
+ }
+
+ export type BytesInResolver<
+ R = Maybe,
+ Parent = TopNetworkTablesEcsField,
+ TContext = SiemContext
+ > = Resolver;
+ export type BytesOutResolver<
+ R = Maybe,
+ Parent = TopNetworkTablesEcsField,
+ TContext = SiemContext
+ > = Resolver;
+}
+
export namespace NetworkTopNFlowDataResolvers {
export interface Resolvers {
edges?: EdgesResolver;
@@ -6365,7 +6666,7 @@ export namespace NetworkTopNFlowItemResolvers {
destination?: DestinationResolver, TypeParent, TContext>;
- network?: NetworkResolver, TypeParent, TContext>;
+ network?: NetworkResolver, TypeParent, TContext>;
}
export type _IdResolver<
@@ -6384,7 +6685,7 @@ export namespace NetworkTopNFlowItemResolvers {
TContext = SiemContext
> = Resolver;
export type NetworkResolver<
- R = Maybe,
+ R = Maybe,
Parent = NetworkTopNFlowItem,
TContext = SiemContext
> = Resolver;
@@ -6456,25 +6757,6 @@ export namespace AutonomousSystemItemResolvers {
> = Resolver;
}
-export namespace GeoItemResolvers {
- export interface Resolvers {
- geo?: GeoResolver, TypeParent, TContext>;
-
- flowTarget?: FlowTargetResolver, TypeParent, TContext>;
- }
-
- export type GeoResolver<
- R = Maybe,
- Parent = GeoItem,
- TContext = SiemContext
- > = Resolver;
- export type FlowTargetResolver<
- R = Maybe,
- Parent = GeoItem,
- TContext = SiemContext
- > = Resolver;
-}
-
export namespace TopNFlowItemDestinationResolvers {
export interface Resolvers {
autonomous_system?: AutonomousSystemResolver, TypeParent, TContext>;
@@ -6522,25 +6804,6 @@ export namespace TopNFlowItemDestinationResolvers {
> = Resolver;
}
-export namespace TopNFlowNetworkEcsFieldResolvers {
- export interface Resolvers {
- bytes_in?: BytesInResolver, TypeParent, TContext>;
-
- bytes_out?: BytesOutResolver, TypeParent, TContext>;
- }
-
- export type BytesInResolver<
- R = Maybe,
- Parent = TopNFlowNetworkEcsField,
- TContext = SiemContext
- > = Resolver;
- export type BytesOutResolver<
- R = Maybe,
- Parent = TopNFlowNetworkEcsField,
- TContext = SiemContext
- > = Resolver;
-}
-
export namespace NetworkDnsDataResolvers {
export interface Resolvers {
edges?: EdgesResolver;
@@ -7922,14 +8185,19 @@ export type IResolvers = {
KpiHostsData?: KpiHostsDataResolvers.Resolvers;
KpiHostHistogramData?: KpiHostHistogramDataResolvers.Resolvers;
KpiHostDetailsData?: KpiHostDetailsDataResolvers.Resolvers;
+ NetworkTopCountriesData?: NetworkTopCountriesDataResolvers.Resolvers;
+ NetworkTopCountriesEdges?: NetworkTopCountriesEdgesResolvers.Resolvers;
+ NetworkTopCountriesItem?: NetworkTopCountriesItemResolvers.Resolvers;
+ TopCountriesItemSource?: TopCountriesItemSourceResolvers.Resolvers;
+ GeoItem?: GeoItemResolvers.Resolvers;
+ TopCountriesItemDestination?: TopCountriesItemDestinationResolvers.Resolvers;
+ TopNetworkTablesEcsField?: TopNetworkTablesEcsFieldResolvers.Resolvers;
NetworkTopNFlowData?: NetworkTopNFlowDataResolvers.Resolvers;
NetworkTopNFlowEdges?: NetworkTopNFlowEdgesResolvers.Resolvers;
NetworkTopNFlowItem?: NetworkTopNFlowItemResolvers.Resolvers;
TopNFlowItemSource?: TopNFlowItemSourceResolvers.Resolvers