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 0attack: FlowSpec source selection starts out precise, one rule per attacking source IP (each carrying whatever destination port it actually observed, including an explicit0— 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 todst_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/code0for an echo-request/ping flood) and narrows the announced FlowSpec rule to it, with no additional config -GET /api/v1/flowspec/ruleswill showicmp_types/icmp_codeson 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_codesexplicitly: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
>= 1400component. 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.