Compare commits
No commits in common. "master" and "upstream/1.10" have entirely different histories.
master
...
upstream/1
12
.github/dependabot.yml
vendored
12
.github/dependabot.yml
vendored
|
@ -1,12 +0,0 @@
|
||||||
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
36
.github/workflows/packaging_test.yml
vendored
|
@ -1,36 +0,0 @@
|
||||||
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
71
.github/workflows/release.yml
vendored
|
@ -1,71 +0,0 @@
|
||||||
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
32
.travis.yml
|
@ -1,32 +0,0 @@
|
||||||
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/
|
|
33
README
33
README
|
@ -1,4 +1,4 @@
|
||||||
DNS FLood Detector 1.2
|
DNS FLood Detector 1.10
|
||||||
Dennis Opacki
|
Dennis Opacki
|
||||||
dopacki@adotout.com
|
dopacki@adotout.com
|
||||||
|
|
||||||
|
@ -17,19 +17,6 @@ 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
|
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
|
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.
|
near-real-time stats on usage to aid in more detailed troubleshooting.
|
||||||
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?
|
How do I build it?
|
||||||
|
|
||||||
|
@ -51,7 +38,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,2003,2008 or Win7}?
|
Will it run under Windows {95,98,NT,2000,XP}?
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
|
@ -65,26 +52,22 @@ Usage: ./dns_flood_detector [OPTION]
|
||||||
-w N calculate stats every N seconds
|
-w N calculate stats every N seconds
|
||||||
-x N create N buckets
|
-x N create N buckets
|
||||||
-m N mark total query rate every N seconds
|
-m N mark total query rate every N seconds
|
||||||
-A addr filter for specific address
|
|
||||||
-M mask netmask for filter (in conjunction with -A)
|
|
||||||
-Q don't filter by local interface address
|
|
||||||
-b run in foreground in bindsnap mode
|
-b run in foreground in bindsnap mode
|
||||||
-d run in background in daemon mode
|
-d run in background in daemon mode
|
||||||
-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:
|
||||||
|
|
||||||
dopacki:~$ sudo ./dns_flood_detector -v -v -b -t10
|
dopacki:~$ sudo ./dns_flood_detector -v -v -b -t10
|
||||||
[15:14:56] source [192.168.1.45] - 0 qps tcp : 24 qps udp [8 qps A] [16 qps PTR]
|
[15:14:56] source [192.168.1.45] - 0 qps tcp : 24 qps udp [8 qps A] [16
|
||||||
|
qps PTR]
|
||||||
[15:14:56] source [10.0.24.2] - 0 qps tcp : 15 qps udp [15 qps A]
|
[15:14:56] source [10.0.24.2] - 0 qps tcp : 15 qps udp [15 qps A]
|
||||||
[15:15:06] source [192.168.1.45] - 0 qps tcp : 24 qps udp [8 qps A] [16 qps PTR]
|
[15:15:06] source [192.168.1.45] - 0 qps tcp : 24 qps udp [8 qps A] [16
|
||||||
|
qps PTR]
|
||||||
[15:15:06] source [10.0.24.2] - 0 qps tcp : 15 qps udp [14 qps A]
|
[15:15:06] source [10.0.24.2] - 0 qps tcp : 15 qps udp [14 qps A]
|
||||||
[15:15:16] source [192.168.1.45] - 0 qps tcp : 23 qps udp [7 qps A] [15 qps PTR]
|
[15:15:16] source [192.168.1.45] - 0 qps tcp : 23 qps udp [7 qps A] [15
|
||||||
|
qps PTR]
|
||||||
|
|
||||||
What if I have questions?
|
What if I have questions?
|
||||||
|
|
||||||
|
|
14
debian/.gitlab-ci.yml
vendored
14
debian/.gitlab-ci.yml
vendored
|
@ -1,14 +0,0 @@
|
||||||
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
182
debian/changelog
vendored
|
@ -1,182 +0,0 @@
|
||||||
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
25
debian/control
vendored
|
@ -1,25 +0,0 @@
|
||||||
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
30
debian/copyright
vendored
|
@ -1,30 +0,0 @@
|
||||||
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
7
debian/default
vendored
|
@ -1,7 +0,0 @@
|
||||||
# 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
70
debian/dns-flood-detector.8
vendored
|
@ -1,70 +0,0 @@
|
||||||
.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
1
debian/docs
vendored
|
@ -1 +0,0 @@
|
||||||
README
|
|
1
debian/examples
vendored
1
debian/examples
vendored
|
@ -1 +0,0 @@
|
||||||
dns_flood_collector.pl
|
|
66
debian/init.d
vendored
66
debian/init.d
vendored
|
@ -1,66 +0,0 @@
|
||||||
#!/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
13
debian/patches/fix_prototyp
vendored
|
@ -1,13 +0,0 @@
|
||||||
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
1
debian/patches/series
vendored
|
@ -1 +0,0 @@
|
||||||
fix_prototyp
|
|
8
debian/preinst
vendored
8
debian/preinst
vendored
|
@ -1,8 +0,0 @@
|
||||||
#!/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
76
debian/rules
vendored
|
@ -1,76 +0,0 @@
|
||||||
#!/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
14
debian/service
vendored
|
@ -1,14 +0,0 @@
|
||||||
[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
1
debian/source/format
vendored
|
@ -1 +0,0 @@
|
||||||
3.0 (quilt)
|
|
1
debian/source/options
vendored
1
debian/source/options
vendored
|
@ -1 +0,0 @@
|
||||||
extend-diff-ignore = '(^|/)(\.travis\.yml|\.git|\.github|\.gitgnore|config\.sub|config\.guess)'
|
|
2
debian/watch
vendored
2
debian/watch
vendored
|
@ -1,2 +0,0 @@
|
||||||
version=4
|
|
||||||
http://www.adotout.com dnsflood-(.*)\.tgz
|
|
|
@ -1,157 +0,0 @@
|
||||||
#!/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;
|
|
||||||
}
|
|
|
@ -22,18 +22,9 @@
|
||||||
(default 50)
|
(default 50)
|
||||||
-m n mark overall query rate every n seconds
|
-m n mark overall query rate every n seconds
|
||||||
(default disabled)
|
(default disabled)
|
||||||
-A addr filter for specific address
|
|
||||||
-M mask netmask for filter (in conjunction with -A)
|
|
||||||
-Q monitor any addresses (default is to filter only for
|
|
||||||
primary addresses on chosen interface)
|
|
||||||
-b run in foreground in "bindsnap" mode
|
-b run in foreground in "bindsnap" mode
|
||||||
-d run in background in "daemon" mode
|
-d run in background in "daemon" mode
|
||||||
-D dump dns packets (implies -b)
|
|
||||||
-v detailed information (use twice for more detail)
|
-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
|
-h usage info
|
||||||
|
|
||||||
Copyright (C) 2003 Dennis Opacki
|
Copyright (C) 2003 Dennis Opacki
|
||||||
|
@ -81,25 +72,6 @@
|
||||||
10/22/2003 - Added 'mark status' option via '-m' - <dopacki@adotout.com>
|
10/22/2003 - Added 'mark status' option via '-m' - <dopacki@adotout.com>
|
||||||
10/23/2003 - Code cleanup in verbose syslogging - <dopacki@adotout.com>
|
10/23/2003 - Code cleanup in verbose syslogging - <dopacki@adotout.com>
|
||||||
|
|
||||||
--- new in v1.11 ---
|
|
||||||
06/14/2005 - added A6, AAAA, ANY qtypes - <jwestfall@surrealistic.net>
|
|
||||||
examine all packets with >= 1 qdcount - <jwestfall@surrealistic.net>
|
|
||||||
stop processing packet if invalid dns char - <jwestfall@surrealistic.net>
|
|
||||||
fix tcp parsing - <jwestfall@surrealistic.net>
|
|
||||||
add option_D to dump packets - <jwestfall@surrealistic.net>
|
|
||||||
|
|
||||||
--- new in v1.12 ---
|
|
||||||
03/03/2006 - added address filtering options - <erikm@buh.org>
|
|
||||||
fix segfault using argv[0] after getopt - <erikm@buh.org>
|
|
||||||
fix rounding from float/int conversions, use unsigned more consistently - <erikm@buh.org>
|
|
||||||
clean up to work with -Wall - <erikm@buh.org>
|
|
||||||
show fractional qps rates for totals - <erikm@buh.org>
|
|
||||||
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>
|
#include <pcap.h>
|
||||||
|
@ -112,7 +84,6 @@
|
||||||
#include <netinet/ip.h>
|
#include <netinet/ip.h>
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
#include <netinet/udp.h>
|
#include <netinet/udp.h>
|
||||||
#include <arpa/inet.h>
|
|
||||||
#ifdef __bsdi__
|
#ifdef __bsdi__
|
||||||
#include <net/if_ethernet.h>
|
#include <net/if_ethernet.h>
|
||||||
#else
|
#else
|
||||||
|
@ -128,215 +99,79 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include <string.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include "dns_flood_detector.h"
|
#include "dns_flood_detector.h"
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/select.h>
|
|
||||||
|
|
||||||
// global variables and their defaults
|
// global variables and their defaults
|
||||||
pthread_mutex_t stats_lock;
|
pthread_mutex_t stats_lock;
|
||||||
struct bucket **bb;
|
struct bucket **bb;
|
||||||
int option_t = 60;
|
int option_t = 60;
|
||||||
int option_a = 90;
|
int option_a = 90;
|
||||||
int option_w = 20;
|
int option_w = 10;
|
||||||
int option_x = 10000;
|
int option_x = 50;
|
||||||
int option_m = 0;
|
int option_m = 0;
|
||||||
int option_b = 0;
|
int option_b = 0;
|
||||||
int option_d = 0;
|
int option_d = 0;
|
||||||
int option_D = 0;
|
|
||||||
int option_v = 0;
|
int option_v = 0;
|
||||||
int option_h = 0;
|
int option_h = 0;
|
||||||
int option_Q = 0;
|
|
||||||
int option_A = 0;
|
|
||||||
int option_M = 0;
|
|
||||||
int option_s = 0;
|
|
||||||
int totals = 0;
|
int totals = 0;
|
||||||
|
char VERSION[] = "1.10";
|
||||||
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
|
// this is our statistics thread
|
||||||
void *run_stats () {
|
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) {
|
while (1) {
|
||||||
|
|
||||||
// check statistical stuff
|
// check statistical stuff
|
||||||
pthread_mutex_lock(&stats_lock);
|
pthread_mutex_lock(&stats_lock);
|
||||||
calculate_averages();
|
calculate_averages();
|
||||||
saddr_stats(sock,addr,hostname);
|
|
||||||
pthread_mutex_unlock(&stats_lock);
|
pthread_mutex_unlock(&stats_lock);
|
||||||
|
|
||||||
sleep (option_w);
|
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
|
// calculate the running average within each bucket
|
||||||
int calculate_averages() {
|
int calculate_averages() {
|
||||||
u_int i,j,delta,cursize,qps;
|
u_int i,j,delta,cursize,newsize,qps;
|
||||||
int newsize;
|
|
||||||
float qpsf;
|
|
||||||
char st_time[10];
|
char st_time[10];
|
||||||
time_t now = time(0);
|
time_t now = time(0);
|
||||||
u_int types[] = {1,2,5,6,12,15,28,38,252,255,0};
|
u_int types[] = {1,2,5,6,12,15,252,0};
|
||||||
char *target;
|
u_char *type;
|
||||||
char *names[] = {"A","NS","CNAME","SOA","PTR","MX","AAAA","A6","AXFR","ANY",""};
|
u_char *target;
|
||||||
|
char *names[] = {"A","NS","CNAME","SOA","PTR","MX","AXFR",""};
|
||||||
struct tm *raw_time = localtime(&now);
|
struct tm *raw_time = localtime(&now);
|
||||||
snprintf(st_time, 9, "%02d:%02d:%02d",raw_time->tm_hour,raw_time->tm_min,raw_time->tm_sec);
|
snprintf(st_time, 9, "%02d:%02d:%02d",raw_time->tm_hour,raw_time->tm_min,raw_time->tm_sec);
|
||||||
|
|
||||||
for (i=0; i<option_x; i++) {
|
for (i=0; i<option_x; i++) {
|
||||||
|
|
||||||
// only process valid buckets
|
// only process valid buckets
|
||||||
if ( bb[i]->ip_addr.s_addr != BCAST) {
|
if ( bb[i]->ip_addr != NULL ) {
|
||||||
delta = now - bb[i]->first_packet;
|
delta = now - bb[i]->first_packet;
|
||||||
|
|
||||||
// let's try to avoid a divide-by-zero, shall we?
|
// let's try to avoid a divide-by-zero, shall we?
|
||||||
if (delta > 1 ) {
|
if (delta > 1 ) {
|
||||||
|
|
||||||
// round our average and save it in the bucket
|
// round our average and save it in the bucket
|
||||||
bb[i]->qps = (u_int)ceil( (bb[i]->tcp_count + bb[i]->udp_count) / (float)delta);
|
bb[i]->qps = (int)ceil( (float)((((float)bb[i]->tcp_count) + bb[i]->udp_count) / delta));
|
||||||
|
|
||||||
// handle threshold crossing
|
// handle threshold crossing
|
||||||
if ( bb[i]->qps > option_t ) {
|
if ( bb[i]->qps > option_t ) {
|
||||||
|
|
||||||
|
|
||||||
// display detail to either syslog or stdout
|
// display detail to either syslog or stdout
|
||||||
if ( option_b ) {
|
if ( option_b ) {
|
||||||
if ( ! option_v ) {
|
if ( ! option_v ) {
|
||||||
printf("[%s] source [%s] - %u qps\n",st_time,inet_ntoa(bb[i]->ip_addr),bb[i]->qps);
|
printf("[%s] source [%s] - %d qps\n",st_time,bb[i]->ip_addr,bb[i]->qps);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printf("[%s] source [%s] - %u qps tcp : %u qps udp ",st_time,inet_ntoa(bb[i]->ip_addr),
|
printf("[%s] source [%s] - %d qps tcp : %d qps udp ",st_time,bb[i]->ip_addr,
|
||||||
(u_int)ceil( ((float)bb[i]->tcp_count/delta)),
|
(int)ceil( (float)(bb[i]->tcp_count/delta)),
|
||||||
(u_int)ceil( ((float)bb[i]->udp_count/delta)));
|
(int)ceil( (float)(bb[i]->udp_count/delta))
|
||||||
|
);
|
||||||
if ( option_v >1 ) {
|
if ( option_v >1 ) {
|
||||||
for (j=0;types[j];j++) {
|
for (j=0;types[j];j++) {
|
||||||
qps = (u_int)ceil((float)bb[i]->qstats[types[j]]/delta);
|
if ((int)ceil((float)(bb[i]->qstats[types[j]]/delta))){
|
||||||
if (qps){
|
printf("[%d qps %s] ",(int)ceil((float)(bb[i]->qstats[types[j]]/delta)),names[j]);
|
||||||
printf("[%u qps %s] ",qps,names[j]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -350,20 +185,21 @@ int calculate_averages() {
|
||||||
|
|
||||||
// display appropriate level of detail via syslog
|
// display appropriate level of detail via syslog
|
||||||
if ( ! option_v ) {
|
if ( ! option_v ) {
|
||||||
syslog(LOG_NOTICE,"source [%s] - %u qps\n",inet_ntoa(bb[i]->ip_addr),bb[i]->qps);
|
syslog(LOG_NOTICE,"source [%s] - %d qps\n",bb[i]->ip_addr,bb[i]->qps);
|
||||||
}
|
}
|
||||||
else if (option_v > 1) {
|
else if (option_v > 1) {
|
||||||
target = (char *)malloc(sizeof(char)*MAXSYSLOG);
|
target = (char *)malloc(sizeof(char)*MAXSYSLOG);
|
||||||
newsize = MAXSYSLOG;
|
newsize = MAXSYSLOG;
|
||||||
cursize = snprintf(target,newsize,"source [%s] - %u tcp qps : %u udp qps ",inet_ntoa(bb[i]->ip_addr),
|
cursize = snprintf(target,newsize,"source [%s] - %d tcp qps : %d udp qps ",bb[i]->ip_addr,
|
||||||
(u_int)ceil( ((float)bb[i]->tcp_count/delta)),
|
(int)ceil( (float)(bb[i]->tcp_count/delta)),
|
||||||
(u_int)ceil( ((float)bb[i]->udp_count/delta)));
|
(int)ceil( (float)(bb[i]->udp_count/delta))
|
||||||
|
);
|
||||||
newsize-=cursize;
|
newsize-=cursize;
|
||||||
|
|
||||||
for (j=0;types[j];j++ ) {
|
for (j=0;types[j];j++ ) {
|
||||||
qps = (u_int)ceil(((float)bb[i]->qstats[types[j]]/delta));
|
qps = (u_int)ceil((float)(bb[i]->qstats[types[j]]/delta));
|
||||||
if ( ( qps > 0) && ( newsize > 1 ) ) {
|
if ( ( qps > 0) && ( newsize > 1 ) ) {
|
||||||
cursize = snprintf(target+(MAXSYSLOG-newsize),newsize,"[%u qps %s] ",qps,names[j]);
|
cursize = snprintf(target+(MAXSYSLOG-newsize),newsize,"[%d qps %s] ",qps,names[j]);
|
||||||
newsize-=cursize;
|
newsize-=cursize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -374,9 +210,10 @@ int calculate_averages() {
|
||||||
free(target);
|
free(target);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
syslog(LOG_NOTICE,"source [%s] - %u tcp qps - %u udp qps\n",inet_ntoa(bb[i]->ip_addr),
|
syslog(LOG_NOTICE,"source [%s] - %d tcp qps - %d udp qps\n",bb[i]->ip_addr,
|
||||||
(u_int)ceil( ((float)bb[i]->tcp_count/delta)),
|
(int)ceil( (float)(bb[i]->tcp_count/delta)),
|
||||||
(u_int)ceil( ((float)bb[i]->udp_count/delta)));
|
(int)ceil( (float)(bb[i]->udp_count/delta))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset alarm
|
// reset alarm
|
||||||
|
@ -389,17 +226,17 @@ int calculate_averages() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 'mark stats' if required and it is time
|
// 'mark stats' if required and it is time
|
||||||
delta = (u_int)(now - bb[totals]->first_packet);
|
delta = now - bb[totals]->first_packet;
|
||||||
if ( (option_m > 0)&&(delta > 1)&&(delta >= option_m) ) {
|
if ( (option_m > 0)&&(delta > 1)&&(delta >= option_m) ) {
|
||||||
|
|
||||||
// handle bindsnap mode
|
// handle bindsnap mode
|
||||||
if (option_b) {
|
if (option_b) {
|
||||||
printf("[%s] totals - %3.2f qps tcp : %3.2f qps udp ",st_time, ((float)bb[totals]->tcp_count/delta),((float)bb[totals]->udp_count/delta));
|
printf("[%s] totals - %d qps tcp : %d qps udp ",st_time,(int)ceil( (float)(bb[totals]->tcp_count/delta)),(int)ceil( (float)(bb[totals]->udp_count/delta)));
|
||||||
if (option_v) {
|
if (option_v) {
|
||||||
for (j=0;types[j];j++) {
|
for (j=0;types[j];j++) {
|
||||||
qpsf = ((float)bb[totals]->qstats[types[j]]/delta);
|
qps = (u_int)ceil((float)(bb[totals]->qstats[types[j]]/delta));
|
||||||
if (qpsf > 0){
|
if (qps){
|
||||||
printf("[%3.2f qps %s] ",qpsf,names[j]);
|
printf("[%d qps %s] ",qps,names[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -411,15 +248,16 @@ int calculate_averages() {
|
||||||
if (option_v) {
|
if (option_v) {
|
||||||
target = (char *)malloc(sizeof(char)*MAXSYSLOG);
|
target = (char *)malloc(sizeof(char)*MAXSYSLOG);
|
||||||
newsize = MAXSYSLOG;
|
newsize = MAXSYSLOG;
|
||||||
cursize = snprintf(target,newsize,"[totals] - %3.2f tcp qps : %3.2f udp qps ",
|
cursize = snprintf(target,newsize,"[totals] - %d tcp qps : %d udp qps ",
|
||||||
((float)bb[totals]->tcp_count/delta),
|
(int)ceil( (float)(bb[totals]->tcp_count/delta)),
|
||||||
((float)bb[totals]->udp_count/delta));
|
(int)ceil( (float)(bb[totals]->udp_count/delta))
|
||||||
|
);
|
||||||
newsize-=cursize;
|
newsize-=cursize;
|
||||||
|
|
||||||
for (j=0;types[j];j++ ) {
|
for (j=0;types[j];j++ ) {
|
||||||
qpsf = ((float)bb[totals]->qstats[types[j]]/delta);
|
qps = (u_int)ceil((float)(bb[totals]->qstats[types[j]]/delta));
|
||||||
if ( ( qpsf > 0) && ( newsize > 1 ) ) {
|
if ( ( qps > 0) && ( newsize > 1 ) ) {
|
||||||
cursize = snprintf(target+(MAXSYSLOG-newsize),newsize,"[%3.2f qps %s] ",qpsf,names[j]);
|
cursize = snprintf(target+(MAXSYSLOG-newsize),newsize,"[%d qps %s] ",qps,names[j]);
|
||||||
newsize-=cursize;
|
newsize-=cursize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -430,28 +268,18 @@ int calculate_averages() {
|
||||||
free(target);
|
free(target);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
syslog(LOG_NOTICE,"[totals] - %3.2f tcp qps : %3.2f udp qps\n",
|
syslog(LOG_NOTICE,"[totals] - %d tcp qps : %d udp qps\n",
|
||||||
((float)bb[totals]->tcp_count/delta),
|
(int)ceil( (float)(bb[totals]->tcp_count/delta)),
|
||||||
((float)bb[totals]->udp_count/delta));
|
(int)ceil( (float)(bb[totals]->udp_count/delta))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scour_bucket(totals);
|
scour_bucket(totals);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int valid_dns_char(char c) {
|
|
||||||
|
|
||||||
if((c >= '0' && c <= '9')
|
|
||||||
|| (c >= 'a' && c <= 'z')
|
|
||||||
|| (c >= 'A' && c <= 'Z')
|
|
||||||
|| (c == '-')
|
|
||||||
|| (c == '_')) // is valid for SRV records.
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// purge and initialize all buckets
|
// purge and initialize all buckets
|
||||||
void init_buckets() {
|
void init_buckets() {
|
||||||
u_int i;
|
u_int i;
|
||||||
|
@ -461,6 +289,7 @@ void init_buckets() {
|
||||||
if ( ( bb = malloc( sizeof(struct bucket *) * (option_x+1)) ) == NULL ) malloc_fail("bb", sizeof(struct bucket *) * (option_x+1));
|
if ( ( bb = malloc( sizeof(struct bucket *) * (option_x+1)) ) == NULL ) malloc_fail("bb", sizeof(struct bucket *) * (option_x+1));
|
||||||
for (i=0; i <=option_x; i++ ) {
|
for (i=0; i <=option_x; i++ ) {
|
||||||
if ( ( bb[i] = (struct bucket *)malloc( sizeof(struct bucket) ) ) == NULL) malloc_fail("bb[i]", sizeof(struct bucket) );
|
if ( ( bb[i] = (struct bucket *)malloc( sizeof(struct bucket) ) ) == NULL) malloc_fail("bb[i]", sizeof(struct bucket) );
|
||||||
|
bb[i]->ip_addr=NULL;
|
||||||
scour_bucket(i);
|
scour_bucket(i);
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&stats_lock);
|
pthread_mutex_unlock(&stats_lock);
|
||||||
|
@ -470,7 +299,10 @@ void init_buckets() {
|
||||||
int scour_bucket( int i ) {
|
int scour_bucket( int i ) {
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
bb[i]->ip_addr.s_addr=BCAST;
|
if ( bb[i]->ip_addr != NULL ) {
|
||||||
|
free ( bb[i]->ip_addr );
|
||||||
|
}
|
||||||
|
bb[i]->ip_addr=NULL;
|
||||||
bb[i]->tcp_count=0;
|
bb[i]->tcp_count=0;
|
||||||
bb[i]->udp_count=0;
|
bb[i]->udp_count=0;
|
||||||
bb[i]->qps=0;
|
bb[i]->qps=0;
|
||||||
|
@ -481,12 +313,11 @@ int scour_bucket( int i ) {
|
||||||
for (j=0;j<256;j++) {
|
for (j=0;j<256;j++) {
|
||||||
bb[i]->qstats[j]=0;
|
bb[i]->qstats[j]=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add a packet to a bucket
|
// add a packet to a bucket
|
||||||
int add_to_bucket ( struct in_addr *ip_src, int ip_proto, int num_queries, u_int8_t qtype) {
|
int add_to_bucket ( char * ip_src, int ip_proto, int num_queries, u_int8_t qtype) {
|
||||||
int bucket = 0;
|
int bucket = 0;
|
||||||
|
|
||||||
// get the bucket to put packet in
|
// get the bucket to put packet in
|
||||||
|
@ -512,14 +343,14 @@ int add_to_bucket ( struct in_addr *ip_src, int ip_proto, int num_queries, u_int
|
||||||
}
|
}
|
||||||
|
|
||||||
// figure out where to put this packet
|
// figure out where to put this packet
|
||||||
int find_bucket(struct in_addr *ip_src) {
|
int find_bucket(char *ip_src) {
|
||||||
int i, bucket=0;
|
int i, bucket=0;
|
||||||
time_t oldest=0;
|
time_t oldest=0;
|
||||||
|
|
||||||
// look for an existing bucket for this IP
|
// look for an existing bucket for this IP
|
||||||
for (i=0; i< option_x; i++ ){
|
for (i=0; i< option_x; i++ ){
|
||||||
// ip field of bucket seems to match the ip we are checking
|
// ip field of bucket is not null and seems to match the ip we are checking
|
||||||
if (bb[i]->ip_addr.s_addr == ip_src->s_addr) {
|
if ((bb[i]->ip_addr != NULL)&&(strncmp(bb[i]->ip_addr, ip_src, strlen(bb[i]->ip_addr))==0)) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -528,21 +359,14 @@ int find_bucket(struct in_addr *ip_src) {
|
||||||
for (i=0; i< option_x; i++ ) {
|
for (i=0; i< option_x; i++ ) {
|
||||||
|
|
||||||
// found an unused one - clean it, init it, and return it
|
// found an unused one - clean it, init it, and return it
|
||||||
if ( bb[i]->ip_addr.s_addr == BCAST ) {
|
if ( bb[i]->ip_addr == NULL ) {
|
||||||
scour_bucket(i);
|
scour_bucket(i);
|
||||||
bb[i]->ip_addr.s_addr = ip_src->s_addr;
|
if ( ( bb[i]->ip_addr = (char *)strdup(ip_src) ) == NULL) malloc_fail("bb[i]->ip_addr", strlen(ip_src) );
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
// find the most stagnant bucket in case we need it
|
// find the most stagnant bucket in case we need it
|
||||||
// avoids another loop through the buckets
|
// avoids another loop through the buckets
|
||||||
// TODO - should we autoflush buckets after some idle time,
|
|
||||||
// or after alarming? fixes the case where
|
|
||||||
// alarms are unlikely to reappear even if a client
|
|
||||||
// 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))) {
|
if ( ( bb[i]->last_packet != 0 ) && ((oldest==0)||( bb[i]->last_packet < oldest))) {
|
||||||
oldest = bb[i]->last_packet;
|
oldest = bb[i]->last_packet;
|
||||||
bucket = i;
|
bucket = i;
|
||||||
|
@ -552,7 +376,7 @@ int find_bucket(struct in_addr *ip_src) {
|
||||||
// use the most stagnant bucket since all are in use
|
// use the most stagnant bucket since all are in use
|
||||||
// clean it, init it, and return it
|
// clean it, init it, and return it
|
||||||
scour_bucket(bucket);
|
scour_bucket(bucket);
|
||||||
bb[i]->ip_addr.s_addr = ip_src->s_addr;
|
if ( ( bb[bucket]->ip_addr = (char *)strdup(ip_src) ) == NULL) malloc_fail("bb[bucket]->ip_addr", strlen(ip_src) );
|
||||||
|
|
||||||
return bucket;
|
return bucket;
|
||||||
}
|
}
|
||||||
|
@ -567,10 +391,10 @@ void handle_IP(u_char *args, const struct pcap_pkthdr* pkthdr,const u_char* pack
|
||||||
u_int caplen = pkthdr->caplen;
|
u_int caplen = pkthdr->caplen;
|
||||||
u_int hlen,off,version;
|
u_int hlen,off,version;
|
||||||
unsigned char dname[NS_MAXDNAME]="";
|
unsigned char dname[NS_MAXDNAME]="";
|
||||||
struct in_addr ip_src;
|
char *ip_src;
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
u_int len,dpos;
|
u_int i,len,dpos;
|
||||||
u_int8_t qtype,tlen;
|
u_int8_t qtype,qclass,tlen;
|
||||||
|
|
||||||
// skip the ethernet header
|
// skip the ethernet header
|
||||||
length -= sizeof(struct ether_header);
|
length -= sizeof(struct ether_header);
|
||||||
|
@ -607,8 +431,8 @@ void handle_IP(u_char *args, const struct pcap_pkthdr* pkthdr,const u_char* pack
|
||||||
off = ntohs(ip->ip_off);
|
off = ntohs(ip->ip_off);
|
||||||
if((off & 0x1fff) == 0 ) {
|
if((off & 0x1fff) == 0 ) {
|
||||||
|
|
||||||
// get the source ip
|
// get the source ip as a string (probably more efficient to use decimal)
|
||||||
ip_src.s_addr = ip->ip_src.s_addr;
|
ip_src = (char *)inet_ntoa(ip->ip_src);
|
||||||
|
|
||||||
// process udp packets
|
// process udp packets
|
||||||
if ( ip->ip_p == 17 ) {
|
if ( ip->ip_p == 17 ) {
|
||||||
|
@ -621,7 +445,7 @@ void handle_IP(u_char *args, const struct pcap_pkthdr* pkthdr,const u_char* pack
|
||||||
else {
|
else {
|
||||||
// populate dns header
|
// populate dns header
|
||||||
dns = (struct my_dns *) ( (char *) packet + sizeof(struct ether_header) + sizeof (struct ip) + sizeof (struct udphdr) );
|
dns = (struct my_dns *) ( (char *) packet + sizeof(struct ether_header) + sizeof (struct ip) + sizeof (struct udphdr) );
|
||||||
data = (unsigned char *) packet +sizeof(struct ether_header) + sizeof (struct ip) + sizeof (struct udphdr) + sizeof(struct my_dns);
|
data = (char *) packet +sizeof(struct ether_header) + sizeof (struct ip) + sizeof (struct udphdr) + sizeof(struct my_dns);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -630,17 +454,16 @@ 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) );
|
tcp = (struct tcphdr *) ( (char *) packet + sizeof(struct ether_header)+ sizeof (struct ip) );
|
||||||
|
|
||||||
// ignore packets without push flag set
|
// 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
|
// 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 ) {
|
if ( (sizeof(struct my_dns)+sizeof(struct ether_header)+sizeof(struct ip)+(tcp->th_off * sizeof(u_int32_t))) >= caplen ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// populate dns header
|
// 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)));
|
||||||
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);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -654,8 +477,8 @@ void handle_IP(u_char *args, const struct pcap_pkthdr* pkthdr,const u_char* pack
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore packets with no questions
|
// ignore seemingly bogus queries with multiple flags set
|
||||||
if (ntohs(dns->dns_qdcount) == 0) {
|
if ((ntohs(dns->dns_qdcount)>0)+(ntohs(dns->dns_ancount)>0)+(ntohs(dns->dns_nscount)>0)+(ntohs(dns->dns_arcount)>0)>1 ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -665,10 +488,6 @@ void handle_IP(u_char *args, const struct pcap_pkthdr* pkthdr,const u_char* pack
|
||||||
if (!tlen) tlen=*data;
|
if (!tlen) tlen=*data;
|
||||||
for (;(tlen&&((void *)data<((void *)packet+caplen-1)));tlen--){
|
for (;(tlen&&((void *)data<((void *)packet+caplen-1)));tlen--){
|
||||||
data++;
|
data++;
|
||||||
// bail on an invalid dns char
|
|
||||||
if(!valid_dns_char(*data)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (dpos<NS_MAXDNAME) dname[dpos++] = *data;
|
if (dpos<NS_MAXDNAME) dname[dpos++] = *data;
|
||||||
}
|
}
|
||||||
if (dpos<NS_MAXDNAME) dname[dpos++] = '.';
|
if (dpos<NS_MAXDNAME) dname[dpos++] = '.';
|
||||||
|
@ -684,14 +503,9 @@ void handle_IP(u_char *args, const struct pcap_pkthdr* pkthdr,const u_char* pack
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( option_D ) {
|
|
||||||
printf("src: %-15s proto: %s qtype: 0x%02x domain: %s\n", (inet_ntoa(ip_src)),
|
|
||||||
(ip->ip_p == 17 ? "udp" : "tcp"), qtype, dname);
|
|
||||||
}
|
|
||||||
|
|
||||||
// add packet to bucket array
|
// add packet to bucket array
|
||||||
if (ntohs(dns->dns_qdcount)&&qtype) {
|
if (ntohs(dns->dns_qdcount)&&qtype) {
|
||||||
add_to_bucket( &ip_src, ip->ip_p, 1, qtype );
|
add_to_bucket( ip_src, ip->ip_p, 1, qtype );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -699,7 +513,7 @@ void handle_IP(u_char *args, const struct pcap_pkthdr* pkthdr,const u_char* pack
|
||||||
|
|
||||||
// main logic
|
// main logic
|
||||||
// some pcap code borrowed from http://www.cet.nau.edu/~mc8/Socket/Tutorials/section1.html
|
// some pcap code borrowed from http://www.cet.nau.edu/~mc8/Socket/Tutorials/section1.html
|
||||||
int main(int argc,char **argv){
|
int main(int argc,char **argv){
|
||||||
char *dev = NULL;
|
char *dev = NULL;
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
char errbuf[PCAP_ERRBUF_SIZE];
|
char errbuf[PCAP_ERRBUF_SIZE];
|
||||||
|
@ -711,16 +525,15 @@ void handle_IP(u_char *args, const struct pcap_pkthdr* pkthdr,const u_char* pack
|
||||||
char *dst_addr = NULL;
|
char *dst_addr = NULL;
|
||||||
char *dst_mask = NULL;
|
char *dst_mask = NULL;
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
struct in_addr addr,tmpaddr;
|
struct in_addr addr;
|
||||||
u_int f_size;
|
u_int f_size;
|
||||||
char *name = NULL;
|
char *args = NULL;
|
||||||
u_int c = 0;
|
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
|
// loop through command line options and get options
|
||||||
while(1) {
|
while(1) {
|
||||||
c = getopt(argc, argv,"i:t:a:w:x:m:A:M:QbdDvsh");
|
int option_index = 0;
|
||||||
|
c = getopt(argc, argv,"i:t:a:w:x:m:bdvh");
|
||||||
|
|
||||||
if (c==-1) break;
|
if (c==-1) break;
|
||||||
switch(c) {
|
switch(c) {
|
||||||
|
@ -766,55 +579,17 @@ void handle_IP(u_char *args, const struct pcap_pkthdr* pkthdr,const u_char* pack
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'M':
|
|
||||||
if (optarg && (dst_mask == NULL) ) {
|
|
||||||
if ( inet_aton(optarg, &tmpaddr) ) {
|
|
||||||
if ( ( dst_mask = (char *)strdup(optarg) ) == NULL) malloc_fail("filter mask", strlen(optarg) );
|
|
||||||
option_M=1;
|
|
||||||
} else {
|
|
||||||
fprintf(stderr,"Invalid filter mask \"%s\"\n",optarg);
|
|
||||||
option_h = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'A':
|
|
||||||
if (optarg && (dst_addr == NULL) ) {
|
|
||||||
if ( inet_aton(optarg, &tmpaddr) ) {
|
|
||||||
if ( ( dst_addr = (char *)strdup(optarg) ) == NULL) malloc_fail("dest filter", strlen(optarg) );
|
|
||||||
option_A=1;
|
|
||||||
} else {
|
|
||||||
fprintf(stderr,"Invalid filter address \"%s\"\n",optarg);
|
|
||||||
option_h = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'Q':
|
|
||||||
option_Q = 1;
|
|
||||||
break;
|
|
||||||
case 'b':
|
case 'b':
|
||||||
option_b = 1;
|
option_b = 1;
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
option_d = 1;
|
option_d = 1;
|
||||||
break;
|
break;
|
||||||
case 'D':
|
|
||||||
option_D = 1;
|
|
||||||
break;
|
|
||||||
case 'v':
|
case 'v':
|
||||||
option_v++;
|
option_v++;
|
||||||
break;
|
break;
|
||||||
case 's':
|
|
||||||
option_s = 1;
|
|
||||||
break;
|
|
||||||
case 'h':
|
case 'h':
|
||||||
option_h = 1;
|
option_h = 1;
|
||||||
break;
|
|
||||||
case 'z':
|
|
||||||
target_ip = optarg;
|
|
||||||
break;
|
|
||||||
case 'p':
|
|
||||||
target_port = atoi(optarg);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -822,56 +597,27 @@ void handle_IP(u_char *args, const struct pcap_pkthdr* pkthdr,const u_char* pack
|
||||||
|
|
||||||
// display usage info if needed
|
// display usage info if needed
|
||||||
if (optind<argc) option_h = 1;
|
if (optind<argc) option_h = 1;
|
||||||
|
|
||||||
if (option_h) {
|
if (option_h) {
|
||||||
fprintf(stderr,"dns_flood_detector, version %s\n",VERSION);
|
fprintf(stderr,"dns_flood_detector, version %s\n",VERSION);
|
||||||
fprintf(stderr,"Usage: %s [OPTION]\n\n",name);
|
fprintf(stderr,"Usage: %s [OPTION]\n\n",argv[0]);
|
||||||
fprintf(stderr,"-i IFNAME specify device name to listen on\n");
|
fprintf(stderr,"-i IFNAME specify device name to listen on\n");
|
||||||
fprintf(stderr,"-t N alarm at >N queries per second\n");
|
fprintf(stderr,"-t N alarm at >N queries per second\n");
|
||||||
fprintf(stderr,"-a N reset alarm after N seconds\n");
|
fprintf(stderr,"-a N reset alarm after N seconds\n");
|
||||||
fprintf(stderr,"-w N calculate stats every N seconds\n");
|
fprintf(stderr,"-w N calculate stats every N seconds\n");
|
||||||
fprintf(stderr,"-x N create N buckets\n");
|
fprintf(stderr,"-x N create N buckets\n");
|
||||||
fprintf(stderr,"-m N report overall stats every N seconds\n");
|
fprintf(stderr,"-m N report overall stats every N seconds\n");
|
||||||
fprintf(stderr,"-A addr filter for specific address\n");
|
|
||||||
fprintf(stderr,"-M mask netmask for filter (in conjunction with -A)\n");
|
|
||||||
fprintf(stderr,"-Q don't filter by local interface address\n");
|
|
||||||
fprintf(stderr,"-b run in foreground in bindsnap mode\n");
|
fprintf(stderr,"-b run in foreground in bindsnap mode\n");
|
||||||
fprintf(stderr,"-d run in background in daemon mode\n");
|
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,"-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");
|
fprintf(stderr,"-h display this usage information\n");
|
||||||
exit(1);
|
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 )
|
|
||||||
option_b = 1;
|
|
||||||
|
|
||||||
if( option_d )
|
|
||||||
option_d = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ( option_Q ) && ( option_A ) ) {
|
|
||||||
fprintf(stderr,"%s couldn't start\n",name);
|
|
||||||
fprintf(stderr,"You can't specify both -A (address filter) and -Q (no filter)\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ( ! option_d ) && ( ! option_b ) ) {
|
if ( ( ! option_d ) && ( ! option_b ) ) {
|
||||||
fprintf(stderr,"%s couldn't start\n",name);
|
fprintf(stderr,"%s couldn't start\n",argv[0]);
|
||||||
fprintf(stderr,"You must specify either -d (daemon) or -b (bindsnap)\n");
|
fprintf(stderr,"You must specify either either -d (daemon) or -b (bindsnap)\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
free(name);
|
|
||||||
|
|
||||||
// set up for daemonized operation unless running in bindsnap mode
|
// set up for daemonized operation unless running in bindsnap mode
|
||||||
if ( ! option_b ) {
|
if ( ! option_b ) {
|
||||||
openlog("dns_flood_detector",LOG_PID|LOG_CONS,LOG_DAEMON);
|
openlog("dns_flood_detector",LOG_PID|LOG_CONS,LOG_DAEMON);
|
||||||
|
@ -884,7 +630,8 @@ void handle_IP(u_char *args, const struct pcap_pkthdr* pkthdr,const u_char* pack
|
||||||
sa.sa_handler=exit;
|
sa.sa_handler=exit;
|
||||||
sa.sa_flags=0;
|
sa.sa_flags=0;
|
||||||
if(sigaction(SIGTERM,&sa,NULL)) {
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -894,13 +641,6 @@ void handle_IP(u_char *args, const struct pcap_pkthdr* pkthdr,const u_char* pack
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* restrict to queries to primary local address? */
|
|
||||||
if (option_Q) {
|
|
||||||
f_size = strlen("port 53 ");
|
|
||||||
if ( ( filter = (char *) malloc ( f_size+1) ) == NULL ) malloc_fail( "filter", f_size+1 );
|
|
||||||
snprintf( filter, f_size, "port 53");
|
|
||||||
} else {
|
|
||||||
if (! option_A) {
|
|
||||||
// get network address and netmask for device
|
// get network address and netmask for device
|
||||||
pcap_lookupnet(dev,&netp,&maskp,errbuf);
|
pcap_lookupnet(dev,&netp,&maskp,errbuf);
|
||||||
|
|
||||||
|
@ -911,20 +651,9 @@ void handle_IP(u_char *args, const struct pcap_pkthdr* pkthdr,const u_char* pack
|
||||||
dst_addr[strlen((char *)inet_ntoa(addr))]='\0';
|
dst_addr[strlen((char *)inet_ntoa(addr))]='\0';
|
||||||
|
|
||||||
addr.s_addr = (unsigned long int)maskp;
|
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 );
|
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)));
|
strncpy(dst_mask,(char*)inet_ntoa(addr),strlen((char *)inet_ntoa(addr)));
|
||||||
dst_mask[strlen((char *)inet_ntoa(addr))]='\0';
|
dst_mask[strlen((char *)inet_ntoa(addr))]='\0';
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// we're using an address from -A
|
|
||||||
if (!option_M) {
|
|
||||||
// if no mask was specified, then use just a host mask
|
|
||||||
if ( ( dst_mask = (char *)malloc(16) ) == NULL ) malloc_fail("dest_mask", 16);
|
|
||||||
strncpy(dst_mask,"255.255.255.255",15);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
f_size = strlen("port 53 and dst net mask ")+ strlen(dst_mask)+ strlen(dst_addr);
|
f_size = strlen("port 53 and dst net mask ")+ strlen(dst_mask)+ strlen(dst_addr);
|
||||||
if ( ( filter = (char *) malloc ( f_size+1) ) == NULL ) malloc_fail( "filter", f_size+1 );
|
if ( ( filter = (char *) malloc ( f_size+1) ) == NULL ) malloc_fail( "filter", f_size+1 );
|
||||||
|
@ -932,11 +661,6 @@ void handle_IP(u_char *args, const struct pcap_pkthdr* pkthdr,const u_char* pack
|
||||||
|
|
||||||
free (dst_mask);
|
free (dst_mask);
|
||||||
free (dst_addr);
|
free (dst_addr);
|
||||||
}
|
|
||||||
|
|
||||||
if ( option_b && option_v ) {
|
|
||||||
printf("using filter \"%s\" on dev %s\n", filter, dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
// open device for reading only local traffic
|
// open device for reading only local traffic
|
||||||
descr = pcap_open_live(dev,1500,0,1,errbuf);
|
descr = pcap_open_live(dev,1500,0,1,errbuf);
|
||||||
|
@ -947,13 +671,11 @@ void handle_IP(u_char *args, const struct pcap_pkthdr* pkthdr,const u_char* pack
|
||||||
|
|
||||||
// compile filter
|
// compile filter
|
||||||
if(pcap_compile(descr,&fp,filter,0,netp) == -1) {
|
if(pcap_compile(descr,&fp,filter,0,netp) == -1) {
|
||||||
fprintf(stderr,"error compiling filter: %s\n",pcap_geterr(descr));
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set filter
|
// set filter
|
||||||
if(pcap_setfilter(descr,&fp) == -1){
|
if(pcap_setfilter(descr,&fp) == -1){
|
||||||
fprintf(stderr,"error setting filter: %s\n",pcap_geterr(descr));
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -972,7 +694,7 @@ void handle_IP(u_char *args, const struct pcap_pkthdr* pkthdr,const u_char* pack
|
||||||
}
|
}
|
||||||
|
|
||||||
// main pcap loop
|
// main pcap loop
|
||||||
pcap_loop(descr,-1,&handle_IP,NULL);
|
pcap_loop(descr,-1,handle_IP,args);
|
||||||
|
|
||||||
// done
|
// done
|
||||||
closelog();
|
closelog();
|
||||||
|
@ -983,7 +705,6 @@ void handle_IP(u_char *args, const struct pcap_pkthdr* pkthdr,const u_char* pack
|
||||||
int daemonize(void) {
|
int daemonize(void) {
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
int fd;
|
int fd;
|
||||||
int a;
|
|
||||||
|
|
||||||
fd=open("/dev/null",O_RDWR);
|
fd=open("/dev/null",O_RDWR);
|
||||||
if(fd<0) {
|
if(fd<0) {
|
||||||
|
@ -1004,7 +725,7 @@ int daemonize(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
setsid();
|
setsid();
|
||||||
a = chdir("/");
|
chdir("/");
|
||||||
umask(0);
|
umask(0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1019,13 +740,3 @@ int malloc_fail( char * var, int size ) {
|
||||||
}
|
}
|
||||||
exit(1);
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -29,14 +29,7 @@
|
||||||
#define ETHER_HDRLEN 14
|
#define ETHER_HDRLEN 14
|
||||||
#endif
|
#endif
|
||||||
#define NS_MAXDNAME 1025
|
#define NS_MAXDNAME 1025
|
||||||
#define MAXSYSLOG 192
|
#define MAXSYSLOG 128
|
||||||
#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__
|
||||||
|
@ -47,13 +40,6 @@ 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 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
|
// data structures
|
||||||
struct my_dns {
|
struct my_dns {
|
||||||
|
@ -67,7 +53,7 @@ struct my_dns {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bucket {
|
struct bucket {
|
||||||
struct in_addr ip_addr;
|
char * ip_addr;
|
||||||
unsigned int tcp_count;
|
unsigned int tcp_count;
|
||||||
unsigned int udp_count;
|
unsigned int udp_count;
|
||||||
unsigned int qps;
|
unsigned int qps;
|
||||||
|
|
|
@ -7,7 +7,5 @@ clean:
|
||||||
rm -rf dns_flood_detector *.o *~
|
rm -rf dns_flood_detector *.o *~
|
||||||
install:
|
install:
|
||||||
cp dns_flood_detector /usr/local/sbin/
|
cp dns_flood_detector /usr/local/sbin/
|
||||||
distclean: clean
|
|
||||||
rm Makefile
|
|
||||||
|
|
||||||
dns_flood_detector: dns_flood_detector.c
|
dns_flood_detector: dns_flood_detector.c
|
||||||
|
|
|
@ -7,7 +7,5 @@ clean:
|
||||||
rm -rf dns_flood_detector *.o *~
|
rm -rf dns_flood_detector *.o *~
|
||||||
install:
|
install:
|
||||||
cp dns_flood_detector /usr/local/sbin/
|
cp dns_flood_detector /usr/local/sbin/
|
||||||
distclean: clean
|
|
||||||
rm Makefile
|
|
||||||
|
|
||||||
dns_flood_detector: dns_flood_detector.c
|
dns_flood_detector: dns_flood_detector.c
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
CFLAGS=-Wall -O -D_BSD_SOURCE -g
|
CFLAGS=-O -D_BSD_SOURCE -g
|
||||||
LDLIBS=-lpcap -lpthread -lm
|
LDLIBS=-lpcap -lpthread -lm
|
||||||
|
|
||||||
all: dns_flood_detector
|
all: dns_flood_detector
|
||||||
|
@ -7,7 +7,5 @@ clean:
|
||||||
rm -rf dns_flood_detector *.o *~
|
rm -rf dns_flood_detector *.o *~
|
||||||
install:
|
install:
|
||||||
cp dns_flood_detector /usr/local/sbin/
|
cp dns_flood_detector /usr/local/sbin/
|
||||||
distclean: clean
|
|
||||||
rm Makefile
|
|
||||||
|
|
||||||
dns_flood_detector: dns_flood_detector.c
|
dns_flood_detector: dns_flood_detector.c
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
CFLAGS+=-Wall -O -g -I/usr/local/include -I/usr/include
|
CFLAGS+=-O -g -I/usr/local/include -I/usr/include
|
||||||
LDLIBS=-lpcap -lpthread -lm
|
LDLIBS=-L/usr/local/lib -lpcap -lpthread -lm
|
||||||
|
|
||||||
all: dns_flood_detector
|
all: dns_flood_detector
|
||||||
strip dns_flood_detector
|
strip dns_flood_detector
|
||||||
|
@ -7,7 +7,5 @@ clean:
|
||||||
rm -rf dns_flood_detector *.o *~
|
rm -rf dns_flood_detector *.o *~
|
||||||
install:
|
install:
|
||||||
cp dns_flood_detector /usr/local/sbin/
|
cp dns_flood_detector /usr/local/sbin/
|
||||||
distclean: clean
|
|
||||||
rm Makefile
|
|
||||||
|
|
||||||
dns_flood_detector: dns_flood_detector.c
|
dns_flood_detector: dns_flood_detector.c
|
||||||
|
|
|
@ -7,7 +7,5 @@ clean:
|
||||||
rm -rf dns_flood_detector *.o *~
|
rm -rf dns_flood_detector *.o *~
|
||||||
install:
|
install:
|
||||||
cp dns_flood_detector /usr/local/sbin/
|
cp dns_flood_detector /usr/local/sbin/
|
||||||
distclean: clean
|
|
||||||
rm Makefile
|
|
||||||
|
|
||||||
dns_flood_detector: dns_flood_detector.c
|
dns_flood_detector: dns_flood_detector.c
|
||||||
|
|
Loading…
Reference in a new issue