API Usage

Sometimes it may be more convenient to avoid the CLI and instead use the module directly, which exposes more functionality and may be easier te extend if your project also uses Python. Below, we will characterize several use-cases you may encounter and how to address them using the functionality exposed by suricata-check.

All publicly exposed modules, classes, and methods are documented and typed such that IDEs such as Visual Studio Code will provide useful information and suggestions as you write code using suricata_check.

Analyze a single rule

In order to analyze a single rule using the module, you first need to parse the rule using idstools, which is installed together with suricata_check. Thereafter, you can process it using suricata_check.analyze_rule as follows to obtain a RuleReport

import idstools
import idstools.rule
import suricata_check

rule = """\
alert ip any any -> any any (msg:"Some msg"; sid:1;)"""
parsed_rule = idstools.rule.parse(rule)
assert parsed_rule is not None

rule_report = suricata_check.analyze_rule(parsed_rule)

Note that parsed_rule may be None if it is unparseable for idstools. Parseable rules need not be valid Suricata rules. If suricata_check cannot parse the rule, a InvalidRuleError will be raised.

You can further inspect the rule report, which is implemented as a dataclass, by treating it as a dictionary.

print(rule_report.rule['raw'])

print("Number of issues found: " + str(len(rule_report.issues)))

Inspecting issues

Similar to the rule report, issues are represented by dataclasses, which you can treat as dictionaries.

print(rule_report.rule['raw'])

for issue in rule_report.issues:
    print(issue.code)
    print(issue.msg)

Selecting checkers

Sometimes you may only be interested in running a single checker, or enabling/disabling certain codes similar to the CLI usage. You can do so by passing checkers to analyze_rule.

checkers = suricata_check.get_checkers(include=("M.*",), exclude=tuple())

rule_report = suricata_check.analyze_rule(parsed_rule, checkers=checkers)

If you have implemented a checker implementing the CheckerInterface as descibed in CONTRIBUTING, the checker will be discoverable by the get_checkers function. Any other class (e.g. MyOwnChecker) implementing CheckerInterface, may be passed to analyze_rule directly as follows:

rule_report = suricata_check.analyze_rule(parsed_rule, checkers=[MyOwnChecker()])

Processing rulesets

Similar to the CLI, it is possible to process entire rulesets at once using process_rules_file. Also for this function, it is optionally possible to explcitly pass checkers to use.

from suricata_check.checkers import MetadataChecker

ruleset_report = suricata_check.process_rules_file(
    "/var/lib/suricata/rules/suricata.rules", 
    evaluate_disabled=True, 
    checkers=[MetadataChecker()]
)

for rule_report in ruleset_report.rules:
    has_issues = len(rule_report.issues) > 0
    if has_issues:
        print(rule_report.rule['raw'])