# FlowSpec Overview **BGP-based traffic filtering and DDoS mitigation** > ⭐ **ExaBGP was the FIRST open-source FlowSpec implementation** (now also supported by GoBGP, FRRouting, BIRD) --- ## Table of Contents - [What is FlowSpec?](#what-is-flowspec) - [Why FlowSpec Matters](#why-flowspec-matters) - [How FlowSpec Works](#how-flowspec-works) - [Use Cases](#use-cases) - [Match Conditions](#match-conditions) - [Actions](#actions) - [Configuration](#configuration) - [DDoS Mitigation](#ddos-mitigation) - [Integration Examples](#integration-examples) - [Best Practices](#best-practices) - [Limitations](#limitations) - [Next Steps](#next-steps) --- ## What is FlowSpec? **BGP FlowSpec** (Flow Specification) is a BGP extension that allows you to distribute **traffic filtering rules** via BGP. **RFCs:** - **RFC 5575** - Dissemination of Flow Specification Rules (IPv4) - **RFC 8955** - Dissemination of Flow Specification Rules (IPv6) **Key concept:** Instead of announcing "here's a route to a network," FlowSpec announces "here's a rule to filter/rate-limit/redirect specific traffic." **Example:** ```python # Block all TCP traffic from 10.0.0.0/8 to port 80 announce flow route { match { source 10.0.0.0/8; destination-port =80; protocol =tcp; } then { discard; } } ``` The router receives this BGP update and immediately applies the filter in hardware/fast path. --- ## Why FlowSpec Matters ### The Problem **Traditional DDoS mitigation:** 1. Detect attack 2. SSH into routers 3. Manually configure ACLs 4. Apply to interfaces 5. Remove ACLs when attack ends **Issues:** - ⏱️ **Slow**: Minutes to deploy (attack already causing damage) - 🔧 **Manual**: Requires human intervention - 📝 **Error-prone**: Manual configuration mistakes - 🔄 **Doesn't scale**: Can't update hundreds of routers quickly ### The FlowSpec Solution **Automated DDoS mitigation with FlowSpec:** 1. Detection system identifies attack 2. Detection system tells ExaBGP via API 3. ExaBGP announces FlowSpec rule via BGP 4. All routers receive rule and apply filter immediately 5. Attack blocked in **seconds** **Advantages:** - ⚡ **Fast**: Seconds to deploy network-wide - 🤖 **Automated**: No human required - ✅ **Reliable**: API-driven, no manual config - 📈 **Scalable**: Updates all routers simultaneously via BGP - 🔍 **Granular**: Match on multiple packet fields --- ## How FlowSpec Works ### Architecture ``` ┌──────────────────┐ │ DDoS Detection │ (FastNetMon, custom detection) │ System │ └────────┬─────────┘ │ Detects attack │ ▼ ┌──────────────────┐ │ ExaBGP │ Converts to FlowSpec rule │ (FlowSpec │ Announces via BGP │ Generator) │ └────────┬─────────┘ │ BGP FlowSpec UPDATE │ ▼ ┌──────────────────┐ │ Routers │ Receive FlowSpec │ (Cisco, Juniper,│ Apply filter in hardware │ Arista, etc.) │ Drop/rate-limit matching traffic └──────────────────┘ │ │ Filtered traffic ▼ Attack blocked ✅ ``` ### Message Flow 1. **Detection**: DDoS detection system identifies malicious traffic 2. **API Call**: Detection system sends FlowSpec rule to ExaBGP via API 3. **BGP UPDATE**: ExaBGP encodes rule as FlowSpec BGP message 4. **Propagation**: FlowSpec rule propagates to all BGP peers 5. **Filtering**: Routers apply filter in fast path (hardware) 6. **Result**: Attack traffic dropped immediately **Speed:** Entire process takes **seconds**, not minutes or hours. --- ## Use Cases ### 1. DDoS Mitigation (Primary Use Case) **Automated attack blocking:** - SYN floods - UDP amplification - DNS floods - HTTP floods - Volumetric attacks **Example:** ```python # Block SYN flood from 10.0.0.0/8 to port 80 announce flow route { match { source 10.0.0.0/8; destination-port =80; protocol =tcp; tcp-flags [ syn ]; } then { discard; } } ``` --- ### 2. Rate Limiting **Limit traffic instead of blocking entirely:** ```python # Rate-limit DNS queries announce flow route { match { destination-port =53; protocol =udp; } then { rate-limit 1000000; # 1 MB/sec (bytes/sec per RFC 5575) } } ``` --- ### 3. Traffic Redirection **Redirect suspicious traffic to scrubbing center:** ```python # Redirect to VRF for inspection announce flow route { match { destination 100.10.0.0/24; } then { redirect 65001:100; # Route target for scrubbing VRF } } ``` --- ### 4. Protocol-Specific Blocking **Block specific protocols during attacks:** ```python # Block all ICMP (during ICMP flood) announce flow route { match { protocol =icmp; } then { discard; } } ``` --- ### 5. Geographic Blocking **Block traffic from specific regions (combined with BGP communities):** ```python # Block traffic from AS 64512 announce flow route { match { source 203.0.113.0/24; # Address range from that AS } then { discard; } } ``` --- ## Match Conditions FlowSpec rules match traffic based on packet fields. ### Destination Prefix ```python match { destination 100.10.0.0/24; } ``` Match packets destined for this network. --- ### Source Prefix ```python match { source 10.0.0.0/8; } ``` Match packets from this network. --- ### IP Protocol ```python match { protocol =tcp; # TCP (6) protocol =udp; # UDP (17) protocol =icmp; # ICMP (1) protocol =6; # Numeric form } ``` --- ### Destination Port ```python match { destination-port =80; # Exactly port 80 destination-port =80|=443; # Port 80 OR 443 destination-port >=1024&<=65535; # Port range destination-port >1023; # Ports above 1023 } ``` **Operators:** - `=N` - Equals N - `>N` - Greater than N - `=N` - Greater or equal - `<=N` - Less or equal - `>=N&<=M` - Range from N to M (AND) - `=N|=M` - N OR M --- ### Source Port ```python match { source-port =1234; source-port >=1024&<=65535; # Ephemeral ports } ``` --- ### TCP Flags ```python match { tcp-flags [ syn ]; # SYN flag set tcp-flags [ syn ack ]; # SYN+ACK tcp-flags [ fin ]; # FIN flag tcp-flags [ rst ]; # RST flag tcp-flags [ psh ]; # PSH flag tcp-flags [ urg ]; # URG flag tcp-flags [ fin syn rst psh ack urg ]; # All flags } ``` **Use for:** - SYN floods: `tcp-flags [ syn ]` (without ACK) - Connection resets: `tcp-flags [ rst ]` --- ### Packet Length ```python match { packet-length =1500; # Exactly 1500 bytes packet-length >1500; # Larger than MTU (fragmented) packet-length <64; # Tiny packets packet-length >=64&<=1500; # Normal range } ``` **Use for:** - Block fragmented packets: `packet-length >1500` - Block tiny packets: `packet-length <64` --- ### ICMP Type/Code ```python match { icmp-type =8; # Echo request (ping) icmp-type =0; # Echo reply icmp-type =3; icmp-code =3; # Port unreachable } ``` **Common ICMP types:** - 0 - Echo reply - 3 - Destination unreachable - 8 - Echo request - 11 - Time exceeded --- ### DSCP ```python match { dscp =46; # EF (Expedited Forwarding) dscp =0; # Best effort } ``` --- ### Fragment ```python match { fragment [ is-fragment ]; # Any fragment fragment [ first-fragment ]; # First fragment only fragment [ last-fragment ]; # Last fragment only fragment [ not-a-fragment ]; # Not fragmented } ``` **Use for:** - Block all fragments: `fragment [ is-fragment ]` - Allow only non-fragmented: `fragment [ not-a-fragment ]` --- ### Multiple Match Conditions (AND Logic) All conditions must match: ```python match { source 10.0.0.0/8; # AND destination 100.10.0.0/24; # AND destination-port =80; # AND protocol =tcp; # AND tcp-flags [ syn ]; # All must match } ``` --- ## Actions What to do with matching traffic. ### Discard (Drop) ```python then { discard; } ``` Completely drop matching packets. **Most common action for DDoS mitigation.** --- ### Rate-Limit ```python then { rate-limit 1000000; # 1 MB/sec (bytes per second per RFC 5575) } ``` > ⚠️ **Vendor Implementation Warning**: RFC 5575 specifies rate-limit in **bytes per second**, but routers may interpret differently. Juniper converts to bits/sec (×8), Cisco varies by platform. Always test on your equipment! **Rate calculation (RFC 5575 - bytes/sec):** - 1 MB/sec (8 Mbps) = 1,000,000 bytes/sec - 10 MB/sec (80 Mbps) = 10,000,000 bytes/sec - 100 MB/sec (800 Mbps) = 100,000,000 bytes/sec **Use for:** - Limiting specific protocols - Throttling rather than blocking See [Actions Reference](Actions-Reference) for detailed vendor differences. --- ### Redirect to VRF ```python then { redirect 65001:100; # Route target } ``` Redirect traffic to a VRF (Virtual Routing and Forwarding instance) for: - Scrubbing center analysis - IDS inspection - Quarantine network --- ### Mark (DSCP Remarking) ```python then { mark 46; # Mark with DSCP EF } ``` Remark DSCP field for QoS policy. --- ### Community Tagging ```python then { community [ 65001:666 ]; # Tag with community } ``` Tag traffic for downstream policy decisions. --- ## Configuration ### Enable FlowSpec ```ini neighbor 192.168.1.1 { router-id 192.168.1.2; local-address 192.168.1.2; local-as 65001; peer-as 65000; # Enable FlowSpec address family family { ipv4 flowspec; ipv6 flowspec; } # API for dynamic rules api { processes [ flowspec-controller ]; } } process flowspec-controller { run /etc/exabgp/api/flowspec.py; encoder text; } ``` --- ### Static FlowSpec Rule ```ini neighbor 192.168.1.1 { # ... config ... family { ipv4 flowspec; } flow { route { match { destination 100.10.0.0/24; destination-port =80; protocol =tcp; } then { discard; } } } } ``` --- ### API-Based FlowSpec (Recommended) **Configuration:** ```ini process flowspec-api { run /etc/exabgp/api/flowspec.py; encoder text; } neighbor 192.168.1.1 { # ... config ... family { ipv4 flowspec; } api { processes [ flowspec-api ]; } } ``` **API Script:** ```python #!/usr/bin/env python3 import sys import time time.sleep(2) # Announce FlowSpec rule rule = ( "announce flow route { " "match { " "source 10.0.0.0/8; " "destination-port =80; " "protocol =tcp; " "tcp-flags [ syn ]; " "} " "then { discard; } " "}" ) sys.stdout.write(rule + "\n") sys.stdout.flush() # Keep running while True: time.sleep(60) ``` --- ## DDoS Mitigation ### Automated DDoS Response **Workflow:** 1. **Monitor** → DDoS detection system monitors traffic 2. **Detect** → Identifies attack pattern 3. **Generate** → Creates FlowSpec rule 4. **Announce** → Sends to ExaBGP via API 5. **Propagate** → ExaBGP announces to routers via BGP 6. **Block** → Routers drop attack traffic 7. **Cleanup** → Auto-withdraw rule when attack ends --- ### Example: SYN Flood Protection ```python #!/usr/bin/env python3 """ syn_flood_blocker.py - Detect and block SYN floods """ import sys import time import collections # Track SYN packets per source syn_counts = collections.defaultdict(int) blocked_sources = set() THRESHOLD = 1000 # SYN packets per second CHECK_INTERVAL = 1 def detect_syn_flood(): """Detect SYN flood attacks""" # Your detection logic here # Returns source IP if attack detected for source, count in syn_counts.items(): if count > THRESHOLD and source not in blocked_sources: return source return None def block_source(source_ip): """Block source with FlowSpec""" rule = ( f"announce flow route {{ " f"match {{ source {source_ip}/32; tcp-flags [ syn ]; }} " f"then {{ discard; }} " f"}}" ) sys.stdout.write(rule + "\n") sys.stdout.flush() blocked_sources.add(source_ip) sys.stderr.write(f"[BLOCKED] SYN flood from {source_ip}\n") time.sleep(2) while True: attacker = detect_syn_flood() if attacker: block_source(attacker) # Reset counters syn_counts.clear() time.sleep(CHECK_INTERVAL) ``` --- ### Example: UDP Amplification Protection ```python def block_udp_amplification(protocol_port): """Block UDP amplification attacks""" protocols = { 'dns': 53, 'ntp': 123, 'ssdp': 1900, 'chargen': 19, } port = protocols.get(protocol_port, protocol_port) rule = ( f"announce flow route {{ " f"match {{ destination-port ={port}; protocol =udp; packet-length >512; }} " f"then {{ discard; }} " f"}}" ) sys.stdout.write(rule + "\n") sys.stdout.flush() sys.stderr.write(f"[BLOCKED] UDP amplification on port {port}\n") # Block DNS amplification block_udp_amplification('dns') ``` --- ## Integration Examples ### Integration with FastNetMon **FastNetMon** is a DDoS detection system with ExaBGP integration. **Architecture:** ``` FastNetMon (detector) → ExaBGP (FlowSpec generator) → Routers (filters) ``` **FastNetMon config:** ```bash # Enable ExaBGP integration enable_ban_for_tcp_syn_flood = on exabgp = on exabgp_flow_spec_announces = on # ExaBGP command pipe exabgp_command_pipe = /var/run/exabgp.cmd ``` **ExaBGP config:** ```ini process fastnetmon { run /etc/exabgp/api/fastnetmon.py; encoder text; } neighbor 192.168.1.1 { # ... config ... family { ipv4 flowspec; } api { processes [ fastnetmon ]; } } ``` --- ### Integration with Custom Detection ```python #!/usr/bin/env python3 """ custom_detector.py - Custom DDoS detection with FlowSpec """ import sys import time import requests DETECTION_API = "http://localhost:5000/detect" def get_attack_info(): """Query detection system""" response = requests.get(DETECTION_API) if response.status_code == 200: data = response.json() if data.get('attack_detected'): return data return None def announce_flowspec(attack): """Generate and announce FlowSpec rule""" source = attack['source_ip'] dest_port = attack['destination_port'] protocol = attack['protocol'] rule = ( f"announce flow route {{ " f"match {{ source {source}/32; destination-port ={dest_port}; protocol ={protocol}; }} " f"then {{ discard; }} " f"}}" ) sys.stdout.write(rule + "\n") sys.stdout.flush() sys.stderr.write(f"[BLOCKED] Attack from {source} to port {dest_port}\n") time.sleep(2) while True: attack = get_attack_info() if attack: announce_flowspec(attack) time.sleep(5) ``` --- ## Best Practices ### 1. Be Specific **Bad (too broad):** ```python # Blocks ALL TCP traffic match { protocol =tcp; } then { discard; } ``` **Good (specific):** ```python # Blocks only SYN flood from specific source match { source 10.0.0.0/8; destination-port =80; protocol =tcp; tcp-flags [ syn ]; } then { discard; } ``` --- ### 2. Use Rate-Limiting First Try rate-limiting before blocking: ```python # Step 1: Rate-limit then { rate-limit 10000000; # 10 Mbps } # Step 2: If still too much, block then { discard; } ``` --- ### 3. Auto-Expire Rules **Set TTL or withdraw rules after attack ends:** ```python import time import threading def withdraw_after_timeout(rule, timeout=300): """Auto-withdraw rule after timeout (seconds)""" time.sleep(timeout) withdraw = rule.replace('announce', 'withdraw') sys.stdout.write(withdraw + "\n") sys.stdout.flush() # Announce with auto-expiry rule = "announce flow route { ... }" sys.stdout.write(rule + "\n") sys.stdout.flush() threading.Thread(target=withdraw_after_timeout, args=(rule, 300)).start() ``` --- ### 4. Log All Actions ```python import logging logging.basicConfig(filename='/var/log/flowspec.log', level=logging.INFO) def announce_rule(rule): sys.stdout.write(rule + "\n") sys.stdout.flush() logging.info(f"Announced FlowSpec rule: {rule}") ``` --- ### 5. Coordinate with NOC **Alert humans when auto-blocking:** ```python def send_alert(message): """Send alert to NOC""" requests.post("https://alerts.example.com/webhook", json={ "text": message, "severity": "high" }) # When blocking send_alert(f"FlowSpec: Blocking SYN flood from {source_ip}") ``` --- ## Why FlowSpec is Powerful ### "The Ultimate Weapon Against DDoS" (APNIC, 2024) A [September 2024 APNIC article](https://blog.apnic.net/2024/09/18/the-ultimate-weapon-against-ddos-bgp-flowspec/) highlights FlowSpec's key advantage: > **"Lingua Franca" Across Vendors** > > FlowSpec is a standardized protocol that works across multiple vendors' equipment without requiring vendor-specific firewall management interfaces. **Key Benefits:** - ✅ **Vendor-agnostic**: Works on Juniper, Cisco, Nokia, Arista, Extreme, FRR - ✅ **On-premises mitigation**: No third-party cloud scrubbing centers needed - ✅ **Standardized**: One API (ExaBGP) → many router vendors - ✅ **Fast deployment**: Seconds to propagate network-wide via BGP - ✅ **Granular filtering**: L3/L4 header matching **Compared to alternatives:** - Traditional ACLs: Manual, slow, device-specific - Cloud scrubbing: Expensive, adds latency, requires traffic redirection - Proprietary on-premises: Vendor lock-in, complex integration **FlowSpec eliminates these issues** by using BGP as the control plane. --- ## Limitations ### Router Support Required **FlowSpec requires router support:** - ✅ Cisco ASR 1000/9000, NCS 5500, IOS-XR, IOS-XE - ✅ Juniper MX, PTX, Junos (most platforms) - ✅ Arista EOS - ✅ Nokia SR OS - ✅ Huawei routers - ✅ Extreme Networks - ✅ FRRouting (open source) - ❌ Some low-end/consumer routers don't support FlowSpec **Check router documentation for FlowSpec support.** --- ### Vendor-Specific Implementation Differences > ⚠️ **Important**: FlowSpec implementation varies significantly between vendors. **Known limitations (per APNIC 2024 analysis):** **Arista:** - Limited fragment flag support - Missing some TCP flags **Extreme Networks:** - Only partial fragment support - Rate-limit values must be multiples of 22 Kbps **Cisco ASR 9000:** - Maximum 5 values per range in a single rule - Example: Can't match ports 80,443,8080,8443,3000,5000 in one rule **All vendors:** - Hard limits on number of rules (varies by model) - No TTL field filtering (hinders spoofed traffic detection) - Limited visibility into rule effectiveness (can't see per-rule stats easily) **Important:** ExaBGP supports the full RFC 5575/8955 specification. It sends exactly what you tell it to send via the API. Users must understand their router's specific FlowSpec capabilities and limitations when crafting rules. --- ### Hardware Limitations - Some routers limit number of FlowSpec rules (e.g., 1000-10,000) - Rules consume TCAM (ternary content-addressable memory) space - Too many rules can degrade performance - Cross-ASN deployments face rule validation challenges **Best practice:** Keep rules focused and clean up expired rules. **Example limits:** - Small routers: ~1,000 rules - Enterprise routers: ~10,000 rules - Carrier-grade routers: ~50,000+ rules --- ### No Spoofed Source Protection FlowSpec filters at the router, **after** packets arrive. **Can't prevent:** - Bandwidth exhaustion from spoofed sources - Attacks that flood uplink before reaching router - DDoS that consumes all bandwidth upstream **Solution:** Combine with: - **Upstream scrubbing** for volumetric attacks (> line capacity) - **BCP 38** (source address validation) to prevent spoofing - **Rate-limiting** before FlowSpec rules kick in --- ### Visibility Challenges **Problem:** Limited visibility into effectiveness of each rule. **Can't easily see:** - How many packets matched each rule - Which rules are still active vs. stale - Per-rule bandwidth consumption **Workaround:** - Use router-specific CLI to check rule hit counts - Implement TTL-based rule expiration - Log rule announcements/withdrawals in ExaBGP - Monitor overall traffic reduction (before/after) --- ## Next Steps ### Learn More - **[Match Conditions Reference](Match-Conditions)** - All match types detailed - **[Actions Reference](Actions-Reference)** - All actions detailed - **[DDoS Mitigation Guide](DDoS-Mitigation)** - Complete DDoS mitigation workflow ### Examples - **[Text API Reference](Text-API-Reference)** - FlowSpec API commands - **[JSON API Reference](JSON-API-Reference)** - Receiving FlowSpec messages ### Integration - **[FastNetMon Integration](FastNetMon)** - DDoS detection integration - **[Production Best Practices](Production-Best-Practices)** - Production deployment --- **Ready for DDoS protection?** See [DDoS Mitigation Guide](DDoS-Mitigation) → --- **👻 Ghost written by Claude (Anthropic AI)**