Imported Upstream version 1.20
This commit is contained in:
parent
912e105ee9
commit
63b4b0fa48
17
README
17
README
|
@ -1,4 +1,4 @@
|
||||||
DNS FLood Detector 1.12
|
DNS FLood Detector 1.2
|
||||||
Dennis Opacki
|
Dennis Opacki
|
||||||
dopacki@adotout.com
|
dopacki@adotout.com
|
||||||
|
|
||||||
|
@ -21,6 +21,16 @@ By default, it will count dns queries directed to any address in the same
|
||||||
network as the primary IP address on the interface being watched; the -A,
|
network as the primary IP address on the interface being watched; the -A,
|
||||||
-M, and -Q options can be used to modify this behaviour.
|
-M, and -Q options can be used to modify this behaviour.
|
||||||
|
|
||||||
|
As of version 1.2, DNS Flood Detector can now send source IP request
|
||||||
|
data to a network-based collector as JSON. This lets you gather near
|
||||||
|
real-time information about who is using your DNS servers, and from
|
||||||
|
where. I've included a sample application called dns_flood_collector.pl,
|
||||||
|
which you can use to receive and report these data. The output of this
|
||||||
|
program can be easily fed into a graphing tool, such as Caida's
|
||||||
|
plot-latlong:
|
||||||
|
|
||||||
|
http://www.caida.org/tools/visualization/plot-latlong/
|
||||||
|
|
||||||
How do I build it?
|
How do I build it?
|
||||||
|
|
||||||
Execute ./configure.pl to select the appropriate make target. Then simply
|
Execute ./configure.pl to select the appropriate make target. Then simply
|
||||||
|
@ -41,7 +51,7 @@ What platforms does it work on?
|
||||||
|
|
||||||
Linux, BSDI, FreeBSD, Mac OSX, Solaris
|
Linux, BSDI, FreeBSD, Mac OSX, Solaris
|
||||||
|
|
||||||
Will it run under Windows {95,98,NT,2000,XP}?
|
Will it run under Windows {95,98,NT,2000,XP,2003,2008 or Win7}?
|
||||||
|
|
||||||
Maybe. I haven't tried. If it doesn't, feel free to submit a fix.
|
Maybe. I haven't tried. If it doesn't, feel free to submit a fix.
|
||||||
|
|
||||||
|
@ -62,6 +72,9 @@ Usage: ./dns_flood_detector [OPTION]
|
||||||
-d run in background in daemon mode
|
-d run in background in daemon mode
|
||||||
-D dump dns packets (implies -b)
|
-D dump dns packets (implies -b)
|
||||||
-v verbose output - use again for more verbosity
|
-v verbose output - use again for more verbosity
|
||||||
|
-s send source IP stats to collector as JSON
|
||||||
|
-z N.N.N.N address to send stats to (default 226.1.1.2)
|
||||||
|
-p N UDP port to send stats to (default 2000)
|
||||||
-h display this usage information
|
-h display this usage information
|
||||||
|
|
||||||
Sample Output:
|
Sample Output:
|
||||||
|
|
157
dns_flood_collector.pl
Executable file
157
dns_flood_collector.pl
Executable file
|
@ -0,0 +1,157 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use threads;
|
||||||
|
use threads::shared;
|
||||||
|
use Sys::Syslog;
|
||||||
|
use Data::Dumper;
|
||||||
|
use Getopt::Long;
|
||||||
|
use POSIX;
|
||||||
|
use IO::Socket::Multicast;
|
||||||
|
use JSON;
|
||||||
|
|
||||||
|
# Native Maxmind library - http://www.maxmind.com/download/geoip/api/perl/
|
||||||
|
# requires: http://www.maxmind.com/app/c
|
||||||
|
use Geo::IP;
|
||||||
|
|
||||||
|
# set these to the same port and multicast (or unicast) address as the detector
|
||||||
|
use constant GROUP => '226.1.1.2';
|
||||||
|
use constant PORT => '2000';
|
||||||
|
|
||||||
|
my %ipc_source :shared;
|
||||||
|
my %ipc_customer :shared;
|
||||||
|
my $time_to_die :shared = 0;
|
||||||
|
my $debug;
|
||||||
|
my $foreground=0;
|
||||||
|
|
||||||
|
# determines how often you want to aggregage and write-out stats dumps
|
||||||
|
my $interval = 60;
|
||||||
|
|
||||||
|
# you can get the binary format GeoLiteCity.dat from Maxmind
|
||||||
|
# http://www.maxmind.com/app/geolitecity
|
||||||
|
my $gi = Geo::IP->open("/usr/local/GeoLiteCity.dat",GEOIP_MEMORY_CACHE | GEOIP_CHECK_CACHE);
|
||||||
|
|
||||||
|
# adjust this to the path where you want to keep the
|
||||||
|
sub PATH {'/tmp/'}
|
||||||
|
|
||||||
|
$|=1;
|
||||||
|
|
||||||
|
GetOptions(
|
||||||
|
"debug" => \$debug,
|
||||||
|
"foreground" => \$foreground,
|
||||||
|
"interval=s" => \$interval,
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
main();
|
||||||
|
exit();
|
||||||
|
|
||||||
|
sub main() {
|
||||||
|
|
||||||
|
# daemonize unless running in foreground
|
||||||
|
unless ($foreground){
|
||||||
|
daemonize();
|
||||||
|
}
|
||||||
|
|
||||||
|
# prepare data acquisition thread
|
||||||
|
threads->new(\&get_data);
|
||||||
|
|
||||||
|
while (! $time_to_die ) {
|
||||||
|
|
||||||
|
# record time started to help evenly space runs
|
||||||
|
my $start_run = time();
|
||||||
|
my $next_run = $start_run + $interval;
|
||||||
|
|
||||||
|
# de-serialize latest copy of source address structure
|
||||||
|
# execute this in a isolated scope so that lock goes out of scope
|
||||||
|
{
|
||||||
|
my $source_distance;
|
||||||
|
|
||||||
|
# lock data structure to prevent other thread from updating it
|
||||||
|
lock(%ipc_source);
|
||||||
|
|
||||||
|
# open coordinates file for graph generation
|
||||||
|
open(CRDS, ">".PATH."/coords.txt.tmp");
|
||||||
|
|
||||||
|
# calculate great circle distance between each source IP and local POP
|
||||||
|
foreach my $key (keys %ipc_source) {
|
||||||
|
|
||||||
|
eval {
|
||||||
|
my $r = $gi->record_by_addr($key);
|
||||||
|
|
||||||
|
# write raw entry to coordinates file
|
||||||
|
print CRDS $key.",".$ipc_source{$key}.",".$r->latitude.",".$r->longitude."\n";
|
||||||
|
};
|
||||||
|
if ($@) {
|
||||||
|
print CRDS $key.",".$ipc_source{$key}.",0,0\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# close coordinate file
|
||||||
|
close CRDS;
|
||||||
|
system("mv ".PATH."/coords.txt.tmp ".PATH."/coords.txt");
|
||||||
|
|
||||||
|
# clean out structure for next sample period
|
||||||
|
%ipc_source = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
# sleep to make the interval
|
||||||
|
while((my $time_left = ($next_run - time())) > 0) {
|
||||||
|
sleep($time_left);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
threads->join();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
# fetch data from UDP multicast
|
||||||
|
sub get_data() {
|
||||||
|
|
||||||
|
# set up our multicast listener
|
||||||
|
# note: this will receive unicast fine too
|
||||||
|
my $sock = IO::Socket::Multicast->new(LocalPort=>PORT,ReuseAddr=>1);
|
||||||
|
$sock->mcast_add(GROUP) || die "Couldn't set group: $!\n";
|
||||||
|
|
||||||
|
|
||||||
|
while ( ! $time_to_die ) {
|
||||||
|
my $data;
|
||||||
|
next unless $sock->recv($data,1500);
|
||||||
|
|
||||||
|
# decode JSON
|
||||||
|
eval {
|
||||||
|
my $obj = decode_json $data;
|
||||||
|
print Dumper $obj;
|
||||||
|
foreach my $ip (keys %{$obj->{data}}) {
|
||||||
|
my $count = $obj->{data}->{$ip};
|
||||||
|
lock(%ipc_source);
|
||||||
|
$ipc_source{$ip}+=$count;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# done!
|
||||||
|
threads->exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
# daemonize application
|
||||||
|
sub daemonize {
|
||||||
|
|
||||||
|
chdir '/' or die "Can't chdir to /: $!";
|
||||||
|
open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
|
||||||
|
open STDOUT, '>/dev/null';
|
||||||
|
|
||||||
|
# fork and exit parent
|
||||||
|
my $pid = fork();
|
||||||
|
exit if $pid;
|
||||||
|
die "Couldn't fork: $!" unless defined ($pid);
|
||||||
|
POSIX::setsid() || die ("$0 can't start a new session: $!");
|
||||||
|
open STDERR, '>&STDOUT' or die "Can't dup stdout: $!";
|
||||||
|
|
||||||
|
# signal handlers
|
||||||
|
$SIG{KILL} = \&handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub handler {
|
||||||
|
$time_to_die = 1;
|
||||||
|
}
|
1389
dns_flood_detector.c
1389
dns_flood_detector.c
File diff suppressed because it is too large
Load diff
|
@ -30,6 +30,13 @@
|
||||||
#endif
|
#endif
|
||||||
#define NS_MAXDNAME 1025
|
#define NS_MAXDNAME 1025
|
||||||
#define MAXSYSLOG 192
|
#define MAXSYSLOG 192
|
||||||
|
#define MAXMESSAGE 1200
|
||||||
|
#define MAXDATALET 64
|
||||||
|
#define MAXHEAD 300
|
||||||
|
#define MAX_TIME_LEN 20
|
||||||
|
#define DEFAULT_PORT 2000
|
||||||
|
#define DEFAULT_IP "226.1.1.2"
|
||||||
|
#define HOST_NAME_MAX 254
|
||||||
|
|
||||||
// evil Solaris hack
|
// evil Solaris hack
|
||||||
#ifdef __sun__
|
#ifdef __sun__
|
||||||
|
@ -41,10 +48,12 @@ typedef uint32_t u_int32_t;
|
||||||
// prototypes
|
// prototypes
|
||||||
void handle_IP(u_char *args,const struct pcap_pkthdr* pkthdr,const u_char* packet);
|
void handle_IP(u_char *args,const struct pcap_pkthdr* pkthdr,const u_char* packet);
|
||||||
int calculate_averages();
|
int calculate_averages();
|
||||||
|
int saddr_stats(int sock, struct sockaddr_in addr, char *hostname);
|
||||||
int scour_bucket(int i);
|
int scour_bucket(int i);
|
||||||
int find_bucket(struct in_addr *ip_src);
|
int find_bucket(struct in_addr *ip_src);
|
||||||
int daemonize(void);
|
int daemonize(void);
|
||||||
int malloc_fail(char * var, int size);
|
int malloc_fail(char * var, int size);
|
||||||
|
int microsleep(unsigned int usec);
|
||||||
|
|
||||||
// data structures
|
// data structures
|
||||||
struct my_dns {
|
struct my_dns {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
CFLAGS+=-Wall -O -g -I/usr/local/include -I/usr/include
|
CFLAGS+=-Wall -O -g -I/usr/local/include -I/usr/include
|
||||||
LDLIBS=-L/usr/local/lib -lpcap -lpthread -lm
|
LDLIBS=-lpcap -lpthread -lm
|
||||||
|
|
||||||
all: dns_flood_detector
|
all: dns_flood_detector
|
||||||
strip dns_flood_detector
|
strip dns_flood_detector
|
||||||
|
|
Loading…
Reference in a new issue