Source code for suricata_check.checkers.styleguide._state

  1"""`StateChecker`."""
  2
  3import logging
  4from types import MappingProxyType
  5
  6from suricata_check.checkers.interface import CheckerInterface
  7from suricata_check.utils.checker import (
  8    get_rule_suboptions,
  9    is_rule_option_always_equal_to_regex,
 10    is_rule_option_always_put_before,
 11    is_rule_option_set,
 12    is_rule_suboption_set,
 13)
 14from suricata_check.utils.checker_typing import ISSUES_TYPE, Issue
 15from suricata_check.utils.regex_provider import get_regex_provider
 16from suricata_check.utils.rule import Rule
 17
 18_regex_provider = get_regex_provider()
 19
 20_S510_REGEX = _regex_provider.compile(
 21    r"^((set|isset|toggle|unset|isnotset),[A-Z]+\.\w+)|(noalert)$",
 22    _regex_provider.IGNORECASE,
 23)
 24
 25_S520_REGEX = _regex_provider.compile(
 26    r"^((set|isset|toggle|unset|isnotset),[A-Z]+\.\w+)|(noalert),.*$",
 27    _regex_provider.IGNORECASE,
 28)
 29
 30_logger = logging.getLogger(__name__)
 31
 32
[docs] 33class StateChecker(CheckerInterface): 34 """The `StateChecker` contains several checks for Suricata options relating to the connection or detection state. 35 36 Codes S500-S510 report on non-standard usages of `flow` 37 Codes S510-S520 report on non-standard usages of `flowbits` 38 Codes S520-S530 report on non-standard usages of `xbits` 39 """ 40 41 codes = MappingProxyType( 42 { 43 "S500": {"severity": logging.INFO}, 44 "S501": {"severity": logging.INFO}, 45 "S510": {"severity": logging.INFO}, 46 "S511": {"severity": logging.INFO}, 47 "S520": {"severity": logging.INFO}, 48 "S521": {"severity": logging.INFO}, 49 "S522": {"severity": logging.INFO}, 50 }, 51 ) 52 53 def _check_rule( 54 self: "StateChecker", 55 rule: Rule, 56 ) -> ISSUES_TYPE: 57 issues: ISSUES_TYPE = [] 58 59 if is_rule_option_set(rule, "flow") and not is_rule_option_always_put_before( 60 rule, 61 "established", 62 ["to_server", "to_client", "from_server", "from_client"], 63 sequence=[suboption[0] for suboption in get_rule_suboptions(rule, "flow")], 64 ): 65 issues.append( 66 Issue( 67 code="S500", 68 message="""\ 69The rule specifies the connection state after the connection direction in the `flow` option. 70Consider specifying the connection state first like `established,to_server`.\ 71""", 72 ), 73 ) 74 75 if is_rule_suboption_set(rule, "flow", "from_client") or is_rule_suboption_set( 76 rule, 77 "flow", 78 "from_server", 79 ): 80 issues.append( 81 Issue( 82 code="S501", 83 message="""\ 84The rule has set `from_client` or `from_server` as a `flow` option. 85Consider using `to_client` or `to_server` instead.\ 86""", 87 ), 88 ) 89 90 if is_rule_option_always_equal_to_regex(rule, "flowbits", _S510_REGEX) is False: 91 issues.append( 92 Issue( 93 code="S510", 94 message="""\ 95The rule sets flowbits with a non-standard name. 96Consider using `RULESET.description` as name for the flowbit.\ 97""", 98 ), 99 ) 100 101 if ( 102 ( 103 is_rule_suboption_set(rule, "flowbits", "set") 104 or is_rule_suboption_set(rule, "flowbits", "unset") 105 ) 106 and not ( 107 is_rule_suboption_set(rule, "flowbits", "isset") 108 or is_rule_suboption_set(rule, "flowbits", "isnotset") 109 ) 110 and not ( 111 is_rule_option_set(rule, "noalert") 112 or is_rule_suboption_set(rule, "flowbits", "noalert") 113 ) 114 ): 115 issues.append( 116 Issue( 117 code="S511", 118 message="""\ 119The rule (un)sets a flowbit but does not use the noalert option. 120Consider using the noalert option to prevent unnecessary alerts.\ 121""", 122 ), 123 ) 124 125 if is_rule_option_always_equal_to_regex(rule, "xbits", _S520_REGEX) is False: 126 issues.append( 127 Issue( 128 code="S520", 129 message="""\ 130The rule sets xbits with a non-standard name. 131Consider using `RULESET.description` as name for the xbit.\ 132""", 133 ), 134 ) 135 136 if ( 137 ( 138 is_rule_suboption_set(rule, "xbits", "set") 139 or is_rule_suboption_set(rule, "xbits", "unset") 140 ) 141 and not is_rule_option_set(rule, "noalert") 142 and not ( 143 is_rule_suboption_set(rule, "xbits", "isset") 144 or is_rule_suboption_set(rule, "xbits", "isnotset") 145 ) 146 ): 147 issues.append( 148 Issue( 149 code="S521", 150 message="""\ 151The rule (un)sets a xbit but does not use the noalert option. 152Consider using the noalert option to prevent unnecessary alerts.\ 153""", 154 ), 155 ) 156 157 if (is_rule_suboption_set(rule, "xbits", "set")) and not is_rule_suboption_set( 158 rule, 159 "xbits", 160 "expire", 161 ): 162 issues.append( 163 Issue( 164 code="S522", 165 message="""\ 166The rule sets a xbit but does not explcitly set the expire option. 167Consider setting the expire option to indicate for how long the xbit remains relevant.\ 168""", 169 ), 170 ) 171 172 return issues