May 28, 2023

What is Gatekeeper?

Gatekeeper is the first open source DoS protection system. It is designed to scale to any peak bandwidth, so it can withstand DoS attacks both of today and of tomorrow. In spite of the geographically distributed architecture of Gatekeeper, the network policy that describes all decisions that have to be enforced on the incoming traffic is centralized. This centralized policy enables network operators to leverage distributed algorithms that would not be viable under very high latency (e.g. distributed databases) and to fight multiple multi-vector DoS attacks at once.

The intended users of Gatekeeper are network operators of institutions, service and content providers, enterprise networks, etc. It is not intended to be used by individual Internet users.

For more information, see the Gatekeeper wiki.

How to Set Up

Configure Hugepages

DPDK requires the use of hugepages; instructions for mounting hugepages are available in the requirements documentation. On many systems, the following hugepages setup is sufficient:


$ echo 256 | sudo tee /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

Option 1: Obtain Packages

Gatekeeper Debian packages are available for Ubuntu 20.04 LTS at the project’s Releases page.

Install

Once the packages are downloaded, they can be installed with the commands below:











$ tar -zxvf gatekeeper-ubuntu-20.04-packages.tar.gz
$ cd gatekeeper-ubuntu-20.04-packages
$ sudo dpkg -i libgkrte-*.deb \
    libgkdpdk-dev_*_amd64.deb \
    gatekeeper-dpdk_*_amd64.deb \
    gatekeeper-dpdk-dev_*_amd64.deb \
    gatekeeper-dpdk-igb-uio-dkms_*_amd64.deb \
    gatekeeper-dpdk-rte-kni-dkms_*_amd64.deb \
    gatekeeper-bird_*_amd64.deb \
    gatekeeper_*_amd64.deb

The gatekeeper-dpdk-dev package is a dependency of the DKMS packages, which build their respective kernel modules during package installation and kernel upgrades.

Configure Gatekeeper

When installed via Debian packages, Gatekeeper configuration files are located in /etc/gatekeeper. You should edit at least the net.lua file, and set the front_portsfront_ipsback_ports and back_ips variables according to your environment.

The other Lua files configure different Gatekeeper functional blocks. Please refer to the project’s wiki for further information on whether these need to be changed in your setup.

You also need to edit the /etc/gatekeeper/envvars file and set the GATEKEEPER_INTERFACES variable to the PCI addresses of the network adapters to be bound to DPDK. These can found using the lshw command. For example:







# lshw -c network -businfo
Bus info          Device     Class          Description
=======================================================
pci@0000:08:00.0  eth0       network        I350 Gigabit Network Connection
pci@0000:08:00.1  eth1       network        I350 Gigabit Network Connection
...

Given this output, set GATEKEEPER_INTERFACES as below:


GATEKEEPER_INTERFACES="08:00.0 08:00.1"

In the same file, you can optionally specify Environmental Abstraction Layer options in the DPDK_ARGS variable and Gatekeeper-specific options in GATEKEEPER_ARGS.

How to run

Run the commands below to start Gatekeeper and to ensure it is started automatically on reboots.



$ sudo systemctl start gatekeeper
$ sudo systemctl enable gatekeeper

Option 2: Build from Source

Install Dependencies

Install the following software dependencies:







$ sudo apt-get update
$ sudo apt-get -y -q install git clang devscripts doxygen libhugetlbfs-bin \
build-essential gcc-multilib linux-headers-`uname -r` libmnl0 libmnl-dev \
libkmod2 libkmod-dev libnuma-dev libelf1 libelf-dev libc6-dev-i386 \
autoconf flex bison libncurses5-dev libreadline-dev python \
libcap-dev libcap2

Note: Both libmnl0 and libmnl-dev are needed to compile and run gatekeeper, but only libmnl0 is needed for simply running gatekeeper. Both libkmod2 and libkmod-dev are needed to compile and run gatekeeper, but only libkmod2 is needed for simply running gatekeeperlibnuma-dev is needed to compile the latest DPDK and to support NUMA systems. The package libelf-dev is needed to compile DPDK with support to reading BPF programs from ELF files, but only libelf1 is needed to run it. The package libc6-dev-i386 is needed to compile the BPF programs in the folder bpf/. The autoconfflexbisonlibncurses5-dev, and libreadline-dev packages are for BIRD. The devscripts package is used to build Gatekeeper Debian packages. python is needed to be able to run the dpdk-devbind.py script. libcap-dev is needed to compile Gatekeeper, but only libcap2 is needed to run Gatekeeper.

