OPNSense

Manage OPNsense Firewall. For more information see OPNsense documentation. OPNsense is an open source, easy-to-use and easy-to-build HardenedBSD based firewall and routing platform.

Network Security · OPNSense

Details

IDOPNSense
ProviderDeciso B.V.
CategoryNetwork Security
From Version6.0.0
Docker Imagedemisto/opnsense:1.0.0.10133006
Supported ModulesAgentix XSIAM

README

Manage OPNsense Firewall.
For more information see OPNsense documentation.
OPNsense is an open source, easy-to-use and easy-to-build HardenedBSD based firewall and routing platform.
This integration was integrated and tested with version 22.1 of OPNSense

Configure OPNSense in Cortex

Parameter Required
Server URL (e.g. https://opnsense.mydomain.ltd) True
API Key True
API Secret True
Trust any certificate (not secure) False
Use system proxy settings 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.

opnsense-alias-list


Get aliases list

Base Command

opnsense-alias-list

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

Path Type Description
OPNSense.Alias unknown Aliases list

opnsense-alias-add


Create new alias

Base Command

opnsense-alias-add

Input

Argument Name Description Required
name Alias name. Required
type Alias type. Possible values are: host, network, port, url, urltable, geoip, networkgroup, mac, external, dynipv6host. Required
enabled Alias enabled. Possible values are: 1, 0. Default is 1. Optional
proto Alias protocol. Possible values are: inet, inet6. Optional
updatefreq Alias update frequency. Optional
counters Alias statistics. Possible values are: 0, 1. Optional
description Alias description. Optional
content Alias content. Optional
auto_commit Apply automaticly aliases changes. Possible values are: False, True. Default is False. Optional

Context Output

Path Type Description
OPNSense.Alias unknown Alias UUID created

opnsense-alias-del


Delete alias with uuid

Base Command

opnsense-alias-del

Input

Argument Name Description Required
uuid Alias UUID. Required
auto_commit Apply automaticly aliases changes. Possible values are: False, True. Default is False. Optional

Context Output

Path Type Description
OPNSense.Alias unknown Alias UUID deleted

opnsense-alias-mod


Modify an existing alias

Base Command

opnsense-alias-mod

Input

Argument Name Description Required
uuid Alias UUID. Required
content Alias content seperated by comma (NB. will replace actual content!). Required
name Alias name. Optional
type Alias type. Possible values are: host, network, port, url, urltable, geoip, networkgroup, mac, external, dynipv6host. Optional
proto Alias protocol. Possible values are: inet, inet6. Optional
enabled Alias enabled. Possible values are: 0, 1. Optional
updatefreq Alias update frequency. Optional
counters Alias statistics. Possible values are: 0, 1. Optional
description Alias description. Optional
auto_commit Apply automaticly aliases changes. Possible values are: False, True. Default is False. Optional

Context Output

Path Type Description
OPNSense.Alias unknown Alias UUID modified

opnsense-alias-mod-additem


Add item into existing alias

Base Command

opnsense-alias-mod-additem

Input

Argument Name Description Required
name Alias name. Required
entry Entry to add. Optional
auto_commit Apply automaticly aliases changes. Possible values are: False, True. Default is False. Optional

Context Output

Path Type Description
OPNSense.Alias unknown Alias UUID modified

opnsense-alias-mod-delitem


Del item into existing alias

Base Command

opnsense-alias-mod-delitem

Input

Argument Name Description Required
name Alias name. Required
entry Entry to remove. Optional
auto_commit Apply automaticly aliases changes. Possible values are: False, True. Default is False. Optional

Context Output

Path Type Description
OPNSense.Alias unknown Alias UUID modified

opnsense-alias-get


Get alias details

Base Command

opnsense-alias-get

Input

Argument Name Description Required
uuid Alias UUID. Optional
name Alias name. Optional

Context Output

Path Type Description
OPNSense.Alias Unknown Alias details
OPNSense.Alias.name Unknown Alias name
OPNSense.Alias.content Unknown Alias content
OPNSense.Alias.description Unknown Alias description
OPNSense.Alias.enabled Unknown Alias enabled

opnsense-alias-get-uuid


Get alias UUID

Base Command

opnsense-alias-get-uuid

Input

Argument Name Description Required
name Alias name. Required

Context Output

Path Type Description
OPNSense.Alias Unknown Alias UUID

opnsense-interfaces-list


Get interfaces list

Base Command

opnsense-interfaces-list

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

Path Type Description
OPNSense.Interfaces Unknown Interfaces list

opnsense-category-list


Get categories list

Base Command

opnsense-category-list

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

Path Type Description
OPNSense.Category Unknown Categories list

opnsense-category-add


Create new category

Base Command

opnsense-category-add

Input

Argument Name Description Required
name Category name. Required
auto Automatically added, will be removed when unused. Possible values are: 0, 1. Optional
color Category color (format : #YVWXYZ). Optional

Context Output

Path Type Description
OPNSense.Category Unknown Category UUID

opnsense-category-del


Delete category with uuid

Base Command

opnsense-category-del

Input

Argument Name Description Required
uuid Category UUID. Required

Context Output

Path Type Description
OPNSense.Category Unknown Category UUID

opnsense-category-get


Get category details

Base Command

opnsense-category-get

Input

Argument Name Description Required
uuid Category UUID. Optional

Context Output

Path Type Description
OPNSense.Category Unknown Category details

opnsense-category-mod


Modify an axisting category

Base Command

opnsense-category-mod

Input

Argument Name Description Required
uuid Category UUID. Required
name Category name. Optional
color Category color (format : #YVWXYZ). Optional
auto Automatically added, will be removed when unused. Possible values are: 0, 1. Optional

Context Output

Path Type Description
cef2c7d7-68d8-41aa-b6b8-1cac38554d58 Unknown Category UUID

opnsense-rule-list


Get rules list

Base Command

opnsense-rule-list

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

Path Type Description
OPNSense.Rule Unknown Rules list

opnsense-rule-get


Get rule details

Base Command

opnsense-rule-get

Input

Argument Name Description Required
uuid Rule UUID. Required

Context Output

Path Type Description
OPNSense.Rule Unknown Rule details
OPNSense.Rule.description Unknown Rule description
OPNSense.Rule.enabled Unknown Rule enabled
OPNSense.Rule.source_net Unknown Source NET’s rule
OPNSense.Rule.destination_net Unknown Destination NET’s rule
OPNSense.Rule.interface Unknown Interface’s rule

opnsense-alias-apply


Apply configuration

Base Command

opnsense-alias-apply

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

There is no context output for this command.

opnsense-device-reboot


Reboot the device

Base Command

opnsense-device-reboot

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

Path Type Description
OPNSense.Device Unknown Reboot status

opnsense-firmware-info


Get firmware info

Base Command

opnsense-firmware-info

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

Path Type Description
OPNSense.Firmware Unknown Firmware info

opnsense-firmware-status


Get firmware status

Base Command

opnsense-firmware-status

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

Path Type Description
OPNSense.Firmware Unknown Firmware status

opnsense-firmware-upgradestatus


Get firmware upgrade status

Base Command

opnsense-firmware-upgradestatus

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

Path Type Description
OPNSense.Firmware Unknown Firmware upgrade status

opnsense-firmware-update


Do firmware update

Base Command

opnsense-firmware-update

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

Path Type Description
OPNSense.Firmware Unknown Firmware update

opnsense-firmware-upgrade


Do firmware upgrade

Base Command

opnsense-firmware-upgrade

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

Path Type Description
OPNSense.Firmware Unknown Firmware upgrade

opnsense-rule-del


Delete an existing rule

Base Command

opnsense-rule-del

Input

Argument Name Description Required
uuid Rule UUID. Required
auto_commit Apply automaticly aliases changes. Possible values are: None, True. Default is None. Optional

Context Output

Path Type Description
OPNSense.Rule Unknown Rule UUID

opnsense-rule-add


Create a new rule

Base Command

opnsense-rule-add

Input

Argument Name Description Required
action Rule action. Possible values are: pass, block, reject. Default is pass. Optional
enabled Rule enabled. Possible values are: 1, 0. Default is 1. Optional
quick Rule quick. Possible values are: 1, 0. Default is 1. Optional
interface Rule interface. Optional
direction Rule direction. Possible values are: in, out. Default is in. Optional
ipprotocol Rule IP Protocol. Possible values are: inet, inet6. Default is inet. Optional
protocol Rule protocol. Possible values are: any, ICMP, IGMP, GGP, IPENCAP, ST2, TCP, CBT, EGP, IGP, BBN-RCC, NVP, PUP, ARGUS, EMCON, XNET, CHAOS, UDP, MUX, DCN, HMP, PRM, XNS-IDP, TRUNK-1, TRUNK-2, LEAF-1, LEAF-2, RDP, ISO-TP4, NETBLT, MFE-NSP, MERIT-INP, DCCP, 3PC, IDPR, XTP, DDP, IDPR-CMTP, TP++, IL, IPV6, SDRP, IDRP, RSVP, GRE, DSR, BNA, ESP, AH, I-NLSP, SWIPE, NARP, MOBILE, TLSP, SKIP, IPV6-ICMP, CFTP, SAT-EXPAK, KRYPTOLAN, RVD, IPPC, SAT-MON, VISA, IPCV, CPNX, CPHB, WSN, PVP, BR-SAT-MON, SUN-ND, WB-MON, WB-EXPAK, ISO-IP, VMTP, SECURE-VMTP, VINES, TTP, NSFNET-IGP, DGP, TCF, EIGRP, OSPF, SPRITE-RPC, LARP, MTP, AX.25, IPIP, MICP, SCC-SP, ETHERIP, ENCAP, GMTP, IFMP, PNNI, PIM, ARIS, SCPS, QNX, A/N, IPCOMP, SNP, COMPAQ-PEER, IPX-IN-IP, CARP, PGM, L2TP, DDX, IATP, STP, SRP, UTI, SMP, SM, PTP, ISIS, CRTP, CRUDP, SPS, PIPE, SCTP, FC, RSVP-E2E-IGNORE, UDPLITE, MPLS-IN-IP, MANET, HIP, SHIM6, WESP, ROHC, PFSYNC, DIVERT. Default is any. Optional
source_net Source Net. Default is any. Optional
source_not Source NOT. Possible values are: 0, 1. Default is 0. Optional
source_port Source port. Optional
destination_net Destination Net. Default is any. Optional
destination_not Destination NOT. Possible values are: 0, 1. Default is 0. Optional
destination_port Destination port. Optional
log Enable logging. Possible values are: 0, 1. Default is 0. Optional
sequence Provide a valid sequence for sorting (1 - 99999). Default is 1. Optional
description Rule description. Optional
auto_commit Apply automaticly aliases changes. Possible values are: None, True. Default is None. Required

Context Output

Path Type Description
OPNSense.Rule Unknown Rule UUID

opnsense-rule-mod


Modify an existing rule

Base Command

opnsense-rule-mod

Input

Argument Name Description Required
uuid Rule UUID. Required
action Rule action. Possible values are: pass, block, reject. Default is pass. Optional
enabled Rule enabled. Possible values are: 1, 0. Default is 1. Optional
quick Rule quick. Possible values are: 1, 0. Default is 1. Optional
interface Rule interface. Optional
direction Rule description. Possible values are: in, out. Default is in. Optional
ipprotocol Rule IP protocol. Possible values are: inet, inet6. Default is inet. Optional
protocol Rule protocol. Possible values are: any, ICMP, IGMP, GGP, IPENCAP, ST2, TCP, CBT, EGP, IGP, BBN-RCC, NVP, PUP, ARGUS, EMCON, XNET, CHAOS, UDP, MUX, DCN, HMP, PRM, XNS-IDP, TRUNK-1, TRUNK-2, LEAF-1, LEAF-2, RDP, ISO-TP4, NETBLT, MFE-NSP, MERIT-INP, DCCP, 3PC, IDPR, XTP, DDP, IDPR-CMTP, TP++, IL, IPV6, SDRP, IDRP, RSVP, GRE, DSR, BNA, ESP, AH, I-NLSP, SWIPE, NARP, MOBILE, TLSP, SKIP, IPV6-ICMP, CFTP, SAT-EXPAK, KRYPTOLAN, RVD, IPPC, SAT-MON, VISA, IPCV, CPNX, CPHB, WSN, PVP, BR-SAT-MON, SUN-ND, WB-MON, WB-EXPAK, ISO-IP, VMTP, SECURE-VMTP, VINES, TTP, NSFNET-IGP, DGP, TCF, EIGRP, OSPF, SPRITE-RPC, LARP, MTP, AX.25, IPIP, MICP, SCC-SP, ETHERIP, ENCAP, GMTP, IFMP, PNNI, PIM, ARIS, SCPS, QNX, A/N, IPCOMP, SNP, COMPAQ-PEER, IPX-IN-IP, CARP, PGM, L2TP, DDX, IATP, STP, SRP, UTI, SMP, SM, PTP, ISIS, CRTP, CRUDP, SPS, PIPE, SCTP, FC, RSVP-E2E-IGNORE, UDPLITE, MPLS-IN-IP, MANET, HIP, SHIM6, WESP, ROHC, PFSYNC, DIVERT. Optional
source_net Source Net. Optional
source_not Source NOT. Possible values are: 0, 1. Default is 0. Optional
source_port Source port. Optional
destination_net Destination Net. Optional
destination_not Destination NOT. Optional
destination_port Destination port. Optional
log Enable log. Possible values are: 0, 1. Default is 0. Optional
description Rule description. Optional
auto_commit Apply automaticly aliases changes. Possible values are: None, True. Default is None. Optional

Context Output

Path Type Description
OPNSense.Rule Unknown Rule UUID

opnsense-rule-apply


Apply rules current configuration

Base Command

opnsense-rule-apply

Input

Argument Name Description Required
rollback_revision Rollback revision. Optional

Context Output

Path Type Description
OPNSense.Rule Unknown Action status

opnsense-rule-savepoint


Save rules current configuration

Base Command

opnsense-rule-savepoint

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

Path Type Description
OPNSense.Rule Unknown Action status

opnsense-logs-search


Search into firewall logs

Base Command

opnsense-logs-search

Input

Argument Name Description Required
limit Log search limit. Default is 1000. Optional
ip Search IP in src or dst. Optional
interface Interface search filter. Optional

Context Output

| Path | Type | Description |
|—————————–| — | — |
| OPNSense.Logs | Unknown | OPNSense logs |
| OPNSense.Logs.interface | Unknown | interface in logs |
| OPNSense.Logs.src | Unknown | SRC in logs |
| OPNSense.Logs.srcport | Unknown | SRCPORT in logs |
| OPNSense.Logs.dst | Unknown | DST in logs |
| OPNSense.Logs.dstport | Unknown | DSTPORT in logs |
| OPNSense.Logs.action | Unknown | Action in logs |
| OPNSense.Logs.timestamp | Unknown | timestamp in logs |
| OPNSense.Logs.label | Unknown | label in logs |
| OPNSense.Logs.protoname | Unknown | protoname in logs |

opnsense-states-search


Query states

Base Command

opnsense-states-search

Input

Argument Name Description Required
ip Search IP in src or dst. Optional

Context Output

Path Type Description
OPNSense.States Unknown OPNSense States
OPNSense.States.label Unknown label in states
OPNSense.States.descr Unknown states description
OPNSense.States.nat_addr Unknown nat address in states
OPNSense.States.nat_port Unknown nat port in states
OPNSense.States.iface Unknown interface in states
OPNSense.States.ipproto Unknown IP Protocol in states
OPNSense.States.proto Unknown Protocol in states

opnsense-state-del


Delete state with ID

Base Command

opnsense-state-del

Input

Argument Name Description Required
state_id State ID. Optional

Context Output

There is no context output for this command.

opnsense-rule-revert


Revert config to given savepoint

Base Command

opnsense-rule-revert

Input

Argument Name Description Required
rollback_revision Rollback revision. Optional

Context Output

There is no context output for this command.

Configuration parameters

  • url — Server URL (e.g. https://opnsense.mydomain.ltd) (required)
  • apikey — API Key (required)
  • apisecret — API Secret (required)
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings

Commands (32)

  • opnsense-alias-add

    Create new alias.

  • opnsense-alias-apply

    Apply configuration.

  • opnsense-alias-del

    Delete alias with uuid.

  • opnsense-alias-get

    Get alias details.

  • opnsense-alias-get-uuid

    Get alias UUID.

  • opnsense-alias-list

    Get aliases list.

  • opnsense-alias-mod

    Modify an existing alias.

  • opnsense-alias-mod-additem

    Add item into existing alias.

  • opnsense-alias-mod-delitem

    Del item into existing alias.

  • opnsense-category-add

    Create new category.

  • opnsense-category-del

    Delete category with uuid.

  • opnsense-category-get

    Get category details.

  • opnsense-category-list

    Get categories list.

  • opnsense-category-mod

    Modify an axisting category.

  • opnsense-device-reboot

    Reboot the device.

  • opnsense-firmware-info

    Get firmware info.

  • opnsense-firmware-status

    Get firmware status.

  • opnsense-firmware-update

    Do firmware update.

  • opnsense-firmware-upgrade

    Do firmware upgrade.

  • opnsense-firmware-upgradestatus

    Get firmware upgrade status.

  • opnsense-interfaces-list

    Get interfaces list.

  • opnsense-logs-search

    Search into firewall logs.

  • opnsense-rule-add

    Create a new rule.

  • opnsense-rule-apply

    Apply rules current configuration.

  • opnsense-rule-del

    Delete an existing rule.

  • opnsense-rule-get

    Get rule details.

  • opnsense-rule-list

    Get rules list.

  • opnsense-rule-mod

    Modify an existing rule.

  • opnsense-rule-revert

    Revert config to given savepoint.

  • opnsense-rule-savepoint

    Save rules current configuration.

  • opnsense-state-del

    Delete state with ID.

  • opnsense-states-search

    Query states.

import demistomock as demisto  # noqa: F401
from CommonServerPython import *  # noqa: F401

"""OPNSense integration for Cortex XSOAR (aka Demisto)"""

from CommonServerUserPython import *  # noqa


from pyopnsense2 import core_core, core_diagnostics, core_firmware, core_firewall, plugins_firewall
import json
import urllib3
import traceback

# Disable insecure warnings
urllib3.disable_warnings()

if not demisto.params().get("proxy", False):
    for key in ["HTTP_PROXY", "HTTPS_PROXY", "http_proxy", "https_proxy"]:
        try:
            del os.environ[key]
        except KeyError:
            pass

""" CONSTANTS """

""" CLIENT CLASS """


class Client(BaseClient):
    """Client class to interact with the service API"""

    def __init__(self, params):
        # alias util
        self.fw_alias_util = core_firewall.firewall_alias_util(params)
        # alias
        self.fw_alias = core_firewall.firewall_alias(params)
        # category
        self.fw_categ = core_firewall.firewall_category(params)
        # fw rules
        self.fw_filter = plugins_firewall.firewall_filter(params)
        # fw base
        self.fw_base = plugins_firewall.firewall_filter_base(params)
        # interfaces
        self.diag_interfaces = core_diagnostics.diagnostics_interface(params)
        # logs
        self.diag_firewall = core_diagnostics.diagnostics_firewall(params)
        # core system
        self.core_system = core_core.core_system(params)
        # core firmware
        self.core_firmware = core_firmware.Core_Firmware(params)

    def test_module(self):
        return self.fw_alias_util.aliases()

    # core_system in core_core and

    def system_reboot(self):
        return self.core_system.reboot()

    def firmware_info(self):
        return self.core_firmware.info()

    def firmware_status(self):
        return self.core_firmware.status()

    def firmware_upgradestatus(self):
        return self.core_firmware.upgradestatus()

    def firmware_update(self):
        return self.core_firmware.update()

    def firmware_upgrade(self):
        return self.core_firmware.upgrade()

    # diagnostics_interface and diagnostics_firewall in core_diagnostics

    def interfaces_list(self):
        return self.diag_interfaces.getInterfaceNames()

    def log_search(self, limit):
        return self.diag_firewall.log(args={"limit": limit})

    def states_search(self):
        return self.diag_firewall.queryStates()

    def state_del(self, state_id):
        return self.diag_firewall.delState(args={"stateid": state_id})

    # firewall_filter_base and firewall_filter in plugins_firewall

    def firewall_savepoint(self):
        return self.fw_filter.savepoint()

    def firewall_apply(self, rollback=None):
        if rollback:
            return self.fw_filter.apply(args={"rollback_revision": rollback})
        return self.fw_filter.apply()

    def firewall_cancelRollback(self, rollback):
        return self.fw_filter.cancelRollback(args={"rollback_revision": rollback})

    def firewall_revert(self, rollback):
        return self.fw_filter.revert(args={"revision": rollback})

    def firewall_addRule(self, args):
        return self.fw_filter.addRule(args)

    def firewall_delRule(self, args):
        return self.fw_filter.delRule(args)

    def firewall_setRule(self, uuid, args):
        args["uuid"] = uuid
        return self.fw_filter.setRule(args)

    def firewall_getRule(self, args):
        return self.fw_filter.getRule(args)

    def firewall_searchRule(self, args=None):
        return self.fw_filter.searchRule(args)

    # firewall_category in core_firewall

    def category_list(self):
        return self.fw_categ.searchItem({"rowCount": -1})["rows"]

    def category_addItem(self, args):
        return self.fw_categ.addItem(args)

    def category_delItem(self, args):
        return self.fw_categ.delItem(args)

    def category_getItem(self, args):
        return self.fw_categ.getItem(args)

    def category_setItem(self, uuid, args):
        args["uuid"] = uuid
        return self.fw_categ.setItem(args)

    # firewall_alias_util and firewall_alias in core_firewall

    def alias_util_aliases(self):
        return self.fw_alias_util.aliases()

    def alias_util_add(self, args):
        return self.fw_alias_util.add(args)

    def alias_util_del(self, args):
        return self.fw_alias_util.delete(args)

    def alias_getItem(self, args):
        return self.fw_alias.getItem(args)

    def alias_addItem(self, args):
        return self.fw_alias.addItem(args)

    def alias_delItem(self, args):
        return self.fw_alias.delItem(args)

    def alias_setItem(self, uuid, args):
        args["uuid"] = uuid
        return self.fw_alias.setItem(args)

    def alias_getuuid(self, args):
        return self.fw_alias.getAliasUUID(args)

    def alias_reconfigure(self):
        return self.fw_alias.reconfigure()


""" HELPER FUNCTIONS """


def with_keys(d, keys):
    return {x: d[x] for x in d if x in keys}


def output_format(res, output_type_name=None, readable_title=None):
    if res:
        if isinstance(res, list):
            key_list = list(res[0].keys())
        else:
            key_list = list(res.keys())
        if not output_type_name:
            output_type_name = key_list[0].split(".")[0]
        result = []
        if not readable_title:
            readable_title = output_type_name
        result.append(
            CommandResults(
                outputs_prefix="OPNSense." + output_type_name,
                outputs_key_field=key_list,
                outputs=res,
                raw_response=res,
                readable_output=tableToMarkdown(name="OPNSense " + readable_title, t=res, headers=key_list),
            )
        )
        return result
    else:
        return "No result"


def rule_reformat_result(data):
    """reformat data result from api when getting rule"""
    result = {"rule": {}}  # type: Dict[str, Any]
    for key in data["rule"]:
        if key in [
            "enabled",
            "sequence",
            "quick",
            "source_net",
            "source_not",
            "source_port",
            "destination_net",
            "destination_not",
            "destination_port",
            "log",
            "description",
        ]:
            result["rule"][key] = data["rule"][key]
        elif key in ["action", "interface", "direction", "ipprotocol", "protocol", "gateway"]:
            tmpvalue = ""
            for subkey in data["rule"][key]:
                if data["rule"][key][subkey]["selected"] == 1:
                    tmpvalue = subkey
                    break
                if data["rule"][key][subkey]["selected"] == 0:
                    pass
            result["rule"][key] = tmpvalue
        else:
            result["rule"][key] = "REPLACED"
    return result


def alias_reformat_result(data):
    """reformat data result from api when getting alias"""
    result = {"alias": {}}  # type: Dict[str, Any]
    for key in data["alias"]:
        if key in ["enabled", "name", "counters", "updatefreq", "description"]:
            result["alias"][key] = data["alias"][key]
        elif key in ["content", "type", "proto", "interface"]:
            tmpvalue = ""
            for subkey in data["alias"][key]:
                if data["alias"][key][subkey]["selected"] == 1:
                    tmpvalue = subkey
                    break
                if data["alias"][key][subkey]["selected"] == 0:
                    pass
            result["alias"][key] = tmpvalue
        else:
            result["alias"][key] = "REPLACED"
    return result


""" COMMAND FUNCTIONS """


def test_module(client: Client) -> str:
    result = client.test_module()
    if "error" in result:
        return "Test Failed! Error: " + str(json.loads(result["error"]["resp_body"])["message"])
    elif "exception" in result:
        return "Test Failed! Make sure the URL is correctly set. Error: " + str(result["exception"])
    else:
        return "ok"


# Alias commands


def alias_apply_command(client):
    result = client.alias_reconfigure()
    readable_output = f"## {result}"
    return CommandResults(
        readable_output=readable_output, outputs_prefix="OPNSense.Alias", outputs_key_field="", outputs=json.dumps(result)
    )


def alias_list_command(client):
    result = client.alias_util_aliases()
    readable_output = f"## {result}"
    return CommandResults(
        readable_output=readable_output, outputs_prefix="OPNSense.Alias", outputs_key_field="", outputs=json.dumps(result)
    )


def alias_add_command(client, args):
    content = argToList(args.get("content"))
    format_content = "\n".join(content)
    params = {
        "alias": {
            "enabled": args.get("enabled", "1"),
            "name": args.get("name"),
            "type": args.get("type"),
            "proto": args.get("proto", ""),
            "updatefreq": args.get("updatefreq", ""),
            "content": format_content,
            "counters": args.get("counters", ""),
            "description": args.get("description", ""),
        }
    }
    result = client.alias_addItem(params)
    if args.get("auto_commit"):
        client.alias_reconfigure()
    output = output_format(result, "Alias", "Alias uuid : " + str(result["uuid"]) + " created")
    return output


def alias_mod_command(client, args):
    uuid = args.get("uuid")
    content = argToList(args.get("content"))
    format_content = "\n".join(content)
    data = client.alias_getItem({"uuid": uuid})
    original = alias_reformat_result(data)
    original["alias"]["content"] = format_content
    modified = {"alias": {}}  # type: Dict[str, Any]
    for key in original["alias"]:
        newvalue = args.get(key, original["alias"][key])
        modified["alias"][key] = newvalue
    result = client.alias_setItem(uuid, modified)
    if args.get("auto_commit"):
        client.alias_reconfigure()
    output = output_format(result, "Alias", "Alias uuid : " + str(uuid) + " modified")
    return output


def alias_mod_additem_command(client, args):
    name = args.get("name")
    entry = args.get("entry")
    params = {"aliasName": name, "address": entry}
    result = client.alias_util_add(params)
    if args.get("auto_commit"):
        client.alias_reconfigure()
    output = output_format(result, "Alias", "Alias : " + str(name) + " modified")
    return output


def alias_mod_delitem_command(client, args):
    name = args.get("name")
    entry = args.get("entry")
    params = {"aliasName": name, "address": entry}
    result = client.alias_util_del(params)
    if args.get("auto_commit"):
        client.alias_reconfigure()
    output = output_format(result, "Alias", "Alias : " + str(name) + " modified")
    return output


def alias_del_command(client, args):
    params = {"uuid": args.get("uuid")}
    result = client.alias_delItem(params)
    if args.get("auto_commit"):
        client.alias_reconfigure()
    output = output_format(result, "Alias", "Alias uuid : " + str(args.get("uuid")) + " deleted")
    return output


def alias_get_command(client, args):
    name = args.get("name")
    uuid = args.get("uuid")
    if name is None and uuid is None:
        raise DemistoException("You must at least define the name or the uuid argument")
    elif uuid is None and name is not None:
        uuid = client.alias_getuuid({"name": name})["uuid"]
    data = client.alias_getItem({"uuid": uuid})
    result = alias_reformat_result(data)
    output = output_format(result["alias"], "Alias", "Alias uuid : " + str(uuid) + " description")
    return output


def alias_getuuid_command(client, args):
    name = args.get("name")
    result = client.alias_getuuid({"name": name})["uuid"]
    readable_output = f"## {result}"
    return CommandResults(
        readable_output=readable_output, outputs_prefix="OPNSense.Alias", outputs_key_field="", outputs=json.dumps(result)
    )


# Diagnostics commands


def interfaces_list_command(client):
    result = client.interfaces_list()
    output = output_format(result, "Interfaces", "Interfaces list:")
    return output


def logs_search_command(client: Client, args) -> CommandResults:
    limit = args.get("limit")
    ip = args.get("ip")
    interface = args.get("interface")
    results = client.log_search(limit)
    if interface:
        if ip:
            res = [x for x in results if x["interface"] == interface if (x["dst"] == ip or x["src"] == ip)]
        else:
            res = [x for x in results if x["interface"] == interface]
    elif ip:
        res = [x for x in results if (x["dst"] == ip or x["src"] == ip)]
    else:
        res = results
    if res:
        pretty = []
        for result in res:
            display = {"interface", "src", "srcport", "dst", "dstport", "action", "__timestamp__", "protoname", "label"}
            pretty.append(with_keys(result, display))
        return output_format(pretty, "Logs", readable_title="firewall logs")
    else:
        return CommandResults(readable_output="Nothing found")


# States commands


def states_search_command(client: Client, args) -> CommandResults:
    ip = args.get("ip")
    results = client.states_search()
    if ip:
        sresult = [x for x in results["rows"] if (x["dst_addr"] == ip or x["src_addr"] == ip)]
        result = output_format(sresult, "States", readable_title="firewall states")
    elif results:
        result = output_format(results["rows"], "States", readable_title="firewall states")
    else:
        return CommandResults(readable_output="Nothing found")
    return result


def state_del_command(client: Client, args) -> CommandResults:
    state_id = args.get("state_id")
    results = client.state_del(state_id)
    return results


# Categories commands


def category_list_command(client):
    result = client.category_list()
    output = output_format(result, "Category", "Categories list:")
    return output


def category_add_command(client, args):
    params = {"category": {"auto": args.get("auto", "0"), "name": args.get("name"), "color": args.get("color", "")}}
    result = client.category_addItem(params)
    output = output_format(result, "Category", "Category uuid : " + result["uuid"] + " created:")
    return output


def category_del_command(client, args):
    uuid = args.get("uuid")
    params = {"uuid": uuid}
    result = client.category_delItem(params)
    output = output_format(result, "Category", "Category uuid : " + uuid + " deleted")
    return output


def category_get_command(client, args):
    uuid = args.get("uuid")
    result = client.category_getItem({"uuid": uuid})["category"]
    output = output_format(result, "Category", "Category uuid : " + uuid + " description")
    return output


def category_mod_command(client, args):
    uuid = args.get("uuid")
    original = client.category_getItem({"uuid": uuid})
    modified = {"category": {}}  # type: Dict[str, Any]
    for key in original["category"]:
        newvalue = args.get(key, original["category"][key])
        modified["category"][key] = newvalue
    result = client.category_setItem(uuid, modified)
    output = output_format(result, "Category", "Category uuid : " + uuid + " modified:")
    return output


# Firewall rule commands


def fw_rule_list_command(client):
    result = client.firewall_searchRule()
    output = output_format(result["rows"], "Rule", "Rules list: ")
    return output


def fw_rule_get_command(client, args):
    uuid = args.get("uuid")
    data = client.firewall_getRule({"uuid": uuid})
    result = rule_reformat_result(data)
    output = output_format(result["rule"], "Rule", "Rule uuid : " + uuid + " description")
    return output


def fw_rule_del_command(client, args):
    uuid = args.get("uuid")
    params = {"uuid": uuid}
    result = client.firewall_delRule(params)
    if args.get("auto_commit"):
        client.firewall_apply()
    output = output_format(result, "Rule", "Rule uuid : " + uuid + " deleted")
    return output


def fw_rule_add_command(client, args):
    params = {
        "rule": {
            "sequence": args.get("sequence"),
            "action": args.get("action"),
            "enabled": args.get("enabled"),
            "quick": args.get("quick"),
            "interface": args.get("interface", ""),
            "direction": args.get("direction"),
            "ipprotocol": args.get("ipprotocol", ""),
            "source_net": args.get("source_net"),
            "source_not": args.get("source_not"),
            "source_port": args.get("source_port"),
            "destination_net": args.get("destination_net"),
            "destination_not": args.get("destination_not"),
            "destination_port": args.get("destination_port"),
            "log": args.get("log"),
            "description": args.get("description"),
        }
    }
    result = client.firewall_addRule(params)
    if str(result["result"]) == "failed":
        return_error(result["validations"])
    if args.get("auto_commit"):
        client.firewall_apply()
    output = output_format(result, "Rule", "Rule successfully added with ID : " + str(result["uuid"]))
    return output


def fw_rule_mod_command(client, args):
    uuid = args.get("uuid")
    data = client.firewall_getRule({"uuid": uuid})
    original = rule_reformat_result(data)
    modified = {"rule": {}}  # type: Dict[str, Any]
    for key in original["rule"]:
        newvalue = args.get(key, original["rule"][key])
        modified["rule"][key] = newvalue
    result = client.firewall_setRule(uuid, modified)
    if args.get("auto_commit"):
        client.firewall_apply()
    output = output_format(result, "Rule", "Rule uuid : " + uuid + " modified:")
    return output


def fw_rule_apply_command(client, args):
    revision = args.get("rollback_revision", None)
    result = client.firewall_apply(revision)
    output = output_format(result, "Rule", "Rules applyied")
    return output


def fw_rule_savepoint_command(client):
    result = client.firewall_savepoint()
    output = output_format(result, "Rule", "Rules Save point")
    return output


def fw_rule_cancelRollback_command(client, args):
    revision = args.get("rollback_revision")
    result = client.firewall_cancelRollback(revision)
    return result


def fw_rule_revert_command(client, args):
    revision = args.get("rollback_revision")
    result = client.firewall_revert(revision)
    output = output_format(result, "Rule", "Rules reverted")
    return output


# Firmware and System commands


def device_reboot_command(client):
    result = client.system_reboot()
    output = output_format(result, "Device", "Device Reboot")
    return output


def firmware_info_command(client):
    result = client.firmware_info()
    output = output_format(result, "Firmware", "Firmware info")
    return output


def firmware_status_command(client):
    result = client.firmware_status()
    output = output_format(result["product"], "Firmware", "Firmware status")
    return output


def firmware_upgradestatus_command(client):
    result = client.firmware_upgradestatus()
    output = output_format(result, "Firmware", "Firmware Upgrade status")
    return output


def firmware_update_command(client):
    result = client.firmware_update()
    output = output_format(result, "Firmware", "Firmware update")
    return output


def firmware_upgrade_command(client):
    result = client.firmware_upgrade()
    output = output_format(result, "Firmware", "Firmware upgrade")
    return output


""" MAIN FUNCTION """


def main() -> None:
    """main function, parses params and runs command functions"""

    command_list_noarg = {
        "opnsense-interfaces-list": interfaces_list_command,
        "opnsense-alias-apply": alias_apply_command,
        "opnsense-alias-list": alias_list_command,
        "opnsense-category-list": category_list_command,
        "opnsense-rule-list": fw_rule_list_command,
        "opnsense-rule-savepoint": fw_rule_savepoint_command,
        "opnsense-firmware-info": firmware_info_command,
        "opnsense-firmware-status": firmware_status_command,
        "opnsense-firmware-upgradestatus": firmware_upgradestatus_command,
        "opnsense-firmware-update": firmware_update_command,
        "opnsense-firmware-upgrade": firmware_upgrade_command,
        "opnsense-device-reboot": device_reboot_command,
    }

    command_list = {
        "opnsense-alias-add": alias_add_command,
        "opnsense-alias-del": alias_del_command,
        "opnsense-alias-mod": alias_mod_command,
        "opnsense-alias-mod-additem": alias_mod_additem_command,
        "opnsense-alias-mod-delitem": alias_mod_delitem_command,
        "opnsense-alias-get": alias_get_command,
        "opnsense-alias-get-uuid": alias_getuuid_command,
        "opnsense-category-add": category_add_command,
        "opnsense-category-del": category_del_command,
        "opnsense-category-get": category_get_command,
        "opnsense-category-mod": category_mod_command,
        "opnsense-rule-apply": fw_rule_apply_command,
        "opnsense-rule-revert": fw_rule_revert_command,
        "opnsense-rule-get": fw_rule_get_command,
        "opnsense-rule-del": fw_rule_del_command,
        "opnsense-rule-add": fw_rule_add_command,
        "opnsense-rule-mod": fw_rule_mod_command,
        "opnsense-logs-search": logs_search_command,
        "opnsense-states-search": states_search_command,
        "opnsense-state-del": state_del_command,
    }

    params = {
        "base_url": urljoin(demisto.params()["url"], "/api"),
        "auth": (demisto.params().get("apikey"), demisto.params().get("apisecret")),
        "verify_cert": not demisto.params().get("insecure", False),
        "proxy": demisto.params().get("proxy", False),
        "timeout": 60,
    }

    demisto.debug(f"Command being called is {demisto.command()}")
    try:
        client = Client(params)
        cmd = demisto.command()

        if cmd == "test-module":
            return_results(test_module(client))
        elif cmd in command_list_noarg:
            return_results(command_list_noarg[cmd](client))
        elif cmd in command_list:
            return_results(command_list[cmd](client, demisto.args()))

    # Log exceptions and return errors
    except Exception as e:
        demisto.error(traceback.format_exc())  # print the traceback
        return_error(f"Failed to execute {demisto.command()} command.\nError:\n{e!s}")


""" ENTRY POINT """

if __name__ in ("__main__", "__builtin__", "builtins"):
    main()