Skip to content

Rule Examples

Ready-to-use rules: blocks for common DDoS attack patterns. For field reference see RuleConfig and MatchConfig.


How rules work alongside group escalation

A group-level escalation: fires on total inbound BPS/PPS to any victim regardless of protocol. Rules add per-protocol/per-port escalation on top of that. Both can be active simultaneously for the same victim - a rule-triggered FlowSpec and a group-triggered blackhole can coexist.

The usual pattern is to use rules for surgical FlowSpec drops on specific attack vectors and keep the group-level escalation as a last-resort blackhole if total volume climbs past a higher threshold.


UDP amplification attacks

Amplification attacks send spoofed requests to open resolvers/services, which reply to the victim with large responses. The attack traffic arrives at the victim as UDP with a source port matching the abused service.

A single rule covering all common amplification source ports is usually sufficient:

rules:
  - name: "udp-amplification"
    match:
      protocol: 17
      src_ports: [0, 19, 53, 111, 123, 137, 161, 162, 389, 427, 1900, 3389, 3702, 10001, 11211, 20800, 27005, 32414]
    escalation:
      - level: 1
        condition:
          bps: 50m
        mitigation:
          type: flowspec
          flowspec:
            action: discard
        escalate_after: 0s

The ports above cover: chargen (19), DNS (53), portmapper (111), NTP (123), NetBIOS (137), SNMP (161/162), LDAP (389), Apple SSDP (427), SSDP (1900), RDP (3389), WS-Discovery (3702), Ubiquiti discovery (10001), Memcached (11211), Steam (20800/27005), and Plex (32414).

TCP SYN flood

A SYN flood sends a high volume of TCP SYN packets, exhausting connection state tables. Detected by matching the TCP SYN flag with a high PPS threshold.

rules:
  - name: "syn-flood"
    match:
      protocol: 6        # TCP
      tcp_flags: [SYN]
    escalation:
      - level: 1
        condition:
          pps: 100000    # 100k SYN/s - well above legitimate traffic
        mitigation:
          type: flowspec
          flowspec:
            action: discard
        escalate_after: 0s

The FlowSpec rule announced to the router will include a TCP-flags type-9 NLRI component, so only SYN packets are dropped - established sessions are unaffected.


TCP RST flood

RST floods target established TCP sessions and are often used to tear down connections. Match the RST flag independently.

rules:
  - name: "rst-flood"
    match:
      protocol: 6
      tcp_flags: [RST]
    escalation:
      - level: 1
        condition:
          pps: 50000
        mitigation:
          type: flowspec
          flowspec:
            action: discard
        escalate_after: 0s

Randomized-port flood (hping3-style)

Tools like hping3 can flood a target with a fixed packet size but a rotating (or explicitly zeroed) destination port, e.g. hping3 --flood --destport 0 --data 100 <victim>. Don't guess at a dst_ports value for this - there isn't a stable one to match. A protocol-only rule with a high PPS threshold is enough; flowwler figures out the rest at mitigation time:

rules:
  - name: "udp-signature-flood"
    match:
      protocol: 17       # UDP; use 6 for a TCP-based variant
    escalation:
      - level: 1
        condition:
          pps: 200000
        mitigation:
          type: flowspec
          flowspec:
            action: discard
        escalate_after: 0s

What happens for an hping3 --destport 0 attack: FlowSpec source selection starts out precise, one rule per attacking source IP (each carrying whatever destination port it actually observed, including an explicit 0 — which is a real match criterion, not "any port"). As the mitigation refreshes every 5 seconds, flowwler's cross-tick source-persistence tracking notices that the visible source IPs aren't the same machines sending repeatedly - each tick's sources are mostly new. Once that's confirmed (a few consecutive high-churn refreshes), flowwler automatically switches to a single, source-agnostic rule scoped to dst_ports: [0] (or whichever port/short list is actually stable across sources) instead of continuing to chase a rotating set of per-source rules. No config is needed to enable this — it's the same consolidation search FlowSpec uses for any oversized or rotating source set, just triggered here by persistence rather than raw source count.


ICMP flood

Volumetric ICMP floods (ping floods, ICMP fragmentation attacks) can be suppressed surgically without touching other protocols. ICMP has no ports, so there's no dst_ports/src_ports to configure here - protocol: 1 (ICMPv6 = 58) is the only match criterion needed:

rules:
  - name: "icmp-flood"
    match:
      protocol: 1        # ICMP (ICMPv6 = 58)
    escalation:
      - level: 1
        condition:
          pps: 100000
        mitigation:
          type: flowspec
          flowspec:
            action: discard
        escalate_after: 0s

flowwler automatically detects and matches the specific ICMP type/code observed in the attack traffic (e.g. type 8/code 0 for an echo-request/ping flood) and narrows the announced FlowSpec rule to it, with no additional config - GET /api/v1/flowspec/rules will show icmp_types/icmp_codes on the live rule once traffic is flowing. A mixed batch of ICMP traffic (multiple types/codes observed) is matched as a short OR'd list rather than collapsing to "any ICMP", the same value-set behavior used for ports.