To use DPDK, make sure you have all of the environmental requirements.

Clone Repository

Clone the Gatekeeper repository, including the submodules that contain Gatekeeper dependencies:


$ git clone --recursive http://github.com/AltraMayor/gatekeeper.git

If you do not use the --recursive clone option, you need to obtain the submodules that contain the dependencies from within the gatekeeper directory:



$ git submodule init
$ git submodule update

Compile

This section explains how to build Gatekeeper manually. If you want to build Debian packages, refer to the section How to build packages.

While in the gatekeeper directory, run the setup script:


$ . setup.sh

This script compiles DPDK, LuaJIT, and BIRD, and loads the needed kernel modules. Additionally, it saves the interface names and their respective PCI addresses in the file lua/if_map.lua so that interface names can be used in the Gatekeeper configuration files.

It also sets two environmental variables: RTE_SDK and RTE_TARGET. They must be set before gatekeeper will compile.

After running the setup script, you may want to save the environmental variables in your shell’s preferences file. For example, in Bash, you can do:



$ echo "export RTE_SDK=${RTE_SDK}" >> ${HOME}/.profile
$ echo "export RTE_TARGET=${RTE_TARGET}" >> ${HOME}/.profile

Otherwise, each time you login you will need to set these environmental variables again.

Once DPDK is compiled and the variables are set, gatekeeper can be compiled:


$ make

Configure Network Adapters

Before gatekeeper can be used, the network adapters must be bound to DPDK. For this, you can use the script dependencies/dpdk/usertools/dpdk-devbind.py. For example:


$ sudo dependencies/dpdk/usertools/dpdk-devbind.py --bind=uio_pci_generic enp131s0f0

This command binds the interface enp131s0f0 to the uio_pci_generic driver so that frames can be passed directly to DPDK instead of the kernel. Note that this binding must take place after Gatekeeper is setup in the steps above so that the bound interface appears in the list of interfaces in lua/if_map.lua.

How to Run

Once gatekeeper is compiled and the environment is configured correctly, run:


$ sudo build/gatekeeper [EAL OPTIONS]  -- [GATEKEEPER OPTIONS] 

Where [EAL OPTIONS]  are specified before a double dash and represent the parameters for DPDK’s Environmental Abstraction Layer and [GATEKEEPER OPTIONS]  are specified after the double dash and represent Gatekeeper-specific options.

The early configuration of the system, including device and memory configuration in DPDK, will be logged to stdout. Once Gatekeeper is booted, all information is output to the Gatekeeper log.

How to build packages

Gatekeeper Debian packages can be built with the commands below. They are meant to be run from the repository root and assume the git submodules have been pulled, and that the build dependencies have been installed, as instructed above. Gatekeeper and the submodules will be automatically compiled during the package build process.



$ tar --exclude-vcs -Jcvf ../gatekeeper_1.0.0.orig.tar.xz -C .. gatekeeper
$ debuild -uc -us

The Gatekeeper package will be available in the parent directory.

https://github.com/AltraMayor/gatekeeper

How does Gatekeeper work?

Gatekeeper has two components: Gatekeeper servers and Grantor servers. Gatekeeper servers are deployed throughout the Internet at locations called vantage points (VPs). Vantage points are Internet exchange points (IXPs), border and peering-link routers, and (potentially) cloud providers. The aggregated bandwidth of all Gatekeeper servers is what enables a Gatekeeper deployment to scale its incoming bandwidth to match the peak bandwidth of DDoS attacks.

Gatekeeper servers use BGP to announce the network prefixes under their protection. Thus, each traffic source is bound to a VP. Gatekeeper servers’ primary function is to enforce network policies over flows; a flow is defined by the pair source and destination IP addresses. An example of a policy decision is for IP address A to be allowed to send packets to IP address B at 1Gbps or less. An analogy that may help some to wrap their head around Gatekeeper is to think of Gatekeeper servers as reverse proxies that work at the IP layer.

When a Gatekeeper server does not have is a policy decision in its flow table to enforce over any given flow. Instead, it encapsulates the packet of that flow using IP-in-IP, assigns a priority to the encapsulated packet based on the rate of the given flow (higher priority for lower rates), and forwards it through the request channel. The request channel is reserved 5% of the bandwidth of the path that goes from a Gatekeeper server to the Grantor server responsible for the policy decision. Whenever a router forwarding the packets in the request channel needs to drop packets due to the limited bandwidth, it drops the packets of lowest priority in its queues.

