├── debian ├── compat ├── docs ├── source │ └── format ├── dirs ├── rules ├── control ├── changelog └── copyright ├── config.rpath ├── src ├── test │ ├── test1.sh │ └── Makefile.am ├── main.cpp ├── exceptions.h ├── raw_socket_sender.h ├── payload_file.h ├── dns_receiver_thread.h ├── packet.h ├── query.h ├── raw_socket_receiver.h ├── dns_receiver_thread.cpp ├── raw_socket_sender.cpp ├── dns_sender_thread.h ├── system_stat.h ├── dns_sender.h ├── query.cpp ├── payload_file.cpp ├── packet.cpp ├── dnsmeter.1.in ├── dns_sender_thread.cpp ├── raw_socket_receiver.cpp ├── system_stat.cpp ├── Makefile.am └── dns_sender.cpp ├── .gitmodules ├── fmt.sh ├── .clang-format ├── autogen.sh ├── .copr └── Makefile ├── Makefile.am ├── m4 ├── dl.sh ├── ax_require_defined.m4 ├── ax_append_flag.m4 ├── ax_prepend_flag.m4 ├── ax_compiler_vendor.m4 ├── ax_cflags_warn_all.m4 └── ax_pthread.m4 ├── CHANGES ├── .gitignore ├── configure.ac ├── rpm └── dnsmeter.spec └── README.md /debian/compat: -------------------------------------------------------------------------------- 1 | 10 2 | -------------------------------------------------------------------------------- /debian/docs: -------------------------------------------------------------------------------- 1 | README.md 2 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /config.rpath: -------------------------------------------------------------------------------- 1 | src/pplib/autoconf/config.rpath -------------------------------------------------------------------------------- /debian/dirs: -------------------------------------------------------------------------------- 1 | usr/share/man/man1 2 | usr/bin 3 | -------------------------------------------------------------------------------- /src/test/test1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -xe 2 | 3 | ../dnsmeter -h 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/pplib"] 2 | path = src/pplib 3 | url = https://github.com/DNS-OARC/pplib.git 4 | -------------------------------------------------------------------------------- /fmt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | clang-format-4.0 \ 4 | -style=file \ 5 | -i \ 6 | src/*.cpp \ 7 | src/*.h 8 | -------------------------------------------------------------------------------- /src/test/Makefile.am: -------------------------------------------------------------------------------- 1 | MAINTAINERCLEANFILES = $(srcdir)/Makefile.in 2 | 3 | CLEANFILES = test*.log test*.trs 4 | 5 | TESTS = test1.sh 6 | 7 | EXTRA_DIST = $(TESTS) 8 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: webkit 2 | IndentWidth: 4 3 | AlignConsecutiveAssignments: true 4 | AlignConsecutiveDeclarations: true 5 | AlignOperands: true 6 | SortIncludes: false 7 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | 4 | # Uncomment this to turn on verbose mode. 5 | #export DH_VERBOSE=1 6 | 7 | %: 8 | dh $@ 9 | 10 | override_dh_auto_configure: 11 | ./autogen.sh 12 | dh_auto_configure 13 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | # Copyright (c) 2019-2021, OARC, Inc. 3 | # Copyright (c) 2019, DENIC eG 4 | # All rights reserved. 5 | # 6 | # This file is part of dnsmeter. 7 | # 8 | # dnsmeter is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # dnsmeter is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with dnsmeter. If not, see . 20 | 21 | autoreconf --force --install --no-recursive --include=m4 22 | -------------------------------------------------------------------------------- /.copr/Makefile: -------------------------------------------------------------------------------- 1 | top=.. 2 | 3 | all: srpm 4 | 5 | prereq: $(top)/rpmbuild 6 | rpm -q git rpm-build >/dev/null || dnf -y install git rpm-build 7 | 8 | update-dist-tools: $(top)/dist-tools 9 | ( cd "$(top)/dist-tools" && git pull ) 10 | 11 | $(top)/dist-tools: 12 | git clone https://github.com/jelu/dist-tools.git "$(top)/dist-tools" 13 | 14 | $(top)/rpmbuild: 15 | mkdir -p "$(top)"/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS} 16 | 17 | srpm: prereq update-dist-tools 18 | test -f .gitmodules && git submodule update --init || true 19 | echo "$(spec)" | grep -q "develop.spec" && auto_build_number=`date --utc +%s` message="Auto build `date --utc --iso-8601=seconds`" "$(top)/dist-tools/spec-new-changelog-entry" || true 20 | overwrite=yes nosign=yes "$(top)/dist-tools/create-source-packages" rpm 21 | cp ../*.orig.tar.gz "$(top)/rpmbuild/SOURCES/" 22 | echo "$(spec)" | grep -q "develop.spec" && rpmbuild -bs --define "%_topdir $(top)/rpmbuild" --undefine=dist rpm/*.spec || rpmbuild -bs --define "%_topdir $(top)/rpmbuild" --undefine=dist "$(spec)" 23 | cp "$(top)"/rpmbuild/SRPMS/*.src.rpm "$(outdir)" 24 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2021, OARC, Inc. 2 | # Copyright (c) 2019, DENIC eG 3 | # All rights reserved. 4 | # 5 | # This file is part of dnsmeter. 6 | # 7 | # dnsmeter is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # dnsmeter is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with dnsmeter. If not, see . 19 | 20 | ACLOCAL_AMFLAGS = -I m4 21 | 22 | MAINTAINERCLEANFILES = $(srcdir)/Makefile.in \ 23 | $(srcdir)/src/config.h.in~ \ 24 | $(srcdir)/configure 25 | 26 | SUBDIRS = src 27 | 28 | dist_doc_DATA = CHANGES README.md LICENSE 29 | 30 | EXTRA_DIST = m4 31 | 32 | test: check 33 | -------------------------------------------------------------------------------- /m4/dl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | # Copyright (c) 2019-2021, OARC, Inc. 3 | # Copyright (c) 2019, DENIC eG 4 | # All rights reserved. 5 | # 6 | # This file is part of dnsmeter. 7 | # 8 | # dnsmeter is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # dnsmeter is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with dnsmeter. If not, see . 20 | 21 | m4_files="ax_append_flag.m4 ax_cflags_warn_all.m4 ax_compiler_vendor.m4 \ 22 | ax_prepend_flag.m4 ax_pthread.m4 ax_require_defined.m4" 23 | 24 | for ax in $m4_files; do 25 | rm -f "$ax" 26 | wget -O "$ax" "http://git.savannah.gnu.org/gitweb/?p=autoconf-archive.git;a=blob_plain;f=m4/$ax" 27 | done 28 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | 2021-06-02 Jerry Lundström 2 | 3 | Release 1.0.2 4 | 5 | This release fixes an issue with source port being static when only 6 | using `-q` to generate traffic from one host/IP. The source port is 7 | now randomized for every DNS query. 8 | 9 | Other changes is mainly about build system, packages and fixed issues 10 | detected by code analysis tools. 11 | 12 | 05000cc Typo, random source port 13 | 6a71707 Coverage 14 | 1c724ce SonarCloud 15 | 0776d20 Badges 16 | c274884 LGTM 17 | 5a12c61 COPR 18 | f77efed Build dependency 19 | a359b66 iconv 20 | 21 | 2019-10-07 Jerry Lundström 22 | 23 | Release 1.0.1 24 | 25 | This release fixes a few minor bugs and a dependency issue which made 26 | `dnsmeter` throw an exception when using the `-r` option. 27 | 28 | Bugfixes: 29 | - Use existing `rtt_avg`, was showing total RTT divided by number of threads 30 | - Fix an issue which missed the first 8 bytes of a text payload 31 | 32 | 72197b5 PCAP detect 33 | 665be2d RTT average 34 | 3fe7b66 pplib dependencies, RTT average 35 | e565d42 Funding 36 | 1a1ea40 README 37 | 38 | 2019-09-23 Jerry Lundström 39 | 40 | Release 1.0.0 41 | 42 | Initial release after project was moved from DENIC to DNS-OARC. 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | 54 | # Automake 55 | Makefile.in 56 | aclocal.m4 57 | ar-lib 58 | autom4te.cache 59 | compile 60 | config.guess 61 | config.sub 62 | configure 63 | depcomp 64 | install-sh 65 | ltmain.sh 66 | m4/libtool.m4 67 | m4/ltoptions.m4 68 | m4/ltsugar.m4 69 | m4/ltversion.m4 70 | m4/lt~obsolete.m4 71 | missing 72 | config.h.in 73 | config.h.in~ 74 | test-driver 75 | 76 | # Configure 77 | Makefile 78 | config.log 79 | config.status 80 | libtool 81 | .deps 82 | src/config.h 83 | src/stamp-h1 84 | build 85 | .dirstamp 86 | 87 | # Project specific files 88 | src/dnsmeter 89 | src/dnsmeter.1 90 | src/test/test-suite.log 91 | src/test/test*.sh.log 92 | src/test/test*.sh.trs 93 | src/test/*.dist 94 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, OARC, Inc. 3 | * Copyright (c) 2019, DENIC eG 4 | * All rights reserved. 5 | * 6 | * This file is part of dnsmeter. 7 | * 8 | * dnsmeter is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * dnsmeter is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with dnsmeter. If not, see . 20 | */ 21 | 22 | #include "config.h" 23 | 24 | #include "dns_sender.h" 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | int main(int argc, char** argv) 31 | { 32 | res_init(); 33 | // For unknown reason, res_mkquery is much slower (factor 3) when not 34 | // setting the following options: 35 | _res.options |= RES_USE_EDNS0; 36 | _res.options |= RES_USE_DNSSEC; 37 | 38 | DNSSender Sender; 39 | return Sender.main(argc, argv); 40 | } 41 | -------------------------------------------------------------------------------- /m4/ax_require_defined.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # https://www.gnu.org/software/autoconf-archive/ax_require_defined.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_REQUIRE_DEFINED(MACRO) 8 | # 9 | # DESCRIPTION 10 | # 11 | # AX_REQUIRE_DEFINED is a simple helper for making sure other macros have 12 | # been defined and thus are available for use. This avoids random issues 13 | # where a macro isn't expanded. Instead the configure script emits a 14 | # non-fatal: 15 | # 16 | # ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found 17 | # 18 | # It's like AC_REQUIRE except it doesn't expand the required macro. 19 | # 20 | # Here's an example: 21 | # 22 | # AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG]) 23 | # 24 | # LICENSE 25 | # 26 | # Copyright (c) 2014 Mike Frysinger 27 | # 28 | # Copying and distribution of this file, with or without modification, are 29 | # permitted in any medium without royalty provided the copyright notice 30 | # and this notice are preserved. This file is offered as-is, without any 31 | # warranty. 32 | 33 | #serial 2 34 | 35 | AC_DEFUN([AX_REQUIRE_DEFINED], [dnl 36 | m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])]) 37 | ])dnl AX_REQUIRE_DEFINED 38 | -------------------------------------------------------------------------------- /src/exceptions.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, OARC, Inc. 3 | * Copyright (c) 2019, DENIC eG 4 | * All rights reserved. 5 | * 6 | * This file is part of dnsmeter. 7 | * 8 | * dnsmeter is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * dnsmeter is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with dnsmeter. If not, see . 20 | */ 21 | 22 | #include 23 | 24 | #ifndef __dnsmeter_exceptions_h 25 | #define __dnsmeter_exceptions_h 26 | 27 | PPL7EXCEPTION(MissingCommandlineParameter, Exception); 28 | PPL7EXCEPTION(InvalidCommandlineParameter, Exception); 29 | PPL7EXCEPTION(InvalidDNSQuery, Exception); 30 | PPL7EXCEPTION(UnknownRRType, Exception); 31 | PPL7EXCEPTION(BufferOverflow, Exception); 32 | PPL7EXCEPTION(UnknownDestination, Exception); 33 | PPL7EXCEPTION(InvalidQueryFile, Exception); 34 | PPL7EXCEPTION(UnsupportedIPFamily, Exception); 35 | PPL7EXCEPTION(FailedToInitializePacketfilter, Exception); 36 | PPL7EXCEPTION(KernelAccessFailed, Exception); 37 | PPL7EXCEPTION(SystemCallFailed, Exception); 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: dnsmeter 2 | Section: net 3 | Priority: optional 4 | Maintainer: Jerry Lundström 5 | Build-Depends: debhelper (>= 10), build-essential, automake, autoconf, 6 | libtool, libssl-dev, libbz2-dev, libidn2-dev | libidn11-dev, 7 | zlib1g-dev, libpcap-dev, libpcre3-dev, gettext 8 | Standards-Version: 3.9.4 9 | Homepage: https://codeberg.org/DNS-OARC/dnsmeter 10 | Vcs-Git: https://codeberg.org/DNS-OARC/dnsmeter.git 11 | Vcs-Browser: https://codeberg.org/DNS-OARC/dnsmeter 12 | 13 | Package: dnsmeter 14 | Architecture: any 15 | Depends: ${shlibs:Depends}, ${misc:Depends} 16 | Description: DNS performance and infrastructure testing 17 | DNSMeter is a tool for testing performance of nameserver and/or 18 | infrastructure around it. 19 | It generates dns queries and sends them via UDP to a target nameserver 20 | and counts the answers. 21 | . 22 | Features: 23 | - payload can be given as text file or pcap file 24 | - can automatically run different load steps, which can be given as 25 | list or ranges 26 | - results per load step can be stored in CSV file 27 | - sender address can be spoofed from a given network or from pcap file, 28 | if payload is a pcap file 29 | - answers are counted, even if source address is spoofed, if answers get 30 | routed back to the load generator 31 | - roundtrip-times are measured (average, min, mix) 32 | - amount of DNSSEC queries can be given as percentage of total traffic 33 | - optimized for high amount of packets. On an Intel(R) Xeon(R) CPU E5-2430 34 | v2 @ 2.50GHz it can generate more than 900.000 packets per second 35 | -------------------------------------------------------------------------------- /src/raw_socket_sender.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, OARC, Inc. 3 | * Copyright (c) 2019, DENIC eG 4 | * All rights reserved. 5 | * 6 | * This file is part of dnsmeter. 7 | * 8 | * dnsmeter is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * dnsmeter is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with dnsmeter. If not, see . 20 | */ 21 | 22 | #include "packet.h" 23 | 24 | #include 25 | 26 | #ifndef __dnsmeter_raw_socket_sender_h 27 | #define __dnsmeter_raw_socket_sender_h 28 | 29 | class RawSocketSender { 30 | private: 31 | #if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L 32 | RawSocketSender& operator=(const RawSocketSender& other); 33 | RawSocketSender(RawSocketSender &&other) noexcept; 34 | RawSocketSender const & operator=(RawSocketSender &&other); 35 | #endif 36 | 37 | void* buffer; 38 | int sd; 39 | 40 | public: 41 | RawSocketSender(); 42 | ~RawSocketSender(); 43 | void setDestination(const ppl7::IPAddress& ip_addr, int port); 44 | ssize_t send(Packet& pkt); 45 | ppl7::SockAddr getSockAddr() const; 46 | bool socketReady(); 47 | }; 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /src/payload_file.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, OARC, Inc. 3 | * Copyright (c) 2019, DENIC eG 4 | * All rights reserved. 5 | * 6 | * This file is part of dnsmeter. 7 | * 8 | * dnsmeter is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * dnsmeter is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with dnsmeter. If not, see . 20 | */ 21 | 22 | #include 23 | #include 24 | 25 | #ifndef __dnsmeter_payload_file_h 26 | #define __dnsmeter_payload_file_h 27 | 28 | class PayloadFile { 29 | private: 30 | ppl7::Mutex QueryMutex; 31 | ppluint64 validLinesInQueryFile; 32 | std::list querycache; 33 | std::list::const_iterator it; 34 | bool payloadIsPcap; 35 | bool detectPcap(ppl7::File& ff); 36 | void loadAndCompile(ppl7::File& ff); 37 | void loadAndCompilePcapFile(const ppl7::String& Filename); 38 | 39 | public: 40 | PayloadFile(); 41 | void openQueryFile(const ppl7::String& Filename); 42 | const ppl7::ByteArrayPtr& getQuery(); 43 | bool isPcap(); 44 | }; 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | dnsmeter (1.0.2-1~unstable+1) unstable; urgency=low 2 | 3 | * Release 1.0.2 4 | 5 | This release fixes an issue with source port being static when only 6 | using `-q` to generate traffic from one host/IP. The source port is 7 | now randomized for every DNS query. 8 | 9 | Other changes is mainly about build system, packages and fixed issues 10 | detected by code analysis tools. 11 | 12 | 05000cc Typo, random source port 13 | 6a71707 Coverage 14 | 1c724ce SonarCloud 15 | 0776d20 Badges 16 | c274884 LGTM 17 | 5a12c61 COPR 18 | f77efed Build dependency 19 | a359b66 iconv 20 | 21 | -- Jerry Lundström Wed, 02 Jun 2021 09:27:07 +0200 22 | 23 | dnsmeter (1.0.1-1~unstable+1) unstable; urgency=low 24 | 25 | * Release 1.0.1 26 | 27 | This release fixes a few minor bugs and a dependency issue which made 28 | `dnsmeter` throw an exception when using the `-r` option. 29 | 30 | Bugfixes: 31 | - Use existing `rtt_avg`, was showing total RTT divided by number of threads 32 | - Fix an issue which missed the first 8 bytes of a text payload 33 | 34 | 72197b5 PCAP detect 35 | 665be2d RTT average 36 | 3fe7b66 pplib dependencies, RTT average 37 | e565d42 Funding 38 | 1a1ea40 README 39 | 40 | -- Jerry Lundström Mon, 07 Oct 2019 16:31:06 +0200 41 | 42 | dnsmeter (1.0.0-1~unstable+1) unstable; urgency=low 43 | 44 | * Release 1.0.0 45 | 46 | -- Jerry Lundström Mon, 23 Sep 2019 15:09:21 +0200 47 | 48 | dnsmeter (0.9.0-1~unstable+1) unstable; urgency=low 49 | 50 | * First package release 51 | 52 | -- Jerry Lundström Wed, 18 Sep 2019 17:19:16 +0200 53 | -------------------------------------------------------------------------------- /m4/ax_append_flag.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # https://www.gnu.org/software/autoconf-archive/ax_append_flag.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # FLAG is appended to the FLAGS-VARIABLE shell variable, with a space 12 | # added in between. 13 | # 14 | # If FLAGS-VARIABLE is not specified, the current language's flags (e.g. 15 | # CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains 16 | # FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly 17 | # FLAG. 18 | # 19 | # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. 20 | # 21 | # LICENSE 22 | # 23 | # Copyright (c) 2008 Guido U. Draheim 24 | # Copyright (c) 2011 Maarten Bosmans 25 | # 26 | # Copying and distribution of this file, with or without modification, are 27 | # permitted in any medium without royalty provided the copyright notice 28 | # and this notice are preserved. This file is offered as-is, without any 29 | # warranty. 30 | 31 | #serial 8 32 | 33 | AC_DEFUN([AX_APPEND_FLAG], 34 | [dnl 35 | AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF 36 | AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])]) 37 | AS_VAR_SET_IF(FLAGS,[ 38 | AS_CASE([" AS_VAR_GET(FLAGS) "], 39 | [*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])], 40 | [ 41 | AS_VAR_APPEND(FLAGS,[" $1"]) 42 | AC_RUN_LOG([: FLAGS="$FLAGS"]) 43 | ]) 44 | ], 45 | [ 46 | AS_VAR_SET(FLAGS,[$1]) 47 | AC_RUN_LOG([: FLAGS="$FLAGS"]) 48 | ]) 49 | AS_VAR_POPDEF([FLAGS])dnl 50 | ])dnl AX_APPEND_FLAG 51 | -------------------------------------------------------------------------------- /m4/ax_prepend_flag.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # https://www.gnu.org/software/autoconf-archive/ax_prepend_flag.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_PREPEND_FLAG(FLAG, [FLAGS-VARIABLE]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # FLAG is added to the front of the FLAGS-VARIABLE shell variable, with a 12 | # space added in between. 13 | # 14 | # If FLAGS-VARIABLE is not specified, the current language's flags (e.g. 15 | # CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains 16 | # FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly 17 | # FLAG. 18 | # 19 | # NOTE: Implementation based on AX_APPEND_FLAG. 20 | # 21 | # LICENSE 22 | # 23 | # Copyright (c) 2008 Guido U. Draheim 24 | # Copyright (c) 2011 Maarten Bosmans 25 | # Copyright (c) 2018 John Zaitseff 26 | # 27 | # Copying and distribution of this file, with or without modification, are 28 | # permitted in any medium without royalty provided the copyright notice 29 | # and this notice are preserved. This file is offered as-is, without any 30 | # warranty. 31 | 32 | #serial 2 33 | 34 | AC_DEFUN([AX_PREPEND_FLAG], 35 | [dnl 36 | AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF 37 | AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])]) 38 | AS_VAR_SET_IF(FLAGS,[ 39 | AS_CASE([" AS_VAR_GET(FLAGS) "], 40 | [*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])], 41 | [ 42 | FLAGS="$1 $FLAGS" 43 | AC_RUN_LOG([: FLAGS="$FLAGS"]) 44 | ]) 45 | ], 46 | [ 47 | AS_VAR_SET(FLAGS,[$1]) 48 | AC_RUN_LOG([: FLAGS="$FLAGS"]) 49 | ]) 50 | AS_VAR_POPDEF([FLAGS])dnl 51 | ])dnl AX_PREPEND_FLAG 52 | -------------------------------------------------------------------------------- /src/dns_receiver_thread.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, OARC, Inc. 3 | * Copyright (c) 2019, DENIC eG 4 | * All rights reserved. 5 | * 6 | * This file is part of dnsmeter. 7 | * 8 | * dnsmeter is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * dnsmeter is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with dnsmeter. If not, see . 20 | */ 21 | 22 | #include "raw_socket_receiver.h" 23 | 24 | #include 25 | #include 26 | 27 | #ifndef __dnsmeter_dns_receiver_thread_h 28 | #define __dnsmeter_dns_receiver_thread_h 29 | 30 | class DNSReceiverThread : public ppl7::Thread { 31 | private: 32 | RawSocketReceiver Socket; 33 | RawSocketReceiver::Counter counter; 34 | 35 | public: 36 | DNSReceiverThread(); 37 | ~DNSReceiverThread(); 38 | void setInterface(const ppl7::String& Device); 39 | void setSource(const ppl7::IPAddress& ip, int port); 40 | void run(); 41 | 42 | ppluint64 getPacketsReceived() const; 43 | ppluint64 getBytesReceived() const; 44 | 45 | double getDuration() const; 46 | double getRoundTripTimeAverage() const; 47 | double getRoundTripTimeMin() const; 48 | double getRoundTripTimeMax() const; 49 | const RawSocketReceiver::Counter& getCounter() const; 50 | }; 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/packet.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, OARC, Inc. 3 | * Copyright (c) 2019, DENIC eG 4 | * All rights reserved. 5 | * 6 | * This file is part of dnsmeter. 7 | * 8 | * dnsmeter is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * dnsmeter is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with dnsmeter. If not, see . 20 | */ 21 | 22 | #include 23 | #include 24 | 25 | #ifndef __dnsmeter_packet_h 26 | #define __dnsmeter_packet_h 27 | 28 | class Packet { 29 | private: 30 | #if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L 31 | Packet& operator=(const Packet& other); 32 | Packet(Packet &&other) noexcept; 33 | Packet const & operator=(Packet &&other); 34 | #endif 35 | 36 | unsigned char* buffer; 37 | int buffersize; 38 | int payload_size; 39 | bool chksum_valid; 40 | 41 | void updateChecksums(); 42 | 43 | public: 44 | Packet(); 45 | ~Packet(); 46 | void setSource(const ppl7::IPAddress& ip_addr, int port); 47 | void setDestination(const ppl7::IPAddress& ip_addr, int port); 48 | void setPayload(const void* payload, size_t size); 49 | void setPayloadDNSQuery(const ppl7::String& query, bool dnssec = false); 50 | void setDnsId(unsigned short id); 51 | void setIpId(unsigned short id); 52 | 53 | void randomSourceIP(const ppl7::IPNetwork& net); 54 | void randomSourceIP(unsigned int start, unsigned int size); 55 | void randomSourcePort(); 56 | void useSourceFromPcap(const char* pkt, size_t size); 57 | 58 | size_t size() const; 59 | unsigned char* ptr(); 60 | }; 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /src/query.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, OARC, Inc. 3 | * Copyright (c) 2019, DENIC eG 4 | * All rights reserved. 5 | * 6 | * This file is part of dnsmeter. 7 | * 8 | * dnsmeter is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * dnsmeter is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with dnsmeter. If not, see . 20 | */ 21 | 22 | #include 23 | 24 | #ifndef __dnsmeter_query_h 25 | #define __dnsmeter_query_h 26 | 27 | struct DNS_HEADER { 28 | unsigned short id; // identification number 29 | 30 | unsigned char rd : 1; // recursion desired 31 | unsigned char tc : 1; // truncated message 32 | unsigned char aa : 1; // authoritive answer 33 | unsigned char opcode : 4; // purpose of message 34 | unsigned char qr : 1; // query/response flag 35 | 36 | unsigned char rcode : 4; // response code 37 | unsigned char cd : 1; // checking disabled 38 | unsigned char ad : 1; // authenticated data 39 | unsigned char z : 1; // its z! reserved 40 | unsigned char ra : 1; // recursion available 41 | 42 | unsigned short q_count; // number of question entries 43 | unsigned short ans_count; // number of answer entries 44 | unsigned short auth_count; // number of authority entries 45 | unsigned short add_count; // number of resource entries 46 | }; 47 | 48 | int MakeQuery(const ppl7::String& query, unsigned char* buffer, size_t buffersize, bool dnssec = false, int udp_payload_size = 4096); 49 | int AddDnssecToQuery(unsigned char* buffer, size_t buffersize, int querysize, int udp_payload_size = 4096); 50 | unsigned short getQueryTimestamp(); 51 | double getQueryRTT(unsigned short start); 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/raw_socket_receiver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, OARC, Inc. 3 | * Copyright (c) 2019, DENIC eG 4 | * All rights reserved. 5 | * 6 | * This file is part of dnsmeter. 7 | * 8 | * dnsmeter is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * dnsmeter is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with dnsmeter. If not, see . 20 | */ 21 | 22 | #include 23 | #include 24 | 25 | #ifndef __dnsmeter_raw_socket_receiver_h 26 | #define __dnsmeter_raw_socket_receiver_h 27 | 28 | class RawSocketReceiver { 29 | private: 30 | #if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L 31 | RawSocketReceiver& operator=(const RawSocketReceiver& other); 32 | RawSocketReceiver(RawSocketReceiver &&other) noexcept; 33 | RawSocketReceiver const & operator=(RawSocketReceiver &&other); 34 | #endif 35 | 36 | ppl7::IPAddress SourceIP; 37 | unsigned char* buffer; 38 | int buflen; 39 | int sd; 40 | unsigned short SourcePort; 41 | #ifdef __FreeBSD__ 42 | bool useZeroCopyBuffer; 43 | #endif 44 | 45 | public: 46 | class Counter { 47 | public: 48 | Counter(); 49 | void clear(); 50 | ppluint64 num_pkgs; 51 | ppluint64 bytes_rcv; 52 | ppluint64 rcodes[16]; 53 | ppluint64 truncated; 54 | double rtt_total, rtt_min, rtt_max; 55 | }; 56 | 57 | RawSocketReceiver(); 58 | ~RawSocketReceiver(); 59 | void initInterface(const ppl7::String& Device); 60 | bool socketReady(); 61 | void setSource(const ppl7::IPAddress& ip_addr, int port); 62 | void receive(Counter& counter); 63 | }; 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /src/dns_receiver_thread.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, OARC, Inc. 3 | * Copyright (c) 2019, DENIC eG 4 | * All rights reserved. 5 | * 6 | * This file is part of dnsmeter. 7 | * 8 | * dnsmeter is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * dnsmeter is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with dnsmeter. If not, see . 20 | */ 21 | 22 | #include "config.h" 23 | 24 | #include "dns_receiver_thread.h" 25 | 26 | DNSReceiverThread::DNSReceiverThread() 27 | { 28 | } 29 | 30 | DNSReceiverThread::~DNSReceiverThread() 31 | { 32 | } 33 | 34 | void DNSReceiverThread::setInterface(const ppl7::String& Device) 35 | { 36 | Socket.initInterface(Device); 37 | } 38 | 39 | void DNSReceiverThread::setSource(const ppl7::IPAddress& ip, int port) 40 | { 41 | Socket.setSource(ip, port); 42 | } 43 | 44 | void DNSReceiverThread::run() 45 | { 46 | counter.clear(); 47 | while (1) { 48 | if (Socket.socketReady()) 49 | Socket.receive(counter); 50 | if (this->threadShouldStop()) 51 | break; 52 | } 53 | } 54 | 55 | ppluint64 DNSReceiverThread::getPacketsReceived() const 56 | { 57 | return counter.num_pkgs; 58 | } 59 | 60 | ppluint64 DNSReceiverThread::getBytesReceived() const 61 | { 62 | return counter.bytes_rcv; 63 | } 64 | 65 | double DNSReceiverThread::getDuration() const 66 | { 67 | return counter.rtt_total; 68 | } 69 | 70 | double DNSReceiverThread::getRoundTripTimeAverage() const 71 | { 72 | if (counter.num_pkgs) 73 | return counter.rtt_total / counter.num_pkgs; //NOSONAR 74 | return 0.0f; 75 | } 76 | 77 | double DNSReceiverThread::getRoundTripTimeMin() const 78 | { 79 | return counter.rtt_min; 80 | } 81 | 82 | double DNSReceiverThread::getRoundTripTimeMax() const 83 | { 84 | return counter.rtt_max; 85 | } 86 | 87 | const RawSocketReceiver::Counter& DNSReceiverThread::getCounter() const 88 | { 89 | return counter; 90 | } 91 | -------------------------------------------------------------------------------- /src/raw_socket_sender.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, OARC, Inc. 3 | * Copyright (c) 2019, DENIC eG 4 | * All rights reserved. 5 | * 6 | * This file is part of dnsmeter. 7 | * 8 | * dnsmeter is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * dnsmeter is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with dnsmeter. If not, see . 20 | */ 21 | 22 | #include "config.h" 23 | 24 | #include "raw_socket_sender.h" 25 | #include "exceptions.h" 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | RawSocketSender::RawSocketSender() 33 | { 34 | buffer = calloc(1, sizeof(struct sockaddr_in)); 35 | if (!buffer) 36 | throw ppl7::OutOfMemoryException(); 37 | struct sockaddr_in* dest = (struct sockaddr_in*)buffer; 38 | dest->sin_addr.s_addr = -1; 39 | if ((sd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) { 40 | free(buffer); 41 | ppl7::throwExceptionFromErrno(errno, "Could not create RawSocket"); 42 | } 43 | unsigned int set = 1; 44 | if (setsockopt(sd, IPPROTO_IP, IP_HDRINCL, &set, sizeof(set)) < 0) { 45 | close(sd); 46 | free(buffer); 47 | ppl7::throwExceptionFromErrno(errno, "Could not set socket option IP_HDRINCL"); 48 | } 49 | } 50 | 51 | RawSocketSender::~RawSocketSender() 52 | { 53 | close(sd); 54 | free(buffer); 55 | } 56 | 57 | void RawSocketSender::setDestination(const ppl7::IPAddress& ip_addr, int port) 58 | { 59 | if (ip_addr.family() != ppl7::IPAddress::IPv4) 60 | throw UnsupportedIPFamily("Only IPv4 is supported"); 61 | ip_addr.toSockAddr(buffer, sizeof(struct sockaddr_in)); 62 | ((struct sockaddr_in*)buffer)->sin_port = htons(port); 63 | } 64 | 65 | ssize_t RawSocketSender::send(Packet& pkt) 66 | { 67 | struct sockaddr_in* dest = (struct sockaddr_in*)buffer; 68 | if (dest->sin_addr.s_addr == (unsigned int)-1) 69 | throw UnknownDestination(); 70 | return sendto(sd, pkt.ptr(), pkt.size(), 0, 71 | (const struct sockaddr*)dest, sizeof(struct sockaddr_in)); 72 | } 73 | 74 | ppl7::SockAddr RawSocketSender::getSockAddr() const 75 | { 76 | return ppl7::SockAddr(buffer, sizeof(struct sockaddr_in)); 77 | } 78 | 79 | bool RawSocketSender::socketReady() 80 | { 81 | fd_set wset; 82 | struct timeval timeout; 83 | timeout.tv_sec = 0; 84 | timeout.tv_usec = 100; 85 | FD_ZERO(&wset); 86 | FD_SET(sd, &wset); // Wir wollen nur prüfen, ob wir schreiben können 87 | int ret = select(sd + 1, NULL, &wset, NULL, &timeout); 88 | if (ret < 0) 89 | return false; 90 | if (FD_ISSET(sd, &wset)) { 91 | return true; 92 | } 93 | return false; 94 | } 95 | -------------------------------------------------------------------------------- /src/dns_sender_thread.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, OARC, Inc. 3 | * Copyright (c) 2019, DENIC eG 4 | * All rights reserved. 5 | * 6 | * This file is part of dnsmeter. 7 | * 8 | * dnsmeter is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * dnsmeter is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with dnsmeter. If not, see . 20 | */ 21 | 22 | #include "raw_socket_sender.h" 23 | #include "payload_file.h" 24 | 25 | #include 26 | 27 | #ifndef __dnsmeter_dns_sender_thread_h 28 | #define __dnsmeter_dns_sender_thread_h 29 | 30 | class DNSSenderThread : public ppl7::Thread { 31 | private: 32 | #if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L 33 | DNSSenderThread& operator=(const DNSSenderThread& other); 34 | DNSSenderThread(DNSSenderThread &&other) noexcept; 35 | DNSSenderThread const & operator=(DNSSenderThread &&other); 36 | #endif 37 | 38 | RawSocketSender Socket; 39 | Packet pkt; 40 | 41 | ppl7::IPAddress destination; 42 | ppl7::IPAddress sourceip; 43 | ppl7::IPNetwork sourcenet; 44 | 45 | PayloadFile* payload; 46 | unsigned char* buffer; 47 | ppluint64 queryrate; 48 | ppluint64 counter_packets_send, errors, counter_0bytes; 49 | ppluint64 counter_bytes_send; 50 | ppluint64 counter_errorcodes[255]; 51 | 52 | unsigned int spoofing_net_start; 53 | unsigned int spoofing_net_size; 54 | 55 | int runtime; 56 | int timeout; 57 | int DnssecRate; 58 | int dnsseccounter; 59 | double Timeslice; 60 | 61 | double duration; 62 | bool spoofingEnabled; 63 | bool verbose; 64 | bool payloadIsPcap; 65 | bool spoofingFromPcap; 66 | 67 | void sendPacket(); 68 | void waitForTimeout(); 69 | bool socketReady(); 70 | 71 | void runWithoutRateLimit(); 72 | void runWithRateLimit(); 73 | 74 | public: 75 | DNSSenderThread(); 76 | ~DNSSenderThread(); 77 | void setDestination(const ppl7::IPAddress& ip, int port); 78 | void setSourceIP(const ppl7::IPAddress& ip); 79 | void setSourceNet(const ppl7::IPNetwork& net); 80 | void setSourcePcap(); 81 | void setRandomSource(const ppl7::IPNetwork& net); 82 | void setRuntime(int seconds); 83 | void setTimeout(int seconds); 84 | void setDNSSECRate(int rate); 85 | void setQueryRate(ppluint64 qps); 86 | void setTimeslice(float ms); 87 | void setVerbose(bool verbose); 88 | void setPayload(PayloadFile& payload); 89 | void run(); 90 | ppluint64 getPacketsSend() const; 91 | ppluint64 getBytesSend() const; 92 | ppluint64 getErrors() const; 93 | ppluint64 getCounter0Bytes() const; 94 | ppluint64 getCounterErrorCode(int err) const; 95 | }; 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2021, OARC, Inc. 2 | # Copyright (c) 2019, DENIC eG 3 | # All rights reserved. 4 | # 5 | # This file is part of dnsmeter. 6 | # 7 | # dnsmeter is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # dnsmeter is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with dnsmeter. If not, see . 19 | 20 | AC_PREREQ(2.69) 21 | AC_INIT([dnsmeter], [1.0.2], [admin@dns-oarc.net], [dnsmeter], [https://codeberg.org/DNS-OARC/dnsmeter/issues]) 22 | AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects]) 23 | AC_CONFIG_SRCDIR([src/main.cpp]) 24 | AC_CONFIG_HEADER([src/config.h]) 25 | AC_CONFIG_MACRO_DIR([m4]) 26 | 27 | # Checks for programs. 28 | AC_PROG_CXX 29 | AC_CANONICAL_HOST 30 | LT_INIT([disable-static]) 31 | 32 | # Check --enable-warn-all 33 | AC_ARG_ENABLE([warn-all], [AS_HELP_STRING([--enable-warn-all], [Enable all compiler warnings])], [AX_CFLAGS_WARN_ALL()]) 34 | 35 | # Check --with-extra-cflags 36 | AC_ARG_WITH([extra-cflags], [AS_HELP_STRING([--with-extra-cflags=CFLAGS], [Add extra CFLAGS/CXXFLAGS])], [ 37 | AC_MSG_NOTICE([appending extra CFLAGS/CXXFLAGS... $withval]) 38 | AS_VAR_APPEND(CFLAGS, [" $withval"]) 39 | AS_VAR_APPEND(CXXFLAGS, [" $withval"]) 40 | ]) 41 | 42 | # Check --with-extra-ldflags 43 | AC_ARG_WITH([extra-ldflags], [AS_HELP_STRING([--with-extra-ldflags=LDFLAGS], [Add extra LDFLAGS])], [ 44 | AC_MSG_NOTICE([appending extra LDFLAGS... $withval]) 45 | AS_VAR_APPEND(LDFLAGS, [" $withval"]) 46 | ]) 47 | 48 | # Check --enable-gcov 49 | AC_ARG_ENABLE([gcov], [AS_HELP_STRING([--enable-gcov], [Enable coverage testing])], [ 50 | coverage_cxxflags="--coverage -g -O0 -fno-inline -fno-inline-small-functions -fno-default-inline" 51 | AC_MSG_NOTICE([enabling coverage testing... $coverage_cxxflags]) 52 | AS_VAR_APPEND(CXXFLAGS, [" $coverage_cxxflags"]) 53 | ]) 54 | AM_CONDITIONAL([ENABLE_GCOV], [test "x$enable_gcov" != "xno"]) 55 | AM_EXTRA_RECURSIVE_TARGETS([gcov]) 56 | 57 | # Checks for support. 58 | AX_PTHREAD 59 | AC_CHECK_LIB([pcap], [pcap_open_live], [], [AC_MSG_ERROR([libpcap not found])]) 60 | AC_CHECK_LIB([m], [sqrt]) 61 | AC_CHECK_LIB([bind], [ns_initparse], [], [AC_CHECK_LIB([bind], [__ns_initparse])]) 62 | AC_CHECK_LIB([resolv], [res_mkquery], [], [ 63 | AC_CHECK_LIB([resolv], [__res_mkquery], [], [ 64 | AC_CHECK_LIB([resolv], [res_9_mkquery]) 65 | ]) 66 | ]) 67 | AC_CHECK_LIB([idn], [idna_to_ascii_4z]) 68 | AC_CHECK_LIB([idn2], [idn2_to_ascii_4z]) 69 | AC_CHECK_LIB([pcre], [pcre_exec]) 70 | 71 | sinclude(src/pplib/autoconf/iconv.m4) 72 | 73 | # Check for OS specific libraries 74 | case "$host_os" in 75 | freebsd*) 76 | AC_CHECK_LIB([kvm], [kvm_open]) 77 | AM_ICONV 78 | ICONV_CFLAGS="$INCICONV" 79 | ICONV_LIBS="$LIBICONV" 80 | AC_SUBST(ICONV_CFLAGS) 81 | AC_SUBST(ICONV_LIBS) 82 | ;; 83 | esac 84 | 85 | # Output Makefiles 86 | AC_CONFIG_FILES([ 87 | Makefile 88 | src/Makefile 89 | src/test/Makefile 90 | ]) 91 | AC_OUTPUT 92 | -------------------------------------------------------------------------------- /src/system_stat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, OARC, Inc. 3 | * Copyright (c) 2019, DENIC eG 4 | * All rights reserved. 5 | * 6 | * This file is part of dnsmeter. 7 | * 8 | * dnsmeter is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * dnsmeter is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with dnsmeter. If not, see . 20 | */ 21 | 22 | #include 23 | 24 | #ifndef __dnsmeter_system_stat_h 25 | #define __dnsmeter_system_stat_h 26 | 27 | class SystemStat { 28 | public: 29 | class Network { 30 | public: 31 | unsigned long bytes; 32 | unsigned long packets; 33 | unsigned long errs; 34 | unsigned long drop; 35 | Network() 36 | { 37 | bytes = packets = errs = drop = 0; 38 | } 39 | Network(unsigned long bytes, unsigned long packets, unsigned long errs, unsigned long drop) 40 | { 41 | this->bytes = bytes; 42 | this->packets = packets; 43 | this->errs = errs; 44 | this->drop = drop; 45 | } 46 | void clear() 47 | { 48 | bytes = packets = errs = drop = 0; 49 | } 50 | void print() 51 | { 52 | printf("Network bytes: %lu, packets: %lu, errs: %lu, drop: %lu\n", 53 | bytes, packets, errs, drop); 54 | } 55 | 56 | static Network getDelta(const Network& sample1, const Network& sample2); 57 | }; 58 | 59 | class Cpu { 60 | public: 61 | Cpu() 62 | { 63 | user = nice = system = idle = iowait = 0; 64 | } 65 | int user; 66 | int nice; 67 | int system; 68 | int idle; 69 | int iowait; 70 | 71 | static double getUsage(const SystemStat::Cpu& sample1, const SystemStat::Cpu& sample2); 72 | }; 73 | 74 | class Sysinfo { 75 | public: 76 | Sysinfo() 77 | { 78 | uptime = freeswap = totalswap = freeram = bufferram = totalram = sharedram = 0; 79 | procs = 0; 80 | } 81 | long uptime; 82 | long freeswap; 83 | long totalswap; 84 | long freeram; 85 | long bufferram; 86 | long totalram; 87 | long sharedram; 88 | int procs; 89 | }; 90 | 91 | class Interface { 92 | public: 93 | ppl7::String Name; 94 | Network receive; 95 | Network transmit; 96 | }; 97 | 98 | double sampleTime; 99 | 100 | Cpu cpu; 101 | Sysinfo sysinfo; 102 | Interface net_total; 103 | std::map interfaces; 104 | 105 | void exportToArray(ppl7::AssocArray& data) const; 106 | void importFromArray(const ppl7::AssocArray& data); 107 | void print() const; 108 | }; 109 | 110 | void sampleSensorData(SystemStat& stat); 111 | 112 | #endif 113 | -------------------------------------------------------------------------------- /rpm/dnsmeter.spec: -------------------------------------------------------------------------------- 1 | Name: dnsmeter 2 | Version: 1.0.2 3 | Release: 1%{?dist} 4 | Summary: DNS performance and infrastructure testing 5 | Group: Productivity/Networking/DNS/Utilities 6 | 7 | License: GPL-3.0 8 | URL: https://www.dns-oarc.net/tools/dnsmeter 9 | # Source needs to be generated by dist-tools/create-source-packages, see 10 | # https://github.com/jelu/dist-tools 11 | Source0: %{name}_%{version}.orig.tar.gz 12 | 13 | BuildRequires: autoconf 14 | BuildRequires: automake 15 | BuildRequires: libtool 16 | BuildRequires: gcc-c++ 17 | BuildRequires: bind-devel 18 | BuildRequires: openssl-devel 19 | %if 0%{?suse_version} || 0%{?sle_version} 20 | BuildRequires: libbz2-devel 21 | %else 22 | BuildRequires: bzip2-devel 23 | %endif 24 | BuildRequires: libidn2-devel 25 | BuildRequires: zlib-devel 26 | BuildRequires: libpcap-devel 27 | BuildRequires: pcre-devel 28 | BuildRequires: gettext-devel 29 | 30 | %description 31 | DNSMeter is a tool for testing performance of nameserver and/or 32 | infrastructure around it. 33 | It generates dns queries and sends them via UDP to a target nameserver 34 | and counts the answers. 35 | 36 | Features: 37 | - payload can be given as text file or pcap file 38 | - can automatically run different load steps, which can be given as 39 | list or ranges 40 | - results per load step can be stored in CSV file 41 | - sender address can be spoofed from a given network or from pcap file, 42 | if payload is a pcap file 43 | - answers are counted, even if source address is spoofed, if answers get 44 | routed back to the load generator 45 | - roundtrip-times are measured (average, min, mix) 46 | - amount of DNSSEC queries can be given as percentage of total traffic 47 | - optimized for high amount of packets. On an Intel(R) Xeon(R) CPU E5-2430 48 | v2 @ 2.50GHz it can generate more than 900.000 packets per second 49 | 50 | 51 | %prep 52 | %setup -q -n %{name}_%{version} 53 | 54 | 55 | %build 56 | sh autogen.sh 57 | %configure 58 | %make_build 59 | 60 | 61 | %install 62 | %make_install 63 | 64 | 65 | %check 66 | true 67 | 68 | 69 | %files 70 | %{_bindir}/dnsmeter 71 | %{_datadir}/doc/* 72 | %{_mandir}/man1/* 73 | 74 | 75 | %changelog 76 | * Wed Jun 02 2021 Jerry Lundström 1.0.2-1 77 | - Release 1.0.2 78 | * This release fixes an issue with source port being static when only 79 | using `-q` to generate traffic from one host/IP. The source port is 80 | now randomized for every DNS query. 81 | * Other changes is mainly about build system, packages and fixed issues 82 | detected by code analysis tools. 83 | * Commits: 84 | 05000cc Typo, random source port 85 | 6a71707 Coverage 86 | 1c724ce SonarCloud 87 | 0776d20 Badges 88 | c274884 LGTM 89 | 5a12c61 COPR 90 | f77efed Build dependency 91 | a359b66 iconv 92 | * Mon Oct 07 2019 Jerry Lundström 1.0.1-1 93 | - Release 1.0.1 94 | * This release fixes a few minor bugs and a dependency issue which made 95 | `dnsmeter` throw an exception when using the `-r` option. 96 | * Bugfixes: 97 | - Use existing `rtt_avg`, was showing total RTT divided by number of threads 98 | - Fix an issue which missed the first 8 bytes of a text payload 99 | * Commits: 100 | 72197b5 PCAP detect 101 | 665be2d RTT average 102 | 3fe7b66 pplib dependencies, RTT average 103 | e565d42 Funding 104 | 1a1ea40 README 105 | * Mon Sep 23 2019 Jerry Lundström 1.0.0-1 106 | - Release 1.0.0 107 | * Wed Sep 18 2019 Jerry Lundström 0.9.0-1 108 | - First package release 109 | -------------------------------------------------------------------------------- /src/dns_sender.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, OARC, Inc. 3 | * Copyright (c) 2019, DENIC eG 4 | * All rights reserved. 5 | * 6 | * This file is part of dnsmeter. 7 | * 8 | * dnsmeter is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * dnsmeter is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with dnsmeter. If not, see . 20 | */ 21 | 22 | #include "dns_receiver_thread.h" 23 | #include "payload_file.h" 24 | #include "system_stat.h" 25 | 26 | #include 27 | 28 | #ifndef __dnsmeter_dns_sender_h 29 | #define __dnsmeter_dns_sender_h 30 | 31 | class DNSSender { 32 | private: 33 | #if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L 34 | DNSSender& operator=(const DNSSender& other); 35 | DNSSender(DNSSender &&other) noexcept; 36 | DNSSender const & operator=(DNSSender &&other); 37 | #endif 38 | 39 | public: 40 | class Results { 41 | public: 42 | int queryrate; 43 | ppluint64 counter_send; 44 | ppluint64 counter_received; 45 | ppluint64 bytes_send; 46 | ppluint64 bytes_received; 47 | ppluint64 counter_errors; 48 | ppluint64 packages_lost; 49 | ppluint64 counter_0bytes; 50 | ppluint64 counter_errorcodes[255]; 51 | ppluint64 rcodes[16]; 52 | ppluint64 truncated; 53 | double rtt_total; 54 | double rtt_avg; 55 | double rtt_min; 56 | double rtt_max; 57 | Results(); 58 | void clear(); 59 | }; 60 | 61 | private: 62 | ppl7::ThreadPool threadpool; 63 | ppl7::IPAddress TargetIP; 64 | ppl7::IPAddress SourceIP; 65 | ppl7::IPNetwork SourceNet; 66 | ppl7::String CSVFileName; 67 | ppl7::String QueryFilename; 68 | ppl7::File CSVFile; 69 | ppl7::Array rates; 70 | ppl7::String InterfaceName; 71 | PayloadFile payload; 72 | DNSReceiverThread* Receiver; 73 | DNSSender::Results vis_prev_results; 74 | SystemStat sys1, sys2; 75 | 76 | int TargetPort; 77 | int Runtime; 78 | int Timeout; 79 | int ThreadCount; 80 | int DnssecRate; 81 | float Timeslices; 82 | bool ignoreResponses; 83 | bool spoofingEnabled; 84 | bool spoofFromPcap; 85 | 86 | void openCSVFile(const ppl7::String& Filename); 87 | void run(int queryrate); 88 | void presentResults(const DNSSender::Results& result); 89 | void saveResultsToCsv(const DNSSender::Results& result); 90 | void prepareThreads(); 91 | void getResults(DNSSender::Results& result); 92 | ppl7::Array getQueryRates(const ppl7::String& QueryRates); 93 | void readSourceIPList(const ppl7::String& filename); 94 | 95 | void getTarget(int argc, char** argv); 96 | void getSource(int argc, char** argv); 97 | int getParameter(int argc, char** argv); 98 | int openFiles(); 99 | void calcTimeslice(int queryrate); 100 | 101 | void showCurrentStats(ppl7::ppl_time_t start_time); 102 | 103 | public: 104 | DNSSender(); 105 | ~DNSSender(); 106 | void help(); 107 | int main(int argc, char** argv); 108 | }; 109 | 110 | DNSSender::Results operator-(const DNSSender::Results& first, const DNSSender::Results& second); 111 | 112 | #endif 113 | -------------------------------------------------------------------------------- /src/query.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, OARC, Inc. 3 | * Copyright (c) 2019, DENIC eG 4 | * All rights reserved. 5 | * 6 | * This file is part of dnsmeter. 7 | * 8 | * dnsmeter is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * dnsmeter is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with dnsmeter. If not, see . 20 | */ 21 | 22 | #include "config.h" 23 | 24 | #include "query.h" 25 | #include "exceptions.h" 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | static const char* rr_types[] = { 34 | "A", "AAAA", "MX", "NS", "DS", "DNSKEY", "TXT", "SOA", "NAPTR", "RRSIG", 35 | "NSEC", "NSEC3", "NSEC3PARAM", "PTR", "SRV", 36 | "CNAME", "TSIG", "*", "ANY", "AXFR", "IXFR", 37 | "SPF", "A6", "HINFO", "WKS", "NULL", 38 | NULL 39 | }; 40 | 41 | static int rr_code[] = { 42 | 1, 28, 15, 2, 43, 48, 16, 6, 35, 46, 43 | 47, 50, 51, 12, 33, 44 | 5, 250, 255, 255, 252, 251, 45 | 99, 38, 13, 11, 10, 46 | 0 47 | }; 48 | 49 | #pragma pack(push) /* push current alignment to stack */ 50 | #pragma pack(1) /* set alignment to 1 byte boundary */ 51 | struct DNS_OPT { 52 | unsigned char name; 53 | unsigned short type; 54 | unsigned short udp_payload_size; 55 | unsigned char extended_rcode; 56 | unsigned char edns0_version; 57 | unsigned short z; 58 | unsigned short data_length; 59 | }; 60 | #pragma pack(pop) /* restore original alignment from stack */ 61 | 62 | int MakeQuery(const ppl7::String& query, unsigned char* buffer, size_t buffersize, bool dnssec, int udp_payload_size) 63 | { 64 | ppl7::Array tok(query, " "); 65 | if (tok.size() != 2) 66 | throw InvalidDNSQuery(query); 67 | ppl7::String Type = tok[1].toUpperCase(); 68 | 69 | int t = 0; 70 | const char* str = Type.c_str(); 71 | while (rr_types[t] != NULL) { 72 | if (!strcmp(str, rr_types[t])) { 73 | int bytes = res_mkquery(QUERY, 74 | (const char*)tok[0], 75 | C_IN, 76 | rr_code[t], 77 | NULL, 0, NULL, buffer, (int)buffersize); 78 | if (bytes < 0) 79 | throw InvalidDNSQuery("%s", hstrerror(h_errno)); 80 | if (!dnssec) 81 | return bytes; 82 | return AddDnssecToQuery(buffer, buffersize, bytes, udp_payload_size); 83 | } 84 | t++; 85 | } 86 | throw UnknownRRType(tok[1]); 87 | } 88 | 89 | int AddDnssecToQuery(unsigned char* buffer, size_t buffersize, int querysize, int udp_payload_size) 90 | { 91 | DNS_HEADER* dns = (DNS_HEADER*)buffer; 92 | dns->ad = 1; 93 | dns->add_count = htons(1); 94 | DNS_OPT* opt = (DNS_OPT*)(buffer + querysize); 95 | memset(opt, 0, 11); 96 | opt->type = htons(41); 97 | opt->udp_payload_size = htons(udp_payload_size); 98 | opt->z = htons(0x8000); // DO-bit 99 | return querysize + 11; 100 | } 101 | 102 | unsigned short getQueryTimestamp() 103 | { 104 | struct timeval tp; 105 | if (gettimeofday(&tp, NULL) == 0) { 106 | return (tp.tv_sec % 6) * 10000 + (tp.tv_usec / 100); 107 | } 108 | return 0; 109 | } 110 | 111 | double getQueryRTT(unsigned short start) 112 | { 113 | unsigned short now = getQueryTimestamp(); 114 | unsigned short diff = now - start; 115 | if (now < start) 116 | diff = 60000 - start + now; 117 | return (double)(diff) / 10000.0f; 118 | } 119 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: dnsmeter 3 | Source: https://codeberg.org/DNS-OARC/dnsmeter 4 | 5 | Files: * 6 | Copyright: 2019-2021 OARC, Inc. 7 | 2019 DENIC eG 8 | License: GPLv3 9 | 10 | Files: debian/* 11 | Copyright: 2021 Jerry Lundström 12 | License: BSD-3-Clause 13 | 14 | Files: src/pplib/* 15 | Copyright: 2019 Patrick Fedick 16 | License: BSD-2-Clause 17 | 18 | License: GPLv3 19 | This is free software: you can redistribute it and/or modify 20 | it under the terms of the GNU General Public License as published by 21 | the Free Software Foundation, either version 3 of the License, or 22 | (at your option) any later version. 23 | . 24 | This is distributed in the hope that it will be useful, 25 | but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 | GNU General Public License for more details. 28 | . 29 | You should have received a copy of the GNU General Public License 30 | along with this. If not, see . 31 | 32 | License: BSD-3-Clause 33 | Redistribution and use in source and binary forms, with or without 34 | modification, are permitted provided that the following conditions 35 | are met: 36 | . 37 | 1. Redistributions of source code must retain the above copyright 38 | notice, this list of conditions and the following disclaimer. 39 | . 40 | 2. Redistributions in binary form must reproduce the above copyright 41 | notice, this list of conditions and the following disclaimer in 42 | the documentation and/or other materials provided with the 43 | distribution. 44 | . 45 | 3. Neither the name of the copyright holder nor the names of its 46 | contributors may be used to endorse or promote products derived 47 | from this software without specific prior written permission. 48 | . 49 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 50 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 51 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 52 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 53 | COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 54 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 55 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 56 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 57 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 58 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 59 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 60 | POSSIBILITY OF SUCH DAMAGE. 61 | 62 | Licence: BSD-2-Clause 63 | Redistribution and use in source and binary forms, with or without 64 | modification, are permitted provided that the following conditions are met: 65 | . 66 | 1. Redistributions of source code must retain the above copyright notice, 67 | this list of conditions and the following disclaimer. 68 | 2. Redistributions in binary form must reproduce the above copyright notice, 69 | this list of conditions and the following disclaimer in the documentation 70 | and/or other materials provided with the distribution. 71 | . 72 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 73 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 74 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 75 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 76 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 77 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 78 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 79 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 80 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 81 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 82 | -------------------------------------------------------------------------------- /m4/ax_compiler_vendor.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # https://www.gnu.org/software/autoconf-archive/ax_compiler_vendor.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_COMPILER_VENDOR 8 | # 9 | # DESCRIPTION 10 | # 11 | # Determine the vendor of the C, C++ or Fortran compiler. The vendor is 12 | # returned in the cache variable $ax_cv_c_compiler_vendor for C, 13 | # $ax_cv_cxx_compiler_vendor for C++ or $ax_cv_fc_compiler_vendor for 14 | # (modern) Fortran. The value is one of "intel", "ibm", "pathscale", 15 | # "clang" (LLVM), "cray", "fujitsu", "sdcc", "sx", "portland" (PGI), "gnu" 16 | # (GCC), "sun" (Oracle Developer Studio), "hp", "dec", "borland", 17 | # "comeau", "kai", "lcc", "sgi", "microsoft", "metrowerks", "watcom", 18 | # "tcc" (Tiny CC) or "unknown" (if the compiler cannot be determined). 19 | # 20 | # To check for a Fortran compiler, you must first call AC_FC_PP_SRCEXT 21 | # with an appropriate preprocessor-enabled extension. For example: 22 | # 23 | # AC_LANG_PUSH([Fortran]) 24 | # AC_PROG_FC 25 | # AC_FC_PP_SRCEXT([F]) 26 | # AX_COMPILER_VENDOR 27 | # AC_LANG_POP([Fortran]) 28 | # 29 | # LICENSE 30 | # 31 | # Copyright (c) 2008 Steven G. Johnson 32 | # Copyright (c) 2008 Matteo Frigo 33 | # Copyright (c) 2018-19 John Zaitseff 34 | # 35 | # This program is free software: you can redistribute it and/or modify it 36 | # under the terms of the GNU General Public License as published by the 37 | # Free Software Foundation, either version 3 of the License, or (at your 38 | # option) any later version. 39 | # 40 | # This program is distributed in the hope that it will be useful, but 41 | # WITHOUT ANY WARRANTY; without even the implied warranty of 42 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 43 | # Public License for more details. 44 | # 45 | # You should have received a copy of the GNU General Public License along 46 | # with this program. If not, see . 47 | # 48 | # As a special exception, the respective Autoconf Macro's copyright owner 49 | # gives unlimited permission to copy, distribute and modify the configure 50 | # scripts that are the output of Autoconf when processing the Macro. You 51 | # need not follow the terms of the GNU General Public License when using 52 | # or distributing such scripts, even though portions of the text of the 53 | # Macro appear in them. The GNU General Public License (GPL) does govern 54 | # all other use of the material that constitutes the Autoconf Macro. 55 | # 56 | # This special exception to the GPL applies to versions of the Autoconf 57 | # Macro released by the Autoconf Archive. When you make and distribute a 58 | # modified version of the Autoconf Macro, you may extend this special 59 | # exception to the GPL to apply to your modified version as well. 60 | 61 | #serial 30 62 | 63 | AC_DEFUN([AX_COMPILER_VENDOR], [dnl 64 | AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor, [dnl 65 | dnl If you modify this list of vendors, please add similar support 66 | dnl to ax_compiler_version.m4 if at all possible. 67 | dnl 68 | dnl Note: Do NOT check for GCC first since some other compilers 69 | dnl define __GNUC__ to remain compatible with it. Compilers that 70 | dnl are very slow to start (such as Intel) are listed first. 71 | 72 | vendors=" 73 | intel: __ICC,__ECC,__INTEL_COMPILER 74 | ibm: __xlc__,__xlC__,__IBMC__,__IBMCPP__,__ibmxl__ 75 | pathscale: __PATHCC__,__PATHSCALE__ 76 | clang: __clang__ 77 | cray: _CRAYC 78 | fujitsu: __FUJITSU 79 | sdcc: SDCC,__SDCC 80 | sx: _SX 81 | portland: __PGI 82 | gnu: __GNUC__ 83 | sun: __SUNPRO_C,__SUNPRO_CC,__SUNPRO_F90,__SUNPRO_F95 84 | hp: __HP_cc,__HP_aCC 85 | dec: __DECC,__DECCXX,__DECC_VER,__DECCXX_VER 86 | borland: __BORLANDC__,__CODEGEARC__,__TURBOC__ 87 | comeau: __COMO__ 88 | kai: __KCC 89 | lcc: __LCC__ 90 | sgi: __sgi,sgi 91 | microsoft: _MSC_VER 92 | metrowerks: __MWERKS__ 93 | watcom: __WATCOMC__ 94 | tcc: __TINYC__ 95 | unknown: UNKNOWN 96 | " 97 | for ventest in $vendors; do 98 | case $ventest in 99 | *:) 100 | vendor=$ventest 101 | continue 102 | ;; 103 | *) 104 | vencpp="defined("`echo $ventest | sed 's/,/) || defined(/g'`")" 105 | ;; 106 | esac 107 | 108 | AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [[ 109 | #if !($vencpp) 110 | thisisanerror; 111 | #endif 112 | ]])], [break]) 113 | done 114 | 115 | ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=`echo $vendor | cut -d: -f1` 116 | ]) 117 | ])dnl 118 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dnsmeter 2 | 3 | [![Total alerts](https://img.shields.io/lgtm/alerts/g/DNS-OARC/dnsmeter.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/DNS-OARC/dnsmeter/alerts/) [![Bugs](https://sonarcloud.io/api/project_badges/measure?project=dns-oarc%3Adnsmeter&metric=bugs)](https://sonarcloud.io/dashboard?id=dns-oarc%3Adnsmeter) [![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=dns-oarc%3Adnsmeter&metric=security_rating)](https://sonarcloud.io/dashboard?id=dns-oarc%3Adnsmeter) 4 | 5 | `dnsmeter` is a tool for testing performance of a nameserver and the 6 | infrastructure around it. It generates DNS queries and sends them via UDP 7 | to a target nameserver and counts the answers. 8 | 9 | Features: 10 | - payload can be given as a text file or a PCAP file 11 | - can automatically run different load steps, which can be given as a list or ranges 12 | - results per load step can be stored in a CSV file 13 | - sender addresses can be spoofed from a given network or from the addresses found in the PCAP file 14 | - answers are counted, even if source address is spoofed, if answers get routed back to the load generator 15 | - round-trip-times are measured (average, min, mix) 16 | - the amount of DNSSEC queries can be given as percentage of total traffic 17 | - optimized for high amount of packets, on an Intel(R) Xeon(R) CPU E5-2430 v2 @ 2.50GHz it can generate more than 900.000 packets per second 18 | - runs on Linux and FreeBSD 19 | 20 | NOTE: 21 | - Only IPv4 is support 22 | 23 | ## Dependencies 24 | 25 | `dnsmeter` requires a couple of libraries beside a normal C++ compiling 26 | environment with autoconf, automake and libtool. 27 | 28 | `dnsmeter` has a non-optional dependency on the PCRE library, `libresolv` 29 | and PCAP library. 30 | 31 | `dnsmeter` also includes [pplib](https://github.com/DNS-OARC/pplib), 32 | collection of C++ functions and classes, and it has non-optional dependency 33 | on OpenSSL, bzip2, IDN2 (or IDN1) library and zlib. 34 | 35 | To install the dependencies under Debian/Ubuntu: 36 | ``` 37 | apt-get install -y libssl-dev libbz2-dev libidn2-dev zlib1g-dev libpcap-dev libpcre3-dev gettext 38 | ``` 39 | 40 | NOTE: If your system does not have `libidn2-dev`, please use `libidn11-dev` instead. 41 | 42 | To install the dependencies under CentOS (with EPEL/PowerTools enabled): 43 | ``` 44 | yum install -y openssl-devel bzip2-devel libidn2-devel zlib-devel libpcap-devel pcre-devel gettext-devel 45 | ``` 46 | 47 | NOTE: If your using openSUSE/SLE then bzip2's package is `libbz2-devel`. 48 | 49 | To install the dependencies under FreeBSD 10+ using `pkg`: 50 | ``` 51 | pkg install -y openssl libidn2 libpcap pcre gettext 52 | ``` 53 | 54 | ## Building from source tarball 55 | 56 | The [source tarball from DNS-OARC](https://www.dns-oarc.net/tools/dnsmeter) 57 | comes prepared with `configure`: 58 | 59 | ``` 60 | tar zxvf dnsmeter-version.tar.gz 61 | cd dnsmeter-version 62 | ./configure [options] 63 | make 64 | make install 65 | ``` 66 | 67 | NOTE: If building fails on FreeBSD, try adding these configure 68 | options: `--with-extra-cflags="-I /usr/local/include" --with-extra-ldflags="-L/usr/local/lib"`. 69 | 70 | ## Building from Git repository 71 | 72 | If you are building `dnsmeter` from it's Git repository you will first need 73 | to initiate the Git submodules that exists and later create autoconf/automake 74 | files, this will require a build environment with autoconf, automake and 75 | libtool to be installed. 76 | 77 | ``` 78 | git clone https://codeberg.org/DNS-OARC/dnsmeter.git 79 | cd dnsmeter 80 | git submodule update --init 81 | ./autogen.sh 82 | ./configure [options] 83 | make 84 | make install 85 | ``` 86 | 87 | ## Usage 88 | 89 | Once installed please see `man dnsmeter` for usage. 90 | 91 | ## Example 92 | 93 | Lets assume the following scenario: 94 | 95 | - load generator runs on FreeBSD 96 | - network interface an which the traffic goes out and comes back is `igb0` 97 | - source IP on the load generator is 192.168.155.20 98 | - target nameserver has IP 192.168.0.1, port 53 99 | - we want to spoof the sender address from the network 10.0.0.0/8 100 | - the payload file is found here: `/home/testdata/payload.txt` 101 | - the nameserver is running on CentOS and we need to set a route back to the load generator: `ip route add 10.0.0.0/8 via 192.168.155.20` 102 | - we want to test the following load steps: 30000,40000,45000,50000,100000,150000 103 | - results should be written to `results.csv` 104 | - DNSSEC rate should be 70% 105 | 106 | This makes the following command: 107 | 108 | ``` 109 | dnsmeter -p /home/testdata/payload.txt \ 110 | -r 30000,40000,45000,50000,100000,150000 \ 111 | -s 10.0.0.0/8 \ 112 | -z 192.168.0.1:53 \ 113 | -e igb0 \ 114 | -d 70 \ 115 | -c results.csv 116 | ``` 117 | 118 | In the second example, we want to use a PCAP file as payload and want 119 | to spoof with the addresses from that file: 120 | 121 | ``` 122 | dnsmeter -p /home/testdata/pcap.file1 \ 123 | -r 30000,40000,45000,50000,100000,150000 \ 124 | -s pcap \ 125 | -z 192.168.0.1:53 \ 126 | -e igb0 \ 127 | -c results_pcap.csv 128 | ``` 129 | 130 | ## Author(s) 131 | 132 | - Patrick Fedick [@pfedick](https://github.com/pfedick) 133 | 134 | ## Contributor(s) 135 | 136 | - Jerry Lundström [@jelu](https://github.com/jelu) 137 | 138 | ## Copyright 139 | 140 | Copyright (c) 2019-2021, OARC, Inc. 141 | 142 | Copyright (c) 2019, DENIC eG 143 | 144 | All rights reserved. 145 | 146 | ``` 147 | This file is part of dnsmeter. 148 | 149 | dnsmeter is free software: you can redistribute it and/or modify 150 | it under the terms of the GNU General Public License as published by 151 | the Free Software Foundation, either version 3 of the License, or 152 | (at your option) any later version. 153 | 154 | dnsmeter is distributed in the hope that it will be useful, 155 | but WITHOUT ANY WARRANTY; without even the implied warranty of 156 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 157 | GNU General Public License for more details. 158 | 159 | You should have received a copy of the GNU General Public License 160 | along with dnsmeter. If not, see . 161 | ``` 162 | -------------------------------------------------------------------------------- /src/payload_file.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, OARC, Inc. 3 | * Copyright (c) 2019, DENIC eG 4 | * All rights reserved. 5 | * 6 | * This file is part of dnsmeter. 7 | * 8 | * dnsmeter is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * dnsmeter is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with dnsmeter. If not, see . 20 | */ 21 | 22 | #include "config.h" 23 | 24 | #include "payload_file.h" 25 | #include "exceptions.h" 26 | #include "query.h" 27 | 28 | #define __FAVOR_BSD 1 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #pragma pack(push) /* push current alignment to stack */ 36 | #pragma pack(1) /* set alignment to 1 byte boundary */ 37 | struct ETHER { 38 | unsigned char destination[6]; 39 | unsigned char source[6]; 40 | unsigned short type; 41 | }; 42 | #pragma pack(pop) /* restore original alignment from stack */ 43 | 44 | PayloadFile::PayloadFile() 45 | { 46 | validLinesInQueryFile = 0; 47 | payloadIsPcap = false; 48 | } 49 | 50 | bool PayloadFile::detectPcap(ppl7::File& ff) 51 | { 52 | unsigned char buffer[8]; 53 | if (ff.read(buffer, 8) != 8) { 54 | ff.seek(0); 55 | return false; 56 | } 57 | ff.seek(0); 58 | unsigned int magic = ppl7::Peek32(buffer + 0); 59 | if (magic == 0xa1b2c3d4 || magic == 0xa1b23c4d) 60 | return true; 61 | if (magic == 0xd4c3b2a1 || magic == 0x4d3cb2a1) 62 | return true; 63 | return false; 64 | } 65 | 66 | void PayloadFile::openQueryFile(const ppl7::String& Filename) 67 | { 68 | if (Filename.isEmpty()) 69 | throw InvalidQueryFile("File not given"); 70 | ppl7::File QueryFile; 71 | QueryFile.open(Filename, ppl7::File::READ); 72 | if (QueryFile.size() == 0) { 73 | throw InvalidQueryFile("File is empty [%s]", (const char*)Filename); 74 | } 75 | printf("INFO: Loading and precompile payload. This could take some time...\n"); 76 | if (detectPcap(QueryFile)) { 77 | loadAndCompilePcapFile(Filename); 78 | } else { 79 | loadAndCompile(QueryFile); 80 | } 81 | printf("INFO: %llu queries loaded\n", validLinesInQueryFile); 82 | it = querycache.begin(); 83 | } 84 | 85 | void PayloadFile::loadAndCompile(ppl7::File& ff) 86 | { 87 | ppl7::ByteArray buf(4096); 88 | ppl7::String buffer; 89 | validLinesInQueryFile = 0; 90 | unsigned char* compiled_query = (unsigned char*)buf.ptr(); 91 | while (1) { 92 | try { 93 | if (ff.eof()) 94 | throw ppl7::EndOfFileException(); 95 | ff.gets(buffer, 1024); 96 | buffer.trim(); 97 | if (buffer.isEmpty()) 98 | continue; 99 | if (buffer.c_str()[0] == '#') 100 | continue; 101 | try { 102 | // Precompile Query 103 | int size = MakeQuery(buffer, compiled_query, 4096, false); 104 | querycache.push_back(ppl7::ByteArray(compiled_query, size)); 105 | validLinesInQueryFile++; 106 | } catch (...) { 107 | // ignore invalid queries 108 | continue; 109 | } 110 | } catch (const ppl7::EndOfFileException&) { 111 | if (validLinesInQueryFile == 0) { 112 | throw InvalidQueryFile("No valid Queries found in Queryfile"); 113 | } 114 | return; 115 | } 116 | } 117 | } 118 | 119 | void PayloadFile::loadAndCompilePcapFile(const ppl7::String& Filename) 120 | { 121 | char errorbuffer[PCAP_ERRBUF_SIZE]; 122 | struct pcap_pkthdr hdr; 123 | payloadIsPcap = true; 124 | validLinesInQueryFile = 0; 125 | pcap_t* pp = pcap_open_offline((const char*)Filename, errorbuffer); 126 | if (!pp) 127 | throw InvalidQueryFile("%s", errorbuffer); 128 | ppluint64 pkts_total = 0; 129 | const u_char* pkt; 130 | while ((pkt = pcap_next(pp, &hdr)) != NULL) { 131 | pkts_total++; 132 | //printf ("len=%d, caplen=%d\n",hdr.len,hdr.caplen); 133 | const struct ETHER* eth = (const struct ETHER*)pkt; 134 | if (hdr.caplen > 4096) 135 | continue; 136 | if (eth->type != htons(0x0800)) 137 | continue; 138 | const struct ip* iphdr = (const struct ip*)(pkt + 14); 139 | if (iphdr->ip_v != 4) 140 | continue; 141 | const struct udphdr* udp = (const struct udphdr*)(pkt + 14 + sizeof(struct ip)); 142 | if (udp->uh_dport != htons(53)) 143 | continue; 144 | const struct DNS_HEADER* dns = (const struct DNS_HEADER*)(pkt + 14 + sizeof(struct ip) + sizeof(struct udphdr)); 145 | if (dns->qr != 0 || dns->opcode != 0) 146 | continue; 147 | querycache.push_back(ppl7::ByteArray(pkt, hdr.caplen)); 148 | validLinesInQueryFile++; 149 | } 150 | printf("Packets read from pcap file: %llu, valid UDP DNS queries: %llu\n", 151 | pkts_total, validLinesInQueryFile); 152 | pcap_close(pp); 153 | if (validLinesInQueryFile == 0) { 154 | throw InvalidQueryFile("No valid Queries found in pcap file [%s]", (const char*)Filename); 155 | } 156 | } 157 | 158 | const ppl7::ByteArrayPtr& PayloadFile::getQuery() 159 | { 160 | QueryMutex.lock(); 161 | const ppl7::ByteArrayPtr& bap = *it; 162 | ++it; 163 | if (it == querycache.end()) 164 | it = querycache.begin(); 165 | QueryMutex.unlock(); 166 | return bap; 167 | } 168 | 169 | bool PayloadFile::isPcap() 170 | { 171 | return payloadIsPcap; 172 | } 173 | -------------------------------------------------------------------------------- /m4/ax_cflags_warn_all.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # https://www.gnu.org/software/autoconf-archive/ax_cflags_warn_all.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_CFLAGS_WARN_ALL [(shellvar[, default[, action-if-found[, action-if-not-found]]])] 8 | # AX_CXXFLAGS_WARN_ALL [(shellvar[, default[, action-if-found[, action-if-not-found]]])] 9 | # AX_FCFLAGS_WARN_ALL [(shellvar[, default[, action-if-found[, action-if-not-found]]])] 10 | # 11 | # DESCRIPTION 12 | # 13 | # Specify compiler options that enable most reasonable warnings. For the 14 | # GNU Compiler Collection (GCC), for example, it will be "-Wall". The 15 | # result is added to shellvar, one of CFLAGS, CXXFLAGS or FCFLAGS if the 16 | # first parameter is not specified. 17 | # 18 | # Each of these macros accepts the following optional arguments: 19 | # 20 | # - $1 - shellvar 21 | # shell variable to use (CFLAGS, CXXFLAGS or FCFLAGS if not 22 | # specified, depending on macro) 23 | # 24 | # - $2 - default 25 | # value to use for flags if compiler vendor cannot be determined (by 26 | # default, "") 27 | # 28 | # - $3 - action-if-found 29 | # action to take if the compiler vendor has been successfully 30 | # determined (by default, add the appropriate compiler flags to 31 | # shellvar) 32 | # 33 | # - $4 - action-if-not-found 34 | # action to take if the compiler vendor has not been determined or 35 | # is unknown (by default, add the default flags, or "" if not 36 | # specified, to shellvar) 37 | # 38 | # These macros use AX_COMPILER_VENDOR to determine which flags should be 39 | # returned for a given compiler. Not all compilers currently have flags 40 | # defined for them; patches are welcome. If need be, compiler flags may 41 | # be made language-dependent: use a construct like the following: 42 | # 43 | # [vendor_name], [m4_if(_AC_LANG_PREFIX,[C], VAR="--relevant-c-flags",dnl 44 | # m4_if(_AC_LANG_PREFIX,[CXX], VAR="--relevant-c++-flags",dnl 45 | # m4_if(_AC_LANG_PREFIX,[FC], VAR="--relevant-fortran-flags",dnl 46 | # VAR="$2"; FOUND="no")))], 47 | # 48 | # Note: These macros also depend on AX_PREPEND_FLAG. 49 | # 50 | # LICENSE 51 | # 52 | # Copyright (c) 2008 Guido U. Draheim 53 | # Copyright (c) 2010 Rhys Ulerich 54 | # Copyright (c) 2018 John Zaitseff 55 | # 56 | # This program is free software; you can redistribute it and/or modify it 57 | # under the terms of the GNU General Public License as published by the 58 | # Free Software Foundation; either version 3 of the License, or (at your 59 | # option) any later version. 60 | # 61 | # This program is distributed in the hope that it will be useful, but 62 | # WITHOUT ANY WARRANTY; without even the implied warranty of 63 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 64 | # Public License for more details. 65 | # 66 | # You should have received a copy of the GNU General Public License along 67 | # with this program. If not, see . 68 | # 69 | # As a special exception, the respective Autoconf Macro's copyright owner 70 | # gives unlimited permission to copy, distribute and modify the configure 71 | # scripts that are the output of Autoconf when processing the Macro. You 72 | # need not follow the terms of the GNU General Public License when using 73 | # or distributing such scripts, even though portions of the text of the 74 | # Macro appear in them. The GNU General Public License (GPL) does govern 75 | # all other use of the material that constitutes the Autoconf Macro. 76 | # 77 | # This special exception to the GPL applies to versions of the Autoconf 78 | # Macro released by the Autoconf Archive. When you make and distribute a 79 | # modified version of the Autoconf Macro, you may extend this special 80 | # exception to the GPL to apply to your modified version as well. 81 | 82 | #serial 25 83 | 84 | AC_DEFUN([AX_FLAGS_WARN_ALL], [ 85 | AX_REQUIRE_DEFINED([AX_PREPEND_FLAG])dnl 86 | AC_REQUIRE([AX_COMPILER_VENDOR])dnl 87 | 88 | AS_VAR_PUSHDEF([FLAGS], [m4_default($1,_AC_LANG_PREFIX[]FLAGS)])dnl 89 | AS_VAR_PUSHDEF([VAR], [ac_cv_[]_AC_LANG_ABBREV[]flags_warn_all])dnl 90 | AS_VAR_PUSHDEF([FOUND], [ac_save_[]_AC_LANG_ABBREV[]flags_warn_all_found])dnl 91 | 92 | AC_CACHE_CHECK([FLAGS for most reasonable warnings], VAR, [ 93 | VAR="" 94 | FOUND="yes" 95 | dnl Cases are listed in the order found in ax_compiler_vendor.m4 96 | AS_CASE("$ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor", 97 | [intel], [VAR="-w2"], 98 | [ibm], [VAR="-qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd"], 99 | [pathscale], [], 100 | [clang], [VAR="-Wall"], 101 | [cray], [VAR="-h msglevel 2"], 102 | [fujitsu], [], 103 | [sdcc], [], 104 | [sx], [VAR="-pvctl[,]fullmsg"], 105 | [portland], [], 106 | [gnu], [VAR="-Wall"], 107 | [sun], [VAR="-v"], 108 | [hp], [VAR="+w1"], 109 | [dec], [VAR="-verbose -w0 -warnprotos"], 110 | [borland], [], 111 | [comeau], [], 112 | [kai], [], 113 | [lcc], [], 114 | [sgi], [VAR="-fullwarn"], 115 | [microsoft], [], 116 | [metrowerks], [], 117 | [watcom], [], 118 | [tcc], [], 119 | [unknown], [ 120 | VAR="$2" 121 | FOUND="no" 122 | ], 123 | [ 124 | AC_MSG_WARN([Unknown compiler vendor returned by [AX_COMPILER_VENDOR]]) 125 | VAR="$2" 126 | FOUND="no" 127 | ] 128 | ) 129 | 130 | AS_IF([test "x$FOUND" = "xyes"], [dnl 131 | m4_default($3, [AS_IF([test "x$VAR" != "x"], [AX_PREPEND_FLAG([$VAR], [FLAGS])])]) 132 | ], [dnl 133 | m4_default($4, [m4_ifval($2, [AX_PREPEND_FLAG([$VAR], [FLAGS])], [true])]) 134 | ])dnl 135 | ])dnl 136 | 137 | AS_VAR_POPDEF([FOUND])dnl 138 | AS_VAR_POPDEF([VAR])dnl 139 | AS_VAR_POPDEF([FLAGS])dnl 140 | ])dnl AX_FLAGS_WARN_ALL 141 | 142 | AC_DEFUN([AX_CFLAGS_WARN_ALL], [dnl 143 | AC_LANG_PUSH([C]) 144 | AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4]) 145 | AC_LANG_POP([C]) 146 | ])dnl 147 | 148 | AC_DEFUN([AX_CXXFLAGS_WARN_ALL], [dnl 149 | AC_LANG_PUSH([C++]) 150 | AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4]) 151 | AC_LANG_POP([C++]) 152 | ])dnl 153 | 154 | AC_DEFUN([AX_FCFLAGS_WARN_ALL], [dnl 155 | AC_LANG_PUSH([Fortran]) 156 | AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4]) 157 | AC_LANG_POP([Fortran]) 158 | ])dnl 159 | -------------------------------------------------------------------------------- /src/packet.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, OARC, Inc. 3 | * Copyright (c) 2019, DENIC eG 4 | * All rights reserved. 5 | * 6 | * This file is part of dnsmeter. 7 | * 8 | * dnsmeter is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * dnsmeter is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with dnsmeter. If not, see . 20 | */ 21 | 22 | #include "config.h" 23 | 24 | #include "packet.h" 25 | #include "exceptions.h" 26 | #include "query.h" 27 | 28 | #define __FAVOR_BSD 1 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #define USZ sizeof(struct udphdr) 36 | #define ISZ sizeof(struct ip) 37 | #define HDRSZ ISZ + USZ 38 | #define MAXPACKETSIZE 4096 39 | 40 | static unsigned short in_cksum(unsigned short* addr, int len) 41 | { 42 | int nleft = len; 43 | unsigned short* w = addr; 44 | int sum = 0; 45 | unsigned short answer = 0; 46 | while (nleft > 1) { 47 | sum += *w++; 48 | nleft -= 2; 49 | } 50 | if (nleft == 1) { 51 | *(unsigned char*)(&answer) = *(unsigned char*)w; 52 | sum += answer; 53 | } 54 | sum = (sum >> 16) + (sum & 0xffff); 55 | sum += (sum >> 16); 56 | answer = ~sum; 57 | return (answer); 58 | } 59 | 60 | static unsigned short udp_cksum(const struct ip* iphdr, const struct udphdr* udp, const unsigned char* payload, size_t payload_size) 61 | { 62 | unsigned char cbuf[MAXPACKETSIZE]; 63 | memset(cbuf, 0, sizeof(cbuf)); 64 | unsigned char* p = (unsigned char*)cbuf; 65 | *(unsigned int*)p = iphdr->ip_src.s_addr; 66 | p += sizeof(unsigned int); 67 | *(unsigned int*)p = iphdr->ip_dst.s_addr; 68 | p += sizeof(unsigned int); 69 | *(unsigned char*)p++ = 0; 70 | *(unsigned char*)p++ = iphdr->ip_p; 71 | *(unsigned short*)p = udp->uh_ulen; 72 | p += sizeof(unsigned short); 73 | memcpy(p, udp, USZ); 74 | p += USZ; 75 | memcpy(p, payload, payload_size); 76 | return in_cksum((unsigned short*)cbuf, sizeof(uint) * 3 + sizeof(struct udphdr) + payload_size + (payload_size % 2)); 77 | } 78 | 79 | Packet::Packet() 80 | { 81 | buffersize = MAXPACKETSIZE; 82 | payload_size = 0; 83 | buffer = (unsigned char*)calloc(1, buffersize); 84 | if (!buffer) 85 | throw ppl7::OutOfMemoryException(); 86 | 87 | struct ip* iphdr = (struct ip*)buffer; 88 | struct udphdr* udp = (struct udphdr*)(buffer + ISZ); 89 | 90 | iphdr->ip_hl = ISZ >> 2; 91 | iphdr->ip_v = IPVERSION; 92 | iphdr->ip_tos = 0; 93 | iphdr->ip_off = 0; 94 | iphdr->ip_ttl = 64; 95 | iphdr->ip_p = IPPROTO_UDP; 96 | iphdr->ip_sum = 0; 97 | iphdr->ip_id = 0; 98 | iphdr->ip_src.s_addr = 0; 99 | iphdr->ip_dst.s_addr = 0; 100 | iphdr->ip_len = htons(HDRSZ + payload_size); 101 | iphdr->ip_sum = in_cksum((unsigned short*)iphdr, ISZ); 102 | 103 | udp->uh_ulen = htons(USZ + payload_size); 104 | chksum_valid = false; 105 | } 106 | 107 | Packet::~Packet() 108 | { 109 | free(buffer); 110 | } 111 | 112 | void Packet::setSource(const ppl7::IPAddress& ip_addr, int port) 113 | { 114 | struct ip* iphdr = (struct ip*)buffer; 115 | struct udphdr* udp = (struct udphdr*)(buffer + ISZ); 116 | iphdr->ip_src.s_addr = *(in_addr_t*)ip_addr.addr(); 117 | udp->uh_sport = htons(port); 118 | chksum_valid = false; 119 | } 120 | 121 | void Packet::randomSourcePort() 122 | { 123 | struct udphdr* udp = (struct udphdr*)(buffer + ISZ); 124 | udp->uh_sport = htons(ppl7::rand(1024, 65535)); 125 | chksum_valid = false; 126 | } 127 | 128 | void Packet::randomSourceIP(const ppl7::IPNetwork& net) 129 | { 130 | struct ip* iphdr = (struct ip*)buffer; 131 | in_addr_t start = ntohl(*(in_addr_t*)net.first().addr()); 132 | size_t size = powl(2, 32 - net.prefixlen()); 133 | iphdr->ip_src.s_addr = htonl(ppl7::rand(start, start + size - 1)); 134 | chksum_valid = false; 135 | } 136 | 137 | void Packet::randomSourceIP(unsigned int start, unsigned int size) 138 | { 139 | struct ip* iphdr = (struct ip*)buffer; 140 | iphdr->ip_src.s_addr = htonl(ppl7::rand(start, start + size - 1)); 141 | chksum_valid = false; 142 | } 143 | 144 | void Packet::useSourceFromPcap(const char* pkt, size_t size) 145 | { 146 | const struct ip* s_iphdr = (const struct ip*)(pkt + 14); 147 | const struct udphdr* s_udp = (const struct udphdr*)(pkt + 14 + sizeof(struct ip)); 148 | struct ip* iphdr = (struct ip*)buffer; 149 | struct udphdr* udp = (struct udphdr*)(buffer + ISZ); 150 | iphdr->ip_src.s_addr = s_iphdr->ip_src.s_addr; 151 | udp->uh_sport = s_udp->uh_sport; 152 | } 153 | 154 | void Packet::setDestination(const ppl7::IPAddress& ip_addr, int port) 155 | { 156 | struct ip* iphdr = (struct ip*)buffer; 157 | struct udphdr* udp = (struct udphdr*)(buffer + ISZ); 158 | iphdr->ip_dst.s_addr = *(in_addr_t*)ip_addr.addr(); 159 | udp->uh_dport = htons(port); 160 | chksum_valid = false; 161 | } 162 | 163 | void Packet::setIpId(unsigned short id) 164 | { 165 | struct ip* iphdr = (struct ip*)buffer; 166 | iphdr->ip_id = htons(id); 167 | chksum_valid = false; 168 | } 169 | 170 | void Packet::setDnsId(unsigned short id) 171 | { 172 | *((unsigned short*)(buffer + HDRSZ)) = htons(id); 173 | chksum_valid = false; 174 | } 175 | 176 | void Packet::setPayload(const void* payload, size_t size) 177 | { 178 | if (size + HDRSZ > MAXPACKETSIZE) 179 | throw BufferOverflow("%zd > %zd", size, MAXPACKETSIZE - HDRSZ); 180 | memcpy(buffer + HDRSZ, payload, size); 181 | payload_size = size; 182 | struct ip* iphdr = (struct ip*)buffer; 183 | struct udphdr* udp = (struct udphdr*)(buffer + ISZ); 184 | iphdr->ip_len = htons(HDRSZ + payload_size); 185 | udp->uh_ulen = htons(USZ + payload_size); 186 | chksum_valid = false; 187 | } 188 | 189 | void Packet::setPayloadDNSQuery(const ppl7::String& query, bool dnssec) 190 | { 191 | payload_size = MakeQuery(query, buffer + HDRSZ, buffersize - HDRSZ, dnssec); 192 | struct ip* iphdr = (struct ip*)buffer; 193 | struct udphdr* udp = (struct udphdr*)(buffer + ISZ); 194 | iphdr->ip_len = htons(HDRSZ + payload_size); 195 | udp->uh_ulen = htons(USZ + payload_size); 196 | chksum_valid = false; 197 | } 198 | 199 | void Packet::updateChecksums() 200 | { 201 | struct ip* iphdr = (struct ip*)buffer; 202 | struct udphdr* udp = (struct udphdr*)(buffer + ISZ); 203 | iphdr->ip_sum = 0; 204 | iphdr->ip_sum = in_cksum((unsigned short*)iphdr, ISZ); 205 | udp->uh_sum = 0; 206 | udp->uh_sum = udp_cksum(iphdr, udp, buffer + HDRSZ, payload_size); 207 | chksum_valid = true; 208 | } 209 | 210 | size_t Packet::size() const 211 | { 212 | return HDRSZ + payload_size; 213 | } 214 | 215 | unsigned char* Packet::ptr() 216 | { 217 | if (!chksum_valid) 218 | updateChecksums(); 219 | return buffer; 220 | } 221 | -------------------------------------------------------------------------------- /src/dnsmeter.1.in: -------------------------------------------------------------------------------- 1 | .\" Copyright (c) 2019-2021, OARC, Inc. 2 | .\" Copyright (c) 2019, DENIC eG 3 | .\" All rights reserved. 4 | .\" 5 | .\" This file is part of dnsmeter. 6 | .\" 7 | .\" dnsmeter is free software: you can redistribute it and/or modify 8 | .\" it under the terms of the GNU General Public License as published by 9 | .\" the Free Software Foundation, either version 3 of the License, or 10 | .\" (at your option) any later version. 11 | .\" 12 | .\" dnsmeter is distributed in the hope that it will be useful, 13 | .\" but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | .\" GNU General Public License for more details. 16 | .\" 17 | .\" You should have received a copy of the GNU General Public License 18 | .\" along with dnsmeter. If not, see . 19 | .TH dnsmeter 1 "@PACKAGE_VERSION@" "dnsmeter" 20 | .SH NAME 21 | dnsmeter \- DNS performance and infrastructure testing 22 | .SH SYNOPSIS 23 | .hy 0 24 | .ad l 25 | \fBdnsmeter\fR\ [\fB\-h\fR] 26 | [\fB\-q\ \fIHOST\fR] 27 | [\fB\-s\ \fINET|pcap\fR] 28 | [\fB\-e\ \fIETH\fR] 29 | [\fB\-z\ \fIHOST:PORT\fR] 30 | [\fB\-p\ \fIFILE\fR] 31 | [\fB\-l\ \fI#\fR] 32 | [\fB\-t\ \fI#\fR] 33 | [\fB\-n\ \fI#\fR] 34 | [\fB\-r\ \fI#\fR] 35 | [\fB\-d\ \fI#\fR] 36 | [\fB\-c\ \fIFILE\fR] 37 | [\fB\--ignore\fR] 38 | .ad 39 | .hy 40 | .SH DESCRIPTION 41 | DNSMeter is a tool for testing performance of nameserver and/or 42 | infrastructure around it. 43 | It generates dns queries and sends them via UDP to a target nameserver 44 | and counts the answers. 45 | 46 | Features: 47 | .br 48 | - payload can be given as text file or PCAP file 49 | .br 50 | - can automatically run different load steps, which can be given as 51 | list or ranges 52 | .br 53 | - results per load step can be stored in CSV file 54 | .br 55 | - sender address can be spoofed from a given network or from PCAP file, 56 | if payload is a PCAP file 57 | .br 58 | - answers are counted, even if source address is spoofed, if answers get 59 | routed back to the load generator 60 | .br 61 | - roundtrip-times are measured (average, min, mix) 62 | .br 63 | - amount of DNSSEC queries can be given as percentage of total traffic 64 | .br 65 | - optimized for high amount of packets. On an Intel(R) Xeon(R) CPU E5-2430 66 | v2 @ 2.50GHz it can generate more than 900.000 packets per second 67 | .SH OPTIONS 68 | .TP 69 | .B -h 70 | Show option help. 71 | .TP 72 | .BI -q \ HOST 73 | Hostname or IP address of sender if you don't want to spoof (see 74 | .IR -s ). 75 | .TP 76 | .BI -s \ NET|pcap 77 | Spoof sender address. 78 | Use random IP from the given network (example: 79 | .IR 192.168.0.0/16 ). 80 | Only works when running as root! 81 | If payload is a PCAP file, you can use 82 | .BI -s pcap 83 | to use the source addresses and ports from the PCAP file. 84 | .TP 85 | .BI -e \ ETH 86 | Interface on which the packet receiver should listen (FreeBSD only). 87 | .TP 88 | .BI -z \ HOST:PORT 89 | Hostname or IP address and port of the target nameserver. 90 | .TP 91 | .BI -p \ FILE 92 | File with queries/payload or PCAP file. 93 | .TP 94 | .BI -l \ # 95 | Runtime in seconds (default=10 seconds). 96 | .TP 97 | .BI -t \ # 98 | Timeout in seconds (default=2 seconds). 99 | .TP 100 | .BI -n \ # 101 | Number of worker threads (default=1). 102 | .TP 103 | .BI -r \ # 104 | Query rate (Default=as much as possible) can be a single value, a comma 105 | separated list (rate,rate,...) or a range and a step value (start - end, 106 | step). 107 | .TP 108 | .BI -d \ # 109 | Amount of queries in percent on which the DNSSEC-flags are set (default=0). 110 | .TP 111 | .BI -c \ FILE 112 | CSV-file for results. 113 | .TP 114 | .B --ignore 115 | Answers are ignored and therefor not counted. 116 | In this mode the tool only generates traffic. 117 | .SH USAGE 118 | This section contains additional usage information not covered by 119 | the options documentation. 120 | 121 | .BI -q \ HOST 122 | | 123 | .BI -s \ NETWORK 124 | | 125 | .BI -s \ pcap 126 | 127 | Source IP, hostname or network from which the packets should be send. 128 | If you dont't want to spoof, use 129 | .I -q 130 | with a single IP address or hostname. 131 | Use 132 | .I -s 133 | followed by a network, if you want to spoof the source address. 134 | .B dnsmeter 135 | will generated random IP addresses inside this network. 136 | Example: 137 | .B -s 138 | .IR 10.0.0.0/8 . 139 | 140 | If payload is a PCAP file, you can use the source addresses and ports 141 | from the PCAP file, if you use 142 | .B -s 143 | .IR pcap . 144 | 145 | .BI -e \ ETH 146 | 147 | Ignored on Linux, but on FreeBSD you have to enter the name of the 148 | network interface on which the tool should listen for the answers. 149 | 150 | .BI -p \ FILE 151 | 152 | File with payload in text format or PCAP file. 153 | When using a text format each line must contain one query with name 154 | and record type. 155 | 156 | Example: 157 | 158 | www.denic.de A 159 | denic.de NS 160 | ... 161 | 162 | .IR NOTE : 163 | the file should not be too big, because it is completely 164 | loaded into memory and pre-compiled to DNS query packets. 165 | 166 | .BI -n \ # 167 | 168 | Number of worker threads, recommendation: 169 | .br 170 | - less than 200000 packets per second: 1 Thread 171 | .br 172 | - 200000 - 500000 packets per second: 2 Threads 173 | .br 174 | - more than 500000 packets per second: 4 Threads 175 | 176 | .BI NOTE : 177 | this is CPU dependent! 178 | If you have a fast CPU, you may need lesser threads, on a slow CPU you 179 | may need more threads. 180 | Don't use more threads than cores available on your CPU, minus one! 181 | 182 | .BI -r \ #[,#,#] 183 | 184 | Query rate or load steps. 185 | Can be a single value if you want to test a specific query rate, a comma 186 | separated list or a range with step with. 187 | 188 | Examples: 189 | .br 190 | - Single value: -r 100000 191 | .br 192 | - a list of query rates: -r 10000,20000,30000,40000,50000,60000 193 | .br 194 | - a range with step: -r 10000-200000,10000 195 | 196 | .BI -d \ # 197 | 198 | Amount of DNSSEC queries in percentage between 0 and 100. 199 | Is ignored, if using PCAP file as payload. 200 | 201 | .BI -c \ FILENAME 202 | 203 | Filename for results in CSV format. 204 | 205 | .BI NOTE : 206 | if file exists, results are appended! 207 | 208 | .SH EXAMPLE 209 | 210 | Lets assume the following scenario: 211 | .br 212 | - load generator runs on FreeBSD 213 | .br 214 | - network interface an which the traffic goes out and comes back is "igb0" 215 | .br 216 | - source ip on the load generator is 192.168.155.20 217 | .br 218 | - target nameserver has ip 192.168.0.1, port 53 219 | .br 220 | - we want to spoof the sender address from the network 10.0.0.0/8 221 | .br 222 | - the payload file is found here: /home/testdata/payload.txt 223 | .br 224 | - the nameserver is running on CentOS and we need to set a route back to the load generator: 225 | .br 226 | ip route add 10.0.0.0/8 via 192.168.155.20 227 | .br 228 | - we want to test the following load steps: 30000,40000,45000,50000,100000,150000 229 | .br 230 | - results should be written to results.csv 231 | .br 232 | - DNSSEC rate should be 70% 233 | 234 | This makes the following command: 235 | 236 | dnsmeter -p /home/testdata/payload.txt \\ 237 | -r 30000,40000,45000,50000,100000,150000 \\ 238 | -s 10.0.0.0/8 \\ 239 | -z 192.168.0.1:53 \\ 240 | -e igb0 \\ 241 | -d 70 \\ 242 | -c results.csv 243 | 244 | In the second example, we want to use a PCAP file as payload and want 245 | to spoof with the addresses from that file: 246 | 247 | dnsmeter -p /home/testdata/pcap.file1 \\ 248 | -r 30000,40000,45000,50000,100000,150000 \\ 249 | -s pcap \\ 250 | -z 192.168.0.1:53 \\ 251 | -e igb0 \\ 252 | -c results_pcap.csv 253 | 254 | .SH AUTHOR 255 | Patrick Fedick 256 | .RI ( https://github.com/pfedick ) 257 | .LP 258 | Maintained by DNS-OARC 259 | .LP 260 | .RS 261 | .I https://www.dns-oarc.net/ 262 | .RE 263 | .LP 264 | .SH BUGS 265 | For issues and feature requests please use: 266 | .LP 267 | .RS 268 | \fI@PACKAGE_URL@\fP 269 | .RE 270 | .LP 271 | For question and help please use: 272 | .LP 273 | .RS 274 | \fI@PACKAGE_BUGREPORT@\fP 275 | .RE 276 | .LP 277 | -------------------------------------------------------------------------------- /src/dns_sender_thread.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, OARC, Inc. 3 | * Copyright (c) 2019, DENIC eG 4 | * All rights reserved. 5 | * 6 | * This file is part of dnsmeter. 7 | * 8 | * dnsmeter is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * dnsmeter is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with dnsmeter. If not, see . 20 | */ 21 | 22 | #include "config.h" 23 | 24 | #include "dns_sender_thread.h" 25 | #include "query.h" 26 | #include "exceptions.h" 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | DNSSenderThread::DNSSenderThread() 37 | { 38 | buffer = (unsigned char*)malloc(4096); 39 | if (!buffer) 40 | throw ppl7::OutOfMemoryException(); 41 | Timeslice = 0.0f; 42 | runtime = 10; 43 | timeout = 5; 44 | queryrate = 0; 45 | counter_packets_send = 0; 46 | counter_bytes_send = 0; 47 | errors = 0; 48 | counter_0bytes = 0; 49 | duration = 0.0; 50 | for (int i = 0; i < 255; i++) 51 | counter_errorcodes[i] = 0; 52 | verbose = false; 53 | spoofingEnabled = false; 54 | DnssecRate = 0; 55 | dnsseccounter = 0; 56 | payload = NULL; 57 | spoofing_net_start = 0; 58 | spoofing_net_size = 0; 59 | payloadIsPcap = false; 60 | spoofingFromPcap = false; 61 | } 62 | 63 | DNSSenderThread::~DNSSenderThread() 64 | { 65 | free(buffer); 66 | } 67 | 68 | void DNSSenderThread::setDestination(const ppl7::IPAddress& ip, int port) 69 | { 70 | Socket.setDestination(ip, port); 71 | pkt.setDestination(ip, port); 72 | } 73 | 74 | void DNSSenderThread::setPayload(PayloadFile& payload) 75 | { 76 | this->payload = &payload; 77 | this->payloadIsPcap = payload.isPcap(); 78 | } 79 | 80 | void DNSSenderThread::setRuntime(int seconds) 81 | { 82 | runtime = seconds; 83 | } 84 | 85 | void DNSSenderThread::setTimeout(int seconds) 86 | { 87 | timeout = seconds; 88 | } 89 | 90 | void DNSSenderThread::setDNSSECRate(int rate) 91 | { 92 | DnssecRate = rate; 93 | } 94 | 95 | void DNSSenderThread::setQueryRate(ppluint64 qps) 96 | { 97 | queryrate = qps; 98 | } 99 | 100 | void DNSSenderThread::setTimeslice(float ms) 101 | { 102 | if (ms == 0.0f || ms > 1000.0f) 103 | throw ppl7::InvalidArgumentsException(); 104 | //if ((1000 % ms)!=0) throw ppl7::InvalidArgumentsException(); 105 | Timeslice = (double)ms / 1000; 106 | } 107 | 108 | void DNSSenderThread::setSourceIP(const ppl7::IPAddress& ip) 109 | { 110 | sourceip = ip; 111 | spoofingEnabled = false; 112 | } 113 | 114 | void DNSSenderThread::setSourceNet(const ppl7::IPNetwork& net) 115 | { 116 | sourcenet = net; 117 | spoofingEnabled = true; 118 | spoofing_net_start = ntohl(*(in_addr_t*)net.first().addr()); 119 | spoofing_net_size = powl(2, 32 - net.prefixlen()); 120 | } 121 | 122 | void DNSSenderThread::setSourcePcap() 123 | { 124 | spoofingEnabled = true; 125 | spoofingFromPcap = true; 126 | } 127 | 128 | void DNSSenderThread::setVerbose(bool verbose) 129 | { 130 | this->verbose = verbose; 131 | } 132 | 133 | #define PCAP_HEADER_SIZE 14 + sizeof(struct ip) + sizeof(struct udphdr) 134 | 135 | void DNSSenderThread::sendPacket() 136 | { 137 | size_t query_size; 138 | while (1) { 139 | try { 140 | const ppl7::ByteArrayPtr& bap = payload->getQuery(); 141 | query_size = bap.size(); 142 | if (payloadIsPcap) { 143 | query_size -= PCAP_HEADER_SIZE; 144 | memcpy(buffer, ((const char*)bap.ptr()) + PCAP_HEADER_SIZE, query_size); 145 | } else { 146 | memcpy(buffer, bap.ptr(), query_size); 147 | dnsseccounter += DnssecRate; 148 | if (dnsseccounter >= 100) { 149 | query_size = AddDnssecToQuery(buffer, 4096, query_size); 150 | dnsseccounter -= 100; 151 | } 152 | } 153 | pkt.setPayload(buffer, query_size); 154 | if (spoofingEnabled) { 155 | if (spoofingFromPcap) { 156 | pkt.useSourceFromPcap((const char*)bap.ptr(), bap.size()); 157 | } else { 158 | pkt.randomSourceIP(spoofing_net_start, spoofing_net_size); 159 | pkt.randomSourcePort(); 160 | } 161 | } else { 162 | pkt.randomSourcePort(); 163 | } 164 | pkt.setDnsId(getQueryTimestamp()); 165 | ssize_t n = Socket.send(pkt); 166 | if (n > 0 && (size_t)n == pkt.size()) { 167 | counter_packets_send++; 168 | counter_bytes_send += pkt.size(); 169 | } else if (n < 0) { 170 | if (errno < 255) 171 | counter_errorcodes[errno]++; 172 | errors++; 173 | } else { 174 | counter_0bytes++; 175 | } 176 | return; 177 | } catch (const UnknownRRType& exp) { 178 | continue; 179 | } catch (const InvalidDNSQuery& exp) { 180 | continue; 181 | } 182 | } 183 | } 184 | 185 | void DNSSenderThread::run() 186 | { 187 | if (!payload) 188 | throw ppl7::NullPointerException("payload not set!"); 189 | if (!spoofingEnabled) { 190 | pkt.setSource(sourceip, 0x4567); 191 | } 192 | dnsseccounter = 0; 193 | counter_packets_send = 0; 194 | counter_bytes_send = 0; 195 | counter_0bytes = 0; 196 | errors = 0; 197 | duration = 0.0; 198 | for (int i = 0; i < 255; i++) 199 | counter_errorcodes[i] = 0; 200 | double start = ppl7::GetMicrotime(); 201 | if (queryrate > 0) { 202 | runWithRateLimit(); 203 | } else { 204 | runWithoutRateLimit(); 205 | } 206 | duration = ppl7::GetMicrotime() - start; 207 | waitForTimeout(); 208 | } 209 | 210 | void DNSSenderThread::runWithoutRateLimit() 211 | { 212 | double start = ppl7::GetMicrotime(); 213 | double end = start + (double)runtime; 214 | double now; 215 | int pc = 0; 216 | while (1) { 217 | sendPacket(); 218 | pc++; 219 | if (pc > 10000) { 220 | pc = 0; 221 | if (this->threadShouldStop()) 222 | break; 223 | now = ppl7::GetMicrotime(); 224 | if (now > end) 225 | break; 226 | } 227 | } 228 | } 229 | 230 | static inline double getNsec() 231 | { 232 | struct timespec ts; 233 | clock_gettime(CLOCK_REALTIME, &ts); 234 | return (double)ts.tv_sec + ((double)ts.tv_nsec / 1000000000.0); 235 | } 236 | 237 | void DNSSenderThread::runWithRateLimit() 238 | { 239 | struct timespec ts; 240 | ppluint64 total_timeslices = runtime * 1000 / (Timeslice * 1000.0); 241 | ppluint64 queries_rest = runtime * queryrate; 242 | ppl7::SockAddr addr = Socket.getSockAddr(); 243 | verbose = true; 244 | if (verbose) { 245 | //printf ("qps=%d, runtime=%d\n",queryrate, runtime); 246 | printf("runtime: %d s, timeslice: %0.6f s, total timeslices: %llu, Qpts: %llu, Source: %s:%d\n", 247 | runtime, Timeslice, total_timeslices, 248 | queries_rest / total_timeslices, 249 | (const char*)addr.toIPAddress().toString(), addr.port()); 250 | } 251 | double now = getNsec(); 252 | double next_timeslice = now; 253 | double next_checktime = now + 0.1; 254 | 255 | double start = ppl7::GetMicrotime(); 256 | double end = start + (double)runtime; 257 | double total_idle = 0.0; 258 | 259 | for (ppluint64 z = 0; z < total_timeslices; z++) { 260 | next_timeslice += Timeslice; 261 | ppluint64 timeslices_rest = total_timeslices - z; 262 | ppluint64 queries_per_timeslice = queries_rest / timeslices_rest; 263 | if (timeslices_rest == 1) 264 | queries_per_timeslice = queries_rest; 265 | for (ppluint64 i = 0; i < queries_per_timeslice; i++) { 266 | sendPacket(); 267 | } 268 | 269 | queries_rest -= queries_per_timeslice; 270 | while ((now = getNsec()) < next_timeslice) { 271 | if (now < next_timeslice) { 272 | total_idle += next_timeslice - now; 273 | ts.tv_sec = 0; 274 | ts.tv_nsec = (next_timeslice - now) * 1000000000; 275 | nanosleep(&ts, NULL); 276 | } 277 | } 278 | if (now > next_checktime) { 279 | next_checktime = now + 0.1; 280 | if (this->threadShouldStop()) 281 | break; 282 | if (ppl7::GetMicrotime() >= end) 283 | break; 284 | //printf ("Zeitscheiben rest: %llu\n", z); 285 | } 286 | } 287 | if (verbose) { 288 | //printf ("total idle: %0.6f\n",total_idle); 289 | } 290 | } 291 | 292 | void DNSSenderThread::waitForTimeout() 293 | { 294 | double start = ppl7::GetMicrotime(); 295 | double end = start + (double)timeout; 296 | double now, next_checktime = start + 0.1; 297 | while ((now = ppl7::GetMicrotime()) < end) { 298 | if (now > next_checktime) { 299 | next_checktime = now + 0.1; 300 | if (this->threadShouldStop()) 301 | break; 302 | } 303 | ppl7::MSleep(10); 304 | } 305 | } 306 | 307 | ppluint64 DNSSenderThread::getPacketsSend() const 308 | { 309 | return counter_packets_send; 310 | } 311 | 312 | ppluint64 DNSSenderThread::getBytesSend() const 313 | { 314 | return counter_bytes_send; 315 | } 316 | 317 | ppluint64 DNSSenderThread::getErrors() const 318 | { 319 | return errors; 320 | } 321 | 322 | ppluint64 DNSSenderThread::getCounter0Bytes() const 323 | { 324 | return counter_0bytes; 325 | } 326 | 327 | ppluint64 DNSSenderThread::getCounterErrorCode(int err) const 328 | { 329 | if (err < 255) 330 | return counter_errorcodes[err]; 331 | return 0; 332 | } 333 | -------------------------------------------------------------------------------- /src/raw_socket_receiver.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, OARC, Inc. 3 | * Copyright (c) 2019, DENIC eG 4 | * All rights reserved. 5 | * 6 | * This file is part of dnsmeter. 7 | * 8 | * dnsmeter is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * dnsmeter is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with dnsmeter. If not, see . 20 | */ 21 | 22 | #include "config.h" 23 | 24 | #include "raw_socket_receiver.h" 25 | #include "query.h" 26 | #include "exceptions.h" 27 | 28 | #define __FAVOR_BSD 1 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #ifdef __OpenBSD__ 39 | #error "Raw socket receiver not implemented for OpenBSD" 40 | #endif 41 | #ifdef __FreeBSD__ 42 | #define DNSMETER_USE_BPF 1 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #endif 50 | 51 | #pragma pack(push) /* push current alignment to stack */ 52 | #pragma pack(1) /* set alignment to 1 byte boundary */ 53 | struct ETHER { 54 | unsigned char destination[6]; 55 | unsigned char source[6]; 56 | unsigned short type; 57 | }; 58 | #pragma pack(pop) /* restore original alignment from stack */ 59 | 60 | #ifdef DNSMETER_USE_BPF 61 | static int open_bpf() 62 | { 63 | int sd; 64 | for (int i = 0; i < 255; i++) { 65 | ppl7::String Device; 66 | Device.setf("/dev/bpf%d", i); 67 | sd = open((const char*)Device, O_RDWR); 68 | if (sd >= 0) { 69 | return sd; 70 | } 71 | } 72 | ppl7::throwExceptionFromErrno(errno, "Could not create RawReceiverSocket"); 73 | return -1; 74 | } 75 | 76 | bool tryAllocZeroCopyBuffer(int sd, struct bpf_zbuf* zbuf, size_t size) 77 | { 78 | zbuf->bz_buflen = size; 79 | zbuf->bz_bufa = malloc(zbuf->bz_buflen); 80 | if (!zbuf->bz_bufa) { 81 | throw ppl7::OutOfMemoryException(); 82 | } 83 | zbuf->bz_bufb = malloc(zbuf->bz_buflen); 84 | if (!zbuf->bz_bufb) { 85 | free(zbuf->bz_bufa); 86 | throw ppl7::OutOfMemoryException(); 87 | } 88 | memset(zbuf->bz_bufa, 0, zbuf->bz_buflen); 89 | memset(zbuf->bz_bufb, 0, zbuf->bz_buflen); 90 | 91 | if (ioctl(sd, BIOCSETZBUF, zbuf) < 0) { 92 | free(zbuf->bz_bufa); 93 | free(zbuf->bz_bufb); 94 | return false; 95 | } 96 | return true; 97 | } 98 | 99 | void initZeroCopyBuffer(int sd, struct bpf_zbuf* zbuf) 100 | { 101 | unsigned int bufmode = BPF_BUFMODE_ZBUF; 102 | if (ioctl(sd, BIOCSETBUFMODE, &bufmode) < 0) { 103 | ppl7::throwExceptionFromErrno(errno, "BIOCSETBUFMODE with BPF_BUFMODE_ZBUF failed"); 104 | } 105 | unsigned int tstype = BPF_T_MICROTIME; 106 | if (ioctl(sd, BIOCSTSTAMP, &tstype) < 0) { 107 | ppl7::throwExceptionFromErrno(errno, "BIOCSTSTAMP"); 108 | } 109 | if (tryAllocZeroCopyBuffer(sd, zbuf, 8192)) 110 | return; 111 | if (tryAllocZeroCopyBuffer(sd, zbuf, 4096)) 112 | return; 113 | throw FailedToInitializePacketfilter("Could not configure ZeroCopy-Buffer (BIOCSETZBUF)"); 114 | } 115 | 116 | void initBufferedMode(int sd, unsigned int buflen) 117 | { 118 | unsigned int bufmode = BPF_BUFMODE_BUFFER; 119 | if (ioctl(sd, BIOCSETBUFMODE, &bufmode) < 0) { 120 | ppl7::throwExceptionFromErrno(errno, "BIOCSETBUFMODE with BPF_BUFMODE_BUFFER failed"); 121 | } 122 | if (ioctl(sd, BIOCSBLEN, &buflen) < 0) { 123 | ppl7::throwExceptionFromErrno(errno, "BIOCSBLEN failed"); 124 | } 125 | } 126 | 127 | #endif 128 | 129 | RawSocketReceiver::Counter::Counter() 130 | { 131 | num_pkgs = 0; 132 | bytes_rcv = 0; 133 | truncated = 0; 134 | for (int i = 0; i < 15; i++) 135 | rcodes[i] = 0; 136 | rtt_total = 0.0f; 137 | rtt_min = 0.0f; 138 | rtt_max = 0.0f; 139 | } 140 | 141 | void RawSocketReceiver::Counter::clear() 142 | { 143 | num_pkgs = 0; 144 | bytes_rcv = 0; 145 | truncated = 0; 146 | for (int i = 0; i < 15; i++) 147 | rcodes[i] = 0; 148 | rtt_total = 0.0f; 149 | rtt_min = 0.0f; 150 | rtt_max = 0.0f; 151 | } 152 | 153 | RawSocketReceiver::RawSocketReceiver() 154 | { 155 | SourceIP.set("0.0.0.0"); 156 | SourcePort = 0; 157 | buflen = 4096; 158 | sd = -1; 159 | buffer = NULL; 160 | #ifdef DNSMETER_USE_BPF 161 | useZeroCopyBuffer = false; 162 | sd = open_bpf(); 163 | buffer = (unsigned char*)malloc(sizeof(struct bpf_zbuf)); 164 | if (!buffer) { 165 | close(sd); 166 | throw ppl7::OutOfMemoryException(); 167 | } 168 | struct bpf_zbuf* zbuf = (struct bpf_zbuf*)buffer; 169 | 170 | try { 171 | initZeroCopyBuffer(sd, zbuf); 172 | useZeroCopyBuffer = true; 173 | buflen = zbuf->bz_buflen; 174 | printf("INFO: using fast bpf zero copy buffer for packet capturing\n"); 175 | return; 176 | } catch (const ppl7::Exception& ex) { 177 | useZeroCopyBuffer = false; 178 | free(buffer); 179 | } 180 | buflen = 8192; 181 | buffer = (unsigned char*)malloc(buflen); 182 | if (!buffer) { 183 | close(sd); 184 | throw ppl7::OutOfMemoryException(); 185 | } 186 | try { 187 | initBufferedMode(sd, buflen); 188 | printf("INFO: using normal bpf buffered mode for packet capturing\n"); 189 | int ret = fcntl(sd, F_SETFL, fcntl(sd, F_GETFL, 0) | O_NONBLOCK); // NON-Blocking 190 | if (ret < 0) 191 | ppl7::throwExceptionFromErrno(errno, "Could not set bpf into non blocking mode"); 192 | 193 | } catch (const ppl7::Exception& ex) { 194 | free(buffer); 195 | close(sd); 196 | throw; 197 | } 198 | 199 | #else 200 | buffer = (unsigned char*)malloc(buflen); 201 | if (!buffer) 202 | throw ppl7::OutOfMemoryException(); 203 | if ((sd = socket(AF_PACKET, SOCK_RAW, htons(0x0800))) == -1) { 204 | int e = errno; 205 | free(buffer); 206 | ppl7::throwExceptionFromErrno(e, "Could not create RawReceiverSocket"); 207 | } 208 | int ret = fcntl(sd, F_SETFL, fcntl(sd, F_GETFL, 0) | O_NONBLOCK); // NON-Blocking 209 | if (ret < 0) { 210 | int e = errno; 211 | close(sd); 212 | free(buffer); 213 | ppl7::throwExceptionFromErrno(e, "Could not set bpf into non blocking mode"); 214 | } 215 | 216 | #endif 217 | } 218 | 219 | RawSocketReceiver::~RawSocketReceiver() 220 | { 221 | close(sd); 222 | #ifdef DNSMETER_USE_BPF 223 | if (useZeroCopyBuffer) { 224 | struct bpf_zbuf* zbuf = (struct bpf_zbuf*)buffer; 225 | free(zbuf->bz_bufa); 226 | free(zbuf->bz_bufb); 227 | } 228 | #endif 229 | free(buffer); 230 | } 231 | 232 | void RawSocketReceiver::initInterface(const ppl7::String& Device) 233 | { 234 | #ifdef DNSMETER_USE_BPF 235 | struct ifreq ifreq; 236 | strcpy((char*)ifreq.ifr_name, (const char*)Device); 237 | if (ioctl(sd, BIOCSETIF, &ifreq) < 0) { 238 | ppl7::throwExceptionFromErrno(errno, "Could not bind RawReceiverSocket on interface (BIOCSETIF)"); 239 | } 240 | unsigned int promiscuous_mode = 1; 241 | if (ioctl(sd, BIOCPROMISC, &promiscuous_mode) < 0) { 242 | ppl7::throwExceptionFromErrno(errno, "Could not set Interface into promiscuous mode (BIOCPROMISC)"); 243 | } 244 | #endif 245 | } 246 | 247 | void RawSocketReceiver::setSource(const ppl7::IPAddress& ip_addr, int port) 248 | { 249 | SourceIP = ip_addr; 250 | SourcePort = htons(port); 251 | #ifdef DNSMETER_USE_BPF 252 | // Install packet filter in bpf 253 | int sip = htonl(*(int*)SourceIP.addr()); 254 | struct bpf_insn insns[] = { 255 | // load halfword at position 12 from packet into register 256 | BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), 257 | // is it 0x800? if no, jump over 5 instructions, else jump over 0 258 | BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0800, 0, 7), 259 | // source ip 260 | BPF_STMT(BPF_LD + BPF_W + BPF_ABS, 26), 261 | BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (unsigned int)sip, 0, 5), 262 | 263 | // udp? 264 | BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23), 265 | BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 17, 0, 3), 266 | 267 | // source port 268 | BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 34), 269 | BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (unsigned int)port, 0, 1), 270 | 271 | /* if we reach here, return -1 which will allow the packet to be read */ 272 | BPF_STMT(BPF_RET + BPF_K, (u_int)-1), 273 | /* if we reach here, return 0 which will ignore the packet */ 274 | BPF_STMT(BPF_RET + BPF_K, 0), 275 | }; 276 | struct bpf_program bpf_program = { 277 | 10, 278 | (struct bpf_insn*)&insns 279 | }; 280 | if (ioctl(sd, BIOCSETF, (struct bpf_program*)&bpf_program) < 0) { 281 | throw FailedToInitializePacketfilter(); 282 | } 283 | #endif 284 | } 285 | 286 | bool RawSocketReceiver::socketReady() 287 | { 288 | // #ifdef DNSMETER_USE_BPF 289 | // if (useZeroCopyBuffer) return true; 290 | // #endif 291 | fd_set rset; 292 | struct timeval timeout; 293 | timeout.tv_sec = 0; 294 | timeout.tv_usec = 100; 295 | FD_ZERO(&rset); 296 | FD_SET(sd, &rset); // Wir wollen nur prüfen, ob wir lesen können 297 | int ret = select(sd + 1, &rset, NULL, NULL, &timeout); 298 | if (ret < 0) 299 | return false; 300 | if (FD_ISSET(sd, &rset)) { 301 | return true; 302 | } 303 | return false; 304 | } 305 | 306 | static void count_packet(RawSocketReceiver::Counter& counter, unsigned char* buffer, size_t size) 307 | { 308 | counter.num_pkgs++; 309 | counter.bytes_rcv += size; 310 | struct DNS_HEADER* dns = (struct DNS_HEADER*)(buffer + 14 + sizeof(struct ip) + sizeof(struct udphdr)); 311 | double rd = getQueryRTT(ntohs(dns->id)); 312 | counter.rtt_total += rd; 313 | if (rd < counter.rtt_min || counter.rtt_min == 0) 314 | counter.rtt_min = rd; 315 | if (rd > counter.rtt_max) 316 | counter.rtt_max = rd; 317 | if (dns->rcode < 16) 318 | counter.rcodes[dns->rcode]++; 319 | if (dns->tc) 320 | counter.truncated++; 321 | } 322 | 323 | #ifdef DNSMETER_USE_BPF 324 | /* 325 | * Return ownership of a buffer to the kernel for reuse. 326 | */ 327 | static void buffer_acknowledge(struct bpf_zbuf_header* bzh) 328 | { 329 | atomic_store_rel_int(&bzh->bzh_user_gen, bzh->bzh_kernel_gen); 330 | } 331 | 332 | static int buffer_check(struct bpf_zbuf_header* bzh) 333 | { 334 | return (bzh->bzh_user_gen != atomic_load_acq_int(&bzh->bzh_kernel_gen)); 335 | } 336 | 337 | static void read_buffer(unsigned char* ptr, size_t size, RawSocketReceiver::Counter& counter) 338 | { 339 | size_t done = 0; 340 | while (done < size) { 341 | struct bpf_hdr* bpfh = (struct bpf_hdr*)ptr; 342 | if (bpfh->bh_caplen == 0 || bpfh->bh_hdrlen == 0) 343 | break; 344 | size_t chunk_size = BPF_WORDALIGN(bpfh->bh_caplen + bpfh->bh_hdrlen); 345 | count_packet(counter, ptr + bpfh->bh_hdrlen, chunk_size - bpfh->bh_datalen); 346 | ptr += chunk_size; 347 | done += chunk_size; 348 | } 349 | } 350 | 351 | static void read_zbuffer(struct bpf_zbuf_header* zhdr, RawSocketReceiver::Counter& counter) 352 | { 353 | size_t size = zhdr->bzh_kernel_len - sizeof(struct bpf_zbuf_header); 354 | unsigned char* ptr = (unsigned char*)zhdr + sizeof(struct bpf_zbuf_header); 355 | read_buffer(ptr, size, counter); 356 | buffer_acknowledge(zhdr); 357 | } 358 | void RawSocketReceiver::receive(RawSocketReceiver::Counter& counter) 359 | { 360 | if (useZeroCopyBuffer) { 361 | struct bpf_zbuf* zbuf = (struct bpf_zbuf*)buffer; 362 | struct bpf_zbuf_header* zhdr = NULL; 363 | if (buffer_check((struct bpf_zbuf_header*)zbuf->bz_bufa)) { 364 | zhdr = ((struct bpf_zbuf_header*)zbuf->bz_bufa); 365 | read_zbuffer(zhdr, counter); 366 | } 367 | if (buffer_check((struct bpf_zbuf_header*)zbuf->bz_bufb)) { 368 | zhdr = ((struct bpf_zbuf_header*)zbuf->bz_bufb); 369 | read_zbuffer(zhdr, counter); 370 | } 371 | } else { 372 | ssize_t bufused = read(sd, buffer, buflen); 373 | if (bufused < 34) 374 | return; 375 | read_buffer(buffer, bufused, counter); 376 | } 377 | } 378 | 379 | #else 380 | void RawSocketReceiver::receive(Counter& counter) 381 | { 382 | unsigned char* ptr = buffer; 383 | ssize_t bufused = recvfrom(sd, buffer, buflen, 0, NULL, NULL); 384 | if (bufused < 34) 385 | return; 386 | struct ETHER* eth = (struct ETHER*)ptr; 387 | //ppl7::HexDump(ptr,bufused); 388 | //printf ("sizeof ETHER=%d, type=%X\n",sizeof(struct ETHER),eth->type); 389 | if (eth->type != htons(0x0800)) 390 | return; 391 | struct ip* iphdr = (struct ip*)(ptr + 14); 392 | if (iphdr->ip_v != 4) 393 | return; 394 | if (iphdr->ip_src.s_addr != *(in_addr_t*)SourceIP.addr()) 395 | return; 396 | 397 | struct udphdr* udp = (struct udphdr*)(ptr + 14 + sizeof(struct ip)); 398 | if (udp->uh_sport != SourcePort) 399 | return; 400 | count_packet(counter, ptr, bufused); 401 | } 402 | #endif 403 | -------------------------------------------------------------------------------- /src/system_stat.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, OARC, Inc. 3 | * Copyright (c) 2019, DENIC eG 4 | * All rights reserved. 5 | * 6 | * This file is part of dnsmeter. 7 | * 8 | * dnsmeter is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * dnsmeter is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with dnsmeter. If not, see . 20 | */ 21 | 22 | #include "config.h" 23 | 24 | #include "system_stat.h" 25 | #include "exceptions.h" 26 | 27 | #ifdef __linux__ 28 | #include 29 | #endif 30 | #include 31 | #include 32 | #include 33 | #ifdef __FreeBSD__ 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #endif 42 | 43 | // ########################################################### Linux specific 44 | #ifdef __linux__ 45 | static void sampleCpuUsage(SystemStat::Cpu& stat) 46 | { 47 | FILE* fp = fopen("/proc/stat", "r"); 48 | if (fscanf(fp, "%*s %d %d %d %d %d", &stat.user, &stat.nice, &stat.system, &stat.idle, &stat.iowait) != 5) { 49 | // ignore 50 | } 51 | fclose(fp); 52 | } 53 | 54 | static void sampleSysinfo(SystemStat::Sysinfo& stat) 55 | { 56 | struct sysinfo info; 57 | if (0 != sysinfo(&info)) { 58 | return; 59 | } 60 | stat.uptime = info.uptime; 61 | stat.freeswap = info.freeswap * info.mem_unit; 62 | stat.freeram = info.freeram * info.mem_unit; 63 | stat.bufferram = info.bufferram * info.mem_unit; 64 | stat.totalram = info.totalram * info.mem_unit; 65 | stat.totalswap = info.totalswap * info.mem_unit; 66 | stat.sharedram = info.sharedram * info.mem_unit; 67 | stat.procs = info.procs; 68 | } 69 | 70 | static void sampleNetwork(std::map& interfaces, SystemStat::Interface& total) 71 | { 72 | total.receive.clear(); 73 | total.transmit.clear(); 74 | 75 | ppl7::String buffer; 76 | ppl7::File ff("/proc/net/dev"); 77 | while (!ff.eof()) { 78 | ff.gets(buffer, 2048); 79 | buffer.trim(); 80 | ssize_t t = buffer.instr(":"); 81 | if (t > 1) { 82 | SystemStat::Interface nif; 83 | nif.Name.set(buffer, t); 84 | buffer.replace("\t", " "); 85 | ppl7::Array tok = ppl7::StrTok(buffer, " "); 86 | nif.receive.bytes = tok[1].toUnsignedLong(); 87 | nif.receive.packets = tok[2].toUnsignedLong(); 88 | nif.receive.errs = tok[3].toUnsignedLong(); 89 | nif.receive.drop = tok[4].toUnsignedLong(); 90 | 91 | nif.transmit.bytes = tok[9].toUnsignedLong(); 92 | nif.transmit.packets = tok[10].toUnsignedLong(); 93 | nif.transmit.errs = tok[11].toUnsignedLong(); 94 | nif.transmit.drop = tok[12].toUnsignedLong(); 95 | 96 | total.receive.bytes += nif.receive.bytes; 97 | total.receive.packets += nif.receive.packets; 98 | total.receive.errs += nif.receive.errs; 99 | total.receive.drop += nif.receive.drop; 100 | 101 | total.transmit.bytes += nif.transmit.bytes; 102 | total.transmit.packets += nif.transmit.packets; 103 | total.transmit.errs += nif.transmit.errs; 104 | total.transmit.drop += nif.transmit.drop; 105 | interfaces.insert(std::pair(nif.Name, nif)); 106 | } 107 | } 108 | } 109 | 110 | // ########################################################### FreeBSD specific 111 | #elif defined __FreeBSD__ 112 | static kvm_t* kd = NULL; 113 | #define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var)) 114 | 115 | static void 116 | getsysctl(const char* name, void* ptr, size_t len) 117 | { 118 | size_t nlen = len; 119 | if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) { 120 | throw SystemCallFailed("sysctlbyname(%s...) failed: %s\n", name, 121 | strerror(errno)); 122 | } 123 | if (nlen != len) { 124 | throw SystemCallFailed("sysctlbyname(%s...) expected %lu, got %lu\n", 125 | name, (unsigned long)len, (unsigned long)nlen); 126 | } 127 | } 128 | 129 | static void sampleCpuUsage(SystemStat::Cpu& stat) 130 | { 131 | size_t cp_size = sizeof(long) * CPUSTATES * 8; 132 | long* cp_times = (long*)malloc(cp_size); 133 | if (sysctlbyname("kern.cp_time", cp_times, &cp_size, NULL, 0) < 0) { 134 | perror("sysctlbyname"); 135 | free(cp_times); 136 | } 137 | stat.user = (int)cp_times[0]; 138 | stat.nice = (int)cp_times[1]; 139 | stat.system = (int)cp_times[2]; 140 | stat.iowait = (int)cp_times[3]; 141 | stat.idle = (int)cp_times[4]; 142 | } 143 | 144 | static int 145 | swapmode(long* retavail, long* retfree) 146 | { 147 | int n; 148 | int pagesize = getpagesize(); 149 | struct kvm_swap swapary[1]; 150 | 151 | *retavail = 0; 152 | *retfree = 0; 153 | 154 | #define CONVERT(v) ((quad_t)(v)*pagesize) 155 | 156 | n = kvm_getswapinfo(kd, swapary, 1, 0); 157 | if (n < 0 || swapary[0].ksw_total == 0) 158 | return (0); 159 | 160 | *retavail = CONVERT(swapary[0].ksw_total); 161 | *retfree = CONVERT(swapary[0].ksw_total - swapary[0].ksw_used); 162 | 163 | n = (int)(swapary[0].ksw_used * 100.0 / swapary[0].ksw_total); 164 | return (n); 165 | } 166 | 167 | static void sampleSysinfo(SystemStat::Sysinfo& stat) 168 | { 169 | struct timespec uptime; 170 | int pagesize = getpagesize(); 171 | if (clock_gettime(CLOCK_UPTIME, &uptime) == 0) 172 | stat.uptime = uptime.tv_sec; 173 | swapmode(&stat.totalswap, &stat.freeswap); 174 | int tmp; 175 | long tmp_l; 176 | GETSYSCTL("vm.stats.vm.v_free_count", tmp); 177 | stat.freeram = tmp * pagesize; 178 | GETSYSCTL("hw.physmem", tmp_l); 179 | stat.totalram = tmp_l; 180 | } 181 | 182 | static void sampleNetwork(std::map& interfaces, SystemStat::Interface& total) 183 | { 184 | total.receive.clear(); 185 | total.transmit.clear(); 186 | 187 | #define IFA_STAT(s) (((struct if_data*)ifa->ifa_data)->ifi_##s) 188 | 189 | struct ifaddrs* ifap = NULL; 190 | if (getifaddrs(&ifap) != 0) { 191 | throw SystemCallFailed("FreeBSD, getifaddrs: %s", strerror(errno)); 192 | } 193 | for (struct ifaddrs* ifa = ifap; ifa; ifa = ifa->ifa_next) { 194 | if (ifa->ifa_addr->sa_family != AF_LINK) 195 | continue; 196 | SystemStat::Interface nif; 197 | nif.Name.setf("%s", ifa->ifa_name); 198 | 199 | nif.receive.bytes = IFA_STAT(ibytes); 200 | nif.receive.packets = IFA_STAT(ipackets); 201 | nif.receive.errs = IFA_STAT(ierrors); 202 | nif.receive.drop = IFA_STAT(iqdrops); 203 | 204 | nif.transmit.bytes = IFA_STAT(obytes); 205 | nif.transmit.packets = IFA_STAT(opackets); 206 | nif.transmit.errs = IFA_STAT(oerrors); 207 | nif.transmit.drop = IFA_STAT(oqdrops); 208 | 209 | total.receive.bytes += nif.receive.bytes; 210 | total.receive.packets += nif.receive.packets; 211 | total.receive.errs += nif.receive.errs; 212 | total.receive.drop += nif.receive.drop; 213 | 214 | total.transmit.bytes += nif.transmit.bytes; 215 | total.transmit.packets += nif.transmit.packets; 216 | total.transmit.errs += nif.transmit.errs; 217 | total.transmit.drop += nif.transmit.drop; 218 | interfaces.insert(std::pair(nif.Name, nif)); 219 | } 220 | freeifaddrs(ifap); 221 | } 222 | 223 | static void exit_kvm() 224 | { 225 | if (kd) 226 | kvm_close(kd); 227 | } 228 | 229 | #endif 230 | 231 | void sampleSensorData(SystemStat& stat) 232 | { 233 | #ifdef __FreeBSD__ 234 | if (!kd) { 235 | kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open"); 236 | if (!kd) 237 | throw KernelAccessFailed("FreeBSD kvm_open failed"); 238 | atexit(exit_kvm); 239 | } 240 | #endif 241 | stat.sampleTime = ppl7::GetMicrotime(); 242 | sampleCpuUsage(stat.cpu); 243 | sampleSysinfo(stat.sysinfo); 244 | sampleNetwork(stat.interfaces, stat.net_total); 245 | } 246 | 247 | double SystemStat::Cpu::getUsage(const SystemStat::Cpu& sample1, const SystemStat::Cpu& sample2) 248 | { 249 | return 100.0 * (double)((sample2.user + sample2.nice + sample2.system) - (sample1.user + sample1.nice + sample1.system)) / (double)((sample2.user + sample2.nice + sample2.system + sample2.idle) - (sample1.user + sample1.nice + sample1.system + sample1.idle)); 250 | } 251 | 252 | static unsigned long delta_with_overflow(unsigned long sample1, unsigned long sample2) 253 | { 254 | if (sample2 >= sample1) 255 | return sample2 - sample1; 256 | return ULONG_MAX - sample1 + sample2; 257 | } 258 | 259 | SystemStat::Network SystemStat::Network::getDelta(const SystemStat::Network& sample1, const SystemStat::Network& sample2) 260 | { 261 | return SystemStat::Network(delta_with_overflow(sample1.bytes, sample2.bytes), 262 | delta_with_overflow(sample1.packets, sample2.packets), 263 | delta_with_overflow(sample1.errs, sample2.errs), 264 | delta_with_overflow(sample1.drop, sample2.drop)); 265 | } 266 | 267 | void SystemStat::exportToArray(ppl7::AssocArray& data) const 268 | { 269 | data.setf("sampleTime", "%0.6f", sampleTime); 270 | data.setf("net_total/receive/bytes", "%lu", net_total.receive.bytes); 271 | data.setf("net_total/receive/packets", "%lu", net_total.receive.packets); 272 | data.setf("net_total/receive/errs", "%lu", net_total.receive.errs); 273 | data.setf("net_total/receive/drop", "%lu", net_total.receive.drop); 274 | data.setf("net_total/transmit/bytes", "%lu", net_total.transmit.bytes); 275 | data.setf("net_total/transmit/packets", "%lu", net_total.transmit.packets); 276 | data.setf("net_total/transmit/errs", "%lu", net_total.transmit.errs); 277 | data.setf("net_total/transmit/drop", "%lu", net_total.transmit.drop); 278 | std::map::const_iterator it; 279 | for (it = interfaces.begin(); it != interfaces.end(); ++it) { 280 | ppl7::AssocArray d; 281 | const SystemStat::Interface& nif = it->second; 282 | d.setf("receive/bytes", "%lu", nif.receive.bytes); 283 | d.setf("receive/packets", "%lu", nif.receive.packets); 284 | d.setf("receive/errs", "%lu", nif.receive.errs); 285 | d.setf("receive/drop", "%lu", nif.receive.drop); 286 | d.setf("transmit/bytes", "%lu", nif.transmit.bytes); 287 | d.setf("transmit/packets", "%lu", nif.transmit.packets); 288 | d.setf("transmit/errs", "%lu", nif.transmit.errs); 289 | d.setf("transmit/drop", "%lu", nif.transmit.drop); 290 | d.set("name", nif.Name); 291 | ppl7::String key; 292 | key.setf("interface/%s", (const char*)nif.Name); 293 | data.set(key, d); 294 | } 295 | 296 | data.setf("cpu/user", "%d", cpu.user); 297 | data.setf("cpu/nice", "%d", cpu.nice); 298 | data.setf("cpu/system", "%d", cpu.system); 299 | data.setf("cpu/idle", "%d", cpu.idle); 300 | data.setf("cpu/iowait", "%d", cpu.iowait); 301 | 302 | data.setf("sysinfo/uptime", "%ld", sysinfo.uptime); 303 | data.setf("sysinfo/freeswap", "%ld", sysinfo.freeswap); 304 | data.setf("sysinfo/totalswap", "%ld", sysinfo.totalswap); 305 | data.setf("sysinfo/freeram", "%ld", sysinfo.freeram); 306 | data.setf("sysinfo/bufferram", "%ld", sysinfo.bufferram); 307 | data.setf("sysinfo/totalram", "%ld", sysinfo.totalram); 308 | data.setf("sysinfo/sharedram", "%ld", sysinfo.sharedram); 309 | data.setf("sysinfo/procs", "%d", sysinfo.procs); 310 | } 311 | 312 | void SystemStat::importFromArray(const ppl7::AssocArray& data) 313 | { 314 | sampleTime = data.getString("sampleTime").toDouble(); 315 | net_total.receive.bytes = data.getString("net_total/receive/bytes").toUnsignedLong(); 316 | net_total.receive.packets = data.getString("net_total/receive/packets").toUnsignedLong(); 317 | net_total.receive.errs = data.getString("net_total/receive/errs").toUnsignedLong(); 318 | net_total.receive.drop = data.getString("net_total/receive/drop").toUnsignedLong(); 319 | net_total.transmit.bytes = data.getString("net_total/transmit/bytes").toUnsignedLong(); 320 | net_total.transmit.packets = data.getString("net_total/transmit/packets").toUnsignedLong(); 321 | net_total.transmit.errs = data.getString("net_total/transmit/errs").toUnsignedLong(); 322 | net_total.transmit.drop = data.getString("net_total/transmit/drop").toUnsignedLong(); 323 | 324 | const ppl7::AssocArray& data_if_list = data.getAssocArray("interface"); 325 | ppl7::AssocArray::Iterator it; 326 | data_if_list.reset(it); 327 | while (data_if_list.getNext(it)) { 328 | Interface nif; 329 | nif.Name = it.key(); 330 | const ppl7::AssocArray& d = it.value().toAssocArray(); 331 | nif.receive.bytes = d.getString("receive/bytes").toUnsignedLong(); 332 | nif.receive.packets = d.getString("receive/packets").toUnsignedLong(); 333 | nif.receive.errs = d.getString("receive/errs").toUnsignedLong(); 334 | nif.receive.drop = d.getString("receive/drop").toUnsignedLong(); 335 | nif.transmit.bytes = d.getString("transmit/bytes").toUnsignedLong(); 336 | nif.transmit.packets = d.getString("transmit/packets").toUnsignedLong(); 337 | nif.transmit.errs = d.getString("transmit/errs").toUnsignedLong(); 338 | nif.transmit.drop = d.getString("transmit/drop").toUnsignedLong(); 339 | interfaces.insert(std::pair(nif.Name, nif)); 340 | } 341 | cpu.user = data.getString("cpu/user").toInt(); 342 | cpu.nice = data.getString("cpu/nice").toInt(); 343 | cpu.system = data.getString("cpu/system").toInt(); 344 | cpu.idle = data.getString("cpu/idle").toInt(); 345 | cpu.iowait = data.getString("cpu/iowait").toInt(); 346 | 347 | sysinfo.uptime = data.getString("sysinfo/uptime").toLong(); 348 | sysinfo.freeswap = data.getString("sysinfo/freeswap").toLong(); 349 | sysinfo.totalswap = data.getString("sysinfo/totalswap").toLong(); 350 | sysinfo.freeram = data.getString("sysinfo/freeram").toLong(); 351 | sysinfo.bufferram = data.getString("sysinfo/bufferram").toLong(); 352 | sysinfo.totalram = data.getString("sysinfo/totalram").toLong(); 353 | sysinfo.sharedram = data.getString("sysinfo/sharedram").toLong(); 354 | sysinfo.procs = data.getString("sysinfo/procs").toInt(); 355 | } 356 | 357 | void SystemStat::print() const 358 | { 359 | ppl7::AssocArray a; 360 | exportToArray(a); 361 | a.list(); 362 | } 363 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2021, OARC, Inc. 2 | # Copyright (c) 2019, DENIC eG 3 | # All rights reserved. 4 | # 5 | # This file is part of dnsmeter. 6 | # 7 | # dnsmeter is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # dnsmeter is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with dnsmeter. If not, see . 19 | 20 | MAINTAINERCLEANFILES = $(srcdir)/Makefile.in 21 | DISTCLEANFILES = $(srcdir)/pplib/include/ppl7-config.h \ 22 | $(srcdir)/pplib/release/libppl7.a 23 | CLEANFILES = dnsmeter.1 *.gcda *.gcno *.gcov 24 | 25 | SUBDIRS = test 26 | 27 | AM_CXXFLAGS = -I$(srcdir) \ 28 | -I$(top_srcdir) \ 29 | -I$(srcdir)/pplib/include \ 30 | $(PTHREAD_CFLAGS) $(ICONV_CFLAGS) 31 | 32 | bin_PROGRAMS = dnsmeter 33 | 34 | dnsmeter_SOURCES = dns_receiver_thread.cpp dns_sender.cpp \ 35 | dns_sender_thread.cpp main.cpp packet.cpp payload_file.cpp query.cpp \ 36 | raw_socket_receiver.cpp raw_socket_sender.cpp system_stat.cpp 37 | dist_dnsmeter_SOURCES = dns_receiver_thread.h dns_sender.h \ 38 | dns_sender_thread.h exceptions.h packet.h payload_file.h query.h \ 39 | raw_socket_receiver.h raw_socket_sender.h system_stat.h 40 | dnsmeter_LDADD = $(PTHREAD_LIBS) $(ICONV_LIBS) \ 41 | $(srcdir)/pplib/release/libppl7.a 42 | 43 | BUILT_SOURCES = pplib/include/ppl7-config.h 44 | 45 | pplib/include/ppl7-config.h: 46 | cd "$(srcdir)/pplib" && ./configure --disable-oggtest \ 47 | --disable-freetypetest --disable-sdltest --disable-sdlframework \ 48 | --without-jpeg --without-libjpegturbo --without-libpng \ 49 | --without-libmicrohttpd --without-libmcrypt-prefix \ 50 | --without-libtiff --without-libcurl --without-mpg123 \ 51 | --without-lame --without-ogg --without-libcdio --without-libiconv-prefix \ 52 | --without-imlib --without-mysql --without-postgresql \ 53 | --without-sqlite3 --without-libldn --without-nasm 54 | 55 | $(srcdir)/pplib/release/libppl7.a: pplib/include/ppl7-config.h 56 | cd "$(srcdir)/pplib" && make 57 | 58 | man1_MANS = dnsmeter.1 59 | 60 | dnsmeter.1: dnsmeter.1.in Makefile 61 | sed -e 's,[@]PACKAGE_VERSION[@],$(PACKAGE_VERSION),g' \ 62 | -e 's,[@]PACKAGE_URL[@],$(PACKAGE_URL),g' \ 63 | -e 's,[@]PACKAGE_BUGREPORT[@],$(PACKAGE_BUGREPORT),g' \ 64 | < $(srcdir)/dnsmeter.1.in > dnsmeter.1 65 | 66 | if ENABLE_GCOV 67 | gcov-local: 68 | for src in $(dnsmeter_SOURCES); do \ 69 | gcov -l -r -s "$(srcdir)" "$$src"; \ 70 | done 71 | endif 72 | 73 | EXTRA_DIST = dnsmeter.1.in \ 74 | pplib/Makefile.in \ 75 | pplib/src/types/ByteArrayPtr.cpp \ 76 | pplib/src/types/ByteArray.cpp \ 77 | pplib/src/types/Array.cpp \ 78 | pplib/src/types/Pointer.cpp \ 79 | pplib/src/types/WideString.cpp \ 80 | pplib/src/types/AssocArray.cpp \ 81 | pplib/src/types/String.cpp \ 82 | pplib/src/types/Variant.cpp \ 83 | pplib/src/types/DateTime.cpp \ 84 | pplib/src/math/crc32.cpp \ 85 | pplib/src/math/calc.cpp \ 86 | pplib/src/math/md5.cpp \ 87 | pplib/src/math/random.cpp \ 88 | pplib/src/database/MySQL.cpp \ 89 | pplib/src/database/ResultSet.cpp \ 90 | pplib/src/database/Database.cpp \ 91 | pplib/src/database/PostgreSQL.cpp \ 92 | pplib/src/database/DBPool.cpp \ 93 | pplib/src/database/DBPoolOfPools.cpp \ 94 | pplib/src/database/Sqlite3.cpp \ 95 | pplib/src/audio/AudioCD.cpp \ 96 | pplib/src/audio/AudioEncoder_MP3.cpp \ 97 | pplib/src/audio/AudioDecoder_Ogg.cpp \ 98 | pplib/src/audio/AudioInfo.cpp \ 99 | pplib/src/audio/Cddb.cpp \ 100 | pplib/src/audio/AudioDecoder_MP3.cpp \ 101 | pplib/src/audio/AudioDecoder_Aiff.cpp \ 102 | pplib/src/audio/AudioEncoder_Wave.cpp \ 103 | pplib/src/audio/Icecast.cpp \ 104 | pplib/src/audio/AudioEncoder_Ogg.cpp \ 105 | pplib/src/audio/ID3Tag.cpp \ 106 | pplib/src/audio/AudioDecoder_Wave.cpp \ 107 | pplib/src/audio/Mp3.cpp \ 108 | pplib/src/audio/AudioEncoder_Aiff.cpp \ 109 | pplib/src/toolkit/Divider.cpp \ 110 | pplib/src/toolkit/WindowManager.cpp \ 111 | pplib/src/toolkit/Window.cpp \ 112 | pplib/src/toolkit/LineInput.cpp \ 113 | pplib/src/toolkit/WindowManager_SDL2.cpp \ 114 | pplib/src/toolkit/Layout.cpp \ 115 | pplib/src/toolkit/Widget.cpp \ 116 | pplib/src/toolkit/Surface.cpp \ 117 | pplib/src/toolkit/Frame.cpp \ 118 | pplib/src/toolkit/Label.cpp \ 119 | pplib/src/toolkit/Button.cpp \ 120 | pplib/src/toolkit/Event.cpp \ 121 | pplib/src/asm/common.asm \ 122 | pplib/src/asm/colors.asm \ 123 | pplib/src/asm/pixel.asm \ 124 | pplib/src/asm/chromakey.asm \ 125 | pplib/src/asm/cpu.asm \ 126 | pplib/src/asm/blt_blend.asm \ 127 | pplib/src/asm/rect.asm \ 128 | pplib/src/asm/fonts.asm \ 129 | pplib/src/asm/blt.asm \ 130 | pplib/src/internet/WikiParser.cpp \ 131 | pplib/src/internet/Webserver.cpp \ 132 | pplib/src/internet/ipaddress.cpp \ 133 | pplib/src/internet/sockaddr.cpp \ 134 | pplib/src/internet/resolver.cpp \ 135 | pplib/src/internet/UDPSocket.cpp \ 136 | pplib/src/internet/ipnetwork.cpp \ 137 | pplib/src/internet/curl.cpp \ 138 | pplib/src/internet/SocketMessage.cpp \ 139 | pplib/src/internet/inet_functions.cpp \ 140 | pplib/src/internet/openssl.cpp \ 141 | pplib/src/internet/TCPSocket.cpp \ 142 | pplib/src/crypto/Digest.cpp \ 143 | pplib/src/crypto/Crypt.cpp \ 144 | pplib/src/crypto/MCrypt.cpp \ 145 | pplib/src/core/Signal.cpp \ 146 | pplib/src/core/Compat.cpp \ 147 | pplib/src/core/Mutex.cpp \ 148 | pplib/src/core/ThreadPool.cpp \ 149 | pplib/src/core/Functions.cpp \ 150 | pplib/src/core/MemoryGroup.cpp \ 151 | pplib/src/core/MemFile.cpp \ 152 | pplib/src/core/StringFunctions.cpp \ 153 | pplib/src/core/Dir.cpp \ 154 | pplib/src/core/File.cpp \ 155 | pplib/src/core/ConfigParser.cpp \ 156 | pplib/src/core/DirEntry.cpp \ 157 | pplib/src/core/Resourcen.cpp \ 158 | pplib/src/core/Exceptions.cpp \ 159 | pplib/src/core/FileObject.cpp \ 160 | pplib/src/core/PerlHelper.cpp \ 161 | pplib/src/core/Json.cpp \ 162 | pplib/src/core/Iconv.cpp \ 163 | pplib/src/core/AVLTree.cpp \ 164 | pplib/src/core/Logger.cpp \ 165 | pplib/src/core/Threads.cpp \ 166 | pplib/src/core/PythonHelper.cpp \ 167 | pplib/src/core/Compression.cpp \ 168 | pplib/src/core/Time.cpp \ 169 | pplib/src/core/cpu.cpp \ 170 | pplib/src/core/MemoryHeap.cpp \ 171 | pplib/src/core/PFPFile.cpp \ 172 | pplib/src/core/Resource.cpp \ 173 | pplib/src/core/GzFile.cpp \ 174 | pplib/src/grafix/Point.cpp \ 175 | pplib/src/grafix/ImageFilter_PPM.cpp \ 176 | pplib/src/grafix/Font5.cpp \ 177 | pplib/src/grafix/ImageFilter_JPEG.cpp \ 178 | pplib/src/grafix/Rect.cpp \ 179 | pplib/src/grafix/DrawableBlit.cpp \ 180 | pplib/src/grafix/Point3D.cpp \ 181 | pplib/src/grafix/RGBFormat.cpp \ 182 | pplib/src/grafix/ImageFilter_GIF.cpp \ 183 | pplib/src/grafix/Fonts.cpp \ 184 | pplib/src/grafix/ImageFilter_TGA.cpp \ 185 | pplib/src/grafix/ImageFilter_PNG.cpp \ 186 | pplib/src/grafix/FontFreeType.cpp \ 187 | pplib/src/grafix/Grafix.cpp \ 188 | pplib/src/grafix/Font6.cpp \ 189 | pplib/src/grafix/DrawablePixel.cpp \ 190 | pplib/src/grafix/ImageFilter_BMP.cpp \ 191 | pplib/src/grafix/Sprite.cpp \ 192 | pplib/src/grafix/ImageFilter_TIFF.cpp \ 193 | pplib/src/grafix/Size.cpp \ 194 | pplib/src/grafix/ImageList.cpp \ 195 | pplib/src/grafix/DrawableLines.cpp \ 196 | pplib/src/grafix/DrawableColor.cpp \ 197 | pplib/src/grafix/DrawableShapes.cpp \ 198 | pplib/src/grafix/Image.cpp \ 199 | pplib/src/grafix/ImageFilter.cpp \ 200 | pplib/src/grafix/ImageFilter_ImageMagick.cpp \ 201 | pplib/src/grafix/Font4.cpp \ 202 | pplib/src/grafix/Drawable.cpp \ 203 | pplib/src/grafix/Color.cpp \ 204 | pplib/genConfigure \ 205 | pplib/genMakefile.in \ 206 | pplib/aclocal.m4 \ 207 | pplib/conf.sh \ 208 | pplib/include/crypto.h \ 209 | pplib/include/ppl7-ppl6compat.h \ 210 | pplib/include/ppl7.h \ 211 | pplib/include/ppl7-tk.h \ 212 | pplib/include/ppl7-visualc-config.h \ 213 | pplib/include/ppl7-config.h.in \ 214 | pplib/include/config.h.in \ 215 | pplib/include/ppl7-inet.h \ 216 | pplib/include/ppl7-audio.h \ 217 | pplib/include/threads.h \ 218 | pplib/include/ppl7-grafix.h \ 219 | pplib/include/socket.h \ 220 | pplib/include/ppl7-crypto.h \ 221 | pplib/include/prolog.h \ 222 | pplib/include/ppl7-types.h \ 223 | pplib/include/ppl7-algorithms.h \ 224 | pplib/include/ppl7-exceptions.h \ 225 | pplib/include/ppl7-db.h \ 226 | pplib/include/compat.h \ 227 | pplib/tests/Makefile.in \ 228 | pplib/tests/src/toolkit.h \ 229 | pplib/tests/src/stringspeed.cpp \ 230 | pplib/tests/src/database/db_mysql.cpp \ 231 | pplib/tests/src/database/db_sqlite.cpp \ 232 | pplib/tests/src/database/db_postgres.cpp \ 233 | pplib/tests/src/audio/id3tag.cpp \ 234 | pplib/tests/src/audio/audio_decoder_aiff.cpp \ 235 | pplib/tests/src/audio/audio_decoder_mp3.cpp \ 236 | pplib/tests/src/audio/audio_encoder_mp3.cpp \ 237 | pplib/tests/src/audio/audioinfo.cpp \ 238 | pplib/tests/src/audio/audio_encoder_aiff.cpp \ 239 | pplib/tests/src/audio/audio_encoder_wave.cpp \ 240 | pplib/tests/src/audio/audio_decoder_wave.cpp \ 241 | pplib/tests/src/ppl6/strings.cpp \ 242 | pplib/tests/src/ppl6/assocarray.cpp \ 243 | pplib/tests/src/crypto/mcrypt.cpp \ 244 | pplib/tests/src/crypto/crypto.cpp \ 245 | pplib/tests/src/crypto/digest.cpp \ 246 | pplib/tests/src/wordlist.cpp \ 247 | pplib/tests/src/core/stringfunctions.cpp \ 248 | pplib/tests/src/core/iconv.cpp \ 249 | pplib/tests/src/core/functions.cpp \ 250 | pplib/tests/src/core/json.cpp \ 251 | pplib/tests/src/core/filestatic.cpp \ 252 | pplib/tests/src/core/strings.cpp \ 253 | pplib/tests/src/core/gzfile.cpp \ 254 | pplib/tests/src/core/pythonhelper.cpp \ 255 | pplib/tests/src/core/memoryheap.cpp \ 256 | pplib/tests/src/core/avltree.cpp \ 257 | pplib/tests/src/core/variant.cpp \ 258 | pplib/tests/src/core/pointer.cpp \ 259 | pplib/tests/src/core/math.cpp \ 260 | pplib/tests/src/core/dir.cpp \ 261 | pplib/tests/src/core/configparser.cpp \ 262 | pplib/tests/src/core/time.cpp \ 263 | pplib/tests/src/core/bytearray.cpp \ 264 | pplib/tests/src/core/datetime.cpp \ 265 | pplib/tests/src/core/memorygroup.cpp \ 266 | pplib/tests/src/core/bytearrayptr.cpp \ 267 | pplib/tests/src/core/widestrings.cpp \ 268 | pplib/tests/src/core/array.cpp \ 269 | pplib/tests/src/core/perlhelper.cpp \ 270 | pplib/tests/src/core/file.cpp \ 271 | pplib/tests/src/core/logger.cpp \ 272 | pplib/tests/src/core/assocarray.cpp \ 273 | pplib/tests/src/core/list.cpp \ 274 | pplib/tests/src/loggertest.cpp \ 275 | pplib/tests/src/grafix/grafix_image.cpp \ 276 | pplib/tests/src/grafix/grafix_rect.cpp \ 277 | pplib/tests/src/grafix/grafix_imagefilter.cpp \ 278 | pplib/tests/src/grafix/grafix_size.cpp \ 279 | pplib/tests/src/grafix/grafix_font.cpp \ 280 | pplib/tests/src/grafix/grafix_rgbformat.cpp \ 281 | pplib/tests/src/grafix/grafix_point3d.cpp \ 282 | pplib/tests/src/grafix/grafix_point.cpp \ 283 | pplib/tests/src/grafix/grafix.cpp \ 284 | pplib/tests/src/grafix/grafix_color.cpp \ 285 | pplib/tests/src/grafix/grafix_drawable.cpp \ 286 | pplib/tests/src/gfxreftest.cpp \ 287 | pplib/tests/src/toolkit.cpp \ 288 | pplib/tests/src/textsnippets.cpp \ 289 | pplib/tests/src/main.cpp \ 290 | pplib/tests/src/threadtest.cpp \ 291 | pplib/tests/src/inet/tcpsocket.cpp \ 292 | pplib/tests/src/inet/ipaddress.cpp \ 293 | pplib/tests/src/inet/wikiparser.cpp \ 294 | pplib/tests/src/inet/sockaddr.cpp \ 295 | pplib/tests/src/inet/resolver.cpp \ 296 | pplib/tests/src/inet/inet.cpp \ 297 | pplib/tests/src/inet/ipnetwork.cpp \ 298 | pplib/tests/create_postgres_db.sh \ 299 | pplib/tests/valgrind.suppressions \ 300 | pplib/tests/gcovr \ 301 | pplib/tests/test.conf \ 302 | pplib/tests/ppl7-tests.h \ 303 | pplib/tests/testdata/test_192cbr_taggedWithCover.mp3 \ 304 | pplib/tests/testdata/test_192vbr.mp3 \ 305 | pplib/tests/testdata/unittest.png \ 306 | pplib/tests/testdata/ppl7-icon-64x64.png \ 307 | pplib/tests/testdata/test_44kHz_tagged.wav \ 308 | pplib/tests/testdata/test.pcx \ 309 | pplib/tests/testdata/unicodeUSASCII.txt \ 310 | pplib/tests/testdata/test-pal-trans.png \ 311 | pplib/tests/testdata/fonts/liberationsans8.fnt5 \ 312 | pplib/tests/testdata/fonts/LiberationSans-Bold.ttf \ 313 | pplib/tests/testdata/fonts/freesans4.fnt5 \ 314 | pplib/tests/testdata/fonts/segoeui4.fnt5 \ 315 | pplib/tests/testdata/filenameUSASCII.txt \ 316 | pplib/tests/testdata/database/postgresql.sql \ 317 | pplib/tests/testdata/database/mysql.sql \ 318 | pplib/tests/testdata/database/sqlite3.sql \ 319 | pplib/tests/testdata/test_192cbr_tagged.mp3 \ 320 | pplib/tests/testdata/test.tga \ 321 | pplib/tests/testdata/test.png \ 322 | pplib/tests/testdata/jsontest2.json \ 323 | pplib/tests/testdata/jsontest4.json \ 324 | pplib/tests/testdata/compression.txt \ 325 | pplib/tests/testdata/mpg123.h \ 326 | pplib/tests/testdata/test.gif \ 327 | pplib/tests/testdata/cover.jpg \ 328 | pplib/tests/testdata/unittest.bmp \ 329 | pplib/tests/testdata/screenshot1.png \ 330 | pplib/tests/testdata/lame.h \ 331 | pplib/tests/testdata/example.conf \ 332 | pplib/tests/testdata/test.tif \ 333 | pplib/tests/testdata/dirwalk/testfile.txt \ 334 | pplib/tests/testdata/dirwalk/zfile.txt \ 335 | pplib/tests/testdata/dirwalk/file1.txt \ 336 | pplib/tests/testdata/dirwalk/LICENSE.TXT \ 337 | pplib/tests/testdata/dirwalk/file3.txt \ 338 | pplib/tests/testdata/dirwalk/file4äöü.txt \ 339 | pplib/tests/testdata/dirwalk/afile.txt \ 340 | pplib/tests/testdata/dirwalk/file2.txt \ 341 | pplib/tests/testdata/test.jpg \ 342 | pplib/tests/testdata/reference.png \ 343 | pplib/tests/testdata/lame_API.txt \ 344 | pplib/tests/testdata/filenameUTF8äöü.txt \ 345 | pplib/tests/testdata/tags_at_eof.aiff \ 346 | pplib/tests/testdata/test_44kHz.aiff \ 347 | pplib/tests/testdata/test_44kHz_tagged.aiff \ 348 | pplib/tests/testdata/compression.txt.gz \ 349 | pplib/tests/testdata/test_44kHz_taggedWithCover.aiff \ 350 | pplib/tests/testdata/test_192cbr.mp3 \ 351 | pplib/tests/testdata/test_44kHz.wav \ 352 | pplib/tests/testdata/test.ppm \ 353 | pplib/tests/testdata/jsontest1.json \ 354 | pplib/tests/testdata/unicodeUtf8äöü.txt \ 355 | pplib/tests/testdata/jsontest3.json \ 356 | pplib/tests/testdata/test_320cbr.mp3 \ 357 | pplib/tests/testdata/test.bmp \ 358 | pplib/tests/testdata/test-pal.png \ 359 | pplib/LICENSE.TXT \ 360 | pplib/configure \ 361 | pplib/autoconf/iconv.m4 \ 362 | pplib/autoconf/imlib.m4 \ 363 | pplib/autoconf/libidn.m4 \ 364 | pplib/autoconf/imagemagick.m4 \ 365 | pplib/autoconf/freetds.m4 \ 366 | pplib/autoconf/ax_lib_gcrypt.m4 \ 367 | pplib/autoconf/checkfuncs.m4 \ 368 | pplib/autoconf/libtiff.m4 \ 369 | pplib/autoconf/ldns.m4 \ 370 | pplib/autoconf/bzip2.m4 \ 371 | pplib/autoconf/ax_lib_crypto.m4 \ 372 | pplib/autoconf/ax_lib_sqlite3.m4 \ 373 | pplib/autoconf/lib-link.m4 \ 374 | pplib/autoconf/ax_check_compiler_flags.m4 \ 375 | pplib/autoconf/ax_path_lib_pcre.m4 \ 376 | pplib/autoconf/nasm.m4 \ 377 | pplib/autoconf/missing \ 378 | pplib/autoconf/libcdio.m4 \ 379 | pplib/autoconf/libjpeg-turbo.m4 \ 380 | pplib/autoconf/libmicrohttpd.m4 \ 381 | pplib/autoconf/ax_gcc_x86_cpuid.m4 \ 382 | pplib/autoconf/ogg.m4 \ 383 | pplib/autoconf/compile \ 384 | pplib/autoconf/ax_pthread.m4 \ 385 | pplib/autoconf/sdl2.m4 \ 386 | pplib/autoconf/ax_cxx_compile_stdcxx.m4 \ 387 | pplib/autoconf/ax_check_openssl.m4 \ 388 | pplib/autoconf/ax_lib_mysql.m4 \ 389 | pplib/autoconf/ax_lib_postgresql.m4 \ 390 | pplib/autoconf/ax_have_qt.m4 \ 391 | pplib/autoconf/ax_gcc_archflag.m4 \ 392 | pplib/autoconf/gtest.m4 \ 393 | pplib/autoconf/ax_check_zlib.m4 \ 394 | pplib/autoconf/shout.m4 \ 395 | pplib/autoconf/jpeg.m4 \ 396 | pplib/autoconf/libcurl.m4 \ 397 | pplib/autoconf/config.rpath \ 398 | pplib/autoconf/ax_cc_maxopt.m4 \ 399 | pplib/autoconf/freetype.m4 \ 400 | pplib/autoconf/install-sh \ 401 | pplib/autoconf/config.sub \ 402 | pplib/autoconf/lame.m4 \ 403 | pplib/autoconf/libbind.m4 \ 404 | pplib/autoconf/config.guess \ 405 | pplib/autoconf/libidn2.m4 \ 406 | pplib/autoconf/png.m4 \ 407 | pplib/autoconf/mpg123.m4 \ 408 | pplib/autoconf/libmcrypt.m4 \ 409 | pplib/autoconf/ax_cxx_compile_stdcxx_11.m4 \ 410 | pplib/TODO.TXT \ 411 | pplib/docs/threads.dox \ 412 | pplib/docs/credits.dox \ 413 | pplib/docs/CWikiParser_diagram.png \ 414 | pplib/docs/groups.dox \ 415 | pplib/docs/formate.dox \ 416 | pplib/docs/pcrenote.dox \ 417 | pplib/docs/CWStringSetFunctions.dox \ 418 | pplib/docs/pregexpr.dox \ 419 | pplib/docs/verwendung.dox \ 420 | pplib/docs/win32-vc9-clr.png \ 421 | pplib/docs/header-bg.png \ 422 | pplib/docs/ppl7style.css \ 423 | pplib/docs/CDrawable.png \ 424 | pplib/docs/Class_Point.png \ 425 | pplib/docs/datentypen.dox \ 426 | pplib/docs/main.dox \ 427 | pplib/docs/DoxygenLayout.xml \ 428 | pplib/docs/sprintf.dox \ 429 | pplib/docs/strftime.dox \ 430 | pplib/docs/examples/nasm.rules \ 431 | pplib/docs/examples/db_examples.cpp \ 432 | pplib/docs/examples/CThread_ThreadMain.cpp \ 433 | pplib/docs/examples/IcecastExample.cpp \ 434 | pplib/docs/examples/ppl7.m4 \ 435 | pplib/docs/installation.dox \ 436 | pplib/docs/gtest.dox \ 437 | pplib/docs/sockets.dox \ 438 | pplib/docs/icecast_status.png \ 439 | pplib/docs/formate/PFPVersion1.dox \ 440 | pplib/docs/formate/PFPVersion2.dox \ 441 | pplib/docs/formate/SocketMessage.dox \ 442 | pplib/docs/formate/PFPVersion3.dox \ 443 | pplib/docs/formate/PPLResVersion6.dox \ 444 | pplib/docs/structures.dox \ 445 | pplib/docs/header.html \ 446 | pplib/docs/win32-vc9-rl.png \ 447 | pplib/docs/datenbanken.dox \ 448 | pplib/Doxyfile \ 449 | pplib/configure.ac \ 450 | pplib/HISTORY.TXT \ 451 | pplib/acinclude.m4 \ 452 | pplib/ppl7-config.in \ 453 | pplib/resource/ppl7-icon-16x16.png \ 454 | pplib/resource/ppl7-icon-64x64.png \ 455 | pplib/resource/toolbar.png \ 456 | pplib/resource/wikistyle.css \ 457 | pplib/resource/liberationsans2.fnt6 \ 458 | pplib/resource/resourcen.lst \ 459 | pplib/resource/ppl7.ico \ 460 | pplib/resource/ppl7-icon-256x256.png \ 461 | pplib/resource/ppl7-icon-32x32.png \ 462 | pplib/resource/ButtonSymbols.png \ 463 | pplib/resource/ppl7-icon-128x128.png \ 464 | pplib/resource/ppl7-icon-48x48.png \ 465 | pplib/resource/cursor.png \ 466 | pplib/resource/makefonts.sh \ 467 | pplib/resource/mimetypes.png \ 468 | pplib/resource/liberationmono2.fnt6 \ 469 | pplib/resource/res.h \ 470 | pplib/resource/SymbolsAlpha.png \ 471 | pplib/resource/icons.png \ 472 | pplib/README.TXT 473 | -------------------------------------------------------------------------------- /m4/ax_pthread.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # https://www.gnu.org/software/autoconf-archive/ax_pthread.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # This macro figures out how to build C programs using POSIX threads. It 12 | # sets the PTHREAD_LIBS output variable to the threads library and linker 13 | # flags, and the PTHREAD_CFLAGS output variable to any special C compiler 14 | # flags that are needed. (The user can also force certain compiler 15 | # flags/libs to be tested by setting these environment variables.) 16 | # 17 | # Also sets PTHREAD_CC to any special C compiler that is needed for 18 | # multi-threaded programs (defaults to the value of CC otherwise). (This 19 | # is necessary on AIX to use the special cc_r compiler alias.) 20 | # 21 | # NOTE: You are assumed to not only compile your program with these flags, 22 | # but also to link with them as well. For example, you might link with 23 | # $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS 24 | # 25 | # If you are only building threaded programs, you may wish to use these 26 | # variables in your default LIBS, CFLAGS, and CC: 27 | # 28 | # LIBS="$PTHREAD_LIBS $LIBS" 29 | # CFLAGS="$CFLAGS $PTHREAD_CFLAGS" 30 | # CC="$PTHREAD_CC" 31 | # 32 | # In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant 33 | # has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to 34 | # that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). 35 | # 36 | # Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the 37 | # PTHREAD_PRIO_INHERIT symbol is defined when compiling with 38 | # PTHREAD_CFLAGS. 39 | # 40 | # ACTION-IF-FOUND is a list of shell commands to run if a threads library 41 | # is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it 42 | # is not found. If ACTION-IF-FOUND is not specified, the default action 43 | # will define HAVE_PTHREAD. 44 | # 45 | # Please let the authors know if this macro fails on any platform, or if 46 | # you have any other suggestions or comments. This macro was based on work 47 | # by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help 48 | # from M. Frigo), as well as ac_pthread and hb_pthread macros posted by 49 | # Alejandro Forero Cuervo to the autoconf macro repository. We are also 50 | # grateful for the helpful feedback of numerous users. 51 | # 52 | # Updated for Autoconf 2.68 by Daniel Richard G. 53 | # 54 | # LICENSE 55 | # 56 | # Copyright (c) 2008 Steven G. Johnson 57 | # Copyright (c) 2011 Daniel Richard G. 58 | # 59 | # This program is free software: you can redistribute it and/or modify it 60 | # under the terms of the GNU General Public License as published by the 61 | # Free Software Foundation, either version 3 of the License, or (at your 62 | # option) any later version. 63 | # 64 | # This program is distributed in the hope that it will be useful, but 65 | # WITHOUT ANY WARRANTY; without even the implied warranty of 66 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 67 | # Public License for more details. 68 | # 69 | # You should have received a copy of the GNU General Public License along 70 | # with this program. If not, see . 71 | # 72 | # As a special exception, the respective Autoconf Macro's copyright owner 73 | # gives unlimited permission to copy, distribute and modify the configure 74 | # scripts that are the output of Autoconf when processing the Macro. You 75 | # need not follow the terms of the GNU General Public License when using 76 | # or distributing such scripts, even though portions of the text of the 77 | # Macro appear in them. The GNU General Public License (GPL) does govern 78 | # all other use of the material that constitutes the Autoconf Macro. 79 | # 80 | # This special exception to the GPL applies to versions of the Autoconf 81 | # Macro released by the Autoconf Archive. When you make and distribute a 82 | # modified version of the Autoconf Macro, you may extend this special 83 | # exception to the GPL to apply to your modified version as well. 84 | 85 | #serial 25 86 | 87 | AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) 88 | AC_DEFUN([AX_PTHREAD], [ 89 | AC_REQUIRE([AC_CANONICAL_HOST]) 90 | AC_REQUIRE([AC_PROG_CC]) 91 | AC_REQUIRE([AC_PROG_SED]) 92 | AC_LANG_PUSH([C]) 93 | ax_pthread_ok=no 94 | 95 | # We used to check for pthread.h first, but this fails if pthread.h 96 | # requires special compiler flags (e.g. on Tru64 or Sequent). 97 | # It gets checked for in the link test anyway. 98 | 99 | # First of all, check if the user has set any of the PTHREAD_LIBS, 100 | # etcetera environment variables, and if threads linking works using 101 | # them: 102 | if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then 103 | ax_pthread_save_CC="$CC" 104 | ax_pthread_save_CFLAGS="$CFLAGS" 105 | ax_pthread_save_LIBS="$LIBS" 106 | AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"]) 107 | CFLAGS="$CFLAGS $PTHREAD_CFLAGS" 108 | LIBS="$PTHREAD_LIBS $LIBS" 109 | AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS]) 110 | AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes]) 111 | AC_MSG_RESULT([$ax_pthread_ok]) 112 | if test "x$ax_pthread_ok" = "xno"; then 113 | PTHREAD_LIBS="" 114 | PTHREAD_CFLAGS="" 115 | fi 116 | CC="$ax_pthread_save_CC" 117 | CFLAGS="$ax_pthread_save_CFLAGS" 118 | LIBS="$ax_pthread_save_LIBS" 119 | fi 120 | 121 | # We must check for the threads library under a number of different 122 | # names; the ordering is very important because some systems 123 | # (e.g. DEC) have both -lpthread and -lpthreads, where one of the 124 | # libraries is broken (non-POSIX). 125 | 126 | # Create a list of thread flags to try. Items starting with a "-" are 127 | # C compiler flags, and other items are library names, except for "none" 128 | # which indicates that we try without any flags at all, and "pthread-config" 129 | # which is a program returning the flags for the Pth emulation library. 130 | 131 | ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" 132 | 133 | # The ordering *is* (sometimes) important. Some notes on the 134 | # individual items follow: 135 | 136 | # pthreads: AIX (must check this before -lpthread) 137 | # none: in case threads are in libc; should be tried before -Kthread and 138 | # other compiler flags to prevent continual compiler warnings 139 | # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) 140 | # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64 141 | # (Note: HP C rejects this with "bad form for `-t' option") 142 | # -pthreads: Solaris/gcc (Note: HP C also rejects) 143 | # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it 144 | # doesn't hurt to check since this sometimes defines pthreads and 145 | # -D_REENTRANT too), HP C (must be checked before -lpthread, which 146 | # is present but should not be used directly; and before -mthreads, 147 | # because the compiler interprets this as "-mt" + "-hreads") 148 | # -mthreads: Mingw32/gcc, Lynx/gcc 149 | # pthread: Linux, etcetera 150 | # --thread-safe: KAI C++ 151 | # pthread-config: use pthread-config program (for GNU Pth library) 152 | 153 | case $host_os in 154 | 155 | freebsd*) 156 | 157 | # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) 158 | # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) 159 | 160 | ax_pthread_flags="-kthread lthread $ax_pthread_flags" 161 | ;; 162 | 163 | hpux*) 164 | 165 | # From the cc(1) man page: "[-mt] Sets various -D flags to enable 166 | # multi-threading and also sets -lpthread." 167 | 168 | ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" 169 | ;; 170 | 171 | openedition*) 172 | 173 | # IBM z/OS requires a feature-test macro to be defined in order to 174 | # enable POSIX threads at all, so give the user a hint if this is 175 | # not set. (We don't define these ourselves, as they can affect 176 | # other portions of the system API in unpredictable ways.) 177 | 178 | AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING], 179 | [ 180 | # if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) 181 | AX_PTHREAD_ZOS_MISSING 182 | # endif 183 | ], 184 | [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])]) 185 | ;; 186 | 187 | solaris*) 188 | 189 | # On Solaris (at least, for some versions), libc contains stubbed 190 | # (non-functional) versions of the pthreads routines, so link-based 191 | # tests will erroneously succeed. (N.B.: The stubs are missing 192 | # pthread_cleanup_push, or rather a function called by this macro, 193 | # so we could check for that, but who knows whether they'll stub 194 | # that too in a future libc.) So we'll check first for the 195 | # standard Solaris way of linking pthreads (-mt -lpthread). 196 | 197 | ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags" 198 | ;; 199 | esac 200 | 201 | # GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) 202 | 203 | AS_IF([test "x$GCC" = "xyes"], 204 | [ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"]) 205 | 206 | # The presence of a feature test macro requesting re-entrant function 207 | # definitions is, on some systems, a strong hint that pthreads support is 208 | # correctly enabled 209 | 210 | case $host_os in 211 | darwin* | hpux* | linux* | osf* | solaris*) 212 | ax_pthread_check_macro="_REENTRANT" 213 | ;; 214 | 215 | aix*) 216 | ax_pthread_check_macro="_THREAD_SAFE" 217 | ;; 218 | 219 | *) 220 | ax_pthread_check_macro="--" 221 | ;; 222 | esac 223 | AS_IF([test "x$ax_pthread_check_macro" = "x--"], 224 | [ax_pthread_check_cond=0], 225 | [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"]) 226 | 227 | # Are we compiling with Clang? 228 | 229 | AC_CACHE_CHECK([whether $CC is Clang], 230 | [ax_cv_PTHREAD_CLANG], 231 | [ax_cv_PTHREAD_CLANG=no 232 | # Note that Autoconf sets GCC=yes for Clang as well as GCC 233 | if test "x$GCC" = "xyes"; then 234 | AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG], 235 | [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ 236 | # if defined(__clang__) && defined(__llvm__) 237 | AX_PTHREAD_CC_IS_CLANG 238 | # endif 239 | ], 240 | [ax_cv_PTHREAD_CLANG=yes]) 241 | fi 242 | ]) 243 | ax_pthread_clang="$ax_cv_PTHREAD_CLANG" 244 | 245 | ax_pthread_clang_warning=no 246 | 247 | # Clang needs special handling, because older versions handle the -pthread 248 | # option in a rather... idiosyncratic way 249 | 250 | if test "x$ax_pthread_clang" = "xyes"; then 251 | 252 | # Clang takes -pthread; it has never supported any other flag 253 | 254 | # (Note 1: This will need to be revisited if a system that Clang 255 | # supports has POSIX threads in a separate library. This tends not 256 | # to be the way of modern systems, but it's conceivable.) 257 | 258 | # (Note 2: On some systems, notably Darwin, -pthread is not needed 259 | # to get POSIX threads support; the API is always present and 260 | # active. We could reasonably leave PTHREAD_CFLAGS empty. But 261 | # -pthread does define _REENTRANT, and while the Darwin headers 262 | # ignore this macro, third-party headers might not.) 263 | 264 | PTHREAD_CFLAGS="-pthread" 265 | PTHREAD_LIBS= 266 | 267 | ax_pthread_ok=yes 268 | 269 | # However, older versions of Clang make a point of warning the user 270 | # that, in an invocation where only linking and no compilation is 271 | # taking place, the -pthread option has no effect ("argument unused 272 | # during compilation"). They expect -pthread to be passed in only 273 | # when source code is being compiled. 274 | # 275 | # Problem is, this is at odds with the way Automake and most other 276 | # C build frameworks function, which is that the same flags used in 277 | # compilation (CFLAGS) are also used in linking. Many systems 278 | # supported by AX_PTHREAD require exactly this for POSIX threads 279 | # support, and in fact it is often not straightforward to specify a 280 | # flag that is used only in the compilation phase and not in 281 | # linking. Such a scenario is extremely rare in practice. 282 | # 283 | # Even though use of the -pthread flag in linking would only print 284 | # a warning, this can be a nuisance for well-run software projects 285 | # that build with -Werror. So if the active version of Clang has 286 | # this misfeature, we search for an option to squash it. 287 | 288 | AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread], 289 | [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG], 290 | [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown 291 | # Create an alternate version of $ac_link that compiles and 292 | # links in two steps (.c -> .o, .o -> exe) instead of one 293 | # (.c -> exe), because the warning occurs only in the second 294 | # step 295 | ax_pthread_save_ac_link="$ac_link" 296 | ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' 297 | ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"` 298 | ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" 299 | ax_pthread_save_CFLAGS="$CFLAGS" 300 | for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do 301 | AS_IF([test "x$ax_pthread_try" = "xunknown"], [break]) 302 | CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" 303 | ac_link="$ax_pthread_save_ac_link" 304 | AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], 305 | [ac_link="$ax_pthread_2step_ac_link" 306 | AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], 307 | [break]) 308 | ]) 309 | done 310 | ac_link="$ax_pthread_save_ac_link" 311 | CFLAGS="$ax_pthread_save_CFLAGS" 312 | AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no]) 313 | ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" 314 | ]) 315 | 316 | case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in 317 | no | unknown) ;; 318 | *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; 319 | esac 320 | 321 | fi # $ax_pthread_clang = yes 322 | 323 | if test "x$ax_pthread_ok" = "xno"; then 324 | for ax_pthread_try_flag in $ax_pthread_flags; do 325 | 326 | case $ax_pthread_try_flag in 327 | none) 328 | AC_MSG_CHECKING([whether pthreads work without any flags]) 329 | ;; 330 | 331 | -mt,pthread) 332 | AC_MSG_CHECKING([whether pthreads work with -mt -lpthread]) 333 | PTHREAD_CFLAGS="-mt" 334 | PTHREAD_LIBS="-lpthread" 335 | ;; 336 | 337 | -*) 338 | AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag]) 339 | PTHREAD_CFLAGS="$ax_pthread_try_flag" 340 | ;; 341 | 342 | pthread-config) 343 | AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) 344 | AS_IF([test "x$ax_pthread_config" = "xno"], [continue]) 345 | PTHREAD_CFLAGS="`pthread-config --cflags`" 346 | PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" 347 | ;; 348 | 349 | *) 350 | AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag]) 351 | PTHREAD_LIBS="-l$ax_pthread_try_flag" 352 | ;; 353 | esac 354 | 355 | ax_pthread_save_CFLAGS="$CFLAGS" 356 | ax_pthread_save_LIBS="$LIBS" 357 | CFLAGS="$CFLAGS $PTHREAD_CFLAGS" 358 | LIBS="$PTHREAD_LIBS $LIBS" 359 | 360 | # Check for various functions. We must include pthread.h, 361 | # since some functions may be macros. (On the Sequent, we 362 | # need a special flag -Kthread to make this header compile.) 363 | # We check for pthread_join because it is in -lpthread on IRIX 364 | # while pthread_create is in libc. We check for pthread_attr_init 365 | # due to DEC craziness with -lpthreads. We check for 366 | # pthread_cleanup_push because it is one of the few pthread 367 | # functions on Solaris that doesn't have a non-functional libc stub. 368 | # We try pthread_create on general principles. 369 | 370 | AC_LINK_IFELSE([AC_LANG_PROGRAM([#include 371 | # if $ax_pthread_check_cond 372 | # error "$ax_pthread_check_macro must be defined" 373 | # endif 374 | static void routine(void *a) { a = 0; } 375 | static void *start_routine(void *a) { return a; }], 376 | [pthread_t th; pthread_attr_t attr; 377 | pthread_create(&th, 0, start_routine, 0); 378 | pthread_join(th, 0); 379 | pthread_attr_init(&attr); 380 | pthread_cleanup_push(routine, 0); 381 | pthread_cleanup_pop(0) /* ; */])], 382 | [ax_pthread_ok=yes], 383 | []) 384 | 385 | CFLAGS="$ax_pthread_save_CFLAGS" 386 | LIBS="$ax_pthread_save_LIBS" 387 | 388 | AC_MSG_RESULT([$ax_pthread_ok]) 389 | AS_IF([test "x$ax_pthread_ok" = "xyes"], [break]) 390 | 391 | PTHREAD_LIBS="" 392 | PTHREAD_CFLAGS="" 393 | done 394 | fi 395 | 396 | # Various other checks: 397 | if test "x$ax_pthread_ok" = "xyes"; then 398 | ax_pthread_save_CFLAGS="$CFLAGS" 399 | ax_pthread_save_LIBS="$LIBS" 400 | CFLAGS="$CFLAGS $PTHREAD_CFLAGS" 401 | LIBS="$PTHREAD_LIBS $LIBS" 402 | 403 | # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. 404 | AC_CACHE_CHECK([for joinable pthread attribute], 405 | [ax_cv_PTHREAD_JOINABLE_ATTR], 406 | [ax_cv_PTHREAD_JOINABLE_ATTR=unknown 407 | for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do 408 | AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], 409 | [int attr = $ax_pthread_attr; return attr /* ; */])], 410 | [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break], 411 | []) 412 | done 413 | ]) 414 | AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ 415 | test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ 416 | test "x$ax_pthread_joinable_attr_defined" != "xyes"], 417 | [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], 418 | [$ax_cv_PTHREAD_JOINABLE_ATTR], 419 | [Define to necessary symbol if this constant 420 | uses a non-standard name on your system.]) 421 | ax_pthread_joinable_attr_defined=yes 422 | ]) 423 | 424 | AC_CACHE_CHECK([whether more special flags are required for pthreads], 425 | [ax_cv_PTHREAD_SPECIAL_FLAGS], 426 | [ax_cv_PTHREAD_SPECIAL_FLAGS=no 427 | case $host_os in 428 | solaris*) 429 | ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" 430 | ;; 431 | esac 432 | ]) 433 | AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ 434 | test "x$ax_pthread_special_flags_added" != "xyes"], 435 | [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" 436 | ax_pthread_special_flags_added=yes]) 437 | 438 | AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], 439 | [ax_cv_PTHREAD_PRIO_INHERIT], 440 | [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], 441 | [[int i = PTHREAD_PRIO_INHERIT; 442 | return i;]])], 443 | [ax_cv_PTHREAD_PRIO_INHERIT=yes], 444 | [ax_cv_PTHREAD_PRIO_INHERIT=no]) 445 | ]) 446 | AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ 447 | test "x$ax_pthread_prio_inherit_defined" != "xyes"], 448 | [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.]) 449 | ax_pthread_prio_inherit_defined=yes 450 | ]) 451 | 452 | CFLAGS="$ax_pthread_save_CFLAGS" 453 | LIBS="$ax_pthread_save_LIBS" 454 | 455 | # More AIX lossage: compile with *_r variant 456 | if test "x$GCC" != "xyes"; then 457 | case $host_os in 458 | aix*) 459 | AS_CASE(["x/$CC"], 460 | [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], 461 | [#handle absolute path differently from PATH based program lookup 462 | AS_CASE(["x$CC"], 463 | [x/*], 464 | [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], 465 | [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) 466 | ;; 467 | esac 468 | fi 469 | fi 470 | 471 | test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" 472 | 473 | AC_SUBST([PTHREAD_LIBS]) 474 | AC_SUBST([PTHREAD_CFLAGS]) 475 | AC_SUBST([PTHREAD_CC]) 476 | 477 | # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: 478 | if test "x$ax_pthread_ok" = "xyes"; then 479 | ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) 480 | : 481 | else 482 | ax_pthread_ok=no 483 | $2 484 | fi 485 | AC_LANG_POP 486 | ])dnl AX_PTHREAD 487 | -------------------------------------------------------------------------------- /src/dns_sender.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2021, OARC, Inc. 3 | * Copyright (c) 2019, DENIC eG 4 | * All rights reserved. 5 | * 6 | * This file is part of dnsmeter. 7 | * 8 | * dnsmeter is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * dnsmeter is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with dnsmeter. If not, see . 20 | */ 21 | 22 | #include "config.h" 23 | 24 | #include "dns_sender.h" 25 | #include "exceptions.h" 26 | #include "dns_sender_thread.h" 27 | 28 | #include 29 | #include 30 | 31 | static const char* rcode_names[] = { 32 | "OK", "FORMAT", "SRVFAIL", "NAME", "NOTIMPL", "REFUSED", 33 | "YXDOMAIN", "YXRRSET", "NXRRSET", "NOTAUTH", "NOTZONE", 34 | "11", "12", "13", "14", "15", 35 | NULL 36 | }; 37 | 38 | bool stopFlag = false; 39 | 40 | void sighandler(int sig) 41 | { 42 | stopFlag = true; 43 | printf("Stopping...\n"); 44 | } 45 | 46 | void DNSSender::help() 47 | { 48 | ppl7::String name, underline; 49 | name.setf("dnsmeter %s", PACKAGE_VERSION); 50 | underline.repeat("=", name.size()); 51 | name.printnl(); 52 | underline.printnl(); 53 | printf("\nUsage:\n" 54 | " -h shows this help\n" 55 | " -q HOST hostname or IP address of sender if you don't want to spoof\n" 56 | " (see -s)\n" 57 | " -s NET|pcap spoof sender address. Use random IP from the given network\n" 58 | " (example: 192.168.0.0/16). Only works when running as root!\n" 59 | " If payload is a pcap file, you can use \"-s pcap\" to use the\n" 60 | " source addresses and ports from the pcap file.\n" 61 | " -e ETH interface on which the packet receiver should listen\n" 62 | " (FreeBSD only)\n" 63 | " -z HOST:PORT hostname or IP address and port of the target nameserver\n" 64 | " -p FILE file with queries/payload or pcap file\n" 65 | " -l # runtime in seconds (default=10 seconds)\n" 66 | " -t # timeout in seconds (default=2 seconds)\n" 67 | " -n # number of worker threads (default=1)\n" 68 | " -r # queryrate (Default=as much as possible)\n" 69 | " can be a single value, a comma separated list (rate,rate,...)\n" 70 | " or a range and a step value (start - end, step)\n" 71 | " -d # amount of queries in percent on which the DNSSEC-flags are set\n" 72 | " (default=0)\n" 73 | " -c FILE CSV-file for results\n" 74 | " --ignore answers are ignored and therefor not counted. In this mode\n" 75 | " the tool only generates traffic." 76 | "\n"); 77 | } 78 | 79 | DNSSender::Results::Results() 80 | { 81 | queryrate = 0; 82 | counter_send = 0; 83 | counter_received = 0; 84 | bytes_send = 0; 85 | bytes_received = 0; 86 | counter_errors = 0; 87 | packages_lost = 0; 88 | counter_0bytes = 0; 89 | for (int i = 0; i < 255; i++) 90 | counter_errorcodes[i] = 0; 91 | rtt_avg = 0.0f; 92 | rtt_total = 0.0f; 93 | rtt_min = 0.0f; 94 | rtt_max = 0.0f; 95 | for (int i = 0; i < 16; i++) 96 | rcodes[i] = 0; 97 | truncated = 0; 98 | } 99 | 100 | void DNSSender::Results::clear() 101 | { 102 | queryrate = 0; 103 | counter_send = 0; 104 | counter_received = 0; 105 | bytes_send = 0; 106 | bytes_received = 0; 107 | counter_errors = 0; 108 | packages_lost = 0; 109 | counter_0bytes = 0; 110 | for (int i = 0; i < 255; i++) 111 | counter_errorcodes[i] = 0; 112 | rtt_avg = 0.0f; 113 | rtt_total = 0.0f; 114 | rtt_min = 0.0f; 115 | rtt_max = 0.0f; 116 | for (int i = 0; i < 16; i++) 117 | rcodes[i] = 0; 118 | truncated = 0; 119 | } 120 | 121 | DNSSender::Results operator-(const DNSSender::Results& second, const DNSSender::Results& first) 122 | { 123 | DNSSender::Results r; 124 | r.queryrate = second.queryrate - first.queryrate; 125 | r.counter_send = second.counter_send - first.counter_send; 126 | r.counter_received = second.counter_received - first.counter_received; 127 | r.bytes_send = second.bytes_send - first.bytes_send; 128 | r.bytes_received = second.bytes_received - first.bytes_received; 129 | r.counter_errors = second.counter_errors - first.counter_errors; 130 | r.packages_lost = second.packages_lost - first.packages_lost; 131 | r.counter_0bytes = second.counter_0bytes - first.counter_0bytes; 132 | for (int i = 0; i < 255; i++) 133 | r.counter_errorcodes[i] = second.counter_errorcodes[i] - first.counter_errorcodes[i]; 134 | r.rtt_total = second.rtt_total - first.rtt_total; 135 | if (r.counter_received) 136 | r.rtt_avg = r.rtt_total / r.counter_received; //NOSONAR 137 | else 138 | r.rtt_avg = 0.0; 139 | r.rtt_min = second.rtt_min - first.rtt_min; 140 | r.rtt_max = second.rtt_max - first.rtt_max; 141 | 142 | for (int i = 0; i < 16; i++) 143 | r.rcodes[i] = second.rcodes[i] - first.rcodes[i]; 144 | r.truncated = second.truncated - first.truncated; 145 | return r; 146 | } 147 | 148 | DNSSender::DNSSender() 149 | { 150 | ppl7::InitSockets(); 151 | Runtime = 10; 152 | Timeout = 2; 153 | ThreadCount = 1; 154 | Timeslices = 1.0f; 155 | ignoreResponses = false; 156 | DnssecRate = 0; 157 | TargetPort = 53; 158 | spoofingEnabled = false; 159 | Receiver = NULL; 160 | spoofFromPcap = false; 161 | } 162 | 163 | DNSSender::~DNSSender() 164 | { 165 | if (Receiver) 166 | delete Receiver; 167 | } 168 | 169 | ppl7::Array DNSSender::getQueryRates(const ppl7::String& QueryRates) 170 | { 171 | ppl7::Array rates; 172 | if (QueryRates.isEmpty()) { 173 | rates.add("0"); 174 | } else { 175 | ppl7::Array matches; 176 | if (QueryRates.pregMatch("/^([0-9]+)-([0-9]+),([0-9]+)$", matches)) { 177 | for (ppluint64 i = matches[1].toUnsignedInt64(); i <= matches[2].toUnsignedInt64(); i += matches[3].toUnsignedInt64()) { 178 | rates.addf("%llu", i); 179 | } 180 | } else { 181 | rates.explode(QueryRates, ","); 182 | } 183 | } 184 | return rates; 185 | } 186 | 187 | void DNSSender::getTarget(int argc, char** argv) 188 | { 189 | if (!ppl7::HaveArgv(argc, argv, "-z")) { 190 | throw MissingCommandlineParameter("target IP/hostname or port missing (-z IP:PORT)"); 191 | } 192 | ppl7::String Tmp = ppl7::GetArgv(argc, argv, "-z"); 193 | ppl7::Array Tok(Tmp, ":"); 194 | if (Tok.size() != 2) { 195 | if (Tok.size() != 1) 196 | throw InvalidCommandlineParameter("-z IP:PORT"); 197 | TargetPort = 53; 198 | } else { 199 | TargetPort = Tok[1].toInt(); 200 | } 201 | if (TargetPort < 1 || TargetPort > 65535) 202 | throw InvalidCommandlineParameter("-z IP:PORT, Invalid Port"); 203 | std::list Result; 204 | size_t num = ppl7::GetHostByName(Tok[0], Result, ppl7::af_inet); 205 | if (!num) 206 | throw InvalidCommandlineParameter("-z IP:PORT, Invalid IP or could not resolve Hostname"); 207 | TargetIP = Result.front(); 208 | //printf ("num=%d, %s\n",num, (const char*)TargetIP.toString()); 209 | } 210 | 211 | void DNSSender::getSource(int argc, char** argv) 212 | { 213 | if (ppl7::HaveArgv(argc, argv, "-s")) { 214 | ppl7::String Tmp = ppl7::GetArgv(argc, argv, "-s").toLowerCase(); 215 | if (Tmp == "pcap") { 216 | spoofFromPcap = true; 217 | } else { 218 | SourceNet.set(Tmp); 219 | if (SourceNet.family() != ppl7::IPAddress::IPv4) 220 | throw UnsupportedIPFamily("only IPv4 works"); 221 | } 222 | spoofingEnabled = true; 223 | } else { 224 | ppl7::String Tmp = ppl7::GetArgv(argc, argv, "-q"); 225 | std::list Result; 226 | size_t num = ppl7::GetHostByName(Tmp, Result, ppl7::af_inet); 227 | if (!num) 228 | throw InvalidCommandlineParameter("-q HOST, Invalid IP or could not resolve Hostname"); 229 | SourceIP = Result.front(); 230 | if (SourceIP.family() != ppl7::IPAddress::IPv4) 231 | throw UnsupportedIPFamily("only IPv4 works"); 232 | spoofingEnabled = false; 233 | } 234 | } 235 | 236 | int DNSSender::getParameter(int argc, char** argv) 237 | { 238 | if (ppl7::HaveArgv(argc, argv, "-q") && ppl7::HaveArgv(argc, argv, "-s")) { 239 | printf("ERROR: could not use parameters -q and -s together\n\n"); 240 | help(); 241 | return 1; 242 | } 243 | if ((!ppl7::HaveArgv(argc, argv, "-q")) && (!ppl7::HaveArgv(argc, argv, "-s"))) { 244 | printf("ERROR: source IP/hostname or network for source address spoofing missing (-q IP | -s NETWORK)\n\n"); 245 | help(); 246 | return 1; 247 | } 248 | ignoreResponses = ppl7::HaveArgv(argc, argv, "--ignore"); 249 | 250 | if (ppl7::HaveArgv(argc, argv, "-e")) { 251 | InterfaceName = ppl7::GetArgv(argc, argv, "-e"); 252 | } 253 | 254 | try { 255 | getTarget(argc, argv); 256 | getSource(argc, argv); 257 | } catch (const ppl7::Exception& e) { 258 | printf("ERROR: missing or invalid parameter\n"); 259 | e.print(); 260 | printf("\n"); 261 | help(); 262 | return 1; 263 | } 264 | 265 | Runtime = ppl7::GetArgv(argc, argv, "-l").toInt(); 266 | Timeout = ppl7::GetArgv(argc, argv, "-t").toInt(); 267 | ThreadCount = ppl7::GetArgv(argc, argv, "-n").toInt(); 268 | ppl7::String QueryRates = ppl7::GetArgv(argc, argv, "-r"); 269 | CSVFileName = ppl7::GetArgv(argc, argv, "-c"); 270 | QueryFilename = ppl7::GetArgv(argc, argv, "-p"); 271 | if (ppl7::HaveArgv(argc, argv, "-d")) { 272 | DnssecRate = ppl7::GetArgv(argc, argv, "-d").toInt(); 273 | if (DnssecRate < 0 || DnssecRate > 100) { 274 | printf("ERROR: DNSSEC-Rate must be an integer between 0 and 100 (-d #)\n\n"); 275 | help(); 276 | return 1; 277 | } 278 | } 279 | if (!ThreadCount) 280 | ThreadCount = 1; 281 | if (!Runtime) 282 | Runtime = 10; 283 | if (!Timeout) 284 | Timeout = 2; 285 | if (QueryFilename.isEmpty()) { 286 | printf("ERROR: Payload-File is missing (-p FILENAME)\n\n"); 287 | help(); 288 | return 1; 289 | } 290 | rates = getQueryRates(QueryRates); 291 | return 0; 292 | } 293 | 294 | int DNSSender::openFiles() 295 | { 296 | if (CSVFileName.notEmpty()) { 297 | try { 298 | openCSVFile(CSVFileName); 299 | } catch (const ppl7::Exception& e) { 300 | printf("ERROR: could not open CSV-file for writing\n"); 301 | e.print(); 302 | return 1; 303 | } 304 | } 305 | try { 306 | payload.openQueryFile(QueryFilename); 307 | } catch (const ppl7::Exception& e) { 308 | printf("ERROR: could not open payload file or it does not contain any queries\n"); 309 | e.print(); 310 | return 1; 311 | } 312 | return 0; 313 | } 314 | 315 | int DNSSender::main(int argc, char** argv) 316 | { 317 | if (ppl7::HaveArgv(argc, argv, "-h") || ppl7::HaveArgv(argc, argv, "--help") || argc < 2) { 318 | help(); 319 | return 0; 320 | } 321 | if (getParameter(argc, argv) != 0) 322 | return 1; 323 | if (openFiles() != 0) 324 | return 1; 325 | 326 | signal(SIGINT, sighandler); 327 | signal(SIGKILL, sighandler); 328 | 329 | DNSSender::Results results; 330 | try { 331 | if (!ignoreResponses) { 332 | Receiver = new DNSReceiverThread(); 333 | Receiver->setSource(TargetIP, TargetPort); 334 | try { 335 | Receiver->setInterface(InterfaceName); 336 | } catch (const ppl7::Exception& e) { 337 | printf("ERROR: could not bind on device [%s]\n", (const char*)InterfaceName); 338 | e.print(); 339 | printf("\n"); 340 | help(); 341 | return 1; 342 | } 343 | } 344 | prepareThreads(); 345 | for (size_t i = 0; i < rates.size(); i++) { 346 | results.queryrate = rates[i].toInt(); 347 | run(rates[i].toInt()); 348 | getResults(results); 349 | presentResults(results); 350 | saveResultsToCsv(results); 351 | } 352 | threadpool.destroyAllThreads(); 353 | } catch (const ppl7::OperationInterruptedException&) { 354 | getResults(results); 355 | presentResults(results); 356 | saveResultsToCsv(results); 357 | } catch (const ppl7::Exception& e) { 358 | e.print(); 359 | return 1; 360 | } 361 | return 0; 362 | } 363 | 364 | void DNSSender::prepareThreads() 365 | { 366 | for (int i = 0; i < ThreadCount; i++) { 367 | DNSSenderThread* thread = new DNSSenderThread(); 368 | thread->setDestination(TargetIP, TargetPort); 369 | thread->setRuntime(Runtime); 370 | thread->setTimeout(Timeout); 371 | thread->setTimeslice(Timeslices); 372 | thread->setDNSSECRate(DnssecRate); 373 | thread->setVerbose(false); 374 | thread->setPayload(payload); 375 | if (spoofingEnabled) { 376 | if (spoofFromPcap) 377 | thread->setSourcePcap(); 378 | else 379 | thread->setSourceNet(SourceNet); 380 | } else { 381 | thread->setSourceIP(SourceIP); 382 | } 383 | threadpool.addThread(thread); 384 | } 385 | } 386 | 387 | void DNSSender::openCSVFile(const ppl7::String& Filename) 388 | { 389 | CSVFile.open(Filename, ppl7::File::APPEND); 390 | if (CSVFile.size() == 0) { 391 | CSVFile.putsf("#QPS Send; QPS Received; QPS Errors; Lostrate; " 392 | "rtt_avg; rtt_min; rtt_max;" 393 | "\n"); 394 | CSVFile.flush(); 395 | } 396 | } 397 | 398 | void DNSSender::showCurrentStats(ppl7::ppl_time_t start_time) 399 | { 400 | DNSSender::Results result, diff; 401 | ppl7::ppl_time_t runtime = ppl7::GetTime() - start_time; 402 | getResults(result); 403 | diff = result - vis_prev_results; 404 | vis_prev_results = result; 405 | 406 | int h = (int)(runtime / 3600); 407 | runtime -= h * 3600; 408 | int m = (int)(runtime / 60); 409 | int s = runtime - (m * 60); 410 | 411 | printf("%02d:%02d:%02d Queries send: %7llu, rcv: %7llu, ", h, m, s, 412 | diff.counter_send, diff.counter_received); 413 | printf("Data send: %6llu KB, rcv: %6llu KB", diff.bytes_send / 1024, diff.bytes_received / 1024); 414 | printf("\n"); 415 | } 416 | 417 | void DNSSender::calcTimeslice(int queryrate) 418 | { 419 | Timeslices = (1000.0f / queryrate) * ThreadCount; //NOSONAR 420 | //if (Zeitscheibe<1.0f) Zeitscheibe=1.0f; 421 | if (Timeslices < 0.1f) 422 | Timeslices = 0.1f; 423 | } 424 | 425 | void DNSSender::run(int queryrate) 426 | { 427 | printf("###############################################################################\n"); 428 | if (queryrate) { 429 | calcTimeslice(queryrate); 430 | printf("# Start Session with Threads: %d, Queryrate: %d, Timeslot: %0.6f ms\n", 431 | ThreadCount, queryrate, Timeslices); 432 | } else { 433 | printf("# Start Session with Threads: %d, Queryrate: unlimited\n", 434 | ThreadCount); 435 | } 436 | 437 | ppl7::ThreadPool::iterator it; 438 | for (it = threadpool.begin(); it != threadpool.end(); ++it) { 439 | ((DNSSenderThread*)(*it))->setQueryRate(queryrate / ThreadCount); 440 | ((DNSSenderThread*)(*it))->setTimeslice(Timeslices); 441 | } 442 | vis_prev_results.clear(); 443 | sampleSensorData(sys1); 444 | if (Receiver) 445 | Receiver->threadStart(); 446 | threadpool.startThreads(); 447 | ppl7::ppl_time_t start = ppl7::GetTime(); 448 | ppl7::ppl_time_t report = start + 1; 449 | ppl7::MSleep(500); 450 | while (threadpool.running() == true && stopFlag == false) { 451 | ppl7::MSleep(100); 452 | ppl7::ppl_time_t now = ppl7::GetTime(); 453 | if (now >= report) { 454 | report = now + 1; 455 | showCurrentStats(start); 456 | } 457 | } 458 | if (Receiver) 459 | Receiver->threadStop(); 460 | sampleSensorData(sys2); 461 | if (stopFlag == true) { 462 | threadpool.stopThreads(); 463 | throw ppl7::OperationInterruptedException("test aborted"); 464 | } 465 | } 466 | 467 | void DNSSender::getResults(DNSSender::Results& result) 468 | { 469 | ppl7::ThreadPool::iterator it; 470 | result.clear(); 471 | 472 | for (it = threadpool.begin(); it != threadpool.end(); ++it) { 473 | result.counter_send += ((DNSSenderThread*)(*it))->getPacketsSend(); 474 | result.bytes_send += ((DNSSenderThread*)(*it))->getBytesSend(); 475 | result.counter_errors += ((DNSSenderThread*)(*it))->getErrors(); 476 | result.counter_0bytes += ((DNSSenderThread*)(*it))->getCounter0Bytes(); 477 | for (int i = 0; i < 255; i++) 478 | result.counter_errorcodes[i] += ((DNSSenderThread*)(*it))->getCounterErrorCode(i); 479 | } 480 | if (Receiver) { 481 | const RawSocketReceiver::Counter& counter = Receiver->getCounter(); 482 | result.counter_received = counter.num_pkgs; 483 | result.bytes_received = counter.bytes_rcv; 484 | result.rtt_total = counter.rtt_total; 485 | if (counter.num_pkgs) 486 | result.rtt_avg = counter.rtt_total / counter.num_pkgs; //NOSONAR 487 | else 488 | result.rtt_avg = 0.0; 489 | result.rtt_min = counter.rtt_min; 490 | result.rtt_max = counter.rtt_max; 491 | for (int i = 0; i < 16; i++) 492 | result.rcodes[i] = counter.rcodes[i]; 493 | result.truncated = counter.truncated; 494 | } 495 | 496 | result.packages_lost = result.counter_send - result.counter_received; 497 | if (result.counter_received > result.counter_send) 498 | result.packages_lost = 0; 499 | } 500 | 501 | void DNSSender::saveResultsToCsv(const DNSSender::Results& result) 502 | { 503 | 504 | if (CSVFile.isOpen()) { 505 | CSVFile.putsf("%llu;%llu;%llu;%0.3f;%0.4f;%0.4f;%0.4f;\n", 506 | (ppluint64)((double)result.counter_send / (double)Runtime), 507 | (ppluint64)((double)result.counter_received / (double)Runtime), 508 | (ppluint64)((double)result.counter_errors / (double)Runtime), 509 | (double)result.packages_lost * 100.0 / (double)result.counter_send, 510 | result.rtt_avg * 1000.0, 511 | result.rtt_min * 1000.0, 512 | result.rtt_max * 1000.0); 513 | CSVFile.flush(); 514 | } 515 | } 516 | 517 | void DNSSender::presentResults(const DNSSender::Results& result) 518 | { 519 | printf("===============================================================================\n"); 520 | const SystemStat::Interface& net1 = sys1.interfaces[InterfaceName]; 521 | const SystemStat::Interface& net2 = sys2.interfaces[InterfaceName]; 522 | SystemStat::Network transmit = SystemStat::Network::getDelta(net1.transmit, net2.transmit); 523 | SystemStat::Network received = SystemStat::Network::getDelta(net1.receive, net2.receive); 524 | printf("network if %s Pkt send: %lu, rcv: %lu, Data send: %lu KB, rcv: %lu KB\n", 525 | (const char*)InterfaceName, 526 | transmit.packets, received.packets, transmit.bytes / 1024, received.bytes / 1024); 527 | 528 | ppluint64 qps_send = (ppluint64)((double)result.counter_send / (double)Runtime); 529 | ppluint64 bps_send = (ppluint64)((double)result.bytes_send / (double)Runtime); 530 | ppluint64 qps_received = (ppluint64)((double)result.counter_received / (double)Runtime); 531 | ppluint64 bps_received = (ppluint64)((double)result.bytes_received / (double)Runtime); 532 | 533 | printf("DNS Queries send: %10llu, Qps: %7llu, Data send: %7llu KB = %6llu MBit\n", 534 | result.counter_send, qps_send, result.bytes_send / 1024, bps_send / (1024 * 1024)); 535 | 536 | printf("DNS Queries rcv: %10llu, Qps: %7llu, Data rcv: %7llu KB = %6llu MBit\n", 537 | result.counter_received, qps_received, result.bytes_received / 1024, bps_received / (1024 * 1024)); 538 | 539 | printf("DNS Queries lost: %10llu = %0.3f %%\n", result.packages_lost, 540 | (double)result.packages_lost * 100.0 / (double)result.counter_send); 541 | 542 | printf("DNS rtt average: %0.4f ms, " 543 | "min: %0.4f ms, " 544 | "max: %0.4f ms\n", 545 | result.rtt_avg * 1000.0, 546 | result.rtt_min * 1000.0, 547 | result.rtt_max * 1000.0); 548 | printf("DNS truncated: %llu\nDNS RCODES: ", result.truncated); 549 | for (int i = 0; i < 15; i++) { 550 | if (result.rcodes[i]) { 551 | printf("%s: %llu, ", rcode_names[i], result.rcodes[i]); 552 | } 553 | } 554 | printf("\n"); 555 | 556 | if (result.counter_errors) { 557 | printf("Errors: %10llu, Qps: %10llu\n", result.counter_errors, 558 | (ppluint64)((double)result.counter_errors / (double)Runtime)); 559 | } 560 | if (result.counter_0bytes) { 561 | printf("Errors 0Byte: %10llu, Qps: %10llu\n", result.counter_0bytes, 562 | (ppluint64)((double)result.counter_0bytes / (double)Runtime)); 563 | } 564 | for (int i = 0; i < 255; i++) { 565 | if (result.counter_errorcodes[i] > 0) { 566 | printf("Errors %3d: %10llu, Qps: %10llu [%s]\n", i, result.counter_errorcodes[i], 567 | (ppluint64)((double)result.counter_errorcodes[i] / (double)Runtime), 568 | strerror(i)); 569 | } 570 | } 571 | } 572 | --------------------------------------------------------------------------------