-
Notifications
You must be signed in to change notification settings - Fork 461
FlowSpec Overview
BGP-based traffic filtering and DDoS mitigation
⭐ ExaBGP was the FIRST open-source FlowSpec implementation (now also supported by GoBGP, FRRouting, BIRD)
- What is FlowSpec?
- Why FlowSpec Matters
- How FlowSpec Works
- Use Cases
- Match Conditions
- Actions
- Configuration
- DDoS Mitigation
- Integration Examples
- Best Practices
- Limitations
- Next Steps
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:
# 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.
Traditional DDoS mitigation:
- Detect attack
- SSH into routers
- Manually configure ACLs
- Apply to interfaces
- 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
Automated DDoS mitigation with FlowSpec:
- Detection system identifies attack
- Detection system tells ExaBGP via API
- ExaBGP announces FlowSpec rule via BGP
- All routers receive rule and apply filter immediately
- 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
┌──────────────────┐
│ 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 ✅
- Detection: DDoS detection system identifies malicious traffic
- API Call: Detection system sends FlowSpec rule to ExaBGP via API
- BGP UPDATE: ExaBGP encodes rule as FlowSpec BGP message
- Propagation: FlowSpec rule propagates to all BGP peers
- Filtering: Routers apply filter in fast path (hardware)
- Result: Attack traffic dropped immediately
Speed: Entire process takes seconds, not minutes or hours.
Automated attack blocking:
- SYN floods
- UDP amplification
- DNS floods
- HTTP floods
- Volumetric attacks
Example:
# 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;
}
}Limit traffic instead of blocking entirely:
# 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)
}
}Redirect suspicious traffic to scrubbing center:
# Redirect to VRF for inspection
announce flow route {
match {
destination 100.10.0.0/24;
}
then {
redirect 65001:100; # Route target for scrubbing VRF
}
}Block specific protocols during attacks:
# Block all ICMP (during ICMP flood)
announce flow route {
match {
protocol =icmp;
}
then {
discard;
}
}Block traffic from specific regions (combined with BGP communities):
# Block traffic from AS 64512
announce flow route {
match {
source 203.0.113.0/24; # Address range from that AS
}
then {
discard;
}
}FlowSpec rules match traffic based on packet fields.
match {
destination 100.10.0.0/24;
}Match packets destined for this network.
match {
source 10.0.0.0/8;
}Match packets from this network.
match {
protocol =tcp; # TCP (6)
protocol =udp; # UDP (17)
protocol =icmp; # ICMP (1)
protocol =6; # Numeric form
}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- Less than N -
>=N- Greater or equal -
<=N- Less or equal -
>=N&<=M- Range from N to M (AND) -
=N|=M- N OR M
match {
source-port =1234;
source-port >=1024&<=65535; # Ephemeral ports
}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 ]
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
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
match {
dscp =46; # EF (Expedited Forwarding)
dscp =0; # Best effort
}match {
fragment [ is-fragment ]; # Any fragment
fragment [ first-fragment ]; # First fragment only
fragment [ last-fragment ]; # Last fragment only
fragment [ dont-fragment ]; # Don't fragment (DF bit set)
}Use for:
- Block all fragments:
fragment [ is-fragment ] - Allow only non-fragmented:
fragment [ dont-fragment ]
All conditions must match:
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
}What to do with matching traffic.
then {
discard;
}Completely drop matching packets. Most common action for DDoS mitigation.
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 for detailed vendor differences.
then {
redirect 65001:100; # Route target
}Redirect traffic to a VRF (Virtual Routing and Forwarding instance) for:
- Scrubbing center analysis
- IDS inspection
- Quarantine network
then {
mark 46; # Mark with DSCP EF
}Remark DSCP field for QoS policy.
then {
community [ 65001:666 ]; # Tag with community
}Tag traffic for downstream policy decisions.
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 flow;
ipv6 flow;
}
# API for dynamic rules
api {
processes [ flowspec-controller ];
}
}
process flowspec-controller {
run /etc/exabgp/api/flowspec.py;
encoder text;
}neighbor 192.168.1.1 {
# ... config ...
family {
ipv4 flow;
}
flow {
route {
match {
destination 100.10.0.0/24;
destination-port =80;
protocol =tcp;
}
then {
discard;
}
}
}
}Configuration:
process flowspec-api {
run /etc/exabgp/api/flowspec.py;
encoder text;
}
neighbor 192.168.1.1 {
# ... config ...
family {
ipv4 flow;
}
api {
processes [ flowspec-api ];
}
}API Script:
#!/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)Workflow:
- Monitor → DDoS detection system monitors traffic
- Detect → Identifies attack pattern
- Generate → Creates FlowSpec rule
- Announce → Sends to ExaBGP via API
- Propagate → ExaBGP announces to routers via BGP
- Block → Routers drop attack traffic
- Cleanup → Auto-withdraw rule when attack ends
#!/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)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')FastNetMon is a DDoS detection system with ExaBGP integration.
Architecture:
FastNetMon (detector) → ExaBGP (FlowSpec generator) → Routers (filters)
FastNetMon config:
# 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.cmdExaBGP config:
process fastnetmon {
run /etc/exabgp/api/fastnetmon.py;
encoder text;
}
neighbor 192.168.1.1 {
# ... config ...
family {
ipv4 flow;
}
api {
processes [ fastnetmon ];
}
}#!/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)Bad (too broad):
# Blocks ALL TCP traffic
match {
protocol =tcp;
}
then {
discard;
}Good (specific):
# Blocks only SYN flood from specific source
match {
source 10.0.0.0/8;
destination-port =80;
protocol =tcp;
tcp-flags [ syn ];
}
then {
discard;
}Try rate-limiting before blocking:
# Step 1: Rate-limit
then {
rate-limit 10000000; # 10 MB/s (~80 Mbps)
}
# Step 2: If still too much, block
then {
discard;
}Set TTL or withdraw rules after attack ends:
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()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}")Alert humans when auto-blocking:
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}")A September 2024 APNIC article 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.
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.
⚠️ 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.
- 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
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
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)
- Match Conditions Reference - All match types detailed
- Actions Reference - All actions detailed
- DDoS Mitigation Guide - Complete DDoS mitigation workflow
- Text API Reference - FlowSpec API commands
- JSON API Reference - Receiving FlowSpec messages
- FastNetMon Integration - DDoS detection integration
- Production Best Practices - Production deployment
Ready for DDoS protection? See DDoS Mitigation Guide →
Getting Started
Configuration
- Configuration Syntax
- Neighbor Configuration
- Directives A-Z
- Templates
- Environment Variables
- Process Configuration
API
- API Overview
- Text API Reference
- JSON API Reference
- API Commands
- Writing API Programs
- Error Handling
- Production Best Practices
Address Families
- Overview
- IPv4 Unicast
- IPv6 Unicast
- FlowSpec
- EVPN
- L3VPN
- BGP-LS
- VPLS
- SRv6 / MUP
- Multicast
- RT Constraint
Features
Use Cases
Tools
Operations
Reference
- Architecture
- Design
- Attribute Reference
- Command Reference
- BGP State Machine
- Capabilities
- Communities
- Examples Index
- Glossary
- RFC Support
Integration
Migration
Community
External