DNS is an ideal transport for amplification attacks (and even moreso with DNSSEC/IPv6 bringing EDNS extensions to DNS). A forged 60 byte DNS request packet can generate up to a 4096 byte response packet via UDP.
You can tell if you are being used in an attack by a massive increase in outbound DNS responses on your authorative DNS server. Your DNS will receive a packet and return the data for the query to the IP it believes it came from. There’s no handshaking in UDP so it will just trust the sender address and blindly reply to it. This is normal operation.
To reduce the effects of this in FreeBSD, we can apply a bandwidth limiter on our responses on a per-IP basis.
First, we need to ensure the dummynet module is loaded:
To make it load at boot time, edit your /boot/loader.conf file and add the following line:
Next, edit your ipfw script (or create a new one). We need to define the pipe as follows:
/sbin/ipfw pipe 1 config mask dst-ip 0xffffffff bw 256Kbit/s
This will limit dns traffic to each IP to 256kbits/sec (about 32KB/sec) when we use it. Dummynet granularity isn’t all that great so don’t expect it to be accurate – but the fact we are limiting it is enough. NOTE: your setup may require a different figure depending on your normal DNS load.
Next, we need to apply it to all DNS responses from us:
/sbin/ipfw add 01000 pipe 1 udp from me 53 to any out
You may need to tweak the rule number (01000) to fit into your setup. It needs to ideally be as high up in your firewall as possible.
That’s all you need to do. The above will add additional load to your server in terms of CPU – but that’s the price you have to pay.
You can, of course, use the above settings (slightly tweaked) on a firewall in front of any DNS server.
Personally, to reduce load on my nameservers I also add a second pipe for incoming bandwidth on a per IP basis. For this, you need to use src-ip mask instead of dst-ip and apply it to incoming traffic.