-
Notifications
You must be signed in to change notification settings - Fork 459
Match Conditions
Complete reference for all FlowSpec match conditions
RFC 5575 (IPv4) / RFC 8955 (IPv6)
- Overview
- Match Operators
- Destination Prefix
- Source Prefix
- IP Protocol
- Destination Port
- Source Port
- TCP Flags
- Packet Length
- ICMP Type
- ICMP Code
- DSCP
- Fragment
- Combining Conditions
- Best Practices
- Common Patterns
FlowSpec match conditions define which traffic to filter.
Basic structure:
announce flow route {
match {
<condition1>;
<condition2>;
<condition3>;
}
then {
<action>;
}
}Logic: All conditions must match (AND logic).
Example:
match {
source 10.0.0.0/8; # AND
destination-port =80; # AND
protocol =tcp; # AND
}This matches: TCP packets from 10.0.0.0/8 AND to port 80 AND protocol TCP.
FlowSpec supports numeric comparison operators:
| Operator | Meaning | Example |
|---|---|---|
=N |
Equals N | destination-port =80 |
>N |
Greater than N | packet-length >1500 |
<N |
Less than N | packet-length <64 |
>=N |
Greater or equal | source-port >=1024 |
<=N |
Less or equal | source-port <=65535 |
>=N&<=M |
Range (AND) | destination-port >=80&<=443 |
=N|=M |
Equals N OR M | destination-port =80|=443 |
>N&<M |
Greater N AND less M | packet-length >64&<1500 |
Important:
- Use
&for AND - Use
|for OR - Can combine multiple operators
Match packets destined for specific IP prefix
Syntax:
destination <prefix>Examples:
# IPv4 single host
match {
destination 100.10.0.100/32;
}
# IPv4 network
match {
destination 100.10.0.0/24;
}
# IPv6 single host
match {
destination 2001:db8::1/128;
}
# IPv6 network
match {
destination 2001:db8::/32;
}Use cases:
- Protect specific server IPs
- Protect entire subnets
- Protect anycast IPs
Example - Protect web server:
announce flow route {
match {
destination 100.10.0.100/32; # Web server IP
destination-port =80|=443; # HTTP/HTTPS
}
then {
rate-limit 100000000; # 100 Mbps max
}
}Match packets from specific IP prefix
Syntax:
source <prefix>Examples:
# Block single attacker
match {
source 203.0.113.50/32;
}
# Block entire network
match {
source 203.0.113.0/24;
}
# Block RFC 1918 private addresses (shouldn't be on internet)
match {
source 10.0.0.0/8;
}Use cases:
- Block known attackers
- Block spoofed sources
- Block geographic regions (via prefix lists)
- Block unwanted sources
Example - Block botnet C2:
announce flow route {
match {
source 198.51.100.0/24; # Known C2 network
}
then {
discard;
}
}Match specific IP protocol number
Syntax:
protocol =<number>
protocol =<name>Common protocols:
| Protocol | Number | Name |
|---|---|---|
| ICMP | 1 | icmp |
| IGMP | 2 | igmp |
| TCP | 6 | tcp |
| UDP | 17 | udp |
| GRE | 47 | gre |
| ESP | 50 | esp |
| AH | 51 | ah |
| ICMPv6 | 58 | icmpv6 |
Examples:
# Match TCP (numeric)
match {
protocol =6;
}
# Match TCP (name)
match {
protocol =tcp;
}
# Match UDP
match {
protocol =udp;
}
# Match ICMP
match {
protocol =icmp;
}
# Match GRE
match {
protocol =gre;
}Use cases:
- Block all ICMP during ICMP flood
- Rate-limit UDP (amplification attacks)
- Filter specific protocols
Example - Block all ICMP:
announce flow route {
match {
protocol =icmp;
}
then {
discard;
}
}Match destination port (TCP/UDP)
Syntax:
destination-port <operator><value>Examples:
# Exact port
destination-port =80
# Port 80 OR 443
destination-port =80|=443
# Ports above 1023 (ephemeral)
destination-port >1023
# Port range (80-443)
destination-port >=80&<=443
# Multiple specific ports
destination-port =80|=443|=8080|=8443
# Everything except 22 (complicated, use carefully)
destination-port <22|>22Common ports:
| Port | Service |
|---|---|
| 20, 21 | FTP |
| 22 | SSH |
| 23 | Telnet |
| 25 | SMTP |
| 53 | DNS |
| 80 | HTTP |
| 110 | POP3 |
| 143 | IMAP |
| 443 | HTTPS |
| 3306 | MySQL |
| 3389 | RDP |
| 5432 | PostgreSQL |
Use cases:
- Protect web servers (80, 443)
- Block attack on specific service
- Rate-limit DNS queries
Example - Protect web services:
announce flow route {
match {
destination 100.10.0.100/32;
destination-port =80|=443; # HTTP + HTTPS
protocol =tcp;
}
then {
rate-limit 100000000; # 100 Mbps
}
}Example - Block DNS amplification:
announce flow route {
match {
destination-port =53;
protocol =udp;
packet-length >512; # Large DNS responses
}
then {
discard;
}
}Match source port (TCP/UDP)
Syntax:
source-port <operator><value>Examples:
# Block DNS responses (source port 53)
source-port =53
# Block responses from common amplification vectors
source-port =53|=123|=1900 # DNS, NTP, SSDP
# Ephemeral ports (client connections)
source-port >=1024&<=65535
# Privileged ports
source-port <1024Use cases:
- Block amplification responses
- Identify server vs. client traffic
- Block specific service responses
Example - Block NTP amplification:
announce flow route {
match {
source-port =123; # NTP server response
protocol =udp;
packet-length >100; # Large NTP response (amplification)
}
then {
discard;
}
}Example - Block SSDP amplification:
announce flow route {
match {
source-port =1900; # SSDP
protocol =udp;
}
then {
discard;
}
}Match specific TCP flags
Syntax:
tcp-flags [ <flags> ]Available flags:
| Flag | Meaning |
|---|---|
fin |
FIN - Connection termination |
syn |
SYN - Connection establishment |
rst |
RST - Connection reset |
psh |
PSH - Push data immediately |
ack |
ACK - Acknowledgment |
urg |
URG - Urgent data |
Examples:
# SYN flag only (SYN flood)
tcp-flags [ syn ]
# SYN+ACK (normal handshake)
tcp-flags [ syn ack ]
# FIN flag
tcp-flags [ fin ]
# RST flag (connection reset)
tcp-flags [ rst ]
# All flags set (invalid, likely attack)
tcp-flags [ fin syn rst psh ack urg ]Use cases:
- SYN flood detection
- Invalid flag combinations
- Connection abuse
Example - Block SYN flood:
announce flow route {
match {
destination-port =80;
protocol =tcp;
tcp-flags [ syn ]; # SYN without ACK
}
then {
rate-limit 10000000; # 10 Mbps
}
}Example - Block XMAS scan (all flags):
announce flow route {
match {
protocol =tcp;
tcp-flags [ fin syn rst psh ack urg ]; # All flags
}
then {
discard;
}
}Example - Block NULL scan (no flags):
announce flow route {
match {
protocol =tcp;
# No flags specified = match no flags set
}
then {
discard;
}
}Match packet size in bytes
Syntax:
packet-length <operator><value>Examples:
# Exact size
packet-length =1500
# Larger than MTU (fragmented)
packet-length >1500
# Tiny packets (runt)
packet-length <64
# Normal range
packet-length >=64&<=1500
# Large packets only
packet-length >=1400Use cases:
- Block fragmented packets
- Block tiny packets (runt frames)
- Detect amplification (large responses)
- Filter specific packet sizes
Example - Block fragmented packets:
announce flow route {
match {
packet-length >1500; # Larger than standard MTU
}
then {
discard;
}
}Example - Block DNS amplification (large responses):
announce flow route {
match {
source-port =53;
protocol =udp;
packet-length >512; # DNS responses shouldn't be this large
}
then {
discard;
}
}Example - Block runt packets:
announce flow route {
match {
packet-length <64; # Below minimum Ethernet frame size
}
then {
discard;
}
}Match ICMP message type
Syntax:
icmp-type =<number>Common ICMP types:
| Type | Name | Description |
|---|---|---|
| 0 | Echo Reply | Ping response |
| 3 | Destination Unreachable | Cannot reach destination |
| 5 | Redirect | Route change |
| 8 | Echo Request | Ping |
| 11 | Time Exceeded | TTL expired |
| 13 | Timestamp | Timestamp request |
| 14 | Timestamp Reply | Timestamp response |
Examples:
# Block ping requests
icmp-type =8
# Block ping responses
icmp-type =0
# Block destination unreachable
icmp-type =3
# Block time exceeded
icmp-type =11Use cases:
- Block ICMP floods
- Block reconnaissance (ping sweeps)
- Block specific ICMP types
Example - Block ping:
announce flow route {
match {
protocol =icmp;
icmp-type =8; # Echo request
}
then {
discard;
}
}Example - Block ICMP flood (all types):
announce flow route {
match {
protocol =icmp;
# No icmp-type = match all types
}
then {
rate-limit 1000000; # 1 Mbps
}
}Match ICMP message code (sub-type)
Syntax:
icmp-code =<number>Common codes (for type 3 - Destination Unreachable):
| Code | Meaning |
|---|---|
| 0 | Network unreachable |
| 1 | Host unreachable |
| 2 | Protocol unreachable |
| 3 | Port unreachable |
| 4 | Fragmentation needed |
| 9 | Network administratively prohibited |
| 10 | Host administratively prohibited |
| 13 | Communication administratively prohibited |
Examples:
# Port unreachable
match {
protocol =icmp;
icmp-type =3;
icmp-code =3;
}
# Network unreachable
match {
protocol =icmp;
icmp-type =3;
icmp-code =0;
}Use cases:
- Filter specific ICMP error messages
- Block reconnaissance responses
Example - Block port unreachable:
announce flow route {
match {
protocol =icmp;
icmp-type =3; # Destination unreachable
icmp-code =3; # Port unreachable
}
then {
discard;
}
}Match Differentiated Services Code Point (QoS marking)
Syntax:
dscp =<value>Common DSCP values:
| DSCP | Name | Use |
|---|---|---|
| 0 | BE (Best Effort) | Default |
| 46 | EF (Expedited Forwarding) | Voice |
| 34 | AF41 | Video |
| 26 | AF31 | Signaling |
| 10 | AF11 | Bulk data |
Examples:
# Match best effort (default)
dscp =0
# Match expedited forwarding (voice)
dscp =46
# Match video
dscp =34Use cases:
- Filter by QoS class
- Rate-limit specific traffic classes
- Block marked attack traffic
Example - Rate-limit best effort during attack:
announce flow route {
match {
dscp =0; # Best effort
}
then {
rate-limit 10000000; # 10 Mbps
}
}Match packet fragmentation state
Syntax:
fragment [ <flags> ]Available flags:
| Flag | Meaning |
|---|---|
is-fragment |
Any fragment |
first-fragment |
First fragment only |
last-fragment |
Last fragment only |
not-a-fragment |
Not fragmented |
Examples:
# Any fragment
fragment [ is-fragment ]
# First fragment
fragment [ first-fragment ]
# Last fragment
fragment [ last-fragment ]
# Not fragmented
fragment [ not-a-fragment ]Use cases:
- Block all fragments (avoid fragmentation attacks)
- Allow only non-fragmented packets
- Filter specific fragment types
Example - Block all fragments:
announce flow route {
match {
fragment [ is-fragment ];
}
then {
discard;
}
}Example - Allow only non-fragmented:
announce flow route {
match {
fragment [ is-fragment ]; # Match fragments
}
then {
discard; # Drop them
}
}
# Non-fragmented packets pass throughNote: Fragment filtering can break legitimate traffic using large MTUs or IPv6 (which relies on fragmentation).
All conditions in a match block use AND logic.
announce flow route {
match {
source 10.0.0.0/8; # From 10.0.0.0/8 AND
destination 100.10.0.100/32; # To 100.10.0.100 AND
destination-port =80; # Port 80 AND
protocol =tcp; # TCP AND
tcp-flags [ syn ]; # SYN flag set
}
then {
discard;
}
}Matches: TCP SYN packets from 10.0.0.0/8 to 100.10.0.100:80.
announce flow route {
match {
destination 100.10.0.100/32;
destination-port =80|=443|=8080; # Port 80 OR 443 OR 8080
protocol =tcp;
}
then {
rate-limit 100000000;
}
}Matches: TCP to 100.10.0.100 on ports 80, 443, or 8080.
announce flow route {
match {
destination 100.10.0.0/24; # Target network AND
protocol =udp; # UDP AND
source-port =53; # From DNS servers AND
packet-length >512; # Large packets (amplification)
}
then {
discard;
}
}Matches: DNS amplification attack (UDP from port 53 with large packets).
Bad (too broad):
match {
protocol =tcp;
}
then {
discard;
}Blocks all TCP traffic (including SSH, database connections, etc.).
Good (specific):
match {
source 10.0.0.0/8;
destination-port =80;
protocol =tcp;
tcp-flags [ syn ];
}
then {
discard;
}Blocks only TCP SYN packets from 10.0.0.0/8 to port 80.
Always test FlowSpec rules in lab environment first:
# Test: rate-limit instead of discard
match {
destination 100.10.0.100/32;
destination-port =80;
}
then {
rate-limit 100000; # Low limit to test
}After confirming it works, increase rate or change to discard.
Bad (too broad):
source 0.0.0.0/0; # Entire internetGood (specific):
source 203.0.113.0/24; # Specific attack sourceLog when rules are announced:
import logging
logging.info(f"Blocking SYN flood from {attacker_ip}")
announce_flowspec(rule)Track metrics:
- Bandwidth before/after rule
- Number of packets blocked
- Attack duration
import threading
import time
def auto_withdraw(rule, timeout=300):
time.sleep(timeout)
withdraw = rule.replace('announce', 'withdraw')
sys.stdout.write(withdraw + "\n")
sys.stdout.flush()
# Announce with 5-minute timeout
rule = "announce flow route { ... }"
sys.stdout.write(rule + "\n")
sys.stdout.flush()
threading.Thread(target=auto_withdraw, args=(rule, 300)).start()match {
destination 100.10.0.100/32;
destination-port =80|=443;
protocol =tcp;
tcp-flags [ syn ];
}
then {
rate-limit 10000000; # 10 Mbps
}match {
source-port =53;
protocol =udp;
packet-length >512;
}
then {
discard;
}match {
source-port =123;
protocol =udp;
packet-length >100;
}
then {
discard;
}match {
protocol =icmp;
icmp-type =8; # Echo request
}
then {
rate-limit 1000000; # 1 Mbps
}match {
fragment [ is-fragment ];
}
then {
discard;
}match {
destination 100.10.0.100/32;
destination-port =80;
protocol =udp;
}
then {
discard;
}match {
destination 100.10.0.0/24;
tcp-flags [ syn ];
destination-port >=1&<=1024; # Scan privileged ports
}
then {
rate-limit 1000000;
}- FlowSpec Overview - Introduction to FlowSpec
- Actions Reference - What to do with matched traffic
- DDoS Mitigation Guide - Complete mitigation workflow
- Text API Reference - FlowSpec API commands
- API Commands - Command reference
- Quick Start - First FlowSpec rule
- Production Best Practices - Production deployment
Ready to define actions? See Actions Reference β
π» Ghost written by Claude (Anthropic AI)
π Home
π Getting Started
π§ API
π‘οΈ Use Cases
π Address Families
βοΈ Configuration
π Operations
π Reference
- Architecture
- BGP State Machine
- Communities (RFC)
- Extended Communities
- BGP Ecosystem
- Capabilities (AFI/SAFI)
- RFC Support
π Migration
π Community
π External
- GitHub Repo β
- Slack β
- Issues β
π» Ghost written by Claude (Anthropic AI)