Skip to content

orbityaps/snortify

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 

Repository files navigation

Snort Rule Generator — Complete Reference

A fully client-side, zero-dependency HTML tool for building, editing, and copying Snort 2.9 IDS/IPS rules visually.


Table of Contents

  1. Overview
  2. Quick Start
  3. Understanding a Snort Rule
  4. Interface Layout
  5. Section Reference — Rule Header
  6. Section Reference — Rule Metadata
  7. Section Reference — Detection Options
  8. Section Reference — Advanced Options
  9. Right Panel — Live Output & Controls
  10. Quick Templates
  11. JavaScript Function Reference
  12. State Variables
  13. Event Binding System
  14. Syntax Highlighting System
  15. CSS Architecture & Design System
  16. Snort Rule Field Reference
  17. Common Workflows
  18. Troubleshooting

Overview

The Snort Rule Generator is a self-contained single HTML file (~1,300 lines) that allows network security analysts, SOC engineers, and students to construct valid Snort 2.9 detection rules without memorizing syntax. Every change to any form field instantly rebuilds and re-renders the rule output with full syntax highlighting.

Key characteristics:

  • Zero dependencies — no frameworks, no build tools, no server. Open the file in a browser and it works.
  • Fully client-side — nothing leaves your machine. Safe for use in air-gapped or restricted environments.
  • Live rule preview — the output panel updates on every keystroke or click.
  • Syntax-highlighted output — color-coded rule display for easy reading and review.
  • Six pre-built templates for the most common detection scenarios.
  • Editable raw output textarea for manual fine-tuning after generation.
  • Responsive layout that collapses gracefully to a single column on smaller screens.

Quick Start

  1. Download or save snort-rule-generator.html to your local machine.
  2. Open it in any modern browser (Chrome, Firefox, Edge, Safari).
  3. The tool loads with a default rule pre-populated: alert tcp any any -> any any (msg:"Suspicious activity detected"; sid:1000001; rev:1;)
  4. Modify fields in the left column. The rule in the right panel updates live.
  5. Click Copy Rule to copy the plain-text rule to your clipboard.
  6. Paste into your local.rules, snort.rules, or any Snort configuration file.

No internet connection is required after the initial page load (Google Fonts are the only external resource, and the tool functions perfectly without them if offline).


Understanding a Snort Rule

Every Snort rule has two parts: a header and an options body.

alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:"Example"; sid:1000001; rev:1;)
|_____|   |____________| |_|  |____________| |__________|  |___________________________________|
 Action    Source IP   S.Port  Dest IP        Dest Port              Options body
           Protocol           Direction

The generator assembles this structure from the fields you fill in. Every field maps directly to a position or keyword in the Snort rule grammar.


Interface Layout

The page is divided into two columns:

┌─────────────────────────────────────┬───────────────────┐
│  LEFT COLUMN (scrollable)           │  RIGHT COLUMN      │
│                                     │  (sticky)          │
│  ┌─────────────────────────────┐    │  ┌─────────────┐   │
│  │  Rule Header                │    │  │  Stats Bar  │   │
│  └─────────────────────────────┘    │  └─────────────┘   │
│  ┌─────────────────────────────┐    │  ┌─────────────┐   │
│  │  Rule Metadata              │    │  │ Live Output │   │
│  └─────────────────────────────┘    │  │  (terminal) │   │
│  ┌─────────────────────────────┐    │  └─────────────┘   │
│  │  Detection Options          │    │  ┌─────────────┐   │
│  └─────────────────────────────┘    │  │  Copy/Reset │   │
│  ┌─────────────────────────────┐    │  └─────────────┘   │
│  │  Advanced Options           │    │  ┌─────────────┐   │
│  └─────────────────────────────┘    │  │  Raw Output │   │
│                                     │  └─────────────┘   │
│                                     │  ┌─────────────┐   │
│                                     │  │  Templates  │   │
│                                     │  └─────────────┘   │
└─────────────────────────────────────┴───────────────────┘

The right column is position: sticky so the rule output is always visible while you scroll through the left column.


Section Reference — Rule Header

The Rule Header card defines the first line of every Snort rule — the part before the parentheses.

Action (dropdown)

Controls what Snort does when the rule matches.

Value Behavior
alert Generate an alert and log the packet. Most commonly used for detection.
log Log the packet only, no alert. Useful for passive recording.
pass Ignore the packet. Used to whitelist trusted traffic.
activate Alert and then activate a dynamic rule for subsequent packets.
dynamic Triggered by an activate rule; logs subsequent packets in the same stream.
drop Block the packet and log it (inline/IPS mode only).
reject Block the packet, log it, and send a TCP reset or ICMP unreachable (inline/IPS mode only).
sdrop Silently drop the packet without logging (inline/IPS mode only).

