Saturday, November 17, 2012

BGP TTL Security

I had actually never labbed TTL Security before today, and I got "good and stuck" for a while on the mechanics.  One of the items that baffled me is I saw it good for an enterprise, but didn't realize the service provider had to play along or it was essentially useless.  Here's our diagram:

In this case, R1 is the service provider core router, and R4 is the customer.

So what's the threat?

There's really nothing an attacker can do in this scenario, provided he is outside your service provider's network, except DOS your BGP process.  Assuming your BGP is configured correctly, there is no threat of establishing an invalid connection.  If you're not using ebgp-multihop or ttl-security to begin with, your router (R4 in this diagram) will always respond to an inbound TCP SYN to the BGP process with a SYN/ACK with TTL 1, and your upstream router (R3) in this case, will always drop the SYN/ACK because the TTL expired, and the TCP session will never establish.  Moreover, in order to even initiate a connection to your BGP process, the attacker must spoof your service provider's source IP address.  This means that even if you had ebgp-multihop turned on, your SYN/ACK would route back to your service provider's router, and get dropped harmlessly.
The real threat is in DOS; if the attacker managed to open tens of thousands of TCP connections into your BGP control plane process, he could potentially overwhelm it and cause real BGP peerings to fail.
This is where TTL security comes in. 
Rule #1 is that both the service provider (R1) and the customer edge (R4) must both play along.  The trick is in that it is impossible to accurately spoof TTL results without having control over the service provider's network, and if that's the case, you have much bigger problems!  I particuarly like the quote from RFC 5082:
"  We also assume that each router in the path between the attacker and
   the victim protocol speaker decrements TTL properly (clearly, if
   either the path or the adjacent peer is compromised, then there are
   worse problems to worry about)."
The trick is to set the TTL of the packet on both sides to 255.  As it's decremented down the line, it will come in with a predictable final TTL.  If that final TTL is >= TTL defined by your router (sort of - the math is backwards - more later), it passes, and the TCP SYN is allowed up to the control plane, where the BGP process takes over.  If it's < TTL defined by your router, the packet is dropped with no ICMP response.  Why respond to a hacker -- it wouldn't arrive anyway, because the source is spoofed by definition.
Let's look at this in action:
R1 sets its TTL to 255 (this is done by default when you enable TTL security - like I said, both sides should be involved).  You'll also notice ebgp-multihop is happening here, which you don't need to configure, this is automatically enabled when you enable ttl-security.  R2 receives R1's packet and decrements it by 1, as does R3.  R4 also does this as it passes the packet on to the BGP process.  We end up with a TTL of 252.
This is what held me up for a good long while on the implementation.  I figured I'd set "252" as the ttl-security setting.  BZZZT!  The answer is 3, because R1 is 3 hops away.  So the math is (255 - (expected TTL) = appropriate setting).  255 - 252 = 3.
The configuration of this feature is super-simple after you understand this:
router bgp
  neighbor remote-as 4
  neighbor ttl-security hops 3
router bgp
  neighbor remote-as 1
  neighbor ttl-security hops 3
Now that we know how it works, how does this prevent "ATTACKER" from being able to open a TCP session on our BGP port?
Attacker would probably have a TTL of 255, as we're assuming this is some rogue server or other device capable of opening tens of thousands of spoofed TCP sessions. If he was set to 255, even in this "optimal" drawing, he'd arrive with a TTL of 251, and the packet would be immediately dropped.  If he was set lower than 255 to begin with, he'd end up with an even lower TTL when he reached R4, and would then also get dropped.  And of course setting TTL to 256 is impossible, it would take more than the 1 byte allowed by the IP header.
If Attacker was interposed between R2 and R3, well, then, you're out of luck.  The process looks for a TTL >= the expected TTL, so if he came in with 253, he'd be accepted.  That still doesn't mean he can pass you rogue routes - your return traffic will still be routed to R1, and the TCP session won't establish - but he could DOS you.
By the way, if you want to test the "ATTACKER" config on your own using a router, the simple answer is to create a loopback on it with R1's IP address ( with a /32 mask, put it in BGP AS 1, create a neighbor peering to, set the update source as the loopback you just created, and set ebgp-multihop to anything you like > 4.  You can use wireshark to watch its SYN packets get ignored over and over again.  A sample config is:
interface Loopback7
 ip address
router bgp 1
 neighbor remote-as 4
 neighbor ebgp-multihop 255
 neighbor update-source Loopback7
Jeff Kronlage


  1. Hi Jeff
    Thanks for this awesome post. However I have difficulty in understanding this in case of peering with loopbacks. Following test cases I used.
    1. Peering between R1 and R2 loopbacks wont come up if use TTL value of 1. TTL2 works with directly connected neighbors.

    2. Peering does come up between R1 and R2 (loopback Peerings) when we are using TTL value=3.


  2. Sorry I am writing point 2 again

    2. Peering does come up between R1 and R4 (loopback Peerings) when we are using TTL value=3.