NetQuestOMX

NetQuest’s products are high-capacity service nodes that help security teams access and analyze network traffic. Powerful packet and flow processing features assist security tools in detecting and mitigating security threats as cost effectively as possible.

Utilities · NetQuest OMX

Details

IDNetQuestOMX
ProviderNetQuest Corporation
CategoryUtilities
From Version6.10.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesAgentix XSIAM

README

NetQuest’s products are high-capacity service nodes that help security teams access and analyze network traffic. Powerful packet and flow processing features assist security tools in detecting and mitigating security threats as cost effectively as possible.
This integration was integrated and tested with version 3.7.5a of NetQuest OMX.

Configure NetQuest OMX in Cortex

Parameter Description Required
Server URL The IP of the 5G device using NetQuest OMX, formatted as https://X.X.X.X True
Username   True
Password   True
Slot number Target NetQuest device slot number. True
Port number Target NetQuest device port number. True
Fetch Events Whether to collect events. False
Statistic types to fetch   True
Use system proxy settings   False
Trust any certificate (not secure)   False

Commands

You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.

netquest-address-list-upload


Uploads a .txt file with the address list to the appliance. The appliance temporarily stores the file until it is saved to the Library and replaces any previously loaded list file.

Base Command

netquest-address-list-upload

Input

Argument Name Description Required
entry_id The entry ID of the file to upload. Required

Context Output

There is no context output for this command.

netquest-address-list-optimize


Optimizes the updated address list. If the traffic elements are IP addresses, the integration will optimize the list by compressing IP addresses into CIDR groups.

Base Command

netquest-address-list-optimize

Input

There are no input arguments for this command.

Context Output

Path Type Description
NetQuest.AddressList.OverlappingAddresses list A list of overlapping addresses in the address list.
NetQuest.AddressList.OverlapsPresent boolean A boolean field that indicates whether overlapping IP address ranges are present in the address list.
NetQuest.AddressList.MergedAddresses list A list that contains consolidated IP address ranges, combining overlapping or contiguous addresses into a unified set.
NetQuest.AddressList.MergesPresent boolean A boolean field that indicates whether any address ranges in the list have been merged to eliminate overlaps or contiguous entries.
NetQuest.AddressList.CountsBefore Dictionary A dictionary that stores the number of occurrences of each IP address or address range before any processing or modifications were applied.
NetQuest.AddressList.CountsAfter Dictionary A dictionary that stores the number of occurrences of each IP address or address range after processing or modifications have been applied.

netquest-address-list-create


Creates a new address list. This list will replace and override the old list entity.

Base Command

netquest-address-list-create

Input

Argument Name Description Required
name The name for the new address list. Required

Context Output

There is no context output for this command.

netquest-address-list-rename


Renames an address list. This is only meant to change the name of the list. If you try to give the value of the new_name argument to an existing address list, the command will fail.

Base Command

netquest-address-list-rename

Input

Argument Name Description Required
new_name The new name for an existing address list. Required
existing_name The name of the address list that you want to modify. Required

Context Output

There is no context output for this command.

netquest-address-list-delete


Deletes the address list of the name provided.

Base Command

netquest-address-list-delete

Input

Argument Name Description Required
name The name of the address list to delete. Required

Context Output

There is no context output for this command.

get-events


Gets events from NetQuest OMX. Each event is a report for the specified statistic type. Available only for Cortex XSIAM.

Base Command

get-events

Input

Argument Name Description Required
should_push_events When true, the integration creates Cortex XSIAM events. Otherwise, they will only be displayed. Possible values are: true, false. Default is false. Required
statistic_types_to_fetch Comma-separated list of statistic types to return. Default is Metering Stats,Export Stats,Export Peaks FPS,Optimization Stats. Required

Context Output

There is no context output for this command.

<~PLATFORM>

License Requirements

The following configuration parameters require the Cortex XSIAM license:

  • Fetch Events

</~PLATFORM>

Configuration parameters

  • url — Server URL (required)
  • credentials — Username (required)
  • slot — Slot number (required)
  • port — Port number (required)
  • isFetchEvents — Fetch Events
  • eventFetchInterval — Events Fetch Interval
  • statistic_types_to_fetch — Statistic types to fetch (required)
  • proxy — Use system proxy settings
  • insecure — Trust any certificate (not secure)

Commands (6)

  • get-events

    Gets events from NetQuest OMX. Each event is a report for the specified statistic type. Available only for Cortex XSIAM.

  • netquest-address-list-create

    Creates a new address list. This list will replace and override the old list entity.

  • netquest-address-list-delete

    Deletes the address list of the name provided.

  • netquest-address-list-optimize

    Optimizes the updated address list. If the traffic elements are IP addresses, the integration will optimize the list by compressing IP addresses into CIDR groups.

  • netquest-address-list-rename

    Renames an address list. This is only meant to change the name of the list. If you try to give the value of the new_name argument to an existing address list, the command will fail.

  • netquest-address-list-upload

    Uploads a .txt file with the address list to the appliance. The appliance temporarily stores the file until it is saved to the Library and replaces any previously loaded list file.