A network policy is a Lua script that runs on Grantor servers. Grantor servers are co-located near the protected destination; typically in the same datacenter of the destination. One can deploy Grantor servers in other locations and even employ anycast to reach varied destinations, but we assume here (for the sake of simplicity) that the destination prefix is deployed in a single datacenter.

Grantor servers are responsible for making a policy decision on each flow in the request channel. These policy decisions are sent to the corresponding Gatekeeper servers to enforce them. As policy decisions are installed into Gatekeeper servers, the flows of legitimate senders get moved to the granted channel, in which bandwidth is allocated according to the policy. Similarly, identified malicious hosts would be blocked. This, in turn, would reduce the delay experienced by legitimate flows waiting at the request channel.

Summarizing, a Gatekeeper deployment consists of a number of vantage points forming a shield around the protected networks. Grantor servers, which reside inside of the shield but before the final destinations of the packets, run the network policy to decide the fate of all incoming traffic. The policy decisions are installed at Gatekeeper servers, which enforce these policy decisions.

Anatomy of a Gatekeeper Response

For an example of what all this means, consider the nearly 1Tbps SYN flood that Cloudflare faced in 2018. A Gatekeeper deployment with enough bandwidth at VPs and enough Gatekeeper servers to process the incoming packets would, before any policy evaluation or priority adjustments, reduce that incoming flood to 50Gbps (i.e. 5% of 1Tbps).

How? Since it was a direct attack and the attacker was targeting bandwidth capacity — that is, there was no attempt to establish connections — the request channel would start to automatically filter the flood before reaching Grantor servers in a couple of seconds. This couple of seconds would become the delay experienced by legitimate senders to have their policy decisions installed into the Gatekeeper servers.

The key points to understand how such an attack would be mitigated by Gatekeeper are: (1) ensuring that 5% of the path bandwidth is reserved for requests, (2) assigning priorities to those requests based on the time between requests in the same flow, and (3) dropping packets of lower priority when the bandwidth of the request channel is overflowing. These properties guarantee the results of Theorems 4.1 and 4.2 presented in Section 4.2 of the Portcullis paper (SIGCOMM 2007). In plain English, Theorem 4.1 states that if a network policy cannot identify malicious hosts, a legitimate sender will wait, in the worst case, a time proportional to the number of malicious hosts to have a policy decision installed at the corresponding Gatekeeper server. Theorem 4.2 states that under these conditions, that result is optimal. If a policy can identify malicious hosts, the waiting time becomes, at worst case, proportional to the number of undetected malicious hosts.

What about flows that start behaving well to receive a favorable policy decision and then abuse? There are two parts to this answer. The first is that all policy decisions eventually expire. The second is that policy decisions are BPF programs, so they can limit or act on changes of behavior. The folder bpf in our repository shows examples of BPF programs that limit the bandwidth of a flow (e.g. granted.c), penalize unwanted traffic with less bandwidth (e.g. grantedv2.c), and enforce behaviors expected by simple Web servers (e.g. web.c).

What about abuses that cannot be identified by a BPF program? If the abuse can still be identified by an intrusion detection system (IDS), one will eventually be able to combine IDSes with Gatekeeper; track the status of this feature at issue #298. Another approach is for applications to identify abuses and to feed their results into policies. For a simple example, consider a WordPress plugin that identifies a number of abuses on a WordPress site. The list of abusers from this plugin can be fed into a policy to enable Grantor servers to either bluntly reject abusers or to apply stricter rules on them.

Finally, what about abuses that cannot be identified by an IDS or even an application itself? In this case, all that can be done is to schedule the flows in such a way that enables the network and servers to serve the flows at the best rate possible. Without the scheduling of the flows, the infrastructure is going to serve nobody under such an attack. Gatekeeper is not ready for this scenario. We have many milestones in front of us before we can work on this last milestone.

Where to go from here?

The page Publications has several resources to help you understand Gatekeeper. Newcomers will find our NANOG 82 a good starting point. Those interested in learning from a large-scale Gatekeeper deployment will have plenty of information in the NextHop 2020 presentation. The technical report “Gatekeeper: The Design and Deployment of a DDoS Protection System” covers the underpinnings of Gatekeeper, and is a recommended read for those looking for the big picture.

The page Tips for Deployments describes a simple deployment and includes practical details to help those getting started. The page Overview is a quick reference of the components of Gatekeeper. Much more information is available on the pages of this wiki.

Where to find help?

The primary point of contact for bugs and issues in general is the issues page here on GitHub. The milestones

Leave a Reply

%d bloggers like this: