Compare commits

...

No commits in common. "upstream/1.12" and "master" have entirely different histories.

26 changed files with 1620 additions and 617 deletions

12
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,12 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: daily
time: "04:00"
reviewers:
- "waja"
pull-request-branch-name:
separator: "-"
open-pull-requests-limit: 10

36
.github/workflows/packaging_test.yml vendored Normal file
View file

@ -0,0 +1,36 @@
name: Packaging Test
on:
push:
branches:
- $default-branch
- development
- master
# Run tests for any PRs
pull_request:
env:
SOURCE_DIR: ./
ARTIFACTS_DIR: debian/build/release/
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
env:
DEBIAN_FRONTEND: "noninteractive"
- name: Remove github artefacts
run: |
rm -rf .github*
- name: Adjust distibution in changelog file
run: |
sed -i '0,/restricted/s//stable/' debian/changelog
- name: Build Debian package
uses: dawidd6/action-debian-package@v1.5.0
with:
artifacts_directory: debian/build/release/
os_distribution: testing
- name: Debug
run: |
ls -la

71
.github/workflows/release.yml vendored Normal file
View file

@ -0,0 +1,71 @@
on:
push:
# Sequence of patterns matched against refs/tags
tags:
- 'debian/*' # Push events to matching debian/*, i.e. debian/1.0-2, debian/20.15.10, debian/23.20020326
name: Release Process
env:
SOURCE_DIR: ./
ARTIFACTS_DIR: debian/build/release/
jobs:
create-release:
name: Create Release
runs-on: ubuntu-latest
outputs:
release-id: ${{ steps.create_release.outputs.id }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install needed packages
run: |
if [ $(dpkg -l | grep -c dpkg-dev) -ne 1 ]; then sudo apt-get update && sudo apt-get install -y dpkg-dev; fi
- name: Gather changelog
run: |
ls -la
dpkg-parsechangelog | tail -n +9 > debian.changelog
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
body_path: debian.changelog
draft: false
prerelease: false
build:
name: Build and upload packages
needs: create-release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
env:
DEBIAN_FRONTEND: "noninteractive"
- name: Remove github artefacts
run: |
rm -rf .github*
- name: Adjust distibution in changelog file
run: |
sed -i '0,/restricted/s//stable/' debian/changelog
- name: Build Debian package
uses: dawidd6/action-debian-package@v1.5.0
with:
artifacts_directory: debian/build/release/
os_distribution: testing
# - name: Build Debian package
# uses: pi-top/action-debian-package@v0.2.0
# with:
# artifacts_directory: debian/build/release/
# target_architectures: "amd64,i386"
- name: Upload the artifacts
uses: skx/github-action-publish-binaries@release-2.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
releaseId: ${{ needs.create-release.outputs.release-id }}
args: debian/build/release/*

32
.travis.yml Normal file
View file

@ -0,0 +1,32 @@
dist: xenial
sudo: required
env:
- TRAVIS_DEBIAN_DISTRIBUTION=unstable TRAVIS_DEBIAN_MIRROR="http://httpredir.debian.org/debian/" TRAVIS_DEBIAN_SECURITY_UPDATES=false
- TRAVIS_DEBIAN_DISTRIBUTION=testing TRAVIS_DEBIAN_MIRROR="http://httpredir.debian.org/debian/"
- TRAVIS_DEBIAN_DISTRIBUTION=stable TRAVIS_DEBIAN_MIRROR="http://httpredir.debian.org/debian/"
services:
- docker
before_script:
# fetch all tags (not done due travis cloning with depth=50)
- git fetch --tags
script:
# build the debian package
- wget -O- http://travis.debian.net/script.sh | sh -
after_script:
# run lintian after build
- sudo add-apt-repository -y ppa:waja/trusty-backports
- sudo apt-get update -qq
- sudo apt-get install -qq --no-install-recommends lintian
- lintian --info --display-info --display-experimental --pedantic --show-overrides ../*.deb && lintian --info --display-info --display-experimental --pedantic --show-overrides ../*.dsc
#notifications:
# email: false
branches:
except:
- /^debian\/\d/

17
README
View file

@ -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:

14
debian/.gitlab-ci.yml vendored Normal file
View file

@ -0,0 +1,14 @@
include:
- https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml
- https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml
variables:
RELEASE: 'unstable'
SALSA_CI_DISABLE_APTLY: 0
SALSA_CI_DISABLE_AUTOPKGTEST: 1
SALSA_CI_DISABLE_BLHC: 0
SALSA_CI_DISABLE_LINTIAN: 0
SALSA_CI_DISABLE_PIUPARTS: 1
SALSA_CI_DISABLE_REPROTEST: 1
SALSA_CI_DISABLE_BUILD_PACKAGE_ALL: 0
SALSA_CI_DISABLE_BUILD_PACKAGE_ANY: 0

182
debian/changelog vendored Normal file
View file

@ -0,0 +1,182 @@
dns-flood-detector (1.20-8) UNRELEASED; urgency=medium
*
-- Jan Wagner <waja@cyconet.org> Mon, 23 Jan 2023 12:11:35 +0000
dns-flood-detector (1.20-7) unstable; urgency=medium
[ Jan Wagner ]
* [34a5705] Use secure copyright file specification URI.
* [812b668] Remove overrides for lintian tags that are no longer supported.
* [1da11e5] Update watch file format version to 4.
* [bd99c1c] d/source/options: Adding .github to diff ignore
* [ab52f4a] Bump debhelper from old 12 to 13.
* [2d78c7e] Bump Standards-Version to 4.6.2
* [14e7160] Drop lsb-base, sysvinit-utils is essential
* [dcdc452] Set Rules-Requires-Root: no.
* [353f35e] Adding unitfile
-- Jan Wagner <waja@cyconet.org> Mon, 23 Jan 2023 11:34:04 +0000
dns-flood-detector (1.20-6) unstable; urgency=medium
[ Jan Wagner ]
* [9f76895] Adding d/.gitlab-ci.yml
* [2fdc34f] Bump Standards-Version to 4.5.1.0, no changes needed
[ Helmut Grohne ]
* [9db1d5f] Fix FTCBFS: Let dpkg's buildtools.mk supply $(CC).
(Closes: #949599)
[ Jan Wagner ]
* [88f1ad9] Adding Github CI
* [17a80e0] d/control: Raise compat level to 12
-- Jan Wagner <waja@cyconet.org> Wed, 06 Jan 2021 21:33:15 +0100
dns-flood-detector (1.20-5) unstable; urgency=medium
* [d1ee939] travis-ci: Use xenial image
* [187c4cb] d/control: Bump Standards-Version to 4.3.0, no changes needed
* [0f96e5a] d/rules: don't touch opmimisations cflags directly
-- Jan Wagner <waja@cyconet.org> Thu, 24 Jan 2019 10:45:28 +0100
dns-flood-detector (1.20-4) unstable; urgency=medium
* [0ff1167] d/control: Depend on lsb-base
* [51a32a6] d/changelog: Fixing typo
* [2d36138] travis-ci: Make use of travis.d.n
-- Jan Wagner <waja@cyconet.org> Mon, 05 Dec 2016 14:13:55 +0100
dns-flood-detector (1.20-3) unstable; urgency=medium
* [e388f86] travis-ci: don't install build-deps manual
* [5035fb3] travis-ci: build package with dpkg-buildpackage
* [1b42314] Refresh patches/fix_prototyp
* [e7cde7c] debian/control: reformating with warp-and-sort
* [fec98e0] travis-ci: grab actual used upstream version
* [118ec9c] travis-ci: Adding required arguments for trusty
* [aeab465] travis-ci: automatically install dependencies
* [9144fb8] d/control: Remove hardening-wrapper from Build-Depends
(Closes: #836622)
* [5b0f4ee] d/control: Bump Standards-Version to 3.9.8, no changes needed
-- Jan Wagner <waja@cyconet.org> Sat, 10 Sep 2016 14:08:46 +0200
dns-flood-detector (1.20-2) unstable; urgency=medium
* [278015a] Update Vcs-headers to selfhosted VCS
* [09a0485] Bump Standards-Version to 3.9.6, no changes needed
-- Jan Wagner <waja@cyconet.org> Sun, 12 Oct 2014 20:56:29 +0200
dns-flood-detector (1.20-1) unstable; urgency=low
* New upstream release
* Enable Hardening
- build-dep on hardening-wrapper
* [a454efe] Source init functions in init script
* [39f0420] Updating standards version to 3.9.4, no changes needed
* [a6c1551] Include dns_flood_collector.pl as example
* [b7b35b2] Update Vcs-headers
* [8260b99] Updating standards version to 3.9.5, no changes needed
* [7bffbb7] Add travis-ci config
* [1b8697f] Reorder and comment .travis.yml
* [a63e27c] Add lintian checks after build to .travis.yml
* [738c15d] Update VCS-* fields to current canonical URIs
* [ccc5dba] Update to recent copyright format
* [f383018] Adjust debian/rules to make hardening efficient
* [1438e9d] Provide lintian override for missing upstream changelog
-- Jan Wagner <waja@cyconet.org> Sun, 02 Mar 2014 19:49:52 +0100
dns-flood-detector (1.12-7) unstable; urgency=low
* Add trailing trunk/ at Vcs-Svn-field
* Updating standards version to 3.9.3, no changes needed
* Switch over to packaging format 3.0 (quit) (closes: #664409)
* Remove build-dependency of dpatch
* Use dh_prep instead of dh_clean -k
* Add build-arch and build-indep targets to debian/rules
-- Jan Wagner <waja@cyconet.org> Thu, 29 Mar 2012 18:26:14 +0200
dns-flood-detector (1.12-6) unstable; urgency=low
* Add "Copyright" to all copyrights in debian/copyright
* Updating standards version to 3.8.4
- Add README.source
* Migrate Vcs-Fields over to scm.uncompleted.org
* Add 1.0 to debian/source/format
* Add ${misc:Depends} to dependencies
-- Jan Wagner <waja@cyconet.org> Wed, 10 Mar 2010 00:07:06 +0100
dns-flood-detector (1.12-5) unstable; urgency=low
* Updating standards version to 3.8.2, no changes needed
* remove absolute path of pidof from preinst
-- Jan Wagner <waja@cyconet.org> Sun, 26 Jul 2009 00:31:45 +0200
dns-flood-detector (1.12-4) unstable; urgency=low
* Updating standards version to 3.8.0, no changes needed
* implement machine-interpretable copyright file
-- Jan Wagner <waja@cyconet.org> Sun, 20 Jul 2008 12:53:51 +0200
dns-flood-detector (1.12-3) unstable; urgency=low
* added Vcs- fields, moved Homepage into source header's field
* bump standards version to 3.7.3 (no changes needed)
* change copyright of packaging to 2008 in debian/copyright
* get rid of 'ps aux' in init script and preinst, using pidof instead
-- Jan Wagner <waja@cyconet.org> Mon, 14 Apr 2008 22:39:46 +0200
dns-flood-detector (1.12-2) unstable; urgency=low
* some cosmetic fixes to init script
* make start-stop-daemon working instead of using kill (Closes: #431676).
* providing upgrade path via preinst
* drop own maintainers scripts and make again use of debhelper
-- Jan Wagner <waja@cyconet.org> Wed, 04 Jul 2007 12:29:06 +0200
dns-flood-detector (1.12-1) unstable; urgency=medium
* New upstream release
* modified fix_prototyp patch for upstream
-- Jan Wagner <waja@cyconet.org> Thu, 23 Nov 2006 13:35:11 +0100
dns-flood-detector (1.10-4) unstable; urgency=low
* included fix_prototyp patch provided by "dann frazier <dannf@debian.org>"
(Closes: #399283).
* build depend to dpatch
-- Jan Wagner <waja@cyconet.org> Sun, 19 Nov 2006 10:18:55 +0100
dns-flood-detector (1.10-3) unstable; urgency=low
* using killall in init script to get daemon stopped
* same for prerm
-- Jan Wagner <waja@cyconet.org> Thu, 9 Nov 2006 20:49:10 +0100
dns-flood-detector (1.10-2) unstable; urgency=low
* fixed typo in initscript
-- Jan Wagner <waja@cyconet.org> Sat, 4 Nov 2006 21:46:03 +0100
dns-flood-detector (1.10-1) unstable; urgency=low
* Initial release (Closes: #396618).
-- Jan Wagner <waja@cyconet.org> Fri, 3 Nov 2006 12:39:42 +0100

25
debian/control vendored Normal file
View file

@ -0,0 +1,25 @@
Source: dns-flood-detector
Section: net
Priority: optional
Maintainer: Jan Wagner <waja@cyconet.org>
Build-Depends: debhelper-compat (= 13), libpcap0.8-dev
Homepage: http://www.adotout.com/
Vcs-Browser: https://gitlab.uncompleted.org/debian/dns-flood-detector
Vcs-Git: https://gitlab.uncompleted.org/debian/dns-flood-detector.git
Standards-Version: 4.6.2
Rules-Requires-Root: no
Package: dns-flood-detector
Architecture: any
Depends: ${misc:Depends}, ${shlibs:Depends}
Description: detect abusive usage levels on high traffic nameservers
This package provides the dns-flood-detector daemon.
.
It was developed to detect abusive usage levels on high traffic nameservers
and to enable quick response in halting the use of one's nameserver to
facilitate spam.
It uses libpcap (in non-promiscuous mode) to monitor incoming dns queries to a
nameserver. The tool may be run in one of two modes, either daemon mode or
"bindsnap" mode. In daemon mode, the tool will alarm via syslog. In bindsnap
mode, the user is able to get near-real-time stats on usage to aid in more
detailed troubleshooting.

30
debian/copyright vendored Normal file
View file

@ -0,0 +1,30 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: DNS Flood Detector
Upstream-Contact: Dennis Opacki <dopacki@adotout.com>
Source: http://www.adotout.com/
Files: *
Copyright: Copyright (C) 2003 Dennis Opacki <dopacki@adotout.com>
License: GPL-2+
Files: debian/*
Copyright: Copyright (C) 2006, 2008 Jan Wagner <waja@cyconet.org>
License: GPL-2+
License: GPL-2+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
.
On Debian systems, the complete text of the GNU General Public License can be
found in /usr/share/common-licenses/GPL-2 file.

7
debian/default vendored Normal file
View file

@ -0,0 +1,7 @@
# Defaults for dns-flood-detector initscript
# sourced by /etc/init.d/dns-flood-detector
# installed at /etc/default/dns-flood-detector by the maintainer scripts
# options that are passed to the Daemon.
# here: daemon mode, be more verbose, alarm at > 5/s, stats every 3 secs
DAEMON_OPTS="-d -v -v -t5 -w3"

70
debian/dns-flood-detector.8 vendored Normal file
View file

@ -0,0 +1,70 @@
.TH DNS-FLOOD-DETECTOR 8 "2006-11-03" "1.10" "dns flood detection tool"
.SH NAME
DNS-FLOOD-DETECTOR \- dns flood detection and alert tool
.SH SYNOPSIS
.B dns-flood-detector
.RB [\| \-b \||\| \-d \|]
.RB [\| \-v \|]
.RB [\| \-h \|]
.RB [\| \-i
.IR device \|]
.RB [\| -t
.IR n \|]
.RB [\| -a
.IR n \|]
.RB [\| -w
.IR n \|]
.RB [\| -x
.IR n \|]
.RB [\| -m
.IR n \|]
.SH DESCRIPTION
.B DNS Flood Detector
was developed to detect abusive usage levels on high traffic nameservers and to
enable quick response to the use of one's nameserver to facilitate spam.
.SH OPTIONS
.B
.TP
.B \-b
run in foreground in bindsnap mode
.TP
.B \-d
run in background in daemon mode
.TP
.B \-v
verbose output \- use again for more verbosity
.TP
.B \-h
display help
.TP
.B \-i device
specify device name to listen on
.TP
.B \-t n
alarm at >n queries per second
.TP
.B \-a n
reset alarm after n seconds
.TP
.B \-w n
calculate stats every n seconds
.TP
.B \-x n
create n buckets
.TP
.B \-m n
report overall stats every n seconds
.SH SEE ALSO
.B Website
<http://www.adotout.com/>
.SH AUTHOR
DNS-FLOOD-DETECTOR was written by Dennis Opacki <dopacki@adotout.com>.
.PP
This manual page was written by Jan Wagner <waja@cyconet.org>,
for the Debian project (but may be used by others).

1
debian/docs vendored Normal file
View file

@ -0,0 +1 @@
README

1
debian/examples vendored Normal file
View file

@ -0,0 +1 @@
dns_flood_collector.pl

66
debian/init.d vendored Normal file
View file

@ -0,0 +1,66 @@
#!/bin/sh
# Written by Miquel van Smoorenburg <miquels@cistron.nl>.
# Modified for Debian
# by Ian Murdock <imurdock@gnu.ai.mit.edu>.
#
# Version: @(#)skeleton 1.9 26-Feb-2001 miquels@cistron.nl
# /etc/init.d/dns-flood-detector: v1 2006/11/03 Jan Wagner <waja@cyconet.org>
### BEGIN INIT INFO
# Provides: dns-flood-detector
# Required-Start: $local_fs $network $remote_fs $syslog
# Required-Stop: $local_fs $network $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: start and stop the dns-flood-detector daemon
# Description: detect abusive usage levels on high traffic nameservers
### END INIT INFO
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/bin/dns-flood-detector
NAME=dns-flood-detector
DESC=dns-flood-detector
test -x $DAEMON || exit 0
. /lib/lsb/init-functions
# Include dns-flood-detector defaults if available
if [ -f /etc/default/dns-flood-detector ] ; then
. /etc/default/dns-flood-detector
fi
set -e
case "$1" in
start)
echo -n "Starting $DESC: "
start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \
--exec $DAEMON -- $DAEMON_OPTS
/bin/pidof $DAEMON > /var/run/$NAME.pid
echo "$NAME."
;;
stop)
echo -n "Stopping $DESC: "
start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \
--exec $DAEMON
echo "$NAME."
;;
restart|force-reload)
echo -n "Restarting $DESC: "
start-stop-daemon --stop --quiet --pidfile \
/var/run/$NAME.pid --exec $DAEMON
start-stop-daemon --start --quiet --pidfile \
/var/run/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS
/bin/pidof $DAEMON > /var/run/$NAME.pid
echo "$NAME."
;;
*)
N=/etc/init.d/$NAME
# echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
echo "Usage: $N {start|stop|restart|force-reload}" >&2
exit 1
;;
esac
exit 0

13
debian/patches/fix_prototyp vendored Normal file
View file

@ -0,0 +1,13 @@
From: dann frazier <dannf@debian.org>
Subject: fix missing function prototype definition
--- a/dns_flood_detector.c
+++ b/dns_flood_detector.c
@@ -107,6 +107,7 @@
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
+#include <sys/socket.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>

1
debian/patches/series vendored Normal file
View file

@ -0,0 +1 @@
fix_prototyp

8
debian/preinst vendored Executable file
View file

@ -0,0 +1,8 @@
#!/bin/sh
set -e
# generate correct pid file, for versions where was non or incorrect
if [ "$1" = "upgrade" ] && [ "$2" ] && dpkg --compare-versions "$2" <= "1.12-1"; then
pidof dns-flood-detector > /var/run/dns-flood-detector.pid
fi
#DEBHELPER#

76
debian/rules vendored Executable file
View file

@ -0,0 +1,76 @@
#!/usr/bin/make -f
# written by Jan Wagner <waja@cyconet.org>
#
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
include /usr/share/dpkg/buildtools.mk
# hardening
export DEB_BUILD_HARDENING=1
CPPFLAGS:=$(shell dpkg-buildflags --get CPPFLAGS)
CFLAGS:=$(shell dpkg-buildflags --get CFLAGS)
CXXFLAGS:=$(shell dpkg-buildflags --get CXXFLAGS)
LDFLAGS:=$(shell dpkg-buildflags --get LDFLAGS)
CFLAGS += -D_BSD_SOURCE -Wall -g
LDLIBS += -lpcap -lpthread -lm
build: build-arch build-indep
build-arch: build-stamp
build-indep: build-stamp
build-stamp:
dh_testdir
# Add here commands to compile the package.
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) dns_flood_detector.c $(LDLIBS) -o dns_flood_detector
touch $@
clean:
dh_testdir
dh_testroot
rm -f build-stamp
# Add here commands to clean up after the build process.
rm -rf dns_flood_detector *.o *~
dh_clean
install: build
dh_testdir
dh_testroot
dh_prep
dh_installdirs
# Add here commands to install the package into debian/dns-flood-detector.
install -D -m 0755 dns_flood_detector debian/dns-flood-detector/usr/bin/dns-flood-detector
install -D -m 0644 debian/default debian/dns-flood-detector/etc/default/dns-flood-detector
install -D -m 0755 debian/init.d debian/dns-flood-detector/etc/init.d/dns-flood-detector
# Build architecture-independent files here.
binary-indep: build install
# We have nothing to do by default.
# Build architecture-dependent files here.
binary-arch: build install
dh_testdir
dh_testroot
dh_installchangelogs
dh_installdocs
dh_installman debian/dns-flood-detector.8
dh_installexamples
dh_installinit -- defaults 40
dh_installsystemd --no-enable
dh_lintian
dh_link
dh_strip
dh_compress
dh_fixperms
dh_shlibdeps
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install

14
debian/service vendored Normal file
View file

@ -0,0 +1,14 @@
[Unit]
Description=dns-flood-detector daemon
[Service]
Environment=PIDFILE=/var/run/dns-flood-detector.pid
EnvironmentFile=-/etc/default/dns-flood-detector
ExecStart=/usr/sbin/dns-flood-detector $DAEMON_OPTS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
Type=notify
[Install]
WantedBy=multi-user.target

1
debian/source/format vendored Normal file
View file

@ -0,0 +1 @@
3.0 (quilt)

1
debian/source/options vendored Normal file
View file

@ -0,0 +1 @@
extend-diff-ignore = '(^|/)(\.travis\.yml|\.git|\.github|\.gitgnore|config\.sub|config\.guess)'

2
debian/watch vendored Normal file
View file

@ -0,0 +1,2 @@
version=4
http://www.adotout.com dnsflood-(.*)\.tgz

157
dns_flood_collector.pl Executable file
View 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;
}

View file

@ -30,6 +30,10 @@
-d run in background in "daemon" mode
-D dump dns packets (implies -b)
-v detailed information (use twice for more detail)
-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 usage info
Copyright (C) 2003 Dennis Opacki
@ -93,6 +97,9 @@
store addresses raw, instead of as text (speedup/reduce memory usage) - <erikm@buh.org>
fix crash on long syslog messages - <jwestfall@surrealistic.net>
--- new in v1.2 ---
05/10/2012 - added sending of source-IP telemetry to a network collector - <dopacki@adotout.com>
********************************************************************************/
#include <pcap.h>
@ -124,14 +131,17 @@
#include <string.h>
#include <sys/stat.h>
#include "dns_flood_detector.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
// global variables and their defaults
pthread_mutex_t stats_lock;
struct bucket **bb;
int option_t = 60;
int option_a = 90;
int option_w = 10;
int option_x = 50;
int option_w = 20;
int option_x = 10000;
int option_m = 0;
int option_b = 0;
int option_d = 0;
@ -141,25 +151,148 @@ int option_h = 0;
int option_Q = 0;
int option_A = 0;
int option_M = 0;
int option_s = 0;
int totals = 0;
char VERSION[] = "1.12";
static char *target_ip = NULL;
int target_port = DEFAULT_PORT;
int mcast_ttl = 10;
char hostname[HOST_NAME_MAX];
char VERSION[] = "1.2";
// 255.255.255.255 is invalid as a src IP address; we'll use it to mark empty buckets
#define BCAST 0xffFFffFF
// this is our statistics thread
void *run_stats () {
// prepare multicast socket
struct sockaddr_in addr;
int sock;
sock = socket(AF_INET, SOCK_DGRAM,0);
if (sock<0) {
perror("can't set up socket");
exit(1);
}
// is it harmful to set this on non-multicast sockets?
setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&mcast_ttl, sizeof(mcast_ttl));
bzero((char*)&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(target_ip);
addr.sin_port = htons(target_port);
// get our hostname
gethostname(hostname, HOST_NAME_MAX-1);
while (1) {
// check statistical stuff
pthread_mutex_lock(&stats_lock);
calculate_averages();
saddr_stats(sock,addr,hostname);
pthread_mutex_unlock(&stats_lock);
sleep (option_w);
}
}
// report saddr stats
int saddr_stats(int sock, struct sockaddr_in addr, char *hostname) {
u_int i;
int addrlen;
char buff[MAXMESSAGE];
int buffhead = 0;
char st_time[10];
time_t now = time(0);
struct tm *raw_time = localtime(&now);
addrlen = sizeof(addr);
snprintf(st_time, 9, "%02d:%02d:%02d",raw_time->tm_hour,raw_time->tm_min,raw_time->tm_sec);
// prepare jason structure for multicast datagrams
char head[MAXHEAD];
char *tail = "}}";
snprintf(head,MAXHEAD,"{\"hostname\":\"%s\",\"type\":\"source\",\"data\":{",hostname);
int netsize = MAXMESSAGE - strlen(head) - strlen(tail);
if (netsize<=0) exit(EXIT_FAILURE); // this should never ever happen
int avail = netsize;
int dlen = 0;
char datalet[MAXDATALET];
// copy the initial json header into the buffer
bzero(buff,sizeof(buff));
memcpy(buff,head,strlen(head));
buffhead = buffhead + strlen(head);
// report all source address stats, cleaning up afterward
for (i=0; ( (i < option_x) && ( bb[i]->ip_addr.s_addr != 0 ) ); i++) {
if ( bb[i]->ip_addr.s_addr != BCAST ) {
// prepare a datalet
snprintf(datalet,MAXDATALET,"\"%s\":%d,",inet_ntoa(bb[i]->ip_addr),bb[i]->udp_count+bb[i]->tcp_count);
dlen = strlen(datalet);
// see if the current datagram has room for the datalet
if ( avail > dlen ) {
// append this datalet to the current datagram (minus null terminator)
avail = avail - dlen;
memcpy(buff+buffhead,datalet,dlen);
buffhead = buffhead + dlen;
}
// no room in current dgram
else {
// remove trailing comma from the buffer so we can close it out
buffhead = buffhead - 1;
// add the tail
strncpy(buff+buffhead,tail, strlen(tail));
// send the transmission if option_s is set
if (option_s > 0 ) {
sendto(sock,buff,strlen(buff)+1,0,(struct sockaddr *) &addr, addrlen);
microsleep(10);
}
// init next datagram
bzero(buff,sizeof(buff));
memcpy(buff,head,strlen(head));
buffhead = strlen(head);
avail = netsize;
// append this datalet to the current datagram (minus null terminatin)
avail = avail - dlen;
memcpy(buff+buffhead,datalet,dlen);
buffhead = buffhead + dlen;
}
}
scour_bucket(i);
}
// transmit final buffer contents if needed
if ( ( option_b == 0) && (buffhead>strlen(head)) ) {
// remove trailing comma
buffhead = buffhead - 1;
// add the tail
strncpy(buff+buffhead,tail,strlen(tail));
// send the multicast transmission
sendto(sock,buff,strlen(buff)+1,0,(struct sockaddr *) &addr, addrlen);
microsleep(10);
bzero(buff,sizeof(buff));
}
return 1;
}
// calculate the running average within each bucket
int calculate_averages() {
u_int i,j,delta,cursize,qps;
@ -188,7 +321,6 @@ int calculate_averages() {
// handle threshold crossing
if ( bb[i]->qps > option_t ) {
// display detail to either syslog or stdout
if ( option_b ) {
if ( ! option_v ) {
@ -198,8 +330,8 @@ int calculate_averages() {
else {
printf("[%s] source [%s] - %u qps tcp : %u qps udp ",st_time,inet_ntoa(bb[i]->ip_addr),
(u_int)ceil( ((float)bb[i]->tcp_count/delta)),
(u_int)ceil( ((float)bb[i]->udp_count/delta))
);
(u_int)ceil( ((float)bb[i]->udp_count/delta)));
if ( option_v >1 ) {
for (j=0;types[j];j++) {
qps = (u_int)ceil((float)bb[i]->qstats[types[j]]/delta);
@ -225,8 +357,7 @@ int calculate_averages() {
newsize = MAXSYSLOG;
cursize = snprintf(target,newsize,"source [%s] - %u tcp qps : %u udp qps ",inet_ntoa(bb[i]->ip_addr),
(u_int)ceil( ((float)bb[i]->tcp_count/delta)),
(u_int)ceil( ((float)bb[i]->udp_count/delta))
);
(u_int)ceil( ((float)bb[i]->udp_count/delta)));
newsize-=cursize;
for (j=0;types[j];j++ ) {
@ -245,8 +376,7 @@ int calculate_averages() {
else {
syslog(LOG_NOTICE,"source [%s] - %u tcp qps - %u udp qps\n",inet_ntoa(bb[i]->ip_addr),
(u_int)ceil( ((float)bb[i]->tcp_count/delta)),
(u_int)ceil( ((float)bb[i]->udp_count/delta))
);
(u_int)ceil( ((float)bb[i]->udp_count/delta)));
}
// reset alarm
@ -283,8 +413,7 @@ int calculate_averages() {
newsize = MAXSYSLOG;
cursize = snprintf(target,newsize,"[totals] - %3.2f tcp qps : %3.2f udp qps ",
((float)bb[totals]->tcp_count/delta),
((float)bb[totals]->udp_count/delta)
);
((float)bb[totals]->udp_count/delta));
newsize-=cursize;
for (j=0;types[j];j++ ) {
@ -303,13 +432,11 @@ int calculate_averages() {
else {
syslog(LOG_NOTICE,"[totals] - %3.2f tcp qps : %3.2f udp qps\n",
((float)bb[totals]->tcp_count/delta),
((float)bb[totals]->udp_count/delta)
);
((float)bb[totals]->udp_count/delta));
}
}
scour_bucket(totals);
}
return 1;
}
@ -324,6 +451,7 @@ int valid_dns_char(char c) {
return 0;
}
// purge and initialize all buckets
void init_buckets() {
u_int i;
@ -353,6 +481,7 @@ int scour_bucket( int i ) {
for (j=0;j<256;j++) {
bb[i]->qstats[j]=0;
}
return 1;
}
@ -413,6 +542,7 @@ int find_bucket(struct in_addr *ip_src) {
// resumes flooding if there isn't bucket contention
// churning them out and resetting the timer for the rate
// calculation...
if ( ( bb[i]->last_packet != 0 ) && ((oldest==0)||( bb[i]->last_packet < oldest))) {
oldest = bb[i]->last_packet;
bucket = i;
@ -491,7 +621,7 @@ void handle_IP(u_char *args, const struct pcap_pkthdr* pkthdr,const u_char* pack
else {
// populate dns header
dns = (struct my_dns *) ( (char *) packet + sizeof(struct ether_header) + sizeof (struct ip) + sizeof (struct udphdr) );
data = (char *) packet +sizeof(struct ether_header) + sizeof (struct ip) + sizeof (struct udphdr) + sizeof(struct my_dns);
data = (unsigned char *) packet +sizeof(struct ether_header) + sizeof (struct ip) + sizeof (struct udphdr) + sizeof(struct my_dns);
}
}
@ -500,7 +630,7 @@ void handle_IP(u_char *args, const struct pcap_pkthdr* pkthdr,const u_char* pack
tcp = (struct tcphdr *) ( (char *) packet + sizeof(struct ether_header)+ sizeof (struct ip) );
// ignore packets without push flag set
if (! tcp->th_flags & TH_PUSH) return;
if (! (tcp->th_flags & TH_PUSH)) return;
// try to make sure it is safe to cast packet into dns structure
if ( (sizeof(struct my_dns)+sizeof(struct ether_header)+sizeof(struct ip)+(tcp->th_off * sizeof(u_int32_t)) + sizeof(u_int16_t)) >= caplen ) {
@ -510,7 +640,7 @@ void handle_IP(u_char *args, const struct pcap_pkthdr* pkthdr,const u_char* pack
// populate dns header
// tcp dns lookups also include a 16bit length field = dns header + data.
dns = (struct my_dns *) ( (char *) packet + sizeof(struct ether_header)+ sizeof (struct ip) + (tcp->th_off * sizeof(u_int32_t) + sizeof(u_int16_t)));
data = (char *) packet + sizeof(struct ether_header) + sizeof (struct ip) + (tcp->th_off * sizeof(u_int32_t)) + sizeof(struct my_dns) + sizeof(u_int16_t);
data = (unsigned char *) packet + sizeof(struct ether_header) + sizeof (struct ip) + (tcp->th_off * sizeof(u_int32_t)) + sizeof(struct my_dns) + sizeof(u_int16_t);
}
}
@ -583,14 +713,14 @@ int main(int argc,char **argv){
struct sigaction sa;
struct in_addr addr,tmpaddr;
u_int f_size;
char *args = NULL;
char *name = NULL;
u_int c = 0;
if ( ( name = (char *)strdup(argv[0]) ) == NULL) malloc_fail("name", strlen(argv[0]) );
// loop through command line options and get options
while(1) {
c = getopt(argc, argv,"i:t:a:w:x:m:A:M:QbdDvh");
c = getopt(argc, argv,"i:t:a:w:x:m:A:M:QbdDvsh");
if (c==-1) break;
switch(c) {
@ -673,8 +803,18 @@ int main(int argc,char **argv){
case 'v':
option_v++;
break;
case 's':
option_s = 1;
break;
case 'h':
option_h = 1;
break;
case 'z':
target_ip = optarg;
break;
case 'p':
target_port = atoi(optarg);
break;
default:
break;
}
@ -682,6 +822,7 @@ int main(int argc,char **argv){
// display usage info if needed
if (optind<argc) option_h = 1;
if (option_h) {
fprintf(stderr,"dns_flood_detector, version %s\n",VERSION);
fprintf(stderr,"Usage: %s [OPTION]\n\n",name);
@ -698,10 +839,17 @@ int main(int argc,char **argv){
fprintf(stderr,"-d run in background in daemon mode\n");
fprintf(stderr,"-D dump dns packets (implies -b)\n");
fprintf(stderr,"-v verbose output - use again for more verbosity\n");
fprintf(stderr,"-s send source-IP data to network collector as JSON\n");
fprintf(stderr,"-z addr address to send stats to (default 226.1.1.2)\n");
fprintf(stderr,"-p N UDP port to send stats to (default 2000)\n");
fprintf(stderr,"-h display this usage information\n");
exit(1);
}
if ( target_ip == NULL ) {
target_ip = DEFAULT_IP;
}
// if dumping packets, force option_b and disable option_d
if( option_D ) {
if( ! option_b )
@ -709,7 +857,6 @@ int main(int argc,char **argv){
if( option_d )
option_d = 0;
}
if ( ( option_Q ) && ( option_A ) ) {
@ -717,12 +864,14 @@ int main(int argc,char **argv){
fprintf(stderr,"You can't specify both -A (address filter) and -Q (no filter)\n");
exit(1);
}
if ( ( ! option_d ) && ( ! option_b ) ) {
fprintf(stderr,"%s couldn't start\n",name);
fprintf(stderr,"You must specify either -d (daemon) or -b (bindsnap)\n");
exit(1);
}
free(name);
// set up for daemonized operation unless running in bindsnap mode
if ( ! option_b ) {
openlog("dns_flood_detector",LOG_PID|LOG_CONS,LOG_DAEMON);
@ -735,8 +884,7 @@ int main(int argc,char **argv){
sa.sa_handler=exit;
sa.sa_flags=0;
if(sigaction(SIGTERM,&sa,NULL)) {
syslog(LOG_ERR,"Unable to set signal handler: %s. Exiting.",
strerror(errno));
syslog(LOG_ERR,"Unable to set signal handler: %s. Exiting.",strerror(errno));
}
}
@ -763,6 +911,7 @@ int main(int argc,char **argv){
dst_addr[strlen((char *)inet_ntoa(addr))]='\0';
addr.s_addr = (unsigned long int)maskp;
if (!option_M) {
if ( ( dst_mask = (char *)malloc( strlen((char *)inet_ntoa(addr))+1) ) == NULL ) malloc_fail("dest_mask", strlen((char *)inet_ntoa(addr))+1 );
strncpy(dst_mask,(char*)inet_ntoa(addr),strlen((char *)inet_ntoa(addr)));
@ -788,6 +937,7 @@ int main(int argc,char **argv){
if ( option_b && option_v ) {
printf("using filter \"%s\" on dev %s\n", filter, dev);
}
// open device for reading only local traffic
descr = pcap_open_live(dev,1500,0,1,errbuf);
if(descr == NULL) {
@ -822,7 +972,7 @@ int main(int argc,char **argv){
}
// main pcap loop
pcap_loop(descr,-1,handle_IP,args);
pcap_loop(descr,-1,&handle_IP,NULL);
// done
closelog();
@ -833,6 +983,7 @@ int main(int argc,char **argv){
int daemonize(void) {
pid_t pid;
int fd;
int a;
fd=open("/dev/null",O_RDWR);
if(fd<0) {
@ -853,7 +1004,7 @@ int daemonize(void) {
}
setsid();
chdir("/");
a = chdir("/");
umask(0);
return 0;
}
@ -868,3 +1019,13 @@ int malloc_fail( char * var, int size ) {
}
exit(1);
}
int microsleep(unsigned int usec) {
struct timeval timeout;
timeout.tv_sec = usec / 1000000;
timeout.tv_usec = usec % 1000000;
while ((select(0, (fd_set *) 0, (fd_set *) 0,(fd_set *) 0, &timeout) < 0) && (errno == EINTR));
return(0);
}

View file

@ -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 {

View file

@ -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