Skip to content

Match Conditions

Thomas Mangin edited this page Nov 13, 2025 · 4 revisions

FlowSpec Match Conditions Reference

Complete reference for all FlowSpec match conditions

RFC 5575 (IPv4) / RFC 8955 (IPv6)


Table of Contents


Overview

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.


Match Operators

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

Destination Prefix

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
    }
}

Source Prefix

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;
    }
}

IP Protocol

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;
    }
}

Destination Port

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|>22

Common 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;
    }
}

Source Port

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 <1024

Use 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;
    }
}

TCP Flags

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;
    }
}

Packet Length

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 >=1400

Use 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;
    }
}

ICMP Type

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 =11

Use 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
    }
}

ICMP Code

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;
    }
}

DSCP

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 =34

Use 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
    }
}

Fragment

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 through

Note: Fragment filtering can break legitimate traffic using large MTUs or IPv6 (which relies on fragmentation).


Combining Conditions

All conditions in a match block use AND logic.

Example 1: Specific Attack

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.


Example 2: Multiple Ports (OR Logic)

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.


Example 3: Complex Attack Pattern

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).


Best Practices

1. Be Specific

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.


2. Test Before Deploying

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.


3. Use Specific Prefixes

Bad (too broad):

source 0.0.0.0/0;  # Entire internet

Good (specific):

source 203.0.113.0/24;  # Specific attack source

4. Monitor Rule Effectiveness

Log 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

5. Auto-Expire Rules

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()

Common Patterns

SYN Flood Protection

match {
    destination 100.10.0.100/32;
    destination-port =80|=443;
    protocol =tcp;
    tcp-flags [ syn ];
}
then {
    rate-limit 10000000;  # 10 Mbps
}

DNS Amplification

match {
    source-port =53;
    protocol =udp;
    packet-length >512;
}
then {
    discard;
}

NTP Amplification

match {
    source-port =123;
    protocol =udp;
    packet-length >100;
}
then {
    discard;
}

ICMP Flood

match {
    protocol =icmp;
    icmp-type =8;  # Echo request
}
then {
    rate-limit 1000000;  # 1 Mbps
}

Block Fragmented Packets

match {
    fragment [ is-fragment ];
}
then {
    discard;
}

UDP Flood to Service

match {
    destination 100.10.0.100/32;
    destination-port =80;
    protocol =udp;
}
then {
    discard;
}

Port Scan Detection

match {
    destination 100.10.0.0/24;
    tcp-flags [ syn ];
    destination-port >=1&<=1024;  # Scan privileged ports
}
then {
    rate-limit 1000000;
}

Next Steps

Learn More

API Reference

Examples


Ready to define actions? See Actions Reference β†’


πŸ‘» Ghost written by Claude (Anthropic AI)

Clone this wiki locally