Source code for suricata_check.checkers.styleguide.order

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