How to Get Rid of Denial of Service AttacksOn august 10th, I had the opportunity to talk about (Distributed) Denial of Service (DDoS) at the Megabit 2002 event. I wanted to show a new way to use standard routers and protocols to combat denial of service. Unfortunately, there wasn't enough time to really prepare the test setup, so I was unable to conclusively show it works. However, I was still able to explain how it is supposed to work. I'm going to repeat that part first here, and then go into the Cisco router configurations that make it all happen.
I assume everyone is familiar with network-based (D)DoS attacks. They all basically boil down to a lot of unwanted traffic coming in, which uses up either the available bandwidth, CPU time or memory, or a combination. The idea is to filter out this unwanted traffic. This has to happen as close to the source as possible, since the available bandwidth typically goes down as the traffic gets closer to the destination. Filtering out traffic that has already succeeded in completely filling up the link to an ISP isn't extremely useful. In practice, this means the ISP has to configure a filter when a customer is under attack.
Filtering PossibilitiesThis leads to the next problem: how do we filter? There are three possibilities:
Filtering on the source address is the preferred way to get rid of unwanted traffic, since it just catches traffic from the attacker. Unfortunately, attackers are in the habit of falsifying (spoofing) the source address in attacking traffic, so often this approach can't be used because the attack seems to come from huge numbers of different hosts throughout the net. And even when the source addresses are real, in a distributed attack there may be so many of them that configuring a filter for all of them isn't doable.
If you are lucky, you may encounter an attacker who uses a single non-essential service for all attacking packets. For instance, some early DDoS tools used a single UDP port for all attacking traffic. Smurf directed broadcast attacks by their nature only create ICMP echo reply packets. In such a case, the attacking traffic can easily be filtered out by filtering on UDP or TCP port or ICMP type. However, if the attack uses unpredictable ports or ports that can't be filtered because they are used for important services, it is not possible to filter on service type.
As a last resort, it is possible to filter out all traffic to the host or hosts under attack in order to at least protect the rest of the network. This is usually possible because most attacks are directed at a small number of hosts. If the attack is directed at the entire network, filtering on destination address isn't possible.
Installing the right type of filter will get rid of most attacks. Unfortunately, this has to be done at the transit ISP, which is very inconvenient because it requires an ISP engineer to be available to install the filter. Often, this takes a long time. So what I propose is incorporating mechanisms so customers can do this themselves in the ISP network.
Destination Address FilteringLet's start with what's easiest to implement: filtering on destination address. An ISP can easily give a customer the necessary tools to do this by creating a BGP community that routes traffic for the advertised address range to the null interface. The customer then announces /32 routes with this black hole community set (in addition to the regular address block announcements) and all traffic for these /32s is sent to the null interface. A route map to do this would look like this (sorry for the Cisco-centrism):
! ip community-list 13 permit 65000:13 ! route-map customer-in permit 10 match community 13 set ip next-hop 22.214.171.124 !This route map will set the next hop address for all routes with the community 65000:13 attached to it to 126.96.36.199. (A community is a 32 bit value written down as AS:nn that can be added to BGP routes to trigger actions on remote routers.) This route map must be applied to the customer BGP session. Then, on all routers in the network, the 188.8.131.52 address must be routed to the null interface:
! ip route 184.108.40.206 255.255.255.255 Null0 !(In the real world, you would use an address out of your own address block rather than the 220.127.116.11 address.)
When this setup is in effect, all traffic directed to a blackholed address is immediately thrown away as soon as it enters the network. This is unlike regular anti-DoS filters that are applied to customer interfaces: with those, traffic is first transported through the ISP network to the router connecting the customer, only to be thrown out there. And the main advantage is the customer can initiate filtering at any time without any need for cooperation from the ISP. (Obviously, customers shouldn't be allowed to announce addresses that aren't theirs with this black hole community, or they could blackhole addresses belonging to others. But regular filters on customer BGP sessions should take care of this.)
Source Address Filtering with Unicast RPFSince routing looks at the destination addresses, filtering on those is pretty simple. But filtering on source addresses isn't actually all that hard either, if we employ Cisco's unicast reverse path forwarding (uRPF) check. uRPF takes the source address of incoming packets and checks in the routing table (well, actually the CEF table) whether the interface the packet arrived on is the next hop interface for the source address. Packets that arrive on an interface the router wouldn't use to reach the source address are considered falsified and dropped. This works very well for interfaces that connect to well-defined networks, such as customers. It can also work for peers (over private connections or over an internet exchange) but uRPF isn't very useful on transit links.
By just enabling the uRPF feature and using the same community as in the earlier example, we can now filter on source address:
! interface Serial0 ip verify unicast reverse-path !The community makes sure the address is routed to the null interface, packets with the indicated source address are only allowed if they are received from the null interface. (Actually the uRPF feature has a special check for "null adjacencies": those are immediately dropped.) Since attacking traffic tends to come in over other interfaces, this should work very well as long as uRPF is enabled. There is also a "loose uRPF" that doesn't check where the packet came from, but just if the source address is in the routing table. My router doesn't support this and I can't find the right command, so I'll leave implementing this as an exercise for the reader. This type of uRPF can be enabled for all interfaces because it doesn't break asymmetric routing, so it is very useful here.
Unfortunately, this kind of filtering on the source address can't be used in practice, since then customers would be allowed to arbitrarily blackhole source addresses in an ISP network. This is way too dangerous to allow.
Using a Filter BoxSo now we arrive at the solution I'm advocating: having a separate filter box in the network. This should look something like this:
inet | +---+------+ +----------+ | ISP +--------+ Filter | | router 1 | | box | +--------+-+ +-+--------+ \ / \ / +-+------+-+ | ISP | | router 2 | +----+-----+ | | +----+-----+ | Customer | | router | +----------+It works like this. Whenever a customer's address is under attack, the customer announces this address with a community similar to the one in the first example. Only, rather than changing the next hop address to an unreachable address, the next hop address is set to that of the filter box. This means all traffic to hosts under attack is led through the filter box.
Any traffic surviving the filtering process is sent on its way to the customer. So essentially the traffic is "cleansed" by the filter box.
Note that since different routers in the ISP network need different views of the next hop address for the addresses under attack, (ISP router 1 needs to send traffic to the filter box, ISP router 2 to the customer) there should probably be route maps configured on IBGP sessions. This isn't particularly elegant, but I see no reason why it couldn't be done. If this is a problem, the traffic can be sent from the filter box to the customer over a tunnel.
On the filter box, it shouldn't be a problem to use the BGP blackholing + uRPF trick described above to filter on source addresses. Customers would have an extra BGP session to the filter box so they can tell it which source addresses they want to have filtered out. Since only traffic under attack is being rerouted over the filter box, this essentially creates a filter on the source/destination combinations. It is of course entirely possible to create the filters on the filter box in a different way. For instance, the filter box could be a host-based router on which filters can be set and removed using a web interface.
Stateful FirewallingIf it proves impossible to get rid of spoofed source addresses, there is still a last resort: stateful firewalling. The filter box should then monitor all (TCP) sessions and only allow traffic that belongs to a valid session or an IP address partaking in a valid session. Since it is next to impossible to complete the TCP three-way handshake with a falsified source address, this will get rid of all excess traffic except TCP SYNs, and these can be rate limited to a level the host under attack can handle.
However, this solution won't be easy to implement: it will be hard to get the outgoing traffic that matches the incoming traffic that must be filtered flowing through the same box. This is necessary to do the stateful filtering. This could be solved by having different stateful firewalls work together. A customer firewall could monitor the outgoing traffic and instruct the ISP "filter box" firewall to allow traffic as soon as there is a valid three-way handshake.
Iljitsch van Beijnum
(If you're interested in testing this approach, email me.)