Default: alert

Protocol (dropdown)

The network protocol to inspect.

Value Description
tcp Transmission Control Protocol. Used for web, SSH, FTP, etc.
udp User Datagram Protocol. Used for DNS, SNMP, TFTP, etc.
icmp Internet Control Message Protocol. Used for ping, traceroute, etc.
ip Any IP protocol. Matches all IP traffic regardless of transport.

Default: tcp

Source IP (text input)

The IP address or network range that the traffic originates from. Accepts:

  • any — match all source IPs (no filtering).
  • A literal IP address: 192.168.1.100
  • A CIDR range: 192.168.1.0/24
  • A Snort variable: $HOME_NET, $EXTERNAL_NET, $HTTP_SERVERS, $SQL_SERVERS, etc.
  • A negated value using !: !192.168.1.0/24 (match anything except this range).
  • A grouped list: [192.168.1.0/24,10.0.0.0/8]

Default: any

Source Port (text input)

The port the traffic originates from. Accepts:

  • any — match all ports.
  • A single port number: 80
  • A port range: 1024:65535 (from 1024 to 65535), :1023 (up to 1023), 1024: (from 1024 up).
  • A negated port: !80
  • A grouped list: [80,443,8080]
  • Snort variables: $HTTP_PORTS, $SHELLCODE_PORTS, etc.

Default: any

Direction (toggle buttons)

Controls the directionality of traffic matching.

Option Symbol Meaning
One-way -> Traffic flows only from source to destination. This is the standard choice for most rules.
Bidirectional <> Traffic in both directions is inspected. Useful for monitoring sessions without knowing which side initiates.

Clicking either button updates dirVal (a module-level variable) and immediately triggers renderRule().

Destination IP (text input)

The IP address or network range of the traffic destination. Accepts the same formats as Source IP.

Default: any

Destination Port (text input)

The destination port. Accepts the same formats as Source Port.

Default: any


Section Reference — Rule Metadata

The Rule Metadata card fills the options body with identification and classification keywords.

Message — msg (text input)

A human-readable string that describes what the rule detects. This string appears in Snort alert logs, SIEMs, and SOC dashboards. It is the primary way analysts identify an alert.

  • Should be clear and descriptive: "WEB-ATTACKS SQL Injection Attempt"
  • Convention: prefix with a category in ALL CAPS: ET SCAN, SHELLCODE, WEB-ATTACKS, MALWARE-CNC
  • Colons and most special characters are allowed inside double quotes.
  • The generator automatically escapes double-quote characters inside the msg value.

Default: Suspicious activity detected

SID — sid (number input)

The Snort Identification Number. Every rule must have a unique SID.

SID Range Owner
1 – 999 Reserved
1000 – 999,999 Snort official rules
1,000,000 – 1,999,999 Sourcefire / Talos community
2,000,000+ Emerging Threats (ET)
Local rules typically start at 9,000,000+ Your organization

Default: 1000001

Revision — rev (number input)

An integer that increments each time the rule is modified. Snort uses the SID + rev combination to track rule versions. Always increment rev when editing an existing rule.

Default: 1

Priority (number input)

Overrides the priority assigned by classtype. Integer from 1 to 10, where 1 is highest severity.

  • Priority 1: Critical / immediate threat
  • Priority 2: High severity
  • Priority 3: Medium / informational

If left empty, the priority is inherited from the classtype definition (if set) or omitted from the rule.

GID — gid (number input)

Generator ID. Identifies which Snort component generated the event. Leave blank for standard rules (defaults to GID 1, the rules engine). Used primarily by preprocessors which use GIDs like 106 (stream5), 119 (http_inspect), etc.

Classtype (dropdown)

Associates the rule with a pre-defined attack category. Classtypes affect default priority and how alerts are grouped in reporting tools. The generator includes all 29 standard Snort classtypes:

Classtype Default Priority
attempted-admin 1
attempted-user 1
attempted-dos 2
attempted-recon 3
bad-unknown 2
default-login-attempt 2
denial-of-service 2
misc-activity 3
misc-attack 2
network-scan 3
not-suspicious 3
policy-violation 1
protocol-command-decode 3
shellcode-detect 1
string-detect 3
successful-admin 1
successful-dos 2
successful-recon-largescale 2
successful-recon-limited 3
successful-user 1
suspicious-filename-detect 2
suspicious-login 2
system-call-detect 2
tcp-connection 4
trojan-activity 1
unknown 3
unusual-client-port-connection 2
web-application-activity 3
web-application-attack 1

