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 with suricata_check. Thereafter, you can process it using suricata_check.analyze_rule as follows to obtain a suricata_check.utils.checker_typing.RuleReport

import suricata_check

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

rule_report = suricata_check.analyze_rule(parsed_rule)

Note that if a rule is unparseable, parsed_rule may be None or suricata_check.utils.rule.parse may throw a suricata_check.utils.rule.ParsingError. Parseable rules need not be valid Suricata rules. If suricata_check.utils.rule.parse cannot parse the rule, a suricata_check.utils.checker_typing.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 suricata_check.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 suricata_check.get_checkers function. Any other class (e.g. MyOwnChecker) implementing suricata_check.checkers.interface.CheckerInterface, may be passed to suricata_check.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 suricata_check.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'])