To pin the rule to a specific ICMP type/code instead of relying on auto-detection — e.g. only ever match echo-request, ignoring destination-unreachable or other ICMP noise on the same victim — set match.icmp_types/match.icmp_codes explicitly: match: {protocol: 1, icmp_types: [8]}. This also narrows detection matching (the rule only triggers on the configured type/code), not just the announced FlowSpec rule.


IP fragment flood

Fragmented packet floods aim to exhaust reassembly buffers. The fragments: true match adds a FlowSpec type-12 is-fragment NLRI component.

rules:
  - name: "fragment-flood"
    match:
      fragments: true
    escalation:
      - level: 1
        condition:
          pps: 50000
        mitigation:
          type: flowspec
          flowspec:
            action: discard
        escalate_after: 0s

SIP flooding

SIP bombing floods a gateway with a high volume of SIP messages (INVITE, REGISTER, OPTIONS, etc.) to exhaust call-processing capacity. At the flow level, SIP request type is not visible - detection is based on PPS to the SIP signalling ports. SIP messages are small UDP packets, so attacks present as high PPS with relatively low BPS.

rules:
  - name: "sip-flood"
    match:
      protocol: 17       # UDP (use 6 for TCP SIP)
      dst_ports: [5060, 5061]
    escalation:
      - level: 1
        condition:
          pps: 10000
        mitigation:
          type: flowspec
          flowspec:
            action: discard
        escalate_after: 0s

FlowSpec drops are per-source, so legitimate SIP peers not contributing to the flood continue to reach the gateway. For environments where the set of valid SIP peers is small and fixed, a BGP blackhole on the gateway IP combined with static allowlist routes for known peers may be more effective.


HTTP/HTTPS flood

Application-layer floods on port 80/443. At the flow level these are detectable by the volume of TCP connections to the web ports.

rules:
  - name: "http-flood"
    match:
      protocol: 6
      dst_ports: [80, 443, 8080, 8443]
    escalation:
      - level: 1
        condition:
          pps: 200000    # 200k req/s of pure SYN traffic is a flood
        mitigation:
          type: flowspec
          flowspec:
            action: rate-limit
            rate_limit_bps: 100m    # rate-limit rather than hard-drop for web traffic
        escalate_after: 2m
      - level: 2
        condition:
          pps: 500000
        mitigation:
          type: flowspec
          flowspec:
            action: discard
        escalate_after: 0s

Large packet flood

Volumetric floods using near-MTU-sized packets (1400–1500 bytes) deliver maximum bandwidth with minimum packet rate. Per-BPS thresholds catch these, but a pkt_len match makes the FlowSpec rule more precise — only packets in the attack size range are dropped, protecting legitimate large transfers from unrelated sources. This works even against exporters with no native packet-length fields (e.g. most NetFlow v9 templates and MikroTik's NetFlow v5): flowwler falls back to an average derived from bytes/packets — see PktLenRange.

rules:
  - name: "large-packet-flood"
    match:
      pkt_len:
        min: 1400         # match flows where observed packets are >= 1400 bytes
    escalation:
      - level: 1
        condition:
          bps: 5g
        mitigation:
          type: flowspec
          flowspec:
            action: discard
        escalate_after: 0s

The announced FlowSpec NLRI includes a type-10 packet-length >= 1400 component. Only packets within the specified size range are dropped; smaller packets from the same source continue to pass.


Carpet bomb detection

A carpet bomb attack spreads traffic across many victim IPs in a subnet rather than concentrating on one host. Per-IP thresholds never fire because no single victim receives enough traffic. The match.subnet field enables subnet-level aggregation: BPS/PPS is summed across all victims in the configured prefix, and min_victims gates the rule so a single high-rate host does not trigger it.

rules:
  - name: "carpet-bomb"
    match:
      subnet:
        ipv4: 24          # aggregate per /24; 0 = use group subnet size
        ipv6: 48          # aggregate per /48; 0 = use group subnet size
        min_victims: 3    # at least 3 distinct victims must be hit
    escalation:
      - level: 1
        condition:
          bps: 20g        # aggregate BPS across all victims in the /24
        mitigation:
          type: subnet-blackhole
          subnet-blackhole:
            community: "65535:666"
        escalate_after: 0s

The mitigation is always a subnet-level action (subnet-blackhole or flowspec destination-only). The derived subnet prefix is the same one used for aggregation: the /24 that contains the victim addresses.


FlowSpec with upstream community tagging

By default FlowSpec rules are local — your upstream does not see them. Add a community to control which rules propagate upstream via your router's BGP import/export policy. Set the community on higher escalation levels only, so low-volume events stay local while large attacks are pushed upstream.

rules:
  - name: "udp-flood"
    match:
      protocol: 17
    escalation:
      - level: 1
        condition:
          bps: 500m
        mitigation:
          type: flowspec
          flowspec:
            action: discard
            # no community — handled locally, upstream does not receive this rule

      - level: 2
        condition:
          bps: 5g
        mitigation:
          type: flowspec
          flowspec:
            action: discard
            community: "65000:100"   # upstream import policy permits FlowSpec with this tag

Both standard (AS:VALUE) and large (ASN:Local1:Local2, RFC 8092) community formats are accepted.