Section Reference — Detection Options

This card handles the payload and session inspection logic — the heart of any Snort rule.

Flow State (dropdown)

The flow keyword restricts the rule to packets matching a specific TCP session state and direction. This dramatically reduces false positives by ensuring the rule only fires on the expected side of a conversation.

Value Meaning
to_server,established Client sending data to server on an established TCP session. Standard choice for inspecting HTTP requests, POST bodies, form submissions.
to_client,established Server sending data back to the client. Used for detecting malicious responses, drive-by downloads, C2 responses.
from_server,established Alias for to_client,established.
from_client,established Alias for to_server,established.
established Any established session, either direction.
stateless Inspect all matching packets regardless of session state. Used for scanning detection where no full connection is expected.
not_established Only match packets that are NOT part of an established connection. Catches SYN floods, half-open scans.
to_server,stateless All packets toward the server, established or not.
to_client,stateless All packets toward the client, established or not.

HTTP Method (dropdown)

When set, adds content:"METHOD"; http_method to the options, restricting the rule to a specific HTTP request verb. Options: GET, POST, PUT, DELETE, HEAD, TRACE, OPTIONS, CONNECT, PATCH.

Requires an HTTP preprocessor (http_inspect) to be configured in snort.conf.

TCP Flags (toggle buttons)

Clickable flag tags that build the flags: keyword value. Multiple flags can be selected simultaneously. The resulting string concatenates their single-letter codes.

Tag Code Meaning
SYN S Synchronize — connection initiation
ACK A Acknowledge — confirming receipt
PSH P Push — send data immediately
RST R Reset — abort connection
FIN F Finish — graceful close
URG U Urgent — prioritized data
+ + Reserved bit set (unusual, potentially evasion)
any * Match any flags combination

Example: Selecting SYN + ACK produces flags:SA, which matches only SYN-ACK packets (server responding to a connection request).

Click behavior: Each tag is a <span> element. Clicking it calls the flags event listener, which toggles the flag's letter in the flagSelected Set and re-renders the rule. Active flags glow blue.

Content Matches

The most important part of most rules. Three types of match blocks can be added, in any order and any quantity.

Adding a match block

Three dashed "add" buttons at the bottom of the section:

  • + content — raw byte/string match in the packet payload.
  • + PCRE regex — Perl-Compatible Regular Expression match.
  • + uricontent — match specifically in the HTTP URI (requires http_inspect preprocessor).

Each click calls addContent(type), which pushes a new object into the contentItems array and calls renderContents().

content block

Used for exact string or hex-byte matching anywhere in the payload.

  • Input field: The string to match. Can be ASCII text or pipe-delimited hex bytes like |90 90 90|.
  • nocase toggle: Makes the string match case-insensitive. Adds nocase modifier.
  • rawbytes toggle: Ignores any preprocessor normalization. Inspects the raw packet bytes.
  • offset: Start searching from this byte position in the payload (0-indexed).
  • depth: Only search within this many bytes from the start (or from offset).
  • distance: After the previous content match, skip this many bytes before starting the next search.
  • within: After the previous content match, only search within this many bytes.

Offset and depth are absolute positions. Distance and within are relative to the previous content match — useful for chaining multiple patterns.

Example: Matching UNION followed by SELECT within 20 bytes:

content:"UNION"; nocase; content:"SELECT"; nocase; within:20;

pcre block

Matches the payload against a PCRE regular expression. The value field should contain the full PCRE expression including delimiters and flags, e.g. /union(\s|%20)+select/i.

PCRE flags can be toggled inline:

Flag Meaning
i Case-insensitive match
s . matches newlines too (single-line mode)
m ^ and $ match start/end of each line (multi-line mode)
x Allow whitespace and comments in the pattern
A Anchored — pattern must match at the current position
E $ matches only at the end of the string
G Ungreedy — quantifiers match as few characters as possible

The selected flag letters are appended to the pcre value during rule generation.

uricontent block

Functionally identical to content but restricts the match to the normalized HTTP request URI. Requires http_inspect to be active. Supports nocase and rawbytes modifiers but does not support offset/depth/distance/within (those apply to the full payload, not the URI-only buffer).

Removing a match block

Each block has a small × button in the top-right corner. Clicking it calls removeContent(i), which splices the item out of contentItems and re-renders.


Section Reference — Advanced Options

Threshold

Controls how many times a rule must fire before generating an alert, and over what time window. Used to suppress noisy rules or detect rate-based attacks.