import json

import pytest
from CommonServerPython import *  # noqa: F401
from freezegun import freeze_time
from NetQuestOMX import (
    DATE_FORMAT_FOR_TOKEN,
    TOKEN_TTL_S,
    Client,
    StatType,
    address_list_create_command,
    address_list_delete_command,
    address_list_optimize_command,
    address_list_rename_command,
    address_list_upload_command,
    demisto,
    fetch_events,
    get_events,
)
from pytest_mock import MockerFixture

BASE_URL = "https://www.example.com/api/"


def util_load_json(path):
    with open(path, encoding="utf-8") as f:
        return json.loads(f.read())


# ----------------------------------------- COMMAND FUNCTIONS TESTS ---------------------------
@pytest.fixture
def net_quest_omx_client(requests_mock):
    credentials = {"identifier": "UserName", "password": "Password"}

    requests_mock.post(f"{BASE_URL}SessionService/Sessions", status_code=200, headers={"X-Auth-Token": "TEST"})

    return Client(base_url="https://www.example.com", credentials=credentials, verify=True, proxy=False)


@freeze_time("2020-06-03T02:00:00Z")
def test_new_token_login_client(requests_mock):
    """
    Given:
        - NetQuestOMX client object
    When:
        - getting the integration context
    Then:
        - Ensure the expiration time of the new token is calculated as expected in the integration context
    """
    credentials = {"identifier": "UserName", "password": "Password"}

    requests_mock.post(f"{BASE_URL}SessionService/Sessions", status_code=200, headers={"X-Auth-Token": "TEST"})

    Client(base_url="https://www.example.com", credentials=credentials, verify=True, proxy=False)
    integration_context = get_integration_context()

    assert integration_context["expiration_time"] == (datetime.utcnow() + timedelta(seconds=TOKEN_TTL_S)).strftime(
        DATE_FORMAT_FOR_TOKEN
    )


@freeze_time("2020-06-03T02:00:00Z")
def test_old_token_login_client(mocker: MockerFixture):
    """
    Given:
        - Mocked integration context which contains a valid token (not expired)
    When:
        - Building a client
    Then:
        - Ensure that no new token is generated (since the existing token is not expired)
    """
    credentials = {"identifier": "UserName", "password": "Password"}
    context = {
        "Token": "TEST",
        "expiration_time": (datetime.utcnow() + timedelta(seconds=TOKEN_TTL_S)).strftime(DATE_FORMAT_FOR_TOKEN),
    }

    mocker.patch.object(demisto, "getIntegrationContext", return_value=context)
    mocker.patch.object(demisto, "setIntegrationContext")
    mock_refresh_access_token = mocker.patch.object(Client, "_refresh_access_token")

    Client(base_url="https://www.example.com", credentials=credentials, verify=True, proxy=False)

    mock_refresh_access_token.assert_not_called()  # ensuring _refresh_access_token was not called


def test_fetch_events(requests_mock, net_quest_omx_client):
    """
    Given:
        - The all 4 statistic_types_to_fetch
    When:
        - Executing fetch_events function
    Then:
        - Ensure number of events as number of statistic_types_to_fetch (event for each type)
        - Ensure all events contain the 'STAT_TYPE' field
    """

    slot_number, port_number = "1", "1"

    requests_mock.get(
        f"{BASE_URL}Systems/Slot/{slot_number}/Ipfix/Status/Metering", json=util_load_json("test_data/MeteringStas.json")
    )

    requests_mock.get(
        f"{BASE_URL}Systems/Slot/{slot_number}/Ipfix/Status/Export", json=util_load_json("test_data/ExportStats.json")
    )

    requests_mock.get(
        f"{BASE_URL}Systems/Slot/{slot_number}/Ipfix/Status/ExportHwm", json=util_load_json("test_data/ExportPeakFPS.json")
    )

    requests_mock.get(
        f"{BASE_URL}Systems/Slot/{slot_number}/Port/{port_number}/EthernetInterfaces/Status/EthRxTx",
        json=util_load_json("test_data/OptimizationStats.json"),
    )

    statistic_types_to_fetch = ["Metering Stats", "Export Stats", "Export Peaks FPS", "Optimization Stats"]

    events = fetch_events(
        client=net_quest_omx_client,
        slot_number=slot_number,
        port_number=port_number,
        statistic_types_to_fetch=statistic_types_to_fetch,
    )

    assert len(events) == len(statistic_types_to_fetch)

    for event in events:
        assert event["STAT_TYPE"] in [statistic_type.replace(" ", "") for statistic_type in statistic_types_to_fetch]


