Source code for suricata_check.checkers.styleguide._order

  1"""`OrderChecker`."""
  2
  3import logging
  4from types import MappingProxyType
  5
  6from suricata_check.checkers.interface import CheckerInterface
  7from suricata_check.utils.checker import (
  8    are_rule_options_put_before,
  9    count_rule_options,
 10    get_rule_keyword_sequences,
 11    get_rule_option_position,
 12    is_rule_option_always_put_before,
 13    is_rule_option_first,
 14    is_rule_option_put_before,
 15    is_rule_option_set,
 16)
 17from suricata_check.utils.checker_typing import ISSUES_TYPE, Issue
 18from suricata_check.utils.regex import (
 19    ALL_DETECTION_KEYWORDS,
 20    ALL_TRANSFORMATION_KEYWORDS,
 21    BUFFER_KEYWORDS,
 22    CONTENT_KEYWORDS,
 23    FLOW_STREAM_KEYWORDS,
 24    MODIFIER_KEYWORDS,
 25    OTHER_PAYLOAD_KEYWORDS,
 26    PERFORMANCE_DETECTION_OPTIONS,
 27    POINTER_MOVEMENT_KEYWORDS,
 28    SIZE_KEYWORDS,
 29    TRANSFORMATION_KEYWORDS,
 30    get_rule_body,
 31)
 32from suricata_check.utils.regex_provider import get_regex_provider
 33from suricata_check.utils.rule import Rule
 34
 35_regex_provider = get_regex_provider()
 36
 37
 38# Regular expressions are placed here such that they are compiled only once.
 39# This has a significant impact on the performance.
 40REGEX_S210 = _regex_provider.compile(
 41    r"^\(.*content\s*:.*;\s*content\s*:.*;.*(depth|offset)\s*:.*\)$",
 42)
 43
 44