Field Snort keyword part Description
Type type threshold / type limit / type both threshold fires once per N events; limit fires for the first N events only; both combines the behaviors.
Track by track by_src / track by_dst Whether the counter is per source IP or per destination IP.
Count count N Number of events required to trigger (or suppress after, for limit).
Seconds seconds N The sliding time window over which events are counted.

All four fields must be filled for the threshold: option to be included in the rule. If any one is blank, the threshold block is omitted.

Example config: type threshold, track by_src, count 10, seconds 60 — alert once if the source IP triggers this rule 10 times in 60 seconds.

TTL (IP)

Matches packets by their IP Time-To-Live value. Useful for detecting OS fingerprinting (different OSes use different default TTLs) or hop-count manipulation.

  • Operator: <, >, or =
  • Value: integer 0–255

Example: TTL < 5 generates ttl:<5 — catches packets that have been routed through many hops or packets deliberately crafted with a low TTL.

ICMP Type

Matches ICMP packets by their type field value (0–255).

Common ICMP types: 0 (Echo Reply), 3 (Destination Unreachable), 8 (Echo Request / ping), 11 (Time Exceeded).

  • Operator: <, >, or =
  • Value: integer 0–255

Generates keyword: itype:=8

ICMP Code

Matches the ICMP code subfield within an ICMP type. For example, ICMP type 3 (Destination Unreachable) has codes 0–15 indicating the specific reason.

  • Operator: <, >, or =
  • Value: integer 0–255

Generates keyword: icode:=0

Data Size (dsize)

Matches packets by the size of the payload data in bytes.

  • Operator: <, >, =, or <> (range, requires two values separated by <>)
  • Value: integer

Example: dsize:>512 fires only on packets with more than 512 bytes of payload — useful for DNS amplification detection.

IP Protocol (ip_proto)

Matches the IP protocol number in the IP header. Useful when using the ip protocol in the rule header to then filter by specific sub-protocols.

  • Operator: <, >, =, or ! (not equal)
  • Value: protocol number or name (6 for TCP, 17 for UDP, 1 for ICMP, 47 for GRE, etc.)

Generates keyword: ip_proto:=47

Detection Filter (text input)

A free-text field that maps directly to the detection_filter keyword — Snort's newer, more powerful alternative to threshold. Allows filtering based on rate of matching at the rule level.

Enter the full value string, for example: track by_src, count 5, seconds 60

This generates: detection_filter: track by_src, count 5, seconds 60

Unlike threshold, detection_filter does not generate an alert during the "ramp-up" period — it suppresses the alert entirely until the threshold is met.

References

External links that document the threat the rule detects. Each reference consists of a type and a value. References appear in Snort alert output and are clickable in some SIEMs.

Type Format Example value
url Full URL https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44228
cve CVE number 2021-44228
bugtraq BugTraq ID number 12345
ms Microsoft Security Bulletin MS08-067
bid BugTraq alternative 67890
nessus Nessus plugin ID 10176
arachnids Arachnids IDS alert ID 533
osvdb OSVDB vulnerability ID 60799

Click + add reference to add an entry. Each entry renders with a type dropdown and a value input. Click × to remove. Multiple references are allowed and each becomes a separate reference:type,value option.


Right Panel — Live Output & Controls

Stats Bar

Three metric tiles that update live as you build the rule:

  • Options — total count of keyword options in the current rule body (every key:value pair).
  • Matches — number of content/pcre/uricontent blocks added.
  • Refs — number of reference entries added.

These give a quick visual sense of rule complexity.

Live Output (Terminal panel)

The centerpiece of the right panel. Styled as a macOS-style terminal window (with red/yellow/green decorative dots). Displays the complete generated rule with syntax highlighting applied in real time.

Color coding of the rule output:

Color Token type Example
Red / bold Action keyword alert
Blue / bold Protocol tcp
Green IP addresses and ports $HOME_NET 80
Muted gray Direction arrow and punctuation -> ( ; )
Purple Option keywords msg sid content
Amber / orange Option values (non-string) 1000001 SA
Teal Quoted string values "Suspicious activity"

The colored output is rendered as HTML using <span> tags with CSS classes (t-action, t-proto, t-net, t-dir, t-key, t-val, t-str, t-punc). The raw plain-text version is stored on the DOM node as element._raw for clipboard copying.

Copy Rule button

Reads rule_out._raw (the unstyled plain-text version of the rule) and writes it to the system clipboard via navigator.clipboard.writeText(). On success, the button label changes to ✓ Copied! with a green glow animation for 2 seconds, then reverts.

Reset button

