Merging upstream version 1.2.1.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-09 08:31:51 +01:00
parent 9ce9cc1418
commit cc381791fc
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
340 changed files with 71346 additions and 6734 deletions

View file

@ -24,11 +24,11 @@ SUBDIRS = test
AM_CFLAGS = -Werror=attributes \
-I$(srcdir) \
-I$(top_srcdir) \
-I$(top_srcdir)/include \
$(SIMD_FLAGS) $(CPUEXT_FLAGS) \
$(PTHREAD_CFLAGS) \
$(luajit_CFLAGS) \
$(libuv_CFLAGS) \
$(libnghttp2_CFLAGS)
$(liblz4_CFLAGS) $(libzstd_CFLAGS)
EXTRA_DIST = gen-manpage.lua gen-compat.lua gen-errno.sh dnsjit.1in
@ -37,23 +37,24 @@ BUILT_SOURCES = core/compat.hh core/log_errstr.c
bin_PROGRAMS = dnsjit
dnsjit_SOURCES = dnsjit.c globals.c
dist_dnsjit_SOURCES = core.lua lib.lua input.lua filter.lua globals.h \
output.lua
dist_dnsjit_SOURCES = core.lua lib.lua input.lua filter.lua output.lua
dnsjitincludedir = $(includedir)/dnsjit
nobase_dnsjitinclude_HEADERS = globals.h version.h
lua_hobjects = core/compat.luaho
lua_objects = core.luao lib.luao input.luao filter.luao output.luao
dnsjit_LDADD = $(PTHREAD_LIBS) $(luajit_LIBS) $(libuv_LIBS) $(libnghttp2_LIBS)
dnsjit_LDADD = $(PTHREAD_LIBS) $(luajit_LIBS) $(liblz4_LIBS) $(libzstd_LIBS)
# C source and headers
dnsjit_SOURCES += core/channel.c core/compat.c core/log.c core/object.c core/object/dns.c core/object/ether.c core/object/gre.c core/object/icmp6.c core/object/icmp.c core/object/ieee802.c core/object/ip6.c core/object/ip.c core/object/linuxsll.c core/object/loop.c core/object/null.c core/object/payload.c core/object/pcap.c core/object/tcp.c core/object/udp.c core/producer.c core/receiver.c core/thread.c filter/copy.c filter/ipsplit.c filter/layer.c filter/split.c filter/timing.c input/fpcap.c input/mmpcap.c input/pcap.c input/zero.c lib/base64url.c lib/clock.c lib/trie.c output/dnscli.c output/dnssim.c output/dnssim/common.c output/dnssim/connection.c output/dnssim/https2.c output/dnssim/tcp.c output/dnssim/tls.c output/dnssim/udp.c output/null.c output/pcap.c output/respdiff.c output/tcpcli.c output/tlscli.c output/udpcli.c
dist_dnsjit_SOURCES += core/assert.h core/channel.h core/compat.h core/log.h core/object/dns.h core/object/ether.h core/object/gre.h core/object.h core/object/icmp6.h core/object/icmp.h core/object/ieee802.h core/object/ip6.h core/object/ip.h core/object/linuxsll.h core/object/loop.h core/object/null.h core/object/payload.h core/object/pcap.h core/object/tcp.h core/object/udp.h core/producer.h core/receiver.h core/thread.h core/timespec.h filter/copy.h filter/ipsplit.h filter/layer.h filter/split.h filter/timing.h input/fpcap.h input/mmpcap.h input/pcap.h input/zero.h lib/base64url.h lib/clock.h lib/trie.h output/dnscli.h output/dnssim.h output/dnssim/internal.h output/dnssim/ll.h output/null.h output/pcap.h output/respdiff.h output/tcpcli.h output/tlscli.h output/udpcli.h
dnsjit_SOURCES += core/channel.c core/compat.c core/file.c core/log.c core/object.c core/object/dns.c core/object/ether.c core/object/gre.c core/object/icmp6.c core/object/icmp.c core/object/ieee802.c core/object/ip6.c core/object/ip.c core/object/linuxsll.c core/object/loop.c core/object/null.c core/object/payload.c core/object/pcap.c core/object/tcp.c core/object/udp.c core/producer.c core/receiver.c core/thread.c filter/copy.c filter/ipsplit.c filter/layer.c filter/split.c filter/timing.c input/fpcap.c input/mmpcap.c input/pcap.c input/zpcap.c lib/base64url.c lib/clock.c lib/trie.c output/dnscli.c output/pcap.c output/respdiff.c output/tcpcli.c output/tlscli.c output/udpcli.c
nobase_dnsjitinclude_HEADERS += core/assert.h core/channel.h core/compat.h core/file.h core/log.h core/object/dns.h core/object/ether.h core/object/gre.h core/object.h core/object/icmp6.h core/object/icmp.h core/object/ieee802.h core/object/ip6.h core/object/ip.h core/object/linuxsll.h core/object/loop.h core/object/null.h core/object/payload.h core/object/pcap.h core/object/tcp.h core/object/udp.h core/producer.h core/receiver.h core/thread.h core/timespec.h filter/copy.h filter/ipsplit.h filter/layer.h filter/split.h filter/timing.h input/fpcap.h input/mmpcap.h input/pcap.h input/zpcap.h lib/base64url.h lib/clock.h lib/trie.h output/dnscli.h output/pcap.h output/respdiff.h output/tcpcli.h output/tlscli.h output/udpcli.h
# Lua headers
dist_dnsjit_SOURCES += core/channel.hh core/log.hh core/object/dns.hh core/object/ether.hh core/object/gre.hh core/object.hh core/object/icmp6.hh core/object/icmp.hh core/object/ieee802.hh core/object/ip6.hh core/object/ip.hh core/object/linuxsll.hh core/object/loop.hh core/object/null.hh core/object/payload.hh core/object/pcap.hh core/object/tcp.hh core/object/udp.hh core/producer.hh core/receiver.hh core/thread.hh core/timespec.hh filter/copy.hh filter/ipsplit.hh filter/layer.hh filter/split.hh filter/timing.hh input/fpcap.hh input/mmpcap.hh input/pcap.hh input/zero.hh lib/base64url.hh lib/clock.hh lib/trie.hh output/dnscli.hh output/dnssim.hh output/null.hh output/pcap.hh output/respdiff.hh output/tcpcli.hh output/tlscli.hh output/udpcli.hh
lua_hobjects += core/channel.luaho core/log.luaho core/object/dns.luaho core/object/ether.luaho core/object/gre.luaho core/object/icmp6.luaho core/object/icmp.luaho core/object/ieee802.luaho core/object/ip6.luaho core/object/ip.luaho core/object/linuxsll.luaho core/object/loop.luaho core/object.luaho core/object/null.luaho core/object/payload.luaho core/object/pcap.luaho core/object/tcp.luaho core/object/udp.luaho core/producer.luaho core/receiver.luaho core/thread.luaho core/timespec.luaho filter/copy.luaho filter/ipsplit.luaho filter/layer.luaho filter/split.luaho filter/timing.luaho input/fpcap.luaho input/mmpcap.luaho input/pcap.luaho input/zero.luaho lib/base64url.luaho lib/clock.luaho lib/trie.luaho output/dnscli.luaho output/dnssim.luaho output/null.luaho output/pcap.luaho output/respdiff.luaho output/tcpcli.luaho output/tlscli.luaho output/udpcli.luaho
nobase_dnsjitinclude_HEADERS += core/channel.hh core/file.hh core/log.hh core/object/dns.hh core/object/ether.hh core/object/gre.hh core/object.hh core/object/icmp6.hh core/object/icmp.hh core/object/ieee802.hh core/object/ip6.hh core/object/ip.hh core/object/linuxsll.hh core/object/loop.hh core/object/null.hh core/object/payload.hh core/object/pcap.hh core/object/tcp.hh core/object/udp.hh core/producer.hh core/receiver.hh core/thread.hh core/timespec.hh filter/copy.hh filter/ipsplit.hh filter/layer.hh filter/split.hh filter/timing.hh input/fpcap.hh input/mmpcap.hh input/pcap.hh input/zpcap.hh lib/base64url.hh lib/clock.hh lib/trie.hh output/dnscli.hh output/pcap.hh output/respdiff.hh output/tcpcli.hh output/tlscli.hh output/udpcli.hh
lua_hobjects += core/channel.luaho core/file.luaho core/log.luaho core/object/dns.luaho core/object/ether.luaho core/object/gre.luaho core/object/icmp6.luaho core/object/icmp.luaho core/object/ieee802.luaho core/object/ip6.luaho core/object/ip.luaho core/object/linuxsll.luaho core/object/loop.luaho core/object.luaho core/object/null.luaho core/object/payload.luaho core/object/pcap.luaho core/object/tcp.luaho core/object/udp.luaho core/producer.luaho core/receiver.luaho core/thread.luaho core/timespec.luaho filter/copy.luaho filter/ipsplit.luaho filter/layer.luaho filter/split.luaho filter/timing.luaho input/fpcap.luaho input/mmpcap.luaho input/pcap.luaho input/zpcap.luaho lib/base64url.luaho lib/clock.luaho lib/trie.luaho output/dnscli.luaho output/pcap.luaho output/respdiff.luaho output/tcpcli.luaho output/tlscli.luaho output/udpcli.luaho
# Lua sources
dist_dnsjit_SOURCES += core/channel.lua core/compat.lua core/log.lua core/object/dns/label.lua core/object/dns.lua core/object/dns/q.lua core/object/dns/rr.lua core/object/ether.lua core/object/gre.lua core/object/icmp6.lua core/object/icmp.lua core/object/ieee802.lua core/object/ip6.lua core/object/ip.lua core/object/linuxsll.lua core/object/loop.lua core/object.lua core/object/null.lua core/object/payload.lua core/object/pcap.lua core/objects.lua core/object/tcp.lua core/object/udp.lua core/producer.lua core/receiver.lua core/thread.lua core/timespec.lua filter/copy.lua filter/ipsplit.lua filter/layer.lua filter/split.lua filter/timing.lua input/fpcap.lua input/mmpcap.lua input/pcap.lua input/zero.lua lib/base64url.lua lib/clock.lua lib/getopt.lua lib/ip.lua lib/parseconf.lua lib/trie/iter.lua lib/trie.lua lib/trie/node.lua output/dnscli.lua output/dnssim.lua output/null.lua output/pcap.lua output/respdiff.lua output/tcpcli.lua output/tlscli.lua output/udpcli.lua
lua_objects += core/channel.luao core/compat.luao core/log.luao core/object/dns/label.luao core/object/dns.luao core/object/dns/q.luao core/object/dns/rr.luao core/object/ether.luao core/object/gre.luao core/object/icmp6.luao core/object/icmp.luao core/object/ieee802.luao core/object/ip6.luao core/object/ip.luao core/object/linuxsll.luao core/object/loop.luao core/object.luao core/object/null.luao core/object/payload.luao core/object/pcap.luao core/objects.luao core/object/tcp.luao core/object/udp.luao core/producer.luao core/receiver.luao core/thread.luao core/timespec.luao filter/copy.luao filter/ipsplit.luao filter/layer.luao filter/split.luao filter/timing.luao input/fpcap.luao input/mmpcap.luao input/pcap.luao input/zero.luao lib/base64url.luao lib/clock.luao lib/getopt.luao lib/ip.luao lib/parseconf.luao lib/trie/iter.luao lib/trie.luao lib/trie/node.luao output/dnscli.luao output/dnssim.luao output/null.luao output/pcap.luao output/respdiff.luao output/tcpcli.luao output/tlscli.luao output/udpcli.luao
dist_dnsjit_SOURCES += core/channel.lua core/compat.lua core/file.lua core/loader.lua core/log.lua core/object/dns/label.lua core/object/dns.lua core/object/dns/q.lua core/object/dns/rr.lua core/object/ether.lua core/object/gre.lua core/object/icmp6.lua core/object/icmp.lua core/object/ieee802.lua core/object/ip6.lua core/object/ip.lua core/object/linuxsll.lua core/object/loop.lua core/object.lua core/object/null.lua core/object/payload.lua core/object/pcap.lua core/objects.lua core/object/tcp.lua core/object/udp.lua core/producer.lua core/receiver.lua core/thread.lua core/timespec.lua filter/copy.lua filter/ipsplit.lua filter/layer.lua filter/split.lua filter/timing.lua input/fpcap.lua input/mmpcap.lua input/pcap.lua input/zero.lua input/zpcap.lua lib/base64url.lua lib/clock.lua lib/getopt.lua lib/ip.lua lib/parseconf.lua lib/trie/iter.lua lib/trie.lua lib/trie/node.lua output/dnscli.lua output/null.lua output/pcap.lua output/respdiff.lua output/tcpcli.lua output/tlscli.lua output/udpcli.lua
lua_objects += core/channel.luao core/compat.luao core/file.luao core/loader.luao core/log.luao core/object/dns/label.luao core/object/dns.luao core/object/dns/q.luao core/object/dns/rr.luao core/object/ether.luao core/object/gre.luao core/object/icmp6.luao core/object/icmp.luao core/object/ieee802.luao core/object/ip6.luao core/object/ip.luao core/object/linuxsll.luao core/object/loop.luao core/object.luao core/object/null.luao core/object/payload.luao core/object/pcap.luao core/objects.luao core/object/tcp.luao core/object/udp.luao core/producer.luao core/receiver.luao core/thread.luao core/timespec.luao filter/copy.luao filter/ipsplit.luao filter/layer.luao filter/split.luao filter/timing.luao input/fpcap.luao input/mmpcap.luao input/pcap.luao input/zero.luao input/zpcap.luao lib/base64url.luao lib/clock.luao lib/getopt.luao lib/ip.luao lib/parseconf.luao lib/trie/iter.luao lib/trie.luao lib/trie/node.luao output/dnscli.luao output/null.luao output/pcap.luao output/respdiff.luao output/tcpcli.luao output/tlscli.luao output/udpcli.luao
dnsjit_LDFLAGS = -Wl,-E
dnsjit_LDADD += $(lua_hobjects) $(lua_objects)
@ -63,7 +64,7 @@ man1_MANS = dnsjit.1
CLEANFILES += $(man1_MANS)
man3_MANS = dnsjit.core.3 dnsjit.lib.3 dnsjit.input.3 dnsjit.filter.3 dnsjit.output.3
man3_MANS += dnsjit.core.channel.3 dnsjit.core.compat.3 dnsjit.core.log.3 dnsjit.core.object.3 dnsjit.core.object.dns.3 dnsjit.core.object.dns.label.3 dnsjit.core.object.dns.q.3 dnsjit.core.object.dns.rr.3 dnsjit.core.object.ether.3 dnsjit.core.object.gre.3 dnsjit.core.object.icmp.3 dnsjit.core.object.icmp6.3 dnsjit.core.object.ieee802.3 dnsjit.core.object.ip.3 dnsjit.core.object.ip6.3 dnsjit.core.object.linuxsll.3 dnsjit.core.object.loop.3 dnsjit.core.object.null.3 dnsjit.core.object.payload.3 dnsjit.core.object.pcap.3 dnsjit.core.objects.3 dnsjit.core.object.tcp.3 dnsjit.core.object.udp.3 dnsjit.core.producer.3 dnsjit.core.receiver.3 dnsjit.core.thread.3 dnsjit.core.timespec.3 dnsjit.filter.copy.3 dnsjit.filter.ipsplit.3 dnsjit.filter.layer.3 dnsjit.filter.split.3 dnsjit.filter.timing.3 dnsjit.input.fpcap.3 dnsjit.input.mmpcap.3 dnsjit.input.pcap.3 dnsjit.input.zero.3 dnsjit.lib.base64url.3 dnsjit.lib.clock.3 dnsjit.lib.getopt.3 dnsjit.lib.ip.3 dnsjit.lib.parseconf.3 dnsjit.lib.trie.3 dnsjit.lib.trie.iter.3 dnsjit.lib.trie.node.3 dnsjit.output.dnscli.3 dnsjit.output.dnssim.3 dnsjit.output.null.3 dnsjit.output.pcap.3 dnsjit.output.respdiff.3 dnsjit.output.tcpcli.3 dnsjit.output.tlscli.3 dnsjit.output.udpcli.3
man3_MANS += dnsjit.core.channel.3 dnsjit.core.compat.3 dnsjit.core.file.3 dnsjit.core.loader.3 dnsjit.core.log.3 dnsjit.core.object.3 dnsjit.core.object.dns.3 dnsjit.core.object.dns.label.3 dnsjit.core.object.dns.q.3 dnsjit.core.object.dns.rr.3 dnsjit.core.object.ether.3 dnsjit.core.object.gre.3 dnsjit.core.object.icmp.3 dnsjit.core.object.icmp6.3 dnsjit.core.object.ieee802.3 dnsjit.core.object.ip.3 dnsjit.core.object.ip6.3 dnsjit.core.object.linuxsll.3 dnsjit.core.object.loop.3 dnsjit.core.object.null.3 dnsjit.core.object.payload.3 dnsjit.core.object.pcap.3 dnsjit.core.objects.3 dnsjit.core.object.tcp.3 dnsjit.core.object.udp.3 dnsjit.core.producer.3 dnsjit.core.receiver.3 dnsjit.core.thread.3 dnsjit.core.timespec.3 dnsjit.filter.copy.3 dnsjit.filter.ipsplit.3 dnsjit.filter.layer.3 dnsjit.filter.split.3 dnsjit.filter.timing.3 dnsjit.input.fpcap.3 dnsjit.input.mmpcap.3 dnsjit.input.pcap.3 dnsjit.input.zero.3 dnsjit.input.zpcap.3 dnsjit.lib.base64url.3 dnsjit.lib.clock.3 dnsjit.lib.getopt.3 dnsjit.lib.ip.3 dnsjit.lib.parseconf.3 dnsjit.lib.trie.3 dnsjit.lib.trie.iter.3 dnsjit.lib.trie.node.3 dnsjit.output.dnscli.3 dnsjit.output.null.3 dnsjit.output.pcap.3 dnsjit.output.respdiff.3 dnsjit.output.tcpcli.3 dnsjit.output.tlscli.3 dnsjit.output.udpcli.3
CLEANFILES += *.3in $(man3_MANS)
.lua.luao:
@ -129,6 +130,12 @@ dnsjit.core.channel.3in: core/channel.lua gen-manpage.lua
dnsjit.core.compat.3in: core/compat.lua gen-manpage.lua
$(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/compat.lua" > "$@"
dnsjit.core.file.3in: core/file.lua gen-manpage.lua
$(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/file.lua" > "$@"
dnsjit.core.loader.3in: core/loader.lua gen-manpage.lua
$(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/loader.lua" > "$@"
dnsjit.core.log.3in: core/log.lua gen-manpage.lua
$(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/log.lua" > "$@"
@ -231,6 +238,9 @@ dnsjit.input.pcap.3in: input/pcap.lua gen-manpage.lua
dnsjit.input.zero.3in: input/zero.lua gen-manpage.lua
$(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/input/zero.lua" > "$@"
dnsjit.input.zpcap.3in: input/zpcap.lua gen-manpage.lua
$(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/input/zpcap.lua" > "$@"
dnsjit.lib.base64url.3in: lib/base64url.lua gen-manpage.lua
$(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/lib/base64url.lua" > "$@"
@ -258,9 +268,6 @@ dnsjit.lib.trie.node.3in: lib/trie/node.lua gen-manpage.lua
dnsjit.output.dnscli.3in: output/dnscli.lua gen-manpage.lua
$(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/output/dnscli.lua" > "$@"
dnsjit.output.dnssim.3in: output/dnssim.lua gen-manpage.lua
$(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/output/dnssim.lua" > "$@"
dnsjit.output.null.3in: output/null.lua gen-manpage.lua
$(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/output/null.lua" > "$@"

1652
src/Makefile.in Normal file

File diff suppressed because it is too large Load diff

295
src/config.h.in Normal file
View file

@ -0,0 +1,295 @@
/* src/config.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 to support Advanced Bit Manipulation */
#undef HAVE_ABM
/* Define to 1 to support Multi-Precision Add-Carry Instruction Extensions */
#undef HAVE_ADX
/* Define to 1 to support Advanced Encryption Standard New Instruction Set
(AES-NI) */
#undef HAVE_AES
/* Support Altivec instructions */
#undef HAVE_ALTIVEC
/* Define to 1 to support Advanced Vector Extensions */
#undef HAVE_AVX
/* Define to 1 to support Advanced Vector Extensions 2 */
#undef HAVE_AVX2
/* Define to 1 to support AVX-512 Byte and Word Instructions */
#undef HAVE_AVX512_BW
/* Define to 1 to support AVX-512 Conflict Detection Instructions */
#undef HAVE_AVX512_CD
/* Define to 1 to support AVX-512 Doubleword and Quadword Instructions */
#undef HAVE_AVX512_DQ
/* Define to 1 to support AVX-512 Exponential & Reciprocal Instructions */
#undef HAVE_AVX512_ER
/* Define to 1 to support AVX-512 Foundation Extensions */
#undef HAVE_AVX512_F
/* Define to 1 to support AVX-512 Integer Fused Multiply Add Instructions */
#undef HAVE_AVX512_IFMA
/* Define to 1 to support AVX-512 Conflict Prefetch Instructions */
#undef HAVE_AVX512_PF
/* Define to 1 to support AVX-512 Vector Byte Manipulation Instructions */
#undef HAVE_AVX512_VBMI
/* Define to 1 to support AVX-512 Vector Length Extensions */
#undef HAVE_AVX512_VL
/* Define to 1 to support Bit Manipulation Instruction Set 1 */
#undef HAVE_BMI1
/* Define to 1 to support Bit Manipulation Instruction Set 2 */
#undef HAVE_BMI2
/* Define to 1 if you have the <byteswap.h> header file. */
#undef HAVE_BYTESWAP_H
/* Define to 1 if you have the <ck_pr.h> header file. */
#undef HAVE_CK_PR_H
/* Define to 1 if you have the <ck_ring.h> header file. */
#undef HAVE_CK_RING_H
/* Define to 1 if you have the `clock_nanosleep' function. */
#undef HAVE_CLOCK_NANOSLEEP
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define to 1 if you have the <endian.h> header file. */
#undef HAVE_ENDIAN_H
/* Define to 1 to support Fused Multiply-Add Extensions 3 */
#undef HAVE_FMA3
/* Define to 1 to support Fused Multiply-Add Extensions 4 */
#undef HAVE_FMA4
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the `ck' library (-lck). */
#undef HAVE_LIBCK
/* Define to 1 if you have the `gnutls' library (-lgnutls). */
#undef HAVE_LIBGNUTLS
/* Define to 1 if you have the `lmdb' library (-llmdb). */
#undef HAVE_LIBLMDB
/* Define to 1 if you have the `pcap' library (-lpcap). */
#undef HAVE_LIBPCAP
/* Define to 1 if you have the <lmdb.h> header file. */
#undef HAVE_LMDB_H
/* Use liblz4 */
#undef HAVE_LZ4
/* Define to 1 if you have the <machine/endian.h> header file. */
#undef HAVE_MACHINE_ENDIAN_H
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 to support Multimedia Extensions */
#undef HAVE_MMX
/* Define to 1 to support Memory Protection Extensions */
#undef HAVE_MPX
/* Define to 1 if you have the `nanosleep' function. */
#undef HAVE_NANOSLEEP
/* Define to 1 if you have the <net/ethernet.h> header file. */
#undef HAVE_NET_ETHERNET_H
/* Define to 1 if you have the <net/ethertypes.h> header file. */
#undef HAVE_NET_ETHERTYPES_H
/* Define to 1 if you have the `pcap_activate' function. */
#undef HAVE_PCAP_ACTIVATE
/* Define to 1 if you have the `pcap_create' function. */
#undef HAVE_PCAP_CREATE
/* Define to 1 if the system has the type `pcap_direction_t'. */
#undef HAVE_PCAP_DIRECTION_T
/* Define to 1 if you have the `pcap_open_offline_with_tstamp_precision'
function. */
#undef HAVE_PCAP_OPEN_OFFLINE_WITH_TSTAMP_PRECISION
/* Define to 1 if you have the `pcap_setdirection' function. */
#undef HAVE_PCAP_SETDIRECTION
/* Define to 1 if you have the `pcap_set_immediate_mode' function. */
#undef HAVE_PCAP_SET_IMMEDIATE_MODE
/* Define to 1 if you have the `pcap_set_tstamp_precision' function. */
#undef HAVE_PCAP_SET_TSTAMP_PRECISION
/* Define to 1 if you have the `pcap_set_tstamp_type' function. */
#undef HAVE_PCAP_SET_TSTAMP_TYPE
/* Define to 1 to support Prefetch Vector Data Into Caches WT1 */
#undef HAVE_PREFETCHWT1
/* Define if you have POSIX threads libraries and header files. */
#undef HAVE_PTHREAD
/* Have PTHREAD_PRIO_INHERIT. */
#undef HAVE_PTHREAD_PRIO_INHERIT
/* Define to 1 to support Digital Random Number Generator */
#undef HAVE_RDRND
/* Define to 1 if you have the `sched_yield' function. */
#undef HAVE_SCHED_YIELD
/* Define to 1 to support Secure Hash Algorithm Extension */
#undef HAVE_SHA
/* Define to 1 to support Streaming SIMD Extensions */
#undef HAVE_SSE
/* Define to 1 to support Streaming SIMD Extensions */
#undef HAVE_SSE2
/* Define to 1 to support Streaming SIMD Extensions 3 */
#undef HAVE_SSE3
/* Define to 1 to support Streaming SIMD Extensions 4.1 */
#undef HAVE_SSE4_1
/* Define to 1 to support Streaming SIMD Extensions 4.2 */
#undef HAVE_SSE4_2
/* Define to 1 to support AMD Streaming SIMD Extensions 4a */
#undef HAVE_SSE4a
/* Define to 1 to support Supplemental Streaming SIMD Extensions 3 */
#undef HAVE_SSSE3
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the <sys/endian.h> header file. */
#undef HAVE_SYS_ENDIAN_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/time.h> header file. */
#undef HAVE_SYS_TIME_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Support VSX instructions */
#undef HAVE_VSX
/* Define to 1 to support eXtended Operations Extensions */
#undef HAVE_XOP
/* Use libzstd */
#undef HAVE_ZSTD
/* Define to the sub-directory where libtool stores uninstalled libraries. */
#undef LT_OBJDIR
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the major version of this package. */
#undef PACKAGE_MAJOR_VERSION
/* Define to the minor version of this package. */
#undef PACKAGE_MINOR_VERSION
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the patch version of this package. */
#undef PACKAGE_PATCH_VERSION
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define to necessary symbol if this constant uses a non-standard name on
your system. */
#undef PTHREAD_CREATE_JOINABLE
/* The size of `ck_ring_buffer_t', as computed by sizeof. */
#undef SIZEOF_CK_RING_BUFFER_T
/* The size of `ck_ring_t', as computed by sizeof. */
#undef SIZEOF_CK_RING_T
/* The size of `gnutls_certificate_credentials_t', as computed by sizeof. */
#undef SIZEOF_GNUTLS_CERTIFICATE_CREDENTIALS_T
/* The size of `gnutls_session_t', as computed by sizeof. */
#undef SIZEOF_GNUTLS_SESSION_T
/* The size of `pthread_cond_t', as computed by sizeof. */
#undef SIZEOF_PTHREAD_COND_T
/* The size of `pthread_mutex_t', as computed by sizeof. */
#undef SIZEOF_PTHREAD_MUTEX_T
/* The size of `pthread_t', as computed by sizeof. */
#undef SIZEOF_PTHREAD_T
/* The size of `struct pollfd', as computed by sizeof. */
#undef SIZEOF_STRUCT_POLLFD
/* The size of `struct sockaddr_storage', as computed by sizeof. */
#undef SIZEOF_STRUCT_SOCKADDR_STORAGE
/* The size of `void*', as computed by sizeof. */
#undef SIZEOF_VOIDP
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
#undef TIME_WITH_SYS_TIME
/* Version number of package */
#undef VERSION

View file

@ -21,7 +21,7 @@
#ifndef __dnsjit_core_assert_h
#define __dnsjit_core_assert_h
#include "core/log.h"
#include <dnsjit/core/log.h>
#define mlassert_self() \
if (!self) \

View file

@ -18,8 +18,8 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/log.h"
#include "core/receiver.h"
#include <dnsjit/core/log.h>
#include <dnsjit/core/receiver.h>
#ifndef __dnsjit_core_channel_h
#define __dnsjit_core_channel_h
@ -36,6 +36,6 @@
#include <ck_pr.h>
#include <stdbool.h>
#include "core/channel.hh"
#include <dnsjit/core/channel.hh>
#endif

View file

@ -18,20 +18,20 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
//lua:require("dnsjit.core.log")
//lua:require("dnsjit.core.receiver_h")
//lua:require("dnsjit.core.producer_h")
#include "config.h"
typedef struct input_zero {
core_log_t _log;
core_receiver_t recv;
void* ctx;
} input_zero_t;
#include "core/file.h"
core_log_t* input_zero_log();
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
void input_zero_init(input_zero_t* self);
void input_zero_destroy(input_zero_t* self);
void input_zero_run(input_zero_t* self, uint64_t num);
int core_file_exists(const char* filename)
{
struct stat s;
core_producer_t input_zero_producer();
if (stat(filename, &s)) {
return 1;
}
return 0;
}

View file

@ -18,15 +18,9 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/log.h"
#include "core/receiver.h"
#include "core/producer.h"
#ifndef __dnsjit_core_file_h
#define __dnsjit_core_file_h
#ifndef __dnsjit_input_zero_h
#define __dnsjit_input_zero_h
#include <stdint.h>
#include "input/zero.hh"
#include <dnsjit/core/file.hh>
#endif

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, CZ.NIC, z.s.p.o.
* Copyright (c) 2018-2021, OARC, Inc.
* All rights reserved.
*
* This file is part of dnsjit.
@ -18,14 +18,4 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/log.h"
#include "core/receiver.h"
#ifndef __dnsjit_output_dnssim_h
#define __dnsjit_output_dnssim_h
#include <stdbool.h>
#include "output/dnssim.hh"
#endif
int core_file_exists(const char*);

37
src/core/file.lua Normal file
View file

@ -0,0 +1,37 @@
-- Copyright (c) 2018-2021, OARC, Inc.
-- All rights reserved.
--
-- This file is part of dnsjit.
--
-- dnsjit is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- dnsjit is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
-- dnsjit.core.file
-- OS file operations
-- require("dnsjit.core.file")
-- local ffi = require("ffi")
-- if ffi.C.core_file_exists("path/file") == 0 then
-- ...
-- end
--
-- Module that exposes some file operations that are missing from Lua.
-- .SS C functions
-- .TP
-- core_file_exists(path/filename)
-- Function that takes a string and uses
-- .B stat()
-- to check if that path/filename exists.
-- Returns zero if it exists.
module(...,package.seeall)
require("dnsjit.core.file_h")

68
src/core/loader.lua Normal file
View file

@ -0,0 +1,68 @@
-- Copyright (c) 2018-2021, OARC, Inc.
-- All rights reserved.
--
-- This file is part of dnsjit.
--
-- dnsjit is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- dnsjit is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
-- dnsjit.core.loader
-- Dynamic library loader
-- local loader = require("dnsjit.core.loader")
-- loader.load("example-input-zero/zero")
--
-- Module for loading dynamic libraries (.so) in more ways then LuaJIT can.
-- This is mainly used in external modules.
module(...,package.seeall)
require("dnsjit.core.file")
local ffi = require("ffi")
local C = ffi.C
local Loader = {}
-- Search
-- .B package.cpath
-- for the given name and load the first found.
-- If
-- .B global
-- is true (default true if not given) then the loaded symbols will also
-- be available globally.
-- Returns the loaded C library as per
-- .BR ffi.load() .
-- .br
-- The
-- .B ?
-- in each path of
-- .B package.cpath
-- will be replace by the given name, so usually the ".so" part of the
-- library does not need to be given.
-- See
-- .I package.cpath
-- and
-- .I package.loaders
-- in Lua 5.1 for more information.
function Loader.load(name, global)
if global ~= false then
global = true
end
for path in string.gmatch(package.cpath, "[^;]+") do
path = path:gsub("?", name)
if C.core_file_exists(path) == 0 then
return ffi.load(path, global)
end
end
return ffi.load(name)
end
return Loader

View file

@ -38,7 +38,7 @@
name, 1, LOG_SETTINGS_T_INIT, &_log.settings \
}
#include "core/log.hh"
#include <dnsjit/core/log.hh>
#ifdef DNSJIT_NO_LOGGING
#define ldebug(msg...)

View file

@ -44,7 +44,7 @@
#define CORE_OBJECT_DNS 50
#include <stdint.h>
#include "core/object.hh"
#include <dnsjit/core/object.hh>
#define CORE_OBJECT_INIT(type, prev) (core_object_t*)prev, type

View file

@ -18,8 +18,8 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/log.h"
#include "core/object.h"
#include <dnsjit/core/log.h>
#include <dnsjit/core/object.h>
#ifndef __dnsjit_core_object_dns_h
#define __dnsjit_core_object_dns_h
@ -27,7 +27,7 @@
#include <netinet/in.h>
#include <sys/types.h>
#include "core/object/dns.hh"
#include <dnsjit/core/object/dns.hh>
#define CORE_OBJECT_DNS_INIT(prev) \
{ \

View file

@ -18,15 +18,15 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/object.h"
#include "core/timespec.h"
#include <dnsjit/core/object.h>
#include <dnsjit/core/timespec.h>
#ifndef __dnsjit_core_object_ether_h
#define __dnsjit_core_object_ether_h
#include <stddef.h>
#include "core/object/ether.hh"
#include <dnsjit/core/object/ether.hh>
#define CORE_OBJECT_ETHER_INIT(prev) \
{ \

View file

@ -18,15 +18,15 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/object.h"
#include "core/timespec.h"
#include <dnsjit/core/object.h>
#include <dnsjit/core/timespec.h>
#ifndef __dnsjit_core_object_gre_h
#define __dnsjit_core_object_gre_h
#include <stddef.h>
#include "core/object/gre.hh"
#include <dnsjit/core/object/gre.hh>
#define CORE_OBJECT_GRE_INIT(prev) \
{ \

View file

@ -18,15 +18,15 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/object.h"
#include "core/timespec.h"
#include <dnsjit/core/object.h>
#include <dnsjit/core/timespec.h>
#ifndef __dnsjit_core_object_icmp_h
#define __dnsjit_core_object_icmp_h
#include <stddef.h>
#include "core/object/icmp.hh"
#include <dnsjit/core/object/icmp.hh>
#define CORE_OBJECT_ICMP_INIT(prev) \
{ \

View file

@ -18,15 +18,15 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/object.h"
#include "core/timespec.h"
#include <dnsjit/core/object.h>
#include <dnsjit/core/timespec.h>
#ifndef __dnsjit_core_object_icmp6_h
#define __dnsjit_core_object_icmp6_h
#include <stddef.h>
#include "core/object/icmp6.hh"
#include <dnsjit/core/object/icmp6.hh>
#define CORE_OBJECT_ICMP6_INIT(prev) \
{ \

View file

@ -18,15 +18,15 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/object.h"
#include "core/timespec.h"
#include <dnsjit/core/object.h>
#include <dnsjit/core/timespec.h>
#ifndef __dnsjit_core_object_ieee802_h
#define __dnsjit_core_object_ieee802_h
#include <stddef.h>
#include "core/object/ieee802.hh"
#include <dnsjit/core/object/ieee802.hh>
#define CORE_OBJECT_IEEE802_INIT(prev) \
{ \

View file

@ -18,15 +18,15 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/object.h"
#include "core/timespec.h"
#include <dnsjit/core/object.h>
#include <dnsjit/core/timespec.h>
#ifndef __dnsjit_core_object_ip_h
#define __dnsjit_core_object_ip_h
#include <stddef.h>
#include "core/object/ip.hh"
#include <dnsjit/core/object/ip.hh>
#define CORE_OBJECT_IP_INIT(prev) \
{ \

View file

@ -18,15 +18,15 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/object.h"
#include "core/timespec.h"
#include <dnsjit/core/object.h>
#include <dnsjit/core/timespec.h>
#ifndef __dnsjit_core_object_ip6_h
#define __dnsjit_core_object_ip6_h
#include <stddef.h>
#include "core/object/ip6.hh"
#include <dnsjit/core/object/ip6.hh>
#define CORE_OBJECT_IP6_INIT(prev) \
{ \

View file

@ -18,15 +18,15 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/object.h"
#include "core/timespec.h"
#include <dnsjit/core/object.h>
#include <dnsjit/core/timespec.h>
#ifndef __dnsjit_core_object_linuxsll_h
#define __dnsjit_core_object_linuxsll_h
#include <stddef.h>
#include "core/object/linuxsll.hh"
#include <dnsjit/core/object/linuxsll.hh>
#define CORE_OBJECT_LINUXSLL_INIT(prev) \
{ \

View file

@ -18,15 +18,15 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/object.h"
#include "core/timespec.h"
#include <dnsjit/core/object.h>
#include <dnsjit/core/timespec.h>
#ifndef __dnsjit_core_object_loop_h
#define __dnsjit_core_object_loop_h
#include <stddef.h>
#include "core/object/loop.hh"
#include <dnsjit/core/object/loop.hh>
#define CORE_OBJECT_LOOP_INIT(prev) \
{ \

View file

@ -18,15 +18,15 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/object.h"
#include "core/timespec.h"
#include <dnsjit/core/object.h>
#include <dnsjit/core/timespec.h>
#ifndef __dnsjit_core_object_null_h
#define __dnsjit_core_object_null_h
#include <stddef.h>
#include "core/object/null.hh"
#include <dnsjit/core/object/null.hh>
#define CORE_OBJECT_NULL_INIT(prev) \
{ \

View file

@ -18,15 +18,15 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/object.h"
#include "core/timespec.h"
#include <dnsjit/core/object.h>
#include <dnsjit/core/timespec.h>
#ifndef __dnsjit_core_object_payload_h
#define __dnsjit_core_object_payload_h
#include <stddef.h>
#include "core/object/payload.hh"
#include <dnsjit/core/object/payload.hh>
#define CORE_OBJECT_PAYLOAD_INIT(prev) \
{ \

View file

@ -18,13 +18,13 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/object.h"
#include "core/timespec.h"
#include <dnsjit/core/object.h>
#include <dnsjit/core/timespec.h>
#ifndef __dnsjit_core_object_pcap_h
#define __dnsjit_core_object_pcap_h
#include "core/object/pcap.hh"
#include <dnsjit/core/object/pcap.hh>
#define CORE_OBJECT_PCAP_INIT(prev) \
{ \

View file

@ -18,15 +18,15 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/object.h"
#include "core/timespec.h"
#include <dnsjit/core/object.h>
#include <dnsjit/core/timespec.h>
#ifndef __dnsjit_core_object_tcp_h
#define __dnsjit_core_object_tcp_h
#include <stddef.h>
#include "core/object/tcp.hh"
#include <dnsjit/core/object/tcp.hh>
#define CORE_OBJECT_TCP_INIT(prev) \
{ \

View file

@ -18,15 +18,15 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/object.h"
#include "core/timespec.h"
#include <dnsjit/core/object.h>
#include <dnsjit/core/timespec.h>
#ifndef __dnsjit_core_object_udp_h
#define __dnsjit_core_object_udp_h
#include <stddef.h>
#include "core/object/udp.hh"
#include <dnsjit/core/object/udp.hh>
#define CORE_OBJECT_UDP_INIT(prev) \
{ \

View file

@ -18,11 +18,11 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/object.h"
#include <dnsjit/core/object.h>
#ifndef __dnsjit_core_producer_h
#define __dnsjit_core_producer_h
#include "core/producer.hh"
#include <dnsjit/core/producer.hh>
#endif

View file

@ -18,11 +18,11 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/object.h"
#include <dnsjit/core/object.h>
#ifndef __dnsjit_core_receiver_h
#define __dnsjit_core_receiver_h
#include "core/receiver.hh"
#include <dnsjit/core/receiver.hh>
#endif

View file

@ -18,7 +18,7 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/log.h"
#include <dnsjit/core/log.h>
#ifndef __dnsjit_core_thread_h
#define __dnsjit_core_thread_h
@ -26,6 +26,6 @@
#include <pthread.h>
#include <unistd.h>
#include "core/thread.hh"
#include <dnsjit/core/thread.hh>
#endif

View file

@ -23,7 +23,7 @@
#include <stdint.h>
#include "core/timespec.hh"
#include <dnsjit/core/timespec.hh>
#define CORE_TIMESPEC_INIT \
{ \

View file

@ -19,14 +19,36 @@
-- dnsjit.core.receiver
-- Non-system depended time specification structure definition
-- typedef struct core_timespec {
-- uint64_t sec;
-- uint64_t nsec;
-- int64_t sec;
-- int64_t nsec;
-- } core_timespec_t;
-- .SS C
-- #include "core/timespec.h"
-- .SS Lua
-- require("dnsjit.core.timespec_h")
-- .SS Lua functions
-- local ts = require("dnsjit.core.timespec"):max_init()
--
-- Mainly used in C modules for a system independent time specification
-- structure that can be passed to Lua.
module(...,package.seeall)
require("dnsjit.core.timespec_h")
local ffi = require("ffi")
local Timespec = {}
-- Return a new structure with both
-- .I sec
-- and
-- .I nsec
-- set to 2LL ^ 62, the maximum positive values according to Lua.
function Timespec:max_init()
local ts = ffi.new("core_timespec_t")
ts.sec = 2LL ^ 62
ts.nsec = 2LL ^ 62
return ts
end
return Timespec

View file

@ -52,17 +52,6 @@ int main(int argc, char* argv[])
sigset_t set;
pthread_t sighthr;
#ifdef PACKAGE_NAME
fprintf(stderr, "<< " PACKAGE_NAME
#ifdef PACKAGE_VERSION
" v" PACKAGE_VERSION
#endif
#ifdef PACKAGE_URL
" " PACKAGE_URL
#endif
" >>\n");
#endif
if (argc < 2) {
fprintf(stderr, "usage: %s <file.lua> ...\n", argv[0]);
exit(1);

View file

@ -18,13 +18,13 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/log.h"
#include "core/object.h"
#include "core/receiver.h"
#include <dnsjit/core/log.h>
#include <dnsjit/core/object.h>
#include <dnsjit/core/receiver.h>
#ifndef __dnsjit_filter_copy_h
#define __dnsjit_filter_copy_h
#include "filter/copy.hh"
#include <dnsjit/filter/copy.hh>
#endif

View file

@ -18,12 +18,12 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/log.h"
#include "core/receiver.h"
#include <dnsjit/core/log.h>
#include <dnsjit/core/receiver.h>
#ifndef __dnsjit_filter_ipsplit_h
#define __dnsjit_filter_ipsplit_h
#include "filter/ipsplit.hh"
#include <dnsjit/filter/ipsplit.hh>
#endif

View file

@ -18,27 +18,27 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/log.h"
#include "core/receiver.h"
#include "core/producer.h"
#include "core/object/pcap.h"
#include "core/object/null.h"
#include "core/object/ether.h"
#include "core/object/loop.h"
#include "core/object/linuxsll.h"
#include "core/object/ieee802.h"
#include "core/object/ip.h"
#include "core/object/ip6.h"
#include "core/object/gre.h"
#include "core/object/icmp.h"
#include "core/object/icmp6.h"
#include "core/object/udp.h"
#include "core/object/tcp.h"
#include "core/object/payload.h"
#include <dnsjit/core/log.h>
#include <dnsjit/core/receiver.h>
#include <dnsjit/core/producer.h>
#include <dnsjit/core/object/pcap.h>
#include <dnsjit/core/object/null.h>
#include <dnsjit/core/object/ether.h>
#include <dnsjit/core/object/loop.h>
#include <dnsjit/core/object/linuxsll.h>
#include <dnsjit/core/object/ieee802.h>
#include <dnsjit/core/object/ip.h>
#include <dnsjit/core/object/ip6.h>
#include <dnsjit/core/object/gre.h>
#include <dnsjit/core/object/icmp.h>
#include <dnsjit/core/object/icmp6.h>
#include <dnsjit/core/object/udp.h>
#include <dnsjit/core/object/tcp.h>
#include <dnsjit/core/object/payload.h>
#ifndef __dnsjit_filter_layer_h
#define __dnsjit_filter_layer_h
#include "filter/layer.hh"
#include <dnsjit/filter/layer.hh>
#endif

View file

@ -18,12 +18,12 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/log.h"
#include "core/receiver.h"
#include <dnsjit/core/log.h>
#include <dnsjit/core/receiver.h>
#ifndef __dnsjit_filter_split_h
#define __dnsjit_filter_split_h
#include "filter/split.hh"
#include <dnsjit/filter/split.hh>
#endif

View file

@ -18,13 +18,13 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/log.h"
#include "core/receiver.h"
#include "core/producer.h"
#include <dnsjit/core/log.h>
#include <dnsjit/core/receiver.h>
#include <dnsjit/core/producer.h>
#ifndef __dnsjit_filter_timing_h
#define __dnsjit_filter_timing_h
#include "filter/timing.hh"
#include <dnsjit/filter/timing.hh>
#endif

View file

@ -1,130 +0,0 @@
#!/bin/sh
echo '# Copyright (c) 2018-2021, OARC, Inc.
# All rights reserved.
#
# This file is part of dnsjit.
#
# dnsjit is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# dnsjit is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
CLEANFILES = *.gcda *.gcno *.gcov
SUBDIRS = test
AM_CFLAGS = -Werror=attributes \
-I$(srcdir) \
-I$(top_srcdir) \
$(SIMD_FLAGS) $(CPUEXT_FLAGS) \
$(PTHREAD_CFLAGS) \
$(luajit_CFLAGS) \
$(libuv_CFLAGS) \
$(libnghttp2_CFLAGS)
EXTRA_DIST = gen-manpage.lua gen-compat.lua gen-errno.sh dnsjit.1in
BUILT_SOURCES = core/compat.hh core/log_errstr.c
bin_PROGRAMS = dnsjit
dnsjit_SOURCES = dnsjit.c globals.c
dist_dnsjit_SOURCES = core.lua lib.lua input.lua filter.lua globals.h \
output.lua
lua_hobjects = core/compat.luaho
lua_objects = core.luao lib.luao input.luao filter.luao output.luao
dnsjit_LDADD = $(PTHREAD_LIBS) $(luajit_LIBS) $(libuv_LIBS) $(libnghttp2_LIBS)
# C source and headers';
echo "dnsjit_SOURCES +=`find core lib input filter output -type f -name '*.c' | sort | while read line; do echo -n " $line"; done`"
echo "dist_dnsjit_SOURCES +=`find core lib input filter output -type f -name '*.h' | sort | while read line; do echo -n " $line"; done`"
echo '
# Lua headers'
echo "dist_dnsjit_SOURCES +=`find core lib input filter output -type f -name '*.hh' | sort | while read line; do echo -n " $line"; done`"
echo "lua_hobjects +=`find core lib input filter output -type f -name '*.hh' | sed -e 's%.hh%.luaho%g' | sort | while read line; do echo -n " $line"; done`"
echo '
# Lua sources'
echo "dist_dnsjit_SOURCES +=`find core lib input filter output -type f -name '*.lua' | sort | while read line; do echo -n " $line"; done`"
echo "lua_objects +=`find core lib input filter output -type f -name '*.lua' | sed -e 's%.lua%.luao%g' | sort | while read line; do echo -n " $line"; done`"
echo '
dnsjit_LDFLAGS = -Wl,-E
dnsjit_LDADD += $(lua_hobjects) $(lua_objects)
CLEANFILES += $(lua_hobjects) $(lua_objects)
man1_MANS = dnsjit.1
CLEANFILES += $(man1_MANS)
man3_MANS = dnsjit.core.3 dnsjit.lib.3 dnsjit.input.3 dnsjit.filter.3 dnsjit.output.3';
echo "man3_MANS +=`find core lib input filter output -type f -name '*.lua' | sed -e 's%.lua%.3%g' | sed -e 's%/%.%g' | sort | while read line; do echo -n " dnsjit.$line"; done`"
echo 'CLEANFILES += *.3in $(man3_MANS)
.lua.luao:
@mkdir -p `dirname "$@"`
$(LUAJIT) -bg -n "dnsjit.`echo \"$@\" | sed '"'"'s%\..*%%'"'"' | sed '"'"'s%/%.%g'"'"'`" -t o "$<" "$@"
.luah.luaho:
@mkdir -p `dirname "$@"`
$(LUAJIT) -bg -n "dnsjit.`echo \"$@\" | sed '"'"'s%\..*%%'"'"' | sed '"'"'s%/%.%g'"'"'`_h" -t o "$<" "$@"
.hh.luah:
@mkdir -p `dirname "$@"`
@echo '"'"'module(...,package.seeall);'"'"' > "$@"
@cat "$<" | grep '"'"'^//lua:'"'"' | sed '"'"'s%^//lua:%%'"'"' >> "$@"
@echo '"'"'require("ffi").cdef[['"'"' >> "$@"
@cat "$<" | grep -v '"'"'^#'"'"' >> "$@"
@echo '"'"']]'"'"' >> "$@"
.1in.1:
sed -e '"'"'s,[@]PACKAGE_VERSION[@],$(PACKAGE_VERSION),g'"'"' \
-e '"'"'s,[@]PACKAGE_URL[@],$(PACKAGE_URL),g'"'"' \
-e '"'"'s,[@]PACKAGE_BUGREPORT[@],$(PACKAGE_BUGREPORT),g'"'"' \
< "$<" > "$@"
.3in.3:
sed -e '"'"'s,[@]PACKAGE_VERSION[@],$(PACKAGE_VERSION),g'"'"' \
-e '"'"'s,[@]PACKAGE_URL[@],$(PACKAGE_URL),g'"'"' \
-e '"'"'s,[@]PACKAGE_BUGREPORT[@],$(PACKAGE_BUGREPORT),g'"'"' \
< "$<" > "$@"
if ENABLE_GCOV
gcov-local:
for src in $(dnsjit_SOURCES); do \
gcov -x -l -r -s "$(srcdir)" "$$src"; \
done
endif
core/compat.hh: gen-compat.lua
$(LUAJIT) "$(srcdir)/gen-compat.lua" > "$@"
core/log_errstr.c: gen-errno.sh
"$(srcdir)/gen-errno.sh" > "$@"
';
for file in core.lua lib.lua input.lua filter.lua output.lua; do
man=`echo "$file"|sed -e 's%.lua%.3%g'|sed -e 's%/%.%g'`
echo "
dnsjit.${man}in: $file gen-manpage.lua
\$(LUAJIT) \"\$(srcdir)/gen-manpage.lua\" \"\$(srcdir)/$file\" > \"\$@\"";
done
find core lib input filter output -type f -name '*.lua' | sort | while read file; do
man=`echo "$file"|sed -e 's%.lua%.3%g'|sed -e 's%/%.%g'`
echo "
dnsjit.${man}in: $file gen-manpage.lua
\$(LUAJIT) \"\$(srcdir)/gen-manpage.lua\" \"\$(srcdir)/$file\" > \"\$@\"";
done

View file

@ -100,9 +100,10 @@ for line in io.lines(arg[1]) do
end
print[[
.SH AUTHORS
.SH AUTHORS and CONTRIBUTORS
Jerry Lundström (DNS-OARC),
Tomáš Křížek (CZ.NIC)
Tomáš Křížek (CZ.NIC),
Petr Špaček (ISC)
.LP
Maintained by DNS-OARC
.LP

View file

@ -25,5 +25,6 @@ module(...,package.seeall)
-- dnsjit.input.fpcap (3),
-- dnsjit.input.mmpcap (3),
-- dnsjit.input.pcap (3),
-- dnsjit.input.zero (3)
-- dnsjit.input.zero (3),
-- dnsjit.input.zpcap (3)
return

View file

@ -24,6 +24,7 @@
#include "core/assert.h"
#include "core/object/pcap.h"
#include <fcntl.h>
#include <stdio.h>
#ifdef HAVE_ENDIAN_H
#include <endian.h>
@ -60,7 +61,7 @@ static input_fpcap_t _defaults = {
0, 0,
0, 0, 0,
CORE_OBJECT_PCAP_INIT(0),
0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0
};
@ -91,6 +92,16 @@ static int _open(input_fpcap_t* self)
{
mlassert_self();
#if _POSIX_C_SOURCE >= 200112L || defined(__FreeBSD__)
if (self->use_fadvise) {
int err = posix_fadvise(fileno((FILE*)self->file), 0, 0, POSIX_FADV_SEQUENTIAL);
if (err) {
lcritical("posix_fadvise() failed: %s", core_log_errstr(err));
return -2;
}
}
#endif
if (fread(&self->magic_number, 1, 4, self->file) != 4
|| fread(&self->version_major, 1, 2, self->file) != 2
|| fread(&self->version_minor, 1, 2, self->file) != 2

View file

@ -18,14 +18,14 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/log.h"
#include "core/receiver.h"
#include "core/producer.h"
#include "core/object/pcap.h"
#include <dnsjit/core/log.h>
#include <dnsjit/core/receiver.h>
#include <dnsjit/core/producer.h>
#include <dnsjit/core/object/pcap.h>
#ifndef __dnsjit_input_fpcap_h
#define __dnsjit_input_fpcap_h
#include "input/fpcap.hh"
#include <dnsjit/input/fpcap.hh>
#endif

View file

@ -35,7 +35,7 @@ typedef struct input_fpcap {
core_object_pcap_t prod_pkt;
void* file;
int extern_file;
int extern_file, use_fadvise;
size_t pkts;
uint8_t* buf;
size_t buf_size;

View file

@ -100,6 +100,15 @@ function Fpcap:produce()
return C.input_fpcap_producer(self.obj), self.obj
end
-- Use
-- .B posix_fadvise()
-- to indicate sequential reading (if supported), may increase performance.
-- MUST be called before
-- .BR open() .
function Fpcap:fadvise_sequential()
self.obj.use_fadvise = 1
end
-- Open a PCAP file for processing and read the PCAP header.
-- Returns 0 on success.
function Fpcap:open(file)

View file

@ -18,14 +18,14 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/log.h"
#include "core/receiver.h"
#include "core/producer.h"
#include "core/object/pcap.h"
#include <dnsjit/core/log.h>
#include <dnsjit/core/receiver.h>
#include <dnsjit/core/producer.h>
#include <dnsjit/core/object/pcap.h>
#ifndef __dnsjit_input_mmpcap_h
#define __dnsjit_input_mmpcap_h
#include "input/mmpcap.hh"
#include <dnsjit/input/mmpcap.hh>
#endif

View file

@ -18,16 +18,16 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/log.h"
#include "core/receiver.h"
#include "core/producer.h"
#include "core/object/pcap.h"
#include <dnsjit/core/log.h>
#include <dnsjit/core/receiver.h>
#include <dnsjit/core/producer.h>
#include <dnsjit/core/object/pcap.h>
#ifndef __dnsjit_input_pcap_h
#define __dnsjit_input_pcap_h
#include <pcap/pcap.h>
#include "input/pcap.hh"
#include <dnsjit/input/pcap.hh>
#endif

View file

@ -1,75 +0,0 @@
/*
* Copyright (c) 2018-2021, OARC, Inc.
* All rights reserved.
*
* This file is part of dnsjit.
*
* dnsjit is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dnsjit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "input/zero.h"
#include "core/assert.h"
#include "core/object/null.h"
#include <time.h>
static core_log_t _log = LOG_T_INIT("input.zero");
static input_zero_t _defaults = {
LOG_T_INIT_OBJ("input.zero"),
0,
0,
};
static core_object_null_t _null = CORE_OBJECT_NULL_INIT(0);
core_log_t* input_zero_log()
{
return &_log;
}
void input_zero_init(input_zero_t* self)
{
mlassert_self();
*self = _defaults;
}
void input_zero_destroy(input_zero_t* self)
{
mlassert_self();
}
void input_zero_run(input_zero_t* self, uint64_t num)
{
mlassert_self();
if (!self->recv) {
lfatal("no receiver set");
}
while (num--) {
self->recv(self->ctx, (core_object_t*)&_null);
}
}
static const core_object_t* _produce(void* ctx)
{
return (core_object_t*)&_null;
}
core_producer_t input_zero_producer()
{
return _produce;
}

View file

@ -17,59 +17,15 @@
-- along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
-- dnsjit.input.zero
-- Generate empty objects (/dev/zero)
-- local input = require("dnsjit.input.zero").new()
-- input:receiver(filter_or_output)
-- input:run(1e6)
-- Dummy layer to example.input.zero
--
-- Input module for generating empty
-- .I core.object.null
-- objects, mostly used for testing.
-- This module has moved to example.input.zero, see examples/modules/input-example in
-- dnsjit source repository.
module(...,package.seeall)
require("dnsjit.input.zero_h")
local ffi = require("ffi")
local C = ffi.C
local t_name = "input_zero_t"
local input_zero_t = ffi.typeof(t_name)
local Zero = {}
-- Create a new Zero input.
function Zero.new()
local self = {
_receiver = nil,
obj = input_zero_t(),
}
C.input_zero_init(self.obj)
ffi.gc(self.obj, C.input_zero_destroy)
return setmetatable(self, { __index = Zero })
ok, cls = pcall(require, "example.input.zero")
if not ok then
error("You need to install the example module input-example\n" .. cls)
end
-- Return the Log object to control logging of this instance or module.
function Zero:log()
if self == nil then
return C.input_zero_log()
end
return self.obj._log
end
-- Set the receiver to pass objects to.
function Zero:receiver(o)
self.obj.recv, self.obj.ctx = o:receive()
self._receiver = o
end
-- Return the C functions and context for producing objects.
function Zero:produce()
return C.input_zero_producer(), self.obj
end
-- Generate
-- .I num
-- empty objects and send them to the receiver.
function Zero:run(num)
C.input_zero_run(self.obj, num)
end
return Zero
return cls

582
src/input/zpcap.c Normal file
View file

@ -0,0 +1,582 @@
/*
* Copyright (c) 2018-2021, OARC, Inc.
* All rights reserved.
*
* This file is part of dnsjit.
*
* dnsjit is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dnsjit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "input/zpcap.h"
#include "core/assert.h"
#include "core/object/pcap.h"
#include <fcntl.h>
#include <stdio.h>
#ifdef HAVE_ENDIAN_H
#include <endian.h>
#else
#ifdef HAVE_SYS_ENDIAN_H
#include <sys/endian.h>
#else
#ifdef HAVE_MACHINE_ENDIAN_H
#include <machine/endian.h>
#endif
#endif
#endif
#ifdef HAVE_BYTESWAP_H
#include <byteswap.h>
#endif
#ifndef bswap_16
#ifndef bswap16
#define bswap_16(x) swap16(x)
#define bswap_32(x) swap32(x)
#define bswap_64(x) swap64(x)
#else
#define bswap_16(x) bswap16(x)
#define bswap_32(x) bswap32(x)
#define bswap_64(x) bswap64(x)
#endif
#endif
#include <pcap/pcap.h>
#include <string.h>
#ifdef HAVE_LZ4
#include <lz4frame.h>
struct _lz4_ctx {
LZ4F_dctx* ctx;
LZ4F_decompressOptions_t opts;
};
#define lz4 ((struct _lz4_ctx*)self->comp_ctx)
#endif
#ifdef HAVE_ZSTD
#include <zstd.h>
struct _zstd_ctx {
ZSTD_DCtx* ctx;
ZSTD_inBuffer in;
ZSTD_outBuffer out;
};
#define zstd ((struct _zstd_ctx*)self->comp_ctx)
#endif
#define MAX_SNAPLEN 0x40000
static core_log_t _log = LOG_T_INIT("input.zpcap");
static input_zpcap_t _defaults = {
LOG_T_INIT_OBJ("input.zpcap"),
0, 0,
0, 0, 0,
CORE_OBJECT_PCAP_INIT(0),
input_zpcap_type_none, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0
};
core_log_t* input_zpcap_log()
{
return &_log;
}
void input_zpcap_init(input_zpcap_t* self)
{
mlassert_self();
*self = _defaults;
}
void input_zpcap_destroy(input_zpcap_t* self)
{
mlassert_self();
switch (self->compression) {
#ifdef HAVE_LZ4
case input_zpcap_type_lz4: {
LZ4F_errorCode_t code;
if (lz4) {
if (lz4->ctx && (code = LZ4F_freeDecompressionContext(lz4->ctx))) {
lfatal("LZ4F_freeDecompressionContext() failed: %s", LZ4F_getErrorName(code));
}
}
free(lz4);
free(self->in);
free(self->out);
break;
}
#endif
#ifdef HAVE_ZSTD
case input_zpcap_type_zstd:
if (zstd) {
if (zstd->ctx) {
ZSTD_freeDCtx(zstd->ctx);
}
}
free(zstd);
free(self->in);
free(self->out);
break;
#endif
default:
break;
}
if (!self->extern_file && self->file) {
fclose(self->file);
}
free(self->buf);
}
static ssize_t _read(input_zpcap_t* self, void* dst, size_t len, void** dstp)
{
switch (self->compression) {
#ifdef HAVE_LZ4
case input_zpcap_type_lz4: {
size_t need = len;
if (dstp && self->out_have > need) {
*dstp = self->out + self->out_at;
self->out_have -= need;
self->out_at += need;
return len;
}
for (;;) {
if (self->out_have > need) {
memcpy(dst, self->out + self->out_at, need);
self->out_have -= need;
self->out_at += need;
return len;
}
memcpy(dst, self->out + self->out_at, self->out_have);
need -= self->out_have;
dst += self->out_have;
ssize_t n = fread(self->in + self->in_at, 1, self->in_size - self->in_have, self->file);
if (n < 0) {
return n;
}
self->in_at += n;
self->in_have += n;
if (!self->in_have) {
return 0;
}
size_t dst_size = self->out_size, src_size = self->in_have;
size_t code = LZ4F_decompress(lz4->ctx, self->out, &dst_size, self->in, &src_size, &lz4->opts);
if (LZ4F_isError(code)) {
lfatal("LZ4F_decompress() failed: %s", LZ4F_getErrorName(code));
}
if (src_size < self->in_have) {
self->in_have -= src_size;
memmove(self->in, self->in + src_size, self->in_have);
self->in_at = self->in_have;
} else {
self->in_at = 0;
self->in_have = 0;
}
self->out_at = 0;
self->out_have = dst_size;
}
}
#endif
#ifdef HAVE_ZSTD
case input_zpcap_type_zstd: {
size_t need = len;
if (dstp && self->out_have > need) {
*dstp = self->out + self->out_at;
self->out_have -= need;
self->out_at += need;
return len;
}
for (;;) {
if (self->out_have > need) {
memcpy(dst, self->out + self->out_at, need);
self->out_have -= need;
self->out_at += need;
return len;
}
memcpy(dst, self->out + self->out_at, self->out_have);
need -= self->out_have;
dst += self->out_have;
if (zstd->in.pos >= zstd->in.size) {
ssize_t n = fread(self->in, 1, self->in_size, self->file);
if (n < 1) {
return n;
}
zstd->in.size = n;
zstd->in.pos = 0;
}
zstd->out.size = self->out_size;
zstd->out.pos = 0;
size_t code = ZSTD_decompressStream(zstd->ctx, &zstd->out, &zstd->in);
if (ZSTD_isError(code)) {
lfatal("ZSTD_decompressStream() failed: %s", ZSTD_getErrorName(code));
}
self->out_have = zstd->out.pos;
self->out_at = 0;
}
}
#endif
default:
return 0;
}
}
static int _open(input_zpcap_t* self)
{
mlassert_self();
#if _POSIX_C_SOURCE >= 200112L || defined(__FreeBSD__)
if (self->use_fadvise) {
int err = posix_fadvise(fileno((FILE*)self->file), 0, 0, POSIX_FADV_SEQUENTIAL);
if (err) {
lcritical("posix_fadvise() failed: %s", core_log_errstr(err));
return -2;
}
}
#endif
switch (self->compression) {
#ifdef HAVE_LZ4
case input_zpcap_type_lz4: {
LZ4F_errorCode_t code;
if (lz4) {
if (lz4->ctx && (code = LZ4F_freeDecompressionContext(lz4->ctx))) {
lfatal("LZ4F_freeDecompressionContext() failed: %s", LZ4F_getErrorName(code));
}
}
free(lz4);
free(self->in);
free(self->out);
lfatal_oom(self->comp_ctx = calloc(1, sizeof(struct _lz4_ctx)));
if ((code = LZ4F_createDecompressionContext(&lz4->ctx, LZ4F_VERSION))) {
lfatal("LZ4F_createDecompressionContext() failed: %s", LZ4F_getErrorName(code));
}
lz4->opts.stableDst = 1;
self->in_size = 256 * 1024;
lfatal_oom(self->in = malloc(self->in_size));
self->out_size = 256 * 1024;
lfatal_oom(self->out = malloc(self->out_size));
break;
}
#endif
#ifdef HAVE_ZSTD
case input_zpcap_type_zstd:
if (zstd) {
if (zstd->ctx) {
ZSTD_freeDCtx(zstd->ctx);
}
}
free(zstd);
free(self->in);
free(self->out);
lfatal_oom(self->comp_ctx = calloc(1, sizeof(struct _zstd_ctx)));
lfatal_oom(zstd->ctx = ZSTD_createDCtx());
self->in_size = ZSTD_DStreamInSize();
lfatal_oom(self->in = malloc(self->in_size));
self->out_size = ZSTD_DStreamOutSize();
lfatal_oom(self->out = malloc(self->out_size));
zstd->in.src = self->in;
zstd->out.dst = self->out;
zstd->out.size = self->out_size;
break;
#endif
default:
lcritical("no support for selected compression");
return -2;
}
if (_read(self, &self->magic_number, 4, 0) != 4
|| _read(self, &self->version_major, 2, 0) != 2
|| _read(self, &self->version_minor, 2, 0) != 2
|| _read(self, &self->thiszone, 4, 0) != 4
|| _read(self, &self->sigfigs, 4, 0) != 4
|| _read(self, &self->snaplen, 4, 0) != 4
|| _read(self, &self->network, 4, 0) != 4) {
lcritical("could not read full PCAP header");
return -2;
}
switch (self->magic_number) {
case 0x4d3cb2a1:
self->is_nanosec = 1;
case 0xd4c3b2a1:
self->is_swapped = 1;
self->version_major = bswap_16(self->version_major);
self->version_minor = bswap_16(self->version_minor);
self->thiszone = (int32_t)bswap_32((uint32_t)self->thiszone);
self->sigfigs = bswap_32(self->sigfigs);
self->snaplen = bswap_32(self->snaplen);
self->network = bswap_32(self->network);
break;
case 0xa1b2c3d4:
case 0xa1b23c4d:
break;
default:
lcritical("invalid PCAP header");
return -2;
}
if (self->snaplen > MAX_SNAPLEN) {
lcritical("too large snaplen (%u)", self->snaplen);
return -2;
}
if (self->version_major != 2 || self->version_minor != 4) {
lcritical("unsupported PCAP version v%u.%u", self->version_major, self->version_minor);
return -2;
}
/*
* Translation taken from https://github.com/the-tcpdump-group/libpcap/blob/90543970fd5fbed261d3637f5ec4811d7dde4e49/pcap-common.c#L1212 .
*/
switch (self->network) {
case 101:
self->linktype = DLT_RAW;
break;
#ifdef DLT_FR
case 107: /* LINKTYPE_FRELAY */
self->linktype = DLT_FR;
break;
#endif
case 100: /* LINKTYPE_ATM_RFC1483 */
self->linktype = DLT_ATM_RFC1483;
break;
case 102: /* LINKTYPE_SLIP_BSDOS */
self->linktype = DLT_SLIP_BSDOS;
break;
case 103: /* LINKTYPE_PPP_BSDOS */
self->linktype = DLT_PPP_BSDOS;
break;
case 104: /* LINKTYPE_C_HDLC */
self->linktype = DLT_C_HDLC;
break;
case 106: /* LINKTYPE_ATM_CLIP */
self->linktype = DLT_ATM_CLIP;
break;
case 50: /* LINKTYPE_PPP_HDLC */
self->linktype = DLT_PPP_SERIAL;
break;
case 51: /* LINKTYPE_PPP_ETHER */
self->linktype = DLT_PPP_ETHER;
break;
default:
self->linktype = self->network;
}
lfatal_oom(self->buf = malloc(self->snaplen));
self->prod_pkt.snaplen = self->snaplen;
self->prod_pkt.linktype = self->linktype;
self->prod_pkt.is_swapped = self->is_swapped;
ldebug("pcap v%u.%u snaplen:%lu %s", self->version_major, self->version_minor, self->snaplen, self->is_swapped ? " swapped" : "");
return 0;
}
int input_zpcap_open(input_zpcap_t* self, const char* file)
{
mlassert_self();
lassert(file, "file is nil");
if (self->file) {
lfatal("already opened");
}
if (!(self->file = fopen(file, "rb"))) {
lcritical("fopen(%s) error: %s", file, core_log_errstr(errno));
return -1;
}
return _open(self);
}
int input_zpcap_openfp(input_zpcap_t* self, void* fp)
{
mlassert_self();
if (self->file) {
lfatal("already opened");
}
self->file = fp;
self->extern_file = 1;
return _open(self);
}
int input_zpcap_run(input_zpcap_t* self)
{
struct {
uint32_t ts_sec;
uint32_t ts_usec;
uint32_t incl_len;
uint32_t orig_len;
} hdr;
core_object_pcap_t pkt = CORE_OBJECT_PCAP_INIT(0);
int ret;
mlassert_self();
if (!self->file) {
lfatal("no PCAP opened");
}
if (!self->recv) {
lfatal("no receiver set");
}
pkt.snaplen = self->snaplen;
pkt.linktype = self->linktype;
pkt.is_swapped = self->is_swapped;
while ((ret = _read(self, &hdr, 16, 0)) == 16) {
if (self->is_swapped) {
hdr.ts_sec = bswap_32(hdr.ts_sec);
hdr.ts_usec = bswap_32(hdr.ts_usec);
hdr.incl_len = bswap_32(hdr.incl_len);
hdr.orig_len = bswap_32(hdr.orig_len);
}
if (hdr.incl_len > self->snaplen) {
lwarning("invalid packet length, larger then snaplen");
return -1;
}
pkt.bytes = (unsigned char*)self->buf;
if (_read(self, self->buf, hdr.incl_len, (void**)&pkt.bytes) != hdr.incl_len) {
lwarning("could not read all of packet, aborting");
return -1;
}
self->pkts++;
pkt.ts.sec = hdr.ts_sec;
if (self->is_nanosec) {
pkt.ts.nsec = hdr.ts_usec;
} else {
pkt.ts.nsec = hdr.ts_usec * 1000;
}
pkt.caplen = hdr.incl_len;
pkt.len = hdr.orig_len;
self->recv(self->ctx, (core_object_t*)&pkt);
}
if (ret) {
lwarning("could not read next PCAP header, aborting");
return -1;
}
return 0;
}
int input_zpcap_have_support(input_zpcap_t* self)
{
mlassert_self();
switch (self->compression) {
#ifdef HAVE_LZ4
case input_zpcap_type_lz4:
return 1;
#endif
#ifdef HAVE_ZSTD
case input_zpcap_type_zstd:
return 1;
#endif
default:
break;
}
return 0;
}
static const core_object_t* _produce(input_zpcap_t* self)
{
struct {
uint32_t ts_sec;
uint32_t ts_usec;
uint32_t incl_len;
uint32_t orig_len;
} hdr;
int ret;
mlassert_self();
if (self->is_broken) {
lwarning("PCAP is broken, will not read next packet");
return 0;
}
if ((ret = _read(self, &hdr, 16, 0)) != 16) {
if (ret) {
lwarning("could not read next PCAP header, aborting");
self->is_broken = 1;
}
return 0;
}
if (self->is_swapped) {
hdr.ts_sec = bswap_32(hdr.ts_sec);
hdr.ts_usec = bswap_32(hdr.ts_usec);
hdr.incl_len = bswap_32(hdr.incl_len);
hdr.orig_len = bswap_32(hdr.orig_len);
}
if (hdr.incl_len > self->snaplen) {
lwarning("invalid packet length, larger then snaplen");
self->is_broken = 1;
return 0;
}
self->prod_pkt.bytes = (unsigned char*)self->buf;
if (_read(self, self->buf, hdr.incl_len, (void**)&self->prod_pkt.bytes) != hdr.incl_len) {
lwarning("could not read all of packet, aborting");
self->is_broken = 1;
return 0;
}
self->pkts++;
self->prod_pkt.ts.sec = hdr.ts_sec;
if (self->is_nanosec) {
self->prod_pkt.ts.nsec = hdr.ts_usec;
} else {
self->prod_pkt.ts.nsec = hdr.ts_usec * 1000;
}
self->prod_pkt.caplen = hdr.incl_len;
self->prod_pkt.len = hdr.orig_len;
return (core_object_t*)&self->prod_pkt;
}
core_producer_t input_zpcap_producer(input_zpcap_t* self)
{
mlassert_self();
if (!self->file) {
lfatal("no PCAP opened");
}
return (core_producer_t)_produce;
}

31
src/input/zpcap.h Normal file
View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2018-2021, OARC, Inc.
* All rights reserved.
*
* This file is part of dnsjit.
*
* dnsjit is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dnsjit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include <dnsjit/core/log.h>
#include <dnsjit/core/receiver.h>
#include <dnsjit/core/producer.h>
#include <dnsjit/core/object/pcap.h>
#ifndef __dnsjit_input_zpcap_h
#define __dnsjit_input_zpcap_h
#include <dnsjit/input/zpcap.hh>
#endif

77
src/input/zpcap.hh Normal file
View file

@ -0,0 +1,77 @@
/*
* Copyright (c) 2018-2021, OARC, Inc.
* All rights reserved.
*
* This file is part of dnsjit.
*
* dnsjit is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dnsjit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
//lua:require("dnsjit.core.log")
//lua:require("dnsjit.core.receiver_h")
//lua:require("dnsjit.core.producer_h")
//lua:require("dnsjit.core.object.pcap_h")
typedef enum input_zpcap_type {
input_zpcap_type_none,
input_zpcap_type_lz4,
input_zpcap_type_zstd
} input_zpcap_type_t;
typedef struct input_zpcap {
core_log_t _log;
core_receiver_t recv;
void* ctx;
uint8_t is_swapped;
uint8_t is_nanosec;
uint8_t is_broken;
core_object_pcap_t prod_pkt;
input_zpcap_type_t compression;
void* comp_ctx;
void * in, *out;
size_t in_size, out_size;
size_t in_have, out_have;
size_t in_at, out_at;
void* file;
int extern_file, use_fadvise;
size_t pkts;
uint8_t* buf;
size_t buf_size;
uint32_t magic_number;
uint16_t version_major;
uint16_t version_minor;
int32_t thiszone;
uint32_t sigfigs;
uint32_t snaplen;
uint32_t network;
uint32_t linktype;
} input_zpcap_t;
core_log_t* input_zpcap_log();
void input_zpcap_init(input_zpcap_t* self);
void input_zpcap_destroy(input_zpcap_t* self);
int input_zpcap_open(input_zpcap_t* self, const char* file);
int input_zpcap_openfp(input_zpcap_t* self, void* fp);
int input_zpcap_run(input_zpcap_t* self);
int input_zpcap_have_support(input_zpcap_t* self);
core_producer_t input_zpcap_producer(input_zpcap_t* self);

159
src/input/zpcap.lua Normal file
View file

@ -0,0 +1,159 @@
-- Copyright (c) 2018-2021, OARC, Inc.
-- All rights reserved.
--
-- This file is part of dnsjit.
--
-- dnsjit is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- dnsjit is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
-- dnsjit.input.zpcap
-- Read input from a PCAP file that is compressed
-- local input = require("dnsjit.input.zpcap").new()
-- input:zstd()
-- input:open("file.pcap.zst")
-- input:receiver(filter_or_output)
-- input:run()
--
-- Read input from a PCAP file that is compressed and parse the PCAP without
-- libpcap.
-- After opening a file and reading the PCAP header, the attributes are
-- populated.
-- .SS Attributes
-- .TP
-- is_swapped
-- Indicate if the byte order in the PCAP is in reverse order of the host.
-- .TP
-- is_nanosec
-- Indicate if the time stamps are in nanoseconds or not.
-- .TP
-- magic_number
-- Magic number.
-- .TP
-- version_major
-- Major version number.
-- .TP
-- version_minor
-- Minor version number.
-- .TP
-- thiszone
-- GMT to local correction.
-- .TP
-- sigfigs
-- Accuracy of timestamps.
-- .TP
-- snaplen
-- Max length of captured packets, in octets.
-- .TP
-- network
-- The link type found in the PCAP header, see https://www.tcpdump.org/linktypes.html .
-- .TP
-- linktype
-- The data link type, mapped from
-- .IR network .
module(...,package.seeall)
require("dnsjit.input.zpcap_h")
local ffi = require("ffi")
local C = ffi.C
local t_name = "input_zpcap_t"
local input_zpcap_t = ffi.typeof(t_name)
local Zpcap = {}
-- Create a new Zpcap input.
function Zpcap.new()
local self = {
_receiver = nil,
obj = input_zpcap_t(),
}
C.input_zpcap_init(self.obj)
ffi.gc(self.obj, C.input_zpcap_destroy)
return setmetatable(self, { __index = Zpcap })
end
-- Return the Log object to control logging of this instance or module.
function Zpcap:log()
if self == nil then
return C.input_zpcap_log()
end
return self.obj._log
end
-- Set the receiver to pass objects to.
function Zpcap:receiver(o)
self.obj.recv, self.obj.ctx = o:receive()
self._receiver = o
end
-- Return the C functions and context for producing objects.
function Zpcap:produce()
return C.input_zpcap_producer(self.obj), self.obj
end
-- Use
-- .B posix_fadvise()
-- to indicate sequential reading (if supported), may increase performance.
-- MUST be called before
-- .BR open() .
function Zpcap:fadvise_sequential()
self.obj.use_fadvise = 1
end
-- Use liblz4 to decompress the input file/data.
function Zpcap:lz4()
self.obj.compression = "input_zpcap_type_lz4"
end
-- Use libzstd to decompress the input file/data.
function Zpcap:zstd()
self.obj.compression = "input_zpcap_type_zstd"
end
-- Return true if support for selected compression library is built in.
function Zpcap:have_support()
if C.input_zpcap_have_support(self.obj) == 1 then
return true
end
return false
end
-- Open a PCAP file for processing and read the PCAP header.
-- Returns 0 on success.
function Zpcap:open(file)
return C.input_zpcap_open(self.obj, file)
end
-- Open a PCAP file for processing and read the PCAP header using a
-- file descriptor, for example
-- .B io.stdin
-- or with
-- .BR io.open() .
-- Will not take ownership of the file descriptor.
-- Returns 0 on success.
function Zpcap:openfp(fp)
return C.input_zpcap_openfp(self.obj, fp)
end
-- Start processing packets and send each packet read to the receiver.
-- Returns 0 if all packets was read successfully.
function Zpcap:run()
return C.input_zpcap_run(self.obj)
end
-- Return the number of packets seen.
function Zpcap:packets()
return tonumber(self.obj.pkts)
end
-- dnsjit.input.fpcap (3)
return Zpcap

View file

@ -23,6 +23,6 @@
#ifndef __dnsjit_lib_base64url_h
#define __dnsjit_lib_base64url_h
#include "lib/base64url.hh"
#include <dnsjit/lib/base64url.hh>
#endif

View file

@ -93,6 +93,5 @@ function Base64Url.decode(data)
return ffi.string(buf, out_len)
end
-- dnsjit.core.object.payload(3)
-- dnsjit.output.dnssim (3)
-- dnsjit.core.object.payload (3)
return Base64Url

View file

@ -18,11 +18,11 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/timespec.h"
#include <dnsjit/core/timespec.h>
#ifndef __dnsjit_lib_clock_h
#define __dnsjit_lib_clock_h
#include "lib/clock.hh"
#include <dnsjit/lib/clock.hh>
#endif

View file

@ -122,6 +122,9 @@ function Getopt:add(short, long, default, help, extensions)
elseif name == "" then
error("name (long|short) needs to be set")
end
if short and (type(short) ~= "string" or #short ~= 1) then
error("short needs to be a string of length 1")
end
if self._opt[name] then
error("option "..name.." alredy exists")

View file

@ -22,7 +22,7 @@
#ifndef __dnsjit_contrib_trie_h
#define __dnsjit_contrib_trie_h
#include "lib/trie.hh"
#include <dnsjit/lib/trie.hh>
#ifndef likely
/*! \brief Optimize for x to be true value. */

View file

@ -24,7 +24,6 @@
module(...,package.seeall)
-- dnsjit.output.dnscli (3),
-- dnsjit.output.dnssim (3),
-- dnsjit.output.null (3),
-- dnsjit.output.pcap (3),
-- dnsjit.output.respdiff (3),

View file

@ -18,12 +18,12 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/log.h"
#include "core/receiver.h"
#include "core/producer.h"
#include "core/object/payload.h"
#include "core/timespec.h"
#include "core/compat.h"
#include <dnsjit/core/log.h>
#include <dnsjit/core/receiver.h>
#include <dnsjit/core/producer.h>
#include <dnsjit/core/object/payload.h>
#include <dnsjit/core/timespec.h>
#include <dnsjit/core/compat.h>
#ifndef __dnsjit_output_dnscli_h
#define __dnsjit_output_dnscli_h
@ -33,6 +33,6 @@
#include <gnutls/gnutls.h>
#include <poll.h>
#include "output/dnscli.hh"
#include <dnsjit/output/dnscli.hh>
#endif

View file

@ -1,502 +0,0 @@
/*
* Copyright (c) 2019-2020, CZ.NIC, z.s.p.o.
* All rights reserved.
*
* This file is part of dnsjit.
*
* dnsjit is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dnsjit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "output/dnssim.h"
#include "output/dnssim/internal.h"
#include "output/dnssim/ll.h"
#include "core/assert.h"
#include "core/object/ip.h"
#include "core/object/ip6.h"
#include <gnutls/gnutls.h>
#include <string.h>
static core_log_t _log = LOG_T_INIT("output.dnssim");
static output_dnssim_t _defaults = { LOG_T_INIT_OBJ("output.dnssim") };
static uint64_t _now_ms()
{
#if HAVE_CLOCK_NANOSLEEP
struct timespec ts;
uint64_t now_ms;
if (clock_gettime(CLOCK_REALTIME, &ts)) {
mlfatal("clock_gettime()");
}
now_ms = ts.tv_sec * 1000;
now_ms += ts.tv_nsec / 1000000;
return now_ms;
#else
mlfatal("clock_gettime() not available");
return 0;
#endif
}
core_log_t* output_dnssim_log()
{
return &_log;
}
output_dnssim_t* output_dnssim_new(size_t max_clients)
{
output_dnssim_t* self;
int ret, i;
mlfatal_oom(self = calloc(1, sizeof(_output_dnssim_t)));
*self = _defaults;
self->handshake_timeout_ms = 5000;
self->idle_timeout_ms = 10000;
output_dnssim_timeout_ms(self, 2000);
_self->source = NULL;
_self->transport = OUTPUT_DNSSIM_TRANSPORT_UDP_ONLY;
_self->h2_zero_out_msgid = false;
self->max_clients = max_clients;
lfatal_oom(_self->client_arr = calloc(max_clients, sizeof(_output_dnssim_client_t)));
for (i = 0; i < max_clients; ++i) {
_self->client_arr[i].dnssim = self;
}
ret = gnutls_certificate_allocate_credentials(&_self->tls_cred);
if (ret < 0)
lfatal("failed to allocated TLS credentials (%s)", gnutls_strerror(ret));
ret = uv_loop_init(&_self->loop);
if (ret < 0)
lfatal("failed to initialize uv_loop (%s)", uv_strerror(ret));
ldebug("initialized uv_loop");
return self;
}
void output_dnssim_free(output_dnssim_t* self)
{
mlassert_self();
int ret, i;
_output_dnssim_source_t* source;
_output_dnssim_source_t* first = _self->source;
output_dnssim_stats_t* stats_prev;
free(self->stats_sum->latency);
free(self->stats_sum);
do {
stats_prev = self->stats_current->prev;
free(self->stats_current->latency);
free(self->stats_current);
self->stats_current = stats_prev;
} while (self->stats_current != NULL);
if (_self->source != NULL) {
// free cilcular linked list
do {
source = _self->source->next;
free(_self->source);
_self->source = source;
} while (_self->source != first);
}
for (i = 0; i < self->max_clients; ++i) {
if (_self->client_arr[i].tls_ticket.size != 0) {
gnutls_free(_self->client_arr[i].tls_ticket.data);
}
}
free(_self->client_arr);
ret = uv_loop_close(&_self->loop);
if (ret < 0) {
lcritical("failed to close uv_loop (%s)", uv_strerror(ret));
} else {
ldebug("closed uv_loop");
}
gnutls_certificate_free_credentials(_self->tls_cred);
if (_self->tls_priority != NULL) {
gnutls_priority_deinit(*_self->tls_priority);
free(_self->tls_priority);
}
free(self);
}
void output_dnssim_log_name(output_dnssim_t* self, const char* name)
{
mlassert_self();
lassert(name, "name is nil");
strncpy(self->_log.name, name, sizeof(self->_log.name) - 1);
self->_log.name[sizeof(self->_log.name) - 1] = 0;
self->_log.is_obj = false;
}
static uint32_t _extract_client(const core_object_t* obj)
{
uint32_t client;
uint8_t* ip;
switch (obj->obj_type) {
case CORE_OBJECT_IP:
ip = ((core_object_ip_t*)obj)->dst;
break;
case CORE_OBJECT_IP6:
ip = ((core_object_ip6_t*)obj)->dst;
break;
default:
return -1;
}
memcpy(&client, ip, sizeof(client));
return client;
}
static void _receive(output_dnssim_t* self, const core_object_t* obj)
{
mlassert_self();
core_object_t* current = (core_object_t*)obj;
core_object_payload_t* payload;
uint32_t client;
self->processed++;
/* get payload from packet */
for (;;) {
if (current->obj_type == CORE_OBJECT_PAYLOAD) {
payload = (core_object_payload_t*)current;
break;
}
if (current->obj_prev == NULL) {
self->discarded++;
lwarning("packet discarded (missing payload object)");
return;
}
current = (core_object_t*)current->obj_prev;
}
/* extract client information from IP/IP6 layer */
for (;;) {
if (current->obj_type == CORE_OBJECT_IP || current->obj_type == CORE_OBJECT_IP6) {
client = _extract_client(current);
break;
}
if (current->obj_prev == NULL) {
self->discarded++;
lwarning("packet discarded (missing ip/ip6 object)");
return;
}
current = (core_object_t*)current->obj_prev;
}
if (self->free_after_use) {
/* free all objects except payload */
current = (core_object_t*)obj;
core_object_t* parent = current;
while (current != NULL) {
parent = current;
current = (core_object_t*)current->obj_prev;
if (parent->obj_type != CORE_OBJECT_PAYLOAD) {
core_object_free(parent);
}
}
}
if (_self->h2_zero_out_msgid) {
lassert(_self->transport == OUTPUT_DNSSIM_TRANSPORT_HTTPS2, "must use HTTP/2 to zero-out msgid");
if (payload->len < 2) {
self->discarded++;
lwarning("packet discarded (payload len < 2)");
return;
}
uint8_t* data = (uint8_t*)payload->payload;
data[0] = 0x00;
data[1] = 0x00;
}
if (client >= self->max_clients) {
self->discarded++;
lwarning("packet discarded (client exceeded max_clients)");
return;
}
ldebug("client(c): %d", client);
_output_dnssim_create_request(self, &_self->client_arr[client], payload);
}
core_receiver_t output_dnssim_receiver()
{
return (core_receiver_t)_receive;
}
void output_dnssim_set_transport(output_dnssim_t* self, output_dnssim_transport_t tr)
{
mlassert_self();
switch (tr) {
case OUTPUT_DNSSIM_TRANSPORT_UDP_ONLY:
lnotice("transport set to UDP (no TCP fallback)");
break;
case OUTPUT_DNSSIM_TRANSPORT_TCP:
lnotice("transport set to TCP");
break;
case OUTPUT_DNSSIM_TRANSPORT_TLS:
#if GNUTLS_VERSION_NUMBER >= DNSSIM_MIN_GNUTLS_VERSION
lnotice("transport set to TLS");
#else
lfatal(DNSSIM_MIN_GNUTLS_ERRORMSG);
#endif
break;
case OUTPUT_DNSSIM_TRANSPORT_HTTPS2:
#if GNUTLS_VERSION_NUMBER >= DNSSIM_MIN_GNUTLS_VERSION
lnotice("transport set to HTTP/2 over TLS");
if (&_self->h2_uri_authority[0])
lnotice("set uri authority to: %s", _self->h2_uri_authority);
#else
lfatal(DNSSIM_MIN_GNUTLS_ERRORMSG);
#endif
break;
case OUTPUT_DNSSIM_TRANSPORT_UDP:
lfatal("UDP transport with TCP fallback is not supported yet.");
break;
default:
lfatal("unknown or unsupported transport");
break;
}
_self->transport = tr;
}
int output_dnssim_target(output_dnssim_t* self, const char* ip, uint16_t port)
{
int ret;
mlassert_self();
lassert(ip, "ip is nil");
lassert(port, "port is nil");
ret = uv_ip6_addr(ip, port, (struct sockaddr_in6*)&_self->target);
if (ret != 0) {
ret = uv_ip4_addr(ip, port, (struct sockaddr_in*)&_self->target);
if (ret != 0) {
lfatal("failed to parse IPv4 or IPv6 from \"%s\"", ip);
} else {
ret = snprintf(_self->h2_uri_authority, _MAX_URI_LEN, "%s:%d", ip, port);
}
} else {
ret = snprintf(_self->h2_uri_authority, _MAX_URI_LEN, "[%s]:%d", ip, port);
}
if (ret > 0) {
if (_self->transport == OUTPUT_DNSSIM_TRANSPORT_HTTPS2)
lnotice("set uri authority to: %s", _self->h2_uri_authority);
} else {
_self->h2_uri_authority[0] = '\0';
if (_self->transport == OUTPUT_DNSSIM_TRANSPORT_HTTPS2)
lfatal("failed to set authority");
}
lnotice("set target to %s port %d", ip, port);
return 0;
}
int output_dnssim_bind(output_dnssim_t* self, const char* ip)
{
int ret;
mlassert_self();
lassert(ip, "ip is nil");
_output_dnssim_source_t* source;
lfatal_oom(source = malloc(sizeof(_output_dnssim_source_t)));
ret = uv_ip6_addr(ip, 0, (struct sockaddr_in6*)&source->addr);
if (ret != 0) {
ret = uv_ip4_addr(ip, 0, (struct sockaddr_in*)&source->addr);
if (ret != 0) {
lfatal("failed to parse IPv4 or IPv6 from \"%s\"", ip);
}
}
if (_self->source == NULL) {
source->next = source;
_self->source = source;
} else {
source->next = _self->source->next;
_self->source->next = source;
}
lnotice("bind to source address %s", ip);
return 0;
}
int output_dnssim_tls_priority(output_dnssim_t* self, const char* priority)
{
mlassert_self();
lassert(priority, "priority is nil");
if (_self->tls_priority != NULL) {
gnutls_priority_deinit(*_self->tls_priority);
free(_self->tls_priority);
}
lfatal_oom(_self->tls_priority = malloc(sizeof(gnutls_priority_t)));
int ret = gnutls_priority_init(_self->tls_priority, priority, NULL);
if (ret < 0) {
lfatal("failed to initialize TLS priority cache: %s", gnutls_strerror(ret));
} else {
lnotice("GnuTLS priority set: %s", priority);
}
return 0;
}
int output_dnssim_run_nowait(output_dnssim_t* self)
{
mlassert_self();
return uv_run(&_self->loop, UV_RUN_NOWAIT);
}
void output_dnssim_timeout_ms(output_dnssim_t* self, uint64_t timeout_ms)
{
mlassert_self();
lassert(timeout_ms > 0, "timeout must be greater than 0");
if (self->stats_sum != NULL) {
free(self->stats_sum->latency);
free(self->stats_sum);
self->stats_sum = 0;
}
if (self->stats_current != NULL) {
output_dnssim_stats_t* stats_prev;
do {
stats_prev = self->stats_current->prev;
free(self->stats_current->latency);
free(self->stats_current);
self->stats_current = stats_prev;
} while (self->stats_current != NULL);
}
self->timeout_ms = timeout_ms;
lfatal_oom(self->stats_sum = calloc(1, sizeof(output_dnssim_stats_t)));
lfatal_oom(self->stats_sum->latency = calloc(self->timeout_ms + 1, sizeof(uint64_t)));
lfatal_oom(self->stats_current = calloc(1, sizeof(output_dnssim_stats_t)));
lfatal_oom(self->stats_current->latency = calloc(self->timeout_ms + 1, sizeof(uint64_t)));
self->stats_first = self->stats_current;
}
void output_dnssim_h2_uri_path(output_dnssim_t* self, const char* uri_path)
{
mlassert_self();
lassert(uri_path, "uri_path is nil");
lassert(strlen(uri_path) < _MAX_URI_LEN, "uri_path too long");
strncpy(_self->h2_uri_path, uri_path, _MAX_URI_LEN - 1);
_self->h2_uri_path[_MAX_URI_LEN - 1] = 0;
lnotice("http2: set uri path to: %s", _self->h2_uri_path);
}
void output_dnssim_h2_method(output_dnssim_t* self, const char* method)
{
mlassert_self();
lassert(method, "method is nil");
if (strcmp("GET", method) == 0) {
_self->h2_method = OUTPUT_DNSSIM_H2_GET;
} else if (strcmp("POST", method) == 0) {
_self->h2_method = OUTPUT_DNSSIM_H2_POST;
} else {
lfatal("http2: unsupported method: \"%s\"", method);
}
lnotice("http2: set method to %s", method);
}
void output_dnssim_h2_zero_out_msgid(output_dnssim_t* self, bool zero_out_msgid)
{
mlassert_self();
if (zero_out_msgid) {
lassert(_self->transport == OUTPUT_DNSSIM_TRANSPORT_HTTPS2, "transport must be set to HTTP/2 to set zero_out_msgid");
_self->h2_zero_out_msgid = zero_out_msgid;
}
}
static void _on_stats_timer_tick(uv_timer_t* handle)
{
uint64_t now_ms = _now_ms();
output_dnssim_t* self;
mlassert(handle, "handle is nil");
self = (output_dnssim_t*)handle->data;
mlassert_self();
lassert(self->stats_sum, "stats_sum is nil");
lassert(self->stats_current, "stats_current is nil");
lnotice("total processed:%10ld; answers:%10ld; discarded:%10ld; ongoing:%10ld",
self->processed, self->stats_sum->answers, self->discarded, self->ongoing);
output_dnssim_stats_t* stats_next;
lfatal_oom(stats_next = calloc(1, sizeof(output_dnssim_stats_t)));
lfatal_oom(stats_next->latency = calloc(self->timeout_ms + 1, sizeof(uint64_t)));
self->stats_current->until_ms = now_ms;
stats_next->since_ms = now_ms;
stats_next->conn_active = self->stats_current->conn_active;
stats_next->ongoing = self->ongoing;
stats_next->prev = self->stats_current;
self->stats_current->next = stats_next;
self->stats_current = stats_next;
}
void output_dnssim_stats_collect(output_dnssim_t* self, uint64_t interval_ms)
{
uint64_t now_ms = _now_ms();
mlassert_self();
lassert(self->stats_sum, "stats_sum is nil");
lassert(self->stats_current, "stats_current is nil");
if (self->stats_interval_ms != 0) {
lfatal("statistics collection has already started!");
}
self->stats_interval_ms = interval_ms;
self->stats_sum->since_ms = now_ms;
self->stats_current->since_ms = now_ms;
_self->stats_timer.data = (void*)self;
uv_timer_init(&_self->loop, &_self->stats_timer);
uv_timer_start(&_self->stats_timer, _on_stats_timer_tick, interval_ms, interval_ms);
}
void output_dnssim_stats_finish(output_dnssim_t* self)
{
uint64_t now_ms = _now_ms();
mlassert_self();
lassert(self->stats_sum, "stats_sum is nil");
lassert(self->stats_current, "stats_current is nil");
self->stats_sum->until_ms = now_ms;
self->stats_current->until_ms = now_ms;
uv_timer_stop(&_self->stats_timer);
uv_close((uv_handle_t*)&_self->stats_timer, NULL);
}

View file

@ -1,123 +0,0 @@
/*
* Copyright (c) 2018-2020, CZ.NIC, z.s.p.o.
* All rights reserved.
*
* This file is part of dnsjit.
*
* dnsjit is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dnsjit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
//lua:require("dnsjit.core.log")
//lua:require("dnsjit.core.receiver_h")
typedef enum output_dnssim_transport {
OUTPUT_DNSSIM_TRANSPORT_UDP_ONLY,
OUTPUT_DNSSIM_TRANSPORT_UDP,
OUTPUT_DNSSIM_TRANSPORT_TCP,
OUTPUT_DNSSIM_TRANSPORT_TLS,
OUTPUT_DNSSIM_TRANSPORT_HTTPS2
} output_dnssim_transport_t;
typedef enum output_dnssim_h2_method {
OUTPUT_DNSSIM_H2_GET,
OUTPUT_DNSSIM_H2_POST
} output_dnssim_h2_method_t;
typedef struct output_dnssim_stats output_dnssim_stats_t;
struct output_dnssim_stats {
output_dnssim_stats_t* prev;
output_dnssim_stats_t* next;
uint64_t* latency;
uint64_t since_ms;
uint64_t until_ms;
uint64_t requests;
uint64_t ongoing;
uint64_t answers;
/* Number of connections that are open at the end of the stats interval. */
uint64_t conn_active;
/* Number of connection handshake attempts during the stats interval. */
uint64_t conn_handshakes;
/* Number of connection that have been resumed with TLS session resumption. */
uint64_t conn_resumed;
/* Number of timed out connection handshakes during the stats interval. */
uint64_t conn_handshakes_failed;
uint64_t rcode_noerror;
uint64_t rcode_formerr;
uint64_t rcode_servfail;
uint64_t rcode_nxdomain;
uint64_t rcode_notimp;
uint64_t rcode_refused;
uint64_t rcode_yxdomain;
uint64_t rcode_yxrrset;
uint64_t rcode_nxrrset;
uint64_t rcode_notauth;
uint64_t rcode_notzone;
uint64_t rcode_badvers;
uint64_t rcode_badkey;
uint64_t rcode_badtime;
uint64_t rcode_badmode;
uint64_t rcode_badname;
uint64_t rcode_badalg;
uint64_t rcode_badtrunc;
uint64_t rcode_badcookie;
uint64_t rcode_other;
};
typedef struct output_dnssim {
core_log_t _log;
uint64_t processed;
uint64_t discarded;
uint64_t ongoing;
output_dnssim_stats_t* stats_sum;
output_dnssim_stats_t* stats_current;
output_dnssim_stats_t* stats_first;
size_t max_clients;
bool free_after_use;
uint64_t timeout_ms;
uint64_t idle_timeout_ms;
uint64_t handshake_timeout_ms;
uint64_t stats_interval_ms;
} output_dnssim_t;
core_log_t* output_dnssim_log();
output_dnssim_t* output_dnssim_new(size_t max_clients);
void output_dnssim_free(output_dnssim_t* self);
void output_dnssim_log_name(output_dnssim_t* self, const char* name);
void output_dnssim_set_transport(output_dnssim_t* self, output_dnssim_transport_t tr);
int output_dnssim_target(output_dnssim_t* self, const char* ip, uint16_t port);
int output_dnssim_bind(output_dnssim_t* self, const char* ip);
int output_dnssim_tls_priority(output_dnssim_t* self, const char* priority);
int output_dnssim_run_nowait(output_dnssim_t* self);
void output_dnssim_timeout_ms(output_dnssim_t* self, uint64_t timeout_ms);
void output_dnssim_h2_uri_path(output_dnssim_t* self, const char* uri_path);
void output_dnssim_h2_method(output_dnssim_t* self, const char* method);
void output_dnssim_h2_zero_out_msgid(output_dnssim_t* self, bool zero_out_msgid);
void output_dnssim_stats_collect(output_dnssim_t* self, uint64_t interval_ms);
void output_dnssim_stats_finish(output_dnssim_t* self);
core_receiver_t output_dnssim_receiver();

View file

@ -1,433 +0,0 @@
-- Copyright (c) 2018-2021, CZ.NIC, z.s.p.o.
-- All rights reserved.
--
-- This file is part of dnsjit.
--
-- dnsjit is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- dnsjit is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
-- dnsjit.output.dnssim
-- Simulate independent DNS clients over various transports
-- output = require("dnsjit.output.dnssim").new()
-- .SS Usage
-- output:udp()
-- output:target("::1", 53)
-- recv, rctx = output:receive()
-- -- pass in objects using recv(rctx, obj)
-- -- repeatedly call output:run_nowait() until it returns 0
-- .SS DNS-over-TLS example configuration
-- output:tls("NORMAL:-VERS-ALL:+VERS-TLS1.3") -- enforce TLS 1.3
-- .SS DNS-over-HTTPS/2 example configuration
-- output:https2({ method = "POST", uri_path = "/doh" })
--
-- Output module for simulating traffic from huge number of independent,
-- individual DNS clients.
-- Uses libuv for asynchronous communication.
-- There may only be a single DnsSim in a thread.
-- Use
-- .I dnsjit.core.thread
-- to have multiple DnsSim instances.
-- .P
-- With proper use of this component, it is possible to simulate hundreds of
-- thousands of clients when using a high-performance server.
-- This also applies for state-full transports.
-- The complete set-up is quite complex and requires other components.
-- See DNS Shotgun
-- .RI ( https://gitlab.nic.cz/knot/shotgun )
-- for dnsjit scripts ready for use for high-performance
-- benchmarking.
module(...,package.seeall)
require("dnsjit.output.dnssim_h")
local bit = require("bit")
local object = require("dnsjit.core.objects")
local ffi = require("ffi")
local C = ffi.C
local DnsSim = {}
local _DNSSIM_VERSION = 20210129
local _DNSSIM_JSON_VERSION = 20200527
-- Create a new DnsSim output for up to max_clients.
function DnsSim.new(max_clients)
local self = {
obj = C.output_dnssim_new(max_clients),
max_clients = max_clients,
}
ffi.gc(self.obj, C.output_dnssim_free)
return setmetatable(self, { __index = DnsSim })
end
local function _check_version(version, req_version)
if req_version == nil then
return version
end
local min_version = tonumber(req_version)
if min_version == nil then
C.output_dnssim_log():fatal("invalid version number: "..req_version)
return nil
end
if version >= min_version then
return version
end
return nil
end
-- Check that version of dnssim is at minimum the one passed as
-- .B req_version
-- and return the actual version number.
-- Return nil if the condition is not met.
--
-- If no
-- .B req_version
-- is specified no check is done and only the version number is returned.
function DnsSim.check_version(req_version)
return _check_version(_DNSSIM_VERSION, req_version)
end
-- Check that version of dnssim's JSON data format is at minimum the one passed as
-- .B req_version
-- and return the actual version number.
-- Return nil if the condition is not met.
--
-- If no
-- .B req_version
-- is specified no check is done and only the version number is returned.
function DnsSim.check_json_version(req_version)
return _check_version(_DNSSIM_JSON_VERSION, req_version)
end
-- Return the Log object to control logging of this instance or module.
-- Optionally, set the instance's log name.
-- Unique name should be used for each instance.
function DnsSim:log(name)
if self == nil then
return C.output_dnssim_log()
end
if name ~= nil then
C.output_dnssim_log_name(self.obj, name)
end
return self.obj._log
end
-- Set the target IPv4/IPv6 address where queries will be sent to.
function DnsSim:target(ip, port)
local nport = tonumber(port)
if nport == nil then
self.obj._log:fatal("invalid port: "..port)
return -1
end
if nport <= 0 or nport > 65535 then
self.obj._log:fatal("invalid port number: "..nport)
return -1
end
return C.output_dnssim_target(self.obj, ip, nport)
end
-- Specify source IPv4/IPv6 address for sending queries.
-- Can be set multiple times.
-- Addresses are selected round-robin when sending.
function DnsSim:bind(ip)
return C.output_dnssim_bind(self.obj, ip)
end
-- Set the preferred transport to UDP.
--
-- When the optional argument
-- .B tcp_fallback
-- is set to true, individual queries are re-tried over TCP when TC bit is set in the answer.
-- Defaults to
-- .B false
-- (aka only UDP is used).
function DnsSim:udp(tcp_fallback)
if tcp_fallback == true then
C.output_dnssim_set_transport(self.obj, C.OUTPUT_DNSSIM_TRANSPORT_UDP)
else
C.output_dnssim_set_transport(self.obj, C.OUTPUT_DNSSIM_TRANSPORT_UDP_ONLY)
end
end
-- Set the transport to TCP.
function DnsSim:tcp()
C.output_dnssim_set_transport(self.obj, C.OUTPUT_DNSSIM_TRANSPORT_TCP)
end
-- Set the transport to TLS.
--
-- The optional argument
-- .B tls_priority
-- is a GnuTLS priority string, which can be used to select TLS versions, cipher suites etc.
-- For example:
--
-- .RB "- """ NORMAL:%NO_TICKETS """"
-- will use defaults without TLS session resumption.
--
-- .RB "- """ SECURE128:-VERS-ALL:+VERS-TLS1.3 """"
-- will use only TLS 1.3 with 128-bit secure ciphers.
--
-- Refer to:
-- .I https://gnutls.org/manual/html_node/Priority-Strings.html
function DnsSim:tls(tls_priority)
if tls_priority ~= nil then
C.output_dnssim_tls_priority(self.obj, tls_priority)
end
C.output_dnssim_set_transport(self.obj, C.OUTPUT_DNSSIM_TRANSPORT_TLS)
end
-- Set the transport to HTTP/2 over TLS.
--
-- .B http2_options
-- is a lua table which supports the following keys:
--
-- .B method:
-- .B GET
-- (default)
-- or
-- .B POST
--
-- .B uri_path:
-- where queries will be sent.
-- Defaults to
-- .B /dns-query
--
-- .B zero_out_msgid:
-- when
-- .B true
-- (default), query ID is always set to 0
--
-- See tls() method for
-- .B tls_priority
-- documentation.
function DnsSim:https2(http2_options, tls_priority)
if tls_priority ~= nil then
C.output_dnssim_tls_priority(self.obj, tls_priority)
end
uri_path = "/dns-query"
zero_out_msgid = true
method = "GET"
if http2_options ~= nil then
if type(http2_options) ~= "table" then
self.obj._log:fatal("http2_options must be a table")
else
if http2_options["uri_path"] ~= nil then
uri_path = http2_options["uri_path"]
end
if http2_options["zero_out_msgid"] ~= nil and http2_options["zero_out_msgid"] ~= true then
zero_out_msgid = false
end
if http2_options["method"] ~= nil then
method = http2_options["method"]
end
end
end
C.output_dnssim_set_transport(self.obj, C.OUTPUT_DNSSIM_TRANSPORT_HTTPS2)
C.output_dnssim_h2_uri_path(self.obj, uri_path)
C.output_dnssim_h2_method(self.obj, method)
C.output_dnssim_h2_zero_out_msgid(self.obj, zero_out_msgid)
end
-- Set timeout for the individual requests in seconds (default 2s).
--
-- .BR Beware :
-- increasing this value while the target resolver isn't very responsive
-- (cold cache, heavy load) may degrade DnsSim's performance and skew
-- the results.
function DnsSim:timeout(seconds)
if seconds == nil then
seconds = 2
end
timeout_ms = math.floor(seconds * 1000)
C.output_dnssim_timeout_ms(self.obj, timeout_ms)
end
-- Set TCP connection idle timeout for connection reuse according to RFC7766,
-- Section 6.2.3 (defaults to 10s).
-- When set to zero, connections are closed immediately after there are no
-- more pending queries.
function DnsSim:idle_timeout(seconds)
if seconds == nil then
seconds = 10
end
self.obj.idle_timeout_ms = math.floor(seconds * 1000)
end
-- Set TCP connection handshake timeout (defaults to 5s).
-- During heavy load, the server may no longer accept new connections.
-- This parameter ensures such connection attempts are aborted after the
-- timeout expires.
function DnsSim:handshake_timeout(seconds)
if seconds == nil then
seconds = 5
end
self.obj.handshake_timeout_ms = math.floor(seconds * 1000)
end
-- Run the libuv loop once without blocking when there is no I/O.
-- This should be called repeatedly until 0 is returned and no more data
-- is expected to be received by DnsSim.
function DnsSim:run_nowait()
return C.output_dnssim_run_nowait(self.obj)
end
-- Set this to true if DnsSim should free the memory of passed-in objects
-- (useful when using
-- .I dnsjit.filter.copy
-- to pass objects from different thread).
function DnsSim:free_after_use(free_after_use)
self.obj.free_after_use = free_after_use
end
-- Number of input packets discarded due to various reasons.
-- To investigate causes, run with increased logging level.
function DnsSim:discarded()
return tonumber(self.obj.discarded)
end
-- Number of valid requests (input packets) processed.
function DnsSim:requests()
return tonumber(self.obj.stats_sum.requests)
end
-- Number of requests that received an answer
function DnsSim:answers()
return tonumber(self.obj.stats_sum.answers)
end
-- Number of requests that received a NOERROR response
function DnsSim:noerror()
return tonumber(self.obj.stats_sum.rcode_noerror)
end
-- Configure statistics to be collected every N seconds.
function DnsSim:stats_collect(seconds)
if seconds == nil then
self.obj._log:fatal("number of seconds must be set for stats_collect()")
end
interval_ms = math.floor(seconds * 1000)
C.output_dnssim_stats_collect(self.obj, interval_ms)
end
-- Stop the collection of statistics.
function DnsSim:stats_finish()
C.output_dnssim_stats_finish(self.obj)
end
-- Export the results to a JSON file.
function DnsSim:export(filename)
local file = io.open(filename, "w")
if file == nil then
self.obj._log:fatal("export failed: no filename")
return
end
local function write_stats(file, stats)
file:write(
"{ ",
'"since_ms":', tonumber(stats.since_ms), ',',
'"until_ms":', tonumber(stats.until_ms), ',',
'"requests":', tonumber(stats.requests), ',',
'"ongoing":', tonumber(stats.ongoing), ',',
'"answers":', tonumber(stats.answers), ',',
'"conn_active":', tonumber(stats.conn_active), ',',
'"conn_handshakes":', tonumber(stats.conn_handshakes), ',',
'"conn_resumed":', tonumber(stats.conn_resumed), ',',
'"conn_handshakes_failed":', tonumber(stats.conn_handshakes_failed), ',',
'"rcode_noerror":', tonumber(stats.rcode_noerror), ',',
'"rcode_formerr":', tonumber(stats.rcode_formerr), ',',
'"rcode_servfail":', tonumber(stats.rcode_servfail), ',',
'"rcode_nxdomain":', tonumber(stats.rcode_nxdomain), ',',
'"rcode_notimp":', tonumber(stats.rcode_notimp), ',',
'"rcode_refused":', tonumber(stats.rcode_refused), ',',
'"rcode_yxdomain":', tonumber(stats.rcode_yxdomain), ',',
'"rcode_yxrrset":', tonumber(stats.rcode_yxrrset), ',',
'"rcode_nxrrset":', tonumber(stats.rcode_nxrrset), ',',
'"rcode_notauth":', tonumber(stats.rcode_notauth), ',',
'"rcode_notzone":', tonumber(stats.rcode_notzone), ',',
'"rcode_badvers":', tonumber(stats.rcode_badvers), ',',
'"rcode_badkey":', tonumber(stats.rcode_badkey), ',',
'"rcode_badtime":', tonumber(stats.rcode_badtime), ',',
'"rcode_badmode":', tonumber(stats.rcode_badmode), ',',
'"rcode_badname":', tonumber(stats.rcode_badname), ',',
'"rcode_badalg":', tonumber(stats.rcode_badalg), ',',
'"rcode_badtrunc":', tonumber(stats.rcode_badtrunc), ',',
'"rcode_badcookie":', tonumber(stats.rcode_badcookie), ',',
'"rcode_other":', tonumber(stats.rcode_other), ',',
'"latency":[')
file:write(tonumber(stats.latency[0]))
for i=1,tonumber(self.obj.timeout_ms) do
file:write(',', tonumber(stats.latency[i]))
end
file:write("]}")
end
file:write(
"{ ",
'"version":', _DNSSIM_JSON_VERSION, ',',
'"merged":false,',
'"stats_interval_ms":', tonumber(self.obj.stats_interval_ms), ',',
'"timeout_ms":', tonumber(self.obj.timeout_ms), ',',
'"idle_timeout_ms":', tonumber(self.obj.idle_timeout_ms), ',',
'"handshake_timeout_ms":', tonumber(self.obj.handshake_timeout_ms), ',',
'"discarded":', self:discarded(), ',',
'"stats_sum":')
write_stats(file, self.obj.stats_sum)
file:write(
',',
'"stats_periodic":[')
local stats = self.obj.stats_first
write_stats(file, stats)
while (stats.next ~= nil) do
stats = stats.next
file:write(',')
write_stats(file, stats)
end
file:write(']}')
file:close()
self.obj._log:notice("results exported to "..filename)
end
-- Return the C function and context for receiving objects.
-- Only
-- .I dnsjit.filter.core.object.ip
-- or
-- .I dnsjit.filter.core.object.ip6
-- objects are supported.
-- The component expects a 32bit integer (in host order) ranging from 0
-- to max_clients written to first 4 bytes of destination IP.
-- See
-- .IR dnsjit.filter.ipsplit .
function DnsSim:receive()
local receive = C.output_dnssim_receiver()
return receive, self.obj
end
-- Deprecated: use udp() instead.
--
-- Set the transport to UDP (without any TCP fallback).
function DnsSim:udp_only()
C.output_dnssim_set_transport(self.obj, C.OUTPUT_DNSSIM_TRANSPORT_UDP_ONLY)
end
-- dnsjit.filter.copy (3),
-- dnsjit.filter.ipsplit (3),
-- dnsjit.filter.core.object.ip (3),
-- dnsjit.filter.core.object.ip6 (3),
-- https://gitlab.nic.cz/knot/shotgun
return DnsSim

View file

@ -1,16 +0,0 @@
dnssim v20210129
================
- Added DNS-over-HTTPS support with https2()
- Added IPv4 support
- Abort operation on insufficient file descriptors
- Match QUESTION section of received responses
- Improvements in connection state handling
- Deprecate udp_only() in favor of udp()
- Allow setting logger name with log(name)
- Added check_version() and check_json_version()
dnssim v20200723
================
- First released dnssim version with UDP, TCP and DoT support

View file

@ -1,384 +0,0 @@
/*
* Copyright (c) 2019-2020, CZ.NIC, z.s.p.o.
* All rights reserved.
*
* This file is part of dnsjit.
*
* dnsjit is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dnsjit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "output/dnssim.h"
#include "output/dnssim/internal.h"
#include "output/dnssim/ll.h"
#include "core/assert.h"
#include <string.h>
#define MAX_LABELS 127
static core_log_t _log = LOG_T_INIT("output.dnssim");
static void _close_request(_output_dnssim_request_t* req);
static void _on_request_timeout(uv_timer_t* handle)
{
_close_request((_output_dnssim_request_t*)handle->data);
}
static ssize_t parse_qsection(core_object_dns_t* dns)
{
core_object_dns_q_t q;
static core_object_dns_label_t labels[MAX_LABELS];
const uint8_t* start;
int i;
int ret;
if (!dns || !dns->have_qdcount)
return -1;
start = dns->at;
for (i = 0; i < dns->qdcount; i++) {
ret = core_object_dns_parse_q(dns, &q, labels, MAX_LABELS);
if (ret < 0)
return -1;
}
return (dns->at - start);
}
int _output_dnssim_answers_request(_output_dnssim_request_t* req, core_object_dns_t* response)
{
const uint8_t* question;
ssize_t len;
if (!response->have_id || !response->have_qdcount)
return _ERR_MALFORMED;
if (req->dns_q->id != response->id)
return _ERR_MSGID;
if (req->dns_q->qdcount != response->qdcount)
return _ERR_QUESTION;
question = response->at;
len = parse_qsection(response);
if (req->question_len != len)
return _ERR_QUESTION;
if (memcmp(req->question, question, len) != 0)
return _ERR_QUESTION;
return 0;
}
void _output_dnssim_create_request(output_dnssim_t* self, _output_dnssim_client_t* client, core_object_payload_t* payload)
{
int ret;
_output_dnssim_request_t* req;
mlassert_self();
lassert(client, "client is nil");
lassert(payload, "payload is nil");
lfatal_oom(req = calloc(1, sizeof(_output_dnssim_request_t)));
req->dnssim = self;
req->client = client;
req->payload = payload;
req->dns_q = core_object_dns_new();
req->dns_q->obj_prev = (core_object_t*)req->payload;
req->dnssim->ongoing++;
req->state = _OUTPUT_DNSSIM_REQ_ONGOING;
req->stats = self->stats_current;
ret = core_object_dns_parse_header(req->dns_q);
if (ret != 0) {
ldebug("discarded malformed dns query: couldn't parse header");
goto failure;
}
req->question = req->dns_q->at;
req->question_len = parse_qsection(req->dns_q);
if (req->question_len < 0) {
ldebug("discarded malformed dns query: invalid question");
goto failure;
}
req->dnssim->stats_sum->requests++;
req->stats->requests++;
switch (_self->transport) {
case OUTPUT_DNSSIM_TRANSPORT_UDP_ONLY:
case OUTPUT_DNSSIM_TRANSPORT_UDP:
ret = _output_dnssim_create_query_udp(self, req);
break;
case OUTPUT_DNSSIM_TRANSPORT_TCP:
ret = _output_dnssim_create_query_tcp(self, req);
break;
case OUTPUT_DNSSIM_TRANSPORT_TLS:
#if GNUTLS_VERSION_NUMBER >= DNSSIM_MIN_GNUTLS_VERSION
ret = _output_dnssim_create_query_tls(self, req);
#else
lfatal(DNSSIM_MIN_GNUTLS_ERRORMSG);
#endif
break;
case OUTPUT_DNSSIM_TRANSPORT_HTTPS2:
#if GNUTLS_VERSION_NUMBER >= DNSSIM_MIN_GNUTLS_VERSION
ret = _output_dnssim_create_query_https2(self, req);
#else
lfatal(DNSSIM_MIN_GNUTLS_ERRORMSG);
#endif
break;
default:
lfatal("unsupported dnssim transport");
break;
}
if (ret < 0) {
goto failure;
}
req->created_at = uv_now(&_self->loop);
req->ended_at = req->created_at + self->timeout_ms;
lfatal_oom(req->timer = malloc(sizeof(uv_timer_t)));
uv_timer_init(&_self->loop, req->timer);
req->timer->data = req;
uv_timer_start(req->timer, _on_request_timeout, self->timeout_ms, 0);
return;
failure:
self->discarded++;
_close_request(req);
return;
}
/* Bind before connect to be able to send from different source IPs. */
int _output_dnssim_bind_before_connect(output_dnssim_t* self, uv_handle_t* handle)
{
mlassert_self();
lassert(handle, "handle is nil");
if (_self->source != NULL) {
struct sockaddr* addr = (struct sockaddr*)&_self->source->addr;
struct sockaddr* dest = (struct sockaddr*)&_self->target;
int ret = -1;
if (addr->sa_family != dest->sa_family) {
lfatal("failed to bind: source/desitnation address family mismatch");
}
switch (handle->type) {
case UV_UDP:
ret = uv_udp_bind((uv_udp_t*)handle, addr, 0);
break;
case UV_TCP:
ret = uv_tcp_bind((uv_tcp_t*)handle, addr, 0);
break;
default:
lfatal("failed to bind: unsupported handle type");
break;
}
if (ret < 0) {
/* This typically happens when we run out of file descriptors.
* Quit to prevent skewed results or unexpected behaviour. */
lfatal("failed to bind: %s", uv_strerror(ret));
return ret;
}
_self->source = _self->source->next;
}
return 0;
}
void _output_dnssim_maybe_free_request(_output_dnssim_request_t* req)
{
mlassert(req, "req is nil");
if (req->qry == NULL && req->timer == NULL) {
if (req->dnssim->free_after_use) {
core_object_payload_free(req->payload);
}
core_object_dns_free(req->dns_q);
free(req);
}
}
static void _close_query(_output_dnssim_query_t* qry)
{
mlassert(qry, "qry is nil");
switch (qry->transport) {
case OUTPUT_DNSSIM_TRANSPORT_UDP:
_output_dnssim_close_query_udp((_output_dnssim_query_udp_t*)qry);
break;
case OUTPUT_DNSSIM_TRANSPORT_TCP:
_output_dnssim_close_query_tcp((_output_dnssim_query_tcp_t*)qry);
break;
case OUTPUT_DNSSIM_TRANSPORT_TLS:
#if GNUTLS_VERSION_NUMBER >= DNSSIM_MIN_GNUTLS_VERSION
_output_dnssim_close_query_tls((_output_dnssim_query_tcp_t*)qry);
#else
mlfatal(DNSSIM_MIN_GNUTLS_ERRORMSG);
#endif
break;
case OUTPUT_DNSSIM_TRANSPORT_HTTPS2:
#if GNUTLS_VERSION_NUMBER >= DNSSIM_MIN_GNUTLS_VERSION
_output_dnssim_close_query_https2((_output_dnssim_query_tcp_t*)qry);
#else
mlfatal(DNSSIM_MIN_GNUTLS_ERRORMSG);
#endif
break;
default:
mlfatal("invalid query transport");
break;
}
}
static void _on_request_timer_closed(uv_handle_t* handle)
{
_output_dnssim_request_t* req = (_output_dnssim_request_t*)handle->data;
mlassert(req, "req is nil");
free(handle);
req->timer = NULL;
_output_dnssim_maybe_free_request(req);
}
static void _close_request(_output_dnssim_request_t* req)
{
if (req == NULL || req->state == _OUTPUT_DNSSIM_REQ_CLOSING)
return;
mlassert(req->state == _OUTPUT_DNSSIM_REQ_ONGOING, "request to be closed must be ongoing");
req->state = _OUTPUT_DNSSIM_REQ_CLOSING;
req->dnssim->ongoing--;
/* Calculate latency. */
uint64_t latency;
req->ended_at = uv_now(&((_output_dnssim_t*)req->dnssim)->loop);
latency = req->ended_at - req->created_at;
if (latency > req->dnssim->timeout_ms) {
req->ended_at = req->created_at + req->dnssim->timeout_ms;
latency = req->dnssim->timeout_ms;
}
req->stats->latency[latency]++;
req->dnssim->stats_sum->latency[latency]++;
if (req->timer != NULL) {
uv_timer_stop(req->timer);
uv_close((uv_handle_t*)req->timer, _on_request_timer_closed);
}
/* Finish any queries in flight. */
_output_dnssim_query_t* qry = req->qry;
if (qry != NULL)
_close_query(qry);
_output_dnssim_maybe_free_request(req);
}
void _output_dnssim_request_answered(_output_dnssim_request_t* req, core_object_dns_t* msg)
{
mlassert(req, "req is nil");
mlassert(msg, "msg is nil");
req->dnssim->stats_sum->answers++;
req->stats->answers++;
switch (msg->rcode) {
case CORE_OBJECT_DNS_RCODE_NOERROR:
req->dnssim->stats_sum->rcode_noerror++;
req->stats->rcode_noerror++;
break;
case CORE_OBJECT_DNS_RCODE_FORMERR:
req->dnssim->stats_sum->rcode_formerr++;
req->stats->rcode_formerr++;
break;
case CORE_OBJECT_DNS_RCODE_SERVFAIL:
req->dnssim->stats_sum->rcode_servfail++;
req->stats->rcode_servfail++;
break;
case CORE_OBJECT_DNS_RCODE_NXDOMAIN:
req->dnssim->stats_sum->rcode_nxdomain++;
req->stats->rcode_nxdomain++;
break;
case CORE_OBJECT_DNS_RCODE_NOTIMP:
req->dnssim->stats_sum->rcode_notimp++;
req->stats->rcode_notimp++;
break;
case CORE_OBJECT_DNS_RCODE_REFUSED:
req->dnssim->stats_sum->rcode_refused++;
req->stats->rcode_refused++;
break;
case CORE_OBJECT_DNS_RCODE_YXDOMAIN:
req->dnssim->stats_sum->rcode_yxdomain++;
req->stats->rcode_yxdomain++;
break;
case CORE_OBJECT_DNS_RCODE_YXRRSET:
req->dnssim->stats_sum->rcode_yxrrset++;
req->stats->rcode_yxrrset++;
break;
case CORE_OBJECT_DNS_RCODE_NXRRSET:
req->dnssim->stats_sum->rcode_nxrrset++;
req->stats->rcode_nxrrset++;
break;
case CORE_OBJECT_DNS_RCODE_NOTAUTH:
req->dnssim->stats_sum->rcode_notauth++;
req->stats->rcode_notauth++;
break;
case CORE_OBJECT_DNS_RCODE_NOTZONE:
req->dnssim->stats_sum->rcode_notzone++;
req->stats->rcode_notzone++;
break;
case CORE_OBJECT_DNS_RCODE_BADVERS:
req->dnssim->stats_sum->rcode_badvers++;
req->stats->rcode_badvers++;
break;
case CORE_OBJECT_DNS_RCODE_BADKEY:
req->dnssim->stats_sum->rcode_badkey++;
req->stats->rcode_badkey++;
break;
case CORE_OBJECT_DNS_RCODE_BADTIME:
req->dnssim->stats_sum->rcode_badtime++;
req->stats->rcode_badtime++;
break;
case CORE_OBJECT_DNS_RCODE_BADMODE:
req->dnssim->stats_sum->rcode_badmode++;
req->stats->rcode_badmode++;
break;
case CORE_OBJECT_DNS_RCODE_BADNAME:
req->dnssim->stats_sum->rcode_badname++;
req->stats->rcode_badname++;
break;
case CORE_OBJECT_DNS_RCODE_BADALG:
req->dnssim->stats_sum->rcode_badalg++;
req->stats->rcode_badalg++;
break;
case CORE_OBJECT_DNS_RCODE_BADTRUNC:
req->dnssim->stats_sum->rcode_badtrunc++;
req->stats->rcode_badtrunc++;
break;
case CORE_OBJECT_DNS_RCODE_BADCOOKIE:
req->dnssim->stats_sum->rcode_badcookie++;
req->stats->rcode_badcookie++;
break;
default:
req->dnssim->stats_sum->rcode_other++;
req->stats->rcode_other++;
}
_close_request(req);
}
void _output_dnssim_on_uv_alloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)
{
mlfatal_oom(buf->base = malloc(suggested_size));
buf->len = suggested_size;
}

View file

@ -1,471 +0,0 @@
/*
* Copyright (c) 2020, CZ.NIC, z.s.p.o.
* All rights reserved.
*
* This file is part of dnsjit.
*
* dnsjit is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dnsjit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "output/dnssim.h"
#include "output/dnssim/internal.h"
#include "output/dnssim/ll.h"
#include "core/assert.h"
#include <string.h>
static core_log_t _log = LOG_T_INIT("output.dnssim");
static bool _conn_is_connecting(_output_dnssim_connection_t* conn)
{
return (conn->state >= _OUTPUT_DNSSIM_CONN_TCP_HANDSHAKE && conn->state <= _OUTPUT_DNSSIM_CONN_ACTIVE);
}
void _output_dnssim_conn_maybe_free(_output_dnssim_connection_t* conn)
{
mlassert(conn, "conn can't be nil");
mlassert(conn->client, "conn must belong to a client");
if (conn->handle == NULL && conn->handshake_timer == NULL && conn->idle_timer == NULL) {
_ll_try_remove(conn->client->conn, conn);
if (conn->tls != NULL) {
free(conn->tls);
conn->tls = NULL;
}
if (conn->http2 != NULL) {
free(conn->http2);
conn->http2 = NULL;
}
free(conn);
}
}
static void _on_handshake_timer_closed(uv_handle_t* handle)
{
_output_dnssim_connection_t* conn = (_output_dnssim_connection_t*)handle->data;
mlassert(conn, "conn is nil");
mlassert(conn->handshake_timer, "conn must have handshake timer when closing it");
free(conn->handshake_timer);
conn->handshake_timer = NULL;
_output_dnssim_conn_maybe_free(conn);
}
static void _on_idle_timer_closed(uv_handle_t* handle)
{
_output_dnssim_connection_t* conn = (_output_dnssim_connection_t*)handle->data;
mlassert(conn, "conn is nil");
mlassert(conn->idle_timer, "conn must have idle timer when closing it");
free(conn->idle_timer);
conn->is_idle = false;
conn->idle_timer = NULL;
_output_dnssim_conn_maybe_free(conn);
}
void _output_dnssim_conn_close(_output_dnssim_connection_t* conn)
{
mlassert(conn, "conn can't be nil");
mlassert(conn->stats, "conn must have stats");
mlassert(conn->client, "conn must have client");
mlassert(conn->client->dnssim, "client must have dnssim");
output_dnssim_t* self = conn->client->dnssim;
switch (conn->state) {
case _OUTPUT_DNSSIM_CONN_CLOSING:
case _OUTPUT_DNSSIM_CONN_CLOSED:
return;
case _OUTPUT_DNSSIM_CONN_TCP_HANDSHAKE:
case _OUTPUT_DNSSIM_CONN_TLS_HANDSHAKE:
conn->stats->conn_handshakes_failed++;
self->stats_sum->conn_handshakes_failed++;
break;
case _OUTPUT_DNSSIM_CONN_ACTIVE:
case _OUTPUT_DNSSIM_CONN_CONGESTED:
self->stats_current->conn_active--;
break;
case _OUTPUT_DNSSIM_CONN_INITIALIZED:
case _OUTPUT_DNSSIM_CONN_CLOSE_REQUESTED:
break;
default:
lfatal("unknown conn state: %d", conn->state);
}
if (conn->prevent_close) {
lassert(conn->state <= _OUTPUT_DNSSIM_CONN_CLOSE_REQUESTED, "conn already closing");
conn->state = _OUTPUT_DNSSIM_CONN_CLOSE_REQUESTED;
return;
}
conn->state = _OUTPUT_DNSSIM_CONN_CLOSING;
if (conn->handshake_timer != NULL) {
uv_timer_stop(conn->handshake_timer);
uv_close((uv_handle_t*)conn->handshake_timer, _on_handshake_timer_closed);
}
if (conn->idle_timer != NULL) {
conn->is_idle = false;
uv_timer_stop(conn->idle_timer);
uv_close((uv_handle_t*)conn->idle_timer, _on_idle_timer_closed);
}
switch (_self->transport) {
case OUTPUT_DNSSIM_TRANSPORT_TCP:
_output_dnssim_tcp_close(conn);
break;
case OUTPUT_DNSSIM_TRANSPORT_TLS:
#if GNUTLS_VERSION_NUMBER >= DNSSIM_MIN_GNUTLS_VERSION
_output_dnssim_tls_close(conn);
#else
lfatal(DNSSIM_MIN_GNUTLS_ERRORMSG);
#endif
break;
case OUTPUT_DNSSIM_TRANSPORT_HTTPS2:
#if GNUTLS_VERSION_NUMBER >= DNSSIM_MIN_GNUTLS_VERSION
_output_dnssim_https2_close(conn);
#else
lfatal(DNSSIM_MIN_GNUTLS_ERRORMSG);
#endif
break;
default:
lfatal("unsupported transport");
break;
}
}
/* Close connection or run idle timer when there are no more outstanding queries. */
void _output_dnssim_conn_idle(_output_dnssim_connection_t* conn)
{
mlassert(conn, "conn can't be nil");
if (conn->queued == NULL && conn->sent == NULL) {
if (conn->idle_timer == NULL)
_output_dnssim_conn_close(conn);
else if (!conn->is_idle) {
conn->is_idle = true;
uv_timer_again(conn->idle_timer);
}
}
}
static void _send_pending_queries(_output_dnssim_connection_t* conn)
{
_output_dnssim_query_tcp_t* qry;
mlassert(conn, "conn is nil");
mlassert(conn->client, "conn->client is nil");
qry = (_output_dnssim_query_tcp_t*)conn->client->pending;
while (qry != NULL && conn->state == _OUTPUT_DNSSIM_CONN_ACTIVE) {
_output_dnssim_query_tcp_t* next = (_output_dnssim_query_tcp_t*)qry->qry.next;
if (qry->qry.state == _OUTPUT_DNSSIM_QUERY_PENDING_WRITE) {
switch (qry->qry.transport) {
case OUTPUT_DNSSIM_TRANSPORT_TCP:
_output_dnssim_tcp_write_query(conn, qry);
break;
case OUTPUT_DNSSIM_TRANSPORT_TLS:
#if GNUTLS_VERSION_NUMBER >= DNSSIM_MIN_GNUTLS_VERSION
_output_dnssim_tls_write_query(conn, qry);
#else
mlfatal(DNSSIM_MIN_GNUTLS_ERRORMSG);
#endif
break;
case OUTPUT_DNSSIM_TRANSPORT_HTTPS2:
#if GNUTLS_VERSION_NUMBER >= DNSSIM_MIN_GNUTLS_VERSION
_output_dnssim_https2_write_query(conn, qry);
#else
mlfatal(DNSSIM_MIN_GNUTLS_ERRORMSG);
#endif
break;
default:
mlfatal("unsupported protocol");
break;
}
}
qry = next;
}
}
int _output_dnssim_handle_pending_queries(_output_dnssim_client_t* client)
{
int ret = 0;
mlassert(client, "client is nil");
if (client->pending == NULL)
return ret;
output_dnssim_t* self = client->dnssim;
mlassert(self, "client must belong to dnssim");
/* Get active connection or find out whether new connection has to be opened. */
bool is_connecting = false;
_output_dnssim_connection_t* conn = client->conn;
while (conn != NULL) {
if (conn->state == _OUTPUT_DNSSIM_CONN_ACTIVE)
break;
else if (_conn_is_connecting(conn))
is_connecting = true;
conn = conn->next;
}
if (conn != NULL) { /* Send data right away over active connection. */
_send_pending_queries(conn);
} else if (!is_connecting) { /* No active or connecting connection -> open a new one. */
lfatal_oom(conn = calloc(1, sizeof(_output_dnssim_connection_t)));
conn->state = _OUTPUT_DNSSIM_CONN_INITIALIZED;
conn->client = client;
conn->stats = self->stats_current;
if (_self->transport == OUTPUT_DNSSIM_TRANSPORT_TLS) {
#if GNUTLS_VERSION_NUMBER >= DNSSIM_MIN_GNUTLS_VERSION
ret = _output_dnssim_tls_init(conn);
if (ret < 0) {
free(conn);
return ret;
}
#else
lfatal(DNSSIM_MIN_GNUTLS_ERRORMSG);
#endif
} else if (_self->transport == OUTPUT_DNSSIM_TRANSPORT_HTTPS2) {
#if GNUTLS_VERSION_NUMBER >= DNSSIM_MIN_GNUTLS_VERSION
ret = _output_dnssim_https2_init(conn);
if (ret < 0) {
free(conn);
return ret;
}
#else
lfatal(DNSSIM_MIN_GNUTLS_ERRORMSG);
#endif
}
ret = _output_dnssim_tcp_connect(self, conn);
if (ret < 0)
return ret;
_ll_append(client->conn, conn);
} /* Otherwise, pending queries wil be sent after connected callback. */
return ret;
}
void _output_dnssim_conn_activate(_output_dnssim_connection_t* conn)
{
mlassert(conn, "conn is nil");
mlassert(conn->client, "conn must be associated with a client");
mlassert(conn->client->dnssim, "client must be associated with dnssim");
uv_timer_stop(conn->handshake_timer);
conn->state = _OUTPUT_DNSSIM_CONN_ACTIVE;
conn->client->dnssim->stats_current->conn_active++;
conn->read_state = _OUTPUT_DNSSIM_READ_STATE_DNSLEN;
conn->dnsbuf_len = 2;
conn->dnsbuf_pos = 0;
conn->dnsbuf_free_after_use = false;
_send_pending_queries(conn);
_output_dnssim_conn_idle(conn);
}
int _process_dnsmsg(_output_dnssim_connection_t* conn)
{
mlassert(conn, "conn can't be nil");
mlassert(conn->client, "conn must have client");
mlassert(conn->client->dnssim, "client must have dnssim");
output_dnssim_t* self = conn->client->dnssim;
core_object_payload_t payload = CORE_OBJECT_PAYLOAD_INIT(NULL);
core_object_dns_t dns_a = CORE_OBJECT_DNS_INIT(&payload);
payload.payload = (uint8_t*)conn->dnsbuf_data;
payload.len = conn->dnsbuf_len;
dns_a.obj_prev = (core_object_t*)&payload;
int ret = core_object_dns_parse_header(&dns_a);
if (ret != 0) {
lwarning("tcp response malformed");
return _ERR_MALFORMED;
}
ldebug("tcp recv dnsmsg id: %04x", dns_a.id);
_output_dnssim_query_t* qry;
if (_self->transport == OUTPUT_DNSSIM_TRANSPORT_HTTPS2) {
lassert(conn->http2, "conn must have http2 ctx");
lassert(conn->http2->current_qry, "http2 has no current_qry");
lassert(conn->http2->current_qry->qry.req, "current_qry has no req");
lassert(conn->http2->current_qry->qry.req->dns_q, "req has no dns_q");
ret = _output_dnssim_answers_request(conn->http2->current_qry->qry.req, &dns_a);
switch (ret) {
case 0:
_output_dnssim_request_answered(conn->http2->current_qry->qry.req, &dns_a);
break;
case _ERR_MSGID:
lwarning("https2 QID mismatch: request=0x%04x, response=0x%04x",
conn->http2->current_qry->qry.req->dns_q->id, dns_a.id);
break;
case _ERR_QUESTION:
default:
lwarning("https2 response question mismatch");
break;
}
} else {
qry = conn->sent;
while (qry != NULL) {
if (qry->req->dns_q->id == dns_a.id) {
ret = _output_dnssim_answers_request(qry->req, &dns_a);
if (ret != 0) {
lwarning("response question mismatch");
} else {
_output_dnssim_request_answered(qry->req, &dns_a);
}
break;
}
qry = qry->next;
}
}
return 0;
}
static int _parse_dnsbuf_data(_output_dnssim_connection_t* conn)
{
mlassert(conn, "conn can't be nil");
mlassert(conn->dnsbuf_pos == conn->dnsbuf_len, "attempt to parse incomplete dnsbuf_data");
int ret = 0;
switch (conn->read_state) {
case _OUTPUT_DNSSIM_READ_STATE_DNSLEN: {
uint16_t* p_dnslen = (uint16_t*)conn->dnsbuf_data;
conn->dnsbuf_len = ntohs(*p_dnslen);
if (conn->dnsbuf_len == 0) {
mlwarning("invalid dnslen received: 0");
conn->dnsbuf_len = 2;
conn->read_state = _OUTPUT_DNSSIM_READ_STATE_DNSLEN;
} else if (conn->dnsbuf_len < 12) {
mldebug("invalid dnslen received: %d", conn->dnsbuf_len);
ret = -1;
} else {
mldebug("dnslen: %d", conn->dnsbuf_len);
conn->read_state = _OUTPUT_DNSSIM_READ_STATE_DNSMSG;
}
break;
}
case _OUTPUT_DNSSIM_READ_STATE_DNSMSG:
ret = _process_dnsmsg(conn);
if (ret) {
conn->read_state = _OUTPUT_DNSSIM_READ_STATE_INVALID;
} else {
conn->dnsbuf_len = 2;
conn->read_state = _OUTPUT_DNSSIM_READ_STATE_DNSLEN;
}
break;
default:
mlfatal("tcp invalid connection read_state");
break;
}
conn->dnsbuf_pos = 0;
if (conn->dnsbuf_free_after_use) {
conn->dnsbuf_free_after_use = false;
free(conn->dnsbuf_data);
}
conn->dnsbuf_data = NULL;
return ret;
}
static unsigned int _read_dns_stream_chunk(_output_dnssim_connection_t* conn, size_t len, const char* data)
{
mlassert(conn, "conn can't be nil");
mlassert(data, "data can't be nil");
mlassert(len > 0, "no data to read");
mlassert((conn->read_state == _OUTPUT_DNSSIM_READ_STATE_DNSLEN || conn->read_state == _OUTPUT_DNSSIM_READ_STATE_DNSMSG),
"connection has invalid read_state");
int ret = 0;
unsigned int nread;
size_t expected = conn->dnsbuf_len - conn->dnsbuf_pos;
mlassert(expected > 0, "no data expected");
if (conn->dnsbuf_free_after_use == false && expected > len) {
/* Start of partial read. */
mlassert(conn->dnsbuf_pos == 0, "conn->dnsbuf_pos must be 0 at start of partial read");
mlassert(conn->dnsbuf_len > 0, "conn->dnsbuf_len must be set at start of partial read");
mlfatal_oom(conn->dnsbuf_data = malloc(conn->dnsbuf_len * sizeof(char)));
conn->dnsbuf_free_after_use = true;
}
if (conn->dnsbuf_free_after_use) { /* Partial read is in progress. */
char* dest = conn->dnsbuf_data + conn->dnsbuf_pos;
if (expected < len)
len = expected;
memcpy(dest, data, len);
conn->dnsbuf_pos += len;
nread = len;
} else { /* Complete and clean read. */
mlassert(expected <= len, "not enough data to perform complete read");
conn->dnsbuf_data = (char*)data;
conn->dnsbuf_pos = conn->dnsbuf_len;
nread = expected;
}
/* If entire dnslen/dnsmsg was read, attempt to parse it. */
if (conn->dnsbuf_len == conn->dnsbuf_pos) {
ret = _parse_dnsbuf_data(conn);
if (ret < 0)
return ret;
}
return nread;
}
void _output_dnssim_read_dns_stream(_output_dnssim_connection_t* conn, size_t len, const char* data)
{
int pos = 0;
int chunk = 0;
while (pos < len) {
chunk = _read_dns_stream_chunk(conn, len - pos, data + pos);
if (chunk < 0) {
mlwarning("lost orientation in DNS stream, closing");
_output_dnssim_conn_close(conn);
break;
} else {
pos += chunk;
}
}
mlassert((pos == len) || (chunk < 0), "dns stream read invalid, pos != len");
}
void _output_dnssim_read_dnsmsg(_output_dnssim_connection_t* conn, size_t len, const char* data)
{
mlassert(conn, "conn is nil");
mlassert(len > 0, "len is zero");
mlassert(data, "no data");
mlassert(conn->dnsbuf_pos == 0, "dnsbuf not empty");
mlassert(conn->dnsbuf_free_after_use == false, "dnsbuf read in progress");
/* Read dnsmsg of given length from input data. */
conn->dnsbuf_len = len;
conn->read_state = _OUTPUT_DNSSIM_READ_STATE_DNSMSG;
int nread = _read_dns_stream_chunk(conn, len, data);
if (nread != len) {
mlwarning("failed to read received dnsmsg");
if (conn->dnsbuf_free_after_use)
free(conn->dnsbuf_data);
}
/* Clean state afterwards. */
conn->read_state = _OUTPUT_DNSSIM_READ_STATE_DNSLEN;
conn->dnsbuf_len = 2;
conn->dnsbuf_pos = 0;
conn->dnsbuf_free_after_use = false;
}

View file

@ -1,592 +0,0 @@
/*
* Copyright (c) 2020, CZ.NIC, z.s.p.o.
* All rights reserved.
*
* This file is part of dnsjit.
*
* dnsjit is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dnsjit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "output/dnssim.h"
#include "output/dnssim/internal.h"
#include "output/dnssim/ll.h"
#include "core/assert.h"
#include "lib/base64url.h"
#include <gnutls/gnutls.h>
#include <string.h>
#if GNUTLS_VERSION_NUMBER >= DNSSIM_MIN_GNUTLS_VERSION
#define OUTPUT_DNSSIM_MAKE_NV(NAME, VALUE, VALUELEN) \
{ \
(uint8_t*)NAME, (uint8_t*)VALUE, sizeof(NAME) - 1, VALUELEN, \
NGHTTP2_NV_FLAG_NONE \
}
#define OUTPUT_DNSSIM_MAKE_NV2(NAME, VALUE) \
{ \
(uint8_t*)NAME, (uint8_t*)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1, \
NGHTTP2_NV_FLAG_NONE \
}
#define OUTPUT_DNSSIM_HTTP_GET_TEMPLATE "?dns="
#define OUTPUT_DNSSIM_HTTP_GET_TEMPLATE_LEN (sizeof(OUTPUT_DNSSIM_HTTP_GET_TEMPLATE) - 1)
#define OUTPUT_DNSSIM_HTTP2_INITIAL_MAX_CONCURRENT_STREAMS 100
#define OUTPUT_DNSSIM_HTTP2_DEFAULT_MAX_CONCURRENT_STREAMS 0xffffffffu
static core_log_t _log = LOG_T_INIT("output.dnssim");
static ssize_t _http2_send(nghttp2_session* session, const uint8_t* data, size_t length, int flags, void* user_data)
{
_output_dnssim_connection_t* conn = (_output_dnssim_connection_t*)user_data;
mlassert(conn, "conn can't be null");
mlassert(conn->tls, "conn must have tls ctx");
mlassert(conn->tls->session, "conn must have tls session");
mldebug("http2 (%p): sending data, len=%ld", session, length);
ssize_t len = 0;
if ((len = gnutls_record_send(conn->tls->session, data, length)) < 0) {
mlwarning("gnutls_record_send failed: %s", gnutls_strerror(len));
len = NGHTTP2_ERR_CALLBACK_FAILURE;
}
return len;
}
static ssize_t _http2_on_data_provider_read(nghttp2_session* session, int32_t stream_id, uint8_t* buf, size_t length, uint32_t* data_flags, nghttp2_data_source* source, void* user_data)
{
_output_dnssim_https2_data_provider_t* buffer = source->ptr;
mlassert(buffer, "no data provider");
mlassert(buffer->len <= MAX_DNSMSG_SIZE, "invalid dnsmsg size: %zu B", buffer->len);
ssize_t sent = (length < buffer->len) ? length : buffer->len;
mlassert(sent >= 0, "negative length of bytes to send");
memcpy(buf, buffer->buf, sent);
buffer->buf += sent;
buffer->len -= sent;
if (buffer->len == 0)
*data_flags |= NGHTTP2_DATA_FLAG_EOF;
return sent;
}
static _output_dnssim_query_tcp_t* _http2_get_stream_qry(_output_dnssim_connection_t* conn, int32_t stream_id)
{
mlassert(conn, "conn is nil");
mlassert(stream_id >= 0, "invalid stream_id");
_output_dnssim_query_tcp_t* qry = (_output_dnssim_query_tcp_t*)conn->sent;
while (qry != NULL && qry->stream_id != stream_id) {
qry = (_output_dnssim_query_tcp_t*)qry->qry.next;
}
return qry;
}
static int _http2_on_header(nghttp2_session* session, const nghttp2_frame* frame, const uint8_t* name, size_t namelen, const uint8_t* value, size_t valuelen, uint8_t flags, void* user_data)
{
if (frame->hd.type == NGHTTP2_HEADERS && frame->headers.cat == NGHTTP2_HCAT_RESPONSE) {
if (namelen == 7 && strncmp((char*)name, ":status", 7) == 0) {
if (valuelen != 3 || (value[0] != '1' && value[0] != '2')) {
/* When reponse code isn't 1xx or 2xx, close the query.
* This will result in request timeout, which currently seems
* slightly better than mocking SERVFAIL for statistics. */
_output_dnssim_connection_t* conn = (_output_dnssim_connection_t*)user_data;
mlassert(conn, "conn is nil");
_output_dnssim_query_tcp_t* qry = _http2_get_stream_qry(conn, frame->hd.stream_id);
if (qry != NULL) {
_output_dnssim_close_query_https2(qry);
mlinfo("http response %s, closing query", value);
}
}
}
}
return 0;
}
static int _http2_on_data_recv(nghttp2_session* session, uint8_t flags, int32_t stream_id, const uint8_t* data, size_t len, void* user_data)
{
_output_dnssim_connection_t* conn = (_output_dnssim_connection_t*)user_data;
mlassert(conn, "conn is nil");
_output_dnssim_query_tcp_t* qry = _http2_get_stream_qry(conn, stream_id);
mldebug("http2: data chunk recv, session=%p, len=%d", session, len);
if (qry) {
if (qry->recv_buf_len == 0) {
if (len > MAX_DNSMSG_SIZE) {
mlwarning("http response exceeded maximum size of dns message");
return -1;
}
mlfatal_oom(qry->recv_buf = malloc(len));
memcpy(qry->recv_buf, data, len);
qry->recv_buf_len = len;
} else {
size_t total_len = qry->recv_buf_len + len;
if (total_len > MAX_DNSMSG_SIZE) {
mlwarning("http response exceeded maximum size of dns message");
return -1;
}
mlfatal_oom(qry->recv_buf = realloc(qry->recv_buf, total_len));
memcpy(qry->recv_buf + qry->recv_buf_len, data, len);
qry->recv_buf_len = total_len;
}
} else {
mldebug("no query associated with this stream id, ignoring");
}
return 0;
}
static void _http2_check_max_streams(_output_dnssim_connection_t* conn)
{
mlassert(conn, "conn can't be null");
mlassert(conn->http2, "conn must have http2 ctx");
switch (conn->state) {
case _OUTPUT_DNSSIM_CONN_ACTIVE:
if (conn->http2->open_streams >= conn->http2->max_concurrent_streams) {
mlinfo("http2 (%p): reached maximum number of concurrent streams (%ld)",
conn->http2->session, conn->http2->max_concurrent_streams);
conn->state = _OUTPUT_DNSSIM_CONN_CONGESTED;
}
break;
case _OUTPUT_DNSSIM_CONN_CONGESTED:
if (conn->http2->open_streams < conn->http2->max_concurrent_streams)
conn->state = _OUTPUT_DNSSIM_CONN_ACTIVE;
break;
default:
break;
}
}
static int _http2_on_stream_close(nghttp2_session* session, int32_t stream_id, uint32_t error_code, void* user_data)
{
_output_dnssim_connection_t* conn = (_output_dnssim_connection_t*)user_data;
mlassert(conn, "conn can't be null");
mlassert(conn->http2, "conn must have http2 ctx");
mlassert(conn->http2->open_streams > 0, "conn has no open streams");
conn->http2->open_streams--;
_http2_check_max_streams(conn);
return 0;
}
static int _http2_on_frame_recv(nghttp2_session* session, const nghttp2_frame* frame, void* user_data)
{
_output_dnssim_connection_t* conn = (_output_dnssim_connection_t*)user_data;
mlassert(conn, "conn can't be null");
mlassert(conn->tls, "conn must have tls ctx");
mlassert(conn->tls->session, "conn must have tls session");
mlassert(conn->http2, "conn must have http2 ctx");
switch (frame->hd.type) {
case NGHTTP2_DATA:
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
mldebug("http2 (%p): final DATA frame recv", session);
_output_dnssim_query_tcp_t* qry = _http2_get_stream_qry(conn, frame->hd.stream_id);
if (qry != NULL) {
conn->http2->current_qry = qry;
_output_dnssim_read_dnsmsg(conn, qry->recv_buf_len, (char*)qry->recv_buf);
}
}
break;
case NGHTTP2_SETTINGS:
if (!conn->http2->remote_settings_received) {
/* On the first SETTINGS frame, set concurrent streams to unlimited, same as nghttp2. */
conn->http2->remote_settings_received = true;
conn->http2->max_concurrent_streams = OUTPUT_DNSSIM_HTTP2_DEFAULT_MAX_CONCURRENT_STREAMS;
_http2_check_max_streams(conn);
}
nghttp2_settings* settings = (nghttp2_settings*)frame;
int i;
for (i = 0; i < settings->niv; i++) {
switch (settings->iv[i].settings_id) {
case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS:
conn->http2->max_concurrent_streams = settings->iv[i].value;
_http2_check_max_streams(conn);
break;
default:
break;
}
}
break;
default:
break;
}
return 0;
}
int _output_dnssim_https2_init(_output_dnssim_connection_t* conn)
{
mlassert(conn, "conn is nil");
mlassert(conn->tls == NULL, "conn already has tls context");
mlassert(conn->http2 == NULL, "conn already has http2 context");
mlassert(conn->client, "conn must be associated with a client");
mlassert(conn->client->dnssim, "client must have dnssim");
int ret = -1;
nghttp2_session_callbacks* callbacks;
nghttp2_option* option;
output_dnssim_t* self = conn->client->dnssim;
/* Initialize TLS session. */
ret = _output_dnssim_tls_init(conn);
if (ret < 0)
return ret;
/* Configure ALPN to negotiate HTTP/2. */
const gnutls_datum_t protos[] = {
{ (unsigned char*)"h2", 2 }
};
ret = gnutls_alpn_set_protocols(conn->tls->session, protos, 1, 0);
if (ret < 0) {
lwarning("failed to set ALPN protocol: %s", gnutls_strerror(ret));
return ret;
}
lfatal_oom(conn->http2 = calloc(1, sizeof(_output_dnssim_http2_ctx_t)));
conn->http2->max_concurrent_streams = OUTPUT_DNSSIM_HTTP2_INITIAL_MAX_CONCURRENT_STREAMS;
/* Set up HTTP/2 callbacks and client. */
lassert(nghttp2_session_callbacks_new(&callbacks) == 0, "out of memory");
nghttp2_session_callbacks_set_send_callback(callbacks, _http2_send);
nghttp2_session_callbacks_set_on_header_callback(callbacks, _http2_on_header);
nghttp2_session_callbacks_set_on_data_chunk_recv_callback(callbacks, _http2_on_data_recv);
nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks, _http2_on_frame_recv);
nghttp2_session_callbacks_set_on_stream_close_callback(callbacks, _http2_on_stream_close);
lassert(nghttp2_option_new(&option) == 0, "out of memory");
nghttp2_option_set_peer_max_concurrent_streams(option, conn->http2->max_concurrent_streams);
ret = nghttp2_session_client_new2(&conn->http2->session, callbacks, conn, option);
nghttp2_session_callbacks_del(callbacks);
nghttp2_option_del(option);
if (ret < 0) {
free(conn->http2);
conn->http2 = NULL;
}
return ret;
}
int _output_dnssim_https2_setup(_output_dnssim_connection_t* conn)
{
mlassert(conn, "conn is nil");
mlassert(conn->tls, "conn must have tls ctx");
mlassert(conn->tls->session, "conn must have tls session");
mlassert(conn->http2, "conn must have http2 ctx");
mlassert(conn->http2->session, "conn must have http2 session");
int ret = -1;
/* Check "h2" protocol was negotiated with ALPN. */
gnutls_datum_t proto;
ret = gnutls_alpn_get_selected_protocol(conn->tls->session, &proto);
if (ret < 0) {
mlwarning("http2: failed to get negotiated protocol: %s", gnutls_strerror(ret));
return ret;
}
if (proto.size != 2 || memcmp("h2", proto.data, 2) != 0) {
mlwarning("http2: protocol is not negotiated");
return ret;
}
/* Submit SETTIGNS frame. */
static const nghttp2_settings_entry iv[] = {
{ NGHTTP2_SETTINGS_MAX_FRAME_SIZE, MAX_DNSMSG_SIZE },
{ NGHTTP2_SETTINGS_ENABLE_PUSH, 0 }, /* Only we can initiate streams. */
};
ret = nghttp2_submit_settings(conn->http2->session, NGHTTP2_FLAG_NONE, iv, sizeof(iv) / sizeof(*iv));
if (ret < 0) {
mlwarning("http2: failed to submit SETTINGS: %s", nghttp2_strerror(ret));
return ret;
}
ret = 0;
return ret;
}
void _output_dnssim_https2_process_input_data(_output_dnssim_connection_t* conn, size_t len, const char* data)
{
mlassert(conn, "conn is nil");
mlassert(conn->http2, "conn must have http2 ctx");
mlassert(conn->http2->session, "conn must have http2 session");
/* Process incoming frames. */
ssize_t ret = 0;
conn->prevent_close = true;
ret = nghttp2_session_mem_recv(conn->http2->session, (uint8_t*)data, len);
conn->prevent_close = false;
if (ret < 0) {
mlwarning("failed nghttp2_session_mem_recv: %s", nghttp2_strerror(ret));
_output_dnssim_conn_close(conn);
return;
} else if (conn->state == _OUTPUT_DNSSIM_CONN_CLOSE_REQUESTED) {
_output_dnssim_conn_close(conn);
return;
}
mlassert(ret == len, "nghttp2_session_mem_recv didn't process all data");
/* Send any frames the read might have triggered. */
ret = nghttp2_session_send(conn->http2->session);
if (ret < 0) {
mlwarning("failed nghttp2_session_send: %s", nghttp2_strerror(ret));
_output_dnssim_conn_close(conn);
return;
}
}
int _output_dnssim_create_query_https2(output_dnssim_t* self, _output_dnssim_request_t* req)
{
mlassert_self();
lassert(req, "req is nil");
lassert(req->client, "request must have a client associated with it");
_output_dnssim_query_tcp_t* qry;
lfatal_oom(qry = calloc(1, sizeof(_output_dnssim_query_tcp_t)));
qry->qry.transport = OUTPUT_DNSSIM_TRANSPORT_HTTPS2;
qry->qry.req = req;
qry->qry.state = _OUTPUT_DNSSIM_QUERY_PENDING_WRITE;
qry->stream_id = -1;
req->qry = &qry->qry; // TODO change when adding support for multiple Qs for req
_ll_append(req->client->pending, &qry->qry);
return _output_dnssim_handle_pending_queries(req->client);
}
void _output_dnssim_close_query_https2(_output_dnssim_query_tcp_t* qry)
{
mlassert(qry, "qry can't be null");
mlassert(qry->qry.req, "query must be part of a request");
_output_dnssim_request_t* req = qry->qry.req;
mlassert(req->client, "request must belong to a client");
_ll_try_remove(req->client->pending, &qry->qry);
if (qry->conn) {
_output_dnssim_connection_t* conn = qry->conn;
_ll_try_remove(conn->sent, &qry->qry);
qry->conn = NULL;
_output_dnssim_conn_idle(conn);
}
if (qry->recv_buf != NULL)
free(qry->recv_buf);
_ll_remove(req->qry, &qry->qry);
free(qry);
}
void _output_dnssim_https2_close(_output_dnssim_connection_t* conn)
{
mlassert(conn, "conn can't be nil");
mlassert(conn->http2, "conn must have http2 ctx");
nghttp2_session_del(conn->http2->session);
_output_dnssim_tls_close(conn);
}
static int _http2_send_query_get(_output_dnssim_connection_t* conn, _output_dnssim_query_tcp_t* qry)
{
mlassert(conn, "conn can't be null");
mlassert(qry, "qry can't be null");
mlassert(qry->qry.req, "req can't be null");
mlassert(qry->qry.req->payload, "payload can't be null");
mlassert(qry->qry.req->payload->len <= MAX_DNSMSG_SIZE, "payload too big");
mlassert(conn->client, "conn must be associated with client");
mlassert(conn->client->dnssim, "client must have dnssim");
output_dnssim_t* self = conn->client->dnssim;
core_object_payload_t* content = qry->qry.req->payload;
const size_t uri_path_len = strlen(_self->h2_uri_path);
const size_t path_len = uri_path_len
+ OUTPUT_DNSSIM_HTTP_GET_TEMPLATE_LEN
+ (content->len * 4) / 3 + 3 /* upper limit of base64 encoding */
+ 1; /* terminating null byte */
if (path_len >= _MAX_URI_LEN) {
self->discarded++;
linfo("http2: uri path with query too long, query discarded");
return 0;
}
char path[path_len];
memcpy(path, _self->h2_uri_path, uri_path_len);
memcpy(&path[uri_path_len], OUTPUT_DNSSIM_HTTP_GET_TEMPLATE, OUTPUT_DNSSIM_HTTP_GET_TEMPLATE_LEN);
int32_t ret = base64url_encode(content->payload, content->len,
(uint8_t*)&path[uri_path_len + OUTPUT_DNSSIM_HTTP_GET_TEMPLATE_LEN],
sizeof(path) - uri_path_len - OUTPUT_DNSSIM_HTTP_GET_TEMPLATE_LEN - 1);
if (ret < 0) {
self->discarded++;
linfo("http2: base64url encode of query failed, query discarded");
return 0;
}
nghttp2_nv hdrs[] = {
OUTPUT_DNSSIM_MAKE_NV2(":method", "GET"),
OUTPUT_DNSSIM_MAKE_NV2(":scheme", "https"),
OUTPUT_DNSSIM_MAKE_NV(":authority", _self->h2_uri_authority, strlen(_self->h2_uri_authority)),
OUTPUT_DNSSIM_MAKE_NV(":path", path, uri_path_len + sizeof(OUTPUT_DNSSIM_HTTP_GET_TEMPLATE) - 1 + ret),
OUTPUT_DNSSIM_MAKE_NV2("accept", "application/dns-message"),
};
qry->stream_id = nghttp2_submit_request(conn->http2->session, NULL, hdrs, sizeof(hdrs) / sizeof(nghttp2_nv), NULL, NULL);
if (qry->stream_id < 0) {
mldebug("http2 (%p): failed to submit request: %s", conn->http2->session, nghttp2_strerror(qry->stream_id));
return -1;
}
mldebug("http2 (%p): GET %s", conn->http2->session, path);
conn->http2->open_streams++;
_http2_check_max_streams(conn);
ret = nghttp2_session_send(conn->http2->session);
if (ret < 0) {
mldebug("http2 (%p): failed session send: %s", conn->http2->session, nghttp2_strerror(ret));
return -1;
}
return 0;
}
static int _http2_send_query_post(_output_dnssim_connection_t* conn, _output_dnssim_query_tcp_t* qry)
{
mlassert(conn, "conn can't be null");
mlassert(qry, "qry can't be null");
mlassert(qry->qry.req, "req can't be null");
mlassert(qry->qry.req->payload, "payload can't be null");
mlassert(qry->qry.req->payload->len <= MAX_DNSMSG_SIZE, "payload too big");
mlassert(conn->client, "conn must be associated with client");
mlassert(conn->client->dnssim, "client must have dnssim");
output_dnssim_t* self = conn->client->dnssim;
core_object_payload_t* content = qry->qry.req->payload;
int window_size = nghttp2_session_get_remote_window_size(conn->http2->session);
if (content->len > window_size) {
mldebug("http2 (%p): insufficient remote window size, deferring", conn->http2->session);
return 0;
}
char content_length[6]; /* max dnslen "65535" */
int content_length_len = snprintf(content_length, 6, "%zd", content->len);
nghttp2_nv hdrs[] = {
OUTPUT_DNSSIM_MAKE_NV2(":method", "POST"),
OUTPUT_DNSSIM_MAKE_NV2(":scheme", "https"),
OUTPUT_DNSSIM_MAKE_NV(":authority", _self->h2_uri_authority, strlen(_self->h2_uri_authority)),
OUTPUT_DNSSIM_MAKE_NV(":path", _self->h2_uri_path, strlen(_self->h2_uri_path)),
OUTPUT_DNSSIM_MAKE_NV2("accept", "application/dns-message"),
OUTPUT_DNSSIM_MAKE_NV2("content-type", "application/dns-message"),
OUTPUT_DNSSIM_MAKE_NV("content-length", content_length, content_length_len)
};
_output_dnssim_https2_data_provider_t data = {
.buf = content->payload,
.len = content->len
};
nghttp2_data_provider data_provider = {
.source.ptr = &data,
.read_callback = _http2_on_data_provider_read
};
qry->stream_id = nghttp2_submit_request(conn->http2->session, NULL, hdrs, sizeof(hdrs) / sizeof(nghttp2_nv), &data_provider, NULL);
if (qry->stream_id < 0) {
mldebug("http2 (%p): failed to submit request: %s", conn->http2->session, nghttp2_strerror(qry->stream_id));
return -1;
}
mldebug("http2 (%p): POST payload len=%ld", conn->http2->session, content->len);
conn->http2->open_streams++;
_http2_check_max_streams(conn);
window_size = nghttp2_session_get_stream_remote_window_size(conn->http2->session, qry->stream_id);
mlassert(content->len <= window_size,
"unsupported: http2 stream window size (%ld B) is smaller than dns payload (%ld B)",
window_size, content->len);
int ret = nghttp2_session_send(conn->http2->session);
if (ret < 0) {
mldebug("http2 (%p): failed session send: %s", conn->http2->session, nghttp2_strerror(ret));
return -1;
}
return 0;
}
void _output_dnssim_https2_write_query(_output_dnssim_connection_t* conn, _output_dnssim_query_tcp_t* qry)
{
mlassert(qry, "qry can't be null");
mlassert(qry->qry.state == _OUTPUT_DNSSIM_QUERY_PENDING_WRITE, "qry must be pending write");
mlassert(conn, "conn can't be null");
mlassert(conn->state == _OUTPUT_DNSSIM_CONN_ACTIVE, "connection state != ACTIVE");
mlassert(conn->http2, "conn must have http2 ctx");
mlassert(conn->http2->session, "conn must have http2 session");
mlassert(conn->client, "conn must be associated with client");
mlassert(conn->client->pending, "conn has no pending queries");
mlassert(conn->client->dnssim, "client must have dnssim");
int ret = 0;
output_dnssim_t* self = conn->client->dnssim;
if (!nghttp2_session_check_request_allowed(conn->http2->session)) {
mldebug("http2 (%p): request not allowed", conn->http2->session);
_output_dnssim_conn_close(conn);
return;
}
switch (_self->h2_method) {
case OUTPUT_DNSSIM_H2_POST:
ret = _http2_send_query_post(conn, qry);
break;
case OUTPUT_DNSSIM_H2_GET:
ret = _http2_send_query_get(conn, qry);
break;
default:
lfatal("http2: unsupported method");
}
if (ret < 0) {
_output_dnssim_conn_close(conn);
return;
}
qry->conn = conn;
_ll_remove(conn->client->pending, &qry->qry);
_ll_append(conn->sent, &qry->qry);
/* Stop idle timer, since there are queries to answer now. */
if (conn->idle_timer != NULL) {
conn->is_idle = false;
uv_timer_stop(conn->idle_timer);
}
qry->qry.state = _OUTPUT_DNSSIM_QUERY_SENT;
}
#endif

View file

@ -1,343 +0,0 @@
/*
* Copyright (c) 2019-2020, CZ.NIC, z.s.p.o.
* All rights reserved.
*
* This file is part of dnsjit.
*
* dnsjit is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dnsjit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __dnsjit_output_dnssim_internal_h
#define __dnsjit_output_dnssim_internal_h
#include <gnutls/gnutls.h>
#include <nghttp2/nghttp2.h>
#include <uv.h>
#include "core/object/dns.h"
#include "core/object/payload.h"
#define DNSSIM_MIN_GNUTLS_VERSION 0x030603
#define DNSSIM_MIN_GNUTLS_ERRORMSG "dnssim tls/https2 transport requires GnuTLS >= 3.6.3"
#define _self ((_output_dnssim_t*)self)
#define _ERR_MALFORMED -2
#define _ERR_MSGID -3
#define _ERR_TC -4
#define _ERR_QUESTION -5
#define _MAX_URI_LEN 65536
#define MAX_DNSMSG_SIZE 65535
#define WIRE_BUF_SIZE (MAX_DNSMSG_SIZE + 2 + 16384) /** max tcplen + 2b tcplen + 16kb tls record */
typedef struct _output_dnssim_request _output_dnssim_request_t;
typedef struct _output_dnssim_connection _output_dnssim_connection_t;
typedef struct _output_dnssim_client _output_dnssim_client_t;
/*
* Query-related structures.
*/
typedef struct _output_dnssim_query _output_dnssim_query_t;
struct _output_dnssim_query {
/*
* Next query in the list.
*
* Currently, next is used for TCP clients/connection, which makes it
* impossible to use for tracking multiple queries of a single request.
*
* TODO: refactor the linked lists to allow query to be part of multiple lists
*/
_output_dnssim_query_t* next;
output_dnssim_transport_t transport;
_output_dnssim_request_t* req;
/* Query state, currently used only for TCP. */
enum {
_OUTPUT_DNSSIM_QUERY_PENDING_WRITE,
_OUTPUT_DNSSIM_QUERY_PENDING_WRITE_CB,
_OUTPUT_DNSSIM_QUERY_PENDING_CLOSE,
_OUTPUT_DNSSIM_QUERY_WRITE_FAILED,
_OUTPUT_DNSSIM_QUERY_SENT,
_OUTPUT_DNSSIM_QUERY_ORPHANED
} state;
};
typedef struct _output_dnssim_query_udp _output_dnssim_query_udp_t;
struct _output_dnssim_query_udp {
_output_dnssim_query_t qry;
uv_udp_t* handle;
uv_buf_t buf;
};
typedef struct _output_dnssim_query_tcp _output_dnssim_query_tcp_t;
struct _output_dnssim_query_tcp {
_output_dnssim_query_t qry;
/* Connection this query is assigned to. */
_output_dnssim_connection_t* conn;
uv_write_t write_req;
/* Send buffers for libuv; 0 is for dnslen, 1 is for dnsmsg. */
uv_buf_t bufs[2];
/* HTTP/2 stream id that was used to send this query. */
int32_t stream_id;
/* HTTP/2 expected content length. */
int32_t content_len;
/* Receive buffer (currently used only by HTTP/2). */
uint8_t* recv_buf;
ssize_t recv_buf_len;
};
struct _output_dnssim_request {
/* List of queries associated with this request. */
_output_dnssim_query_t* qry;
/* Client this request belongs to. */
_output_dnssim_client_t* client;
/* The DNS question to be resolved. */
core_object_payload_t* payload;
core_object_dns_t* dns_q;
const uint8_t* question;
ssize_t question_len;
/* Timestamps for latency calculation. */
uint64_t created_at;
uint64_t ended_at;
/* Timer for tracking timeout of the request. */
uv_timer_t* timer;
/* The output component of this request. */
output_dnssim_t* dnssim;
/* State of the request. */
enum {
_OUTPUT_DNSSIM_REQ_ONGOING,
_OUTPUT_DNSSIM_REQ_CLOSING
} state;
/* Statistics interval in which this request is tracked. */
output_dnssim_stats_t* stats;
};
/*
* Connection-related structures.
*/
/* Read-state of connection's data stream. */
typedef enum _output_dnssim_read_state {
_OUTPUT_DNSSIM_READ_STATE_CLEAN,
_OUTPUT_DNSSIM_READ_STATE_DNSLEN, /* Expecting bytes of dnslen. */
_OUTPUT_DNSSIM_READ_STATE_DNSMSG, /* Expecting bytes of dnsmsg. */
_OUTPUT_DNSSIM_READ_STATE_INVALID
} _output_dnssim_read_state_t;
/* TLS-related data for a single connection. */
typedef struct _output_dnssim_tls_ctx {
gnutls_session_t session;
uint8_t* buf;
ssize_t buf_len;
ssize_t buf_pos;
size_t write_queue_size;
} _output_dnssim_tls_ctx_t;
/* HTTP2 context for a single connection. */
typedef struct _output_dnssim_http2_ctx {
nghttp2_session* session;
/* Query to which the dnsbuf currently being processed belongs to. */
_output_dnssim_query_tcp_t* current_qry;
/* Maximum number of concurrent and currently open streams. */
uint32_t max_concurrent_streams;
uint32_t open_streams;
/* Flag indicating whether we received the peer's initial SETTINGS frame. */
bool remote_settings_received;
} _output_dnssim_http2_ctx_t;
struct _output_dnssim_connection {
_output_dnssim_connection_t* next;
uv_tcp_t* handle;
/* Timeout timer for establishing the connection. */
uv_timer_t* handshake_timer;
/* Idle timer for connection reuse. rfc7766#section-6.2.3 */
uv_timer_t* idle_timer;
bool is_idle;
/* List of queries that have been queued (pending write callback). */
_output_dnssim_query_t* queued;
/* List of queries that have been sent over this connection. */
_output_dnssim_query_t* sent;
/* Client this connection belongs to. */
_output_dnssim_client_t* client;
/* State of the connection.
* Numeric ordering of constants is significant and follows the typical connection lifecycle.
* Ensure new states are added to a proper place. */
enum {
_OUTPUT_DNSSIM_CONN_INITIALIZED = 0,
_OUTPUT_DNSSIM_CONN_TCP_HANDSHAKE = 10,
_OUTPUT_DNSSIM_CONN_TLS_HANDSHAKE = 20,
_OUTPUT_DNSSIM_CONN_ACTIVE = 30,
_OUTPUT_DNSSIM_CONN_CONGESTED = 35,
_OUTPUT_DNSSIM_CONN_CLOSE_REQUESTED = 38,
_OUTPUT_DNSSIM_CONN_CLOSING = 40,
_OUTPUT_DNSSIM_CONN_CLOSED = 50
} state;
/* State of the data stream read. */
_output_dnssim_read_state_t read_state;
/* Total length of the expected dns data (either 2 for dnslen, or dnslen itself). */
size_t dnsbuf_len;
/* Current position in the receive dns buffer. */
size_t dnsbuf_pos;
/* Receive buffer used for incomplete messages or dnslen. */
char* dnsbuf_data;
bool dnsbuf_free_after_use;
/* Statistics interval in which the handshake is tracked. */
output_dnssim_stats_t* stats;
/* TLS-related data. */
_output_dnssim_tls_ctx_t* tls;
/* HTTP/2-related data. */
_output_dnssim_http2_ctx_t* http2;
/* Prevents immediate closure of connection. Instead, connection is moved
* to CLOSE_REQUESTED state and setter of this flag is responsible for
* closing the connection when clearing this flag. */
bool prevent_close;
};
/*
* Client structure.
*/
struct _output_dnssim_client {
/* Dnssim component this client belongs to. */
output_dnssim_t* dnssim;
/* List of connections.
* Multiple connections may be used (e.g. some are already closed for writing).
*/
_output_dnssim_connection_t* conn;
/* List of queries that are pending to be sent over any available connection. */
_output_dnssim_query_t* pending;
/* TLS-ticket for session resumption. */
gnutls_datum_t tls_ticket;
};
/*
* DnsSim-related structures.
*/
typedef struct _output_dnssim_source _output_dnssim_source_t;
struct _output_dnssim_source {
_output_dnssim_source_t* next;
struct sockaddr_storage addr;
};
typedef struct _output_dnssim _output_dnssim_t;
struct _output_dnssim {
output_dnssim_t pub;
uv_loop_t loop;
uv_timer_t stats_timer;
struct sockaddr_storage target;
_output_dnssim_source_t* source;
output_dnssim_transport_t transport;
char h2_uri_authority[_MAX_URI_LEN];
char h2_uri_path[_MAX_URI_LEN];
bool h2_zero_out_msgid;
output_dnssim_h2_method_t h2_method;
/* Array of clients, mapped by client ID (ranges from 0 to max_clients). */
_output_dnssim_client_t* client_arr;
gnutls_priority_t* tls_priority;
gnutls_certificate_credentials_t tls_cred;
char wire_buf[WIRE_BUF_SIZE]; /* thread-local buffer for processing tls input */
};
/* Provides data for HTTP/2 data frames. */
typedef struct {
const uint8_t* buf;
size_t len;
} _output_dnssim_https2_data_provider_t;
/*
* Forward function declarations.
*/
int _output_dnssim_bind_before_connect(output_dnssim_t* self, uv_handle_t* handle);
int _output_dnssim_create_query_udp(output_dnssim_t* self, _output_dnssim_request_t* req);
int _output_dnssim_create_query_tcp(output_dnssim_t* self, _output_dnssim_request_t* req);
void _output_dnssim_close_query_udp(_output_dnssim_query_udp_t* qry);
void _output_dnssim_close_query_tcp(_output_dnssim_query_tcp_t* qry);
int _output_dnssim_answers_request(_output_dnssim_request_t* req, core_object_dns_t* response);
void _output_dnssim_request_answered(_output_dnssim_request_t* req, core_object_dns_t* msg);
void _output_dnssim_maybe_free_request(_output_dnssim_request_t* req);
void _output_dnssim_on_uv_alloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf);
void _output_dnssim_create_request(output_dnssim_t* self, _output_dnssim_client_t* client, core_object_payload_t* payload);
int _output_dnssim_handle_pending_queries(_output_dnssim_client_t* client);
int _output_dnssim_tcp_connect(output_dnssim_t* self, _output_dnssim_connection_t* conn);
void _output_dnssim_tcp_close(_output_dnssim_connection_t* conn);
void _output_dnssim_tcp_write_query(_output_dnssim_connection_t* conn, _output_dnssim_query_tcp_t* qry);
void _output_dnssim_conn_close(_output_dnssim_connection_t* conn);
void _output_dnssim_conn_idle(_output_dnssim_connection_t* conn);
int _output_dnssim_handle_pending_queries(_output_dnssim_client_t* client);
void _output_dnssim_conn_activate(_output_dnssim_connection_t* conn);
void _output_dnssim_conn_maybe_free(_output_dnssim_connection_t* conn);
void _output_dnssim_read_dns_stream(_output_dnssim_connection_t* conn, size_t len, const char* data);
void _output_dnssim_read_dnsmsg(_output_dnssim_connection_t* conn, size_t len, const char* data);
#if GNUTLS_VERSION_NUMBER >= DNSSIM_MIN_GNUTLS_VERSION
int _output_dnssim_create_query_tls(output_dnssim_t* self, _output_dnssim_request_t* req);
void _output_dnssim_close_query_tls(_output_dnssim_query_tcp_t* qry);
int _output_dnssim_tls_init(_output_dnssim_connection_t* conn);
void _output_dnssim_tls_process_input_data(_output_dnssim_connection_t* conn);
void _output_dnssim_tls_close(_output_dnssim_connection_t* conn);
void _output_dnssim_tls_write_query(_output_dnssim_connection_t* conn, _output_dnssim_query_tcp_t* qry);
int _output_dnssim_create_query_https2(output_dnssim_t* self, _output_dnssim_request_t* req);
void _output_dnssim_close_query_https2(_output_dnssim_query_tcp_t* qry);
int _output_dnssim_https2_init(_output_dnssim_connection_t* conn);
int _output_dnssim_https2_setup(_output_dnssim_connection_t* conn);
void _output_dnssim_https2_process_input_data(_output_dnssim_connection_t* conn, size_t len, const char* data);
void _output_dnssim_https2_close(_output_dnssim_connection_t* conn);
void _output_dnssim_https2_write_query(_output_dnssim_connection_t* conn, _output_dnssim_query_tcp_t* qry);
#endif
#endif

View file

@ -1,83 +0,0 @@
/*
* Copyright (c) 2019-2020, CZ.NIC, z.s.p.o.
* All rights reserved.
*
* This file is part of dnsjit.
*
* dnsjit is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dnsjit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __dnsjit_output_dnssim_ll_h
#define __dnsjit_output_dnssim_ll_h
#include "core/assert.h"
/* Utility macros for linked list structures.
*
* - "list" is the pointer to the first node of the linked list
* - "list" can be NULL if there are no nodes
* - every node has "next", which points to the next node (can be NULL)
*/
/* Append a node to the list.
*
* Only a single node can be appended - node->next must be NULL.
*/
#define _ll_append(list, node) \
{ \
glassert((node)->next == NULL, "node->next must be null when appending"); \
if ((list) == NULL) \
(list) = (node); \
else if ((node) != NULL) { \
typeof(list) _current = (list); \
while (_current->next != NULL) \
_current = _current->next; \
_current->next = node; \
} \
}
/* Remove a node from the list.
*
* In strict mode, the node must be present in the list.
*/
#define _ll_remove_template(list, node, strict) \
{ \
if (strict) \
glassert((list), "list can't be null when removing nodes"); \
if ((list) != NULL && (node) != NULL) { \
if ((list) == (node)) { \
(list) = (node)->next; \
(node)->next = NULL; \
} else { \
typeof(list) _current = (list); \
while (_current != NULL && _current->next != (node)) { \
if (strict) \
glassert((_current->next), "list doesn't contain the node to be removed"); \
_current = _current->next; \
} \
if (_current != NULL) { \
_current->next = (node)->next; \
(node)->next = NULL; \
} \
} \
} \
}
/* Remove a node from the list. */
#define _ll_remove(list, node) _ll_remove_template((list), (node), true)
/* Remove a node from the list if it's present. */
#define _ll_try_remove(list, node) _ll_remove_template((list), (node), false)
#endif

View file

@ -1,356 +0,0 @@
/*
* Copyright (c) 2019-2020, CZ.NIC, z.s.p.o.
* All rights reserved.
*
* This file is part of dnsjit.
*
* dnsjit is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dnsjit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "output/dnssim.h"
#include "output/dnssim/internal.h"
#include "output/dnssim/ll.h"
#include "core/assert.h"
#include <string.h>
static core_log_t _log = LOG_T_INIT("output.dnssim");
static void _move_queries_to_pending(_output_dnssim_query_tcp_t* qry)
{
_output_dnssim_query_tcp_t* qry_tmp;
while (qry != NULL) {
mlassert(qry->conn, "query must be associated with conn");
mlassert(qry->conn->state == _OUTPUT_DNSSIM_CONN_CLOSED, "conn must be closed");
mlassert(qry->conn->client, "conn must be associated with client");
qry_tmp = (_output_dnssim_query_tcp_t*)qry->qry.next;
qry->qry.next = NULL;
_ll_append(qry->conn->client->pending, &qry->qry);
qry->conn = NULL;
qry->qry.state = _OUTPUT_DNSSIM_QUERY_ORPHANED;
qry->stream_id = -1;
qry->recv_buf_len = 0;
if (qry->recv_buf != NULL) {
free(qry->recv_buf);
qry->recv_buf = NULL;
}
qry = qry_tmp;
}
}
static void _on_tcp_closed(uv_handle_t* handle)
{
_output_dnssim_connection_t* conn = (_output_dnssim_connection_t*)handle->data;
mlassert(conn, "conn is nil");
conn->state = _OUTPUT_DNSSIM_CONN_CLOSED;
/* Orphan any queries that are still unresolved. */
_move_queries_to_pending((_output_dnssim_query_tcp_t*)conn->queued);
conn->queued = NULL;
_move_queries_to_pending((_output_dnssim_query_tcp_t*)conn->sent);
conn->sent = NULL;
/* TODO Improve client re-connect behavior in case the connection fails to
* establish. Currently, queries are orphaned and attempted to be re-sent
* along with the next query that triggers a new connection.
*
* Attempting to establish new connection immediately leads to performance
* issues if the number of these attempts doesn't have upper limit. */
///* Ensure orhpaned queries are re-sent over a different connection. */
//if (_output_dnssim_handle_pending_queries(conn->client) != 0)
// mlinfo("tcp: orphaned queries failed to be re-sent");
mlassert(conn->handle, "conn must have tcp handle when closing it");
free(conn->handle);
conn->handle = NULL;
_output_dnssim_conn_maybe_free(conn);
}
static void _on_tcp_query_written(uv_write_t* wr_req, int status)
{
_output_dnssim_query_tcp_t* qry = (_output_dnssim_query_tcp_t*)wr_req->data;
mlassert(qry, "qry/wr_req->data is nil");
mlassert(qry->conn, "query must be associated with connection");
_output_dnssim_connection_t* conn = qry->conn;
free(((_output_dnssim_query_tcp_t*)qry)->bufs[0].base);
if (qry->qry.state == _OUTPUT_DNSSIM_QUERY_PENDING_CLOSE) {
qry->qry.state = status < 0 ? _OUTPUT_DNSSIM_QUERY_WRITE_FAILED : _OUTPUT_DNSSIM_QUERY_SENT;
_output_dnssim_request_t* req = qry->qry.req;
_output_dnssim_close_query_tcp(qry);
_output_dnssim_maybe_free_request(req);
qry = NULL;
}
if (status < 0) {
if (status != UV_ECANCELED)
mlinfo("tcp write failed: %s", uv_strerror(status));
if (qry != NULL)
qry->qry.state = _OUTPUT_DNSSIM_QUERY_WRITE_FAILED;
_output_dnssim_conn_close(conn);
return;
}
if (qry == NULL)
return;
/* Mark query as sent and assign it to connection. */
mlassert(qry->qry.state == _OUTPUT_DNSSIM_QUERY_PENDING_WRITE_CB, "invalid query state");
qry->qry.state = _OUTPUT_DNSSIM_QUERY_SENT;
if (qry->conn->state == _OUTPUT_DNSSIM_CONN_ACTIVE) {
mlassert(qry->conn->queued, "conn has no queued queries");
_ll_remove(qry->conn->queued, &qry->qry);
_ll_append(qry->conn->sent, &qry->qry);
}
}
void _output_dnssim_tcp_write_query(_output_dnssim_connection_t* conn, _output_dnssim_query_tcp_t* qry)
{
mlassert(qry, "qry can't be null");
mlassert(qry->qry.state == _OUTPUT_DNSSIM_QUERY_PENDING_WRITE, "qry must be pending write");
mlassert(qry->qry.req, "req can't be null");
mlassert(qry->qry.req->dns_q, "dns_q can't be null");
mlassert(qry->qry.req->dns_q->obj_prev, "payload can't be null");
mlassert(conn, "conn can't be null");
mlassert(conn->state == _OUTPUT_DNSSIM_CONN_ACTIVE, "connection state != ACTIVE");
mlassert(conn->client, "conn must be associated with client");
mlassert(conn->client->pending, "conn has no pending queries");
mldebug("tcp write dnsmsg id: %04x", qry->qry.req->dns_q->id);
core_object_payload_t* payload = (core_object_payload_t*)qry->qry.req->dns_q->obj_prev;
uint16_t* len;
mlfatal_oom(len = malloc(sizeof(uint16_t)));
*len = htons(payload->len);
qry->bufs[0] = uv_buf_init((char*)len, 2);
qry->bufs[1] = uv_buf_init((char*)payload->payload, payload->len);
qry->conn = conn;
_ll_remove(conn->client->pending, &qry->qry);
_ll_append(conn->queued, &qry->qry);
/* Stop idle timer, since there are queries to answer now. */
if (conn->idle_timer != NULL) {
conn->is_idle = false;
uv_timer_stop(conn->idle_timer);
}
qry->write_req.data = (void*)qry;
uv_write(&qry->write_req, (uv_stream_t*)conn->handle, qry->bufs, 2, _on_tcp_query_written);
qry->qry.state = _OUTPUT_DNSSIM_QUERY_PENDING_WRITE_CB;
}
static void _on_tcp_read(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf)
{
_output_dnssim_connection_t* conn = (_output_dnssim_connection_t*)handle->data;
output_dnssim_t* self = conn->client->dnssim;
if (nread > 0) {
mldebug("tcp nread: %d", nread);
switch (_self->transport) {
case OUTPUT_DNSSIM_TRANSPORT_TCP:
_output_dnssim_read_dns_stream(conn, nread, buf->base);
break;
case OUTPUT_DNSSIM_TRANSPORT_TLS:
case OUTPUT_DNSSIM_TRANSPORT_HTTPS2:
#if GNUTLS_VERSION_NUMBER >= DNSSIM_MIN_GNUTLS_VERSION
mlassert(conn->tls, "con must have tls ctx");
conn->tls->buf = (uint8_t*)buf->base;
conn->tls->buf_pos = 0;
conn->tls->buf_len = nread;
_output_dnssim_tls_process_input_data(conn);
#else
mlfatal(DNSSIM_MIN_GNUTLS_ERRORMSG);
#endif
break;
default:
mlfatal("unsupported transport");
break;
}
} else if (nread < 0) {
if (nread != UV_EOF)
mlinfo("tcp conn unexpected close: %s", uv_strerror(nread));
_output_dnssim_conn_close(conn);
}
if (buf->base != NULL)
free(buf->base);
}
static void _on_tcp_connected(uv_connect_t* conn_req, int status)
{
_output_dnssim_connection_t* conn = (_output_dnssim_connection_t*)conn_req->handle->data;
mlassert(conn, "conn is nil");
free(conn_req);
if (status < 0) {
mldebug("tcp connect failed: %s", uv_strerror(status));
_output_dnssim_conn_close(conn);
return;
}
mlassert(conn->state == _OUTPUT_DNSSIM_CONN_TCP_HANDSHAKE, "connection state != TCP_HANDSHAKE");
int ret = uv_read_start((uv_stream_t*)conn->handle, _output_dnssim_on_uv_alloc, _on_tcp_read);
if (ret < 0) {
mlwarning("tcp uv_read_start() failed: %s", uv_strerror(ret));
_output_dnssim_conn_close(conn);
return;
}
mldebug("tcp connected");
mlassert(conn->client, "conn must be associated with a client");
mlassert(conn->client->dnssim, "client must be associated with dnssim");
output_dnssim_t* self = conn->client->dnssim;
switch (_self->transport) {
case OUTPUT_DNSSIM_TRANSPORT_TCP:
_output_dnssim_conn_activate(conn);
break;
case OUTPUT_DNSSIM_TRANSPORT_TLS:
case OUTPUT_DNSSIM_TRANSPORT_HTTPS2:
#if GNUTLS_VERSION_NUMBER >= DNSSIM_MIN_GNUTLS_VERSION
mldebug("init tls handshake");
_output_dnssim_tls_process_input_data(conn); /* Initiate TLS handshake. */
#else
mlfatal(DNSSIM_MIN_GNUTLS_ERRORMSG);
#endif
break;
default:
lfatal("unsupported transport protocol");
break;
}
}
static void _on_connection_timeout(uv_timer_t* handle)
{
_output_dnssim_connection_t* conn = (_output_dnssim_connection_t*)handle->data;
_output_dnssim_conn_close(conn);
}
int _output_dnssim_tcp_connect(output_dnssim_t* self, _output_dnssim_connection_t* conn)
{
mlassert_self();
lassert(conn, "connection can't be null");
lassert(conn->handle == NULL, "connection already has a handle");
lassert(conn->handshake_timer == NULL, "connection already has a handshake timer");
lassert(conn->idle_timer == NULL, "connection already has idle timer");
lassert(conn->state == _OUTPUT_DNSSIM_CONN_INITIALIZED, "connection state != INITIALIZED");
lfatal_oom(conn->handle = malloc(sizeof(uv_tcp_t)));
conn->handle->data = (void*)conn;
int ret = uv_tcp_init(&_self->loop, conn->handle);
if (ret < 0) {
lwarning("failed to init uv_tcp_t");
goto failure;
}
ret = _output_dnssim_bind_before_connect(self, (uv_handle_t*)conn->handle);
if (ret < 0)
goto failure;
/* Set connection parameters. */
ret = uv_tcp_nodelay(conn->handle, 1);
if (ret < 0)
lwarning("tcp: failed to set TCP_NODELAY: %s", uv_strerror(ret));
/* Set connection handshake timeout. */
lfatal_oom(conn->handshake_timer = malloc(sizeof(uv_timer_t)));
uv_timer_init(&_self->loop, conn->handshake_timer);
conn->handshake_timer->data = (void*)conn;
uv_timer_start(conn->handshake_timer, _on_connection_timeout, self->handshake_timeout_ms, 0);
/* Set idle connection timer. */
if (self->idle_timeout_ms > 0) {
lfatal_oom(conn->idle_timer = malloc(sizeof(uv_timer_t)));
uv_timer_init(&_self->loop, conn->idle_timer);
conn->idle_timer->data = (void*)conn;
/* Start and stop the timer to set the repeat value without running the timer. */
uv_timer_start(conn->idle_timer, _on_connection_timeout, self->idle_timeout_ms, self->idle_timeout_ms);
uv_timer_stop(conn->idle_timer);
}
mldebug("tcp connecting");
uv_connect_t* conn_req;
lfatal_oom(conn_req = malloc(sizeof(uv_connect_t)));
ret = uv_tcp_connect(conn_req, conn->handle, (struct sockaddr*)&_self->target, _on_tcp_connected);
if (ret < 0)
goto failure;
conn->stats->conn_handshakes++;
conn->client->dnssim->stats_sum->conn_handshakes++;
conn->state = _OUTPUT_DNSSIM_CONN_TCP_HANDSHAKE;
return 0;
failure:
_output_dnssim_conn_close(conn);
return ret;
}
void _output_dnssim_tcp_close(_output_dnssim_connection_t* conn)
{
mlassert(conn, "conn can't be nil");
if (conn->handle != NULL) {
uv_read_stop((uv_stream_t*)conn->handle);
uv_close((uv_handle_t*)conn->handle, _on_tcp_closed);
}
}
int _output_dnssim_create_query_tcp(output_dnssim_t* self, _output_dnssim_request_t* req)
{
mlassert_self();
lassert(req, "req is nil");
lassert(req->client, "request must have a client associated with it");
_output_dnssim_query_tcp_t* qry;
lfatal_oom(qry = calloc(1, sizeof(_output_dnssim_query_tcp_t)));
qry->qry.transport = OUTPUT_DNSSIM_TRANSPORT_TCP;
qry->qry.req = req;
qry->qry.state = _OUTPUT_DNSSIM_QUERY_PENDING_WRITE;
req->qry = &qry->qry; // TODO change when adding support for multiple Qs for req
_ll_append(req->client->pending, &qry->qry);
return _output_dnssim_handle_pending_queries(req->client);
}
void _output_dnssim_close_query_tcp(_output_dnssim_query_tcp_t* qry)
{
mlassert(qry, "qry can't be null");
mlassert(qry->qry.req, "query must be part of a request");
_output_dnssim_request_t* req = qry->qry.req;
mlassert(req->client, "request must belong to a client");
if ((qry->qry.state == _OUTPUT_DNSSIM_QUERY_PENDING_WRITE_CB || qry->qry.state == _OUTPUT_DNSSIM_QUERY_PENDING_CLOSE)) {
/* Query can't be freed until uv callback is called. */
qry->qry.state = _OUTPUT_DNSSIM_QUERY_PENDING_CLOSE;
return;
}
_ll_try_remove(req->client->pending, &qry->qry);
if (qry->conn) {
_output_dnssim_connection_t* conn = qry->conn;
_ll_try_remove(conn->queued, &qry->qry); /* edge-case of cancelled queries */
_ll_try_remove(conn->sent, &qry->qry);
qry->conn = NULL;
_output_dnssim_conn_idle(conn);
}
_ll_remove(req->qry, &qry->qry);
free(qry);
}

View file

@ -1,475 +0,0 @@
/*
* Copyright (c) 2020, CZ.NIC, z.s.p.o.
* All rights reserved.
*
* This file is part of dnsjit.
*
* dnsjit is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dnsjit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "output/dnssim.h"
#include "output/dnssim/internal.h"
#include "output/dnssim/ll.h"
#include "core/assert.h"
#include <gnutls/gnutls.h>
#include <string.h>
#if GNUTLS_VERSION_NUMBER >= DNSSIM_MIN_GNUTLS_VERSION
#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b)) /** Minimum of two numbers **/
#endif
static core_log_t _log = LOG_T_INIT("output.dnssim");
struct async_write_ctx {
uv_write_t write_req;
_output_dnssim_connection_t* conn;
char buf[];
};
static int _tls_handshake(_output_dnssim_connection_t* conn)
{
mlassert(conn, "conn is nil");
mlassert(conn->tls, "conn must have tls context");
mlassert(conn->client, "conn must belong to a client");
mlassert(conn->state <= _OUTPUT_DNSSIM_CONN_TLS_HANDSHAKE, "conn in invalid state");
/* Set TLS session resumption ticket if available. */
if (conn->state < _OUTPUT_DNSSIM_CONN_TLS_HANDSHAKE && conn->client->tls_ticket.size != 0) {
gnutls_datum_t* ticket = &conn->client->tls_ticket;
gnutls_session_set_data(conn->tls->session, ticket->data, ticket->size);
}
conn->state = _OUTPUT_DNSSIM_CONN_TLS_HANDSHAKE;
return gnutls_handshake(conn->tls->session);
}
void _output_dnssim_tls_process_input_data(_output_dnssim_connection_t* conn)
{
mlassert(conn, "conn is nil");
mlassert(conn->client, "conn must have client");
mlassert(conn->client->dnssim, "client must have dnssim");
mlassert(conn->tls, "conn must have tls ctx");
if (conn->state >= _OUTPUT_DNSSIM_CONN_CLOSING)
return;
output_dnssim_t* self = conn->client->dnssim;
/* Ensure TLS handshake is performed before receiving data.
* See https://www.gnutls.org/manual/html_node/TLS-handshake.html */
while (conn->state <= _OUTPUT_DNSSIM_CONN_TLS_HANDSHAKE) {
int err = _tls_handshake(conn);
mldebug("tls handshake returned: %s", gnutls_strerror(err));
if (err == GNUTLS_E_SUCCESS) {
if (gnutls_session_is_resumed(conn->tls->session))
conn->stats->conn_resumed++;
if (_self->transport == OUTPUT_DNSSIM_TRANSPORT_HTTPS2) {
if (_output_dnssim_https2_setup(conn) < 0) {
_output_dnssim_conn_close(conn);
return;
}
}
_output_dnssim_conn_activate(conn);
break;
} else if (err == GNUTLS_E_AGAIN) {
return; /* Wait for more data */
} else if (err == GNUTLS_E_FATAL_ALERT_RECEIVED) {
gnutls_alert_description_t alert = gnutls_alert_get(conn->tls->session);
mlwarning("gnutls_handshake failed: %s", gnutls_alert_get_name(alert));
_output_dnssim_conn_close(conn);
return;
} else if (gnutls_error_is_fatal(err)) {
mlwarning("gnutls_handshake failed: %s", gnutls_strerror_name(err));
_output_dnssim_conn_close(conn);
return;
}
}
/* See https://gnutls.org/manual/html_node/Data-transfer-and-termination.html#Data-transfer-and-termination */
while (true) {
/* Connection might have been closed due to an error, don't try to use it. */
if (conn->state < _OUTPUT_DNSSIM_CONN_ACTIVE || conn->state >= _OUTPUT_DNSSIM_CONN_CLOSING)
return;
ssize_t count = gnutls_record_recv(conn->tls->session, _self->wire_buf, WIRE_BUF_SIZE);
if (count > 0) {
switch (_self->transport) {
case OUTPUT_DNSSIM_TRANSPORT_TLS:
_output_dnssim_read_dns_stream(conn, count, _self->wire_buf);
break;
case OUTPUT_DNSSIM_TRANSPORT_HTTPS2:
_output_dnssim_https2_process_input_data(conn, count, _self->wire_buf);
break;
default:
lfatal("unsupported transport layer");
break;
}
} else if (count == GNUTLS_E_AGAIN) {
if (conn->tls->buf_pos == conn->tls->buf_len) {
/* See https://www.gnutls.org/manual/html_node/Asynchronous-operation.html */
break; /* No more data available in this libuv buffer */
}
continue;
} else if (count == GNUTLS_E_INTERRUPTED) {
continue;
} else if (count == GNUTLS_E_REHANDSHAKE) {
continue; /* Ignore rehandshake request. */
} else if (count < 0) {
mlwarning("gnutls_record_recv failed: %s", gnutls_strerror_name(count));
_output_dnssim_conn_close(conn);
return;
} else if (count == 0) {
break;
}
}
mlassert(conn->tls->buf_len == conn->tls->buf_pos, "tls didn't read the entire buffer");
}
static ssize_t _tls_pull(gnutls_transport_ptr_t ptr, void* buf, size_t len)
{
_output_dnssim_connection_t* conn = (_output_dnssim_connection_t*)ptr;
mlassert(conn != NULL, "conn is null");
mlassert(conn->tls != NULL, "conn must have tls ctx");
ssize_t avail = conn->tls->buf_len - conn->tls->buf_pos;
if (avail <= 0) {
mldebug("tls pull: no more data");
errno = EAGAIN;
return -1;
}
ssize_t transfer = MIN(avail, len);
memcpy(buf, conn->tls->buf + conn->tls->buf_pos, transfer);
conn->tls->buf_pos += transfer;
return transfer;
}
static void _tls_on_write_complete(uv_write_t* req, int status)
{
mlassert(req->data != NULL, "uv_write req has no data pointer");
struct async_write_ctx* async_ctx = (struct async_write_ctx*)req->data;
_output_dnssim_connection_t* conn = async_ctx->conn;
mlassert(conn, "conn is nil");
mlassert(conn->tls, "conn must have tls ctx");
mlassert(conn->tls->write_queue_size > 0, "invalid write_queue_size: %d", conn->tls->write_queue_size);
conn->tls->write_queue_size -= 1;
free(req->data);
if (status < 0)
_output_dnssim_conn_close(conn);
}
static ssize_t _tls_vec_push(gnutls_transport_ptr_t ptr, const giovec_t* iov, int iovcnt)
{
_output_dnssim_connection_t* conn = (_output_dnssim_connection_t*)ptr;
mlassert(conn != NULL, "conn is null");
mlassert(conn->tls != NULL, "conn must have tls ctx");
if (iovcnt == 0)
return 0;
/*
* This is a little bit complicated. There are two different writes:
* 1. Immediate, these don't need to own the buffered data and return immediately
* 2. Asynchronous, these need to own the buffers until the write completes
* In order to avoid copying the buffer, an immediate write is tried first if possible.
* If it isn't possible to write the data without queueing, an asynchronous write
* is created (with copied buffered data).
*/
size_t total_len = 0;
uv_buf_t uv_buf[iovcnt];
int i;
for (i = 0; i < iovcnt; ++i) {
uv_buf[i].base = iov[i].iov_base;
uv_buf[i].len = iov[i].iov_len;
total_len += iov[i].iov_len;
}
/* Try to perform the immediate write first to avoid copy */
int ret = 0;
if (conn->tls->write_queue_size == 0) {
ret = uv_try_write((uv_stream_t*)conn->handle, uv_buf, iovcnt);
/* from libuv documentation -
uv_try_write will return either:
> 0: number of bytes written (can be less than the supplied buffer size).
< 0: negative error code (UV_EAGAIN is returned if no data can be sent immediately).
*/
if (ret == total_len) {
/* All the data were buffered by libuv.
* Return. */
return ret;
}
if (ret < 0 && ret != UV_EAGAIN) {
/* uv_try_write() has returned error code other then UV_EAGAIN.
* Return. */
errno = EIO;
return -1;
}
/* Since we are here expression below is true
* (ret != total_len) && (ret >= 0 || ret == UV_EAGAIN)
* or the same
* (ret != total_len && ret >= 0) || (ret != total_len && ret == UV_EAGAIN)
* i.e. either occurs partial write or UV_EAGAIN.
* Proceed and copy data amount to owned memory and perform async write.
*/
if (ret == UV_EAGAIN) {
/* No data were buffered, so we must buffer all the data. */
ret = 0;
}
}
/* Fallback when the queue is full, and it's not possible to do an immediate write */
char* p = malloc(sizeof(struct async_write_ctx) + total_len - ret);
if (p != NULL) {
struct async_write_ctx* async_ctx = (struct async_write_ctx*)p;
async_ctx->conn = conn;
char* buf = async_ctx->buf;
/* Skip data written in the partial write */
size_t to_skip = ret;
/* Copy the buffer into owned memory */
size_t off = 0;
int i;
for (i = 0; i < iovcnt; ++i) {
if (to_skip > 0) {
/* Ignore current buffer if it's all skipped */
if (to_skip >= uv_buf[i].len) {
to_skip -= uv_buf[i].len;
continue;
}
/* Skip only part of the buffer */
uv_buf[i].base += to_skip;
uv_buf[i].len -= to_skip;
to_skip = 0;
}
memcpy(buf + off, uv_buf[i].base, uv_buf[i].len);
off += uv_buf[i].len;
}
uv_buf[0].base = buf;
uv_buf[0].len = off;
/* Create an asynchronous write request */
uv_write_t* write_req = &async_ctx->write_req;
memset(write_req, 0, sizeof(uv_write_t));
write_req->data = p;
/* Perform an asynchronous write with a callback */
if (uv_write(write_req, (uv_stream_t*)conn->handle, uv_buf, 1, _tls_on_write_complete) == 0) {
ret = total_len;
conn->tls->write_queue_size += 1;
} else {
free(p);
errno = EIO;
ret = -1;
}
} else {
errno = ENOMEM;
ret = -1;
}
return ret;
}
int _tls_pull_timeout(gnutls_transport_ptr_t ptr, unsigned int ms)
{
_output_dnssim_connection_t* conn = (_output_dnssim_connection_t*)ptr;
mlassert(conn != NULL, "conn is null");
mlassert(conn->tls != NULL, "conn must have tls ctx");
ssize_t avail = conn->tls->buf_len - conn->tls->buf_pos;
if (avail <= 0) {
errno = EAGAIN;
return -1;
}
return avail;
}
int _output_dnssim_tls_init(_output_dnssim_connection_t* conn)
{
mlassert(conn, "conn is nil");
mlassert(conn->tls == NULL, "conn already has tls context");
int ret;
mlfatal_oom(conn->tls = malloc(sizeof(_output_dnssim_tls_ctx_t)));
conn->tls->buf = NULL;
conn->tls->buf_len = 0;
conn->tls->buf_pos = 0;
conn->tls->write_queue_size = 0;
ret = gnutls_init(&conn->tls->session, GNUTLS_CLIENT | GNUTLS_NONBLOCK);
if (ret < 0) {
mldebug("failed gnutls_init() (%s)", gnutls_strerror(ret));
free(conn->tls);
conn->tls = 0;
return ret;
}
output_dnssim_t* self = conn->client->dnssim;
if (_self->tls_priority == NULL) {
ret = gnutls_set_default_priority(conn->tls->session);
if (ret < 0) {
mldebug("failed gnutls_set_default_priority() (%s)", gnutls_strerror(ret));
gnutls_deinit(conn->tls->session);
free(conn->tls);
conn->tls = 0;
return ret;
}
} else {
ret = gnutls_priority_set(conn->tls->session, *_self->tls_priority);
if (ret < 0) {
mldebug("failed gnutls_priority_set() (%s)", gnutls_strerror(ret));
gnutls_deinit(conn->tls->session);
free(conn->tls);
conn->tls = 0;
return ret;
}
}
ret = gnutls_credentials_set(conn->tls->session, GNUTLS_CRD_CERTIFICATE, _self->tls_cred);
if (ret < 0) {
mldebug("failed gnutls_credentials_set() (%s)", gnutls_strerror(ret));
gnutls_deinit(conn->tls->session);
free(conn->tls);
conn->tls = 0;
return ret;
}
gnutls_transport_set_pull_function(conn->tls->session, _tls_pull);
gnutls_transport_set_pull_timeout_function(conn->tls->session, _tls_pull_timeout);
gnutls_transport_set_vec_push_function(conn->tls->session, _tls_vec_push);
gnutls_transport_set_ptr(conn->tls->session, conn);
return 0;
}
int _output_dnssim_create_query_tls(output_dnssim_t* self, _output_dnssim_request_t* req)
{
mlassert_self();
lassert(req, "req is nil");
lassert(req->client, "request must have a client associated with it");
_output_dnssim_query_tcp_t* qry;
lfatal_oom(qry = calloc(1, sizeof(_output_dnssim_query_tcp_t)));
qry->qry.transport = OUTPUT_DNSSIM_TRANSPORT_TLS;
qry->qry.req = req;
qry->qry.state = _OUTPUT_DNSSIM_QUERY_PENDING_WRITE;
req->qry = &qry->qry; // TODO change when adding support for multiple Qs for req
_ll_append(req->client->pending, &qry->qry);
return _output_dnssim_handle_pending_queries(req->client);
}
void _output_dnssim_close_query_tls(_output_dnssim_query_tcp_t* qry)
{
mlassert(qry, "qry can't be null");
mlassert(qry->qry.req, "query must be part of a request");
_output_dnssim_request_t* req = qry->qry.req;
mlassert(req->client, "request must belong to a client");
_ll_try_remove(req->client->pending, &qry->qry);
if (qry->conn) {
_output_dnssim_connection_t* conn = qry->conn;
_ll_try_remove(conn->sent, &qry->qry);
qry->conn = NULL;
_output_dnssim_conn_idle(conn);
}
_ll_remove(req->qry, &qry->qry);
free(qry);
}
void _output_dnssim_tls_close(_output_dnssim_connection_t* conn)
{
mlassert(conn, "conn can't be nil");
mlassert(conn->tls, "conn must have tls ctx");
mlassert(conn->client, "conn must belong to a client");
/* Try and get a TLS session ticket for potential resumption. */
int ret;
if (gnutls_session_get_flags(conn->tls->session) & GNUTLS_SFLAGS_SESSION_TICKET) {
if (conn->client->tls_ticket.size != 0) {
gnutls_free(conn->client->tls_ticket.data);
}
ret = gnutls_session_get_data2(conn->tls->session, &conn->client->tls_ticket);
if (ret < 0) {
mldebug("gnutls_session_get_data2 failed: %s", gnutls_strerror(ret));
conn->client->tls_ticket.size = 0;
}
}
gnutls_deinit(conn->tls->session);
_output_dnssim_tcp_close(conn);
}
void _output_dnssim_tls_write_query(_output_dnssim_connection_t* conn, _output_dnssim_query_tcp_t* qry)
{
mlassert(qry, "qry can't be null");
mlassert(qry->qry.state == _OUTPUT_DNSSIM_QUERY_PENDING_WRITE, "qry must be pending write");
mlassert(qry->qry.req, "req can't be null");
mlassert(qry->qry.req->dns_q, "dns_q can't be null");
mlassert(qry->qry.req->dns_q->obj_prev, "payload can't be null");
mlassert(conn, "conn can't be null");
mlassert(conn->state == _OUTPUT_DNSSIM_CONN_ACTIVE, "connection state != ACTIVE");
mlassert(conn->tls, "conn must have tls ctx");
mlassert(conn->client, "conn must be associated with client");
mlassert(conn->client->pending, "conn has no pending queries");
core_object_payload_t* payload = (core_object_payload_t*)qry->qry.req->dns_q->obj_prev;
uint16_t len = htons(payload->len);
gnutls_record_cork(conn->tls->session);
ssize_t count = 0;
if ((count = gnutls_record_send(conn->tls->session, &len, sizeof(len)) < 0) || (count = gnutls_record_send(conn->tls->session, payload->payload, payload->len) < 0)) {
mlwarning("gnutls_record_send failed: %s", gnutls_strerror_name(count));
_output_dnssim_conn_close(conn);
return;
}
const ssize_t submitted = sizeof(len) + payload->len;
int ret = gnutls_record_uncork(conn->tls->session, GNUTLS_RECORD_WAIT);
if (gnutls_error_is_fatal(ret)) {
mlinfo("gnutls_record_uncorck failed: %s", gnutls_strerror_name(ret));
_output_dnssim_conn_close(conn);
return;
}
if (ret != submitted) {
mlwarning("gnutls_record_uncork didn't send all data");
_output_dnssim_conn_close(conn);
return;
}
qry->conn = conn;
_ll_remove(conn->client->pending, &qry->qry);
_ll_append(conn->sent, &qry->qry);
/* Stop idle timer, since there are queries to answer now. */
if (conn->idle_timer != NULL) {
conn->is_idle = false;
uv_timer_stop(conn->idle_timer);
}
qry->qry.state = _OUTPUT_DNSSIM_QUERY_SENT;
}
#endif

View file

@ -1,156 +0,0 @@
/*
* Copyright (c) 2019-2020, CZ.NIC, z.s.p.o.
* All rights reserved.
*
* This file is part of dnsjit.
*
* dnsjit is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dnsjit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "output/dnssim.h"
#include "output/dnssim/internal.h"
#include "output/dnssim/ll.h"
#include "core/assert.h"
static core_log_t _log = LOG_T_INIT("output.dnssim");
static int _process_udp_response(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf)
{
_output_dnssim_query_udp_t* qry = (_output_dnssim_query_udp_t*)handle->data;
_output_dnssim_request_t* req;
core_object_payload_t payload = CORE_OBJECT_PAYLOAD_INIT(NULL);
core_object_dns_t dns_a = CORE_OBJECT_DNS_INIT(&payload);
mlassert(qry, "qry is nil");
mlassert(qry->qry.req, "query must be part of a request");
req = qry->qry.req;
payload.payload = (uint8_t*)buf->base;
payload.len = nread;
dns_a.obj_prev = (core_object_t*)&payload;
int ret = core_object_dns_parse_header(&dns_a);
if (ret != 0) {
mldebug("udp response malformed");
return _ERR_MALFORMED;
}
if (dns_a.id != req->dns_q->id) {
mldebug("udp response msgid mismatch %x(q) != %x(a)", req->dns_q->id, dns_a.id);
return _ERR_MSGID;
}
if (dns_a.tc == 1) {
mldebug("udp response has TC=1");
return _ERR_TC;
}
ret = _output_dnssim_answers_request(req, &dns_a);
if (ret != 0) {
mlwarning("udp reponse question mismatch");
return _ERR_QUESTION;
}
_output_dnssim_request_answered(req, &dns_a);
return 0;
}
static void _on_udp_query_recv(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags)
{
if (nread > 0) {
mldebug("udp recv: %d", nread);
// TODO handle TC=1
_process_udp_response(handle, nread, buf);
}
if (buf->base != NULL) {
free(buf->base);
}
}
static void _on_query_udp_closed(uv_handle_t* handle)
{
_output_dnssim_query_udp_t* qry = (_output_dnssim_query_udp_t*)handle->data;
_output_dnssim_request_t* req;
mlassert(qry, "qry is nil");
mlassert(qry->qry.req, "query must be part of a request");
req = qry->qry.req;
free(qry->handle);
_ll_remove(req->qry, &qry->qry);
free(qry);
if (req->qry == NULL)
_output_dnssim_maybe_free_request(req);
}
void _output_dnssim_close_query_udp(_output_dnssim_query_udp_t* qry)
{
int ret;
mlassert(qry, "qry is nil");
ret = uv_udp_recv_stop(qry->handle);
if (ret < 0) {
mldebug("failed uv_udp_recv_stop(): %s", uv_strerror(ret));
}
uv_close((uv_handle_t*)qry->handle, _on_query_udp_closed);
}
int _output_dnssim_create_query_udp(output_dnssim_t* self, _output_dnssim_request_t* req)
{
int ret;
_output_dnssim_query_udp_t* qry;
core_object_payload_t* payload;
mlassert_self();
lassert(req, "req is nil");
payload = (core_object_payload_t*)req->dns_q->obj_prev;
lfatal_oom(qry = calloc(1, sizeof(_output_dnssim_query_udp_t)));
lfatal_oom(qry->handle = malloc(sizeof(uv_udp_t)));
qry->qry.transport = OUTPUT_DNSSIM_TRANSPORT_UDP;
qry->qry.req = req;
qry->buf = uv_buf_init((char*)payload->payload, payload->len);
qry->handle->data = (void*)qry;
ret = uv_udp_init(&_self->loop, qry->handle);
if (ret < 0) {
lwarning("failed to init uv_udp_t");
goto failure;
}
_ll_append(req->qry, &qry->qry);
ret = _output_dnssim_bind_before_connect(self, (uv_handle_t*)qry->handle);
if (ret < 0)
return ret;
ret = uv_udp_try_send(qry->handle, &qry->buf, 1, (struct sockaddr*)&_self->target);
if (ret < 0) {
lwarning("failed to send udp packet: %s", uv_strerror(ret));
return ret;
}
// listen for reply
ret = uv_udp_recv_start(qry->handle, _output_dnssim_on_uv_alloc, _on_udp_query_recv);
if (ret < 0) {
lwarning("failed uv_udp_recv_start(): %s", uv_strerror(ret));
return ret;
}
return 0;
failure:
free(qry->handle);
free(qry);
return ret;
}

View file

@ -1,87 +0,0 @@
/*
* Copyright (c) 2018-2021, OARC, Inc.
* All rights reserved.
*
* This file is part of dnsjit.
*
* dnsjit is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dnsjit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "output/null.h"
#include "core/assert.h"
#include "core/object/pcap.h"
static core_log_t _log = LOG_T_INIT("output.null");
static output_null_t _defaults = {
LOG_T_INIT_OBJ("output.null"),
0, 0, 0
};
core_log_t* output_null_log()
{
return &_log;
}
void output_null_init(output_null_t* self)
{
mlassert_self();
*self = _defaults;
}
void output_null_destroy(output_null_t* self)
{
mlassert_self();
}
static void _receive(output_null_t* self, const core_object_t* obj)
{
mlassert_self();
self->pkts++;
}
core_receiver_t output_null_receiver()
{
return (core_receiver_t)_receive;
}
void output_null_run(output_null_t* self, int64_t num)
{
mlassert_self();
if (!self->prod) {
lfatal("no producer set");
}
if (num > 0) {
while (num--) {
const core_object_t* obj = self->prod(self->ctx);
if (!obj)
break;
self->pkts++;
}
} else {
for (;;) {
const core_object_t* obj = self->prod(self->ctx);
if (!obj)
break;
self->pkts++;
}
}
}

View file

@ -1,37 +0,0 @@
/*
* Copyright (c) 2018-2021, OARC, Inc.
* All rights reserved.
*
* This file is part of dnsjit.
*
* dnsjit is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* dnsjit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
//lua:require("dnsjit.core.log")
//lua:require("dnsjit.core.receiver_h")
//lua:require("dnsjit.core.producer_h")
typedef struct output_null {
core_log_t _log;
core_producer_t prod;
void* ctx;
size_t pkts;
} output_null_t;
core_log_t* output_null_log();
void output_null_init(output_null_t* self);
void output_null_destroy(output_null_t* self);
void output_null_run(output_null_t* self, int64_t num);
core_receiver_t output_null_receiver();

View file

@ -17,64 +17,15 @@
-- along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
-- dnsjit.output.null
-- Output to nothing (/dev/null)
-- local output = require("dnsjit.output.null").new()
-- Dummy layer to example.output.null
--
-- Output module for those that doesn't really like packets.
-- This module has moved to example.output.null, see examples/modules/output-example in
-- dnsjit source repository.
module(...,package.seeall)
require("dnsjit.output.null_h")
local ffi = require("ffi")
local C = ffi.C
local t_name = "output_null_t"
local output_null_t = ffi.typeof(t_name)
local Null = {}
-- Create a new Null output.
function Null.new()
local self = {
_producer = nil,
obj = output_null_t(),
}
C.output_null_init(self.obj)
ffi.gc(self.obj, C.output_null_destroy)
return setmetatable(self, { __index = Null })
ok, cls = pcall(require, "example.output.null")
if not ok then
error("You need to install the example module output-example\n" .. cls)
end
-- Return the Log object to control logging of this instance or module.
function Null:log()
if self == nil then
return C.output_null_log()
end
return self.obj._log
end
-- Return the C functions and context for receiving objects.
function Null:receive()
return C.output_null_receiver(), self.obj
end
-- Set the producer to get objects from.
function Null:producer(o)
self.obj.prod, self.obj.ctx = o:produce()
self._producer = o
end
-- Retrieve all objects from the producer, if the optional
-- .I num
-- is a positive number then stop after that amount of objects have been
-- retrieved.
function Null:run(num)
if num == nil then
num = -1
end
C.output_null_run(self.obj, num)
end
-- Return the number of packets we sent into the void.
function Null:packets()
return tonumber(self.obj.pkts)
end
return Null
return cls

View file

@ -82,6 +82,15 @@ void output_pcap_close(output_pcap_t* self)
}
}
int output_pcap_have_errors(output_pcap_t* self)
{
mlassert_self();
if (self->dumper) {
return ferror(pcap_dump_file(self->dumper));
}
return 0;
}
static void _receive(output_pcap_t* self, const core_object_t* obj)
{
struct pcap_pkthdr hdr;

View file

@ -18,15 +18,15 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/log.h"
#include "core/receiver.h"
#include "core/producer.h"
#include <dnsjit/core/log.h>
#include <dnsjit/core/receiver.h>
#include <dnsjit/core/producer.h>
#ifndef __dnsjit_output_pcap_h
#define __dnsjit_output_pcap_h
#include <pcap/pcap.h>
#include "output/pcap.hh"
#include <dnsjit/output/pcap.hh>
#endif

View file

@ -37,5 +37,6 @@ void output_pcap_init(output_pcap_t* self);
void output_pcap_destroy(output_pcap_t* self);
int output_pcap_open(output_pcap_t* self, const char* file, int linktype, int snaplen);
void output_pcap_close(output_pcap_t* self);
int output_pcap_have_errors(output_pcap_t* self);
core_receiver_t output_pcap_receiver(output_pcap_t* self);

View file

@ -60,6 +60,10 @@ end
-- .I linktype
-- and
-- .IR snaplen .
-- Uses
-- .B pcap_dump_open()
-- so you can pass "-" to it to open stdout, see it's man-page for more
-- information.
-- Returns 0 on success.
function Pcap:open(file, linktype, snaplen)
return C.output_pcap_open(self.obj, file, linktype, snaplen)
@ -70,6 +74,16 @@ function Pcap:close()
C.output_pcap_close(self.obj)
end
-- Return true if the underlying
-- .I FILE*
-- indicates that there's been an error.
function Pcap:have_errors()
if C.output_pcap_have_errors(self.obj) == 0 then
return false
end
return true
end
-- Return the C functions and context for receiving objects.
function Pcap:receive()
return C.output_pcap_receiver(self.obj), self.obj

View file

@ -18,14 +18,14 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/log.h"
#include "core/receiver.h"
#include <dnsjit/core/log.h>
#include <dnsjit/core/receiver.h>
#ifndef __dnsjit_output_respdiff_h
#define __dnsjit_output_respdiff_h
#include <stdint.h>
#include "output/respdiff.hh"
#include <dnsjit/output/respdiff.hh>
#endif

View file

@ -18,15 +18,15 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/log.h"
#include "core/receiver.h"
#include "core/producer.h"
#include "core/object/payload.h"
#include "core/timespec.h"
#include <dnsjit/core/log.h>
#include <dnsjit/core/receiver.h>
#include <dnsjit/core/producer.h>
#include <dnsjit/core/object/payload.h>
#include <dnsjit/core/timespec.h>
#ifndef __dnsjit_output_tcpcli_h
#define __dnsjit_output_tcpcli_h
#include "output/tcpcli.hh"
#include <dnsjit/output/tcpcli.hh>
#endif

View file

@ -18,17 +18,17 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/log.h"
#include "core/receiver.h"
#include "core/producer.h"
#include "core/object/payload.h"
#include "core/timespec.h"
#include <dnsjit/core/log.h>
#include <dnsjit/core/receiver.h>
#include <dnsjit/core/producer.h>
#include <dnsjit/core/object/payload.h>
#include <dnsjit/core/timespec.h>
#ifndef __dnsjit_output_tlscli_h
#define __dnsjit_output_tlscli_h
#include <gnutls/gnutls.h>
#include "output/tlscli.hh"
#include <dnsjit/output/tlscli.hh>
#endif

View file

@ -18,11 +18,11 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/log.h"
#include "core/receiver.h"
#include "core/producer.h"
#include "core/object/payload.h"
#include "core/timespec.h"
#include <dnsjit/core/log.h>
#include <dnsjit/core/receiver.h>
#include <dnsjit/core/producer.h>
#include <dnsjit/core/object/payload.h>
#include <dnsjit/core/timespec.h>
#ifndef __dnsjit_output_udpcli_h
#define __dnsjit_output_udpcli_h
@ -30,6 +30,6 @@
#include <sys/types.h>
#include <sys/socket.h>
#include "output/udpcli.hh"
#include <dnsjit/output/udpcli.hh>
#endif

View file

@ -18,12 +18,12 @@
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
CLEANFILES = test*.log test*.trs test*.out \
*.pcap-dist
*.pcap-dist *.lz4-dist *.zst-dist
TESTS = test1.sh test2.sh test3.sh test4.sh test5.sh test6.sh test-ipsplit.sh \
TESTS = test1.sh test2.sh test3.sh test4.sh test6.sh test-ipsplit.sh \
test-trie.sh test-base64url.sh
test1.sh: dns.pcap-dist
test1.sh: dns.pcap-dist dns.pcap.lz4-dist dns.pcap.zst-dist
test2.sh: dns.pcap-dist
@ -31,8 +31,6 @@ test3.sh: dns.pcap-dist
test4.sh: dns.pcap-dist
test5.sh: dns.pcap-dist
test6.sh: dns.pcap-dist
test-ipsplit.sh: pellets.pcap-dist dns.pcap-dist
@ -42,6 +40,13 @@ test-trie.sh: pellets.pcap-dist dns.pcap-dist
.pcap.pcap-dist:
cp "$<" "$@"
.lz4.lz4-dist:
cp "$<" "$@"
.zst.zst-dist:
cp "$<" "$@"
EXTRA_DIST = $(TESTS) \
dns.pcap pellets.pcap test_ipsplit.lua test_trie.lua test_base64url.lua \
test1.gold test2.gold test3.gold test4.gold
test1.gold test2.gold test3.gold test4.gold test_compressupport.lua \
dns.pcap.lz4 dns.pcap.zst

947
src/test/Makefile.in Normal file
View file

@ -0,0 +1,947 @@
# Makefile.in generated by automake 1.16.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2018 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
# Copyright (c) 2018-2021, OARC, Inc.
# All rights reserved.
#
# This file is part of dnsjit.
#
# dnsjit is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# dnsjit is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
subdir = src/test
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cflags_warn_all.m4 \
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
$(top_srcdir)/m4/ax_compiler_vendor.m4 \
$(top_srcdir)/m4/ax_ext.m4 \
$(top_srcdir)/m4/ax_gcc_x86_avx_xgetbv.m4 \
$(top_srcdir)/m4/ax_gcc_x86_cpuid.m4 \
$(top_srcdir)/m4/ax_prepend_flag.m4 \
$(top_srcdir)/m4/ax_pthread.m4 \
$(top_srcdir)/m4/ax_require_defined.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/src/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
SOURCES =
DIST_SOURCES =
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
am__extra_recursive_targets = gcov-recursive
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
am__tty_colors_dummy = \
mgn= red= grn= lgn= blu= brg= std=; \
am__color_tests=no
am__tty_colors = { \
$(am__tty_colors_dummy); \
if test "X$(AM_COLOR_TESTS)" = Xno; then \
am__color_tests=no; \
elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
am__color_tests=yes; \
elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
am__color_tests=yes; \
fi; \
if test $$am__color_tests = yes; then \
red=''; \
grn=''; \
lgn=''; \
blu=''; \
mgn=''; \
brg=''; \
std=''; \
fi; \
}
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
am__install_max = 40
am__nobase_strip_setup = \
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
am__nobase_strip = \
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
am__nobase_list = $(am__nobase_strip_setup); \
for p in $$list; do echo "$$p $$p"; done | \
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
if (++n[$$2] == $(am__install_max)) \
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
END { for (dir in files) print dir, files[dir] }'
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__uninstall_files_from_dir = { \
test -z "$$files" \
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
am__recheck_rx = ^[ ]*:recheck:[ ]*
am__global_test_result_rx = ^[ ]*:global-test-result:[ ]*
am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]*
# A command that, given a newline-separated list of test names on the
# standard input, print the name of the tests that are to be re-run
# upon "make recheck".
am__list_recheck_tests = $(AWK) '{ \
recheck = 1; \
while ((rc = (getline line < ($$0 ".trs"))) != 0) \
{ \
if (rc < 0) \
{ \
if ((getline line2 < ($$0 ".log")) < 0) \
recheck = 0; \
break; \
} \
else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
{ \
recheck = 0; \
break; \
} \
else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
{ \
break; \
} \
}; \
if (recheck) \
print $$0; \
close ($$0 ".trs"); \
close ($$0 ".log"); \
}'
# A command that, given a newline-separated list of test names on the
# standard input, create the global log from their .trs and .log files.
am__create_global_log = $(AWK) ' \
function fatal(msg) \
{ \
print "fatal: making $@: " msg | "cat >&2"; \
exit 1; \
} \
function rst_section(header) \
{ \
print header; \
len = length(header); \
for (i = 1; i <= len; i = i + 1) \
printf "="; \
printf "\n\n"; \
} \
{ \
copy_in_global_log = 1; \
global_test_result = "RUN"; \
while ((rc = (getline line < ($$0 ".trs"))) != 0) \
{ \
if (rc < 0) \
fatal("failed to read from " $$0 ".trs"); \
if (line ~ /$(am__global_test_result_rx)/) \
{ \
sub("$(am__global_test_result_rx)", "", line); \
sub("[ ]*$$", "", line); \
global_test_result = line; \
} \
else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
copy_in_global_log = 0; \
}; \
if (copy_in_global_log) \
{ \
rst_section(global_test_result ": " $$0); \
while ((rc = (getline line < ($$0 ".log"))) != 0) \
{ \
if (rc < 0) \
fatal("failed to read from " $$0 ".log"); \
print line; \
}; \
printf "\n"; \
}; \
close ($$0 ".trs"); \
close ($$0 ".log"); \
}'
# Restructured Text title.
am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
# Solaris 10 'make', and several other traditional 'make' implementations,
# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it
# by disabling -e (using the XSI extension "set +e") if it's set.
am__sh_e_setup = case $$- in *e*) set +e;; esac
# Default flags passed to test drivers.
am__common_driver_flags = \
--color-tests "$$am__color_tests" \
--enable-hard-errors "$$am__enable_hard_errors" \
--expect-failure "$$am__expect_failure"
# To be inserted before the command running the test. Creates the
# directory for the log if needed. Stores in $dir the directory
# containing $f, in $tst the test, in $log the log. Executes the
# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
# passes TESTS_ENVIRONMENT. Set up options for the wrapper that
# will run the test scripts (or their associated LOG_COMPILER, if
# thy have one).
am__check_pre = \
$(am__sh_e_setup); \
$(am__vpath_adj_setup) $(am__vpath_adj) \
$(am__tty_colors); \
srcdir=$(srcdir); export srcdir; \
case "$@" in \
*/*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \
*) am__odir=.;; \
esac; \
test "x$$am__odir" = x"." || test -d "$$am__odir" \
|| $(MKDIR_P) "$$am__odir" || exit $$?; \
if test -f "./$$f"; then dir=./; \
elif test -f "$$f"; then dir=; \
else dir="$(srcdir)/"; fi; \
tst=$$dir$$f; log='$@'; \
if test -n '$(DISABLE_HARD_ERRORS)'; then \
am__enable_hard_errors=no; \
else \
am__enable_hard_errors=yes; \
fi; \
case " $(XFAIL_TESTS) " in \
*[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \
am__expect_failure=yes;; \
*) \
am__expect_failure=no;; \
esac; \
$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
# A shell command to get the names of the tests scripts with any registered
# extension removed (i.e., equivalently, the names of the test logs, with
# the '.log' extension removed). The result is saved in the shell variable
# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly,
# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
# since that might cause problem with VPATH rewrites for suffix-less tests.
# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
am__set_TESTS_bases = \
bases='$(TEST_LOGS)'; \
bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
bases=`echo $$bases`
RECHECK_LOGS = $(TEST_LOGS)
AM_RECURSIVE_TARGETS = check recheck
TEST_SUITE_LOG = test-suite.log
TEST_EXTENSIONS = @EXEEXT@ .test
LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
am__set_b = \
case '$@' in \
*/*) \
case '$*' in \
*/*) b='$*';; \
*) b=`echo '$@' | sed 's/\.log$$//'`; \
esac;; \
*) \
b='$*';; \
esac
am__test_logs1 = $(TESTS:=.log)
am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
TEST_LOGS = $(am__test_logs2:.test.log=.log)
TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
$(TEST_LOG_FLAGS)
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/test-driver
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CPUEXT_FLAGS = @CPUEXT_FLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
LUAJIT = @LUAJIT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
PTHREAD_CC = @PTHREAD_CC@
PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
PTHREAD_LIBS = @PTHREAD_LIBS@
RANLIB = @RANLIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SIMD_FLAGS = @SIMD_FLAGS@
STRIP = @STRIP@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
ax_pthread_config = @ax_pthread_config@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
ck_CFLAGS = @ck_CFLAGS@
ck_LIBS = @ck_LIBS@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
liblz4_CFLAGS = @liblz4_CFLAGS@
liblz4_LIBS = @liblz4_LIBS@
libzstd_CFLAGS = @libzstd_CFLAGS@
libzstd_LIBS = @libzstd_LIBS@
localedir = @localedir@
localstatedir = @localstatedir@
luajit_CFLAGS = @luajit_CFLAGS@
luajit_LIBS = @luajit_LIBS@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
CLEANFILES = test*.log test*.trs test*.out \
*.pcap-dist *.lz4-dist *.zst-dist
TESTS = test1.sh test2.sh test3.sh test4.sh test6.sh test-ipsplit.sh \
test-trie.sh test-base64url.sh
EXTRA_DIST = $(TESTS) \
dns.pcap pellets.pcap test_ipsplit.lua test_trie.lua test_base64url.lua \
test1.gold test2.gold test3.gold test4.gold test_compressupport.lua \
dns.pcap.lz4 dns.pcap.zst
all: all-am
.SUFFIXES:
.SUFFIXES: .log .lz4 .lz4-dist .pcap .pcap-dist .test .test$(EXEEXT) .trs .zst .zst-dist
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/test/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign src/test/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
gcov-local:
tags TAGS:
ctags CTAGS:
cscope cscopelist:
# Recover from deleted '.trs' file; this should ensure that
# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells
# to avoid problems with "make -n".
.log.trs:
rm -f $< $@
$(MAKE) $(AM_MAKEFLAGS) $<
# Leading 'am--fnord' is there to ensure the list of targets does not
# expand to empty, as could happen e.g. with make check TESTS=''.
am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
am--force-recheck:
@:
$(TEST_SUITE_LOG): $(TEST_LOGS)
@$(am__set_TESTS_bases); \
am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
redo_bases=`for i in $$bases; do \
am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
done`; \
if test -n "$$redo_bases"; then \
redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
if $(am__make_dryrun); then :; else \
rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
fi; \
fi; \
if test -n "$$am__remaking_logs"; then \
echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
"recursion detected" >&2; \
elif test -n "$$redo_logs"; then \
am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
fi; \
if $(am__make_dryrun); then :; else \
st=0; \
errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
for i in $$redo_bases; do \
test -f $$i.trs && test -r $$i.trs \
|| { echo "$$errmsg $$i.trs" >&2; st=1; }; \
test -f $$i.log && test -r $$i.log \
|| { echo "$$errmsg $$i.log" >&2; st=1; }; \
done; \
test $$st -eq 0 || exit 1; \
fi
@$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
ws='[ ]'; \
results=`for b in $$bases; do echo $$b.trs; done`; \
test -n "$$results" || results=/dev/null; \
all=` grep "^$$ws*:test-result:" $$results | wc -l`; \
pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \
fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \
skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \
xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
if test `expr $$fail + $$xpass + $$error` -eq 0; then \
success=true; \
else \
success=false; \
fi; \
br='==================='; br=$$br$$br$$br$$br; \
result_count () \
{ \
if test x"$$1" = x"--maybe-color"; then \
maybe_colorize=yes; \
elif test x"$$1" = x"--no-color"; then \
maybe_colorize=no; \
else \
echo "$@: invalid 'result_count' usage" >&2; exit 4; \
fi; \
shift; \
desc=$$1 count=$$2; \
if test $$maybe_colorize = yes && test $$count -gt 0; then \
color_start=$$3 color_end=$$std; \
else \
color_start= color_end=; \
fi; \
echo "$${color_start}# $$desc $$count$${color_end}"; \
}; \
create_testsuite_report () \
{ \
result_count $$1 "TOTAL:" $$all "$$brg"; \
result_count $$1 "PASS: " $$pass "$$grn"; \
result_count $$1 "SKIP: " $$skip "$$blu"; \
result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
result_count $$1 "FAIL: " $$fail "$$red"; \
result_count $$1 "XPASS:" $$xpass "$$red"; \
result_count $$1 "ERROR:" $$error "$$mgn"; \
}; \
{ \
echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
$(am__rst_title); \
create_testsuite_report --no-color; \
echo; \
echo ".. contents:: :depth: 2"; \
echo; \
for b in $$bases; do echo $$b; done \
| $(am__create_global_log); \
} >$(TEST_SUITE_LOG).tmp || exit 1; \
mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \
if $$success; then \
col="$$grn"; \
else \
col="$$red"; \
test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
fi; \
echo "$${col}$$br$${std}"; \
echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \
echo "$${col}$$br$${std}"; \
create_testsuite_report --maybe-color; \
echo "$$col$$br$$std"; \
if $$success; then :; else \
echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \
if test -n "$(PACKAGE_BUGREPORT)"; then \
echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \
fi; \
echo "$$col$$br$$std"; \
fi; \
$$success || exit 1
check-TESTS:
@list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
@list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
@set +e; $(am__set_TESTS_bases); \
log_list=`for i in $$bases; do echo $$i.log; done`; \
trs_list=`for i in $$bases; do echo $$i.trs; done`; \
log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
exit $$?;
recheck: all
@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
@set +e; $(am__set_TESTS_bases); \
bases=`for i in $$bases; do echo $$i; done \
| $(am__list_recheck_tests)` || exit 1; \
log_list=`for i in $$bases; do echo $$i.log; done`; \
log_list=`echo $$log_list`; \
$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
am__force_recheck=am--force-recheck \
TEST_LOGS="$$log_list"; \
exit $$?
test1.sh.log: test1.sh
@p='test1.sh'; \
b='test1.sh'; \
$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
--log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
"$$tst" $(AM_TESTS_FD_REDIRECT)
test2.sh.log: test2.sh
@p='test2.sh'; \
b='test2.sh'; \
$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
--log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
"$$tst" $(AM_TESTS_FD_REDIRECT)
test3.sh.log: test3.sh
@p='test3.sh'; \
b='test3.sh'; \
$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
--log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
"$$tst" $(AM_TESTS_FD_REDIRECT)
test4.sh.log: test4.sh
@p='test4.sh'; \
b='test4.sh'; \
$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
--log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
"$$tst" $(AM_TESTS_FD_REDIRECT)
test6.sh.log: test6.sh
@p='test6.sh'; \
b='test6.sh'; \
$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
--log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
"$$tst" $(AM_TESTS_FD_REDIRECT)
test-ipsplit.sh.log: test-ipsplit.sh
@p='test-ipsplit.sh'; \
b='test-ipsplit.sh'; \
$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
--log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
"$$tst" $(AM_TESTS_FD_REDIRECT)
test-trie.sh.log: test-trie.sh
@p='test-trie.sh'; \
b='test-trie.sh'; \
$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
--log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
"$$tst" $(AM_TESTS_FD_REDIRECT)
test-base64url.sh.log: test-base64url.sh
@p='test-base64url.sh'; \
b='test-base64url.sh'; \
$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
--log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
"$$tst" $(AM_TESTS_FD_REDIRECT)
.test.log:
@p='$<'; \
$(am__set_b); \
$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
--log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
"$$tst" $(AM_TESTS_FD_REDIRECT)
@am__EXEEXT_TRUE@.test$(EXEEXT).log:
@am__EXEEXT_TRUE@ @p='$<'; \
@am__EXEEXT_TRUE@ $(am__set_b); \
@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
distdir-am: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
$(MAKE) $(AM_MAKEFLAGS) check-TESTS
check: check-am
all-am: Makefile
installdirs:
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
-test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
-test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
-test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
clean-generic:
-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
clean: clean-am
clean-am: clean-generic clean-libtool mostlyclean-am
distclean: distclean-am
-rm -f Makefile
distclean-am: clean-am distclean-generic
dvi: dvi-am
dvi-am:
gcov: gcov-am
gcov-am: gcov-local
html: html-am
html-am:
info: info-am
info-am:
install-data-am:
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am:
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-generic mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am:
.MAKE: check-am install-am install-strip
.PHONY: all all-am check check-TESTS check-am clean clean-generic \
clean-libtool cscopelist-am ctags-am distclean \
distclean-generic distclean-libtool distdir dvi dvi-am gcov-am \
gcov-local html html-am info info-am install install-am \
install-data install-data-am install-dvi install-dvi-am \
install-exec install-exec-am install-html install-html-am \
install-info install-info-am install-man install-pdf \
install-pdf-am install-ps install-ps-am install-strip \
installcheck installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-generic \
mostlyclean-libtool pdf pdf-am ps ps-am recheck tags-am \
uninstall uninstall-am
.PRECIOUS: Makefile
test1.sh: dns.pcap-dist dns.pcap.lz4-dist dns.pcap.zst-dist
test2.sh: dns.pcap-dist
test3.sh: dns.pcap-dist
test4.sh: dns.pcap-dist
test6.sh: dns.pcap-dist
test-ipsplit.sh: pellets.pcap-dist dns.pcap-dist
test-trie.sh: pellets.pcap-dist dns.pcap-dist
.pcap.pcap-dist:
cp "$<" "$@"
.lz4.lz4-dist:
cp "$<" "$@"
.zst.zst-dist:
cp "$<" "$@"
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

BIN
src/test/dns.pcap.lz4 Normal file

Binary file not shown.

BIN
src/test/dns.pcap.zst Normal file

Binary file not shown.

View file

@ -19,3 +19,13 @@
../dnsjit "$srcdir/../../examples/dumpdns.lua" dns.pcap-dist >test1.out
diff "$srcdir/test1.gold" test1.out
support=`../dnsjit "$srcdir/test_compressupport.lua"`
if echo "$support"|grep -q lz4; then
../dnsjit "$srcdir/../../examples/dumpdns.lua" dns.pcap.lz4-dist lz4 >test1.out
diff "$srcdir/test1.gold" test1.out
fi
if echo "$support"|grep -q zstd; then
../dnsjit "$srcdir/../../examples/dumpdns.lua" dns.pcap.zst-dist zstd >test1.out
diff "$srcdir/test1.gold" test1.out
fi

View file

@ -1,24 +0,0 @@
#!/bin/sh -e
# Copyright (c) 2018-2021, OARC, Inc.
# All rights reserved.
#
# This file is part of dnsjit.
#
# dnsjit is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# dnsjit is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
../dnsjit "$srcdir/../../examples/test_throughput.lua" -vvvvv -t -s 1000000
../dnsjit "$srcdir/../../examples/test_pcap_read.lua" -vvvvv dns.pcap-dist
../dnsjit "$srcdir/../../examples/test_pcap_read.lua" -l -vvvvv dns.pcap-dist
../dnsjit "$srcdir/../../examples/test_pcap_read.lua" -p -vvvvv dns.pcap-dist
../dnsjit "$srcdir/../../examples/test_pcap_read.lua" -l -p -vvvvv dns.pcap-dist

View file

@ -0,0 +1,10 @@
local zpcap = require("dnsjit.input.zpcap").new()
zpcap:lz4()
if zpcap:have_support() then
print("lz4")
end
zpcap:zstd()
if zpcap:have_support() then
print("zstd")
end

View file

@ -18,16 +18,11 @@
* along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
*/
#include "core/log.h"
#include "core/receiver.h"
#include "core/producer.h"
#ifndef __dnsjit_version_h
#define __dnsjit_version_h
#ifndef __dnsjit_output_null_h
#define __dnsjit_output_null_h
#include <stddef.h>
#include <stdint.h>
#include "output/null.hh"
#define DNSJIT_MAJOR_VERSION 1
#define DNSJIT_MINOR_VERSION 2
#define DNSJIT_PATCH_VERSION 1
#endif