[docs] 45class OrderChecker(CheckerInterface): 46 """The `OrderChecker` contains several checks on the ordering Suricata options. 47 48 Note that the correct ordering of detection options is as follows: 49 1. Buffer 50 2. Size 51 3. Transformation 52 4. Content 53 5. Pointer movement 54 6. Fast pattern 55 7. Nocase 56 8. Other payload options 57 58 Codes S200-S209 report on the non-standard ordering of common options. 59 60 Codes S210-S219 report on the non-standard ordering of content matches. 61 62 Codes S220-S229 report on the non-standard ordering of flow options. 63 64 Codes S230-S239 report on the non-standard ordering of detection options. 65 66 Codes S240-S249 report on the non-standard ordering of threshold options. 67 """ 68 69 codes = MappingProxyType( 70 { 71 "S200": {"severity": logging.INFO}, 72 "S201": {"severity": logging.INFO}, 73 "S202": {"severity": logging.INFO}, 74 "S203": {"severity": logging.INFO}, 75 "S204": {"severity": logging.INFO}, 76 "S205": {"severity": logging.INFO}, 77 "S206": {"severity": logging.INFO}, 78 "S207": {"severity": logging.INFO}, 79 "S208": {"severity": logging.INFO}, 80 "S210": {"severity": logging.INFO}, 81 "S211": {"severity": logging.INFO}, 82 "S212": {"severity": logging.INFO}, 83 "S220": {"severity": logging.INFO}, 84 "S221": {"severity": logging.INFO}, 85 "S222": {"severity": logging.INFO}, 86 "S223": {"severity": logging.INFO}, 87 "S224": {"severity": logging.INFO}, 88 "S230": {"severity": logging.INFO}, 89 "S231": {"severity": logging.INFO}, 90 "S232": {"severity": logging.INFO}, 91 "S233": {"severity": logging.INFO}, 92 "S234": {"severity": logging.INFO}, 93 "S235": {"severity": logging.INFO}, 94 "S236": {"severity": logging.INFO}, 95 "S240": {"severity": logging.INFO}, 96 "S241": {"severity": logging.INFO}, 97 }, 98 ) 99 100 def _check_rule( # noqa: C901, PLR0912, PLR0915 101 self: "OrderChecker", 102 rule: Rule, 103 ) -> ISSUES_TYPE: 104 issues: ISSUES_TYPE = [] 105 106 body = get_rule_body(rule) 107 108 if is_rule_option_first(rule, "msg") is not True: 109 issues.append( 110 Issue( 111 code="S200", 112 message="""The rule body does not have msg as the first option. 113Consider reording to make msg the first option.""", 114 ), 115 ) 116 117 if is_rule_option_put_before(rule, "reference", ("content", "pcre")) is True: 118 issues.append( 119 Issue( 120 code="S201", 121 message="""The rule body contains the reference option before the detection logic. 122Consider reording to put the detection logic directly after the msg option.""", 123 ), 124 ) 125 126 if is_rule_option_put_before(rule, "classtype", ("reference",)) is True: 127 issues.append( 128 Issue( 129 code="S202", 130 message="""The rule body contains the classtype option before the reference option. 131Consider reording to put the classtype option directly after the reference option.""", 132 ), 133 ) 134 135 if is_rule_option_put_before(rule, "classtype", ("content", "pcre")) is True: 136 issues.append( 137 Issue( 138 code="S203", 139 message="""The rule body contains the classtype option before the detection logic. 140Consider reording to put the classtype option directly after the detection logic.""", 141 ), 142 ) 143 144 if is_rule_option_put_before(rule, "sid", ("classtype",)) is True: 145 issues.append( 146 Issue( 147 code="S204", 148 message="""The rule body contains the sid option before the classtype option. 149Consider reording to put the sid option directly after the classtype option.""", 150 ), 151 ) 152 153 if is_rule_option_put_before(rule, "sid", ("reference",)) is True: 154 issues.append( 155 Issue( 156 code="S205", 157 message="""The rule body contains the sid option before the reference option. 158Consider reording to put the sid option directly after the reference option.""", 159 ), 160 ) 161 162 if is_rule_option_put_before(rule, "sid", ("content", "pcre")) is True: 163 issues.append( 164 Issue( 165 code="S206", 166 message="""The rule body contains the sid option before the detection logic. 167Consider reording to put the sid option directly after the detection logic.""", 168 ), 169 ) 170 171 if is_rule_option_put_before(rule, "rev", ("sid",)) is True: 172 issues.append( 173 Issue( 174 code="S207", 175 message="""The rule body contains the rev option before the sid option. 176Consider reording to put the rev option directly after the sid option.""", 177 ), 178 ) 179 180 if is_rule_option_put_before(rule, "metadata", ("sid", "rev")) is True: 181 issues.append( 182 Issue( 183 code="S208", 184 message="""The rule body contains does not have the metadata option as the last option. 185Consider making metadata the last option.""", 186 ), 187 ) 188 189 if ( 190 REGEX_S210.match( 191 body, 192 ) 193 is not None 194 ): 195 issues.append( 196 Issue( 197 code="S210", 198 message="""The rule body contains a content matches modified by depth or offset \ 199that is not the first content match. 200Consider moving the modified content match to the beginning of the detection options.""", 201 ), 202 ) 203 204 if count_rule_options(rule, "depth") > 1: 205 issues.append( 206 Issue( 207 code="S211", 208 message="""The rule body contains more than one content matche modified by depth. 209Consider making the second content match relative to the first using the within option.""", 210 ), 211 ) 212 213 if count_rule_options(rule, "offset") > 1: 214 issues.append( 215 Issue( 216 code="S212", 217 message="""The rule body contains more than one content matche modified by offset. 218Consider making the second content match relative to the first using the distance option.""", 219 ), 220 ) 221 222 if ( 223 is_rule_option_set(rule, "flow") 224 and get_rule_option_position(rule, "flow") != 1 225 ): 226 issues.append( 227 Issue( 228 code="S220", 229 message="""The rule flow option is set but not directly following the msg option. 230Consider moving the flow option to directly after the msg option.""", 231 ), 232 ) 233 234 if ( 235 is_rule_option_always_put_before( 236 rule, 237 "flow", 238 FLOW_STREAM_KEYWORDS, 239 ) 240 is False 241 ): 242 issues.append( 243 Issue( 244 code="S221", 245 message="""The rule contains flow or stream keywords before the flow option in the rule body. 246Consider moving the flow option to before the flow and/or stream keywords.""", 247 ), 248 ) 249 250 if ( 251 are_rule_options_put_before( 252 rule, 253 ("content", "pcre"), 254 FLOW_STREAM_KEYWORDS, 255 ) 256 is True 257 ): 258 issues.append( 259 Issue( 260 code="S222", 261 message="""The rule contains flow or stream keywords after content buffers or detection logic. 262Consider moving the flow and/or stream keywords to before content buffers and detection options.""", 263 ), 264 ) 265 266 if ( 267 is_rule_option_put_before( 268 rule, 269 "urilen", 270 FLOW_STREAM_KEYWORDS, 271 ) 272 is True 273 ): 274 issues.append( 275 Issue( 276 code="S223", 277 message="""The rule contains the urilen option before the flow or stream keywords in the rule body. 278Consider moving the urilen option to after the flow and/or stream keywords.""", 279 ), 280 ) 281 282 if ( 283 is_rule_option_always_put_before( 284 rule, 285 "urilen", 286 ("content", "pcre"), 287 ) 288 is False 289 ): 290 issues.append( 291 Issue( 292 code="S224", 293 message="""The rule contains the urilen option after content buffers or detection logic. 294Consider moving the urilen option to before content buffers and detection options.""", 295 ), 296 ) 297 298 # Detects pointer movement before any content or buffer option or between a buffer and a content option. 299 for sequence in get_rule_keyword_sequences( 300 rule, 301 seperator_keywords=CONTENT_KEYWORDS, 302 ): 303 if ( 304 are_rule_options_put_before( 305 rule, 306 POINTER_MOVEMENT_KEYWORDS, 307 set(CONTENT_KEYWORDS).union(BUFFER_KEYWORDS), 308 sequence=sequence, 309 ) 310 is True 311 ): 312 issues.append( 313 Issue( 314 code="S230", 315 message="""The rule contains pointer movement before the content option in sequence {}. 316Consider moving the pointer movement options to after the content option.""".format( 317 sequence, 318 ), 319 ), 320 ) 321 322 # Detects fast_pattern before any content or buffer option or between a buffer and a content option. 323 for sequence in get_rule_keyword_sequences( 324 rule, 325 seperator_keywords=CONTENT_KEYWORDS, 326 ): 327 if ( 328 is_rule_option_put_before( 329 rule, 330 "fast_pattern", 331 set(SIZE_KEYWORDS) 332 .union(ALL_TRANSFORMATION_KEYWORDS) 333 .union(CONTENT_KEYWORDS) 334 .union(POINTER_MOVEMENT_KEYWORDS), 335 sequence=sequence, 336 ) 337 is True 338 ): 339 issues.append( 340 Issue( 341 code="S231", 342 message="""The rule contains the fast_pattern option before \ 343size options, transformation options, the content option or pointer movement options in sequence {}. 344Consider moving the fast_pattern option to after \ 345size options, transformation options, the content option or pointer movement options.""".format( 346 sequence, 347 ), 348 ), 349 ) 350 351 # Detects no_case before any content or buffer option or between a buffer and a content option. 352 for sequence in get_rule_keyword_sequences( 353 rule, 354 seperator_keywords=CONTENT_KEYWORDS, 355 ): 356 if ( 357 is_rule_option_put_before( 358 rule, 359 "nocase", 360 set(SIZE_KEYWORDS) 361 .union(ALL_TRANSFORMATION_KEYWORDS) 362 .union(CONTENT_KEYWORDS) 363 .union(POINTER_MOVEMENT_KEYWORDS) 364 .union(PERFORMANCE_DETECTION_OPTIONS), 365 sequence=sequence, 366 ) 367 is True 368 ): 369 issues.append( 370 Issue( 371 code="S232", 372 message="""The rule contains the nocase option before \ 373size options, transformation options, the content option, pointer movement options, or fast_pattern option in sequence {}. 374Consider moving the nocase option to after \ 375size options, transformation options, the content option, pointer movement options, or fast_pattern option.""".format( 376 sequence, 377 ), 378 ), 379 ) 380 381 # Detects modifier options before any content or buffer option or between a buffer and a content option. 382 for sequence in get_rule_keyword_sequences( 383 rule, 384 seperator_keywords=CONTENT_KEYWORDS, 385 ): 386 if ( 387 are_rule_options_put_before( 388 rule, 389 MODIFIER_KEYWORDS, 390 set(CONTENT_KEYWORDS), 391 sequence=sequence, 392 ) 393 is True 394 ): 395 issues.append( 396 Issue( 397 code="S233", 398 message="""The rule contains modifier options before the content option. 399Consider moving the modifier options to after the content option.""", 400 ), 401 ) 402 403 # Detects other detection options before any content or buffer option or between a buffer and a content option. 404 for sequence in get_rule_keyword_sequences( 405 rule, 406 seperator_keywords=CONTENT_KEYWORDS, 407 ): 408 if ( 409 are_rule_options_put_before( 410 rule, 411 OTHER_PAYLOAD_KEYWORDS, 412 set(CONTENT_KEYWORDS).union(BUFFER_KEYWORDS), 413 sequence=sequence, 414 ) 415 is True 416 ): 417 issues.append( 418 Issue( 419 code="S234", 420 message="""The rule contains other detection options before \ 421size options, transformation options, the content option, pointer movement options, nocase option, or fast_pattern option. 422Consider moving the other detection options to after \ 423size options, transformation options, the content option, pointer movement options, nocase option, or fast_pattern option.""", 424 ), 425 ) 426 427 # Detects size options after any transformation options, content option or other detection options. 428 for sequence in get_rule_keyword_sequences( 429 rule, 430 seperator_keywords=CONTENT_KEYWORDS, 431 ): 432 if ( 433 are_rule_options_put_before( 434 rule, 435 set(TRANSFORMATION_KEYWORDS) 436 .union(CONTENT_KEYWORDS) 437 .union(OTHER_PAYLOAD_KEYWORDS), 438 SIZE_KEYWORDS, 439 sequence=sequence, 440 ) 441 is True 442 ): 443 issues.append( 444 Issue( 445 code="S235", 446 message="""The rule contains other size options after \ 447any transformation options, content option or other detection options. 448Consider moving the size options to after any transformation options, content option or other detection options""", 449 ), 450 ) 451 452 # Detects transformation options after any content option or other detection options. 453 for sequence in get_rule_keyword_sequences( 454 rule, 455 seperator_keywords=CONTENT_KEYWORDS, 456 ): 457 if ( 458 are_rule_options_put_before( 459 rule, 460 set(CONTENT_KEYWORDS).union(OTHER_PAYLOAD_KEYWORDS), 461 TRANSFORMATION_KEYWORDS, 462 sequence=sequence, 463 ) 464 is True 465 ): 466 issues.append( 467 Issue( 468 code="S236", 469 message="""The rule contains other transformation options after \ 470any content option or other detection options. 471Consider moving the transformation options to after any content option or other detection options""", 472 ), 473 ) 474 475 if ( 476 is_rule_option_put_before( 477 rule, 478 "threshold", 479 ALL_DETECTION_KEYWORDS, 480 ) 481 is True 482 ): 483 issues.append( 484 Issue( 485 code="S240", 486 message="""The rule contains the threshold option before some detection option. 487Consider moving the threshold option to after the detection options.""", 488 ), 489 ) 490 491 if ( 492 is_rule_option_always_put_before( 493 rule, 494 "threshold", 495 ("reference", "sid"), 496 ) 497 is False 498 ): 499 issues.append( 500 Issue( 501 code="S241", 502 message="""The rule contains the threshold option after the reference and/or sid option. 503Consider moving the threshold option to before the reference and sid options.""", 504 ), 505 ) 506 507 return issues