Calls resetAll(). Resets every field to its default value, clears all content matches, clears all references, clears TCP flag selections, and resets the direction toggle to one-way. The rule output updates immediately to the baseline default rule.

Raw Output (textarea)

An editable textarea that mirrors the generated rule in plain text. Normally read-only (marked with the readonly HTML attribute), it stays in sync with the live output.

Two buttons below it:

  • Edit — removes the readonly attribute, allowing you to type freely in the textarea and make manual adjustments that aren't available in the UI.
  • Rebuild — re-applies readonly and calls renderRule() to overwrite the textarea with a freshly generated rule from the current form state. Use this to discard manual edits and re-sync with the form.

Quick Templates

Six pre-built rule patterns that populate all relevant fields in one click, demonstrating best practices for common detection scenarios. Each template calls resetAll() first to clear any previous state.


Quick Templates

Port Scan Detection

Detects TCP SYN packets from the external network toward the internal network at a rate of more than 5 in 60 seconds from the same source — characteristic of Nmap and similar scanners.

Generated fields: action alert, proto tcp, src $EXTERNAL_NET, dst $HOME_NET, flow stateless, flags S, classtype network-scan, priority 2, threshold type threshold, track by_src, count 5, seconds 60, reference to nmap.org.

SQL Injection Alert

Detects GET requests to HTTP servers containing UNION SELECT (case-insensitive) in the payload, reinforced with a PCRE pattern that also catches URL-encoded variants (%20 instead of space).

Generated fields: action alert, proto tcp, dst $HTTP_SERVERS:$HTTP_PORTS, flow to_server,established, http_method GET, content UNION SELECT with nocase, PCRE /union(\s|%20)+select/i, classtype web-application-attack, priority 1, OWASP reference.

XSS Attempt

Detects two common XSS injection patterns in the URI: literal <script> tags and javascript: protocol handlers, both case-insensitive.

Generated fields: proto tcp, dst $HTTP_SERVERS:$HTTP_PORTS, flow to_server,established, two uricontent matches with nocase, classtype web-application-attack, OWASP reference.

Shellcode Detect

Detects x86 NOP sleds (consecutive 0x90 bytes) in TCP payloads larger than 128 bytes — a hallmark of classic buffer overflow exploits.

Generated fields: proto tcp, content |90 90 90 90 90 90 90 90| (hex-encoded NOP sled), PCRE /\x90{20,}/ (20+ consecutive NOPs), dsize >128, classtype shellcode-detect, priority 1.

DNS Amplification

Detects UDP packets directed at port 53 (DNS) with payload larger than 512 bytes — anomalously large DNS requests used in amplification DDoS attacks.

Generated fields: proto udp, dst port 53, dsize >512, threshold type threshold, track by_src, count 100, seconds 10, classtype attempted-dos, priority 2.

ICMP Flood

Detects ICMP Echo Request (ping) floods from a single source at a rate of more than 200 per second.

Generated fields: proto icmp, itype =8, icode =0, threshold type threshold, track by_src, count 200, seconds 1, classtype attempted-dos.


JavaScript Function Reference

All JavaScript is contained in a single <script> block at the bottom of the HTML file. There are no external scripts or module imports.


q(id)

function q(id){ return document.getElementById(id); }

A shorthand helper that wraps document.getElementById. Used throughout the codebase to avoid repetition.

Parameters: id — string ID of a DOM element. Returns: The DOM element, or null if not found.


val(id)

function val(id){ const el = q(id); return el ? el.value.trim() : ''; }

Retrieves the trimmed .value string from a form element. Returns an empty string if the element doesn't exist, which prevents null-reference errors during rule building.

Parameters: id — string ID of a form input, select, or textarea. Returns: Trimmed string value, or ''.


setDir(el)

function setDir(el){ ... dirVal = el.dataset.dir; renderRule(); }

Handles clicks on the direction toggle buttons. Removes the .active class from all .dir-opt elements, adds it to the clicked one, reads the data-dir attribute ("->" or "<>"), stores it in the module-level dirVal variable, then triggers a rule re-render.

Parameters: el — the clicked .dir-opt DOM element. Side effects: Updates dirVal, triggers renderRule().


addContent(type)

function addContent(type){ const id = ++contentId; contentItems.push({...}); renderContents(); }

Creates a new content match entry and adds it to the contentItems array. Increments the global contentId counter to generate a unique ID for the item. The new item is initialized with default values (val: '', nocase: false, rawbytes: false, all position modifiers empty).

Parameters: type — one of 'content', 'pcre', or 'uricontent'. Side effects: Pushes to contentItems, calls renderContents().


renderContents()

