# FlowSpec Match Conditions Reference **Complete reference for all FlowSpec match conditions** > RFC 5575 (IPv4) / RFC 8955 (IPv6) --- ## Table of Contents - [Overview](#overview) - [Match Operators](#match-operators) - [Destination Prefix](#destination-prefix) - [Source Prefix](#source-prefix) - [IP Protocol](#ip-protocol) - [Destination Port](#destination-port) - [Source Port](#source-port) - [TCP Flags](#tcp-flags) - [Packet Length](#packet-length) - [ICMP Type](#icmp-type) - [ICMP Code](#icmp-code) - [DSCP](#dscp) - [Fragment](#fragment) - [Combining Conditions](#combining-conditions) - [Best Practices](#best-practices) - [Common Patterns](#common-patterns) --- ## Overview FlowSpec match conditions define **which traffic** to filter. **Basic structure:** ```python announce flow route { match { ; ; ; } then { ; } } ``` **Logic:** All conditions must match (AND logic). **Example:** ```python 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` | 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&64&<1500` | **Important:** - Use `&` for AND - Use `|` for OR - Can combine multiple operators --- ## Destination Prefix **Match packets destined for specific IP prefix** **Syntax:** ```python destination ``` **Examples:** ```python # 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:** ```python announce flow route { match { destination 100.10.0.100/32; # Web server IP destination-port =80|=443; # HTTP/HTTPS } then { rate-limit 100000000; # 100 MB/s (~800 Mbps) } } ``` --- ## Source Prefix **Match packets from specific IP prefix** **Syntax:** ```python source ``` **Examples:** ```python # 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:** ```python announce flow route { match { source 198.51.100.0/24; # Known C2 network } then { discard; } } ``` --- ## IP Protocol **Match specific IP protocol number** **Syntax:** ```python protocol = protocol = ``` **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:** ```python # 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:** ```python announce flow route { match { protocol =icmp; } then { discard; } } ``` --- ## Destination Port **Match destination port (TCP/UDP)** **Syntax:** ```python destination-port ``` **Examples:** ```python # 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:** ```python announce flow route { match { destination 100.10.0.100/32; destination-port =80|=443; # HTTP + HTTPS protocol =tcp; } then { rate-limit 100000000; # 100 MB/s (~800 Mbps) } } ``` **Example - Block DNS amplification:** ```python 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:** ```python source-port ``` **Examples:** ```python # 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:** ```python 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:** ```python announce flow route { match { source-port =1900; # SSDP protocol =udp; } then { discard; } } ``` --- ## TCP Flags **Match specific TCP flags** **Syntax:** ```python tcp-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:** ```python # 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:** ```python announce flow route { match { destination-port =80; protocol =tcp; tcp-flags [ syn ]; # SYN without ACK } then { rate-limit 10000000; # 10 MB/s (~80 Mbps) } } ``` **Example - Block XMAS scan (all flags):** ```python announce flow route { match { protocol =tcp; tcp-flags [ fin syn rst psh ack urg ]; # All flags } then { discard; } } ``` **Example - Block NULL scan (no flags):** ```python announce flow route { match { protocol =tcp; # No flags specified = match no flags set } then { discard; } } ``` --- ## Packet Length **Match packet size in bytes** **Syntax:** ```python packet-length ``` **Examples:** ```python # 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:** ```python announce flow route { match { packet-length >1500; # Larger than standard MTU } then { discard; } } ``` **Example - Block DNS amplification (large responses):** ```python 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:** ```python announce flow route { match { packet-length <64; # Below minimum Ethernet frame size } then { discard; } } ``` --- ## ICMP Type **Match ICMP message type** **Syntax:** ```python icmp-type = ``` **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:** ```python # 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:** ```python announce flow route { match { protocol =icmp; icmp-type =8; # Echo request } then { discard; } } ``` **Example - Block ICMP flood (all types):** ```python announce flow route { match { protocol =icmp; # No icmp-type = match all types } then { rate-limit 1000000; # 1 MB/s (~8 Mbps) } } ``` --- ## ICMP Code **Match ICMP message code (sub-type)** **Syntax:** ```python icmp-code = ``` **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:** ```python # 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:** ```python 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:** ```python dscp = ``` **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:** ```python # 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:** ```python announce flow route { match { dscp =0; # Best effort } then { rate-limit 10000000; # 10 MB/s (~80 Mbps) } } ``` --- ## Fragment **Match packet fragmentation state** **Syntax:** ```python fragment [ ] ``` **Available flags:** | Flag | Meaning | Version | |------|---------|---------| | `dont-fragment` | Don't Fragment bit set (DF) | All versions | | `is-fragment` | Any fragment | All versions | | `first-fragment` | First fragment only | All versions | | `last-fragment` | Last fragment only | All versions | | `not-a-fragment` | ~~Not fragmented~~ | ⚠️ **4.x only** (removed in 5.0.0) | > ⚠️ **Breaking Change in 5.0.0**: The `not-a-fragment` syntax was removed. Use `dont-fragment` instead (matches the DF bit in the IP header). **Examples:** ```python # Any fragment fragment [ is-fragment ] # First fragment fragment [ first-fragment ] # Last fragment fragment [ last-fragment ] # Don't Fragment bit set fragment [ dont-fragment ] # Not fragmented (ExaBGP 4.x syntax - removed in 5.0.0) # fragment [ not-a-fragment ] # Use dont-fragment instead ``` **Use cases:** - Block all fragments (avoid fragmentation attacks) - Allow only non-fragmented packets - Filter specific fragment types **Example - Block all fragments:** ```python announce flow route { match { fragment [ is-fragment ]; } then { discard; } } ``` **Example - Match packets with DF bit set:** ```python announce flow route { match { fragment [ dont-fragment ]; } then { accept; } } ``` **Example - Block all fragments:** ```python 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 ```python 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) ```python 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 ```python 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):** ```python match { protocol =tcp; } then { discard; } ``` Blocks **all TCP traffic** (including SSH, database connections, etc.). **Good (specific):** ```python 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:** ```python # 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):** ```python source 0.0.0.0/0; # Entire internet ``` **Good (specific):** ```python source 203.0.113.0/24; # Specific attack source ``` --- ### 4. Monitor Rule Effectiveness **Log when rules are announced:** ```python 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 ```python 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 ```python match { destination 100.10.0.100/32; destination-port =80|=443; protocol =tcp; tcp-flags [ syn ]; } then { rate-limit 10000000; # 10 MB/s (~80 Mbps) } ``` --- ### DNS Amplification ```python match { source-port =53; protocol =udp; packet-length >512; } then { discard; } ``` --- ### NTP Amplification ```python match { source-port =123; protocol =udp; packet-length >100; } then { discard; } ``` --- ### ICMP Flood ```python match { protocol =icmp; icmp-type =8; # Echo request } then { rate-limit 1000000; # 1 MB/s (~8 Mbps) } ``` --- ### Block Fragmented Packets ```python match { fragment [ is-fragment ]; } then { discard; } ``` --- ### UDP Flood to Service ```python match { destination 100.10.0.100/32; destination-port =80; protocol =udp; } then { discard; } ``` --- ### Port Scan Detection ```python 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 - **[FlowSpec Overview](FlowSpec-Overview)** - Introduction to FlowSpec - **[Actions Reference](Actions-Reference)** - What to do with matched traffic - **[DDoS Mitigation Guide](DDoS-Mitigation)** - Complete mitigation workflow ### API Reference - **[Text API Reference](Text-API-Reference)** - FlowSpec API commands - **[API Commands](API-Commands)** - Command reference ### Examples - **[Quick Start](Quick-Start)** - First FlowSpec rule - **[Production Best Practices](Production-Best-Practices)** - Production deployment --- **Ready to define actions?** See [Actions Reference](Actions-Reference) → ---