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
|
||||
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,
|
||||
-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?
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
|
@ -62,6 +72,9 @@ Usage: ./dns_flood_detector [OPTION]
|
|||
-d run in background in daemon mode
|
||||
-D dump dns packets (implies -b)
|
||||
-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
|
||||
|
||||
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;
|
||||
}
|
1371
dns_flood_detector.c
1371
dns_flood_detector.c
File diff suppressed because it is too large
Load diff
|
@ -30,6 +30,13 @@
|
|||
#endif
|
||||
#define NS_MAXDNAME 1025
|
||||
#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
|
||||
#ifdef __sun__
|
||||
|
@ -41,10 +48,12 @@ typedef uint32_t u_int32_t;
|
|||
// prototypes
|
||||
void handle_IP(u_char *args,const struct pcap_pkthdr* pkthdr,const u_char* packet);
|
||||
int calculate_averages();
|
||||
int saddr_stats(int sock, struct sockaddr_in addr, char *hostname);
|
||||
int scour_bucket(int i);
|
||||
int find_bucket(struct in_addr *ip_src);
|
||||
int daemonize(void);
|
||||
int malloc_fail(char * var, int size);
|
||||
int microsleep(unsigned int usec);
|
||||
|
||||
// data structures
|
||||
struct my_dns {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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
|
||||
strip dns_flood_detector
|
||||
|
|
Loading…
Reference in a new issue