Re-renders the entire #content_list div from scratch using the current state of the contentItems array. Uses innerHTML assignment with a .map() that builds HTML strings for each item. After rendering, re-binds PCRE flag toggle event listeners (since those elements are dynamically created). Calls renderRule() at the end to update the output.

No parameters. Side effects: Mutates #content_list DOM, re-binds PCRE flag listeners, calls renderRule().


removeContent(i)

function removeContent(i){ contentItems.splice(i, 1); renderContents(); }

Removes the content item at array index i using splice. Then re-renders the content list and (indirectly) the rule.

Parameters: i — zero-based index into contentItems. Side effects: Mutates contentItems, calls renderContents().


escHtml(s)

function escHtml(s){ return s.replace(/&/g,'&amp;').replace(/"/g,'&quot;').replace(/</g,'&lt;'); }

Escapes HTML special characters in strings before embedding them in dynamically generated HTML markup (primarily for content match input values). Prevents XSS within the tool's own interface.

Parameters: s — raw string. Returns: HTML-safe escaped string.


addRef()

function addRef(){ refItems.push({ type:'url', val:'' }); renderRefs(); }

Adds a new blank reference entry to the refItems array with a default type of 'url'. Calls renderRefs() to update the DOM.

No parameters. Side effects: Pushes to refItems, calls renderRefs().


renderRefs()

Re-renders the #refs_list div from scratch using the current refItems array state. Each item becomes a flex row with a type dropdown and a text input. Inline onchange and oninput handlers directly mutate the corresponding refItems[i] properties. Calls renderRule() at the end.

No parameters. Side effects: Mutates #refs_list DOM, calls renderRule().


buildOptions()

The core rule-building function. Reads all form field values and constructs an array of option objects, each representing one keyword:value pair in the Snort rule body.

Each object has the shape:

{ k: 'keyword', v: 'value', mods: [...] }

Where mods is an optional array of modifier objects for content keywords (nocase, offset, depth, etc.).

The function proceeds in this order:

  1. msg (always first)
  2. flow (if set)
  3. TCP flags (if any selected)
  4. http_method content keyword (if set)
  5. All items from contentItems (including their modifiers)
  6. ttl (if operator and value both set)
  7. ip_proto (if set)
  8. itype / icode (ICMP, if set)
  9. dsize (if set)
  10. classtype (if set)
  11. priority (if set)
  12. All items from refItems (if value is non-empty)
  13. threshold (if all four fields are set)
  14. detection_filter (if set)
  15. gid (if set)
  16. sid (always)
  17. rev (always)

Returns: Array of option objects.


optsToStr(opts)

Converts the options array from buildOptions() into a flat semicolon-separated string suitable for embedding in the rule body.

For items with mods, the base keyword is emitted first, then each modifier is emitted on its own. Items with v === null are emitted as bare keywords (no colon or value).

Parameters: opts — array from buildOptions(). Returns: String like msg:"Example"; flow:established; content:"foo"; nocase; sid:1000001; rev:1


colorizeRule(action, proto, src_ip, src_port, dir, dst_ip, dst_port, opts)

Converts the rule components into a syntax-highlighted HTML string for display in the #rule_out div. Each token type is wrapped in a <span> with a CSS class:

  • Action → <span class="t-action">
  • Protocol → <span class="t-proto">
  • IP/port tokens → <span class="t-net">
  • Direction → <span class="t-dir">
  • Option keywords → <span class="t-key">
  • Quoted string values → <span class="t-str">
  • Non-string values → <span class="t-val">
  • Punctuation (:, ;, (, )) → <span class="t-punc">

Parameters: All rule header parts plus the opts array. Returns: HTML string with <span> tags for coloring.


renderRule()

The master update function. Called by every event listener and after every state mutation. Orchestrates the full render cycle:

  1. Reads all header field values via val().
  2. Calls buildOptions() to assemble the options array.
  3. Constructs the raw plain-text rule string using optsToStr().
  4. Sets rule_out.innerHTML to the colorized HTML from colorizeRule().
  5. Stores the raw string on rule_out._raw for clipboard access.
  6. If #raw_out is in read-only mode, updates its .value to the raw string.
  7. Updates the three stats bar counters.

No parameters. Side effects: Mutates #rule_out, #raw_out, #stat_opts, #stat_content, #stat_refs.


copyRule()

Reads the raw rule string from rule_out._raw (falling back to raw_out.value). Writes it to the clipboard using the async navigator.clipboard.writeText() API. On success, changes the button text to ✓ Copied!, adds the .copied CSS class (which triggers the green glow animation), and schedules a 2-second timeout to restore the original label.

No parameters. Side effects: Writes to clipboard, temporarily mutates Copy button DOM.


resetAll()

Resets the entire tool to its default state. Iterates over a hard-coded list of all field IDs and resets selects to index 0, sets msg and sid and rev to their defaults, and blanks all other inputs. Then:

  • Resets dirVal to "->".
  • Removes .active from all direction options, sets the first one active.
  • Clears flagSelected Set.
  • Removes .active from all flag tags.
  • Empties contentItems and refItems arrays.
  • Clears #content_list and #refs_list innerHTML.
  • Calls renderRule().

No parameters. Side effects: Full DOM and state reset.


loadTemplate(name)

Calls resetAll() first, then executes one of six template functions keyed by name string. Each template function directly sets DOM element values, pushes to contentItems/refItems as needed, and calls renderContents()/renderRefs()/renderRule() as appropriate.

Template keys: 'portscan', 'sqli', 'xss', 'shellcode', 'dns', 'icmp'.

Parameters: name — string key identifying the template. Side effects: Full reset followed by template-specific field population.


State Variables

These module-level variables hold runtime state between function calls:

Variable Type Initial Value Purpose
contentItems Array [] Stores all content/pcre/uricontent match block objects
refItems Array [] Stores all reference entry objects
flagSelected Set new Set() Stores the letter codes of currently active TCP flag tags
dirVal String '->' Current direction operator, updated by setDir()
contentId Number 0 Auto-incrementing counter used to generate unique IDs for content items

Event Binding System

Event listeners are attached in two ways:

Static bindings (bottom of script): A hard-coded array of 30 element IDs is iterated. Both input and change events are bound to renderRule() on each element. This covers all standard form fields.

['action','proto','src_ip', ... ].forEach(id => {
  const el = q(id);
  if(el) { el.addEventListener('input', renderRule); el.addEventListener('change', renderRule); }
});

Dynamic bindings (inside renderContents()): Because content items are created dynamically, their inner controls use inline oninput/onchange HTML attributes that directly mutate contentItems[i] properties. PCRE flag toggles are re-bound with addEventListener after each renderContents() call because they cannot use inline handlers (they need access to closure state).


Syntax Highlighting System

The rule output uses a two-step process:

  1. buildOptions() produces a structured array of token objects.
  2. colorizeRule() walks the token array and wraps each token in a typed <span>.

CSS classes in the .rule-display scope apply the colors:

.rule-display .t-action { color: #f96464; font-weight: 600; }  /* red, bold */
.rule-display .t-proto  { color: #4f9cf9; font-weight: 600; }  /* blue, bold */
.rule-display .t-net    { color: #3dd68c; }                     /* green */
.rule-display .t-dir    { color: var(--text3); }                /* muted gray */
.rule-display .t-key    { color: #b17cf5; }                     /* purple */
.rule-display .t-val    { color: #f5a623; }                     /* amber */
.rule-display .t-str    { color: #3dd8d8; }                     /* teal */
.rule-display .t-punc   { color: var(--text3); }                /* muted gray */

The distinction between t-val (amber) and t-str (teal) is: values that start with " are strings and get teal; all other values (numbers, keywords, operators) get amber.


CSS Architecture & Design System

The stylesheet is embedded in the <head> and uses CSS custom properties (variables) defined on :root for a consistent dark theme.

Color palette

Background layers:    --bg (#0d0f14) → --bg2 (#13161e) → --bg3 (#1a1e2a) → --bg4 (#21263a)
Borders:              --border (7% white) → --border2 (12%) → --border3 (18%)
Text:                 --text (#e8eaf2) → --text2 (#8b90a8) → --text3 (#565c78)
Accent (blue):        --accent (#4f9cf9), --accent2 (#2563c4), --accent-glow (15% alpha)
Status colors:        --green, --orange, --red, --purple, --teal + matching -bg variants

Typography

Two font families loaded from Google Fonts:

  • JetBrains Mono — used for all monospaced content: rule output, form inputs, labels, buttons. Weights 300/400/500/600.
  • Syne — used for headings and card titles. Weights 400/500/600/700.

Layout system

  • The page is constrained to max-width: 1200px and centered with auto margins.
  • The main content is a CSS Grid with 1fr 340px columns.
  • The right column is position: sticky with top: 24px.
  • Internal sections use utility grid classes: .grid2, .grid3, .grid4.

Responsive breakpoints

  • Below 900px: main grid collapses to single column, grid4 becomes grid2, direction arrow hides.
  • Below 600px: grid3 becomes grid2, rule header grid collapses to single column.

Animation

  • Card entrance: fadeSlideIn — each card fades in and slides up 6px with staggered animation-delay values (0.05s increments).
  • Content item entrance: same animation applied to dynamically rendered blocks.
  • Copy flash: copyFlash keyframe — expands and fades an outward glow ring in green when the Copy button is clicked.

Snort Rule Field Reference

Quick-reference for what each generated keyword does inside Snort's rule engine:

Keyword Section Description
msg Metadata Human-readable alert description string
sid Metadata Unique rule identifier number
rev Metadata Rule revision number
gid Metadata Generator ID (component that generates the event)
priority Metadata Override alert severity (1=highest)
classtype Metadata Associate rule with a threat category
reference Metadata Link to external documentation or CVE
flow Detection Restrict to specific TCP session state/direction
flags Detection Match TCP header flags
http_method Detection Match HTTP request method verb
content Detection Match a byte string in the packet payload
pcre Detection Match payload against a PCRE regex
uricontent Detection Match a string in the HTTP URI buffer
nocase Modifier Make preceding content match case-insensitive
rawbytes Modifier Inspect raw bytes, bypassing preprocessor normalization
offset Modifier Start content search at this byte offset
depth Modifier Limit content search to this many bytes
distance Modifier Relative offset from end of previous content match
within Modifier Window size relative to end of previous content match
ttl Advanced Match IP Time-To-Live value
ip_proto Advanced Match IP protocol number
itype Advanced Match ICMP message type
icode Advanced Match ICMP message code
dsize Advanced Match payload size in bytes
threshold Advanced Rate-based alerting and suppression
detection_filter Advanced Rate-based filtering at rule evaluation time

Common Workflows

Write a rule from scratch

  1. Open the tool in a browser.
  2. In Rule Header: select your action, protocol, and fill in source/destination IPs and ports. Use $ variables like $HOME_NET for flexibility.
  3. Choose direction (one-way for most rules).
  4. In Rule Metadata: write a clear msg, set a unique SID in the 9,000,000+ range for local rules, keep rev at 1, and choose an appropriate classtype.
  5. In Detection Options: set flow state (almost always to_server,established for inbound web traffic), add one or more content or pcre matches.
  6. Review the live output. Verify the rule looks correct.
  7. Click Copy Rule and paste into your rules file.

Start from a template and customize

  1. Click a template button on the right panel.
  2. The tool populates all fields with a working baseline rule.
  3. Modify the SID to your organization's range.
  4. Adjust the msg to match your environment's naming convention.
  5. Add or remove content matches as needed.
  6. Adjust threshold values to reduce false positives in your environment.
  7. Copy the rule.

Manually fine-tune the output

  1. Build the rule using the form.
  2. Click Edit under the Raw Output textarea.
  3. The textarea becomes editable — make your changes directly (add raw keywords, adjust spacing, etc.).
  4. Copy from the textarea directly.
  5. If you want to re-sync with the form, click Rebuild (this will overwrite your manual edits).

Test rule syntax understanding

  1. Open the tool.
  2. Click through different templates and observe how the output changes.
  3. Toggle TCP flags on and off and watch the flags: keyword update.
  4. Add multiple content blocks and observe chained modifiers like distance and within.
  5. Set a threshold and observe the complete threshold: option being built.

Troubleshooting

The Copy button doesn't work. The Clipboard API requires either HTTPS or localhost. If you open the file over a plain file:// path in some browsers (particularly older versions), clipboard access may be blocked. Try serving the file through a local web server (python3 -m http.server in the same directory) or use the Raw Output textarea to manually select and copy.

The rule is missing some options I expect. Most optional fields only appear in the output when they have a value. Check that both halves of compound fields (operator + value for TTL, ICMP, dsize) are filled. For threshold, all four fields (type, track, count, seconds) must be populated.

Content match modifiers aren't showing. Distance and within only appear if their inputs have values. They are positional and only make sense when there are multiple content matches in sequence.

The rule fails to load in Snort. Common causes: SID conflict with an existing rule (increment the SID), missing flow keyword (add flow:established to TCP rules), syntax error from special characters in msg (the tool escapes " but not all characters — avoid unescaped backslashes).

Google Fonts don't load (offline use). The tool works fully without the fonts — it falls back to the browser's default monospace and sans-serif. Only the typography changes, all functionality is unaffected.

PCRE flags aren't appearing in the output. PCRE flag toggles are re-bound after each renderContents() call. If you notice flags not registering, try clicking them again — the bind may have been missed if content was removed and re-added rapidly.


This README was written to match snort-rule-generator.html as generated. If you modify the HTML file, update the relevant sections above to keep documentation accurate.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages