Granular, efficient and distributed firewalling based on good old BGP.

BGP can carry many different network-related information, sometimes described as address families or NLRI (Network Layer Reachability Information). One of them is FlowSpec (RFC 5575), which allows BGP to propagate a filter for a specific IPv4 packet flow. A flow, which is defined by an n-tuple, like a combination of source and destination IP address, protocol number and ports, can be discarded, rate-limited, redirected to some analysis or mitigation device etc. BGP is simply used to signal the routers to perform appropriate filtering actions for a certain flow.

BGP routers in the mesh learn what to do with the traffic that matches the n-tuple – for example, they can drop it or limit it to a some harmless rate. This technique makes BGP routers act like a big distributed firewall that can be easily programmed to mitigate some malicious traffic, a DDoS, for example.
The added value of using BGP to propagate filtering information is that DDoS mitigation actions are distributed across the network and therefore closer to the source of the attack.

The malicious flow is signaled within the iBGP core and the attack from upstreams is blocked at the entrance routers. If the upstream provider supports BGP FlowSpec, the mitigation can be done even closer to the source of the attack.

The malicious flow is signaled within the iBGP core and the attack from upstreams is blocked at the entrance routers. If the upstream provider supports BGP FlowSpec, the mitigation can be done even closer to the source of the attack.

The specification was written by guys from Cisco, Juniper, Arbor Networks and NTT America, but only Juniper implements it at the time of writing. Here is an example for the Junos OS. First, let us statically define a flow:

[edit routing-options flow]
route TestFlowRoute {
    match {
        destination 10.10.10.10/32;
        source 192.168.1.1/32;
        protocol tcp;
        tcp-flags ack;
    }
    then rate-limit 1m;
}
term-order standard;

This locally defined static “flow route” is installed in the inetflow.0 routing table and it is known from a Flow protocol with a Fictitious next-hop type:
matjaz@router.re0> show route table inetflow.0
inetflow.0: 1 destinations, 1 routes (1 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
10.10.10.10,192.168.1.1,proto=6,tcp-flag:10/term:1
                   *[Flow/5] 00:34:40
                      Fictitious

We can inject these kind of routes into BGP with an appropriate import policy. For example:
[edit protocols bgp group iBgp]
type internal;
import [ ImportStaticFlowSpec ...more policy... ];
family inet {
    unicast;
    flow;
}

[edit policy-options policy-statement ImportStaticFlowSpec]
term Import {
    from rib inetflow.0;
    then accept;
}

Now our statically defined flow route is being advertised to our BGP neighbours:
matjaz@router.re0> show route advertising-protocol bgp x.y.z.w table inetflow.0
inetflow.0: 1 destinations, 1 routes (1 active, 0 holddown, 0 hidden)
  Prefix   Nexthop        MED     Lclpref    AS path
  10.10.10.10,192.168.1.1,proto=6,tcp-flag:10/term:1
*                         Self                         100        I

Let us check the receiving BGP router. Here, our test flow route is shown as hidden because it failed the validation:
matjaz@router.re0> show route table inetflow.0 hidden extensive
inetflow.0: 1 destinations, 1 routes (0 active, 0 holddown, 1 hidden)
10.10.10.10,192.168.1.1,proto=6,tcp-flag:10/term:N/A (1 entry, 0 announced)
         BGP                 /-101
                Next hop type: Fictitious
                Address: 0x9011424
                Next-hop reference count: 1
                State: <Hidden Int Ext>
                Local AS:  myAS Peer AS:  myAS
                Age: 2:56
                Validation State: unverified
                Task: BGP_myAS.x.y.z.q+179
                AS path: I
                AS path: Recorded
                Communities: myAS:65533 traffic-rate:0:1000000
                Validation state: Reject, Originator: x.y.z.q
                Via: 0.0.0.0/4, Active
                Localpref: 100
                Router ID: x.y.z.q

The receiving router performs a validation process before installing the flow route into the routing table and setting up the firewall filter. A flow route is accepted if it passes the following criteria:

  • The originator of a flow route matches the originator of the best match unicast route for the destination address that is embedded in the route.
  • There are no more specific unicast routes, when compared to the destination address of the flow route, for which the active route has been received from a different next-hop autonomous system.

In our example, the originator of the best matched route toward the destination address 10.10.10.10 does not match. However, you can bypass the validation process and write your own import policy to check the received flow routes, like this:
[edit protocols bgp group iBgp]
family inet {
    unicast;
    flow {
        no-validate FlowSpecRoutes;
    }
}
[edit policy-options policy-statement FlowSpecRoutes]
from community FlowSpec;
then accept;

Please, check Juniper documentation and RFC for more details.


The feature has been implemented in GRNET – Greek academic, research and educational network as a Firewall on Demand service (here is an interesting talk by Leonidas Poulopoulos from GRNET at 2nd SEE Regional RIPE Meeting in Skopje).

Advertisements