def test_get_events(requests_mock, net_quest_omx_client):
    """
    Given:
        - 2 statistic_types_to_fetch
    When:
        - Executing get_events function
    Then:
        - Ensure number of events as number of statistic_types_to_fetch (event for each type)
    """

    params = {"slot": "1", "port": "1"}
    args = {"statistic_types_to_fetch": "Metering Stats,Export Stats"}

    requests_mock.get(
        f'{BASE_URL}Systems/Slot/{params["slot"]}/Ipfix/Status/Metering', json=util_load_json("test_data/MeteringStas.json")
    )

    requests_mock.get(
        f'{BASE_URL}Systems/Slot/{params["slot"]}/Ipfix/Status/Export', json=util_load_json("test_data/ExportStats.json")
    )

    events = get_events(net_quest_omx_client, params, args)

    assert len(events) == 2


def test_get_events_invalid_input(net_quest_omx_client):
    """
    Given:
        - invalid inputs -  statistic_types_to_fetch
    When:
        - Executing get_events function
    Then:
        - Ensure an exception is thrown
    """

    params = {"slot": "1", "port": "1"}
    args = {"statistic_types_to_fetch": "Metering ,Export"}
    with pytest.raises(DemistoException) as de:
        get_events(net_quest_omx_client, params, args)
    assert f"{argToList(args['statistic_types_to_fetch'])} is not a valid type" in de.value.message
    assert f"Valid types are {list(StatType._value2member_map_.keys())}" in de.value.message


def test_address_list_upload_command(mocker, requests_mock, net_quest_omx_client):
    """
    Given:
        - An entry_id (for a file to upload)
        - A mocked client
    When:
        - Executing netquest-address-list-upload command
    Then:
        - Ensure command is not failed and the readable_output as expected
    """
    mocker.patch.object(demisto, "getFilePath", return_value={"path": "test_data/test_file.txt", "name": "test_file"})
    requests_post = requests_mock.post(f"{BASE_URL}v1/UpdateService/ImportList/Config", json={})
    result = address_list_upload_command(client=net_quest_omx_client, args={"entry_id": "AAAAAAaaaa"})
    assert result.readable_output == "Address list was successfully uploaded"
    assert requests_post.called


def test_address_list_optimize_command(requests_mock, net_quest_omx_client):
    """
    Given:
        - A mocked client
    When:
        - Executing netquest-address-list-optimize command
    Then:
        - Ensure command is not failed and the outputs_prefix as expected
    """
    requests_mock.get(f"{BASE_URL}Systems/Filters/Address/Status/Optimization", json={})
    result = address_list_optimize_command(client=net_quest_omx_client)
    assert result.outputs_prefix == "NetQuest.AddressList"


def test_address_list_create_command(requests_mock, net_quest_omx_client):
    """
    Given:
        - A mocked client
        - A name and a value for the new list
    When:
        - Executing netquest-address-list-create command
    Then:
        - Ensure command is not failed and the readable_output as expected
    """
    name, value = "TEST", "0.0.0.0/24"
    requests_mock.post(f"{BASE_URL}Systems/Filters/ListImport/Config/Install", json={})
    result = address_list_create_command(client=net_quest_omx_client, args={"name": name, "value": value})
    assert result.readable_output == f"Successfully created a new instance of {name}"


def test_address_list_rename_command(requests_mock, net_quest_omx_client):
    """
    Given:
        - A mocked client
        - The name of the list to rename
        - A new name and a new value for the list
    When:
        - Executing netquest-address-list-rename command
    Then:
        - Ensure command is not failed and the readable_output as expected
    """
    new_name, new_value, existing_name = "NEW_TEST", "0.0.0.0/24", "TEST"
    requests_mock.put(f"{BASE_URL}Systems/Filters/ListImport/ListName/{existing_name}/Config/Install", json={})
    result = address_list_rename_command(
        client=net_quest_omx_client, args={"new_name": new_name, "new_value": new_value, "existing_name": existing_name}
    )
    assert result.readable_output == f"Successfully renamed {existing_name} to {new_name}"


def test_address_list_delete_command(requests_mock, net_quest_omx_client):
    """
    Given:
        - A mocked client
        - The name of the list to rename
        - A new name for the list
    When:
        - Executing netquest-address-list-rename command
    Then:
        - Ensure command is not failed and the readable_output as expected
    """
    name = "TEST"
    requests_mock.delete(f"{BASE_URL}Systems/Filters/Address/ListName/{name}/Config/List", json={})
    result = address_list_delete_command(client=net_quest_omx_client, args={"name": name})
    assert result.readable_output == f"Successfully deleted {name} list"