diff options
Diffstat (limited to 'include')
217 files changed, 25974 insertions, 0 deletions
diff --git a/include/dnsjit/Makefile.am b/include/dnsjit/Makefile.am new file mode 100644 index 0000000..3090342 --- /dev/null +++ b/include/dnsjit/Makefile.am @@ -0,0 +1,287 @@ +# 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) \ + -I$(top_srcdir)/include \ + $(SIMD_FLAGS) $(CPUEXT_FLAGS) \ + $(PTHREAD_CFLAGS) \ + $(luajit_CFLAGS) \ + $(liblz4_CFLAGS) $(libzstd_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 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) $(liblz4_LIBS) $(libzstd_LIBS) + +# C source and headers +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 +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/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) +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 +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: + @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" > "$@" + + +dnsjit.core.3in: core.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core.lua" > "$@" + +dnsjit.lib.3in: lib.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/lib.lua" > "$@" + +dnsjit.input.3in: input.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/input.lua" > "$@" + +dnsjit.filter.3in: filter.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/filter.lua" > "$@" + +dnsjit.output.3in: output.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/output.lua" > "$@" + +dnsjit.core.channel.3in: core/channel.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/channel.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" > "$@" + +dnsjit.core.object.dns.label.3in: core/object/dns/label.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/dns/label.lua" > "$@" + +dnsjit.core.object.dns.3in: core/object/dns.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/dns.lua" > "$@" + +dnsjit.core.object.dns.q.3in: core/object/dns/q.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/dns/q.lua" > "$@" + +dnsjit.core.object.dns.rr.3in: core/object/dns/rr.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/dns/rr.lua" > "$@" + +dnsjit.core.object.ether.3in: core/object/ether.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/ether.lua" > "$@" + +dnsjit.core.object.gre.3in: core/object/gre.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/gre.lua" > "$@" + +dnsjit.core.object.icmp6.3in: core/object/icmp6.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/icmp6.lua" > "$@" + +dnsjit.core.object.icmp.3in: core/object/icmp.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/icmp.lua" > "$@" + +dnsjit.core.object.ieee802.3in: core/object/ieee802.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/ieee802.lua" > "$@" + +dnsjit.core.object.ip6.3in: core/object/ip6.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/ip6.lua" > "$@" + +dnsjit.core.object.ip.3in: core/object/ip.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/ip.lua" > "$@" + +dnsjit.core.object.linuxsll.3in: core/object/linuxsll.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/linuxsll.lua" > "$@" + +dnsjit.core.object.loop.3in: core/object/loop.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/loop.lua" > "$@" + +dnsjit.core.object.3in: core/object.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object.lua" > "$@" + +dnsjit.core.object.null.3in: core/object/null.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/null.lua" > "$@" + +dnsjit.core.object.payload.3in: core/object/payload.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/payload.lua" > "$@" + +dnsjit.core.object.pcap.3in: core/object/pcap.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/pcap.lua" > "$@" + +dnsjit.core.objects.3in: core/objects.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/objects.lua" > "$@" + +dnsjit.core.object.tcp.3in: core/object/tcp.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/tcp.lua" > "$@" + +dnsjit.core.object.udp.3in: core/object/udp.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/udp.lua" > "$@" + +dnsjit.core.producer.3in: core/producer.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/producer.lua" > "$@" + +dnsjit.core.receiver.3in: core/receiver.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/receiver.lua" > "$@" + +dnsjit.core.thread.3in: core/thread.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/thread.lua" > "$@" + +dnsjit.core.timespec.3in: core/timespec.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/timespec.lua" > "$@" + +dnsjit.filter.copy.3in: filter/copy.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/filter/copy.lua" > "$@" + +dnsjit.filter.ipsplit.3in: filter/ipsplit.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/filter/ipsplit.lua" > "$@" + +dnsjit.filter.layer.3in: filter/layer.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/filter/layer.lua" > "$@" + +dnsjit.filter.split.3in: filter/split.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/filter/split.lua" > "$@" + +dnsjit.filter.timing.3in: filter/timing.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/filter/timing.lua" > "$@" + +dnsjit.input.fpcap.3in: input/fpcap.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/input/fpcap.lua" > "$@" + +dnsjit.input.mmpcap.3in: input/mmpcap.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/input/mmpcap.lua" > "$@" + +dnsjit.input.pcap.3in: input/pcap.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/input/pcap.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" > "$@" + +dnsjit.lib.clock.3in: lib/clock.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/lib/clock.lua" > "$@" + +dnsjit.lib.getopt.3in: lib/getopt.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/lib/getopt.lua" > "$@" + +dnsjit.lib.ip.3in: lib/ip.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/lib/ip.lua" > "$@" + +dnsjit.lib.parseconf.3in: lib/parseconf.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/lib/parseconf.lua" > "$@" + +dnsjit.lib.trie.iter.3in: lib/trie/iter.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/lib/trie/iter.lua" > "$@" + +dnsjit.lib.trie.3in: lib/trie.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/lib/trie.lua" > "$@" + +dnsjit.lib.trie.node.3in: lib/trie/node.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/lib/trie/node.lua" > "$@" + +dnsjit.output.dnscli.3in: output/dnscli.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/output/dnscli.lua" > "$@" + +dnsjit.output.null.3in: output/null.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/output/null.lua" > "$@" + +dnsjit.output.pcap.3in: output/pcap.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/output/pcap.lua" > "$@" + +dnsjit.output.respdiff.3in: output/respdiff.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/output/respdiff.lua" > "$@" + +dnsjit.output.tcpcli.3in: output/tcpcli.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/output/tcpcli.lua" > "$@" + +dnsjit.output.tlscli.3in: output/tlscli.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/output/tlscli.lua" > "$@" + +dnsjit.output.udpcli.3in: output/udpcli.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/output/udpcli.lua" > "$@" diff --git a/include/dnsjit/Makefile.in b/include/dnsjit/Makefile.in new file mode 100644 index 0000000..7449ba5 --- /dev/null +++ b/include/dnsjit/Makefile.in @@ -0,0 +1,1652 @@ +# 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@ +bin_PROGRAMS = dnsjit$(EXEEXT) +subdir = src +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 $(nobase_dnsjitinclude_HEADERS) \ + $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" \ + "$(DESTDIR)$(man3dir)" "$(DESTDIR)$(dnsjitincludedir)" +PROGRAMS = $(bin_PROGRAMS) +am__dirstamp = $(am__leading_dot)dirstamp +am_dnsjit_OBJECTS = dnsjit.$(OBJEXT) globals.$(OBJEXT) \ + core/channel.$(OBJEXT) core/compat.$(OBJEXT) \ + core/file.$(OBJEXT) core/log.$(OBJEXT) core/object.$(OBJEXT) \ + core/object/dns.$(OBJEXT) core/object/ether.$(OBJEXT) \ + core/object/gre.$(OBJEXT) core/object/icmp6.$(OBJEXT) \ + core/object/icmp.$(OBJEXT) core/object/ieee802.$(OBJEXT) \ + core/object/ip6.$(OBJEXT) core/object/ip.$(OBJEXT) \ + core/object/linuxsll.$(OBJEXT) core/object/loop.$(OBJEXT) \ + core/object/null.$(OBJEXT) core/object/payload.$(OBJEXT) \ + core/object/pcap.$(OBJEXT) core/object/tcp.$(OBJEXT) \ + core/object/udp.$(OBJEXT) core/producer.$(OBJEXT) \ + core/receiver.$(OBJEXT) core/thread.$(OBJEXT) \ + filter/copy.$(OBJEXT) filter/ipsplit.$(OBJEXT) \ + filter/layer.$(OBJEXT) filter/split.$(OBJEXT) \ + filter/timing.$(OBJEXT) input/fpcap.$(OBJEXT) \ + input/mmpcap.$(OBJEXT) input/pcap.$(OBJEXT) \ + input/zpcap.$(OBJEXT) lib/base64url.$(OBJEXT) \ + lib/clock.$(OBJEXT) lib/trie.$(OBJEXT) output/dnscli.$(OBJEXT) \ + output/pcap.$(OBJEXT) output/respdiff.$(OBJEXT) \ + output/tcpcli.$(OBJEXT) output/tlscli.$(OBJEXT) \ + output/udpcli.$(OBJEXT) +dist_dnsjit_OBJECTS = +dnsjit_OBJECTS = $(am_dnsjit_OBJECTS) $(dist_dnsjit_OBJECTS) +am__DEPENDENCIES_1 = +dnsjit_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) $(lua_hobjects) \ + $(lua_objects) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +dnsjit_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(dnsjit_LDFLAGS) $(LDFLAGS) -o $@ +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 = +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/dnsjit.Po ./$(DEPDIR)/globals.Po \ + core/$(DEPDIR)/channel.Po core/$(DEPDIR)/compat.Po \ + core/$(DEPDIR)/file.Po core/$(DEPDIR)/log.Po \ + core/$(DEPDIR)/object.Po core/$(DEPDIR)/producer.Po \ + core/$(DEPDIR)/receiver.Po core/$(DEPDIR)/thread.Po \ + core/object/$(DEPDIR)/dns.Po core/object/$(DEPDIR)/ether.Po \ + core/object/$(DEPDIR)/gre.Po core/object/$(DEPDIR)/icmp.Po \ + core/object/$(DEPDIR)/icmp6.Po \ + core/object/$(DEPDIR)/ieee802.Po core/object/$(DEPDIR)/ip.Po \ + core/object/$(DEPDIR)/ip6.Po core/object/$(DEPDIR)/linuxsll.Po \ + core/object/$(DEPDIR)/loop.Po core/object/$(DEPDIR)/null.Po \ + core/object/$(DEPDIR)/payload.Po core/object/$(DEPDIR)/pcap.Po \ + core/object/$(DEPDIR)/tcp.Po core/object/$(DEPDIR)/udp.Po \ + filter/$(DEPDIR)/copy.Po filter/$(DEPDIR)/ipsplit.Po \ + filter/$(DEPDIR)/layer.Po filter/$(DEPDIR)/split.Po \ + filter/$(DEPDIR)/timing.Po input/$(DEPDIR)/fpcap.Po \ + input/$(DEPDIR)/mmpcap.Po input/$(DEPDIR)/pcap.Po \ + input/$(DEPDIR)/zpcap.Po lib/$(DEPDIR)/base64url.Po \ + lib/$(DEPDIR)/clock.Po lib/$(DEPDIR)/trie.Po \ + output/$(DEPDIR)/dnscli.Po output/$(DEPDIR)/pcap.Po \ + output/$(DEPDIR)/respdiff.Po output/$(DEPDIR)/tcpcli.Po \ + output/$(DEPDIR)/tlscli.Po output/$(DEPDIR)/udpcli.Po +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(dnsjit_SOURCES) $(dist_dnsjit_SOURCES) +DIST_SOURCES = $(dnsjit_SOURCES) $(dist_dnsjit_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +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; }; \ + } +man1dir = $(mandir)/man1 +man3dir = $(mandir)/man3 +NROFF = nroff +MANS = $(man1_MANS) $(man3_MANS) +HEADERS = $(nobase_dnsjitinclude_HEADERS) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__extra_recursive_targets = gcov-recursive +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ + $(LISP)config.h.in +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \ + $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +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 = *.gcda *.gcno *.gcov $(lua_hobjects) $(lua_objects) \ + $(man1_MANS) *.3in $(man3_MANS) +SUBDIRS = test +AM_CFLAGS = -Werror=attributes \ + -I$(srcdir) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/include \ + $(SIMD_FLAGS) $(CPUEXT_FLAGS) \ + $(PTHREAD_CFLAGS) \ + $(luajit_CFLAGS) \ + $(liblz4_CFLAGS) $(libzstd_CFLAGS) + +EXTRA_DIST = gen-manpage.lua gen-compat.lua gen-errno.sh dnsjit.1in +BUILT_SOURCES = core/compat.hh core/log_errstr.c + +# C source and headers +dnsjit_SOURCES = dnsjit.c globals.c 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 + +# Lua sources +dist_dnsjit_SOURCES = core.lua lib.lua input.lua filter.lua output.lua \ + 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 +dnsjitincludedir = $(includedir)/dnsjit + +# Lua headers +nobase_dnsjitinclude_HEADERS = globals.h version.h 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 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/compat.luaho 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_objects = core.luao lib.luao input.luao filter.luao output.luao \ + 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_LDADD = $(PTHREAD_LIBS) $(luajit_LIBS) $(liblz4_LIBS) \ + $(libzstd_LIBS) $(lua_hobjects) $(lua_objects) +dnsjit_LDFLAGS = -Wl,-E +man1_MANS = dnsjit.1 +man3_MANS = dnsjit.core.3 dnsjit.lib.3 dnsjit.input.3 dnsjit.filter.3 \ + dnsjit.output.3 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 +all: $(BUILT_SOURCES) config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: +.SUFFIXES: .1 .1in .3 .3in .c .hh .lo .lua .luah .luaho .luao .o .obj +$(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/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/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): + +config.h: stamp-h1 + @test -f $@ || rm -f stamp-h1 + @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 + +stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status src/config.h +$(srcdir)/config.h.in: $(am__configure_deps) + ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f config.h stamp-h1 +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +core/$(am__dirstamp): + @$(MKDIR_P) core + @: > core/$(am__dirstamp) +core/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) core/$(DEPDIR) + @: > core/$(DEPDIR)/$(am__dirstamp) +core/channel.$(OBJEXT): core/$(am__dirstamp) \ + core/$(DEPDIR)/$(am__dirstamp) +core/compat.$(OBJEXT): core/$(am__dirstamp) \ + core/$(DEPDIR)/$(am__dirstamp) +core/file.$(OBJEXT): core/$(am__dirstamp) \ + core/$(DEPDIR)/$(am__dirstamp) +core/log.$(OBJEXT): core/$(am__dirstamp) \ + core/$(DEPDIR)/$(am__dirstamp) +core/object.$(OBJEXT): core/$(am__dirstamp) \ + core/$(DEPDIR)/$(am__dirstamp) +core/object/$(am__dirstamp): + @$(MKDIR_P) core/object + @: > core/object/$(am__dirstamp) +core/object/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) core/object/$(DEPDIR) + @: > core/object/$(DEPDIR)/$(am__dirstamp) +core/object/dns.$(OBJEXT): core/object/$(am__dirstamp) \ + core/object/$(DEPDIR)/$(am__dirstamp) +core/object/ether.$(OBJEXT): core/object/$(am__dirstamp) \ + core/object/$(DEPDIR)/$(am__dirstamp) +core/object/gre.$(OBJEXT): core/object/$(am__dirstamp) \ + core/object/$(DEPDIR)/$(am__dirstamp) +core/object/icmp6.$(OBJEXT): core/object/$(am__dirstamp) \ + core/object/$(DEPDIR)/$(am__dirstamp) +core/object/icmp.$(OBJEXT): core/object/$(am__dirstamp) \ + core/object/$(DEPDIR)/$(am__dirstamp) +core/object/ieee802.$(OBJEXT): core/object/$(am__dirstamp) \ + core/object/$(DEPDIR)/$(am__dirstamp) +core/object/ip6.$(OBJEXT): core/object/$(am__dirstamp) \ + core/object/$(DEPDIR)/$(am__dirstamp) +core/object/ip.$(OBJEXT): core/object/$(am__dirstamp) \ + core/object/$(DEPDIR)/$(am__dirstamp) +core/object/linuxsll.$(OBJEXT): core/object/$(am__dirstamp) \ + core/object/$(DEPDIR)/$(am__dirstamp) +core/object/loop.$(OBJEXT): core/object/$(am__dirstamp) \ + core/object/$(DEPDIR)/$(am__dirstamp) +core/object/null.$(OBJEXT): core/object/$(am__dirstamp) \ + core/object/$(DEPDIR)/$(am__dirstamp) +core/object/payload.$(OBJEXT): core/object/$(am__dirstamp) \ + core/object/$(DEPDIR)/$(am__dirstamp) +core/object/pcap.$(OBJEXT): core/object/$(am__dirstamp) \ + core/object/$(DEPDIR)/$(am__dirstamp) +core/object/tcp.$(OBJEXT): core/object/$(am__dirstamp) \ + core/object/$(DEPDIR)/$(am__dirstamp) +core/object/udp.$(OBJEXT): core/object/$(am__dirstamp) \ + core/object/$(DEPDIR)/$(am__dirstamp) +core/producer.$(OBJEXT): core/$(am__dirstamp) \ + core/$(DEPDIR)/$(am__dirstamp) +core/receiver.$(OBJEXT): core/$(am__dirstamp) \ + core/$(DEPDIR)/$(am__dirstamp) +core/thread.$(OBJEXT): core/$(am__dirstamp) \ + core/$(DEPDIR)/$(am__dirstamp) +filter/$(am__dirstamp): + @$(MKDIR_P) filter + @: > filter/$(am__dirstamp) +filter/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) filter/$(DEPDIR) + @: > filter/$(DEPDIR)/$(am__dirstamp) +filter/copy.$(OBJEXT): filter/$(am__dirstamp) \ + filter/$(DEPDIR)/$(am__dirstamp) +filter/ipsplit.$(OBJEXT): filter/$(am__dirstamp) \ + filter/$(DEPDIR)/$(am__dirstamp) +filter/layer.$(OBJEXT): filter/$(am__dirstamp) \ + filter/$(DEPDIR)/$(am__dirstamp) +filter/split.$(OBJEXT): filter/$(am__dirstamp) \ + filter/$(DEPDIR)/$(am__dirstamp) +filter/timing.$(OBJEXT): filter/$(am__dirstamp) \ + filter/$(DEPDIR)/$(am__dirstamp) +input/$(am__dirstamp): + @$(MKDIR_P) input + @: > input/$(am__dirstamp) +input/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) input/$(DEPDIR) + @: > input/$(DEPDIR)/$(am__dirstamp) +input/fpcap.$(OBJEXT): input/$(am__dirstamp) \ + input/$(DEPDIR)/$(am__dirstamp) +input/mmpcap.$(OBJEXT): input/$(am__dirstamp) \ + input/$(DEPDIR)/$(am__dirstamp) +input/pcap.$(OBJEXT): input/$(am__dirstamp) \ + input/$(DEPDIR)/$(am__dirstamp) +input/zpcap.$(OBJEXT): input/$(am__dirstamp) \ + input/$(DEPDIR)/$(am__dirstamp) +lib/$(am__dirstamp): + @$(MKDIR_P) lib + @: > lib/$(am__dirstamp) +lib/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) lib/$(DEPDIR) + @: > lib/$(DEPDIR)/$(am__dirstamp) +lib/base64url.$(OBJEXT): lib/$(am__dirstamp) \ + lib/$(DEPDIR)/$(am__dirstamp) +lib/clock.$(OBJEXT): lib/$(am__dirstamp) lib/$(DEPDIR)/$(am__dirstamp) +lib/trie.$(OBJEXT): lib/$(am__dirstamp) lib/$(DEPDIR)/$(am__dirstamp) +output/$(am__dirstamp): + @$(MKDIR_P) output + @: > output/$(am__dirstamp) +output/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) output/$(DEPDIR) + @: > output/$(DEPDIR)/$(am__dirstamp) +output/dnscli.$(OBJEXT): output/$(am__dirstamp) \ + output/$(DEPDIR)/$(am__dirstamp) +output/pcap.$(OBJEXT): output/$(am__dirstamp) \ + output/$(DEPDIR)/$(am__dirstamp) +output/respdiff.$(OBJEXT): output/$(am__dirstamp) \ + output/$(DEPDIR)/$(am__dirstamp) +output/tcpcli.$(OBJEXT): output/$(am__dirstamp) \ + output/$(DEPDIR)/$(am__dirstamp) +output/tlscli.$(OBJEXT): output/$(am__dirstamp) \ + output/$(DEPDIR)/$(am__dirstamp) +output/udpcli.$(OBJEXT): output/$(am__dirstamp) \ + output/$(DEPDIR)/$(am__dirstamp) + +dnsjit$(EXEEXT): $(dnsjit_OBJECTS) $(dnsjit_DEPENDENCIES) $(EXTRA_dnsjit_DEPENDENCIES) + @rm -f dnsjit$(EXEEXT) + $(AM_V_CCLD)$(dnsjit_LINK) $(dnsjit_OBJECTS) $(dnsjit_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + -rm -f core/*.$(OBJEXT) + -rm -f core/object/*.$(OBJEXT) + -rm -f filter/*.$(OBJEXT) + -rm -f input/*.$(OBJEXT) + -rm -f lib/*.$(OBJEXT) + -rm -f output/*.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsjit.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/globals.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@core/$(DEPDIR)/channel.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@core/$(DEPDIR)/compat.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@core/$(DEPDIR)/file.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@core/$(DEPDIR)/log.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@core/$(DEPDIR)/object.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@core/$(DEPDIR)/producer.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@core/$(DEPDIR)/receiver.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@core/$(DEPDIR)/thread.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@core/object/$(DEPDIR)/dns.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@core/object/$(DEPDIR)/ether.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@core/object/$(DEPDIR)/gre.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@core/object/$(DEPDIR)/icmp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@core/object/$(DEPDIR)/icmp6.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@core/object/$(DEPDIR)/ieee802.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@core/object/$(DEPDIR)/ip.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@core/object/$(DEPDIR)/ip6.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@core/object/$(DEPDIR)/linuxsll.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@core/object/$(DEPDIR)/loop.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@core/object/$(DEPDIR)/null.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@core/object/$(DEPDIR)/payload.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@core/object/$(DEPDIR)/pcap.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@core/object/$(DEPDIR)/tcp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@core/object/$(DEPDIR)/udp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@filter/$(DEPDIR)/copy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@filter/$(DEPDIR)/ipsplit.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@filter/$(DEPDIR)/layer.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@filter/$(DEPDIR)/split.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@filter/$(DEPDIR)/timing.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/fpcap.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/mmpcap.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/pcap.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/zpcap.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/base64url.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/clock.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/trie.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@output/$(DEPDIR)/dnscli.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@output/$(DEPDIR)/pcap.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@output/$(DEPDIR)/respdiff.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@output/$(DEPDIR)/tcpcli.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@output/$(DEPDIR)/tlscli.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@output/$(DEPDIR)/udpcli.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-man1: $(man1_MANS) + @$(NORMAL_INSTALL) + @list1='$(man1_MANS)'; \ + list2=''; \ + test -n "$(man1dir)" \ + && test -n "`echo $$list1$$list2`" \ + || exit 0; \ + echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ + { for i in $$list1; do echo "$$i"; done; \ + if test -n "$$list2"; then \ + for i in $$list2; do echo "$$i"; done \ + | sed -n '/\.1[a-z]*$$/p'; \ + fi; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ + done; } + +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list='$(man1_MANS)'; test -n "$(man1dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) +install-man3: $(man3_MANS) + @$(NORMAL_INSTALL) + @list1='$(man3_MANS)'; \ + list2=''; \ + test -n "$(man3dir)" \ + && test -n "`echo $$list1$$list2`" \ + || exit 0; \ + echo " $(MKDIR_P) '$(DESTDIR)$(man3dir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(man3dir)" || exit 1; \ + { for i in $$list1; do echo "$$i"; done; \ + if test -n "$$list2"; then \ + for i in $$list2; do echo "$$i"; done \ + | sed -n '/\.3[a-z]*$$/p'; \ + fi; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man3dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man3dir)" || exit $$?; }; \ + done; } + +uninstall-man3: + @$(NORMAL_UNINSTALL) + @list='$(man3_MANS)'; test -n "$(man3dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + dir='$(DESTDIR)$(man3dir)'; $(am__uninstall_files_from_dir) +install-nobase_dnsjitincludeHEADERS: $(nobase_dnsjitinclude_HEADERS) + @$(NORMAL_INSTALL) + @list='$(nobase_dnsjitinclude_HEADERS)'; test -n "$(dnsjitincludedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(dnsjitincludedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(dnsjitincludedir)" || exit 1; \ + fi; \ + $(am__nobase_list) | while read dir files; do \ + xfiles=; for file in $$files; do \ + if test -f "$$file"; then xfiles="$$xfiles $$file"; \ + else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \ + test -z "$$xfiles" || { \ + test "x$$dir" = x. || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(dnsjitincludedir)/$$dir'"; \ + $(MKDIR_P) "$(DESTDIR)$(dnsjitincludedir)/$$dir"; }; \ + echo " $(INSTALL_HEADER) $$xfiles '$(DESTDIR)$(dnsjitincludedir)/$$dir'"; \ + $(INSTALL_HEADER) $$xfiles "$(DESTDIR)$(dnsjitincludedir)/$$dir" || exit $$?; }; \ + done + +uninstall-nobase_dnsjitincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(nobase_dnsjitinclude_HEADERS)'; test -n "$(dnsjitincludedir)" || list=; \ + $(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \ + dir='$(DESTDIR)$(dnsjitincludedir)'; $(am__uninstall_files_from_dir) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" +gcov-local: + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +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 + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-recursive +all-am: Makefile $(PROGRAMS) $(MANS) $(HEADERS) config.h +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man3dir)" "$(DESTDIR)$(dnsjitincludedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +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: + +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) + -rm -f core/$(DEPDIR)/$(am__dirstamp) + -rm -f core/$(am__dirstamp) + -rm -f core/object/$(DEPDIR)/$(am__dirstamp) + -rm -f core/object/$(am__dirstamp) + -rm -f filter/$(DEPDIR)/$(am__dirstamp) + -rm -f filter/$(am__dirstamp) + -rm -f input/$(DEPDIR)/$(am__dirstamp) + -rm -f input/$(am__dirstamp) + -rm -f lib/$(DEPDIR)/$(am__dirstamp) + -rm -f lib/$(am__dirstamp) + -rm -f output/$(DEPDIR)/$(am__dirstamp) + -rm -f output/$(am__dirstamp) + +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 "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +@ENABLE_GCOV_FALSE@gcov-local: +clean: clean-recursive + +clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f ./$(DEPDIR)/dnsjit.Po + -rm -f ./$(DEPDIR)/globals.Po + -rm -f core/$(DEPDIR)/channel.Po + -rm -f core/$(DEPDIR)/compat.Po + -rm -f core/$(DEPDIR)/file.Po + -rm -f core/$(DEPDIR)/log.Po + -rm -f core/$(DEPDIR)/object.Po + -rm -f core/$(DEPDIR)/producer.Po + -rm -f core/$(DEPDIR)/receiver.Po + -rm -f core/$(DEPDIR)/thread.Po + -rm -f core/object/$(DEPDIR)/dns.Po + -rm -f core/object/$(DEPDIR)/ether.Po + -rm -f core/object/$(DEPDIR)/gre.Po + -rm -f core/object/$(DEPDIR)/icmp.Po + -rm -f core/object/$(DEPDIR)/icmp6.Po + -rm -f core/object/$(DEPDIR)/ieee802.Po + -rm -f core/object/$(DEPDIR)/ip.Po + -rm -f core/object/$(DEPDIR)/ip6.Po + -rm -f core/object/$(DEPDIR)/linuxsll.Po + -rm -f core/object/$(DEPDIR)/loop.Po + -rm -f core/object/$(DEPDIR)/null.Po + -rm -f core/object/$(DEPDIR)/payload.Po + -rm -f core/object/$(DEPDIR)/pcap.Po + -rm -f core/object/$(DEPDIR)/tcp.Po + -rm -f core/object/$(DEPDIR)/udp.Po + -rm -f filter/$(DEPDIR)/copy.Po + -rm -f filter/$(DEPDIR)/ipsplit.Po + -rm -f filter/$(DEPDIR)/layer.Po + -rm -f filter/$(DEPDIR)/split.Po + -rm -f filter/$(DEPDIR)/timing.Po + -rm -f input/$(DEPDIR)/fpcap.Po + -rm -f input/$(DEPDIR)/mmpcap.Po + -rm -f input/$(DEPDIR)/pcap.Po + -rm -f input/$(DEPDIR)/zpcap.Po + -rm -f lib/$(DEPDIR)/base64url.Po + -rm -f lib/$(DEPDIR)/clock.Po + -rm -f lib/$(DEPDIR)/trie.Po + -rm -f output/$(DEPDIR)/dnscli.Po + -rm -f output/$(DEPDIR)/pcap.Po + -rm -f output/$(DEPDIR)/respdiff.Po + -rm -f output/$(DEPDIR)/tcpcli.Po + -rm -f output/$(DEPDIR)/tlscli.Po + -rm -f output/$(DEPDIR)/udpcli.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-hdr distclean-tags + +dvi: dvi-recursive + +dvi-am: + +gcov: gcov-recursive + +gcov-am: gcov-local + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-man install-nobase_dnsjitincludeHEADERS + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: install-binPROGRAMS + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: install-man1 install-man3 + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f ./$(DEPDIR)/dnsjit.Po + -rm -f ./$(DEPDIR)/globals.Po + -rm -f core/$(DEPDIR)/channel.Po + -rm -f core/$(DEPDIR)/compat.Po + -rm -f core/$(DEPDIR)/file.Po + -rm -f core/$(DEPDIR)/log.Po + -rm -f core/$(DEPDIR)/object.Po + -rm -f core/$(DEPDIR)/producer.Po + -rm -f core/$(DEPDIR)/receiver.Po + -rm -f core/$(DEPDIR)/thread.Po + -rm -f core/object/$(DEPDIR)/dns.Po + -rm -f core/object/$(DEPDIR)/ether.Po + -rm -f core/object/$(DEPDIR)/gre.Po + -rm -f core/object/$(DEPDIR)/icmp.Po + -rm -f core/object/$(DEPDIR)/icmp6.Po + -rm -f core/object/$(DEPDIR)/ieee802.Po + -rm -f core/object/$(DEPDIR)/ip.Po + -rm -f core/object/$(DEPDIR)/ip6.Po + -rm -f core/object/$(DEPDIR)/linuxsll.Po + -rm -f core/object/$(DEPDIR)/loop.Po + -rm -f core/object/$(DEPDIR)/null.Po + -rm -f core/object/$(DEPDIR)/payload.Po + -rm -f core/object/$(DEPDIR)/pcap.Po + -rm -f core/object/$(DEPDIR)/tcp.Po + -rm -f core/object/$(DEPDIR)/udp.Po + -rm -f filter/$(DEPDIR)/copy.Po + -rm -f filter/$(DEPDIR)/ipsplit.Po + -rm -f filter/$(DEPDIR)/layer.Po + -rm -f filter/$(DEPDIR)/split.Po + -rm -f filter/$(DEPDIR)/timing.Po + -rm -f input/$(DEPDIR)/fpcap.Po + -rm -f input/$(DEPDIR)/mmpcap.Po + -rm -f input/$(DEPDIR)/pcap.Po + -rm -f input/$(DEPDIR)/zpcap.Po + -rm -f lib/$(DEPDIR)/base64url.Po + -rm -f lib/$(DEPDIR)/clock.Po + -rm -f lib/$(DEPDIR)/trie.Po + -rm -f output/$(DEPDIR)/dnscli.Po + -rm -f output/$(DEPDIR)/pcap.Po + -rm -f output/$(DEPDIR)/respdiff.Po + -rm -f output/$(DEPDIR)/tcpcli.Po + -rm -f output/$(DEPDIR)/tlscli.Po + -rm -f output/$(DEPDIR)/udpcli.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-man \ + uninstall-nobase_dnsjitincludeHEADERS + +uninstall-man: uninstall-man1 uninstall-man3 + +.MAKE: $(am__recursive_targets) all check install install-am \ + install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--depfiles check check-am clean clean-binPROGRAMS \ + clean-generic clean-libtool cscopelist-am ctags ctags-am \ + distclean distclean-compile distclean-generic distclean-hdr \ + distclean-libtool distclean-tags distdir dvi dvi-am gcov-am \ + gcov-local html html-am info info-am install install-am \ + install-binPROGRAMS 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-man1 install-man3 install-nobase_dnsjitincludeHEADERS \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am uninstall-binPROGRAMS uninstall-man \ + uninstall-man1 uninstall-man3 \ + uninstall-nobase_dnsjitincludeHEADERS + +.PRECIOUS: Makefile + + +.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' \ + < "$<" > "$@" + +@ENABLE_GCOV_TRUE@gcov-local: +@ENABLE_GCOV_TRUE@ for src in $(dnsjit_SOURCES); do \ +@ENABLE_GCOV_TRUE@ gcov -x -l -r -s "$(srcdir)" "$$src"; \ +@ENABLE_GCOV_TRUE@ done + +core/compat.hh: gen-compat.lua + $(LUAJIT) "$(srcdir)/gen-compat.lua" > "$@" + +core/log_errstr.c: gen-errno.sh + "$(srcdir)/gen-errno.sh" > "$@" + +dnsjit.core.3in: core.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core.lua" > "$@" + +dnsjit.lib.3in: lib.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/lib.lua" > "$@" + +dnsjit.input.3in: input.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/input.lua" > "$@" + +dnsjit.filter.3in: filter.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/filter.lua" > "$@" + +dnsjit.output.3in: output.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/output.lua" > "$@" + +dnsjit.core.channel.3in: core/channel.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/channel.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" > "$@" + +dnsjit.core.object.dns.label.3in: core/object/dns/label.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/dns/label.lua" > "$@" + +dnsjit.core.object.dns.3in: core/object/dns.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/dns.lua" > "$@" + +dnsjit.core.object.dns.q.3in: core/object/dns/q.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/dns/q.lua" > "$@" + +dnsjit.core.object.dns.rr.3in: core/object/dns/rr.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/dns/rr.lua" > "$@" + +dnsjit.core.object.ether.3in: core/object/ether.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/ether.lua" > "$@" + +dnsjit.core.object.gre.3in: core/object/gre.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/gre.lua" > "$@" + +dnsjit.core.object.icmp6.3in: core/object/icmp6.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/icmp6.lua" > "$@" + +dnsjit.core.object.icmp.3in: core/object/icmp.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/icmp.lua" > "$@" + +dnsjit.core.object.ieee802.3in: core/object/ieee802.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/ieee802.lua" > "$@" + +dnsjit.core.object.ip6.3in: core/object/ip6.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/ip6.lua" > "$@" + +dnsjit.core.object.ip.3in: core/object/ip.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/ip.lua" > "$@" + +dnsjit.core.object.linuxsll.3in: core/object/linuxsll.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/linuxsll.lua" > "$@" + +dnsjit.core.object.loop.3in: core/object/loop.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/loop.lua" > "$@" + +dnsjit.core.object.3in: core/object.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object.lua" > "$@" + +dnsjit.core.object.null.3in: core/object/null.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/null.lua" > "$@" + +dnsjit.core.object.payload.3in: core/object/payload.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/payload.lua" > "$@" + +dnsjit.core.object.pcap.3in: core/object/pcap.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/pcap.lua" > "$@" + +dnsjit.core.objects.3in: core/objects.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/objects.lua" > "$@" + +dnsjit.core.object.tcp.3in: core/object/tcp.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/tcp.lua" > "$@" + +dnsjit.core.object.udp.3in: core/object/udp.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/object/udp.lua" > "$@" + +dnsjit.core.producer.3in: core/producer.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/producer.lua" > "$@" + +dnsjit.core.receiver.3in: core/receiver.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/receiver.lua" > "$@" + +dnsjit.core.thread.3in: core/thread.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/thread.lua" > "$@" + +dnsjit.core.timespec.3in: core/timespec.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/core/timespec.lua" > "$@" + +dnsjit.filter.copy.3in: filter/copy.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/filter/copy.lua" > "$@" + +dnsjit.filter.ipsplit.3in: filter/ipsplit.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/filter/ipsplit.lua" > "$@" + +dnsjit.filter.layer.3in: filter/layer.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/filter/layer.lua" > "$@" + +dnsjit.filter.split.3in: filter/split.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/filter/split.lua" > "$@" + +dnsjit.filter.timing.3in: filter/timing.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/filter/timing.lua" > "$@" + +dnsjit.input.fpcap.3in: input/fpcap.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/input/fpcap.lua" > "$@" + +dnsjit.input.mmpcap.3in: input/mmpcap.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/input/mmpcap.lua" > "$@" + +dnsjit.input.pcap.3in: input/pcap.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/input/pcap.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" > "$@" + +dnsjit.lib.clock.3in: lib/clock.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/lib/clock.lua" > "$@" + +dnsjit.lib.getopt.3in: lib/getopt.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/lib/getopt.lua" > "$@" + +dnsjit.lib.ip.3in: lib/ip.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/lib/ip.lua" > "$@" + +dnsjit.lib.parseconf.3in: lib/parseconf.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/lib/parseconf.lua" > "$@" + +dnsjit.lib.trie.iter.3in: lib/trie/iter.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/lib/trie/iter.lua" > "$@" + +dnsjit.lib.trie.3in: lib/trie.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/lib/trie.lua" > "$@" + +dnsjit.lib.trie.node.3in: lib/trie/node.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/lib/trie/node.lua" > "$@" + +dnsjit.output.dnscli.3in: output/dnscli.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/output/dnscli.lua" > "$@" + +dnsjit.output.null.3in: output/null.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/output/null.lua" > "$@" + +dnsjit.output.pcap.3in: output/pcap.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/output/pcap.lua" > "$@" + +dnsjit.output.respdiff.3in: output/respdiff.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/output/respdiff.lua" > "$@" + +dnsjit.output.tcpcli.3in: output/tcpcli.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/output/tcpcli.lua" > "$@" + +dnsjit.output.tlscli.3in: output/tlscli.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/output/tlscli.lua" > "$@" + +dnsjit.output.udpcli.3in: output/udpcli.lua gen-manpage.lua + $(LUAJIT) "$(srcdir)/gen-manpage.lua" "$(srcdir)/output/udpcli.lua" > "$@" + +# 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: diff --git a/include/dnsjit/config.h.in b/include/dnsjit/config.h.in new file mode 100644 index 0000000..c156fa2 --- /dev/null +++ b/include/dnsjit/config.h.in @@ -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 diff --git a/include/dnsjit/core.lua b/include/dnsjit/core.lua new file mode 100644 index 0000000..47723e6 --- /dev/null +++ b/include/dnsjit/core.lua @@ -0,0 +1,45 @@ +-- 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 +-- Core modules for dnsjit +-- +-- Core modules for handling things like logging, DNS messages and +-- receiver/receive functionality. +-- .SS Global Variables +-- The following global variables exists in +-- .IR dnsjit . +-- .TP +-- .B arg +-- A table with the arguments given on the command line, the first will be +-- the path to the +-- .I dnsjit +-- binary, second will be the path to the +-- .IR script . +module(...,package.seeall) + +-- dnsjit.core.channel (3), +-- dnsjit.core.compat (3), +-- dnsjit.core.log (3), +-- dnsjit.core.object (3), +-- dnsjit.core.objects (3), +-- dnsjit.core.producer (3), +-- dnsjit.core.receiver (3), +-- dnsjit.core.thread (3), +-- dnsjit.core.timespec (3) +return diff --git a/include/dnsjit/core/assert.h b/include/dnsjit/core/assert.h new file mode 100644 index 0000000..1cdc6e6 --- /dev/null +++ b/include/dnsjit/core/assert.h @@ -0,0 +1,46 @@ +/* + * 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/>. + */ + +#ifndef __dnsjit_core_assert_h +#define __dnsjit_core_assert_h + +#include <dnsjit/core/log.h> + +#define mlassert_self() \ + if (!self) \ + core_log_fatal(&_log, __FILE__, __LINE__, "self is nil") +#define glassert_self() \ + if (!self) \ + core_log_fatal(0, __FILE__, __LINE__, "self is nil") + +#define lassert(expression, msg...) \ + if (!(expression)) \ + core_log_fatal(&self->_log, __FILE__, __LINE__, msg) +#define lpassert(expression, msg...) \ + if (!(expression)) \ + core_log_fatal(self->_log, __FILE__, __LINE__, msg) +#define mlassert(expression, msg...) \ + if (!(expression)) \ + core_log_fatal(&_log, __FILE__, __LINE__, msg) +#define glassert(expression, msg...) \ + if (!(expression)) \ + core_log_fatal(0, __FILE__, __LINE__, msg) + +#endif diff --git a/include/dnsjit/core/channel.c b/include/dnsjit/core/channel.c new file mode 100644 index 0000000..691ad1a --- /dev/null +++ b/include/dnsjit/core/channel.c @@ -0,0 +1,169 @@ +/* + * 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 "core/channel.h" +#include "core/assert.h" + +#include <sched.h> + +static core_log_t _log = LOG_T_INIT("core.channel"); +static core_channel_t _defaults = { + LOG_T_INIT_OBJ("core.channel"), + 0, { 0 }, 0, 0, + 0, 0 +}; + +core_log_t* core_channel_log() +{ + return &_log; +} + +static inline bool _is_pow2(size_t num) +{ + while (num != 1) { + if (num % 2 != 0) + return false; + num = num / 2; + } + return true; +} + +void core_channel_init(core_channel_t* self, size_t capacity) +{ + mlassert_self(); + if (capacity < 4 || !_is_pow2(capacity)) { + mlfatal("invalid capacity"); + } + + *self = _defaults; + self->capacity = capacity; + + lfatal_oom(self->ring_buf = malloc(sizeof(ck_ring_buffer_t) * capacity)); + ck_ring_init(&self->ring, capacity); +} + +void core_channel_destroy(core_channel_t* self) +{ + mlassert_self(); + free(self->ring_buf); +} + +void core_channel_put(core_channel_t* self, const void* obj) +{ + mlassert_self(); + lassert(self->ring_buf, "ring_buf is nil"); + + while (!ck_ring_enqueue_spsc(&self->ring, self->ring_buf, (void*)obj)) { + sched_yield(); + } +} + +int core_channel_try_put(core_channel_t* self, const void* obj) +{ + mlassert_self(); + lassert(self->ring_buf, "ring_buf is nil"); + + if (!ck_ring_enqueue_spsc(&self->ring, self->ring_buf, (void*)obj)) { + return -1; + } + + return 0; +} + +void* core_channel_get(core_channel_t* self) +{ + void* obj = 0; + mlassert_self(); + lassert(self->ring_buf, "ring_buf is nil"); + + while (!ck_ring_dequeue_spsc(&self->ring, self->ring_buf, &obj)) { + sched_yield(); + if (ck_pr_load_int(&self->closed)) { + linfo("channel closed"); + return 0; + } + } + + return obj; +} + +void* core_channel_try_get(core_channel_t* self) +{ + void* obj = 0; + mlassert_self(); + lassert(self->ring_buf, "ring_buf is nil"); + + if (!ck_ring_dequeue_spsc(&self->ring, self->ring_buf, &obj)) { + return 0; + } + + return obj; +} + +int core_channel_size(core_channel_t* self) +{ + mlassert_self(); + return ck_ring_size(&self->ring); +} + +bool core_channel_full(core_channel_t* self) +{ + mlassert_self(); + + /* ck_ring can only hold capacity minus one enties at a time */ + if (ck_ring_size(&self->ring) < (self->capacity - 1)) { + return false; + } + return true; +} + +void core_channel_close(core_channel_t* self) +{ + mlassert_self(); + ck_pr_store_int(&self->closed, 1); +} + +core_receiver_t core_channel_receiver() +{ + return (core_receiver_t)core_channel_put; +} + +void core_channel_run(core_channel_t* self) +{ + void* obj = 0; + mlassert_self(); + lassert(self->ring_buf, "ring_buf is nil"); + if (!self->recv) { + lfatal("no receiver set"); + } + + for (;;) { + while (!ck_ring_dequeue_spsc(&self->ring, self->ring_buf, &obj)) { + sched_yield(); + if (ck_pr_load_int(&self->closed)) { + linfo("channel closed"); + return; + } + } + self->recv(self->ctx, obj); + } +} diff --git a/include/dnsjit/core/channel.h b/include/dnsjit/core/channel.h new file mode 100644 index 0000000..b0e90ae --- /dev/null +++ b/include/dnsjit/core/channel.h @@ -0,0 +1,41 @@ +/* + * 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> + +#ifndef __dnsjit_core_channel_h +#define __dnsjit_core_channel_h + +#if defined(__GNUC__) || defined(__SUNPRO_C) +#include "gcc/ck_cc.h" +#ifdef CK_CC_RESTRICT +#undef CK_CC_RESTRICT +#define CK_CC_RESTRICT __restrict__ +#endif +#endif + +#include <ck_ring.h> +#include <ck_pr.h> +#include <stdbool.h> + +#include <dnsjit/core/channel.hh> + +#endif diff --git a/include/dnsjit/core/channel.hh b/include/dnsjit/core/channel.hh new file mode 100644 index 0000000..e6ec0e0 --- /dev/null +++ b/include/dnsjit/core/channel.hh @@ -0,0 +1,49 @@ +/* + * 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.compat_h") +//lua:require("dnsjit.core.log") +//lua:require("dnsjit.core.receiver_h") + +typedef struct core_channel { + core_log_t _log; + ck_ring_buffer_t* ring_buf; + ck_ring_t ring; + int closed; + size_t capacity; + + core_receiver_t recv; + void* ctx; +} core_channel_t; + +core_log_t* core_channel_log(); + +void core_channel_init(core_channel_t* self, size_t capacity); +void core_channel_destroy(core_channel_t* self); +void core_channel_put(core_channel_t* self, const void* obj); +int core_channel_try_put(core_channel_t* self, const void* obj); +void* core_channel_get(core_channel_t* self); +void* core_channel_try_get(core_channel_t* self); +int core_channel_size(core_channel_t* self); +bool core_channel_full(core_channel_t* self); +void core_channel_close(core_channel_t* self); + +core_receiver_t core_channel_receiver(); +void core_channel_run(core_channel_t* self); diff --git a/include/dnsjit/core/channel.lua b/include/dnsjit/core/channel.lua new file mode 100644 index 0000000..b837cc4 --- /dev/null +++ b/include/dnsjit/core/channel.lua @@ -0,0 +1,142 @@ +-- 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.channel +-- Send data to another thread +-- local chan = require("dnsjit.core.channel").new() +-- local thr = require("dnsjit.core.thread").new() +-- thr:start(function(thr) +-- local chan = thr:pop() +-- local obj = chan:get() +-- ... +-- end) +-- thr:push(chan) +-- chan:put(...) +-- chan:close() +-- thr:stop() +-- +-- A channel can be used to send data to another thread, this is done by +-- putting a pointer to the data into a wait-free and lock-free ring buffer +-- (concurrency kit). +-- The channel uses the single producer, single consumer model (SPSC) so +-- there can only be one writer and one reader. +-- .SS Attributes +-- .TP +-- int closed +-- Is 1 if the channel has been closed. +module(...,package.seeall) + +require("dnsjit.core.channel_h") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "core_channel_t" +local core_channel_t +local Channel = {} + +-- Create a new Channel, use the optional +-- .I capacity +-- to specify the capacity of the channel (buffer). +-- Capacity must be a power-of-two greater than or equal to 4. +-- Default capacity is 2048. +function Channel.new(capacity) + if capacity == nil then + capacity = 2048 + end + local self = core_channel_t() + C.core_channel_init(self, capacity) + ffi.gc(self, C.core_channel_destroy) + return self +end + +-- Return the Log object to control logging of this instance or module. +function Channel:log() + if self == nil then + return C.core_channel_log() + end + return self._log +end + +-- Return information to use when sharing this object between threads. +function Channel:share() + return ffi.cast("void*", self), t_name.."*", "dnsjit.core.channel" +end + +-- Put an object into the channel, if the channel is full then it will +-- stall and wait until space becomes available. +-- Object may be nil. +function Channel:put(obj) + C.core_channel_put(self, obj) +end + +-- Try and put an object into the channel. +-- Returns 0 on success. +function Channel:put(obj) + C.core_channel_try_put(self, obj) +end + +-- Get an object from the channel, if the channel is empty it will wait until +-- an object is available. +-- Returns nil if the channel is closed or if a nil object was explicitly put +-- into the channel. +function Channel:get() + return C.core_channel_get(self) +end + +-- Try and get an object from the channel. +-- Returns nil if there was no objects to get. +function Channel:try_get() + return C.core_channel_try_get(self) +end + +-- Return number of enqueued objects. +function Channel:size() + return C.core_channel_size(self) +end + +-- Returns true when channel is full. +function Channel:full() + return C.core_channel_full(self) +end + +-- Close the channel. +function Channel:close() + C.core_channel_close(self) +end + +-- Return the C functions and context for receiving objects. +function Channel:receive() + return C.core_channel_receiver(), self +end + +-- Set the receiver to pass objects to. +-- NOTE; The channel keeps no reference of the receiver, it needs to live as +-- long as the channel does. +function Channel:receiver(o) + self.recv, self.ctx = o:receive() +end + +-- Retrieve all objects from the channel and send it to the receiver. +function Channel:run() + C.core_channel_run(self) +end + +core_channel_t = ffi.metatype(t_name, { __index = Channel }) + +-- dnsjit.core.thread (3) +return Channel diff --git a/include/dnsjit/core/compat.c b/include/dnsjit/core/compat.c new file mode 100644 index 0000000..9f2be98 --- /dev/null +++ b/include/dnsjit/core/compat.c @@ -0,0 +1,25 @@ +/* + * 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 <stdint.h> + +#include "core/compat.hh" diff --git a/include/dnsjit/core/compat.h b/include/dnsjit/core/compat.h new file mode 100644 index 0000000..c9486c3 --- /dev/null +++ b/include/dnsjit/core/compat.h @@ -0,0 +1,32 @@ +/* + * 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/>. + */ + +#ifndef __dnsjit_core_compat_h +#define __dnsjit_core_compat_h + +#include <unistd.h> + +#ifdef __ssize_t_defined +typedef ssize_t luajit_ssize_t; +#else +typedef long luajit_ssize_t; +#endif + +#endif diff --git a/include/dnsjit/core/compat.lua b/include/dnsjit/core/compat.lua new file mode 100644 index 0000000..bb6d45c --- /dev/null +++ b/include/dnsjit/core/compat.lua @@ -0,0 +1,41 @@ +-- 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.compat +-- Cross platform compatibility support +-- require("dnsjit.core.compat_h") +-- +-- This module defines various system structures so they can be exposed into +-- Lua but not really used. The size is generated at compile time to match +-- that of the structures on the platform. +-- .SS Structures +-- .TP +-- pthread_t +-- .TP +-- pthread_cond_t +-- .TP +-- pthread_mutex_t +-- .TP +-- struct sockaddr_storage +-- .TP +-- ck_ring_t +-- .TP +-- ck_ring_buffer_t +module(...,package.seeall) + +require("dnsjit.core.compat_h") diff --git a/include/dnsjit/core/file.c b/include/dnsjit/core/file.c new file mode 100644 index 0000000..d632a73 --- /dev/null +++ b/include/dnsjit/core/file.c @@ -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/>. + */ + +#include "config.h" + +#include "core/file.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +int core_file_exists(const char* filename) +{ + struct stat s; + + if (stat(filename, &s)) { + return 1; + } + return 0; +} diff --git a/include/dnsjit/core/file.h b/include/dnsjit/core/file.h new file mode 100644 index 0000000..ad5a174 --- /dev/null +++ b/include/dnsjit/core/file.h @@ -0,0 +1,26 @@ +/* + * 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/>. + */ + +#ifndef __dnsjit_core_file_h +#define __dnsjit_core_file_h + +#include <dnsjit/core/file.hh> + +#endif diff --git a/include/dnsjit/core/file.hh b/include/dnsjit/core/file.hh new file mode 100644 index 0000000..70b1bc9 --- /dev/null +++ b/include/dnsjit/core/file.hh @@ -0,0 +1,21 @@ +/* + * 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/>. + */ + +int core_file_exists(const char*); diff --git a/include/dnsjit/core/file.lua b/include/dnsjit/core/file.lua new file mode 100644 index 0000000..5ce52d7 --- /dev/null +++ b/include/dnsjit/core/file.lua @@ -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") diff --git a/include/dnsjit/core/loader.lua b/include/dnsjit/core/loader.lua new file mode 100644 index 0000000..b56a390 --- /dev/null +++ b/include/dnsjit/core/loader.lua @@ -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 diff --git a/include/dnsjit/core/log.c b/include/dnsjit/core/log.c new file mode 100644 index 0000000..a334e8e --- /dev/null +++ b/include/dnsjit/core/log.c @@ -0,0 +1,399 @@ +/* + * 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 "core/log.h" + +#include <string.h> +#include <stdarg.h> +#include <stdio.h> + +static core_log_t _log = LOG_T_INIT("core"); + +void core_log_debug(const core_log_t* l, const char* file, size_t line, const char* msg, ...) +{ + char buf[512]; + va_list ap; + if (!l) { + if (_log.settings.debug != 3) { + return; + } + } else { + if (l->settings.debug) { + if (l->settings.debug != 3) { + return; + } + } else if (l->module && l->module->debug) { + if (l->module->debug != 3) { + return; + } + } else if (_log.settings.debug != 3) { + return; + } + } + va_start(ap, msg); + vsnprintf(buf, sizeof(buf), msg, ap); + va_end(ap); + buf[sizeof(buf) - 1] = 0; + for (;;) { + if (!l) { + if (_log.settings.display_file_line != 3) { + break; + } + } else { + if (l->settings.display_file_line) { + if (l->settings.display_file_line != 3) { + break; + } + } else if (l->module && l->module->display_file_line) { + if (l->module->display_file_line != 3) { + break; + } + } else if (_log.settings.display_file_line != 3) { + break; + } + } + if (l) { + if (l->is_obj) { + fprintf(stderr, "%s[%zu] %s[%p] debug: %s\n", file, line, l->name, l, buf); + return; + } + fprintf(stderr, "%s[%zu] %s debug: %s\n", file, line, l->name, buf); + return; + } + fprintf(stderr, "%s[%zu] %s debug: %s\n", file, line, _log.name, buf); + return; + } + + if (l) { + if (l->is_obj) { + fprintf(stderr, "%s[%p] debug: %s\n", l->name, l, buf); + return; + } + fprintf(stderr, "%s debug: %s\n", l->name, buf); + return; + } + fprintf(stderr, "%s debug: %s\n", _log.name, buf); +} + +void core_log_info(const core_log_t* l, const char* file, size_t line, const char* msg, ...) +{ + char buf[512]; + va_list ap; + if (!l) { + if (_log.settings.info != 3) { + return; + } + } else { + if (l->settings.info) { + if (l->settings.info != 3) { + return; + } + } else if (l->module && l->module->info) { + if (l->module->info != 3) { + return; + } + } else if (_log.settings.info != 3) { + return; + } + } + va_start(ap, msg); + vsnprintf(buf, sizeof(buf), msg, ap); + va_end(ap); + buf[sizeof(buf) - 1] = 0; + for (;;) { + if (!l) { + if (_log.settings.display_file_line != 3) { + break; + } + } else { + if (l->settings.display_file_line) { + if (l->settings.display_file_line != 3) { + break; + } + } else if (l->module && l->module->display_file_line) { + if (l->module->display_file_line != 3) { + break; + } + } else if (_log.settings.display_file_line != 3) { + break; + } + } + if (l) { + if (l->is_obj) { + fprintf(stderr, "%s[%zu] %s[%p] info: %s\n", file, line, l->name, l, buf); + return; + } + fprintf(stderr, "%s[%zu] %s info: %s\n", file, line, l->name, buf); + return; + } + fprintf(stderr, "%s[%zu] %s info: %s\n", file, line, _log.name, buf); + return; + } + + if (l) { + if (l->is_obj) { + fprintf(stderr, "%s[%p] info: %s\n", l->name, l, buf); + return; + } + fprintf(stderr, "%s info: %s\n", l->name, buf); + return; + } + fprintf(stderr, "%s info: %s\n", _log.name, buf); +} + +void core_log_notice(const core_log_t* l, const char* file, size_t line, const char* msg, ...) +{ + char buf[512]; + va_list ap; + if (!l) { + if (_log.settings.notice != 3) { + return; + } + } else { + if (l->settings.notice) { + if (l->settings.notice != 3) { + return; + } + } else if (l->module && l->module->notice) { + if (l->module->notice != 3) { + return; + } + } else if (_log.settings.notice != 3) { + return; + } + } + va_start(ap, msg); + vsnprintf(buf, sizeof(buf), msg, ap); + va_end(ap); + buf[sizeof(buf) - 1] = 0; + for (;;) { + if (!l) { + if (_log.settings.display_file_line != 3) { + break; + } + } else { + if (l->settings.display_file_line) { + if (l->settings.display_file_line != 3) { + break; + } + } else if (l->module && l->module->display_file_line) { + if (l->module->display_file_line != 3) { + break; + } + } else if (_log.settings.display_file_line != 3) { + break; + } + } + if (l) { + if (l->is_obj) { + fprintf(stderr, "%s[%zu] %s[%p] notice: %s\n", file, line, l->name, l, buf); + return; + } + fprintf(stderr, "%s[%zu] %s notice: %s\n", file, line, l->name, buf); + return; + } + fprintf(stderr, "%s[%zu] %s notice: %s\n", file, line, _log.name, buf); + return; + } + + if (l) { + if (l->is_obj) { + fprintf(stderr, "%s[%p] notice: %s\n", l->name, l, buf); + return; + } + fprintf(stderr, "%s notice: %s\n", l->name, buf); + return; + } + fprintf(stderr, "%s notice: %s\n", _log.name, buf); +} + +void core_log_warning(const core_log_t* l, const char* file, size_t line, const char* msg, ...) +{ + char buf[512]; + va_list ap; + if (!l) { + if (_log.settings.warning != 3) { + return; + } + } else { + if (l->settings.warning) { + if (l->settings.warning != 3) { + return; + } + } else if (l->module && l->module->warning) { + if (l->module->warning != 3) { + return; + } + } else if (_log.settings.warning != 3) { + return; + } + } + va_start(ap, msg); + vsnprintf(buf, sizeof(buf), msg, ap); + va_end(ap); + buf[sizeof(buf) - 1] = 0; + for (;;) { + if (!l) { + if (_log.settings.display_file_line != 3) { + break; + } + } else { + if (l->settings.display_file_line) { + if (l->settings.display_file_line != 3) { + break; + } + } else if (l->module && l->module->display_file_line) { + if (l->module->display_file_line != 3) { + break; + } + } else if (_log.settings.display_file_line != 3) { + break; + } + } + if (l) { + if (l->is_obj) { + fprintf(stderr, "%s[%zu] %s[%p] warning: %s\n", file, line, l->name, l, buf); + return; + } + fprintf(stderr, "%s[%zu] %s warning: %s\n", file, line, l->name, buf); + return; + } + fprintf(stderr, "%s[%zu] %s warning: %s\n", file, line, _log.name, buf); + return; + } + + if (l) { + if (l->is_obj) { + fprintf(stderr, "%s[%p] warning: %s\n", l->name, l, buf); + return; + } + fprintf(stderr, "%s warning: %s\n", l->name, buf); + return; + } + fprintf(stderr, "%s warning: %s\n", _log.name, buf); +} + +void core_log_critical(const core_log_t* l, const char* file, size_t line, const char* msg, ...) +{ + char buf[512]; + va_list ap; + va_start(ap, msg); + vsnprintf(buf, sizeof(buf), msg, ap); + va_end(ap); + buf[sizeof(buf) - 1] = 0; + for (;;) { + if (!l) { + if (_log.settings.display_file_line != 3) { + break; + } + } else { + if (l->settings.display_file_line) { + if (l->settings.display_file_line != 3) { + break; + } + } else if (l->module && l->module->display_file_line) { + if (l->module->display_file_line != 3) { + break; + } + } else if (_log.settings.display_file_line != 3) { + break; + } + } + if (l) { + if (l->is_obj) { + fprintf(stderr, "%s[%zu] %s[%p] critical: %s\n", file, line, l->name, l, buf); + return; + } + fprintf(stderr, "%s[%zu] %s critical: %s\n", file, line, l->name, buf); + return; + } + fprintf(stderr, "%s[%zu] %s critical: %s\n", file, line, _log.name, buf); + return; + } + + if (l) { + if (l->is_obj) { + fprintf(stderr, "%s[%p] critical: %s\n", l->name, l, buf); + return; + } + fprintf(stderr, "%s critical: %s\n", l->name, buf); + return; + } + fprintf(stderr, "%s critical: %s\n", _log.name, buf); +} + +void core_log_fatal(const core_log_t* l, const char* file, size_t line, const char* msg, ...) +{ + char buf[512]; + va_list ap; + va_start(ap, msg); + vsnprintf(buf, sizeof(buf), msg, ap); + va_end(ap); + buf[sizeof(buf) - 1] = 0; + for (;;) { + if (!l) { + if (_log.settings.display_file_line != 3) { + break; + } + } else { + if (l->settings.display_file_line) { + if (l->settings.display_file_line != 3) { + break; + } + } else if (l->module && l->module->display_file_line) { + if (l->module->display_file_line != 3) { + break; + } + } else if (_log.settings.display_file_line != 3) { + break; + } + } + if (l) { + if (l->is_obj) { + fprintf(stderr, "%s[%zu] %s[%p] fatal: %s\n", file, line, l->name, l, buf); + exit(1); + } + fprintf(stderr, "%s[%zu] %s fatal: %s\n", file, line, l->name, buf); + exit(1); + } + fprintf(stderr, "%s[%zu] %s fatal: %s\n", file, line, _log.name, buf); + exit(1); + } + + if (l) { + if (l->is_obj) { + fprintf(stderr, "%s[%p] fatal: %s\n", l->name, l, buf); + exit(1); + } + fprintf(stderr, "%s fatal: %s\n", l->name, buf); + exit(1); + } + fprintf(stderr, "%s fatal: %s\n", _log.name, buf); + exit(1); +} + +core_log_t* core_log_log() +{ + return &_log; +} + +#include "core/log_errstr.c" diff --git a/include/dnsjit/core/log.h b/include/dnsjit/core/log.h new file mode 100644 index 0000000..05b3db9 --- /dev/null +++ b/include/dnsjit/core/log.h @@ -0,0 +1,105 @@ +/* + * 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/>. + */ + +#ifndef __dnsjit_core_log_h +#define __dnsjit_core_log_h + +#include <stdlib.h> +#include <errno.h> +#include <stdint.h> + +#define LOG_SETTINGS_T_INIT \ + { \ + 0, 0, 0, 0, 0 \ + } +#define LOG_T_INIT(name) \ + { \ + name, 0, LOG_SETTINGS_T_INIT, 0 \ + } +#define LOG_T_INIT_OBJ(name) \ + { \ + name, 1, LOG_SETTINGS_T_INIT, &_log.settings \ + } + +#include <dnsjit/core/log.hh> + +#ifdef DNSJIT_NO_LOGGING +#define ldebug(msg...) +#define linfo(msg...) +#define lnotice(msg...) +#define lwarning(msg...) +#define lcritical(msg...) +#define lpdebug(msg...) +#define lpinfo(msg...) +#define lpnotice(msg...) +#define lpwarning(msg...) +#define lpcritical(msg...) +#define mldebug(msg...) +#define mlinfo(msg...) +#define mlnotice(msg...) +#define mlwarning(msg...) +#define mlcritical(msg...) +#define gldebug(msg...) +#define glinfo(msg...) +#define glnotice(msg...) +#define glwarning(msg...) +#define glcritical(msg...) +#else +#define ldebug(msg...) core_log_debug(&self->_log, __FILE__, __LINE__, msg) +#define linfo(msg...) core_log_info(&self->_log, __FILE__, __LINE__, msg) +#define lnotice(msg...) core_log_notice(&self->_log, __FILE__, __LINE__, msg) +#define lwarning(msg...) core_log_warning(&self->_log, __FILE__, __LINE__, msg) +#define lcritical(msg...) core_log_critical(&self->_log, __FILE__, __LINE__, msg) +#define lpdebug(msg...) core_log_debug(self->_log, __FILE__, __LINE__, msg) +#define lpinfo(msg...) core_log_info(self->_log, __FILE__, __LINE__, msg) +#define lpnotice(msg...) core_log_notice(self->_log, __FILE__, __LINE__, msg) +#define lpwarning(msg...) core_log_warning(self->_log, __FILE__, __LINE__, msg) +#define lpcritical(msg...) core_log_critical(self->_log, __FILE__, __LINE__, msg) +#define mldebug(msg...) core_log_debug(&_log, __FILE__, __LINE__, msg) +#define mlinfo(msg...) core_log_info(&_log, __FILE__, __LINE__, msg) +#define mlnotice(msg...) core_log_notice(&_log, __FILE__, __LINE__, msg) +#define mlwarning(msg...) core_log_warning(&_log, __FILE__, __LINE__, msg) +#define mlcritical(msg...) core_log_critical(&_log, __FILE__, __LINE__, msg) +#define gldebug(msg...) core_log_debug(0, __FILE__, __LINE__, msg) +#define glinfo(msg...) core_log_info(0, __FILE__, __LINE__, msg) +#define glnotice(msg...) core_log_notice(0, __FILE__, __LINE__, msg) +#define glwarning(msg...) core_log_warning(0, __FILE__, __LINE__, msg) +#define glcritical(msg...) core_log_critical(0, __FILE__, __LINE__, msg) +#endif + +#define lfatal(msg...) core_log_fatal(&self->_log, __FILE__, __LINE__, msg) +#define lpfatal(msg...) core_log_fatal(self->_log, __FILE__, __LINE__, msg) +#define mlfatal(msg...) core_log_fatal(&_log, __FILE__, __LINE__, msg) +#define glfatal(msg...) core_log_fatal(0, __FILE__, __LINE__, msg) + +#define lfatal_oom(expression) \ + if (!(expression)) \ + core_log_fatal(&self->_log, __FILE__, __LINE__, "out of memory") +#define lpfatal_oom(expression) \ + if (!(expression)) \ + core_log_fatal(self->_log, __FILE__, __LINE__, "out of memory") +#define mlfatal_oom(expression) \ + if (!(expression)) \ + core_log_fatal(&_log, __FILE__, __LINE__, "out of memory") +#define glfatal_oom(expression) \ + if (!(expression)) \ + core_log_fatal(0, __FILE__, __LINE__, "out of memory") + +#endif diff --git a/include/dnsjit/core/log.hh b/include/dnsjit/core/log.hh new file mode 100644 index 0000000..7273879 --- /dev/null +++ b/include/dnsjit/core/log.hh @@ -0,0 +1,44 @@ +/* + * 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/>. + */ + +typedef struct core_log_settings { + uint8_t debug; + uint8_t info; + uint8_t notice; + uint8_t warning; + uint8_t display_file_line; +} core_log_settings_t; + +typedef struct core_log { + char name[32]; + uint8_t is_obj; + core_log_settings_t settings; + const core_log_settings_t* module; +} core_log_t; + +void core_log_debug(const core_log_t* l, const char* file, size_t line, const char* msg, ...); +void core_log_info(const core_log_t* l, const char* file, size_t line, const char* msg, ...); +void core_log_notice(const core_log_t* l, const char* file, size_t line, const char* msg, ...); +void core_log_warning(const core_log_t* l, const char* file, size_t line, const char* msg, ...); +void core_log_critical(const core_log_t* l, const char* file, size_t line, const char* msg, ...); +void core_log_fatal(const core_log_t* l, const char* file, size_t line, const char* msg, ...); +const char* core_log_errstr(int err); + +core_log_t* core_log_log(); diff --git a/include/dnsjit/core/log.lua b/include/dnsjit/core/log.lua new file mode 100644 index 0000000..d62cbbc --- /dev/null +++ b/include/dnsjit/core/log.lua @@ -0,0 +1,639 @@ +-- 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.log +-- Core logging facility +-- .SS Usage to control global log level +-- local log = require("dnsjit.core.log") +-- log.enable("all") +-- log.disable("debug") +-- .SS Usage to control module log level +-- local example = require("example") -- Example as below +-- example.log():enable("all") +-- example.log():disable("debug") +-- .SS Usage to control object instance log level +-- local example = require("example") -- Example as below +-- local obj = example.new() +-- obj:log():enable("all") +-- obj:log():disable("debug") +-- .SS Usage in C module +-- .B NOTE +-- naming of variables and module only globals are required to exactly as +-- described in order for the macros to work; +-- .B self +-- is the pointer to the object instance, +-- .B self->_log +-- is the object instance logging configuration struct, +-- .B _log +-- is the module logging configuration struct. +-- .LP +-- Include logging: +-- #include "core/log.h" +-- .LP +-- Add the logging struct to the module struct: +-- typedef struct example { +-- core_log_t _log; +-- ... +-- } example_t; +-- .LP +-- Add a module logging configuration and a struct default: +-- static core_log_t _log = LOG_T_INIT("example"); +-- static example_t _defaults = { +-- LOG_T_INIT_OBJ("example"), +-- ... +-- }; +-- .LP +-- Use new/free and/or init/destroy functions (depends if you create the +-- object in Lua or not): +-- example_t* example_new() { +-- example_t* self = calloc(1, sizeof(example_t)); +-- . +-- *self = _defaults; +-- ldebug("new()"); +-- . +-- return self; +-- } +-- . +-- void example_free(example_t* self) { +-- ldebug("free()"); +-- free(self); +-- } +-- . +-- int example_init(example_t* self) { +-- *self = _defaults; +-- . +-- ldebug("init()"); +-- . +-- return 0; +-- } +-- . +-- void example_destroy(example_t* self) { +-- ldebug("destroy()"); +-- ... +-- } +-- .LP +-- In the Lua part of the C module you need to create a function that +-- returns either the object instance Log or the modules Log. +-- .LP +-- Add C function to get module only Log: +-- core_log_t* example_log() { +-- return &_log; +-- } +-- .LP +-- For the structures metatable add the following function: +-- local ffi = require("ffi") +-- local C = ffi.C +-- . +-- function Example:log() +-- if self == nil then +-- return C.example_log() +-- end +-- return self._log +-- end +-- .SS Usage in pure Lua module +-- local log = require("dnsjit.core.log") +-- local ffi = require("ffi") +-- local C = ffi.C +-- . +-- local Example = {} +-- local module_log = log.new("example") +-- . +-- function Example.new() +-- local self = setmetatable({ +-- _log = log.new("example", module_log), +-- }, { __index = Example }) +-- . +-- self._log:debug("new()") +-- . +-- return self +-- end +-- . +-- function Example:log() +-- if self == nil then +-- return module_log +-- end +-- return self._log +-- end +-- +-- Core logging facility used by all modules. +-- .SS Log levels +-- .TP +-- all +-- Keyword to enable/disable all changeable log levels. +-- .TP +-- debug +-- Used for debug information. +-- .TP +-- info +-- Used for informational processing messages. +-- .TP +-- notice +-- Used for messages of that may have impact on processing. +-- .TP +-- warning +-- Used for messages that has impact on processing. +-- .TP +-- critical +-- Used for messages that have severe impact on processing, this level can +-- not be disabled. +-- .TP +-- fatal +-- Used to display a message before stopping all processing and existing, +-- this level can not be disabled. +-- .SS C macros +-- .TP +-- Object instance macros +-- The following macros uses +-- .IR &self->_log : +-- .BR ldebug(msg...) , +-- .BR linfo(msg...) , +-- .BR lnotice(msg...) , +-- .BR lwarning(msg...) , +-- .BR lcritical(msg...) , +-- .BR lfatal(msg...) . +-- .TP +-- Object pointer instance macros +-- The following macros uses +-- .IR self->_log : +-- .BR lpdebug(msg...) , +-- .BR lpinfo(msg...) , +-- .BR lpnotice(msg...) , +-- .BR lpwarning(msg...) , +-- .BR lpcritical(msg...) , +-- .BR lpfatal(msg...) . +-- .TP +-- Module macros +-- The following macros uses +-- .IR &_log : +-- .BR mldebug(msg...) , +-- .BR mlinfo(msg...) , +-- .BR mlnotice(msg...) , +-- .BR mlwarning(msg...) , +-- .BR mlcritical(msg...) , +-- .BR mlfatal(msg...) . +-- .TP +-- Global macros +-- The following macros uses the global logging configuration: +-- .BR gldebug(msg...) , +-- .BR glinfo(msg...) , +-- .BR glnotice(msg...) , +-- .BR glwarning(msg...) , +-- .BR glcritical(msg...) , +-- .BR glfatal(msg...) . +module(...,package.seeall) + +require("dnsjit.core.log_h") +local ffi = require("ffi") +local C = ffi.C +local L = C.core_log_log() + +local t_name = "core_log_t" +local core_log_t +local Log = {} + +-- Create a new Log object with the given module +-- .I name +-- and an optional shared +-- .I module +-- Log object. +function Log.new(name, module) + local self + if ffi.istype(t_name, module) then + self = core_log_t({ is_obj = 1, module = module.settings }) + else + self = core_log_t() + end + + local len = #name + if len > 31 then + len = 31 + end + ffi.copy(self.name, name, len) + self.name[len] = 0 + + return self +end + +-- Enable specified log level. +function Log:enable(level) + if not ffi.istype(t_name, self) then + level = self + self = L + end + if level == "all" then + self.settings.debug = 3 + self.settings.info = 3 + self.settings.notice = 3 + self.settings.warning = 3 + elseif level == "debug" then + self.settings.debug = 3 + elseif level == "info" then + self.settings.info = 3 + elseif level == "notice" then + self.settings.notice = 3 + elseif level == "warning" then + self.settings.warning = 3 + else + error("invalid log level: "..level) + end +end + +-- Disable specified log level. +function Log:disable(level) + if not ffi.istype(t_name, self) then + level = self + self = L + end + if level == "all" then + self.settings.debug = 2 + self.settings.info = 2 + self.settings.notice = 2 + self.settings.warning = 2 + elseif level == "debug" then + self.settings.debug = 2 + elseif level == "info" then + self.settings.info = 2 + elseif level == "notice" then + self.settings.notice = 2 + elseif level == "warning" then + self.settings.warning = 2 + else + error("invalid log level: "..level) + end +end + +-- Clear specified log level, which means it will revert back to default +-- or inherited settings. +function Log:clear(level) + if not ffi.istype(t_name, self) then + level = self + self = L + end + if level == "all" then + self.settings.debug = 0 + self.settings.info = 0 + self.settings.notice = 0 + self.settings.warning = 0 + elseif level == "debug" then + self.settings.debug = 0 + elseif level == "info" then + self.settings.info = 0 + elseif level == "notice" then + self.settings.notice = 0 + elseif level == "warning" then + self.settings.warning = 0 + else + error("invalid log level: "..level) + end +end + +-- Enable or disable the displaying of file and line for messages. +function Log:display_file_line(bool) + if not ffi.istype(t_name, self) then + bool = self + self = L + end + if bool == true then + self.settings.display_file_line = 3 + else + self.settings.display_file_line = 0 + end +end + +-- Convert error number to its text representation. +function Log.errstr(errno) + return ffi.string(C.core_log_errstr(errno)) +end + +-- Generate a debug message. +function Log.debug(self, ...) + local format + if not ffi.istype(t_name, self) then + format = self + self = nil + end + if not self then + if L.settings.debug ~= 3 then + return + end + else + if self.settings.debug ~= 0 then + if self.settings.debug ~= 3 then + return + end + elseif self.module ~= nil and self.module.debug ~= 0 then + if self.module.debug ~= 3 then + return + end + elseif L.settings.debug ~= 3 then + return + end + end + while true do + if not self then + if L.settings.display_file_line ~= 3 then + break + end + else + if self.settings.display_file_line ~= 0 then + if self.settings.display_file_line ~= 3 then + break + end + elseif self.module ~= nil and self.module.display_file_line ~= 0 then + if self.module.display_file_line ~= 3 then + break + end + elseif L.settings.display_file_line ~= 3 then + break + end + end + local info = debug.getinfo(2, "S") + if format then + C.core_log_debug(self, info.source, info.linedefined, format, ...) + return + end + C.core_log_debug(self, info.source, info.linedefined, ...) + return + end + + if format then + C.core_log_debug(self, nil, 0, format, ...) + return + end + C.core_log_debug(self, nil, 0, ...) +end + +-- Generate an info message. +function Log.info(self, ...) + local format + if not ffi.istype(t_name, self) then + format = self + self = nil + end + if not self then + if L.settings.info ~= 3 then + return + end + else + if self.settings.info ~= 0 then + if self.settings.info ~= 3 then + return + end + elseif self.module ~= nil and self.module.info ~= 0 then + if self.module.info ~= 3 then + return + end + elseif L.settings.info ~= 3 then + return + end + end + while true do + if not self then + if L.settings.display_file_line ~= 3 then + break + end + else + if self.settings.display_file_line ~= 0 then + if self.settings.display_file_line ~= 3 then + break + end + elseif self.module ~= nil and self.module.display_file_line ~= 0 then + if self.module.display_file_line ~= 3 then + break + end + elseif L.settings.display_file_line ~= 3 then + break + end + end + local info = debug.getinfo(2, "S") + if format then + C.core_log_info(self, info.source, info.linedefined, format, ...) + return + end + C.core_log_info(self, info.source, info.linedefined, ...) + return + end + + if format then + C.core_log_info(self, nil, 0, format, ...) + return + end + C.core_log_info(self, nil, 0, ...) +end + +-- Generate a notice message. +function Log.notice(self, ...) + local format + if not ffi.istype(t_name, self) then + format = self + self = nil + end + if not self then + if L.settings.notice ~= 3 then + return + end + else + if self.settings.notice ~= 0 then + if self.settings.notice ~= 3 then + return + end + elseif self.module ~= nil and self.module.notice ~= 0 then + if self.module.notice ~= 3 then + return + end + elseif L.settings.notice ~= 3 then + return + end + end + while true do + if not self then + if L.settings.display_file_line ~= 3 then + break + end + else + if self.settings.display_file_line ~= 0 then + if self.settings.display_file_line ~= 3 then + break + end + elseif self.module ~= nil and self.module.display_file_line ~= 0 then + if self.module.display_file_line ~= 3 then + break + end + elseif L.settings.display_file_line ~= 3 then + break + end + end + local info = debug.getinfo(2, "S") + if format then + C.core_log_notice(self, info.source, info.linedefined, format, ...) + return + end + C.core_log_notice(self, info.source, info.linedefined, ...) + return + end + + if format then + C.core_log_notice(self, nil, 0, format, ...) + return + end + C.core_log_notice(self, nil, 0, ...) +end + +-- Generate a warning message. +function Log.warning(self, ...) + local format + if not ffi.istype(t_name, self) then + format = self + self = nil + end + if not self then + if L.settings.warning ~= 3 then + return + end + else + if self.settings.warning ~= 0 then + if self.settings.warning ~= 3 then + return + end + elseif self.module ~= nil and self.module.warning ~= 0 then + if self.module.warning ~= 3 then + return + end + elseif L.settings.warning ~= 3 then + return + end + end + while true do + if not self then + if L.settings.display_file_line ~= 3 then + break + end + else + if self.settings.display_file_line ~= 0 then + if self.settings.display_file_line ~= 3 then + break + end + elseif self.module ~= nil and self.module.display_file_line ~= 0 then + if self.module.display_file_line ~= 3 then + break + end + elseif L.settings.display_file_line ~= 3 then + break + end + end + local info = debug.getinfo(2, "S") + if format then + C.core_log_warning(self, info.source, info.linedefined, format, ...) + return + end + C.core_log_warning(self, info.source, info.linedefined, ...) + return + end + + if format then + C.core_log_warning(self, nil, 0, format, ...) + return + end + C.core_log_warning(self, nil, 0, ...) +end + +-- Generate a critical message. +function Log.critical(self, ...) + local format + if not ffi.istype(t_name, self) then + format = self + self = nil + end + while true do + if not self then + if L.settings.display_file_line ~= 3 then + break + end + else + if self.settings.display_file_line ~= 0 then + if self.settings.display_file_line ~= 3 then + break + end + elseif self.module ~= nil and self.module.display_file_line ~= 0 then + if self.module.display_file_line ~= 3 then + break + end + elseif L.settings.display_file_line ~= 3 then + break + end + end + local info = debug.getinfo(2, "S") + if format then + C.core_log_critical(self, info.source, info.linedefined, format, ...) + return + end + C.core_log_critical(self, info.source, info.linedefined, ...) + return + end + + if format then + C.core_log_critical(self, nil, 0, format, ...) + return + end + C.core_log_critical(self, nil, 0, ...) +end + +-- Generate a fatal message. +function Log.fatal(self, ...) + local format + if not ffi.istype(t_name, self) then + format = self + self = nil + end + while true do + if not self then + if L.settings.display_file_line ~= 3 then + break + end + else + if self.settings.display_file_line ~= 0 then + if self.settings.display_file_line ~= 3 then + break + end + elseif self.module ~= nil and self.module.display_file_line ~= 0 then + if self.module.display_file_line ~= 3 then + break + end + elseif L.settings.display_file_line ~= 3 then + break + end + end + local info = debug.getinfo(2, "S") + if format then + C.core_log_fatal(self, info.source, info.linedefined, format, ...) + return + end + C.core_log_fatal(self, info.source, info.linedefined, ...) + return + end + + if format then + C.core_log_fatal(self, nil, 0, format, ...) + return + end + C.core_log_fatal(self, nil, 0, ...) +end + +core_log_t = ffi.metatype(t_name, { __index = Log }) + +return Log diff --git a/include/dnsjit/core/object.c b/include/dnsjit/core/object.c new file mode 100644 index 0000000..8356f25 --- /dev/null +++ b/include/dnsjit/core/object.c @@ -0,0 +1,135 @@ +/* + * 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 "core/object.h" +#include "core/assert.h" +#include "core/object/pcap.h" +#include "core/object/ether.h" +#include "core/object/null.h" +#include "core/object/loop.h" +#include "core/object/linuxsll.h" +#include "core/object/ieee802.h" +#include "core/object/gre.h" +#include "core/object/ip.h" +#include "core/object/ip6.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 "core/object/dns.h" + +core_object_t* core_object_copy(const core_object_t* self) +{ + glassert_self(); + + switch (self->obj_type) { + case CORE_OBJECT_PCAP: + return (core_object_t*)core_object_pcap_copy((core_object_pcap_t*)self); + case CORE_OBJECT_ETHER: + return (core_object_t*)core_object_ether_copy((core_object_ether_t*)self); + case CORE_OBJECT_NULL: + return (core_object_t*)core_object_null_copy((core_object_null_t*)self); + case CORE_OBJECT_LOOP: + return (core_object_t*)core_object_loop_copy((core_object_loop_t*)self); + case CORE_OBJECT_LINUXSLL: + return (core_object_t*)core_object_linuxsll_copy((core_object_linuxsll_t*)self); + case CORE_OBJECT_IEEE802: + return (core_object_t*)core_object_ieee802_copy((core_object_ieee802_t*)self); + case CORE_OBJECT_GRE: + return (core_object_t*)core_object_gre_copy((core_object_gre_t*)self); + case CORE_OBJECT_IP: + return (core_object_t*)core_object_ip_copy((core_object_ip_t*)self); + case CORE_OBJECT_IP6: + return (core_object_t*)core_object_ip6_copy((core_object_ip6_t*)self); + case CORE_OBJECT_ICMP: + return (core_object_t*)core_object_icmp_copy((core_object_icmp_t*)self); + case CORE_OBJECT_ICMP6: + return (core_object_t*)core_object_icmp6_copy((core_object_icmp6_t*)self); + case CORE_OBJECT_UDP: + return (core_object_t*)core_object_udp_copy((core_object_udp_t*)self); + case CORE_OBJECT_TCP: + return (core_object_t*)core_object_tcp_copy((core_object_tcp_t*)self); + case CORE_OBJECT_PAYLOAD: + return (core_object_t*)core_object_payload_copy((core_object_payload_t*)self); + case CORE_OBJECT_DNS: + return (core_object_t*)core_object_dns_copy((core_object_dns_t*)self); + default: + glfatal("unknown type %d", self->obj_type); + } + return 0; +} + +void core_object_free(core_object_t* self) +{ + glassert_self(); + + switch (self->obj_type) { + case CORE_OBJECT_PCAP: + core_object_pcap_free((core_object_pcap_t*)self); + break; + case CORE_OBJECT_ETHER: + core_object_ether_free((core_object_ether_t*)self); + break; + case CORE_OBJECT_NULL: + core_object_null_free((core_object_null_t*)self); + break; + case CORE_OBJECT_LOOP: + core_object_loop_free((core_object_loop_t*)self); + break; + case CORE_OBJECT_LINUXSLL: + core_object_linuxsll_free((core_object_linuxsll_t*)self); + break; + case CORE_OBJECT_IEEE802: + core_object_ieee802_free((core_object_ieee802_t*)self); + break; + case CORE_OBJECT_GRE: + core_object_gre_free((core_object_gre_t*)self); + break; + case CORE_OBJECT_IP: + core_object_ip_free((core_object_ip_t*)self); + break; + case CORE_OBJECT_IP6: + core_object_ip6_free((core_object_ip6_t*)self); + break; + case CORE_OBJECT_ICMP: + core_object_icmp_free((core_object_icmp_t*)self); + break; + case CORE_OBJECT_ICMP6: + core_object_icmp6_free((core_object_icmp6_t*)self); + break; + case CORE_OBJECT_UDP: + core_object_udp_free((core_object_udp_t*)self); + break; + case CORE_OBJECT_TCP: + core_object_tcp_free((core_object_tcp_t*)self); + break; + case CORE_OBJECT_PAYLOAD: + core_object_payload_free((core_object_payload_t*)self); + break; + case CORE_OBJECT_DNS: + core_object_dns_free((core_object_dns_t*)self); + break; + default: + glfatal("unknown type %d", self->obj_type); + } +} diff --git a/include/dnsjit/core/object.h b/include/dnsjit/core/object.h new file mode 100644 index 0000000..8729cde --- /dev/null +++ b/include/dnsjit/core/object.h @@ -0,0 +1,51 @@ +/* + * 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/>. + */ + +#ifndef __dnsjit_core_object_h +#define __dnsjit_core_object_h + +#define CORE_OBJECT_NONE 0 +#define CORE_OBJECT_PCAP 1 +/* link level objects */ +#define CORE_OBJECT_ETHER 10 +#define CORE_OBJECT_NULL 11 +#define CORE_OBJECT_LOOP 12 +#define CORE_OBJECT_LINUXSLL 13 +#define CORE_OBJECT_IEEE802 14 +#define CORE_OBJECT_GRE 15 +/* protocol objects */ +#define CORE_OBJECT_IP 20 +#define CORE_OBJECT_IP6 21 +#define CORE_OBJECT_ICMP 22 +#define CORE_OBJECT_ICMP6 23 +/* payload carrying objects */ +#define CORE_OBJECT_UDP 30 +#define CORE_OBJECT_TCP 31 +/* payload */ +#define CORE_OBJECT_PAYLOAD 40 +/* service object(s) */ +#define CORE_OBJECT_DNS 50 + +#include <stdint.h> +#include <dnsjit/core/object.hh> + +#define CORE_OBJECT_INIT(type, prev) (core_object_t*)prev, type + +#endif diff --git a/include/dnsjit/core/object.hh b/include/dnsjit/core/object.hh new file mode 100644 index 0000000..b19f858 --- /dev/null +++ b/include/dnsjit/core/object.hh @@ -0,0 +1,28 @@ +/* + * 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 objectd a copy of the GNU General Public License + * along with dnsjit. If not, see <http://www.gnu.org/licenses/>. + */ + +typedef struct core_object core_object_t; +struct core_object { + const core_object_t* obj_prev; + int32_t obj_type; +}; + +core_object_t* core_object_copy(const core_object_t* self); +void core_object_free(core_object_t* self); diff --git a/include/dnsjit/core/object.lua b/include/dnsjit/core/object.lua new file mode 100644 index 0000000..7f58829 --- /dev/null +++ b/include/dnsjit/core/object.lua @@ -0,0 +1,177 @@ +-- 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.object +-- Base object that is passed between receiver and receivee +-- require("dnsjit.core.object") +-- print(object:type()) +-- packet = object:cast() +-- +-- This is the base object that can be casted to other objects that to +-- describe a DNS message, how it was captured or generated. +-- Objects can be chained together, for example a DNS message is created +-- ontop of a packet. +-- .SS Attributes +-- .TP +-- obj_type +-- The enum of the object type. +-- .TP +-- obj_prev +-- The previous object in the object chain. +module(...,package.seeall) + +require("dnsjit.core.object_h") +require("dnsjit.core.object.pcap_h") +require("dnsjit.core.object.ether_h") +require("dnsjit.core.object.null_h") +require("dnsjit.core.object.loop_h") +require("dnsjit.core.object.linuxsll_h") +require("dnsjit.core.object.ieee802_h") +require("dnsjit.core.object.gre_h") +require("dnsjit.core.object.ip_h") +require("dnsjit.core.object.ip6_h") +require("dnsjit.core.object.icmp_h") +require("dnsjit.core.object.icmp6_h") +require("dnsjit.core.object.udp_h") +require("dnsjit.core.object.tcp_h") +require("dnsjit.core.object.payload_h") +require("dnsjit.core.object.dns_h") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "core_object_t" +local core_object_t +local Object = { + NONE = 0, + PCAP = 1, + ETHER = 10, + NULL = 11, + LOOP = 12, + LINUXSLL = 13, + IEEE802 = 14, + GRE = 15, + IP = 20, + IP6 = 21, + ICMP = 22, + ICMP6 = 23, + UDP = 30, + TCP = 31, + PAYLOAD = 40, + DNS = 50 +} + +local _type = {} +_type[Object.PCAP] = "pcap" +_type[Object.ETHER] = "ether" +_type[Object.NULL] = "null" +_type[Object.LOOP] = "loop" +_type[Object.LINUXSLL] = "linuxsll" +_type[Object.IEEE802] = "ieee802" +_type[Object.GRE] = "gre" +_type[Object.IP] = "ip" +_type[Object.IP6] = "ip6" +_type[Object.ICMP] = "icmp" +_type[Object.ICMP6] = "icmp6" +_type[Object.UDP] = "udp" +_type[Object.TCP] = "tcp" +_type[Object.PAYLOAD] = "payload" +_type[Object.DNS] = "dns" + +_type[Object.NONE] = "none" + +-- Return the textual type of the object. +function Object:type() + return _type[self.obj_type] +end + +-- Return the previous object. +function Object:prev() + return self.obj_prev +end + +local _cast = {} +_cast[Object.PCAP] = "core_object_pcap_t*" +_cast[Object.ETHER] = "core_object_ether_t*" +_cast[Object.NULL] = "core_object_null_t*" +_cast[Object.LOOP] = "core_object_loop_t*" +_cast[Object.LINUXSLL] = "core_object_linuxsll_t*" +_cast[Object.IEEE802] = "core_object_ieee802_t*" +_cast[Object.GRE] = "core_object_gre_t*" +_cast[Object.IP] = "core_object_ip_t*" +_cast[Object.IP6] = "core_object_ip6_t*" +_cast[Object.ICMP] = "core_object_icmp_t*" +_cast[Object.ICMP6] = "core_object_icmp6_t*" +_cast[Object.UDP] = "core_object_udp_t*" +_cast[Object.TCP] = "core_object_tcp_t*" +_cast[Object.PAYLOAD] = "core_object_payload_t*" +_cast[Object.DNS] = "core_object_dns_t*" + +-- Cast the object to the underlining object module and return it. +function Object:cast() + return ffi.cast(_cast[self.obj_type], self) +end + +-- Cast the object to the specified object module and return it. +-- Returns nil if the object chain doesn't contained the specified object type. +function Object:cast_to(obj_type) + if obj_type == nil then + obj_type = self.obj_type + end + + local obj = self + while obj.obj_type ~= obj_type do + obj = obj.obj_prev + if obj == nil then return nil end + end + + return ffi.cast(_cast[obj_type], obj) +end + +-- Cast the object to the generic object module and return it. +function Object:uncast() + return self +end + +-- Make a copy of the object and return it. +function Object:copy() + return C.core_object_copy(self) +end + +-- Free the object, should only be used on copies or otherwise allocated. +function Object:free() + C.core_object_free(self) +end + +core_object_t = ffi.metatype(t_name, { __index = Object }) + +-- dnsjit.core.object.pcap (3), +-- dnsjit.core.object.ether (3), +-- dnsjit.core.object.null (3), +-- dnsjit.core.object.loop (3), +-- dnsjit.core.object.linuxsll (3), +-- dnsjit.core.object.ieee802 (3), +-- dnsjit.core.object.gre (3), +-- dnsjit.core.object.ip (3), +-- dnsjit.core.object.ip6 (3), +-- dnsjit.core.object.icmp (3), +-- dnsjit.core.object.icmp6 (3), +-- dnsjit.core.object.udp (3), +-- dnsjit.core.object.tcp (3), +-- dnsjit.core.object.payload (3), +-- dnsjit.core.object.dns (3) +return Object diff --git a/include/dnsjit/core/object/dns.c b/include/dnsjit/core/object/dns.c new file mode 100644 index 0000000..49aec6d --- /dev/null +++ b/include/dnsjit/core/object/dns.c @@ -0,0 +1,471 @@ +/* + * 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 "core/object/dns.h" +#include "core/object/payload.h" +#include "core/assert.h" + +#include <stdlib.h> +#include <string.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 + +#define _ERR_MALFORMED -2 +#define _ERR_NEEDLABELS -3 + +static core_log_t _log = LOG_T_INIT("core.object.dns"); +static core_object_dns_t _defaults = CORE_OBJECT_DNS_INIT(0); + +static core_object_dns_label_t _defaults_label = { 0 }; +static core_object_dns_rr_t _defaults_rr = { 0 }; +static core_object_dns_q_t _defaults_q = { 0 }; + +core_log_t* core_object_dns_log() +{ + return &_log; +} + +core_object_dns_t* core_object_dns_new() +{ + core_object_dns_t* self; + + mlfatal_oom(self = malloc(sizeof(core_object_dns_t))); + *self = _defaults; + + return self; +} + +core_object_dns_t* core_object_dns_copy(const core_object_dns_t* self) +{ + core_object_dns_t* copy; + mlassert_self(); + + mlfatal_oom(copy = malloc(sizeof(core_object_dns_t))); + memcpy(copy, self, sizeof(core_object_dns_t)); + copy->obj_prev = 0; + + return (core_object_dns_t*)copy; +} + +void core_object_dns_free(core_object_dns_t* self) +{ + mlassert_self(); + free(self); +} + +#define need8(v, p, l) \ + if (l < 1) { \ + break; \ + } \ + v = *p; \ + p += 1; \ + l -= 1 + +static inline uint16_t _need16(const void* ptr) +{ + uint16_t v; + memcpy(&v, ptr, sizeof(v)); + return be16toh(v); +} + +#define need16(v, p, l) \ + if (l < 2) { \ + break; \ + } \ + v = _need16(p); \ + p += 2; \ + l -= 2 + +static inline uint32_t _need32(const void* ptr) +{ + uint32_t v; + memcpy(&v, ptr, sizeof(v)); + return be32toh(v); +} + +#define need32(v, p, l) \ + if (l < 4) { \ + break; \ + } \ + v = _need32(p); \ + p += 4; \ + l -= 4 + +#define needxb(b, x, p, l) \ + if (l < x) { \ + break; \ + } \ + memcpy(b, p, x); \ + p += x; \ + l -= x + +#define advancexb(x, p, l) \ + if (l < x) { \ + break; \ + } \ + p += x; \ + l -= x + +int core_object_dns_parse_header(core_object_dns_t* self) +{ + const core_object_payload_t* payload; + uint8_t byte; + mlassert_self(); + + if (!(payload = (core_object_payload_t*)self->obj_prev) || payload->obj_type != CORE_OBJECT_PAYLOAD) { + mlfatal("no obj_prev or invalid type"); + } + if (!payload->payload || !payload->len) { + mlfatal("no payload set or zero length"); + } + + self->payload = self->at = payload->payload; + self->len = self->left = payload->len; + + for (;;) { + if (self->includes_dnslen) { + need16(self->dnslen, self->at, self->left); + self->have_dnslen = 1; + } + need16(self->id, self->at, self->left); + self->have_id = 1; + + need8(byte, self->at, self->left); + self->qr = byte & (1 << 7) ? 1 : 0; + self->opcode = (byte >> 3) & 0xf; + self->aa = byte & (1 << 2) ? 1 : 0; + self->tc = byte & (1 << 1) ? 1 : 0; + self->rd = byte & (1 << 0) ? 1 : 0; + self->have_qr = self->have_opcode = self->have_aa = self->have_tc = self->have_rd = 1; + + need8(byte, self->at, self->left); + self->ra = byte & (1 << 7) ? 1 : 0; + self->z = byte & (1 << 6) ? 1 : 0; + self->ad = byte & (1 << 5) ? 1 : 0; + self->cd = byte & (1 << 4) ? 1 : 0; + self->rcode = byte & 0xf; + self->have_ra = self->have_z = self->have_ad = self->have_cd = self->have_rcode = 1; + + need16(self->qdcount, self->at, self->left); + self->have_qdcount = 1; + + need16(self->ancount, self->at, self->left); + self->have_ancount = 1; + + need16(self->nscount, self->at, self->left); + self->have_nscount = 1; + + need16(self->arcount, self->at, self->left); + self->have_arcount = 1; + + return 0; + } + + // TODO: error here on malformed/truncated? could be quite spammy + return _ERR_MALFORMED; +} + +static inline size_t _rdata_labels(uint16_t type) +{ + switch (type) { + case CORE_OBJECT_DNS_TYPE_NS: + case CORE_OBJECT_DNS_TYPE_MD: + case CORE_OBJECT_DNS_TYPE_MF: + case CORE_OBJECT_DNS_TYPE_CNAME: + case CORE_OBJECT_DNS_TYPE_MB: + case CORE_OBJECT_DNS_TYPE_MG: + case CORE_OBJECT_DNS_TYPE_MR: + case CORE_OBJECT_DNS_TYPE_PTR: + case CORE_OBJECT_DNS_TYPE_NXT: + case CORE_OBJECT_DNS_TYPE_DNAME: + case CORE_OBJECT_DNS_TYPE_NSEC: + case CORE_OBJECT_DNS_TYPE_TKEY: + case CORE_OBJECT_DNS_TYPE_TSIG: + return 1; + + case CORE_OBJECT_DNS_TYPE_SOA: + case CORE_OBJECT_DNS_TYPE_MINFO: + case CORE_OBJECT_DNS_TYPE_RP: + case CORE_OBJECT_DNS_TYPE_TALINK: + return 2; + + case CORE_OBJECT_DNS_TYPE_MX: + case CORE_OBJECT_DNS_TYPE_AFSDB: + case CORE_OBJECT_DNS_TYPE_RT: + case CORE_OBJECT_DNS_TYPE_KX: + case CORE_OBJECT_DNS_TYPE_LP: + return 1; + + case CORE_OBJECT_DNS_TYPE_PX: + return 2; + + case CORE_OBJECT_DNS_TYPE_SIG: + case CORE_OBJECT_DNS_TYPE_RRSIG: + return 1; + + case CORE_OBJECT_DNS_TYPE_SRV: + return 1; + + case CORE_OBJECT_DNS_TYPE_NAPTR: + return 1; + + case CORE_OBJECT_DNS_TYPE_HIP: + return 1; + + default: + break; + } + + return 0; +} + +static inline size_t _label(core_object_dns_t* self, core_object_dns_label_t* label, size_t labels) +{ + size_t n; + + for (n = 0; self->left && n < labels; n++) { + core_object_dns_label_t* l = &label[n]; + *l = _defaults_label; + + need8(l->length, self->at, self->left); + + if ((l->length & 0xc0) == 0xc0) { + need8(l->offset, self->at, self->left); + l->offset |= (l->length & 0x3f) << 8; + l->have_offset = 1; + return n; + } else if (l->length & 0xc0) { + l->extension_bits = l->length >> 6; + l->have_extension_bits = 1; + return n; + } else if (l->length) { + l->have_length = 1; + + l->offset = self->at - self->payload - 1; + advancexb(l->length, self->at, self->left); + l->have_dn = 1; + } else { + l->is_end = 1; + return n; + } + } + + return n; +} + +int core_object_dns_parse_q(core_object_dns_t* self, core_object_dns_q_t* q, core_object_dns_label_t* label, size_t labels) +{ + mlassert_self(); + mlassert(q, "q is nil"); + mlassert(label, "label is nil"); + mlassert(labels, "labels is zero"); + mlassert(self->at, "at is nil"); + + for (;;) { + *q = _defaults_q; + q->labels = _label(self, label, labels); + if (q->labels < labels) { + core_object_dns_label_t* l = &label[q->labels]; + if (!(l->have_offset | l->have_extension_bits | l->is_end)) { + // TODO: error here on malformed/truncated? could be quite spammy + return _ERR_MALFORMED; + } + } else { + mlwarning("need more labels, aborting DNS parsing"); + return _ERR_NEEDLABELS; + } + q->labels++; + + need16(q->type, self->at, self->left); + q->have_type = 1; + + need16(q->class, self->at, self->left); + q->have_class = 1; + + return 0; + } + + // TODO: error here on malformed/truncated? could be quite spammy + return _ERR_MALFORMED; +} + +int core_object_dns_parse_rr(core_object_dns_t* self, core_object_dns_rr_t* rr, core_object_dns_label_t* label, size_t labels) +{ + size_t rdata_label_sets; + mlassert_self(); + mlassert(rr, "rr is nil"); + mlassert(label, "label is nil"); + mlassert(labels, "labels is zero"); + mlassert(self->at, "at is nil"); + + for (;;) { + *rr = _defaults_rr; + rr->labels = _label(self, label, labels); + if (rr->labels < labels) { + core_object_dns_label_t* l = &label[rr->labels]; + if (!(l->have_offset | l->have_extension_bits | l->is_end)) { + // TODO: error here on malformed/truncated? could be quite spammy + return _ERR_MALFORMED; + } + } else { + mlwarning("need more labels, aborting DNS parsing"); + return _ERR_NEEDLABELS; + } + rr->labels++; + + need16(rr->type, self->at, self->left); + rr->have_type = 1; + + need16(rr->class, self->at, self->left); + rr->have_class = 1; + + need32(rr->ttl, self->at, self->left); + rr->have_ttl = 1; + + need16(rr->rdlength, self->at, self->left); + rr->have_rdlength = 1; + + rr->rdata_offset = self->at - self->payload; + if (!(rdata_label_sets = _rdata_labels(rr->type))) { + advancexb(rr->rdlength, self->at, self->left); + rr->have_rdata = 1; + return 0; + } + + switch (rr->type) { + case CORE_OBJECT_DNS_TYPE_MX: + case CORE_OBJECT_DNS_TYPE_AFSDB: + case CORE_OBJECT_DNS_TYPE_RT: + case CORE_OBJECT_DNS_TYPE_KX: + case CORE_OBJECT_DNS_TYPE_LP: + case CORE_OBJECT_DNS_TYPE_PX: + advancexb(2, self->at, self->left); + break; + + case CORE_OBJECT_DNS_TYPE_SIG: + case CORE_OBJECT_DNS_TYPE_RRSIG: + advancexb(18, self->at, self->left); + break; + + case CORE_OBJECT_DNS_TYPE_SRV: + advancexb(6, self->at, self->left); + break; + + case CORE_OBJECT_DNS_TYPE_NAPTR: { + uint8_t naptr_length; + + advancexb(4, self->at, self->left); + need8(naptr_length, self->at, self->left); + advancexb(naptr_length, self->at, self->left); + need8(naptr_length, self->at, self->left); + advancexb(naptr_length, self->at, self->left); + need8(naptr_length, self->at, self->left); + advancexb(naptr_length, self->at, self->left); + } break; + + case CORE_OBJECT_DNS_TYPE_HIP: { + uint8_t hit_length; + uint16_t pk_length; + + need8(hit_length, self->at, self->left); + advancexb(1, self->at, self->left); + need16(pk_length, self->at, self->left); + advancexb(hit_length, self->at, self->left); + advancexb(pk_length, self->at, self->left); + + if (self->at - self->payload >= rr->rdata_offset + rr->rdlength) { + rdata_label_sets = 0; + } + } break; + } + + while (rdata_label_sets) { + rr->rdata_labels += _label(self, &label[rr->labels + rr->rdata_labels], labels - rr->labels - rr->rdata_labels); + if (rr->labels + rr->rdata_labels < labels) { + core_object_dns_label_t* l = &label[rr->labels + rr->rdata_labels]; + if (!(l->have_offset | l->have_extension_bits | l->is_end)) { + // TODO: error here on malformed/truncated? could be quite spammy + return _ERR_MALFORMED; + } + } else { + mlwarning("need more labels, aborting DNS parsing"); + return _ERR_NEEDLABELS; + } + rr->rdata_labels++; + + if (rr->type == CORE_OBJECT_DNS_TYPE_HIP && self->at - self->payload < rr->rdata_offset + rr->rdlength) { + continue; + } + + rdata_label_sets--; + } + + if (self->at - self->payload < rr->rdata_offset + rr->rdlength) { + rr->padding_offset = self->at - self->payload; + rr->padding_length = rr->rdlength - (rr->padding_offset - rr->rdata_offset); + + advancexb(rr->padding_length, self->at, self->left); + + /* + * TODO: + * + * This can indicate padding but we do not set that we have padding + * yet because we need to fully understand all record types before + * that and process valid data after the labels + * + rr->have_padding = 1; + */ + } else if (self->at - self->payload > rr->rdata_offset + rr->rdlength) { + // TODO: error here on malformed/truncated? could be quite spammy + return _ERR_MALFORMED; + } + rr->have_rdata = 1; + + return 0; + } + + // TODO: error here on malformed/truncated? could be quite spammy + return _ERR_MALFORMED; +} diff --git a/include/dnsjit/core/object/dns.h b/include/dnsjit/core/object/dns.h new file mode 100644 index 0000000..68a2dc9 --- /dev/null +++ b/include/dnsjit/core/object/dns.h @@ -0,0 +1,184 @@ +/* + * 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/object.h> + +#ifndef __dnsjit_core_object_dns_h +#define __dnsjit_core_object_dns_h + +#include <netinet/in.h> +#include <sys/types.h> + +#include <dnsjit/core/object/dns.hh> + +#define CORE_OBJECT_DNS_INIT(prev) \ + { \ + CORE_OBJECT_INIT(CORE_OBJECT_DNS, prev) \ + , \ + 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + } + +/* + * 2016-12-09 https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml + */ + +#define CORE_OBJECT_DNS_CLASS_IN 1 +#define CORE_OBJECT_DNS_CLASS_CH 3 +#define CORE_OBJECT_DNS_CLASS_HS 4 +#define CORE_OBJECT_DNS_CLASS_NONE 254 +#define CORE_OBJECT_DNS_CLASS_ANY 255 + +#define CORE_OBJECT_DNS_TYPE_A 1 +#define CORE_OBJECT_DNS_TYPE_NS 2 +#define CORE_OBJECT_DNS_TYPE_MD 3 +#define CORE_OBJECT_DNS_TYPE_MF 4 +#define CORE_OBJECT_DNS_TYPE_CNAME 5 +#define CORE_OBJECT_DNS_TYPE_SOA 6 +#define CORE_OBJECT_DNS_TYPE_MB 7 +#define CORE_OBJECT_DNS_TYPE_MG 8 +#define CORE_OBJECT_DNS_TYPE_MR 9 +#define CORE_OBJECT_DNS_TYPE_NULL 10 +#define CORE_OBJECT_DNS_TYPE_WKS 11 +#define CORE_OBJECT_DNS_TYPE_PTR 12 +#define CORE_OBJECT_DNS_TYPE_HINFO 13 +#define CORE_OBJECT_DNS_TYPE_MINFO 14 +#define CORE_OBJECT_DNS_TYPE_MX 15 +#define CORE_OBJECT_DNS_TYPE_TXT 16 +#define CORE_OBJECT_DNS_TYPE_RP 17 +#define CORE_OBJECT_DNS_TYPE_AFSDB 18 +#define CORE_OBJECT_DNS_TYPE_X25 19 +#define CORE_OBJECT_DNS_TYPE_ISDN 20 +#define CORE_OBJECT_DNS_TYPE_RT 21 +#define CORE_OBJECT_DNS_TYPE_NSAP 22 +#define CORE_OBJECT_DNS_TYPE_NSAP_PTR 23 +#define CORE_OBJECT_DNS_TYPE_SIG 24 +#define CORE_OBJECT_DNS_TYPE_KEY 25 +#define CORE_OBJECT_DNS_TYPE_PX 26 +#define CORE_OBJECT_DNS_TYPE_GPOS 27 +#define CORE_OBJECT_DNS_TYPE_AAAA 28 +#define CORE_OBJECT_DNS_TYPE_LOC 29 +#define CORE_OBJECT_DNS_TYPE_NXT 30 +#define CORE_OBJECT_DNS_TYPE_EID 31 +#define CORE_OBJECT_DNS_TYPE_NIMLOC 32 +#define CORE_OBJECT_DNS_TYPE_SRV 33 +#define CORE_OBJECT_DNS_TYPE_ATMA 34 +#define CORE_OBJECT_DNS_TYPE_NAPTR 35 +#define CORE_OBJECT_DNS_TYPE_KX 36 +#define CORE_OBJECT_DNS_TYPE_CERT 37 +#define CORE_OBJECT_DNS_TYPE_A6 38 +#define CORE_OBJECT_DNS_TYPE_DNAME 39 +#define CORE_OBJECT_DNS_TYPE_SINK 40 +#define CORE_OBJECT_DNS_TYPE_OPT 41 +#define CORE_OBJECT_DNS_TYPE_APL 42 +#define CORE_OBJECT_DNS_TYPE_DS 43 +#define CORE_OBJECT_DNS_TYPE_SSHFP 44 +#define CORE_OBJECT_DNS_TYPE_IPSECKEY 45 +#define CORE_OBJECT_DNS_TYPE_RRSIG 46 +#define CORE_OBJECT_DNS_TYPE_NSEC 47 +#define CORE_OBJECT_DNS_TYPE_DNSKEY 48 +#define CORE_OBJECT_DNS_TYPE_DHCID 49 +#define CORE_OBJECT_DNS_TYPE_NSEC3 50 +#define CORE_OBJECT_DNS_TYPE_NSEC3PARAM 51 +#define CORE_OBJECT_DNS_TYPE_TLSA 52 +#define CORE_OBJECT_DNS_TYPE_SMIMEA 53 +#define CORE_OBJECT_DNS_TYPE_HIP 55 +#define CORE_OBJECT_DNS_TYPE_NINFO 56 +#define CORE_OBJECT_DNS_TYPE_RKEY 57 +#define CORE_OBJECT_DNS_TYPE_TALINK 58 +#define CORE_OBJECT_DNS_TYPE_CDS 59 +#define CORE_OBJECT_DNS_TYPE_CDNSKEY 60 +#define CORE_OBJECT_DNS_TYPE_OPENPGPKEY 61 +#define CORE_OBJECT_DNS_TYPE_CSYNC 62 +#define CORE_OBJECT_DNS_TYPE_SPF 99 +#define CORE_OBJECT_DNS_TYPE_UINFO 100 +#define CORE_OBJECT_DNS_TYPE_UID 101 +#define CORE_OBJECT_DNS_TYPE_GID 102 +#define CORE_OBJECT_DNS_TYPE_UNSPEC 103 +#define CORE_OBJECT_DNS_TYPE_NID 104 +#define CORE_OBJECT_DNS_TYPE_L32 105 +#define CORE_OBJECT_DNS_TYPE_L64 106 +#define CORE_OBJECT_DNS_TYPE_LP 107 +#define CORE_OBJECT_DNS_TYPE_EUI48 108 +#define CORE_OBJECT_DNS_TYPE_EUI64 109 +#define CORE_OBJECT_DNS_TYPE_TKEY 249 +#define CORE_OBJECT_DNS_TYPE_TSIG 250 +#define CORE_OBJECT_DNS_TYPE_IXFR 251 +#define CORE_OBJECT_DNS_TYPE_AXFR 252 +#define CORE_OBJECT_DNS_TYPE_MAILB 253 +#define CORE_OBJECT_DNS_TYPE_MAILA 254 +#define CORE_OBJECT_DNS_TYPE_ANY 255 +#define CORE_OBJECT_DNS_TYPE_URI 256 +#define CORE_OBJECT_DNS_TYPE_CAA 257 +#define CORE_OBJECT_DNS_TYPE_AVC 258 +#define CORE_OBJECT_DNS_TYPE_TA 32768 +#define CORE_OBJECT_DNS_TYPE_DLV 32769 + +#define CORE_OBJECT_DNS_OPCODE_QUERY 0 +#define CORE_OBJECT_DNS_OPCODE_IQUERY 1 +#define CORE_OBJECT_DNS_OPCODE_STATUS 2 +#define CORE_OBJECT_DNS_OPCODE_NOTIFY 4 +#define CORE_OBJECT_DNS_OPCODE_UPDATE 5 + +#define CORE_OBJECT_DNS_RCODE_NOERROR 0 +#define CORE_OBJECT_DNS_RCODE_FORMERR 1 +#define CORE_OBJECT_DNS_RCODE_SERVFAIL 2 +#define CORE_OBJECT_DNS_RCODE_NXDOMAIN 3 +#define CORE_OBJECT_DNS_RCODE_NOTIMP 4 +#define CORE_OBJECT_DNS_RCODE_REFUSED 5 +#define CORE_OBJECT_DNS_RCODE_YXDOMAIN 6 +#define CORE_OBJECT_DNS_RCODE_YXRRSET 7 +#define CORE_OBJECT_DNS_RCODE_NXRRSET 8 +#define CORE_OBJECT_DNS_RCODE_NOTAUTH 9 +#define CORE_OBJECT_DNS_RCODE_NOTZONE 10 +#define CORE_OBJECT_DNS_RCODE_BADVERS 16 +#define CORE_OBJECT_DNS_RCODE_BADSIG 16 +#define CORE_OBJECT_DNS_RCODE_BADKEY 17 +#define CORE_OBJECT_DNS_RCODE_BADTIME 18 +#define CORE_OBJECT_DNS_RCODE_BADMODE 19 +#define CORE_OBJECT_DNS_RCODE_BADNAME 20 +#define CORE_OBJECT_DNS_RCODE_BADALG 21 +#define CORE_OBJECT_DNS_RCODE_BADTRUNC 22 +#define CORE_OBJECT_DNS_RCODE_BADCOOKIE 23 + +#define CORE_OBJECT_DNS_AFSDB_SUBTYPE_AFS3LOCSRV 1 +#define CORE_OBJECT_DNS_AFSDB_SUBTYPE_DCENCA_ROOT 2 + +#define CORE_OBJECT_DNS_DHCID_TYPE_1OCTET 0 +#define CORE_OBJECT_DNS_DHCID_TYPE_DATAOCTET 1 +#define CORE_OBJECT_DNS_DHCID_TYPE_CLIENT_DUID 2 + +#define CORE_OBJECT_DNS_EDNS0_OPT_LLQ 1 +#define CORE_OBJECT_DNS_EDNS0_OPT_UL 2 +#define CORE_OBJECT_DNS_EDNS0_OPT_NSID 3 +#define CORE_OBJECT_DNS_EDNS0_OPT_DAU 5 +#define CORE_OBJECT_DNS_EDNS0_OPT_DHU 6 +#define CORE_OBJECT_DNS_EDNS0_OPT_N3U 7 +#define CORE_OBJECT_DNS_EDNS0_OPT_CLIENT_SUBNET 8 +#define CORE_OBJECT_DNS_EDNS0_OPT_EXPIRE 9 +#define CORE_OBJECT_DNS_EDNS0_OPT_COOKIE 10 +#define CORE_OBJECT_DNS_EDNS0_OPT_TCP_KEEPALIVE 11 +#define CORE_OBJECT_DNS_EDNS0_OPT_PADDING 12 +#define CORE_OBJECT_DNS_EDNS0_OPT_CHAIN 13 +#define CORE_OBJECT_DNS_EDNS0_OPT_DEVICEID 26946 + +#endif diff --git a/include/dnsjit/core/object/dns.hh b/include/dnsjit/core/object/dns.hh new file mode 100644 index 0000000..dfe9719 --- /dev/null +++ b/include/dnsjit/core/object/dns.hh @@ -0,0 +1,119 @@ +/* + * 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.object_h") + +typedef struct core_object_dns_label { + uint8_t is_end; + uint8_t have_length; + uint8_t have_offset; + uint8_t have_extension_bits; + uint8_t have_dn; + uint8_t extension_bits; + + uint8_t length; + uint16_t offset; +} core_object_dns_label_t; + +typedef struct core_object_dns_rr { + uint8_t have_type; + uint8_t have_class; + uint8_t have_ttl; + uint8_t have_rdlength; + uint8_t have_rdata; + uint8_t have_rdata_labels; + uint8_t have_padding; + + uint16_t type; + uint16_t class; + uint32_t ttl; + uint16_t rdlength; + + size_t labels; + size_t rdata_offset; + size_t rdata_labels; + size_t padding_offset; + size_t padding_length; +} core_object_dns_rr_t; + +typedef struct core_object_dns_q { + uint8_t have_type; + uint8_t have_class; + + uint16_t type; + uint16_t class; + + size_t labels; +} core_object_dns_q_t; + +typedef struct core_object_dns { + const core_object_t* obj_prev; + int32_t obj_type; + + int includes_dnslen; + const uint8_t *payload, *at; + size_t len, left; + + uint8_t have_dnslen; + uint8_t have_id; + uint8_t have_qr; + uint8_t have_opcode; + uint8_t have_aa; + uint8_t have_tc; + uint8_t have_rd; + uint8_t have_ra; + uint8_t have_z; + uint8_t have_ad; + uint8_t have_cd; + uint8_t have_rcode; + uint8_t have_qdcount; + uint8_t have_ancount; + uint8_t have_nscount; + uint8_t have_arcount; + + uint16_t dnslen; + uint16_t id; + int8_t qr; + uint8_t opcode; + uint8_t aa; + uint8_t tc; + uint8_t rd; + uint8_t ra; + uint8_t z; + uint8_t ad; + uint8_t cd; + uint8_t rcode; + uint16_t qdcount; + uint16_t ancount; + uint16_t nscount; + uint16_t arcount; +} core_object_dns_t; + +core_log_t* core_object_dns_log(); + +core_object_dns_t* core_object_dns_new(); +core_object_dns_t* core_object_dns_copy(const core_object_dns_t* self); +void core_object_dns_free(core_object_dns_t* self); +void core_object_dns_reset(core_object_dns_t* self, const core_object_t* obj); + +int core_object_dns_parse_header(core_object_dns_t* self); +int core_object_dns_parse_q(core_object_dns_t* self, core_object_dns_q_t* q, core_object_dns_label_t* label, size_t labels); +int core_object_dns_parse_rr(core_object_dns_t* self, core_object_dns_rr_t* rr, core_object_dns_label_t* label, size_t labels); diff --git a/include/dnsjit/core/object/dns.lua b/include/dnsjit/core/object/dns.lua new file mode 100644 index 0000000..e8fb12b --- /dev/null +++ b/include/dnsjit/core/object/dns.lua @@ -0,0 +1,797 @@ +-- 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.object.dns +-- Container of a DNS message +-- .SS Parse DNS header and check if query or response +-- local dns = require("dnsjit.core.object.dns").new(payload) +-- if dns:parse_header() == 0 then +-- if dns.qr == 0 then +-- print(dns.id, dns.opcode_tostring(dns.opcode)) +-- else +-- print(dns.id, dns.rcode_tostring(dns.rcode)) +-- end +-- end +-- .SS Print a DNS payload +-- local dns = require("dnsjit.core.object.dns").new(payload) +-- dns:print() +-- .SS Parse a DNS payload +-- local dns = require("dnsjit.core.object.dns").new(payload) +-- local qs, q_labels, rrs, rr_labels = dns:parse() +-- if qs and q_labels then +-- ... +-- if rrs and rr_labels then +-- ... +-- end +-- end +-- +-- The object that describes a DNS message. +-- .SS Attributes +-- .TP +-- includes_dnslen +-- If non-zero then this indicates that the DNS length is included in the +-- payload (for example if the transport is TCP) and will affect parsing of it. +-- .TP +-- have_dnslen +-- Set if the dnslen was included in the payload and could be read. +-- .TP +-- have_id +-- Set if there is a DNS ID. +-- .TP +-- have_qr +-- Set if there is a QR flag. +-- .TP +-- have_opcode +-- Set if there is an OPCODE. +-- .TP +-- have_aa +-- Set if there is a AA flag. +-- .TP +-- have_tc +-- Set if there is a TC flag. +-- .TP +-- have_rd +-- Set if there is a RD flag. +-- .TP +-- have_ra +-- Set if there is a RA flag. +-- .TP +-- have_z +-- Set if there is a Z flag. +-- .TP +-- have_ad +-- Set if there is a AD flag. +-- .TP +-- have_cd +-- Set if there is a CD flag. +-- .TP +-- have_rcode +-- Set if there is a RCODE. +-- .TP +-- have_qdcount +-- Set if there is an QDCOUNT. +-- .TP +-- have_ancount +-- Set if there is an ANCOUNT. +-- .TP +-- have_nscount +-- Set if there is a NSCOUNT. +-- .TP +-- have_arcount +-- Set if there is an ARCOUNT. +-- .TP +-- dnslen +-- The DNS length found in the payload. +-- .TP +-- id +-- The DNS ID. +-- .TP +-- qr +-- The QR flag. +-- .TP +-- opcode +-- The OPCODE. +-- .TP +-- aa +-- The AA flag. +-- .TP +-- tc +-- The TC flag. +-- .TP +-- rd +-- The RD flag. +-- .TP +-- ra +-- The RA flag. +-- .TP +-- z +-- The Z flag. +-- .TP +-- ad +-- The AD flag. +-- .TP +-- cd +-- The CD flag. +-- .TP +-- rcode +-- The RCODE. +-- .TP +-- qdcount +-- The QDCOUNT. +-- .TP +-- ancount +-- The ANCOUNT. +-- .TP +-- nscount +-- The NSCOUNT. +-- .TP +-- arcount +-- The ARCOUNT. +-- .SS Constants +-- The following tables exists for DNS parameters, taken from +-- .I https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml +-- on the 2016-12-09. +-- .LP +-- .IR CLASS , +-- .IR CLASS_STR , +-- .IR TYPE , +-- .IR TYPE_STR , +-- .IR OPCODE , +-- .IR OPCODE_STR , +-- .IR RCODE , +-- .IR RCODE_STR , +-- .IR AFSDB , +-- .IR AFSDB_STR , +-- .IR DHCID , +-- .IR DHCID_STR , +-- .IR ENDS0 , +-- .IR ENDS0_STR +-- .LP +-- The +-- .I *_STR +-- tables can be used to get a textual representation of the numbers, see also +-- .IR class_tostring() , +-- .IR type_tostring() , +-- .IR opcode_tostring() , +-- .IR rcode_tostring() , +-- .IR afsdb_tostring() , +-- .I dhcid_tostring() +-- and +-- .IR edns0_tostring() . +module(...,package.seeall) + +require("dnsjit.core.object.dns_h") +local label = require("dnsjit.core.object.dns.label") +local Q = require("dnsjit.core.object.dns.q") +local RR = require("dnsjit.core.object.dns.rr") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "core_object_dns_t" +local core_object_dns_t +local Dns = { + CLASS = { + IN = 1, + CH = 3, + HS = 4, + NONE = 254, + ANY = 255, + }, + TYPE = { + A = 1, + NS = 2, + MD = 3, + MF = 4, + CNAME = 5, + SOA = 6, + MB = 7, + MG = 8, + MR = 9, + NULL = 10, + WKS = 11, + PTR = 12, + HINFO = 13, + MINFO = 14, + MX = 15, + TXT = 16, + RP = 17, + AFSDB = 18, + X25 = 19, + ISDN = 20, + RT = 21, + NSAP = 22, + NSAP_PTR = 23, + SIG = 24, + KEY = 25, + PX = 26, + GPOS = 27, + AAAA = 28, + LOC = 29, + NXT = 30, + EID = 31, + NIMLOC = 32, + SRV = 33, + ATMA = 34, + NAPTR = 35, + KX = 36, + CERT = 37, + A6 = 38, + DNAME = 39, + SINK = 40, + OPT = 41, + APL = 42, + DS = 43, + SSHFP = 44, + IPSECKEY = 45, + RRSIG = 46, + NSEC = 47, + DNSKEY = 48, + DHCID = 49, + NSEC3 = 50, + NSEC3PARAM = 51, + TLSA = 52, + SMIMEA = 53, + HIP = 55, + NINFO = 56, + RKEY = 57, + TALINK = 58, + CDS = 59, + CDNSKEY = 60, + OPENPGPKEY = 61, + CSYNC = 62, + SPF = 99, + UINFO = 100, + UID = 101, + GID = 102, + UNSPEC = 103, + NID = 104, + L32 = 105, + L64 = 106, + LP = 107, + EUI48 = 108, + EUI64 = 109, + TKEY = 249, + TSIG = 250, + IXFR = 251, + AXFR = 252, + MAILB = 253, + MAILA = 254, + ANY = 255, + URI = 256, + CAA = 257, + AVC = 258, + TA = 32768, + DLV = 32769, + }, + OPCODE = { + QUERY = 0, + IQUERY = 1, + STATUS = 2, + NOTIFY = 4, + UPDATE = 5, + }, + RCODE = { + NOERROR = 0, + FORMERR = 1, + SERVFAIL = 2, + NXDOMAIN = 3, + NOTIMP = 4, + REFUSED = 5, + YXDOMAIN = 6, + YXRRSET = 7, + NXRRSET = 8, + NOTAUTH = 9, + NOTZONE = 10, + BADVERS = 16, + BADSIG = 16, + BADKEY = 17, + BADTIME = 18, + BADMODE = 19, + BADNAME = 20, + BADALG = 21, + BADTRUNC = 22, + BADCOOKIE = 23, + }, + AFSDB = { + SUBTYPE_AFS3LOCSRV = 1, + SUBTYPE_DCENCA_ROOT = 2, + }, + DHCID = { + TYPE_1OCTET = 0, + TYPE_DATAOCTET = 1, + TYPE_CLIENT_DUID = 2, + }, + EDNS0 = { + OPT_LLQ = 1, + OPT_UL = 2, + OPT_NSID = 3, + OPT_DAU = 5, + OPT_DHU = 6, + OPT_N3U = 7, + OPT_CLIENT_SUBNET = 8, + OPT_EXPIRE = 9, + OPT_COOKIE = 10, + OPT_TCP_KEEPALIVE = 11, + OPT_PADDING = 12, + OPT_CHAIN = 13, + OPT_DEVICEID = 26946, + }, +} +local _CLASS = {} +_CLASS[Dns.CLASS.IN] = "IN" +_CLASS[Dns.CLASS.CH] = "CH" +_CLASS[Dns.CLASS.HS] = "HS" +_CLASS[Dns.CLASS.NONE] = "NONE" +_CLASS[Dns.CLASS.ANY] = "ANY" +local _TYPE = {} +_TYPE[Dns.TYPE.A] = "A" +_TYPE[Dns.TYPE.NS] = "NS" +_TYPE[Dns.TYPE.MD] = "MD" +_TYPE[Dns.TYPE.MF] = "MF" +_TYPE[Dns.TYPE.CNAME] = "CNAME" +_TYPE[Dns.TYPE.SOA] = "SOA" +_TYPE[Dns.TYPE.MB] = "MB" +_TYPE[Dns.TYPE.MG] = "MG" +_TYPE[Dns.TYPE.MR] = "MR" +_TYPE[Dns.TYPE.NULL] = "NULL" +_TYPE[Dns.TYPE.WKS] = "WKS" +_TYPE[Dns.TYPE.PTR] = "PTR" +_TYPE[Dns.TYPE.HINFO] = "HINFO" +_TYPE[Dns.TYPE.MINFO] = "MINFO" +_TYPE[Dns.TYPE.MX] = "MX" +_TYPE[Dns.TYPE.TXT] = "TXT" +_TYPE[Dns.TYPE.RP] = "RP" +_TYPE[Dns.TYPE.AFSDB] = "AFSDB" +_TYPE[Dns.TYPE.X25] = "X25" +_TYPE[Dns.TYPE.ISDN] = "ISDN" +_TYPE[Dns.TYPE.RT] = "RT" +_TYPE[Dns.TYPE.NSAP] = "NSAP" +_TYPE[Dns.TYPE.NSAP_PTR] = "NSAP_PTR" +_TYPE[Dns.TYPE.SIG] = "SIG" +_TYPE[Dns.TYPE.KEY] = "KEY" +_TYPE[Dns.TYPE.PX] = "PX" +_TYPE[Dns.TYPE.GPOS] = "GPOS" +_TYPE[Dns.TYPE.AAAA] = "AAAA" +_TYPE[Dns.TYPE.LOC] = "LOC" +_TYPE[Dns.TYPE.NXT] = "NXT" +_TYPE[Dns.TYPE.EID] = "EID" +_TYPE[Dns.TYPE.NIMLOC] = "NIMLOC" +_TYPE[Dns.TYPE.SRV] = "SRV" +_TYPE[Dns.TYPE.ATMA] = "ATMA" +_TYPE[Dns.TYPE.NAPTR] = "NAPTR" +_TYPE[Dns.TYPE.KX] = "KX" +_TYPE[Dns.TYPE.CERT] = "CERT" +_TYPE[Dns.TYPE.A6] = "A6" +_TYPE[Dns.TYPE.DNAME] = "DNAME" +_TYPE[Dns.TYPE.SINK] = "SINK" +_TYPE[Dns.TYPE.OPT] = "OPT" +_TYPE[Dns.TYPE.APL] = "APL" +_TYPE[Dns.TYPE.DS] = "DS" +_TYPE[Dns.TYPE.SSHFP] = "SSHFP" +_TYPE[Dns.TYPE.IPSECKEY] = "IPSECKEY" +_TYPE[Dns.TYPE.RRSIG] = "RRSIG" +_TYPE[Dns.TYPE.NSEC] = "NSEC" +_TYPE[Dns.TYPE.DNSKEY] = "DNSKEY" +_TYPE[Dns.TYPE.DHCID] = "DHCID" +_TYPE[Dns.TYPE.NSEC3] = "NSEC3" +_TYPE[Dns.TYPE.NSEC3PARAM] = "NSEC3PARAM" +_TYPE[Dns.TYPE.TLSA] = "TLSA" +_TYPE[Dns.TYPE.SMIMEA] = "SMIMEA" +_TYPE[Dns.TYPE.HIP] = "HIP" +_TYPE[Dns.TYPE.NINFO] = "NINFO" +_TYPE[Dns.TYPE.RKEY] = "RKEY" +_TYPE[Dns.TYPE.TALINK] = "TALINK" +_TYPE[Dns.TYPE.CDS] = "CDS" +_TYPE[Dns.TYPE.CDNSKEY] = "CDNSKEY" +_TYPE[Dns.TYPE.OPENPGPKEY] = "OPENPGPKEY" +_TYPE[Dns.TYPE.CSYNC] = "CSYNC" +_TYPE[Dns.TYPE.SPF] = "SPF" +_TYPE[Dns.TYPE.UINFO] = "UINFO" +_TYPE[Dns.TYPE.UID] = "UID" +_TYPE[Dns.TYPE.GID] = "GID" +_TYPE[Dns.TYPE.UNSPEC] = "UNSPEC" +_TYPE[Dns.TYPE.NID] = "NID" +_TYPE[Dns.TYPE.L32] = "L32" +_TYPE[Dns.TYPE.L64] = "L64" +_TYPE[Dns.TYPE.LP] = "LP" +_TYPE[Dns.TYPE.EUI48] = "EUI48" +_TYPE[Dns.TYPE.EUI64] = "EUI64" +_TYPE[Dns.TYPE.TKEY] = "TKEY" +_TYPE[Dns.TYPE.TSIG] = "TSIG" +_TYPE[Dns.TYPE.IXFR] = "IXFR" +_TYPE[Dns.TYPE.AXFR] = "AXFR" +_TYPE[Dns.TYPE.MAILB] = "MAILB" +_TYPE[Dns.TYPE.MAILA] = "MAILA" +_TYPE[Dns.TYPE.ANY] = "ANY" +_TYPE[Dns.TYPE.URI] = "URI" +_TYPE[Dns.TYPE.CAA] = "CAA" +_TYPE[Dns.TYPE.AVC] = "AVC" +_TYPE[Dns.TYPE.TA] = "TA" +_TYPE[Dns.TYPE.DLV] = "DLV" +local _OPCODE = {} +_OPCODE[Dns.OPCODE.QUERY] = "QUERY" +_OPCODE[Dns.OPCODE.IQUERY] = "IQUERY" +_OPCODE[Dns.OPCODE.STATUS] = "STATUS" +_OPCODE[Dns.OPCODE.NOTIFY] = "NOTIFY" +_OPCODE[Dns.OPCODE.UPDATE] = "UPDATE" +local _RCODE = {} +_RCODE[Dns.RCODE.NOERROR] = "NOERROR" +_RCODE[Dns.RCODE.FORMERR] = "FORMERR" +_RCODE[Dns.RCODE.SERVFAIL] = "SERVFAIL" +_RCODE[Dns.RCODE.NXDOMAIN] = "NXDOMAIN" +_RCODE[Dns.RCODE.NOTIMP] = "NOTIMP" +_RCODE[Dns.RCODE.REFUSED] = "REFUSED" +_RCODE[Dns.RCODE.YXDOMAIN] = "YXDOMAIN" +_RCODE[Dns.RCODE.YXRRSET] = "YXRRSET" +_RCODE[Dns.RCODE.NXRRSET] = "NXRRSET" +_RCODE[Dns.RCODE.NOTAUTH] = "NOTAUTH" +_RCODE[Dns.RCODE.NOTZONE] = "NOTZONE" +_RCODE[Dns.RCODE.BADVERS] = "BADVERS" +_RCODE[Dns.RCODE.BADSIG] = "BADSIG" +_RCODE[Dns.RCODE.BADKEY] = "BADKEY" +_RCODE[Dns.RCODE.BADTIME] = "BADTIME" +_RCODE[Dns.RCODE.BADMODE] = "BADMODE" +_RCODE[Dns.RCODE.BADNAME] = "BADNAME" +_RCODE[Dns.RCODE.BADALG] = "BADALG" +_RCODE[Dns.RCODE.BADTRUNC] = "BADTRUNC" +_RCODE[Dns.RCODE.BADCOOKIE] = "BADCOOKIE" +local _AFSDB = {} +_AFSDB[Dns.AFSDB.SUBTYPE_AFS3LOCSRV] = "SUBTYPE_AFS3LOCSRV" +_AFSDB[Dns.AFSDB.SUBTYPE_DCENCA_ROOT] = "SUBTYPE_DCENCA_ROOT" +local _DHCID = {} +_DHCID[Dns.DHCID.TYPE_1OCTET] = "TYPE_1OCTET" +_DHCID[Dns.DHCID.TYPE_DATAOCTET] = "TYPE_DATAOCTET" +_DHCID[Dns.DHCID.TYPE_CLIENT_DUID] = "TYPE_CLIENT_DUID" +local _EDNS0 = {} +_EDNS0[Dns.EDNS0.OPT_LLQ] = "OPT_LLQ" +_EDNS0[Dns.EDNS0.OPT_UL] = "OPT_UL" +_EDNS0[Dns.EDNS0.OPT_NSID] = "OPT_NSID" +_EDNS0[Dns.EDNS0.OPT_DAU] = "OPT_DAU" +_EDNS0[Dns.EDNS0.OPT_DHU] = "OPT_DHU" +_EDNS0[Dns.EDNS0.OPT_N3U] = "OPT_N3U" +_EDNS0[Dns.EDNS0.OPT_CLIENT_SUBNET] = "OPT_CLIENT_SUBNET" +_EDNS0[Dns.EDNS0.OPT_EXPIRE] = "OPT_EXPIRE" +_EDNS0[Dns.EDNS0.OPT_COOKIE] = "OPT_COOKIE" +_EDNS0[Dns.EDNS0.OPT_TCP_KEEPALIVE] = "OPT_TCP_KEEPALIVE" +_EDNS0[Dns.EDNS0.OPT_PADDING] = "OPT_PADDING" +_EDNS0[Dns.EDNS0.OPT_CHAIN] = "OPT_CHAIN" +_EDNS0[Dns.EDNS0.OPT_DEVICEID] = "OPT_DEVICEID" +Dns.CLASS_STR = _CLASS +Dns.TYPE_STR = _TYPE +Dns.OPCODE_STR = _OPCODE +Dns.RCODE_STR = _RCODE +Dns.AFSDB_STR = _AFSDB +Dns.DHCID_STR = _DHCID +Dns.EDNS0_STR = _EDNS0 + +-- Create a new DNS object, optionally on-top of another object. +function Dns.new(obj) + local self = C.core_object_dns_new() + self.obj_prev = obj + ffi.gc(self, C.core_object_dns_free) + return self +end + +-- Return the textual type of the object. +function Dns:type() + return "dns" +end + +-- Return the previous object. +function Dns:prev() + return self.obj_prev +end + +-- Cast the object to the underlining object module and return it. +function Dns:cast() + return self +end + +-- Cast the object to the generic object module and return it. +function Dns:uncast() + return ffi.cast("core_object_t*", self) +end + +-- Make a copy of the object and return it. +function Dns:copy() + return C.core_object_dns_copy(self) +end + +-- Free the object, should only be used on copies or otherwise allocated. +function Dns:free() + C.core_object_dns_free(self) +end + +-- Return the Log object to control logging of this module. +function Dns:log() + return C.core_object_dns_log() +end + +-- Begin parsing the underlaying object, first the header is parsed then +-- optionally continue calling +-- .IR parse_q () +-- for the number of questions (see +-- .IR qdcount ). +-- After that continue calling +-- .IR parse_rr () +-- for the number of answers, authorities and additionals resource records +-- (see +-- .IR ancount ", " +-- .I nscount +-- and +-- .IR arcount ). +-- Returns 0 on success or negative integer on error which can be for +-- malformed or truncated DNS (-2) or if more space for labels is needed (-3). +function Dns:parse_header() + return C.core_object_dns_parse_header(self) +end + +-- Parse the next resource record as a question. +-- Returns 0 on success or negative integer on error which can be for +-- malformed or truncated DNS (-2) or if more space for labels is needed (-3). +function Dns:parse_q(q, labels, num_labels) + return C.core_object_dns_parse_q(self, q, labels, num_labels) +end + +-- Parse the next resource record. +-- Returns 0 on success or negative integer on error which can be for +-- malformed or truncated DNS (-2) or if more space for labels is needed (-3). +function Dns:parse_rr(rr, labels, num_labels) + return C.core_object_dns_parse_rr(self, rr, labels, num_labels) +end + +-- Begin parsing the underlaying object using +-- .IR parse_header "(), " +-- .IR parse_q () +-- and +-- .IR parse_rr (). +-- The optional +-- .I num_labels +-- can be used to set a specific number of labels used for each question +-- and resource record (default 16). +-- Returns result code, an array of questions, an array of question labels, +-- an array of resource records and an array of resource records labels. +-- Result code is 0 on success or negative integer on error which can be for +-- malformed or truncated DNS (-2) or if more space for labels is needed (-3). +function Dns:parse(num_labels) + local qs, qls, rrs, rrls = {}, {}, {}, {} + if num_labels == nil then + num_labels = 16 + end + + ret = self:parse_header() + if ret ~= 0 then + return ret, qs, qls, rrs, rrls + end + for n = 1, self.qdcount do + local labels = label.new(num_labels) + local q = Q.new() + local ret = C.core_object_dns_parse_q(self, q, labels, num_labels) + + if ret ~= 0 then + return ret, qs, qls, rrs, rrls + end + table.insert(qs, q) + table.insert(qls, labels) + end + for n = 1, self.ancount do + local labels = label.new(num_labels) + local rr = RR.new() + local ret = C.core_object_dns_parse_rr(self, rr, labels, num_labels) + + if ret ~= 0 then + return ret, qs, qls, rrs, rrls + end + table.insert(rrs, rr) + table.insert(rrls, labels) + end + for n = 1, self.nscount do + local labels = label.new(num_labels) + local rr = RR.new() + local ret = C.core_object_dns_parse_rr(self, rr, labels, num_labels) + + if ret ~= 0 then + return ret, qs, qls, rrs, rrls + end + table.insert(rrs, rr) + table.insert(rrls, labels) + end + for n = 1, self.arcount do + local labels = label.new(num_labels) + local rr = RR.new() + local ret = C.core_object_dns_parse_rr(self, rr, labels, num_labels) + + if ret ~= 0 then + return ret, qs, qls, rrs, rrls + end + table.insert(rrs, rr) + table.insert(rrls, labels) + end + + return 0, qs, qls, rrs, rrls +end + +-- Begin parsing the underlaying object using +-- .IR parse_header "(), " +-- .IR parse_q () +-- and +-- .IR parse_rr (), +-- and print it's content. +-- The optional +-- .I num_labels +-- can be used to set a specific number of labels used for each question +-- and resource record (default 16). +function Dns:print(num_labels) + if num_labels == nil then + num_labels = 16 + end + local labels = label.new(num_labels) + local q = Q.new() + local rr = RR.new() + + if self:parse_header() ~= 0 then + return + end + + local flags = {} + if self.have_aa and self.aa == 1 then + table.insert(flags, "AA") + end + if self.have_tc and self.tc == 1 then + table.insert(flags, "TC") + end + if self.have_rd and self.rd == 1 then + table.insert(flags, "RD") + end + if self.have_ra and self.ra == 1 then + table.insert(flags, "RA") + end + if self.have_z and self.z == 1 then + table.insert(flags, "Z") + end + if self.have_ad and self.ad == 1 then + table.insert(flags, "AD") + end + if self.have_cd and self.cd == 1 then + table.insert(flags, "CD") + end + + print("id:", self.id) + print("", "qr:", self.qr) + print("", "opcode:", Dns.opcode_tostring(self.opcode)) + print("", "flags:", table.concat(flags, " ")) + print("", "rcode:", Dns.rcode_tostring(self.rcode)) + print("", "qdcount:", self.qdcount) + print("", "ancount:", self.ancount) + print("", "nscount:", self.nscount) + print("", "arcount:", self.arcount) + + if self.qdcount > 0 then + print("questions:", "class", "type", "labels") + for n = 1, self.qdcount do + if C.core_object_dns_parse_q(self, q, labels, num_labels) ~= 0 then + return + end + print("", Dns.class_tostring(q.class), Dns.type_tostring(q.type), label.tooffstr(self, labels, num_labels)) + end + end + if self.ancount > 0 then + print("answers:", "class", "type", "ttl", "labels", "RR labels") + for n = 1, self.ancount do + if C.core_object_dns_parse_rr(self, rr, labels, num_labels) ~= 0 then + return + end + if rr.rdata_labels == 0 then + print("", Dns.class_tostring(rr.class), Dns.type_tostring(rr.type), rr.ttl, label.tooffstr(self, labels, rr.labels)) + else + print("", Dns.class_tostring(rr.class), Dns.type_tostring(rr.type), rr.ttl, label.tooffstr(self, labels, rr.labels), label.tooffstr(self, labels, rr.rdata_labels, rr.labels)) + end + end + end + if self.nscount > 0 then + print("authorities:", "class", "type", "ttl", "labels", "RR labels") + for n = 1, self.nscount do + if C.core_object_dns_parse_rr(self, rr, labels, num_labels) ~= 0 then + return + end + if rr.rdata_labels == 0 then + print("", Dns.class_tostring(rr.class), Dns.type_tostring(rr.type), rr.ttl, label.tooffstr(self, labels, rr.labels)) + else + print("", Dns.class_tostring(rr.class), Dns.type_tostring(rr.type), rr.ttl, label.tooffstr(self, labels, rr.labels), label.tooffstr(self, labels, rr.rdata_labels, rr.labels)) + end + end + end + if self.arcount > 0 then + print("additionals:", "class", "type", "ttl", "labels", "RR labels") + for n = 1, self.arcount do + if C.core_object_dns_parse_rr(self, rr, labels, num_labels) ~= 0 then + return + end + if rr.rdata_labels == 0 then + print("", Dns.class_tostring(rr.class), Dns.type_tostring(rr.type), rr.ttl, label.tooffstr(self, labels, rr.labels)) + else + print("", Dns.class_tostring(rr.class), Dns.type_tostring(rr.type), rr.ttl, label.tooffstr(self, labels, rr.labels), label.tooffstr(self, labels, rr.rdata_labels, rr.labels)) + end + end + end +end + +-- Return the textual name for a class. +function Dns.class_tostring(class) + if Dns.CLASS_STR[class] == nil then + return "UNKNOWN("..class..")" + end + return Dns.CLASS_STR[class] +end + +-- Return the textual name for a type. +function Dns.type_tostring(type) + if Dns.TYPE_STR[type] == nil then + return "UNKNOWN("..type..")" + end + return Dns.TYPE_STR[type] +end + +-- Return the textual name for an opcode. +function Dns.opcode_tostring(opcode) + if Dns.OPCODE_STR[opcode] == nil then + return "UNKNOWN("..opcode..")" + end + return Dns.OPCODE_STR[opcode] +end + +-- Return the textual name for a rcode. +function Dns.rcode_tostring(rcode) + if Dns.RCODE_STR[rcode] == nil then + return "UNKNOWN("..rcode..")" + end + return Dns.RCODE_STR[rcode] +end + +-- Return the textual name for an afsdb subtype. +function Dns.afsdb_tostring(afsdb) + if Dns.AFSDB_STR[afsdb] == nil then + return "UNKNOWN("..afsdb..")" + end + return Dns.AFSDB_STR[afsdb] +end + +-- Return the textual name for a dhcid type. +function Dns.dhcid_tostring(dhcid) + if Dns.DHCID_STR[dhcid] == nil then + return "UNKNOWN("..dhcid..")" + end + return Dns.DHCID_STR[dhcid] +end + +-- Return the textual name for an EDNS0 OPT record. +function Dns.edns0_tostring(edns0) + if Dns.EDNS0_STR[edns0] == nil then + return "UNKNOWN("..edns0..")" + end + return Dns.EDNS0_STR[edns0] +end + +core_object_dns_t = ffi.metatype(t_name, { __index = Dns }) + +-- dnsjit.core.object (3), +-- dnsjit.core.object.payload (3), +-- dnsjit.core.object.dns.label (3), +-- dnsjit.core.object.dns.q (3), +-- dnsjit.core.object.dns.rr (3) +return Dns diff --git a/include/dnsjit/core/object/dns/label.lua b/include/dnsjit/core/object/dns/label.lua new file mode 100644 index 0000000..bc78758 --- /dev/null +++ b/include/dnsjit/core/object/dns/label.lua @@ -0,0 +1,118 @@ +-- 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.object.dns.label +-- Container of a DNS label +-- +-- The object that describes a DNS label. +-- To extract a domain name label first check that +-- .I have_dn +-- is set, then use +-- .I "offset + 1" +-- to indicate where in the payload the label start and +-- .I length +-- for how many bytes long it is. +-- .SS Attributes +-- .TP +-- is_end +-- .TP +-- have_length +-- Set if there is a length. +-- .TP +-- have_offset +-- Set if there is an offset. +-- .TP +-- have_extension_bits +-- Set if there is extension bits. +-- .TP +-- have_dn +-- Set if the label contained a domain name. +-- .TP +-- extension_bits +-- The extension bits. +-- .TP +-- length +-- The length of the domain name. +-- .TP +-- offset +-- If +-- .I have_dn +-- is set then this contains the offset within the payload to where this label +-- start otherwise it contains the offset to another label. +module(...,package.seeall) + +require("dnsjit.core.object.dns_h") +local ffi = require("ffi") + +local Label = {} + +-- Create a new array of labels. +function Label.new(size) + return ffi.new("core_object_dns_label_t[?]", size) +end + +-- Returns labels as a string and an offset to the next label. +-- The string may be nil if the first label was an offset. +-- The offset may be nil if the last label was an extension bits or end marker. +function Label.tostring(dns, labels, num_labels, offset_labels) + if offset_labels == nil then + offset_labels = 0 + end + local dn + for n = 1, tonumber(num_labels) do + local label = labels[n - 1 + offset_labels] + + if label.have_dn == 1 then + if dn == nil then + dn = "" + end + dn = dn .. ffi.string(dns.payload + label.offset + 1, label.length) .. "." + elseif label.have_offset == 1 then + return dn, label.offset + else + return dn, nil + end + end + return dn, nil +end + +-- Returns labels as a string which also includes a textual notation of the +-- offset in the form of +-- .IR "<offset>label" . +function Label.tooffstr(dns, labels, num_labels, offset_labels) + if offset_labels == nil then + offset_labels = 0 + end + local dn = "" + for n = 1, tonumber(num_labels) do + local label = labels[n - 1 + offset_labels] + + if label.have_dn == 1 then + dn = dn .. "<" .. tonumber(label.offset) .. ">" .. ffi.string(dns.payload + label.offset + 1, label.length) .. "." + elseif label.have_offset == 1 then + dn = dn .. "<" .. tonumber(label.offset) .. ">" + break + else + break + end + end + return dn +end + +-- dnsjit.core.object.dns (3) +return Label diff --git a/include/dnsjit/core/object/dns/q.lua b/include/dnsjit/core/object/dns/q.lua new file mode 100644 index 0000000..f65d9e8 --- /dev/null +++ b/include/dnsjit/core/object/dns/q.lua @@ -0,0 +1,52 @@ +-- 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.object.dns.q +-- Container of a DNS question +-- +-- The object that describes a DNS question. +-- .SS Attributes +-- .TP +-- have_type +-- Set if there is a type. +-- .TP +-- have_class +-- Set if there is a class. +-- .TP +-- type +-- The type. +-- .TP +-- class +-- The class. +-- .TP +-- labels +-- The number of labels found in the question. +module(...,package.seeall) + +require("dnsjit.core.object.dns_h") +local ffi = require("ffi") + +local Q = {} + +-- Create a new question. +function Q.new(size) + return ffi.new("core_object_dns_q_t") +end + +-- dnsjit.core.object.dns (3) +return Q diff --git a/include/dnsjit/core/object/dns/rr.lua b/include/dnsjit/core/object/dns/rr.lua new file mode 100644 index 0000000..d360d96 --- /dev/null +++ b/include/dnsjit/core/object/dns/rr.lua @@ -0,0 +1,85 @@ +-- 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.object.dns.rr +-- Container of a DNS resource record +-- +-- The object that describes a DNS resource record. +-- .SS Attributes +-- .TP +-- have_type +-- Set if there is a type. +-- .TP +-- have_class +-- Set if there is a class. +-- .TP +-- have_ttl +-- Set if there is a ttl. +-- .TP +-- have_rdlength +-- Set if there is a rdlength. +-- .TP +-- have_rdata +-- Set if there is resource record data. +-- .TP +-- have_rdata_labels +-- Set if there are any labels within the rdata. +-- .TP +-- have_padding +-- Set if there is padding. +-- .TP +-- type +-- The type. +-- .TP +-- class +-- The class. +-- .TP +-- ttl +-- The TTL. +-- .TP +-- rdlength +-- The resource record data length. +-- .TP +-- labels +-- The number of labels found in the record. +-- .TP +-- rdata_offset +-- The offset within the payload for the resource record data. +-- .TP +-- rdata_labels +-- The number of labels found inside the resource record data. +-- .TP +-- padding_offset +-- The offset within the payload where the padding starts. +-- .TP +-- padding_length +-- The length of the padding. +module(...,package.seeall) + +require("dnsjit.core.object.dns_h") +local ffi = require("ffi") + +local Rr = {} + +-- Create a new resource record. +function Rr.new() + return ffi.new("core_object_dns_rr_t") +end + +-- dnsjit.core.object.dns (3) +return Rr diff --git a/include/dnsjit/core/object/ether.c b/include/dnsjit/core/object/ether.c new file mode 100644 index 0000000..dd7cd98 --- /dev/null +++ b/include/dnsjit/core/object/ether.c @@ -0,0 +1,45 @@ +/* + * 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 "core/object/ether.h" +#include "core/assert.h" + +#include <stdlib.h> +#include <string.h> + +core_object_ether_t* core_object_ether_copy(const core_object_ether_t* self) +{ + core_object_ether_t* copy; + glassert_self(); + + glfatal_oom(copy = malloc(sizeof(core_object_ether_t))); + memcpy(copy, self, sizeof(core_object_ether_t)); + copy->obj_prev = 0; + + return copy; +} + +void core_object_ether_free(core_object_ether_t* self) +{ + glassert_self(); + free(self); +} diff --git a/include/dnsjit/core/object/ether.h b/include/dnsjit/core/object/ether.h new file mode 100644 index 0000000..0fc9e35 --- /dev/null +++ b/include/dnsjit/core/object/ether.h @@ -0,0 +1,38 @@ +/* + * 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/object.h> +#include <dnsjit/core/timespec.h> + +#ifndef __dnsjit_core_object_ether_h +#define __dnsjit_core_object_ether_h + +#include <stddef.h> + +#include <dnsjit/core/object/ether.hh> + +#define CORE_OBJECT_ETHER_INIT(prev) \ + { \ + CORE_OBJECT_INIT(CORE_OBJECT_ETHER, prev) \ + , \ + { 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0 }, 0 \ + } + +#endif diff --git a/include/dnsjit/core/object/ether.hh b/include/dnsjit/core/object/ether.hh new file mode 100644 index 0000000..3b7a0cc --- /dev/null +++ b/include/dnsjit/core/object/ether.hh @@ -0,0 +1,33 @@ +/* + * 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.object_h") + +typedef struct core_object_ether { + const core_object_t* obj_prev; + int32_t obj_type; + + uint8_t dhost[6]; + uint8_t shost[6]; + uint16_t type; +} core_object_ether_t; + +core_object_ether_t* core_object_ether_copy(const core_object_ether_t* self); +void core_object_ether_free(core_object_ether_t* self); diff --git a/include/dnsjit/core/object/ether.lua b/include/dnsjit/core/object/ether.lua new file mode 100644 index 0000000..3359d1f --- /dev/null +++ b/include/dnsjit/core/object/ether.lua @@ -0,0 +1,78 @@ +-- 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.object.ether +-- Ether part of a packet +-- +-- The ether part of a packet that usually can be found in the object chain +-- after parsing with, for example, Layer filter. +-- .SS Attributes +-- .TP +-- dhost +-- The destination ether address. +-- .TP +-- shost +-- The source ether address. +-- .TP +-- type +-- The packet type ID field / EtherType field. +module(...,package.seeall) + +require("dnsjit.core.object.ether_h") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "core_object_ether_t" +local core_object_ether_t +local Ether = {} + +-- Return the textual type of the object. +function Ether:type() + return "ether" +end + +-- Return the previous object. +function Ether:prev() + return self.obj_prev +end + +-- Cast the object to the underlining object module and return it. +function Ether:cast() + return self +end + +-- Cast the object to the generic object module and return it. +function Ether:uncast() + return ffi.cast("core_object_t*", self) +end + +-- Make a copy of the object and return it. +function Ether:copy() + return C.core_object_ether_copy(self) +end + +-- Free the object, should only be used on copies or otherwise allocated. +function Ether:free() + C.core_object_ether_free(self) +end + +core_object_ether_t = ffi.metatype(t_name, { __index = Ether }) + +-- dnsjit.core.object (3), +-- dnsjit.filter.layer (3) +return Ether diff --git a/include/dnsjit/core/object/gre.c b/include/dnsjit/core/object/gre.c new file mode 100644 index 0000000..9a467c3 --- /dev/null +++ b/include/dnsjit/core/object/gre.c @@ -0,0 +1,45 @@ +/* + * 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 "core/object/gre.h" +#include "core/assert.h" + +#include <stdlib.h> +#include <string.h> + +core_object_gre_t* core_object_gre_copy(const core_object_gre_t* self) +{ + core_object_gre_t* copy; + glassert_self(); + + glfatal_oom(copy = malloc(sizeof(core_object_gre_t))); + memcpy(copy, self, sizeof(core_object_gre_t)); + copy->obj_prev = 0; + + return copy; +} + +void core_object_gre_free(core_object_gre_t* self) +{ + glassert_self(); + free(self); +} diff --git a/include/dnsjit/core/object/gre.h b/include/dnsjit/core/object/gre.h new file mode 100644 index 0000000..a716787 --- /dev/null +++ b/include/dnsjit/core/object/gre.h @@ -0,0 +1,38 @@ +/* + * 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/object.h> +#include <dnsjit/core/timespec.h> + +#ifndef __dnsjit_core_object_gre_h +#define __dnsjit_core_object_gre_h + +#include <stddef.h> + +#include <dnsjit/core/object/gre.hh> + +#define CORE_OBJECT_GRE_INIT(prev) \ + { \ + CORE_OBJECT_INIT(CORE_OBJECT_GRE, prev) \ + , \ + 0, 0, 0, 0, 0 \ + } + +#endif diff --git a/include/dnsjit/core/object/gre.hh b/include/dnsjit/core/object/gre.hh new file mode 100644 index 0000000..67a89b1 --- /dev/null +++ b/include/dnsjit/core/object/gre.hh @@ -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/>. + */ + +//lua:require("dnsjit.core.object_h") + +typedef struct core_object_gre { + const core_object_t* obj_prev; + int32_t obj_type; + + uint16_t gre_flags; + uint16_t ether_type; + uint16_t checksum; + uint16_t offset; + uint32_t key; + uint32_t sequence; + // TODO: routing list, check RFC 1701. +} core_object_gre_t; + +core_object_gre_t* core_object_gre_copy(const core_object_gre_t* self); +void core_object_gre_free(core_object_gre_t* self); diff --git a/include/dnsjit/core/object/gre.lua b/include/dnsjit/core/object/gre.lua new file mode 100644 index 0000000..703b02f --- /dev/null +++ b/include/dnsjit/core/object/gre.lua @@ -0,0 +1,87 @@ +-- 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.object.gre +-- Generic Routing Encapsulation (GRE) part of a packet +-- +-- The GRE part of a packet that usually can be found in the object chain +-- after parsing with, for example, Layer filter. +-- See RFC 1701. +-- .SS Attributes +-- .TP +-- gre_flags +-- The GRE flags. +-- .TP +-- ether_type +-- The protocol type of the payload packet. +-- .TP +-- checksum +-- The checksum of the GRE header and the payload packet. +-- .TP +-- key +-- The Key field contains a four octet number which was inserted by +-- the encapsulator. +-- .TP +-- sequence +-- The Sequence Number field contains an unsigned 32 bit integer which is +-- inserted by the encapsulator. +module(...,package.seeall) + +require("dnsjit.core.object.gre_h") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "core_object_gre_t" +local core_object_gre_t +local Gre = {} + +-- Return the textual type of the object. +function Gre:type() + return "gre" +end + +-- Return the previous object. +function Gre:prev() + return self.obj_prev +end + +-- Cast the object to the underlining object module and return it. +function Gre:cast() + return self +end + +-- Cast the object to the generic object module and return it. +function Gre:uncast() + return ffi.cast("core_object_t*", self) +end + +-- Make a copy of the object and return it. +function Gre:copy() + return C.core_object_gre_copy(self) +end + +-- Free the object, should only be used on copies or otherwise allocated. +function Gre:free() + C.core_object_gre_free(self) +end + +core_object_gre_t = ffi.metatype(t_name, { __index = Gre }) + +-- dnsjit.core.object (3), +-- dnsjit.filter.layer (3) +return Gre diff --git a/include/dnsjit/core/object/icmp.c b/include/dnsjit/core/object/icmp.c new file mode 100644 index 0000000..ebd13dc --- /dev/null +++ b/include/dnsjit/core/object/icmp.c @@ -0,0 +1,45 @@ +/* + * 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 "core/object/icmp.h" +#include "core/assert.h" + +#include <stdlib.h> +#include <string.h> + +core_object_icmp_t* core_object_icmp_copy(const core_object_icmp_t* self) +{ + core_object_icmp_t* copy; + glassert_self(); + + glfatal_oom(copy = malloc(sizeof(core_object_icmp_t))); + memcpy(copy, self, sizeof(core_object_icmp_t)); + copy->obj_prev = 0; + + return copy; +} + +void core_object_icmp_free(core_object_icmp_t* self) +{ + glassert_self(); + free(self); +} diff --git a/include/dnsjit/core/object/icmp.h b/include/dnsjit/core/object/icmp.h new file mode 100644 index 0000000..65ffa7d --- /dev/null +++ b/include/dnsjit/core/object/icmp.h @@ -0,0 +1,38 @@ +/* + * 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/object.h> +#include <dnsjit/core/timespec.h> + +#ifndef __dnsjit_core_object_icmp_h +#define __dnsjit_core_object_icmp_h + +#include <stddef.h> + +#include <dnsjit/core/object/icmp.hh> + +#define CORE_OBJECT_ICMP_INIT(prev) \ + { \ + CORE_OBJECT_INIT(CORE_OBJECT_ICMP, prev) \ + , \ + 0, 0, 0 \ + } + +#endif diff --git a/include/dnsjit/core/object/icmp.hh b/include/dnsjit/core/object/icmp.hh new file mode 100644 index 0000000..1a7aa88 --- /dev/null +++ b/include/dnsjit/core/object/icmp.hh @@ -0,0 +1,33 @@ +/* + * 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.object_h") + +typedef struct core_object_icmp { + const core_object_t* obj_prev; + int32_t obj_type; + + uint8_t type; + uint8_t code; + uint16_t cksum; +} core_object_icmp_t; + +core_object_icmp_t* core_object_icmp_copy(const core_object_icmp_t* self); +void core_object_icmp_free(core_object_icmp_t* self); diff --git a/include/dnsjit/core/object/icmp.lua b/include/dnsjit/core/object/icmp.lua new file mode 100644 index 0000000..52062ad --- /dev/null +++ b/include/dnsjit/core/object/icmp.lua @@ -0,0 +1,78 @@ +-- 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.object.icmp +-- An ICMP packet +-- +-- An ICMP packet which is usually at the top of the object chain +-- after parsing with, for example, Layer filter. +-- .SS Attributes +-- .TP +-- type +-- The type of ICMP message. +-- .TP +-- code +-- The (response/error) code for the ICMP type message. +-- .TP +-- cksum +-- The ICMP checksum. +module(...,package.seeall) + +require("dnsjit.core.object.icmp_h") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "core_object_icmp_t" +local core_object_icmp_t +local Icmp = {} + +-- Return the textual type of the object. +function Icmp:type() + return "icmp" +end + +-- Return the previous object. +function Icmp:prev() + return self.obj_prev +end + +-- Cast the object to the underlining object module and return it. +function Icmp:cast() + return self +end + +-- Cast the object to the generic object module and return it. +function Icmp:uncast() + return ffi.cast("core_object_t*", self) +end + +-- Make a copy of the object and return it. +function Icmp:copy() + return C.core_object_icmp_copy(self) +end + +-- Free the object, should only be used on copies or otherwise allocated. +function Icmp:free() + C.core_object_icmp_free(self) +end + +core_object_icmp_t = ffi.metatype(t_name, { __index = Icmp }) + +-- dnsjit.core.object (3), +-- dnsjit.filter.layer (3) +return Icmp diff --git a/include/dnsjit/core/object/icmp6.c b/include/dnsjit/core/object/icmp6.c new file mode 100644 index 0000000..b79fb17 --- /dev/null +++ b/include/dnsjit/core/object/icmp6.c @@ -0,0 +1,45 @@ +/* + * 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 "core/object/icmp6.h" +#include "core/assert.h" + +#include <stdlib.h> +#include <string.h> + +core_object_icmp6_t* core_object_icmp6_copy(const core_object_icmp6_t* self) +{ + core_object_icmp6_t* copy; + glassert_self(); + + glfatal_oom(copy = malloc(sizeof(core_object_icmp6_t))); + memcpy(copy, self, sizeof(core_object_icmp6_t)); + copy->obj_prev = 0; + + return copy; +} + +void core_object_icmp6_free(core_object_icmp6_t* self) +{ + glassert_self(); + free(self); +} diff --git a/include/dnsjit/core/object/icmp6.h b/include/dnsjit/core/object/icmp6.h new file mode 100644 index 0000000..4586d33 --- /dev/null +++ b/include/dnsjit/core/object/icmp6.h @@ -0,0 +1,38 @@ +/* + * 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/object.h> +#include <dnsjit/core/timespec.h> + +#ifndef __dnsjit_core_object_icmp6_h +#define __dnsjit_core_object_icmp6_h + +#include <stddef.h> + +#include <dnsjit/core/object/icmp6.hh> + +#define CORE_OBJECT_ICMP6_INIT(prev) \ + { \ + CORE_OBJECT_INIT(CORE_OBJECT_ICMP6, prev) \ + , \ + 0, 0, 0 \ + } + +#endif diff --git a/include/dnsjit/core/object/icmp6.hh b/include/dnsjit/core/object/icmp6.hh new file mode 100644 index 0000000..2aa1ed4 --- /dev/null +++ b/include/dnsjit/core/object/icmp6.hh @@ -0,0 +1,33 @@ +/* + * 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.object_h") + +typedef struct core_object_icmp6 { + const core_object_t* obj_prev; + int32_t obj_type; + + uint8_t type; + uint8_t code; + uint16_t cksum; +} core_object_icmp6_t; + +core_object_icmp6_t* core_object_icmp6_copy(const core_object_icmp6_t* self); +void core_object_icmp6_free(core_object_icmp6_t* self); diff --git a/include/dnsjit/core/object/icmp6.lua b/include/dnsjit/core/object/icmp6.lua new file mode 100644 index 0000000..a3929bf --- /dev/null +++ b/include/dnsjit/core/object/icmp6.lua @@ -0,0 +1,78 @@ +-- 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.object.icmp6 +-- An ICMPv6 packet +-- +-- An ICMPv6 packet which is usually at the top of the object chain +-- after parsing with, for example, Layer filter. +-- .SS Attributes +-- .TP +-- type +-- The type of ICMPv6 message. +-- .TP +-- code +-- The (response/error) code for the ICMPv6 type message. +-- .TP +-- cksum +-- The ICMPv6 checksum. +module(...,package.seeall) + +require("dnsjit.core.object.icmp6_h") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "core_object_icmp6_t" +local core_object_icmp6_t +local Icmp6 = {} + +-- Return the textual type of the object. +function Icmp6:type() + return "icmp6" +end + +-- Return the previous object. +function Icmp6:prev() + return self.obj_prev +end + +-- Cast the object to the underlining object module and return it. +function Icmp6:cast() + return self +end + +-- Cast the object to the generic object module and return it. +function Icmp6:uncast() + return ffi.cast("core_object_t*", self) +end + +-- Make a copy of the object and return it. +function Icmp6:copy() + return C.core_object_icmp6_copy(self) +end + +-- Free the object, should only be used on copies or otherwise allocated. +function Icmp6:free() + C.core_object_icmp6_free(self) +end + +core_object_icmp6_t = ffi.metatype(t_name, { __index = Icmp6 }) + +-- dnsjit.core.object (3), +-- dnsjit.filter.layer (3) +return Icmp6 diff --git a/include/dnsjit/core/object/ieee802.c b/include/dnsjit/core/object/ieee802.c new file mode 100644 index 0000000..80dd4ea --- /dev/null +++ b/include/dnsjit/core/object/ieee802.c @@ -0,0 +1,45 @@ +/* + * 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 "core/object/ieee802.h" +#include "core/assert.h" + +#include <stdlib.h> +#include <string.h> + +core_object_ieee802_t* core_object_ieee802_copy(const core_object_ieee802_t* self) +{ + core_object_ieee802_t* copy; + glassert_self(); + + glfatal_oom(copy = malloc(sizeof(core_object_ieee802_t))); + memcpy(copy, self, sizeof(core_object_ieee802_t)); + copy->obj_prev = 0; + + return copy; +} + +void core_object_ieee802_free(core_object_ieee802_t* self) +{ + glassert_self(); + free(self); +} diff --git a/include/dnsjit/core/object/ieee802.h b/include/dnsjit/core/object/ieee802.h new file mode 100644 index 0000000..388430d --- /dev/null +++ b/include/dnsjit/core/object/ieee802.h @@ -0,0 +1,38 @@ +/* + * 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/object.h> +#include <dnsjit/core/timespec.h> + +#ifndef __dnsjit_core_object_ieee802_h +#define __dnsjit_core_object_ieee802_h + +#include <stddef.h> + +#include <dnsjit/core/object/ieee802.hh> + +#define CORE_OBJECT_IEEE802_INIT(prev) \ + { \ + CORE_OBJECT_INIT(CORE_OBJECT_IEEE802, prev) \ + , \ + 0, 0, 0, 0, 0 \ + } + +#endif diff --git a/include/dnsjit/core/object/ieee802.hh b/include/dnsjit/core/object/ieee802.hh new file mode 100644 index 0000000..1bce670 --- /dev/null +++ b/include/dnsjit/core/object/ieee802.hh @@ -0,0 +1,35 @@ +/* + * 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.object_h") + +typedef struct core_object_ieee802 { + const core_object_t* obj_prev; + int32_t obj_type; + + uint16_t tpid; + uint8_t pcp; + uint8_t dei; + uint8_t vid; + uint16_t ether_type; +} core_object_ieee802_t; + +core_object_ieee802_t* core_object_ieee802_copy(const core_object_ieee802_t* self); +void core_object_ieee802_free(core_object_ieee802_t* self); diff --git a/include/dnsjit/core/object/ieee802.lua b/include/dnsjit/core/object/ieee802.lua new file mode 100644 index 0000000..77519ef --- /dev/null +++ b/include/dnsjit/core/object/ieee802.lua @@ -0,0 +1,84 @@ +-- 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.object.ieee802 +-- IEEE802 part of a packet +-- +-- The IEEE802 part of a packet that usually can be found in the object chain +-- after parsing with, for example, Layer filter. +-- .SS Attributes +-- .TP +-- tpid +-- Tag protocol identifier. +-- .TP +-- pcp +-- Priority code point. +-- .TP +-- dei +-- Drop eligible indicator. +-- .TP +-- vid +-- VLAN identifier. +-- .TP +-- ether_type +-- The packet type ID field / EtherType field. +module(...,package.seeall) + +require("dnsjit.core.object.ieee802_h") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "core_object_ieee802_t" +local core_object_ieee802_t +local Ieee802 = {} + +-- Return the textual type of the object. +function Ieee802:type() + return "ieee802" +end + +-- Return the previous object. +function Ieee802:prev() + return self.obj_prev +end + +-- Cast the object to the underlining object module and return it. +function Ieee802:cast() + return self +end + +-- Cast the object to the generic object module and return it. +function Ieee802:uncast() + return ffi.cast("core_object_t*", self) +end + +-- Make a copy of the object and return it. +function Ieee802:copy() + return C.core_object_ieee802_copy(self) +end + +-- Free the object, should only be used on copies or otherwise allocated. +function Ieee802:free() + C.core_object_ieee802_free(self) +end + +core_object_ieee802_t = ffi.metatype(t_name, { __index = Ieee802 }) + +-- dnsjit.core.object (3), +-- dnsjit.filter.layer (3) +return Ieee802 diff --git a/include/dnsjit/core/object/ip.c b/include/dnsjit/core/object/ip.c new file mode 100644 index 0000000..4e50b60 --- /dev/null +++ b/include/dnsjit/core/object/ip.c @@ -0,0 +1,45 @@ +/* + * 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 "core/object/ip.h" +#include "core/assert.h" + +#include <stdlib.h> +#include <string.h> + +core_object_ip_t* core_object_ip_copy(const core_object_ip_t* self) +{ + core_object_ip_t* copy; + glassert_self(); + + glfatal_oom(copy = malloc(sizeof(core_object_ip_t))); + memcpy(copy, self, sizeof(core_object_ip_t)); + copy->obj_prev = 0; + + return copy; +} + +void core_object_ip_free(core_object_ip_t* self) +{ + glassert_self(); + free(self); +} diff --git a/include/dnsjit/core/object/ip.h b/include/dnsjit/core/object/ip.h new file mode 100644 index 0000000..00e927b --- /dev/null +++ b/include/dnsjit/core/object/ip.h @@ -0,0 +1,38 @@ +/* + * 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/object.h> +#include <dnsjit/core/timespec.h> + +#ifndef __dnsjit_core_object_ip_h +#define __dnsjit_core_object_ip_h + +#include <stddef.h> + +#include <dnsjit/core/object/ip.hh> + +#define CORE_OBJECT_IP_INIT(prev) \ + { \ + CORE_OBJECT_INIT(CORE_OBJECT_IP, prev) \ + , \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, \ + } + +#endif diff --git a/include/dnsjit/core/object/ip.hh b/include/dnsjit/core/object/ip.hh new file mode 100644 index 0000000..9a379a4 --- /dev/null +++ b/include/dnsjit/core/object/ip.hh @@ -0,0 +1,40 @@ +/* + * 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.object_h") + +typedef struct core_object_ip { + const core_object_t* obj_prev; + int32_t obj_type; + + uint8_t v; + uint8_t hl; + uint8_t tos; + uint16_t len; + uint16_t id; + uint16_t off; + uint8_t ttl; + uint8_t p; + uint16_t sum; + uint8_t src[4], dst[4]; +} core_object_ip_t; + +core_object_ip_t* core_object_ip_copy(const core_object_ip_t* self); +void core_object_ip_free(core_object_ip_t* self); diff --git a/include/dnsjit/core/object/ip.lua b/include/dnsjit/core/object/ip.lua new file mode 100644 index 0000000..0294612 --- /dev/null +++ b/include/dnsjit/core/object/ip.lua @@ -0,0 +1,122 @@ +-- 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.object.ip +-- An IP packet +-- +-- An IP packet that usually can be found in the object chain +-- after parsing with, for example, Layer filter. +-- .SS Attributes +-- .TP +-- v +-- Version. +-- .TP +-- hl +-- Header length. +-- .TP +-- tos +-- Type of service. +-- .TP +-- len +-- Total length. +-- .TP +-- id +-- Identification. +-- .TP +-- off +-- Fragment offset field. +-- .TP +-- ttl +-- Time to live. +-- .TP +-- p +-- Protocol. +-- .TP +-- sum +-- Checksum. +-- .TP +-- src +-- Source address. +-- .TP +-- dst +-- Destination address. +-- .TP +-- payload +-- A pointer to the payload. +-- .TP +-- plen +-- The length of the payload. +-- .TP +-- pad_len +-- The length of padding found, if any. +module(...,package.seeall) + +require("dnsjit.core.object.ip_h") +local ffi = require("ffi") +local C = ffi.C +local libip = require("dnsjit.lib.ip") + +local t_name = "core_object_ip_t" +local core_object_ip_t +local Ip = {} + +-- Return the textual type of the object. +function Ip:type() + return "ip" +end + +-- Return the previous object. +function Ip:prev() + return self.obj_prev +end + +-- Cast the object to the underlining object module and return it. +function Ip:cast() + return self +end + +-- Cast the object to the generic object module and return it. +function Ip:uncast() + return ffi.cast("core_object_t*", self) +end + +-- Make a copy of the object and return it. +function Ip:copy() + return C.core_object_ip_copy(self) +end + +-- Free the object, should only be used on copies or otherwise allocated. +function Ip:free() + C.core_object_ip_free(self) +end + +-- Return the IP source as a string. +function Ip:source() + return libip.ipstring(self.src) +end + +-- Return the IP destination as a string. +function Ip:destination() + return libip.ipstring(self.dst) +end + +core_object_ip_t = ffi.metatype(t_name, { __index = Ip }) + +-- dnsjit.core.object (3), +-- dnsjit.filter.layer (3) +return Ip diff --git a/include/dnsjit/core/object/ip6.c b/include/dnsjit/core/object/ip6.c new file mode 100644 index 0000000..45db361 --- /dev/null +++ b/include/dnsjit/core/object/ip6.c @@ -0,0 +1,45 @@ +/* + * 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 "core/object/ip6.h" +#include "core/assert.h" + +#include <stdlib.h> +#include <string.h> + +core_object_ip6_t* core_object_ip6_copy(const core_object_ip6_t* self) +{ + core_object_ip6_t* copy; + glassert_self(); + + glfatal_oom(copy = malloc(sizeof(core_object_ip6_t))); + memcpy(copy, self, sizeof(core_object_ip6_t)); + copy->obj_prev = 0; + + return copy; +} + +void core_object_ip6_free(core_object_ip6_t* self) +{ + glassert_self(); + free(self); +} diff --git a/include/dnsjit/core/object/ip6.h b/include/dnsjit/core/object/ip6.h new file mode 100644 index 0000000..660b9e9 --- /dev/null +++ b/include/dnsjit/core/object/ip6.h @@ -0,0 +1,42 @@ +/* + * 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/object.h> +#include <dnsjit/core/timespec.h> + +#ifndef __dnsjit_core_object_ip6_h +#define __dnsjit_core_object_ip6_h + +#include <stddef.h> + +#include <dnsjit/core/object/ip6.hh> + +#define CORE_OBJECT_IP6_INIT(prev) \ + { \ + CORE_OBJECT_INIT(CORE_OBJECT_IP6, prev) \ + , \ + 0, 0, 0, 0, \ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, \ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, \ + 0, 0, 0, 0, \ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, \ + } + +#endif diff --git a/include/dnsjit/core/object/ip6.hh b/include/dnsjit/core/object/ip6.hh new file mode 100644 index 0000000..5411dda --- /dev/null +++ b/include/dnsjit/core/object/ip6.hh @@ -0,0 +1,42 @@ +/* + * 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.object_h") + +typedef struct core_object_ip6 { + const core_object_t* obj_prev; + int32_t obj_type; + + uint32_t flow; + uint16_t plen; + uint8_t nxt; + uint8_t hlim; + uint8_t src[16]; + uint8_t dst[16]; + + uint8_t is_frag; + uint8_t have_rtdst; + uint16_t frag_offlg; + uint16_t frag_ident; + uint8_t rtdst[16]; +} core_object_ip6_t; + +core_object_ip6_t* core_object_ip6_copy(const core_object_ip6_t* self); +void core_object_ip6_free(core_object_ip6_t* self); diff --git a/include/dnsjit/core/object/ip6.lua b/include/dnsjit/core/object/ip6.lua new file mode 100644 index 0000000..5271be3 --- /dev/null +++ b/include/dnsjit/core/object/ip6.lua @@ -0,0 +1,130 @@ +-- 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.object.ip6 +-- An IPv6 packet +-- +-- An IPv6 packet that usually can be found in the object chain +-- after parsing with, for example, Layer filter. +-- .SS Attributes +-- .TP +-- flow +-- 4 bits version, 8 bits TC and 20 bits flow-ID. +-- .TP +-- plen +-- Payload length (as in the IPv6 header). +-- .TP +-- nxt +-- Next header. +-- .TP +-- hlim +-- Hop limit. +-- .TP +-- src +-- Source address. +-- .TP +-- dst +-- Destination address. +-- .TP +-- is_frag +-- 1 bit, set if packet is a fragment. +-- .TP +-- have_rtdst +-- 1 bit, set if +-- .I rtdst +-- is set. +-- .TP +-- frag_offlg +-- Offset, reserved, and flag taken from the fragment header. +-- .TP +-- frag_ident +-- Identification taken from the fragment header. +-- .TP +-- rtdst +-- Destination address found in the routing extension header. +-- .TP +-- payload +-- A pointer to the payload. +-- .TP +-- len +-- The length of the payload. +-- .TP +-- pad_len +-- The length of padding found, if any. +module(...,package.seeall) + +require("dnsjit.core.object.ip6_h") +local ffi = require("ffi") +local C = ffi.C +local libip = require("dnsjit.lib.ip") + +local t_name = "core_object_ip6_t" +local core_object_ip6_t +local Ip6 = {} + +-- Return the textual type of the object. +function Ip6:type() + return "ip6" +end + +-- Return the previous object. +function Ip6:prev() + return self.obj_prev +end + +-- Cast the object to the underlining object module and return it. +function Ip6:cast() + return self +end + +-- Cast the object to the generic object module and return it. +function Ip6:uncast() + return ffi.cast("core_object_t*", self) +end + +-- Make a copy of the object and return it. +function Ip6:copy() + return C.core_object_ip6_copy(self) +end + +-- Free the object, should only be used on copies or otherwise allocated. +function Ip6:free() + C.core_object_ip6_free(self) +end + +-- Return the IPv6 source as a string. +-- If +-- .I pretty +-- is true then return an easier to read IPv6 address. +function Ip6:source(pretty) + return libip.ip6string(self.src, pretty) +end + +-- Return the IPv6 destination as a string. +-- If +-- .I pretty +-- is true then return an easier to read IPv6 address. +function Ip6:destination(pretty) + return libip.ip6string(self.dst, pretty) +end + +core_object_ip6_t = ffi.metatype(t_name, { __index = Ip6 }) + +-- dnsjit.core.object (3), +-- dnsjit.filter.layer (3) +return Ip6 diff --git a/include/dnsjit/core/object/linuxsll.c b/include/dnsjit/core/object/linuxsll.c new file mode 100644 index 0000000..cacd23a --- /dev/null +++ b/include/dnsjit/core/object/linuxsll.c @@ -0,0 +1,45 @@ +/* + * 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 "core/object/linuxsll.h" +#include "core/assert.h" + +#include <stdlib.h> +#include <string.h> + +core_object_linuxsll_t* core_object_linuxsll_copy(const core_object_linuxsll_t* self) +{ + core_object_linuxsll_t* copy; + glassert_self(); + + glfatal_oom(copy = malloc(sizeof(core_object_linuxsll_t))); + memcpy(copy, self, sizeof(core_object_linuxsll_t)); + copy->obj_prev = 0; + + return copy; +} + +void core_object_linuxsll_free(core_object_linuxsll_t* self) +{ + glassert_self(); + free(self); +} diff --git a/include/dnsjit/core/object/linuxsll.h b/include/dnsjit/core/object/linuxsll.h new file mode 100644 index 0000000..668581e --- /dev/null +++ b/include/dnsjit/core/object/linuxsll.h @@ -0,0 +1,38 @@ +/* + * 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/object.h> +#include <dnsjit/core/timespec.h> + +#ifndef __dnsjit_core_object_linuxsll_h +#define __dnsjit_core_object_linuxsll_h + +#include <stddef.h> + +#include <dnsjit/core/object/linuxsll.hh> + +#define CORE_OBJECT_LINUXSLL_INIT(prev) \ + { \ + CORE_OBJECT_INIT(CORE_OBJECT_LINUXSLL, prev) \ + , \ + 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 }, 0 \ + } + +#endif diff --git a/include/dnsjit/core/object/linuxsll.hh b/include/dnsjit/core/object/linuxsll.hh new file mode 100644 index 0000000..e808f96 --- /dev/null +++ b/include/dnsjit/core/object/linuxsll.hh @@ -0,0 +1,35 @@ +/* + * 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.object_h") + +typedef struct core_object_linuxsll { + const core_object_t* obj_prev; + int32_t obj_type; + + uint16_t packet_type; + uint16_t arp_hardware; + uint16_t link_layer_address_length; + uint8_t link_layer_address[8]; + uint16_t ether_type; +} core_object_linuxsll_t; + +core_object_linuxsll_t* core_object_linuxsll_copy(const core_object_linuxsll_t* self); +void core_object_linuxsll_free(core_object_linuxsll_t* self); diff --git a/include/dnsjit/core/object/linuxsll.lua b/include/dnsjit/core/object/linuxsll.lua new file mode 100644 index 0000000..6b47525 --- /dev/null +++ b/include/dnsjit/core/object/linuxsll.lua @@ -0,0 +1,84 @@ +-- 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.object.linuxsll +-- Linux cooked-mode capture (SLL) part of a packet +-- +-- The SLL part of a packet that usually can be found in the object chain +-- after parsing with, for example, Layer filter. +-- .SS Attributes +-- .TP +-- packet_type +-- The packet type. +-- .TP +-- arp_hardware +-- The link-layer device type. +-- .TP +-- link_layer_address_length +-- The length of the link-layer address. +-- .TP +-- link_layer_address +-- The link-layer address. +-- .TP +-- ether_type +-- An Ethernet protocol type. +module(...,package.seeall) + +require("dnsjit.core.object.linuxsll_h") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "core_object_linuxsll_t" +local core_object_linuxsll_t +local Linuxsll = {} + +-- Return the textual type of the object. +function Linuxsll:type() + return "linuxsll" +end + +-- Return the previous object. +function Linuxsll:prev() + return self.obj_prev +end + +-- Cast the object to the underlining object module and return it. +function Linuxsll:cast() + return self +end + +-- Cast the object to the generic object module and return it. +function Linuxsll:uncast() + return ffi.cast("core_object_t*", self) +end + +-- Make a copy of the object and return it. +function Linuxsll:copy() + return C.core_object_linuxsll_copy(self) +end + +-- Free the object, should only be used on copies or otherwise allocated. +function Linuxsll:free() + C.core_object_linuxsll_free(self) +end + +core_object_linuxsll_t = ffi.metatype(t_name, { __index = Linuxsll }) + +-- dnsjit.core.object (3). +-- dnsjit.filter.layer (3) +return Linuxsll diff --git a/include/dnsjit/core/object/loop.c b/include/dnsjit/core/object/loop.c new file mode 100644 index 0000000..4149f71 --- /dev/null +++ b/include/dnsjit/core/object/loop.c @@ -0,0 +1,45 @@ +/* + * 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 "core/object/loop.h" +#include "core/assert.h" + +#include <stdlib.h> +#include <string.h> + +core_object_loop_t* core_object_loop_copy(const core_object_loop_t* self) +{ + core_object_loop_t* copy; + glassert_self(); + + glfatal_oom(copy = malloc(sizeof(core_object_loop_t))); + memcpy(copy, self, sizeof(core_object_loop_t)); + copy->obj_prev = 0; + + return copy; +} + +void core_object_loop_free(core_object_loop_t* self) +{ + glassert_self(); + free(self); +} diff --git a/include/dnsjit/core/object/loop.h b/include/dnsjit/core/object/loop.h new file mode 100644 index 0000000..0cdb8e0 --- /dev/null +++ b/include/dnsjit/core/object/loop.h @@ -0,0 +1,38 @@ +/* + * 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/object.h> +#include <dnsjit/core/timespec.h> + +#ifndef __dnsjit_core_object_loop_h +#define __dnsjit_core_object_loop_h + +#include <stddef.h> + +#include <dnsjit/core/object/loop.hh> + +#define CORE_OBJECT_LOOP_INIT(prev) \ + { \ + CORE_OBJECT_INIT(CORE_OBJECT_LOOP, prev) \ + , \ + 0 \ + } + +#endif diff --git a/include/dnsjit/core/object/loop.hh b/include/dnsjit/core/object/loop.hh new file mode 100644 index 0000000..e8c5573 --- /dev/null +++ b/include/dnsjit/core/object/loop.hh @@ -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/>. + */ + +//lua:require("dnsjit.core.object_h") + +typedef struct core_object_loop { + const core_object_t* obj_prev; + int32_t obj_type; + + uint32_t family; +} core_object_loop_t; + +core_object_loop_t* core_object_loop_copy(const core_object_loop_t* self); +void core_object_loop_free(core_object_loop_t* self); diff --git a/include/dnsjit/core/object/loop.lua b/include/dnsjit/core/object/loop.lua new file mode 100644 index 0000000..2cb441f --- /dev/null +++ b/include/dnsjit/core/object/loop.lua @@ -0,0 +1,72 @@ +-- 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.object.loop +-- OpenBSD loopback encapsulation (loop) part of a packet +-- +-- The loop part of a packet that usually can be found in the object chain +-- after parsing with, for example, Layer filter. +-- .SS Attributes +-- .TP +-- family +-- The link-layer header describing what type of packet is encapsulated. +module(...,package.seeall) + +require("dnsjit.core.object.loop_h") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "core_object_loop_t" +local core_object_loop_t +local Loop = {} + +-- Return the textual type of the object. +function Loop:type() + return "loop" +end + +-- Return the previous object. +function Loop:prev() + return self.obj_prev +end + +-- Cast the object to the underlining object module and return it. +function Loop:cast() + return self +end + +-- Cast the object to the generic object module and return it. +function Loop:uncast() + return ffi.cast("core_object_t*", self) +end + +-- Make a copy of the object and return it. +function Loop:copy() + return C.core_object_loop_copy(self) +end + +-- Free the object, should only be used on copies or otherwise allocated. +function Loop:free() + C.core_object_loop_free(self) +end + +core_object_loop_t = ffi.metatype(t_name, { __index = Loop }) + +-- dnsjit.core.object (3), +-- dnsjit.filter.layer (3) +return Loop diff --git a/include/dnsjit/core/object/null.c b/include/dnsjit/core/object/null.c new file mode 100644 index 0000000..7fe617a --- /dev/null +++ b/include/dnsjit/core/object/null.c @@ -0,0 +1,45 @@ +/* + * 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 "core/object/null.h" +#include "core/assert.h" + +#include <stdlib.h> +#include <string.h> + +core_object_null_t* core_object_null_copy(const core_object_null_t* self) +{ + core_object_null_t* copy; + glassert_self(); + + glfatal_oom(copy = malloc(sizeof(core_object_null_t))); + memcpy(copy, self, sizeof(core_object_null_t)); + copy->obj_prev = 0; + + return copy; +} + +void core_object_null_free(core_object_null_t* self) +{ + glassert_self(); + free(self); +} diff --git a/include/dnsjit/core/object/null.h b/include/dnsjit/core/object/null.h new file mode 100644 index 0000000..5127951 --- /dev/null +++ b/include/dnsjit/core/object/null.h @@ -0,0 +1,38 @@ +/* + * 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/object.h> +#include <dnsjit/core/timespec.h> + +#ifndef __dnsjit_core_object_null_h +#define __dnsjit_core_object_null_h + +#include <stddef.h> + +#include <dnsjit/core/object/null.hh> + +#define CORE_OBJECT_NULL_INIT(prev) \ + { \ + CORE_OBJECT_INIT(CORE_OBJECT_NULL, prev) \ + , \ + 0 \ + } + +#endif diff --git a/include/dnsjit/core/object/null.hh b/include/dnsjit/core/object/null.hh new file mode 100644 index 0000000..2e6c639 --- /dev/null +++ b/include/dnsjit/core/object/null.hh @@ -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/>. + */ + +//lua:require("dnsjit.core.object_h") + +typedef struct core_object_null { + const core_object_t* obj_prev; + int32_t obj_type; + + uint32_t family; +} core_object_null_t; + +core_object_null_t* core_object_null_copy(const core_object_null_t* self); +void core_object_null_free(core_object_null_t* self); diff --git a/include/dnsjit/core/object/null.lua b/include/dnsjit/core/object/null.lua new file mode 100644 index 0000000..e6dfc5d --- /dev/null +++ b/include/dnsjit/core/object/null.lua @@ -0,0 +1,72 @@ +-- 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.object.null +-- BSD loopback encapsulation (null) part of a packet +-- +-- The null part of a packet that usually can be found in the object chain +-- after parsing with, for example, Layer filter. +-- .SS Attributes +-- .TP +-- family +-- The link-layer header describing what type of packet is encapsulated. +module(...,package.seeall) + +require("dnsjit.core.object.null_h") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "core_object_null_t" +local core_object_null_t +local Null = {} + +-- Return the textual type of the object. +function Null:type() + return "null" +end + +-- Return the previous object. +function Null:prev() + return self.obj_prev +end + +-- Cast the object to the underlining object module and return it. +function Null:cast() + return self +end + +-- Cast the object to the generic object module and return it. +function Null:uncast() + return ffi.cast("core_object_t*", self) +end + +-- Make a copy of the object and return it. +function Null:copy() + return C.core_object_null_copy(self) +end + +-- Free the object, should only be used on copies or otherwise allocated. +function Null:free() + C.core_object_null_free(self) +end + +core_object_null_t = ffi.metatype(t_name, { __index = Null }) + +-- dnsjit.core.object (3), +-- dnsjit.filter.layer (3) +return Null diff --git a/include/dnsjit/core/object/payload.c b/include/dnsjit/core/object/payload.c new file mode 100644 index 0000000..d6d2ee4 --- /dev/null +++ b/include/dnsjit/core/object/payload.c @@ -0,0 +1,50 @@ +/* + * 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 "core/object/payload.h" +#include "core/assert.h" + +#include <stdlib.h> +#include <string.h> + +core_object_payload_t* core_object_payload_copy(const core_object_payload_t* self) +{ + core_object_payload_t* copy; + glassert_self(); + + glfatal_oom(copy = malloc(sizeof(core_object_payload_t) + self->len + self->padding)); + memcpy(copy, self, sizeof(core_object_payload_t)); + copy->obj_prev = 0; + + if (copy->payload) { + copy->payload = (void*)copy + sizeof(core_object_payload_t); + memcpy((void*)copy->payload, self->payload, self->len + self->padding); + } + + return copy; +} + +void core_object_payload_free(core_object_payload_t* self) +{ + glassert_self(); + free(self); +} diff --git a/include/dnsjit/core/object/payload.h b/include/dnsjit/core/object/payload.h new file mode 100644 index 0000000..07391aa --- /dev/null +++ b/include/dnsjit/core/object/payload.h @@ -0,0 +1,38 @@ +/* + * 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/object.h> +#include <dnsjit/core/timespec.h> + +#ifndef __dnsjit_core_object_payload_h +#define __dnsjit_core_object_payload_h + +#include <stddef.h> + +#include <dnsjit/core/object/payload.hh> + +#define CORE_OBJECT_PAYLOAD_INIT(prev) \ + { \ + CORE_OBJECT_INIT(CORE_OBJECT_PAYLOAD, prev) \ + , \ + 0, 0, 0 \ + } + +#endif diff --git a/include/dnsjit/core/object/payload.hh b/include/dnsjit/core/object/payload.hh new file mode 100644 index 0000000..fc2ad71 --- /dev/null +++ b/include/dnsjit/core/object/payload.hh @@ -0,0 +1,32 @@ +/* + * 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.object_h") + +typedef struct core_object_payload { + const core_object_t* obj_prev; + int32_t obj_type; + + const uint8_t* payload; + size_t len, padding; +} core_object_payload_t; + +core_object_payload_t* core_object_payload_copy(const core_object_payload_t* self); +void core_object_payload_free(core_object_payload_t* self); diff --git a/include/dnsjit/core/object/payload.lua b/include/dnsjit/core/object/payload.lua new file mode 100644 index 0000000..61ea867 --- /dev/null +++ b/include/dnsjit/core/object/payload.lua @@ -0,0 +1,83 @@ +-- 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.object.payload +-- Application data payload +-- +-- Payload object contains the data carried by the underlying transport +-- protocol. +-- Payload is usually at the top of the object chain after parsing with, +-- for example, +-- .IR dnsjit.filter.layer . +-- .SS Attributes +-- .TP +-- payload +-- A pointer to the payload. +-- .TP +-- len +-- The length of the payload. +-- .TP +-- padding +-- The length of padding in the underlying packet. +module(...,package.seeall) + +require("dnsjit.core.object.payload_h") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "core_object_payload_t" +local core_object_payload_t +local Payload = {} + +-- Return the textual type of the object. +function Payload:type() + return "payload" +end + +-- Return the previous object. +function Payload:prev() + return self.obj_prev +end + +-- Cast the object to the underlining object module and return it. +function Payload:cast() + return self +end + +-- Cast the object to the generic object module and return it. +function Payload:uncast() + return ffi.cast("core_object_t*", self) +end + +-- Make a copy of the object and return it. +function Payload:copy() + return C.core_object_payload_copy(self) +end + +-- Free the object, should only be used on copies or otherwise allocated. +function Payload:free() + C.core_object_payload_free(self) +end + +core_object_payload_t = ffi.metatype(t_name, { __index = Payload }) + +-- dnsjit.core.object (3), +-- dnsjit.core.object.udp (3), +-- dnsjit.core.object.tcp (3), +-- dnsjit.filter.layer (3) +return Payload diff --git a/include/dnsjit/core/object/pcap.c b/include/dnsjit/core/object/pcap.c new file mode 100644 index 0000000..576a94e --- /dev/null +++ b/include/dnsjit/core/object/pcap.c @@ -0,0 +1,50 @@ +/* + * 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 "core/object/pcap.h" +#include "core/assert.h" + +#include <stdlib.h> +#include <string.h> + +core_object_pcap_t* core_object_pcap_copy(const core_object_pcap_t* self) +{ + core_object_pcap_t* copy; + glassert_self(); + + glfatal_oom(copy = malloc(sizeof(core_object_pcap_t) + self->caplen)); + memcpy(copy, self, sizeof(core_object_pcap_t)); + copy->obj_prev = 0; + + if (copy->bytes) { + copy->bytes = (void*)copy + sizeof(core_object_pcap_t); + memcpy((void*)copy->bytes, self->bytes, self->caplen); + } + + return copy; +} + +void core_object_pcap_free(core_object_pcap_t* self) +{ + glassert_self(); + free(self); +} diff --git a/include/dnsjit/core/object/pcap.h b/include/dnsjit/core/object/pcap.h new file mode 100644 index 0000000..afcccf3 --- /dev/null +++ b/include/dnsjit/core/object/pcap.h @@ -0,0 +1,38 @@ +/* + * 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/object.h> +#include <dnsjit/core/timespec.h> + +#ifndef __dnsjit_core_object_pcap_h +#define __dnsjit_core_object_pcap_h + +#include <dnsjit/core/object/pcap.hh> + +#define CORE_OBJECT_PCAP_INIT(prev) \ + { \ + CORE_OBJECT_INIT(CORE_OBJECT_PCAP, prev) \ + , \ + 0, 0, \ + { 0, 0 }, 0, 0, 0, \ + 0 \ + } + +#endif diff --git a/include/dnsjit/core/object/pcap.hh b/include/dnsjit/core/object/pcap.hh new file mode 100644 index 0000000..642a7e7 --- /dev/null +++ b/include/dnsjit/core/object/pcap.hh @@ -0,0 +1,38 @@ +/* + * 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.object_h") +//lua:require("dnsjit.core.timespec_h") + +typedef struct core_object_pcap { + const core_object_t* obj_prev; + int32_t obj_type; + + uint32_t snaplen, linktype; + + core_timespec_t ts; + uint32_t caplen, len; + const unsigned char* bytes; + + uint8_t is_swapped; +} core_object_pcap_t; + +core_object_pcap_t* core_object_pcap_copy(const core_object_pcap_t* self); +void core_object_pcap_free(core_object_pcap_t* self); diff --git a/include/dnsjit/core/object/pcap.lua b/include/dnsjit/core/object/pcap.lua new file mode 100644 index 0000000..3d49326 --- /dev/null +++ b/include/dnsjit/core/object/pcap.lua @@ -0,0 +1,98 @@ +-- 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.object.pcap +-- Container of a packet found in a PCAP +-- +-- Container of a PCAP packet which contains information both from the PCAP +-- itself and the +-- .I pcap_pkthdr +-- object receied for each packet in the PCAP. +-- .SS Attributes +-- .TP +-- snaplen +-- Max length saved portion of each packet. +-- .TP +-- linktype +-- Data link type for the PCAP. +-- .TP +-- ts +-- Time stamp of this packet. +-- .TP +-- caplen +-- Length of portion present. +-- .TP +-- len +-- Length of this packet (off wire). +-- .TP +-- bytes +-- A pointer to the packet. +-- .TP +-- is_swapped +-- Indicate if the byte order of the PCAP is different then the host. +-- This is used in, for example, the Layer filter to correctly parse null +-- objects since they are stored in the capturers host byte order. +module(...,package.seeall) + +require("dnsjit.core.object.pcap_h") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "core_object_pcap_t" +local core_object_pcap_t +local Pcap = {} + +-- Return the textual type of the object. +function Pcap:type() + return "pcap" +end + +-- Return the previous object. +function Pcap:prev() + return self.obj_prev +end + +-- Cast the object to the underlining object module and return it. +function Pcap:cast() + return self +end + +-- Cast the object to the generic object module and return it. +function Pcap:uncast() + return ffi.cast("core_object_t*", self) +end + +-- Make a copy of the object and return it. +function Pcap:copy() + return C.core_object_pcap_copy(self) +end + +-- Free the object, should only be used on copies or otherwise allocated. +function Pcap:free() + C.core_object_pcap_free(self) +end + +core_object_pcap_t = ffi.metatype(t_name, { __index = Pcap }) + +-- dnsjit.core.object (3), +-- dnsjit.input.pcap (3), +-- dnsjit.input.fpcap (3), +-- dnsjit.input.mmpcap (3), +-- dnsjit.filter.layer (3), +-- dnsjit.output.pcap (3) +return Pcap diff --git a/include/dnsjit/core/object/tcp.c b/include/dnsjit/core/object/tcp.c new file mode 100644 index 0000000..37f9548 --- /dev/null +++ b/include/dnsjit/core/object/tcp.c @@ -0,0 +1,45 @@ +/* + * 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 "core/object/tcp.h" +#include "core/assert.h" + +#include <stdlib.h> +#include <string.h> + +core_object_tcp_t* core_object_tcp_copy(const core_object_tcp_t* self) +{ + core_object_tcp_t* copy; + glassert_self(); + + glfatal_oom(copy = malloc(sizeof(core_object_tcp_t))); + memcpy(copy, self, sizeof(core_object_tcp_t)); + copy->obj_prev = 0; + + return copy; +} + +void core_object_tcp_free(core_object_tcp_t* self) +{ + glassert_self(); + free(self); +} diff --git a/include/dnsjit/core/object/tcp.h b/include/dnsjit/core/object/tcp.h new file mode 100644 index 0000000..e851a8a --- /dev/null +++ b/include/dnsjit/core/object/tcp.h @@ -0,0 +1,39 @@ +/* + * 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/object.h> +#include <dnsjit/core/timespec.h> + +#ifndef __dnsjit_core_object_tcp_h +#define __dnsjit_core_object_tcp_h + +#include <stddef.h> + +#include <dnsjit/core/object/tcp.hh> + +#define CORE_OBJECT_TCP_INIT(prev) \ + { \ + CORE_OBJECT_INIT(CORE_OBJECT_TCP, prev) \ + , \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + { 0 }, 0 \ + } + +#endif diff --git a/include/dnsjit/core/object/tcp.hh b/include/dnsjit/core/object/tcp.hh new file mode 100644 index 0000000..bd3167d --- /dev/null +++ b/include/dnsjit/core/object/tcp.hh @@ -0,0 +1,43 @@ +/* + * 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.object_h") + +typedef struct core_object_tcp { + const core_object_t* obj_prev; + int32_t obj_type; + + uint16_t sport; + uint16_t dport; + uint32_t seq; + uint32_t ack; + uint8_t off : 4; + uint8_t x2 : 4; + uint8_t flags; + uint16_t win; + uint16_t sum; + uint16_t urp; + + uint8_t opts[64]; + size_t opts_len; +} core_object_tcp_t; + +core_object_tcp_t* core_object_tcp_copy(const core_object_tcp_t* self); +void core_object_tcp_free(core_object_tcp_t* self); diff --git a/include/dnsjit/core/object/tcp.lua b/include/dnsjit/core/object/tcp.lua new file mode 100644 index 0000000..e1d6dc2 --- /dev/null +++ b/include/dnsjit/core/object/tcp.lua @@ -0,0 +1,110 @@ +-- 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.object.tcp +-- A TCP segment header +-- +-- A TCP segment header. +-- The data itself is in the +-- .I dnsjit.core.object.payload +-- object, which is the next object in the chain after parsing with, +-- for example, +-- .IR dnsjit.filter.layer . +-- .SS Attributes +-- .TP +-- sport +-- Source port. +-- .TP +-- dport +-- Destination port. +-- .TP +-- seq +-- Sequence number. +-- .TP +-- ack +-- Acknowledgement number. +-- .TP +-- off +-- Data offset. +-- .TP +-- x2 +-- Unused. +-- .TP +-- flags +-- TCP flags. +-- .TP +-- win +-- Window. +-- .TP +-- sum +-- Checksum. +-- .TP +-- urp +-- Urgent pointer. +-- .TP +-- opts +-- Array of bytes with the TCP options found. +-- .TP +-- opts_len +-- Length of the TCP options. +module(...,package.seeall) + +require("dnsjit.core.object.tcp_h") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "core_object_tcp_t" +local core_object_tcp_t +local Tcp = {} + +-- Return the textual type of the object. +function Tcp:type() + return "tcp" +end + +-- Return the previous object. +function Tcp:prev() + return self.obj_prev +end + +-- Cast the object to the underlining object module and return it. +function Tcp:cast() + return self +end + +-- Cast the object to the generic object module and return it. +function Tcp:uncast() + return ffi.cast("core_object_t*", self) +end + +-- Make a copy of the object and return it. +function Tcp:copy() + return C.core_object_tcp_copy(self) +end + +-- Free the object, should only be used on copies or otherwise allocated. +function Tcp:free() + C.core_object_tcp_free(self) +end + +core_object_tcp_t = ffi.metatype(t_name, { __index = Tcp }) + +-- dnsjit.core.object (3), +-- dnsjit.core.object.payload (3), +-- dnsjit.filter.layer (3) +return Tcp diff --git a/include/dnsjit/core/object/udp.c b/include/dnsjit/core/object/udp.c new file mode 100644 index 0000000..3d05002 --- /dev/null +++ b/include/dnsjit/core/object/udp.c @@ -0,0 +1,45 @@ +/* + * 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 "core/object/udp.h" +#include "core/assert.h" + +#include <stdlib.h> +#include <string.h> + +core_object_udp_t* core_object_udp_copy(const core_object_udp_t* self) +{ + core_object_udp_t* copy; + glassert_self(); + + glfatal_oom(copy = malloc(sizeof(core_object_udp_t))); + memcpy(copy, self, sizeof(core_object_udp_t)); + copy->obj_prev = 0; + + return copy; +} + +void core_object_udp_free(core_object_udp_t* self) +{ + glassert_self(); + free(self); +} diff --git a/include/dnsjit/core/object/udp.h b/include/dnsjit/core/object/udp.h new file mode 100644 index 0000000..e85208b --- /dev/null +++ b/include/dnsjit/core/object/udp.h @@ -0,0 +1,38 @@ +/* + * 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/object.h> +#include <dnsjit/core/timespec.h> + +#ifndef __dnsjit_core_object_udp_h +#define __dnsjit_core_object_udp_h + +#include <stddef.h> + +#include <dnsjit/core/object/udp.hh> + +#define CORE_OBJECT_UDP_INIT(prev) \ + { \ + CORE_OBJECT_INIT(CORE_OBJECT_UDP, prev) \ + , \ + 0, 0, 0, 0, \ + } + +#endif diff --git a/include/dnsjit/core/object/udp.hh b/include/dnsjit/core/object/udp.hh new file mode 100644 index 0000000..5efbd92 --- /dev/null +++ b/include/dnsjit/core/object/udp.hh @@ -0,0 +1,34 @@ +/* + * 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.object_h") + +typedef struct core_object_udp { + const core_object_t* obj_prev; + int32_t obj_type; + + uint16_t sport; + uint16_t dport; + uint16_t ulen; + uint16_t sum; +} core_object_udp_t; + +core_object_udp_t* core_object_udp_copy(const core_object_udp_t* self); +void core_object_udp_free(core_object_udp_t* self); diff --git a/include/dnsjit/core/object/udp.lua b/include/dnsjit/core/object/udp.lua new file mode 100644 index 0000000..1652574 --- /dev/null +++ b/include/dnsjit/core/object/udp.lua @@ -0,0 +1,86 @@ +-- 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.object.udp +-- A UDP datagram header +-- +-- A UDP datagram header. +-- The data itself is in the +-- .I dnsjit.core.object.payload +-- object, which is the next object in the chain after parsing with, +-- for example, +-- .IR dnsjit.filter.layer . +-- .SS Attributes +-- .TP +-- sport +-- Source port. +-- .TP +-- dport +-- Destination port. +-- .TP +-- ulen +-- UDP length (as described in the UDP header). +-- .TP +-- sum +-- Checksum. +module(...,package.seeall) + +require("dnsjit.core.object.udp_h") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "core_object_udp_t" +local core_object_udp_t +local Udp = {} + +-- Return the textual type of the object. +function Udp:type() + return "udp" +end + +-- Return the previous object. +function Udp:prev() + return self.obj_prev +end + +-- Cast the object to the underlining object module and return it. +function Udp:cast() + return self +end + +-- Cast the object to the generic object module and return it. +function Udp:uncast() + return ffi.cast("core_object_t*", self) +end + +-- Make a copy of the object and return it. +function Udp:copy() + return C.core_object_udp_copy(self) +end + +-- Free the object, should only be used on copies or otherwise allocated. +function Udp:free() + C.core_object_udp_free(self) +end + +core_object_udp_t = ffi.metatype(t_name, { __index = Udp }) + +-- dnsjit.core.object (3), +-- dnsjit.core.object.payload (3), +-- dnsjit.filter.layer (3) +return Udp diff --git a/include/dnsjit/core/objects.lua b/include/dnsjit/core/objects.lua new file mode 100644 index 0000000..ce83cd0 --- /dev/null +++ b/include/dnsjit/core/objects.lua @@ -0,0 +1,61 @@ +-- 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.objects +-- Easy way to import all objects +-- require("dnsjit.core.objects") +-- +-- Helper module to require all available objects, returns what +-- .I dnsjit.core.object +-- returned so that constants like object types can be used. +module(...,package.seeall) + +local object = require("dnsjit.core.object") +require("dnsjit.core.object.pcap") +require("dnsjit.core.object.ether") +require("dnsjit.core.object.null") +require("dnsjit.core.object.loop") +require("dnsjit.core.object.linuxsll") +require("dnsjit.core.object.ieee802") +require("dnsjit.core.object.gre") +require("dnsjit.core.object.ip") +require("dnsjit.core.object.ip6") +require("dnsjit.core.object.icmp") +require("dnsjit.core.object.icmp6") +require("dnsjit.core.object.udp") +require("dnsjit.core.object.tcp") +require("dnsjit.core.object.payload") +require("dnsjit.core.object.dns") + +-- dnsjit.core.object (3), +-- dnsjit.core.object.pcap (3), +-- dnsjit.core.object.ether (3), +-- dnsjit.core.object.null (3), +-- dnsjit.core.object.loop (3), +-- dnsjit.core.object.linuxsll (3), +-- dnsjit.core.object.ieee802 (3), +-- dnsjit.core.object.gre (3), +-- dnsjit.core.object.ip (3), +-- dnsjit.core.object.ip6 (3), +-- dnsjit.core.object.icmp (3), +-- dnsjit.core.object.icmp6 (3), +-- dnsjit.core.object.udp (3), +-- dnsjit.core.object.tcp (3), +-- dnsjit.core.object.payload (3), +-- dnsjit.core.object.dns (3) +return object diff --git a/include/dnsjit/core/producer.c b/include/dnsjit/core/producer.c new file mode 100644 index 0000000..8a85c93 --- /dev/null +++ b/include/dnsjit/core/producer.c @@ -0,0 +1,23 @@ +/* + * 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 "core/producer.h" diff --git a/include/dnsjit/core/producer.h b/include/dnsjit/core/producer.h new file mode 100644 index 0000000..da63c17 --- /dev/null +++ b/include/dnsjit/core/producer.h @@ -0,0 +1,28 @@ +/* + * 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/object.h> + +#ifndef __dnsjit_core_producer_h +#define __dnsjit_core_producer_h + +#include <dnsjit/core/producer.hh> + +#endif diff --git a/include/dnsjit/core/producer.hh b/include/dnsjit/core/producer.hh new file mode 100644 index 0000000..2d64035 --- /dev/null +++ b/include/dnsjit/core/producer.hh @@ -0,0 +1,23 @@ +/* + * 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.object_h") + +typedef const core_object_t* (*core_producer_t)(void* ctx); diff --git a/include/dnsjit/core/producer.lua b/include/dnsjit/core/producer.lua new file mode 100644 index 0000000..42f3e44 --- /dev/null +++ b/include/dnsjit/core/producer.lua @@ -0,0 +1,28 @@ +-- 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.producer +-- Producer interfaces +-- require("dnsjit.core.producer_h") +-- +-- Producer interfaces are used by input, filter and output modules to pass +-- objects for processing. +module(...,package.seeall) + +-- dnsjit.core.object (3) +return diff --git a/include/dnsjit/core/receiver.c b/include/dnsjit/core/receiver.c new file mode 100644 index 0000000..f67be0e --- /dev/null +++ b/include/dnsjit/core/receiver.c @@ -0,0 +1,23 @@ +/* + * 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 "core/receiver.h" diff --git a/include/dnsjit/core/receiver.h b/include/dnsjit/core/receiver.h new file mode 100644 index 0000000..5530b6a --- /dev/null +++ b/include/dnsjit/core/receiver.h @@ -0,0 +1,28 @@ +/* + * 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/object.h> + +#ifndef __dnsjit_core_receiver_h +#define __dnsjit_core_receiver_h + +#include <dnsjit/core/receiver.hh> + +#endif diff --git a/include/dnsjit/core/receiver.hh b/include/dnsjit/core/receiver.hh new file mode 100644 index 0000000..316c9be --- /dev/null +++ b/include/dnsjit/core/receiver.hh @@ -0,0 +1,23 @@ +/* + * 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.object_h") + +typedef void (*core_receiver_t)(void* ctx, const core_object_t* obj); diff --git a/include/dnsjit/core/receiver.lua b/include/dnsjit/core/receiver.lua new file mode 100644 index 0000000..02aa39d --- /dev/null +++ b/include/dnsjit/core/receiver.lua @@ -0,0 +1,28 @@ +-- 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.receiver +-- Receiver interfaces +-- require("dnsjit.core.receiver_h") +-- +-- Receiver interfaces are used by input, filter and output modules to pass +-- objects for processing. +module(...,package.seeall) + +-- dnsjit.core.object (3) +return diff --git a/include/dnsjit/core/thread.c b/include/dnsjit/core/thread.c new file mode 100644 index 0000000..189c720 --- /dev/null +++ b/include/dnsjit/core/thread.c @@ -0,0 +1,229 @@ +/* + * 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 "globals.h" +#include "core/assert.h" +#include "core/thread.h" + +#include <string.h> +#include <lualib.h> +#include <lauxlib.h> + +static core_log_t _log = LOG_T_INIT("core.thread"); +static core_thread_t _defaults = { + LOG_T_INIT_OBJ("core.thread"), + 0, 0, 0, 0, + PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, + 0, 0 +}; + +core_log_t* core_thread_log() +{ + return &_log; +} + +void core_thread_init(core_thread_t* self) +{ + mlassert_self(); + + *self = _defaults; +} + +void core_thread_destroy(core_thread_t* self) +{ + core_thread_item_t* item; + mlassert_self(); + + free(self->bytecode); + while ((item = self->stack)) { + self->stack = item->next; + free(item); + } +} + +static void* _thread(void* vp) +{ + core_thread_t* self = (core_thread_t*)vp; + lua_State* L; + mlassert_self(); + + // TODO: move to dnsjit_newstate() + L = luaL_newstate(); + lassert(L, "could not create new Lua state"); + luaL_openlibs(L); + dnsjit_globals(L); + + for (;;) { + lua_getfield(L, LUA_GLOBALSINDEX, "require"); + lua_pushstring(L, "dnsjit.core.thread"); + if (lua_pcall(L, 1, 1, 0)) { + lcritical("%s", lua_tostring(L, -1)); + break; + } + lua_getfield(L, -1, "_in_thread"); + lua_pushlightuserdata(L, (void*)self); + lua_pushlstring(L, self->bytecode, self->bytecode_len); + if (lua_pcall(L, 2, 0, 0)) { + lcritical("%s", lua_tostring(L, -1)); + } + break; + } + + lua_close(L); + return 0; +} + +int core_thread_start(core_thread_t* self, const char* bytecode, size_t len) +{ + int err; + mlassert_self(); + + if (self->bytecode) { + lfatal("bytecode already set"); + } + + lfatal_oom(self->bytecode = malloc(len)); + memcpy(self->bytecode, bytecode, len); + self->bytecode_len = len; + + if ((err = pthread_create(&self->thr_id, 0, _thread, (void*)self))) { + lcritical("pthread_create() error: %s", core_log_errstr(err)); + return -1; + } + + return 0; +} + +int core_thread_stop(core_thread_t* self) +{ + int err; + mlassert_self(); + + if ((err = pthread_join(self->thr_id, 0))) { + lcritical("pthread_join() error: %s", core_log_errstr(err)); + return -1; + } + + return 0; +} + +inline static void _push(core_thread_t* self, core_thread_item_t* item) +{ + if (pthread_mutex_lock(&self->lock)) { + lfatal("mutex lock failed"); + } + if (!self->last) { + self->stack = self->last = item; + } else { + self->last->next = item; + self->last = item; + } + if (pthread_cond_signal(&self->cond)) { + lfatal("cond signal failed"); + } + if (pthread_mutex_unlock(&self->lock)) { + lfatal("mutex unlock failed"); + } +} + +void core_thread_push(core_thread_t* self, void* ptr, const char* type, size_t type_len, const char* module, size_t module_len) +{ + core_thread_item_t* item; + mlassert_self(); + lassert(ptr, "ptr is nil"); + lassert(type, "type is nil"); + lassert(type_len, "type_len is zero"); + lassert(module, "module is nil"); + lassert(module_len, "module_len is zero"); + + lfatal_oom(item = malloc(sizeof(core_thread_item_t) + type_len + module_len + 2)); + item->next = 0; + item->ptr = ptr; + item->type = ((void*)item) + sizeof(core_thread_item_t); + memcpy(item->type, type, type_len); + item->type[type_len] = 0; + item->module = item->type + type_len + 1; + memcpy(item->module, module, module_len); + item->module[module_len] = 0; + + _push(self, item); +} + +void core_thread_push_string(core_thread_t* self, const char* str, size_t len) +{ + core_thread_item_t* item; + mlassert_self(); + lassert(str, "str is nil"); + lassert(len, "len is zero"); + + lfatal_oom(item = malloc(sizeof(core_thread_item_t) + len + 1)); + item->next = 0; + item->ptr = 0; + item->str = ((void*)item) + sizeof(core_thread_item_t); + memcpy(item->str, str, len); + item->str[len] = 0; + + _push(self, item); +} + +void core_thread_push_int64(core_thread_t* self, int64_t i64) +{ + core_thread_item_t* item; + mlassert_self(); + + lfatal_oom(item = malloc(sizeof(core_thread_item_t))); + item->next = 0; + item->ptr = 0; + item->str = 0; + item->i64 = i64; + + _push(self, item); +} + +const core_thread_item_t* core_thread_pop(core_thread_t* self) +{ + mlassert_self(); + + if (pthread_mutex_lock(&self->lock)) { + lfatal("mutex lock failed"); + } + if (!self->at) { + while (!self->stack) { + if (pthread_cond_wait(&self->cond, &self->lock)) { + lfatal("cond wait failed"); + } + } + self->at = self->stack; + } else { + while (!self->at->next) { + if (pthread_cond_wait(&self->cond, &self->lock)) { + lfatal("cond wait failed"); + } + } + self->at = self->at->next; + } + if (pthread_mutex_unlock(&self->lock)) { + lfatal("mutex unlock failed"); + } + + return self->at; +} diff --git a/include/dnsjit/core/thread.h b/include/dnsjit/core/thread.h new file mode 100644 index 0000000..6b7ede6 --- /dev/null +++ b/include/dnsjit/core/thread.h @@ -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> + +#ifndef __dnsjit_core_thread_h +#define __dnsjit_core_thread_h + +#include <pthread.h> +#include <unistd.h> + +#include <dnsjit/core/thread.hh> + +#endif diff --git a/include/dnsjit/core/thread.hh b/include/dnsjit/core/thread.hh new file mode 100644 index 0000000..a61f8c9 --- /dev/null +++ b/include/dnsjit/core/thread.hh @@ -0,0 +1,56 @@ +/* + * 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.compat_h") +//lua:require("dnsjit.core.log") + +typedef struct core_thread_item core_thread_item_t; +struct core_thread_item { + core_thread_item_t* next; + void* ptr; + char * type, *module; + + char* str; + int64_t i64; +}; + +typedef struct core_thread { + core_log_t _log; + pthread_t thr_id; + core_thread_item_t * stack, *last; + const core_thread_item_t* at; + + pthread_mutex_t lock; + pthread_cond_t cond; + + char* bytecode; + size_t bytecode_len; +} core_thread_t; + +core_log_t* core_thread_log(); + +void core_thread_init(core_thread_t* self); +void core_thread_destroy(core_thread_t* self); +int core_thread_start(core_thread_t* self, const char* bytecode, size_t len); +int core_thread_stop(core_thread_t* self); +void core_thread_push(core_thread_t* self, void* ptr, const char* type, size_t type_len, const char* module, size_t module_len); +void core_thread_push_string(core_thread_t* self, const char* str, size_t len); +void core_thread_push_int64(core_thread_t* self, int64_t i64); +const core_thread_item_t* core_thread_pop(core_thread_t* self); diff --git a/include/dnsjit/core/thread.lua b/include/dnsjit/core/thread.lua new file mode 100644 index 0000000..f225726 --- /dev/null +++ b/include/dnsjit/core/thread.lua @@ -0,0 +1,141 @@ +-- 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.thread +-- POSIX thread with separate Lua state +-- local thr = require("dnsjit.core.thread").new() +-- thr:start(function(thr) +-- print("Hello from thread") +-- print("got:", thr:pop(), " = ", thr:pop(3)) +-- end) +-- thr:push("value from main", 1, 2, 3) +-- thr:stop() +-- +-- Start a new POSIX thread with it's own Lua state. +-- Sharable objects can be passed to the thread by pushing and poping them of +-- the thread stack. +-- The Thread object and any other objects passed to the thread needs to be +-- kept alive as long as the thread is running. +module(...,package.seeall) + +require("dnsjit.core.thread_h") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "core_thread_t" +local core_thread_t +local Thread = { + _in_thread = function(thr, bytecode) + thr = ffi.cast("core_thread_t*", thr) + loadstring(bytecode)(thr) + end +} + +-- Create a new Thread object. +function Thread.new() + local self = core_thread_t() + C.core_thread_init(self) + ffi.gc(self, C.core_thread_destroy) + return self +end + +-- Return the Log object to control logging of this instance or module. +function Thread:log() + if self == nil then + return C.core_thread_log() + end + return self._log +end + +-- Start the thread and execute the given function in a separate Lua state, +-- first argument to the function will be the Thread object that created it. +-- Returns 0 on success. +function Thread:start(func) + local bc = string.dump(func) + return C.core_thread_start(self, bc, #bc) +end + +-- Wait for the thread to return. +-- Returns 0 on success. +function Thread:stop() + return C.core_thread_stop(self) +end + +-- Push string(s), number(s) or sharable object(s) onto the thread stack so +-- they can be retrieved inside the thread using +-- .IR pop() . +-- The sharable object(s) needs to be kept alive as long as the thread is +-- running, strings and numbers are copied. +function Thread:push(...) + for _, obj in pairs({...}) do + local t = type(obj) + if t == "string" then + C.core_thread_push_string(self, obj, #obj) + elseif t == "number" then + C.core_thread_push_int64(self, obj) + else + local ptr, type, module = obj:share() + C.core_thread_push(self, ptr, type, #type, module, #module) + end + end +end + +-- Pop value(s) off the thread stack, should only be called within the thread. +-- If +-- .I num +-- is not given then one value is poped. +-- Returns nil if no values are left on the stack. +function Thread:pop(num) + if num == nil or num == 1 then + local item = C.core_thread_pop(self) + if item == nil then + return + end + if item.ptr == nil then + if item.str == nil then + return tonumber(item.i64) + end + return ffi.string(item.str) + end + require(ffi.string(item.module)) + return ffi.cast(ffi.string(item.type), item.ptr) + end + + local ret = {} + for n = 1, num do + local item = C.core_thread_pop(self) + if item == nil then break end + + if item.ptr == nil then + if item.str == nil then + table.insert(ret, tonumber(item.i64)) + else + table.insert(ret, ffi.string(item.str)) + end + else + require(ffi.string(item.module)) + table.insert(ret, ffi.cast(ffi.string(item.type), item.ptr)) + end + end + return unpack(ret) +end + +core_thread_t = ffi.metatype(t_name, { __index = Thread }) + +-- dnsjit.core.channel (3) +return Thread diff --git a/include/dnsjit/core/timespec.h b/include/dnsjit/core/timespec.h new file mode 100644 index 0000000..2110c6d --- /dev/null +++ b/include/dnsjit/core/timespec.h @@ -0,0 +1,33 @@ +/* + * 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/>. + */ + +#ifndef __dnsjit_core_timespec_h +#define __dnsjit_core_timespec_h + +#include <stdint.h> + +#include <dnsjit/core/timespec.hh> + +#define CORE_TIMESPEC_INIT \ + { \ + 0, 0 \ + } + +#endif diff --git a/include/dnsjit/core/timespec.hh b/include/dnsjit/core/timespec.hh new file mode 100644 index 0000000..17a9551 --- /dev/null +++ b/include/dnsjit/core/timespec.hh @@ -0,0 +1,24 @@ +/* + * 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/>. + */ + +typedef struct core_timespec { + int64_t sec; + int64_t nsec; +} core_timespec_t; diff --git a/include/dnsjit/core/timespec.lua b/include/dnsjit/core/timespec.lua new file mode 100644 index 0000000..05c600f --- /dev/null +++ b/include/dnsjit/core/timespec.lua @@ -0,0 +1,54 @@ +-- 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.receiver +-- Non-system depended time specification structure definition +-- typedef struct core_timespec { +-- 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 diff --git a/include/dnsjit/dnsjit.1in b/include/dnsjit/dnsjit.1in new file mode 100644 index 0000000..ae1ca93 --- /dev/null +++ b/include/dnsjit/dnsjit.1in @@ -0,0 +1,144 @@ +.\" 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/>. +.\" +.TH dnsjit 1 "@PACKAGE_VERSION@" "dnsjit" +.SH NAME +dnsjit \- DNS engine based around LuaJIT for capturing, parsing, replaying and statistics gathering +.SH SYNOPSIS +.SS Run a Lua script +.B dnsjit +.I file.lua +.I ... +.SS Shebang-style + #!/usr/bin/env dnsjit + ... +.SH DESCRIPTION +.B dnsjit +is a combination of parts taken from +.BR dsc , +.BR dnscap , +.BR drool, +and put together around Lua to create a script-based engine for easy +capturing, parsing and statistics gathering of DNS message while also +providing facilities for replaying DNS traffic. +.LP +One of the core functionality that +.B dnsjit +brings is to tie together C and Lua modules through a receiver/receive +interface. +This allows creation of custom chains of functionality to meet various +requirements. +Another core functionality is the ability to parse and process DNS messages +even if the messages are non-compliant with the DNS standards. +.LP +.B NOTE +current implementation is +.I ALPHA +which means functionality are not set and may be changed or removed. +.LP +.SH MODULE CATEGORIES +The following Lua module categories exists: +.TP +.B dnsjit.core +Core modules for handling things like logging, DNS messages and +receiver/receive functionality. +.TP +.B dnsjit.lib +Various Lua libraries or C library bindings. +.TP +.B dnsjit.input +Input modules used to read DNS messages in various ways. +.TP +.B dnsjit.filter +Filter modules to process or manipulate DNS messages. +.TP +.B dnsjit.output +Output modules used to display DNS message, export to various formats or +replay them against other targets. +.LP +See each category's man-page for more information. +.SH LUA GLOBALS +The following Lua global variables are defined: +.TP +.B DNSJIT_VERSION +A string with the full version. +.TP +.B DNSJIT_MAJOR_VERSION +An integer with the major version number. +.TP +.B DNSJIT_MINOR_VERSION +An integer with the minor version number. +.TP +.B DNSJIT_PATCH_VERSION +An integer with the patch version number. +.TP +.B DNSJIT_BUGREPORT +A string with the email address to file bug reports to. +.TP +.B DNSJIT_URL +A string with the URL to the repository issue tracker, preferred place to +file bug reports. +.SH EXAMPLE +Following example display the DNS ID found in queries. +.LP + local input = require("dnsjit.input.pcapthread").new() + local output = require("dnsjit.filter.lua").new() + + output:func(function(filter, object) + local packet = object:cast() + local dns = require("dnsjit.core.object.dns").new(packet) + dns:parse() + print(dns.id) + end) + + input:open_offline("file.pcap") + input:only_queries(true) + input:receiver(output) + input:run() +.LP +See more examples in the +.I examples +directory. +.SH SEE ALSO +.BR dnsjit.core (3), +.BR dnsjit.lib (3), +.BR dnsjit.input (3), +.BR dnsjit.filter (3), +.BR dnsjit.output (3) +.SH AUTHORS +Jerry Lundström, DNS-OARC +.LP +Maintained by DNS-OARC +.LP +.RS +.I https://www.dns-oarc.net/ +.RE +.LP +.SH BUGS +For issues and feature requests please use: +.LP +.RS +\fI@PACKAGE_URL@\fP +.RE +.LP +For question and help please use: +.LP +.RS +\fI@PACKAGE_BUGREPORT@\fP +.RE +.LP diff --git a/include/dnsjit/dnsjit.c b/include/dnsjit/dnsjit.c new file mode 100644 index 0000000..1024c4e --- /dev/null +++ b/include/dnsjit/dnsjit.c @@ -0,0 +1,111 @@ +/* + * 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 "globals.h" +#include "core/log.h" + +#include <lua.h> +#include <lualib.h> +#include <lauxlib.h> + +#include <pthread.h> +#include <signal.h> +#include <string.h> +#include <stdio.h> + +static void* _sighthr(void* arg) +{ + sigset_t* set = (sigset_t*)arg; + int sig = 0, err; + + if ((err = sigwait(set, &sig))) { + gldebug("sigwait %d", err); + } + glfatal("signal %d", sig); + + return 0; +} + +int main(int argc, char* argv[]) +{ + lua_State* L; + int n, err; + sigset_t set; + pthread_t sighthr; + + if (argc < 2) { + fprintf(stderr, "usage: %s <file.lua> ...\n", argv[0]); + exit(1); + } + + sigfillset(&set); + if ((err = pthread_sigmask(SIG_BLOCK, &set, 0))) { + glfatal("Unable to set blocked signals with pthread_sigmask()"); + return 2; + } + + sigemptyset(&set); + sigaddset(&set, SIGTERM); + sigaddset(&set, SIGQUIT); + sigaddset(&set, SIGINT); + + if ((err = pthread_create(&sighthr, 0, _sighthr, &set))) { + glfatal("Unable to start signal thread with pthread_create()"); + return 2; + } + + L = luaL_newstate(); + luaL_openlibs(L); + dnsjit_globals(L); + + lua_createtable(L, argc, 0); + for (n = 0; n < argc; n++) { + lua_pushstring(L, argv[n]); + lua_rawseti(L, -2, n); + } + lua_setglobal(L, "arg"); + if ((err = luaL_loadfile(L, argv[1]))) { + switch (err) { + case LUA_ERRSYNTAX: + glcritical("%s: syntax error during pre-compilation", argv[1]); + break; + case LUA_ERRMEM: + glcritical("%s: memory allocation error", argv[1]); + break; + case LUA_ERRFILE: + glcritical("%s: cannot open/read file", argv[1]); + break; + default: + glcritical("%s: unknown error %d", argv[1], err); + break; + } + return 1; + } + if (lua_pcall(L, 0, 0, 0)) { + glcritical("%s: %s", argv[1], lua_tostring(L, -1)); + lua_pop(L, 1); + return 1; + } + lua_close(L); + + return 0; +} diff --git a/include/dnsjit/filter.lua b/include/dnsjit/filter.lua new file mode 100644 index 0000000..fbb3736 --- /dev/null +++ b/include/dnsjit/filter.lua @@ -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/>. + +-- dnsjit.filter +-- Filter/processing modules for dnsjit +-- +-- Filter modules to process or manipulate objects, packets and/or DNS +-- messages. +module(...,package.seeall) + +-- dnsjit.filter.copy (3), +-- dnsjit.filter.ipsplit (3), +-- dnsjit.filter.layer (3), +-- dnsjit.filter.split (3), +-- dnsjit.filter.timing (3) +return diff --git a/include/dnsjit/filter/copy.c b/include/dnsjit/filter/copy.c new file mode 100644 index 0000000..04a90ef --- /dev/null +++ b/include/dnsjit/filter/copy.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2019, 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 "filter/copy.h" +#include "core/assert.h" + +static core_log_t _log = LOG_T_INIT("filter.copy"); +static filter_copy_t _defaults = { + LOG_T_INIT_OBJ("filter.copy"), + 0, 0, + 0 +}; + +core_log_t* filter_copy_log() +{ + return &_log; +} + +void filter_copy_init(filter_copy_t* self) +{ + mlassert_self(); + + *self = _defaults; +} + +void filter_copy_destroy(filter_copy_t* self) +{ + mlassert_self(); +} + +void filter_copy_set(filter_copy_t* self, int32_t obj_type) +{ + mlassert_self(); + + switch (obj_type) { + case CORE_OBJECT_NONE: + self->copy |= 0x1; + break; + case CORE_OBJECT_PCAP: + self->copy |= 0x2; + break; + case CORE_OBJECT_ETHER: + self->copy |= 0x4; + break; + case CORE_OBJECT_NULL: + self->copy |= 0x8; + break; + case CORE_OBJECT_LOOP: + self->copy |= 0x10; + break; + case CORE_OBJECT_LINUXSLL: + self->copy |= 0x20; + break; + case CORE_OBJECT_IEEE802: + self->copy |= 0x40; + break; + case CORE_OBJECT_GRE: + self->copy |= 0x80; + break; + case CORE_OBJECT_IP: + self->copy |= 0x100; + break; + case CORE_OBJECT_IP6: + self->copy |= 0x200; + break; + case CORE_OBJECT_ICMP: + self->copy |= 0x400; + break; + case CORE_OBJECT_ICMP6: + self->copy |= 0x800; + break; + case CORE_OBJECT_UDP: + self->copy |= 0x1000; + break; + case CORE_OBJECT_TCP: + self->copy |= 0x2000; + break; + case CORE_OBJECT_PAYLOAD: + self->copy |= 0x4000; + break; + case CORE_OBJECT_DNS: + self->copy |= 0x8000; + break; + default: + lfatal("unknown type %d", obj_type); + } +} + +uint64_t filter_copy_get(filter_copy_t* self, int32_t obj_type) +{ + mlassert_self(); + + switch (obj_type) { + case CORE_OBJECT_NONE: + return self->copy & 0x1; + case CORE_OBJECT_PCAP: + return self->copy & 0x2; + case CORE_OBJECT_ETHER: + return self->copy & 0x4; + case CORE_OBJECT_NULL: + return self->copy & 0x8; + case CORE_OBJECT_LOOP: + return self->copy & 0x10; + case CORE_OBJECT_LINUXSLL: + return self->copy & 0x20; + case CORE_OBJECT_IEEE802: + return self->copy & 0x40; + case CORE_OBJECT_GRE: + return self->copy & 0x80; + case CORE_OBJECT_IP: + return self->copy & 0x100; + case CORE_OBJECT_IP6: + return self->copy & 0x200; + case CORE_OBJECT_ICMP: + return self->copy & 0x400; + case CORE_OBJECT_ICMP6: + return self->copy & 0x800; + case CORE_OBJECT_UDP: + return self->copy & 0x1000; + case CORE_OBJECT_TCP: + return self->copy & 0x2000; + case CORE_OBJECT_PAYLOAD: + return self->copy & 0x4000; + case CORE_OBJECT_DNS: + return self->copy & 0x8000; + default: + lfatal("unknown type %d", obj_type); + } + return 0; +} + +static void _receive(filter_copy_t* self, const core_object_t* obj) +{ + mlassert_self(); + lassert(obj, "obj is nil"); + + core_object_t* outobj = NULL; + core_object_t* next = NULL; + core_object_t* current = NULL; + const core_object_t* srcobj = obj; + + do { + if (filter_copy_get(self, srcobj->obj_type)) { + next = current; + current = core_object_copy(srcobj); + if (next == NULL) { + next = current; + outobj = current; + } else { + next->obj_prev = current; + } + } + srcobj = srcobj->obj_prev; + } while (srcobj != NULL); + + if (outobj == NULL) { + lnotice("object discarded (no types to copy)"); + return; + } + + self->recv(self->recv_ctx, outobj); +} + +core_receiver_t filter_copy_receiver(filter_copy_t* self) +{ + mlassert_self(); + + if (!self->recv) { + lfatal("no receiver(s) set"); + } + + return (core_receiver_t)_receive; +} diff --git a/include/dnsjit/filter/copy.h b/include/dnsjit/filter/copy.h new file mode 100644 index 0000000..d65a552 --- /dev/null +++ b/include/dnsjit/filter/copy.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2019, 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 <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 <dnsjit/filter/copy.hh> + +#endif diff --git a/include/dnsjit/filter/copy.hh b/include/dnsjit/filter/copy.hh new file mode 100644 index 0000000..edf7fc7 --- /dev/null +++ b/include/dnsjit/filter/copy.hh @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019, 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 struct filter_copy { + core_log_t _log; + + core_receiver_t recv; + void* recv_ctx; + + uint64_t copy; +} filter_copy_t; + +core_log_t* filter_copy_log(); + +void filter_copy_init(filter_copy_t* self); +void filter_copy_destroy(filter_copy_t* self); +void filter_copy_set(filter_copy_t* self, int32_t obj_type); +uint64_t filter_copy_get(filter_copy_t* self, int32_t obj_type); + +core_receiver_t filter_copy_receiver(filter_copy_t* self); diff --git a/include/dnsjit/filter/copy.lua b/include/dnsjit/filter/copy.lua new file mode 100644 index 0000000..4be469f --- /dev/null +++ b/include/dnsjit/filter/copy.lua @@ -0,0 +1,74 @@ +-- Copyright (c) 2019 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.filter.copy +-- Creates a copy of an object chain with selected object types. +-- local copy = require("dnsjit.filter.copy").new() +-- local object = require("dnsjit.core.objects") +-- copy:obj_type(object.PAYLOAD) +-- copy:obj_type(object.IP6) +-- channel:receiver(copy) +-- +-- Filter to create a copy of the object chain with selected object types. +-- The user is responsible for manually freeing the created object chain. +module(...,package.seeall) + +require("dnsjit.filter.copy_h") +local object = require("dnsjit.core.object") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "filter_copy_t" +local filter_copy_t = ffi.typeof(t_name) +local Copy = {} + +-- Create a new Copy filter. +function Copy.new() + local self = { + obj = filter_copy_t(), + } + C.filter_copy_init(self.obj) + ffi.gc(self.obj, C.filter_copy_destroy) + return setmetatable(self, { __index = Copy }) +end + +-- Return the Log object to control logging of this instance or module. +function Copy:log() + if self == nil then + return C.filter_copy_log() + end + return self.obj._log +end + +-- Set the object type to be copied. Can be called multiple times to copy +-- multiple object types from the object chain. +function Copy:obj_type(obj_type) + C.filter_copy_set(self.obj, obj_type) +end + +-- Return the C functions and context for receiving objects. +function Copy:receive() + return C.filter_copy_receiver(self.obj), self.obj +end + +-- Set the receiver to pass objects to. +function Copy:receiver(o) + self.obj.recv, self.obj.recv_ctx = o:receive() +end + +return Copy diff --git a/include/dnsjit/filter/ipsplit.c b/include/dnsjit/filter/ipsplit.c new file mode 100644 index 0000000..8632e2e --- /dev/null +++ b/include/dnsjit/filter/ipsplit.c @@ -0,0 +1,270 @@ +/* + * 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 "filter/ipsplit.h" +#include "core/assert.h" +#include "core/object/ip.h" +#include "core/object/ip6.h" +#include "lib/trie.h" + +#include <string.h> + +typedef struct _filter_ipsplit { + filter_ipsplit_t pub; + + trie_t* trie; + uint32_t weight_total; +} _filter_ipsplit_t; + +typedef struct _client { + /* Receiver-specific client ID (1..N) in host byte order. */ + /* Client ID starts at 1 to avoid issues with lua. */ + uint8_t id[4]; + + filter_ipsplit_recv_t* recv; +} _client_t; + +#define _self ((_filter_ipsplit_t*)self) + +static core_log_t _log = LOG_T_INIT("filter.ipsplit"); +static filter_ipsplit_t _defaults = { + LOG_T_INIT_OBJ("filter.ipsplit"), + IPSPLIT_MODE_SEQUENTIAL, IPSPLIT_OVERWRITE_NONE, + 0, + NULL +}; + +core_log_t* filter_ipsplit_log() +{ + return &_log; +} + +filter_ipsplit_t* filter_ipsplit_new() +{ + filter_ipsplit_t* self; + + mlfatal_oom(self = malloc(sizeof(_filter_ipsplit_t))); + *self = _defaults; + lfatal_oom(_self->trie = trie_create(NULL)); + _self->weight_total = 0; + + return self; +} + +static int _free_trie_value(trie_val_t* val, void* ctx) +{ + free(*val); + return 0; +} + +void filter_ipsplit_free(filter_ipsplit_t* self) +{ + filter_ipsplit_recv_t* first; + filter_ipsplit_recv_t* r; + mlassert_self(); + + trie_apply(_self->trie, _free_trie_value, NULL); + trie_free(_self->trie); + + if (self->recv) { + first = self->recv; + do { + r = self->recv->next; + free(self->recv); + self->recv = r; + } while (self->recv != first); + } + + free(self); +} + +void filter_ipsplit_add(filter_ipsplit_t* self, core_receiver_t recv, void* ctx, uint32_t weight) +{ + filter_ipsplit_recv_t* r; + mlassert_self(); + lassert(recv, "recv is nil"); + lassert(weight > 0, "weight must be positive integer"); + + _self->weight_total += weight; + + lfatal_oom(r = malloc(sizeof(filter_ipsplit_recv_t))); + r->recv = recv; + r->ctx = ctx; + r->n_clients = 0; + r->weight = weight; + + if (!self->recv) { + r->next = r; + self->recv = r; + } else { + r->next = self->recv->next; + self->recv->next = r; + } +} + +/* + * Use portable pseudo-random number generator. + */ +static uint32_t _rand_val = 1; + +static uint32_t _rand() +{ + _rand_val = ((_rand_val * 1103515245) + 12345) & 0x7fffffff; + return _rand_val; +} + +void filter_ipsplit_srand(uint32_t seed) +{ + _rand_val = seed; +} + +static void _assign_client_to_receiver(filter_ipsplit_t* self, _client_t* client) +{ + uint32_t id = 0; + filter_ipsplit_recv_t* recv = 0; + + switch (self->mode) { + case IPSPLIT_MODE_SEQUENTIAL: + recv = self->recv; + id = ++recv->n_clients; + /* When *weight* clients are assigned, switch to next receiver. */ + if (recv->n_clients % recv->weight == 0) + self->recv = recv->next; + break; + case IPSPLIT_MODE_RANDOM: { + /* Get random number from [1, weight_total], then iterate through + * receivers until their weights add up to at least this value. */ + int32_t random = (int32_t)(_rand() % _self->weight_total) + 1; + while (random > 0) { + random -= self->recv->weight; + if (random > 0) + self->recv = self->recv->next; + } + recv = self->recv; + id = ++recv->n_clients; + break; + } + default: + lfatal("invalid ipsplit mode"); + } + + client->recv = recv; + memcpy(client->id, &id, sizeof(client->id)); +} + +/* + * Optionally, write client ID into byte 0-3 of src/dst IP address in the packet. + * + * Client ID is a 4-byte array in host byte order. + */ +static void _overwrite(filter_ipsplit_t* self, core_object_t* obj, _client_t* client) +{ + mlassert_self(); + lassert(obj, "invalid object"); + lassert(client, "invalid client"); + + core_object_ip_t* ip; + core_object_ip6_t* ip6; + + switch (self->overwrite) { + case IPSPLIT_OVERWRITE_NONE: + return; + case IPSPLIT_OVERWRITE_SRC: + if (obj->obj_type == CORE_OBJECT_IP) { + ip = (core_object_ip_t*)obj; + memcpy(&ip->src, client->id, sizeof(client->id)); + } else if (obj->obj_type == CORE_OBJECT_IP6) { + ip6 = (core_object_ip6_t*)obj; + memcpy(&ip6->src, client->id, sizeof(client->id)); + } + break; + case IPSPLIT_OVERWRITE_DST: + if (obj->obj_type == CORE_OBJECT_IP) { + ip = (core_object_ip_t*)obj; + memcpy(&ip->dst, client->id, sizeof(client->id)); + } else if (obj->obj_type == CORE_OBJECT_IP6) { + ip6 = (core_object_ip6_t*)obj; + memcpy(&ip6->dst, client->id, sizeof(client->id)); + } + break; + default: + lfatal("invalid overwrite mode"); + } +} + +static void _receive(filter_ipsplit_t* self, const core_object_t* obj) +{ + mlassert_self(); + + /* Find ip/ip6 object in chain. */ + core_object_t* pkt = (core_object_t*)obj; + while (pkt != NULL) { + if (pkt->obj_type == CORE_OBJECT_IP || pkt->obj_type == CORE_OBJECT_IP6) + break; + pkt = (core_object_t*)pkt->obj_prev; + } + if (pkt == NULL) { + self->discarded++; + lwarning("packet discarded (missing ip/ip6 object)"); + return; + } + + /* Lookup IPv4/IPv6 address in trie (prefix-tree). Inserts new node if not found. */ + trie_val_t* node = 0; + switch (pkt->obj_type) { + case CORE_OBJECT_IP: { + core_object_ip_t* ip = (core_object_ip_t*)pkt; + node = trie_get_ins(_self->trie, ip->src, sizeof(ip->src)); + break; + } + case CORE_OBJECT_IP6: { + core_object_ip6_t* ip6 = (core_object_ip6_t*)pkt; + node = trie_get_ins(_self->trie, ip6->src, sizeof(ip6->src)); + break; + } + default: + lfatal("unsupported object type"); + } + lassert(node, "trie failure"); + + _client_t* client; + if (*node == NULL) { /* IP address not found in tree -> create new client. */ + lfatal_oom(client = malloc(sizeof(_client_t))); + *node = (void*)client; + _assign_client_to_receiver(self, client); + } + + client = (_client_t*)*node; + _overwrite(self, pkt, client); + client->recv->recv(client->recv->ctx, obj); +} + +core_receiver_t filter_ipsplit_receiver(filter_ipsplit_t* self) +{ + mlassert_self(); + + if (!self->recv) { + lfatal("no receiver(s) set"); + } + + return (core_receiver_t)_receive; +} diff --git a/include/dnsjit/filter/ipsplit.h b/include/dnsjit/filter/ipsplit.h new file mode 100644 index 0000000..aa64878 --- /dev/null +++ b/include/dnsjit/filter/ipsplit.h @@ -0,0 +1,29 @@ +/* + * 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 <dnsjit/core/log.h> +#include <dnsjit/core/receiver.h> + +#ifndef __dnsjit_filter_ipsplit_h +#define __dnsjit_filter_ipsplit_h + +#include <dnsjit/filter/ipsplit.hh> + +#endif diff --git a/include/dnsjit/filter/ipsplit.hh b/include/dnsjit/filter/ipsplit.hh new file mode 100644 index 0000000..c362ac3 --- /dev/null +++ b/include/dnsjit/filter/ipsplit.hh @@ -0,0 +1,61 @@ +/* + * 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/>. + */ + +//lua:require("dnsjit.core.log") +//lua:require("dnsjit.core.receiver_h") + +typedef struct filter_ipsplit_recv filter_ipsplit_recv_t; +struct filter_ipsplit_recv { + filter_ipsplit_recv_t* next; + + core_receiver_t recv; + void* ctx; + + uint32_t n_clients; /* Total number of clients assigned to this receiver. */ + + uint32_t weight; +}; + +typedef struct filter_ipsplit { + core_log_t _log; + + enum { + IPSPLIT_MODE_SEQUENTIAL = 0, + IPSPLIT_MODE_RANDOM = 1 + } mode; + enum { + IPSPLIT_OVERWRITE_NONE = 0, + IPSPLIT_OVERWRITE_SRC = 1, + IPSPLIT_OVERWRITE_DST = 2 + } overwrite; + + uint64_t discarded; + + filter_ipsplit_recv_t* recv; +} filter_ipsplit_t; + +core_log_t* filter_ipsplit_log(); + +filter_ipsplit_t* filter_ipsplit_new(); +void filter_ipsplit_free(filter_ipsplit_t* self); +void filter_ipsplit_add(filter_ipsplit_t* self, core_receiver_t recv, void* ctx, uint32_t weight); +void filter_ipsplit_srand(unsigned int seed); + +core_receiver_t filter_ipsplit_receiver(filter_ipsplit_t* self); diff --git a/include/dnsjit/filter/ipsplit.lua b/include/dnsjit/filter/ipsplit.lua new file mode 100644 index 0000000..cca0249 --- /dev/null +++ b/include/dnsjit/filter/ipsplit.lua @@ -0,0 +1,122 @@ +-- 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/>. + +-- dnsjit.filter.ipsplit +-- Pass objects to receivers based on the source IP address +-- local ipsplit = require("dnsjit.filter.ipsplit").new() +-- ipsplit.receiver(...) +-- ipsplit.receiver(...) +-- ipsplit.receiver(...) +-- input.receiver(ipsplit) +-- +-- The filter passes objects to other receivers. +-- Object chains without IPv4/IPv6 packet are discarded. +-- Packets which have the same source IP address are considered to be sent +-- from the same "client". +-- When the first packet from a client is processed, the client is assigned +-- to a receiver. +-- All objects from this client will be passed to the assigned receiver. +-- The filter can also write a receiver-specific client ID (starting from 1) +-- to the source or destination IP in the packet. +module(...,package.seeall) + +require("dnsjit.filter.ipsplit_h") +local bit = require("bit") +local object = require("dnsjit.core.objects") +local ffi = require("ffi") +local C = ffi.C + +local IpSplit = {} + +-- Create a new IpSplit filter. +function IpSplit.new() + local self = { + obj = C.filter_ipsplit_new(), + } + ffi.gc(self.obj, C.filter_ipsplit_free) + return setmetatable(self, { __index = IpSplit }) +end + +-- Return the Log object to control logging of this instance or module. +function IpSplit:log() + if self == nil then + return C.filter_ipsplit_log() + end + return self.obj._log +end + +-- Return the C functions and context for receiving objects. +function IpSplit:receive() + local recv = C.filter_ipsplit_receiver(self.obj) + return recv, self.obj +end + +-- Set the receiver to pass objects to, this can be called multiple times to +-- set additional receivers. +-- The weight parameter can be used to adjust distribution of clients among +-- receivers. +-- Weight must be a positive integer (default is 1). +function IpSplit:receiver(o, weight) + local recv, ctx = o:receive() + if weight == nil then + weight = 1 + end + C.filter_ipsplit_add(self.obj, recv, ctx, weight) +end + +-- Number of input packets discarded due to various reasons. +-- To investigate causes, run with increased logging level. +function IpSplit:discarded() + return tonumber(self.obj.discarded) +end + +-- Set the client assignment mode to sequential. +-- Assigns `weight` clients to a receiver before continuing with the next +-- receiver (default mode). +function IpSplit:sequential() + self.obj.mode = "IPSPLIT_MODE_SEQUENTIAL" +end + +-- Set the client assignment mode to random. +-- Each client is randomly assigned to a receiver (weight affects the +-- probability). +-- The client assignment is stable (and portable) for given seed. +function IpSplit:random(seed) + self.obj.mode = "IPSPLIT_MODE_RANDOM" + if seed then + C.filter_ipsplit_srand(seed) + end +end + +-- Don't overwrite source or destination IP (default). +function IpSplit:overwrite_none() + self.obj.overwrite = "IPSPLIT_OVERWRITE_NONE" +end + +-- Write receiver-specific client ID to bytes 0-3 of source IP (host byte order). +function IpSplit:overwrite_src() + self.obj.overwrite = "IPSPLIT_OVERWRITE_SRC" +end + +-- Write receiver-specific client ID to bytes 0-3 of destination IP (host byte +-- order). +function IpSplit:overwrite_dst() + self.obj.overwrite = "IPSPLIT_OVERWRITE_DST" +end + +return IpSplit diff --git a/include/dnsjit/filter/layer.c b/include/dnsjit/filter/layer.c new file mode 100644 index 0000000..b360ca3 --- /dev/null +++ b/include/dnsjit/filter/layer.c @@ -0,0 +1,689 @@ +/* + * 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 "filter/layer.h" +#include "core/assert.h" + +#include <string.h> +#include <pcap/pcap.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/ip6.h> +#ifdef HAVE_NET_ETHERNET_H +#include <net/ethernet.h> +#endif +#ifdef HAVE_NET_ETHERTYPES_H +#include <net/ethertypes.h> +#endif +#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 + +#define N_IEEE802 3 + +static core_log_t _log = LOG_T_INIT("filter.layer"); +static filter_layer_t _defaults = { + LOG_T_INIT_OBJ("filter.layer"), + 0, 0, + 0, 0, + 0, + CORE_OBJECT_NULL_INIT(0), + CORE_OBJECT_ETHER_INIT(0), + CORE_OBJECT_LOOP_INIT(0), + CORE_OBJECT_LINUXSLL_INIT(0), + 0, { CORE_OBJECT_IEEE802_INIT(0), CORE_OBJECT_IEEE802_INIT(0), CORE_OBJECT_IEEE802_INIT(0) }, + CORE_OBJECT_IP_INIT(0), + CORE_OBJECT_IP6_INIT(0), + CORE_OBJECT_GRE_INIT(0), + CORE_OBJECT_ICMP_INIT(0), + CORE_OBJECT_ICMP6_INIT(0), + CORE_OBJECT_UDP_INIT(0), + CORE_OBJECT_TCP_INIT(0), + CORE_OBJECT_PAYLOAD_INIT(0) +}; + +core_log_t* filter_layer_log() +{ + return &_log; +} + +void filter_layer_init(filter_layer_t* self) +{ + mlassert_self(); + + *self = _defaults; +} + +void filter_layer_destroy(filter_layer_t* self) +{ + mlassert_self(); +} + +#define need4x2(v1, v2, p, l) \ + if (l < 1) { \ + break; \ + } \ + v1 = (*p) >> 4; \ + v2 = (*p) & 0xf; \ + p += 1; \ + l -= 1 + +#define need8(v, p, l) \ + if (l < 1) { \ + break; \ + } \ + v = *p; \ + p += 1; \ + l -= 1 + +static inline uint16_t _need16(const void* ptr) +{ + uint16_t v; + memcpy(&v, ptr, sizeof(v)); + return be16toh(v); +} + +#define need16(v, p, l) \ + if (l < 2) { \ + break; \ + } \ + v = _need16(p); \ + p += 2; \ + l -= 2 + +#define needr16(v, p, l) \ + if (l < 2) { \ + break; \ + } \ + v = bswap_16(_need16(p)); \ + p += 2; \ + l -= 2 + +static inline uint32_t _need32(const void* ptr) +{ + uint32_t v; + memcpy(&v, ptr, sizeof(v)); + return be32toh(v); +} + +#define need32(v, p, l) \ + if (l < 4) { \ + break; \ + } \ + v = _need32(p); \ + p += 4; \ + l -= 4 + +#define needr32(v, p, l) \ + if (l < 4) { \ + break; \ + } \ + v = bswap_32(_need32(p)); \ + p += 4; \ + l -= 4 + +#define needxb(b, x, p, l) \ + if (l < x) { \ + break; \ + } \ + memcpy(b, p, x); \ + p += x; \ + l -= x + +#define advancexb(x, p, l) \ + if (l < x) { \ + break; \ + } \ + p += x; \ + l -= x + +//static int _ip(filter_layer_t* self, const core_object_t* obj, const unsigned char* pkt, size_t len); + +static inline int _proto(filter_layer_t* self, uint8_t proto, const core_object_t* obj, const unsigned char* pkt, size_t len) +{ + switch (proto) { + case IPPROTO_GRE: { + core_object_gre_t* gre = &self->gre; + gre->obj_prev = obj; + + need16(gre->gre_flags, pkt, len); + need16(gre->ether_type, pkt, len); + + /* TODO: Incomplete, check RFC 1701 */ + + self->produced = (core_object_t*)gre; + + // if (gre.gre_flags & 0x1) { + // need16(gre.checksum, pkt, len); + // } + // if (gre.gre_flags & 0x4) { + // need16(gre.key, pkt, len); + // } + // if (gre.gre_flags & 0x8) { + // need16(gre.sequence, pkt, len); + // } + // + // switch (gre.ether_type) { + // case ETHERTYPE_IP: + // case ETHERTYPE_IPV6: + // return _ip(self, (core_object_t*)gre, pkt, len); + // + // default: + // break; + // } + break; + } + case IPPROTO_ICMP: { + core_object_icmp_t* icmp = &self->icmp; + icmp->obj_prev = obj; + + need8(icmp->type, pkt, len); + need8(icmp->code, pkt, len); + need16(icmp->cksum, pkt, len); + + self->produced = (core_object_t*)icmp; + break; + } + case IPPROTO_ICMPV6: { + core_object_icmp6_t* icmp6 = &self->icmp6; + icmp6->obj_prev = obj; + + need8(icmp6->type, pkt, len); + need8(icmp6->code, pkt, len); + need16(icmp6->cksum, pkt, len); + + self->produced = (core_object_t*)icmp6; + break; + } + case IPPROTO_UDP: { + core_object_udp_t* udp = &self->udp; + core_object_payload_t* payload = &self->payload; + udp->obj_prev = obj; + + need16(udp->sport, pkt, len); + need16(udp->dport, pkt, len); + need16(udp->ulen, pkt, len); + need16(udp->sum, pkt, len); + + payload->obj_prev = (core_object_t*)udp; + + /* Check for padding */ + if (len > udp->ulen) { + payload->padding = len - udp->ulen; + payload->len = len - payload->padding; + } else { + payload->padding = 0; + payload->len = len; + } + payload->payload = (uint8_t*)pkt; + + self->produced = (core_object_t*)payload; + break; + } + case IPPROTO_TCP: { + core_object_tcp_t* tcp = &self->tcp; + core_object_payload_t* payload = &self->payload; + tcp->obj_prev = obj; + + need16(tcp->sport, pkt, len); + need16(tcp->dport, pkt, len); + need32(tcp->seq, pkt, len); + need32(tcp->ack, pkt, len); + need4x2(tcp->off, tcp->x2, pkt, len); + need8(tcp->flags, pkt, len); + need16(tcp->win, pkt, len); + need16(tcp->sum, pkt, len); + need16(tcp->urp, pkt, len); + if (tcp->off > 5) { + tcp->opts_len = (tcp->off - 5) * 4; + needxb(tcp->opts, tcp->opts_len, pkt, len); + } else { + tcp->opts_len = 0; + } + + payload->obj_prev = (core_object_t*)tcp; + + /* Check for padding */ + if (obj->obj_type == CORE_OBJECT_IP && len > (((const core_object_ip_t*)obj)->len - (((const core_object_ip_t*)obj)->hl * 4))) { + payload->padding = len - (((const core_object_ip_t*)obj)->len - (((const core_object_ip_t*)obj)->hl * 4)); + payload->len = len - payload->padding; + } else if (obj->obj_type == CORE_OBJECT_IP6 && len > ((const core_object_ip6_t*)obj)->plen) { + payload->padding = len - ((const core_object_ip6_t*)obj)->plen; + payload->len = len - payload->padding; + } else { + payload->padding = 0; + payload->len = len; + } + + payload->payload = (uint8_t*)pkt; + + self->produced = (core_object_t*)payload; + break; + } + default: + self->produced = obj; + break; + } + + return 0; +} + +static inline int _ip(filter_layer_t* self, const core_object_t* obj, const unsigned char* pkt, size_t len) +{ + if (len) { + switch ((*pkt >> 4)) { + case 4: { + core_object_ip_t* ip = &self->ip; + + ip->obj_prev = obj; + + need4x2(ip->v, ip->hl, pkt, len); + need8(ip->tos, pkt, len); + need16(ip->len, pkt, len); + need16(ip->id, pkt, len); + need16(ip->off, pkt, len); + need8(ip->ttl, pkt, len); + need8(ip->p, pkt, len); + need16(ip->sum, pkt, len); + needxb(&ip->src, 4, pkt, len); + needxb(&ip->dst, 4, pkt, len); + + /* TODO: IPv4 options */ + + if (ip->hl < 5) + break; + if (ip->hl > 5) { + advancexb((ip->hl - 5) * 4, pkt, len); + } + + /* Check reported length for missing payload */ + if (ip->len < (ip->hl * 4)) { + break; + } + if (len < (ip->len - (ip->hl * 4))) { + break; + } + + if (ip->off & 0x2000 || ip->off & 0x1fff) { + core_object_payload_t* payload = &self->payload; + + payload->obj_prev = (core_object_t*)ip; + + /* Check for padding */ + if (len > (ip->len - (ip->hl * 4))) { + payload->padding = len - (ip->len - (ip->hl * 4)); + payload->len = len - payload->padding; + } else { + payload->padding = 0; + payload->len = len; + } + payload->payload = (uint8_t*)pkt; + + self->produced = (core_object_t*)payload; + return 0; + } + + return _proto(self, ip->p, (core_object_t*)ip, pkt, len); + } + case 6: { + core_object_ip6_t* ip6 = &self->ip6; + struct ip6_ext ext; + + ip6->obj_prev = obj; + ip6->is_frag = ip6->have_rtdst = 0; + + need32(ip6->flow, pkt, len); + need16(ip6->plen, pkt, len); + need8(ip6->nxt, pkt, len); + need8(ip6->hlim, pkt, len); + needxb(&ip6->src, 16, pkt, len); + needxb(&ip6->dst, 16, pkt, len); + + /* Check reported length for missing payload */ + if (len < ip6->plen) { + break; + } + + ext.ip6e_nxt = ip6->nxt; + ext.ip6e_len = 0; + while (ext.ip6e_nxt != IPPROTO_NONE + && ext.ip6e_nxt != IPPROTO_GRE + && ext.ip6e_nxt != IPPROTO_ICMPV6 + && ext.ip6e_nxt != IPPROTO_UDP + && ext.ip6e_nxt != IPPROTO_TCP) { + + /* + * Advance to the start of next header, this may not be needed + * if it's the first header or if the header is supported. + */ + if (ext.ip6e_len) { + advancexb(ext.ip6e_len * 8, pkt, len); + } + + /* TODO: Store IPv6 headers? */ + + /* Handle supported headers */ + if (ext.ip6e_nxt == IPPROTO_FRAGMENT) { + if (ip6->is_frag) { + return 1; + } + need8(ext.ip6e_nxt, pkt, len); + need8(ext.ip6e_len, pkt, len); + if (ext.ip6e_len) { + return 1; + } + need16(ip6->frag_offlg, pkt, len); + need32(ip6->frag_ident, pkt, len); + ip6->is_frag = 1; + } else if (ext.ip6e_nxt == IPPROTO_ROUTING) { + struct ip6_rthdr rthdr; + + if (ip6->have_rtdst) { + return 1; + } + + need8(ext.ip6e_nxt, pkt, len); + need8(ext.ip6e_len, pkt, len); + need8(rthdr.ip6r_type, pkt, len); + need8(rthdr.ip6r_segleft, pkt, len); + advancexb(4, pkt, len); + + if (!rthdr.ip6r_type && rthdr.ip6r_segleft) { + if (ext.ip6e_len & 1) { + return 1; + } + if (ext.ip6e_len > 2) { + advancexb(ext.ip6e_len - 2, pkt, len); + } + needxb(ip6->rtdst, 16, pkt, len); + ip6->have_rtdst = 1; + } + } else { + need8(ext.ip6e_nxt, pkt, len); + need8(ext.ip6e_len, pkt, len); + advancexb(6, pkt, len); + } + } + + if (ext.ip6e_nxt == IPPROTO_NONE || ip6->is_frag) { + core_object_payload_t* payload = &self->payload; + + payload->obj_prev = (core_object_t*)ip6; + + /* Check for padding */ + if (len > ip6->plen) { + payload->padding = len - ip6->plen; + payload->len = len - payload->padding; + } else { + payload->padding = 0; + payload->len = len; + } + payload->payload = (uint8_t*)pkt; + + self->produced = (core_object_t*)payload; + return 0; + } + + return _proto(self, ext.ip6e_nxt, (core_object_t*)ip6, pkt, len); + } + default: + break; + } + } + + self->produced = obj; + + return 0; +} + +static inline int _ieee802(filter_layer_t* self, uint16_t tpid, const core_object_t* obj, const unsigned char* pkt, size_t len) +{ + core_object_ieee802_t* ieee802 = &self->ieee802[self->n_ieee802]; + uint16_t tci; + + ieee802->obj_prev = obj; + + for (;;) { + ieee802->tpid = tpid; + need16(tci, pkt, len); + ieee802->pcp = (tci & 0xe000) >> 13; + ieee802->dei = (tci & 0x1000) >> 12; + ieee802->vid = tci & 0x0fff; + need16(ieee802->ether_type, pkt, len); + + switch (ieee802->ether_type) { + case 0x88a8: /* 802.1ad */ + case 0x9100: /* 802.1 QinQ non-standard */ + self->n_ieee802++; + if (self->n_ieee802 < N_IEEE802) { + obj = (const core_object_t*)ieee802; + ieee802 = &self->ieee802[self->n_ieee802]; + ieee802->obj_prev = obj; + tpid = ieee802->ether_type; + continue; + } + return 1; + + case ETHERTYPE_IP: + case ETHERTYPE_IPV6: + return _ip(self, (core_object_t*)ieee802, pkt, len); + + default: + break; + } + break; + } + + self->produced = obj; + + return 0; +} + +static inline int _link(filter_layer_t* self, const core_object_pcap_t* pcap) +{ + const unsigned char* pkt; + size_t len; + + self->n_ieee802 = 0; + + pkt = pcap->bytes; + len = pcap->caplen; + + switch (pcap->linktype) { + case DLT_NULL: { + core_object_null_t* null = &self->null; + null->obj_prev = (core_object_t*)pcap; + + if (pcap->is_swapped) { + needr32(null->family, pkt, len); + } else { + need32(null->family, pkt, len); + } + + switch (null->family) { + case 2: + case 24: + case 28: + case 30: + return _ip(self, (core_object_t*)null, pkt, len); + + default: + break; + } + break; + } + case DLT_EN10MB: { + core_object_ether_t* ether = &self->ether; + ether->obj_prev = (core_object_t*)pcap; + + needxb(ether->dhost, 6, pkt, len); + needxb(ether->shost, 6, pkt, len); + need16(ether->type, pkt, len); + + switch (ether->type) { + case 0x8100: /* 802.1q */ + case 0x88a8: /* 802.1ad */ + case 0x9100: /* 802.1 QinQ non-standard */ + return _ieee802(self, ether->type, (core_object_t*)ether, pkt, len); + + case ETHERTYPE_IP: + case ETHERTYPE_IPV6: + return _ip(self, (core_object_t*)ether, pkt, len); + + default: + break; + } + break; + } + case DLT_LOOP: { + core_object_loop_t* loop = &self->loop; + loop->obj_prev = (core_object_t*)pcap; + + need32(loop->family, pkt, len); + + switch (loop->family) { + case 2: + case 24: + case 28: + case 30: + return _ip(self, (core_object_t*)loop, pkt, len); + + default: + break; + } + break; + } + case DLT_RAW: +#ifdef DLT_IPV4 + case DLT_IPV4: +#endif +#ifdef DLT_IPV6 + case DLT_IPV6: +#endif + return _ip(self, (core_object_t*)pcap, pkt, len); + case DLT_LINUX_SLL: { + core_object_linuxsll_t* linuxsll = &self->linuxsll; + linuxsll->obj_prev = (core_object_t*)pcap; + + need16(linuxsll->packet_type, pkt, len); + need16(linuxsll->arp_hardware, pkt, len); + need16(linuxsll->link_layer_address_length, pkt, len); + needxb(linuxsll->link_layer_address, 8, pkt, len); + need16(linuxsll->ether_type, pkt, len); + + switch (linuxsll->ether_type) { + case 0x8100: /* 802.1q */ + case 0x88a8: /* 802.1ad */ + case 0x9100: /* 802.1 QinQ non-standard */ + return _ieee802(self, linuxsll->ether_type, (core_object_t*)linuxsll, pkt, len); + + case ETHERTYPE_IP: + case ETHERTYPE_IPV6: + return _ip(self, (core_object_t*)linuxsll, pkt, len); + + default: + break; + } + break; + } + /* TODO: These might be interesting to implement + case DLT_IPNET: + case DLT_PKTAP: + */ + default: + break; + } + + self->produced = (core_object_t*)pcap; + + return 0; +} + +static void _receive(filter_layer_t* self, const core_object_t* obj) +{ + mlassert_self(); + lassert(obj, "obj is nil"); + + if (!self->recv) { + lfatal("no receiver set"); + } + if (obj->obj_type != CORE_OBJECT_PCAP) { + lfatal("obj is not CORE_OBJECT_PCAP"); + } + + if (!_link(self, (core_object_pcap_t*)obj)) { + self->recv(self->ctx, self->produced); + } +} + +core_receiver_t filter_layer_receiver() +{ + return (core_receiver_t)_receive; +} + +static const core_object_t* _produce(filter_layer_t* self) +{ + const core_object_t* obj; + mlassert_self(); + + obj = self->prod(self->prod_ctx); + if (!obj || obj->obj_type != CORE_OBJECT_PCAP || _link(self, (core_object_pcap_t*)obj)) { + return 0; + } + + return self->produced; +} + +core_producer_t filter_layer_producer(filter_layer_t* self) +{ + mlassert_self(); + + if (!self->prod) { + lfatal("no producer set"); + } + + return (core_producer_t)_produce; +} diff --git a/include/dnsjit/filter/layer.h b/include/dnsjit/filter/layer.h new file mode 100644 index 0000000..d7dde4a --- /dev/null +++ b/include/dnsjit/filter/layer.h @@ -0,0 +1,44 @@ +/* + * 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> +#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 <dnsjit/filter/layer.hh> + +#endif diff --git a/include/dnsjit/filter/layer.hh b/include/dnsjit/filter/layer.hh new file mode 100644 index 0000000..f8f260b --- /dev/null +++ b/include/dnsjit/filter/layer.hh @@ -0,0 +1,70 @@ +/* + * 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") +//lua:require("dnsjit.core.object.null_h") +//lua:require("dnsjit.core.object.ether_h") +//lua:require("dnsjit.core.object.loop_h") +//lua:require("dnsjit.core.object.linuxsll_h") +//lua:require("dnsjit.core.object.ieee802_h") +//lua:require("dnsjit.core.object.ip_h") +//lua:require("dnsjit.core.object.ip6_h") +//lua:require("dnsjit.core.object.gre_h") +//lua:require("dnsjit.core.object.icmp_h") +//lua:require("dnsjit.core.object.icmp6_h") +//lua:require("dnsjit.core.object.udp_h") +//lua:require("dnsjit.core.object.tcp_h") +//lua:require("dnsjit.core.object.payload_h") + +typedef struct filter_layer { + core_log_t _log; + core_receiver_t recv; + void* ctx; + + core_producer_t prod; + void* prod_ctx; + + const core_object_t* produced; + core_object_null_t null; + core_object_ether_t ether; + core_object_loop_t loop; + core_object_linuxsll_t linuxsll; + size_t n_ieee802; + core_object_ieee802_t ieee802[3]; // N_IEEE802 + core_object_ip_t ip; + core_object_ip6_t ip6; + core_object_gre_t gre; + core_object_icmp_t icmp; + core_object_icmp6_t icmp6; + core_object_udp_t udp; + core_object_tcp_t tcp; + core_object_payload_t payload; +} filter_layer_t; + +core_log_t* filter_layer_log(); + +void filter_layer_init(filter_layer_t* self); +void filter_layer_destroy(filter_layer_t* self); + +core_receiver_t filter_layer_receiver(); +core_producer_t filter_layer_producer(filter_layer_t* self); diff --git a/include/dnsjit/filter/layer.lua b/include/dnsjit/filter/layer.lua new file mode 100644 index 0000000..74c56ba --- /dev/null +++ b/include/dnsjit/filter/layer.lua @@ -0,0 +1,93 @@ +-- 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.filter.layer +-- Parse the ether/IP stack +-- local filter = require("dnsjit.filter.layer").new() +-- +-- Parse the ether/IP stack of the received objects and send the top most +-- object to the receivers. +-- Objects are chained which each layer in the stack with the top most first. +-- Currently supports input +-- .IR dnsjit.core.object.pcap . +module(...,package.seeall) + +require("dnsjit.filter.layer_h") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "filter_layer_t" +local filter_layer_t = ffi.typeof(t_name) +local Layer = {} + +-- Create a new Layer filter. +function Layer.new() + local self = { + _receiver = nil, + obj = filter_layer_t(), + } + C.filter_layer_init(self.obj) + ffi.gc(self.obj, C.filter_layer_destroy) + return setmetatable(self, { __index = Layer }) +end + +-- Return the Log object to control logging of this instance or module. +function Layer:log() + if self == nil then + return C.filter_layer_log() + end + return self.obj._log +end + +-- Return the C functions and context for receiving objects. +function Layer:receive() + return C.filter_layer_receiver(), self.obj +end + +-- Set the receiver to pass objects to. +function Layer:receiver(o) + self.obj.recv, self.obj.ctx = o:receive() + self._receiver = o +end + +-- Return the C functions and context for producing objects. +function Layer:produce() + return C.filter_layer_producer(self.obj), self.obj +end + +-- Set the producer to get objects from. +function Layer:producer(o) + self.obj.prod, self.obj.prod_ctx = o:produce() + self._producer = o +end + +-- dnsjit.core.object.pcap (3), +-- dnsjit.core.object.ether (3), +-- dnsjit.core.object.null (3), +-- dnsjit.core.object.loop (3), +-- dnsjit.core.object.linuxsll (3), +-- dnsjit.core.object.ieee802 (3), +-- dnsjit.core.object.gre (3), +-- dnsjit.core.object.ip (3), +-- dnsjit.core.object.ip6 (3), +-- dnsjit.core.object.icmp (3), +-- dnsjit.core.object.icmp6 (3), +-- dnsjit.core.object.udp (3), +-- dnsjit.core.object.tcp (3), +-- dnsjit.core.object.payload (3) +return Layer diff --git a/include/dnsjit/filter/split.c b/include/dnsjit/filter/split.c new file mode 100644 index 0000000..dccf38a --- /dev/null +++ b/include/dnsjit/filter/split.c @@ -0,0 +1,114 @@ +/* + * 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 "filter/split.h" +#include "core/assert.h" + +static core_log_t _log = LOG_T_INIT("filter.split"); +static filter_split_t _defaults = { + LOG_T_INIT_OBJ("filter.split"), + FILTER_SPLIT_MODE_ROUNDROBIN, 0, 0, 0 +}; + +core_log_t* filter_split_log() +{ + return &_log; +} + +void filter_split_init(filter_split_t* self) +{ + mlassert_self(); + + *self = _defaults; +} + +void filter_split_destroy(filter_split_t* self) +{ + filter_split_recv_t* r; + mlassert_self(); + + if (self->recv_last) + self->recv_last->next = 0; + while ((r = self->recv_first)) { + self->recv_first = r->next; + free(r); + } +} + +void filter_split_add(filter_split_t* self, core_receiver_t recv, void* ctx) +{ + filter_split_recv_t* r; + mlassert_self(); + lassert(recv, "recv is nil"); + + lfatal_oom(r = malloc(sizeof(filter_split_recv_t))); + r->recv = recv; + r->ctx = ctx; + + if (self->recv_last) { + self->recv_last->next = r; + r->next = self->recv_first; + self->recv_first = r; + } else { + self->recv_first = self->recv = self->recv_last = r; + r->next = r; + } +} + +static void _roundrobin(filter_split_t* self, const core_object_t* obj) +{ + mlassert_self(); + + self->recv->recv(self->recv->ctx, obj); + self->recv = self->recv->next; +} + +static void _sendall(filter_split_t* self, const core_object_t* obj) +{ + filter_split_recv_t* r; + mlassert_self(); + + for (r = self->recv_first; r; r = r->next) { + r->recv(r->ctx, obj); + if (r == self->recv_last) + break; + } +} + +core_receiver_t filter_split_receiver(filter_split_t* self) +{ + mlassert_self(); + + if (!self->recv) { + lfatal("no receiver(s) set"); + } + + switch (self->mode) { + case FILTER_SPLIT_MODE_ROUNDROBIN: + return (core_receiver_t)_roundrobin; + case FILTER_SPLIT_MODE_SENDALL: + return (core_receiver_t)_sendall; + default: + lfatal("invalid split mode"); + } + return 0; +} diff --git a/include/dnsjit/filter/split.h b/include/dnsjit/filter/split.h new file mode 100644 index 0000000..2b0be09 --- /dev/null +++ b/include/dnsjit/filter/split.h @@ -0,0 +1,29 @@ +/* + * 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> + +#ifndef __dnsjit_filter_split_h +#define __dnsjit_filter_split_h + +#include <dnsjit/filter/split.hh> + +#endif diff --git a/include/dnsjit/filter/split.hh b/include/dnsjit/filter/split.hh new file mode 100644 index 0000000..2aba2ae --- /dev/null +++ b/include/dnsjit/filter/split.hh @@ -0,0 +1,50 @@ +/* + * 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") + +typedef enum filter_split_mode { + FILTER_SPLIT_MODE_ROUNDROBIN, + FILTER_SPLIT_MODE_SENDALL +} filter_split_mode_t; + +typedef struct filter_split_recv filter_split_recv_t; +struct filter_split_recv { + filter_split_recv_t* next; + core_receiver_t recv; + void* ctx; +}; + +typedef struct filter_split { + core_log_t _log; + filter_split_mode_t mode; + filter_split_recv_t* recv_first; + filter_split_recv_t* recv; + filter_split_recv_t* recv_last; +} filter_split_t; + +core_log_t* filter_split_log(); + +void filter_split_init(filter_split_t* self); +void filter_split_destroy(filter_split_t* self); +void filter_split_add(filter_split_t* self, core_receiver_t recv, void* ctx); + +core_receiver_t filter_split_receiver(filter_split_t* self); diff --git a/include/dnsjit/filter/split.lua b/include/dnsjit/filter/split.lua new file mode 100644 index 0000000..d9aec4f --- /dev/null +++ b/include/dnsjit/filter/split.lua @@ -0,0 +1,80 @@ +-- 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.filter.split +-- Passthrough to other receivers in various ways +-- local filter = require("dnsjit.filter.split").new() +-- filter.receiver(...) +-- filter.receiver(...) +-- filter.receiver(...) +-- input.receiver(filter) +-- +-- Filter to pass objects to others in various ways. +module(...,package.seeall) + +require("dnsjit.filter.split_h") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "filter_split_t" +local filter_split_t = ffi.typeof(t_name) +local Split = {} + +-- Create a new Split filter. +function Split.new() + local self = { + receivers = {}, + obj = filter_split_t(), + } + C.filter_split_init(self.obj) + ffi.gc(self.obj, C.filter_split_destroy) + return setmetatable(self, { __index = Split }) +end + +-- Return the Log object to control logging of this instance or module. +function Split:log() + if self == nil then + return C.filter_split_log() + end + return self.obj._log +end + +-- Set the passthrough mode to round robin (default mode). +function Split:roundrobin() + self.obj.mode = "FILTER_SPLIT_MODE_ROUNDROBIN" +end + +-- Set the passthrough mode to send to all receivers. +function Split:sendall() + self.obj.mode = "FILTER_SPLIT_MODE_SENDALL" +end + +-- Return the C functions and context for receiving objects. +function Split:receive() + return C.filter_split_receiver(self.obj), self.obj +end + +-- Set the receiver to pass objects to, this can be called multiple times to +-- set addtional receivers. +function Split:receiver(o) + local recv, ctx = o:receive() + C.filter_split_add(self.obj, recv, ctx) + table.insert(self.receivers, o) +end + +return Split diff --git a/include/dnsjit/filter/timing.c b/include/dnsjit/filter/timing.c new file mode 100644 index 0000000..bf4f865 --- /dev/null +++ b/include/dnsjit/filter/timing.c @@ -0,0 +1,557 @@ +/* + * 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 "filter/timing.h" +#include "core/assert.h" +#include "core/timespec.h" +#include "core/object/pcap.h" + +#include <time.h> +#include <sys/time.h> + +#define N1e9 1000000000 + +typedef struct _filter_timing { + filter_timing_t pub; + + struct timespec diff; + core_timespec_t last_pkthdr_ts; + struct timespec last_ts; + struct timespec first_ts; + void (*timing_callback)(filter_timing_t*, const core_object_pcap_t*); + struct timespec mod_ts; + size_t counter; +} _filter_timing_t; + +static core_log_t _log = LOG_T_INIT("filter.timing"); +static filter_timing_t _defaults = { + LOG_T_INIT_OBJ("filter.timing"), + 0, 0, + TIMING_MODE_KEEP, 0, 0, 0, 0, 0.0, 0, + 0, 0 +}; + +#define _self ((_filter_timing_t*)self) + +core_log_t* filter_timing_log() +{ + return &_log; +} + +static void _keep(filter_timing_t* self, const core_object_pcap_t* pkt) +{ +#if HAVE_CLOCK_NANOSLEEP + struct timespec to = { + _self->diff.tv_sec + pkt->ts.sec, + _self->diff.tv_nsec + pkt->ts.nsec + }; + int ret = EINTR; + + if (to.tv_nsec >= N1e9) { + to.tv_sec += 1; + to.tv_nsec -= N1e9; + } else if (to.tv_nsec < 0) { + to.tv_sec -= 1; + to.tv_nsec += N1e9; + } + + while (ret) { + ldebug("keep mode, sleep to %ld.%09ld", to.tv_sec, to.tv_nsec); + ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &to, 0); + if (ret && ret != EINTR) { + lfatal("clock_nanosleep(%ld.%09ld) %d", to.tv_sec, to.tv_nsec, ret); + } + } +#elif HAVE_NANOSLEEP + struct timespec diff = { + pkt->ts.sec - _self->last_pkthdr_ts.sec, + pkt->ts.nsec - _self->last_pkthdr_ts.nsec + }; + int ret = EINTR; + + if (diff.tv_nsec >= N1e9) { + diff.tv_sec += 1; + diff.tv_nsec -= N1e9; + } else if (diff.tv_nsec < 0) { + diff.tv_sec -= 1; + diff.tv_nsec += N1e9; + } + + if (diff.tv_sec > -1 && diff.tv_nsec > -1) { + while (ret) { + ldebug("keep mode, sleep for %ld.%09ld", diff.tv_sec, diff.tv_nsec); + if ((ret = nanosleep(&diff, &diff))) { + ret = errno; + if (ret != EINTR) { + lfatal("nanosleep(%ld.%09ld) %d", diff.tv_sec, diff.tv_nsec, ret); + } + } + } + } + + _self->last_pkthdr_ts = pkt->ts; +#endif +} + +static void _increase(filter_timing_t* self, const core_object_pcap_t* pkt) +{ + struct timespec diff = { + pkt->ts.sec - _self->last_pkthdr_ts.sec, + pkt->ts.nsec - _self->last_pkthdr_ts.nsec + }; + int ret = EINTR; + + if (diff.tv_nsec >= N1e9) { + diff.tv_sec += 1; + diff.tv_nsec -= N1e9; + } else if (diff.tv_nsec < 0) { + diff.tv_sec -= 1; + diff.tv_nsec += N1e9; + } + + diff.tv_sec += _self->mod_ts.tv_sec; + diff.tv_nsec += _self->mod_ts.tv_nsec; + if (diff.tv_nsec >= N1e9) { + diff.tv_sec += 1; + diff.tv_nsec -= N1e9; + } + + if (diff.tv_sec > -1 && diff.tv_nsec > -1) { +#if HAVE_CLOCK_NANOSLEEP + struct timespec to = { + _self->last_ts.tv_sec + diff.tv_sec, + _self->last_ts.tv_nsec + diff.tv_nsec + }; + + if (to.tv_nsec >= N1e9) { + to.tv_sec += 1; + to.tv_nsec -= N1e9; + } else if (to.tv_nsec < 0) { + to.tv_sec -= 1; + to.tv_nsec += N1e9; + } + + while (ret) { + ldebug("increase mode, sleep to %ld.%09ld", to.tv_sec, to.tv_nsec); + ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &to, 0); + if (ret && ret != EINTR) { + lfatal("clock_nanosleep(%ld.%09ld) %d", to.tv_sec, to.tv_nsec, ret); + } + } +#elif HAVE_NANOSLEEP + while (ret) { + ldebug("increase mode, sleep for %ld.%09ld", diff.tv_sec, diff.tv_nsec); + if ((ret = nanosleep(&diff, &diff))) { + ret = errno; + if (ret != EINTR) { + lfatal("nanosleep(%ld.%09ld) %d", diff.tv_sec, diff.tv_nsec, ret); + } + } + } +#endif + } + + _self->last_pkthdr_ts = pkt->ts; + +#if HAVE_CLOCK_NANOSLEEP + if (clock_gettime(CLOCK_MONOTONIC, &_self->last_ts)) { + lfatal("clock_gettime()"); + } +#endif +} + +static void _reduce(filter_timing_t* self, const core_object_pcap_t* pkt) +{ + struct timespec diff = { + pkt->ts.sec - _self->last_pkthdr_ts.sec, + pkt->ts.nsec - _self->last_pkthdr_ts.nsec + }; + int ret = EINTR; + + if (diff.tv_nsec >= N1e9) { + diff.tv_sec += 1; + diff.tv_nsec -= N1e9; + } else if (diff.tv_nsec < 0) { + diff.tv_sec -= 1; + diff.tv_nsec += N1e9; + } + + diff.tv_sec -= _self->mod_ts.tv_sec; + diff.tv_nsec -= _self->mod_ts.tv_nsec; + if (diff.tv_nsec < 0) { + diff.tv_sec -= 1; + diff.tv_nsec += N1e9; + } + + if (diff.tv_sec > -1 && diff.tv_nsec > -1) { +#if HAVE_CLOCK_NANOSLEEP + struct timespec to = { + _self->last_ts.tv_sec + diff.tv_sec, + _self->last_ts.tv_nsec + diff.tv_nsec + }; + + if (to.tv_nsec >= N1e9) { + to.tv_sec += 1; + to.tv_nsec -= N1e9; + } else if (to.tv_nsec < 0) { + to.tv_sec -= 1; + to.tv_nsec += N1e9; + } + + while (ret) { + ldebug("reduce mode, sleep to %ld.%09ld", to.tv_sec, to.tv_nsec); + ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &to, 0); + if (ret && ret != EINTR) { + lfatal("clock_nanosleep(%ld.%09ld) %d", to.tv_sec, to.tv_nsec, ret); + } + } +#elif HAVE_NANOSLEEP + while (ret) { + ldebug("reduce mode, sleep for %ld.%09ld", diff.tv_sec, diff.tv_nsec); + if ((ret = nanosleep(&diff, &diff))) { + ret = errno; + if (ret != EINTR) { + lfatal("nanosleep(%ld.%09ld) %d", diff.tv_sec, diff.tv_nsec, ret); + } + } + } +#endif + } + + _self->last_pkthdr_ts = pkt->ts; + +#if HAVE_CLOCK_NANOSLEEP + if (clock_gettime(CLOCK_MONOTONIC, &_self->last_ts)) { + lfatal("clock_gettime()"); + } +#endif +} + +static void _multiply(filter_timing_t* self, const core_object_pcap_t* pkt) +{ + struct timespec diff = { + pkt->ts.sec - _self->last_pkthdr_ts.sec, + pkt->ts.nsec - _self->last_pkthdr_ts.nsec + }; + int ret = EINTR; + + if (diff.tv_nsec >= N1e9) { + diff.tv_sec += 1; + diff.tv_nsec -= N1e9; + } else if (diff.tv_nsec < 0) { + diff.tv_sec -= 1; + diff.tv_nsec += N1e9; + } + + diff.tv_sec = (time_t)((float)diff.tv_sec * self->mul); + diff.tv_nsec = (long)((float)diff.tv_nsec * self->mul); + if (diff.tv_nsec >= N1e9) { + diff.tv_sec += diff.tv_nsec / N1e9; + diff.tv_nsec %= N1e9; + } + + if (diff.tv_sec > -1 && diff.tv_nsec > -1) { +#if HAVE_CLOCK_NANOSLEEP + struct timespec to = { + _self->last_ts.tv_sec + diff.tv_sec, + _self->last_ts.tv_nsec + diff.tv_nsec + }; + + if (to.tv_nsec >= N1e9) { + to.tv_sec += 1; + to.tv_nsec -= N1e9; + } else if (to.tv_nsec < 0) { + to.tv_sec -= 1; + to.tv_nsec += N1e9; + } + + while (ret) { + ldebug("multiply mode, sleep to %ld.%09ld", to.tv_sec, to.tv_nsec); + ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &to, 0); + if (ret && ret != EINTR) { + lfatal("clock_nanosleep(%ld.%09ld) %d", to.tv_sec, to.tv_nsec, ret); + } + } +#elif HAVE_NANOSLEEP + while (ret) { + ldebug("multiply mode, sleep for %ld.%09ld", diff.tv_sec, diff.tv_nsec); + if ((ret = nanosleep(&diff, &diff))) { + ret = errno; + if (ret != EINTR) { + lfatal("nanosleep(%ld.%09ld) %d", diff.tv_sec, diff.tv_nsec, ret); + } + } + } +#endif + } + + _self->last_pkthdr_ts = pkt->ts; + +#if HAVE_CLOCK_NANOSLEEP + if (clock_gettime(CLOCK_MONOTONIC, &_self->last_ts)) { + lfatal("clock_gettime()"); + } +#endif +} + +static void _fixed(filter_timing_t* self, const core_object_pcap_t* pkt) +{ + struct timespec diff = { + _self->mod_ts.tv_sec, + _self->mod_ts.tv_nsec + }; + int ret = EINTR; + + if (diff.tv_sec > -1 && diff.tv_nsec > -1) { +#if HAVE_CLOCK_NANOSLEEP + struct timespec to = { + _self->last_ts.tv_sec + diff.tv_sec, + _self->last_ts.tv_nsec + diff.tv_nsec + }; + + if (to.tv_nsec >= N1e9) { + to.tv_sec += 1; + to.tv_nsec -= N1e9; + } else if (to.tv_nsec < 0) { + to.tv_sec -= 1; + to.tv_nsec += N1e9; + } + + while (ret) { + ldebug("fixed mode, sleep to %ld.%09ld", to.tv_sec, to.tv_nsec); + ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &to, 0); + if (ret && ret != EINTR) { + lfatal("clock_nanosleep(%ld.%09ld) %d", to.tv_sec, to.tv_nsec, ret); + } + } +#elif HAVE_NANOSLEEP + while (ret) { + ldebug("fixed mode, sleep for %ld.%09ld", diff.tv_sec, diff.tv_nsec); + if ((ret = nanosleep(&diff, &diff))) { + ret = errno; + if (ret != EINTR) { + lfatal("nanosleep(%ld.%09ld) %d", diff.tv_sec, diff.tv_nsec, ret); + } + } + } +#endif + } + + _self->last_pkthdr_ts = pkt->ts; + +#if HAVE_CLOCK_NANOSLEEP + if (clock_gettime(CLOCK_MONOTONIC, &_self->last_ts)) { + lfatal("clock_gettime()"); + } +#endif +} + +#if HAVE_CLOCK_NANOSLEEP +static inline void _timespec_diff(struct timespec* start, struct timespec* stop, + struct timespec* result) +{ + if ((stop->tv_nsec - start->tv_nsec) < 0) { + mlassert(stop->tv_sec > start->tv_sec, "stop time must be after start time"); + result->tv_sec = stop->tv_sec - start->tv_sec - 1; + result->tv_nsec = stop->tv_nsec - start->tv_nsec + 1000000000UL; + } else { + mlassert(stop->tv_sec >= start->tv_sec, "stop time must be after start time"); + result->tv_sec = stop->tv_sec - start->tv_sec; + result->tv_nsec = stop->tv_nsec - start->tv_nsec; + } +} + +static void _realtime(filter_timing_t* self, const core_object_pcap_t* pkt) +{ + _self->counter++; + if (_self->counter >= self->rt_batch) { + struct timespec simulated; + + _self->counter = 0; + if (clock_gettime(CLOCK_MONOTONIC, &_self->last_ts)) { + lfatal("clock_gettime()"); + } + + // calculate simulated time from packet offsets + simulated.tv_sec = pkt->ts.sec; + simulated.tv_nsec = pkt->ts.nsec; + _timespec_diff(&_self->mod_ts, &simulated, &simulated); + + // calculate real elapsed time from monotonic clock + _timespec_diff(&_self->first_ts, &_self->last_ts, &_self->diff); + + linfo("simulated time: %ld.%09lds; real time: %ld.%09lds", + simulated.tv_sec, simulated.tv_nsec, _self->diff.tv_sec, _self->diff.tv_nsec); + + if (simulated.tv_sec > _self->diff.tv_sec + || (simulated.tv_sec == _self->diff.tv_sec && simulated.tv_nsec > _self->diff.tv_nsec)) { + int ret = EINTR; + _timespec_diff(&_self->diff, &simulated, &simulated); + + ldebug("sleeping for %ld.%09lds", simulated.tv_sec, simulated.tv_nsec); + while (ret) { + ret = clock_nanosleep(CLOCK_MONOTONIC, 0, &simulated, 0); + if (ret && ret != EINTR) { + lfatal("clock_nanosleep(%ld.%09ld) %d", simulated.tv_sec, simulated.tv_nsec, ret); + } + } + } else { + // check that real time didn't drift ahead more than specified drift limit + _timespec_diff(&simulated, &_self->diff, &_self->diff); + if (_self->diff.tv_sec > (self->rt_drift / N1e9) + || (_self->diff.tv_sec == (self->rt_drift / N1e9) && _self->diff.tv_nsec >= (self->rt_drift % N1e9))) { + lfatal("aborting, real time drifted ahead of simulated time (%ld.%09lds) by %ld.%09lds", + simulated.tv_sec, simulated.tv_nsec, _self->diff.tv_sec, _self->diff.tv_nsec); + } + } + } +} +#endif + +static void _init(filter_timing_t* self, const core_object_pcap_t* pkt) +{ +#if HAVE_CLOCK_NANOSLEEP + if (clock_gettime(CLOCK_MONOTONIC, &_self->last_ts)) { + lfatal("clock_gettime()"); + } + _self->first_ts = _self->last_ts; + _self->diff = _self->last_ts; + _self->diff.tv_sec -= pkt->ts.sec; + _self->diff.tv_nsec -= pkt->ts.nsec; + ldebug("init with clock_nanosleep() now is %ld.%09ld, diff of first pkt %ld.%09ld", + _self->last_ts.tv_sec, _self->last_ts.tv_nsec, + _self->diff.tv_sec, _self->diff.tv_nsec); +#elif HAVE_NANOSLEEP + ldebug("init with nanosleep()"); +#else +#error "No clock_nanosleep() or nanosleep(), can not continue" +#endif + + _self->last_pkthdr_ts = pkt->ts; + + switch (self->mode) { + case TIMING_MODE_KEEP: + ldebug("init mode keep"); + _self->timing_callback = _keep; + break; + case TIMING_MODE_INCREASE: + _self->timing_callback = _increase; + _self->mod_ts.tv_sec = self->inc / N1e9; + _self->mod_ts.tv_nsec = self->inc % N1e9; + ldebug("init mode increase by %ld.%09ld", _self->mod_ts.tv_sec, _self->mod_ts.tv_nsec); + break; + case TIMING_MODE_REDUCE: + _self->timing_callback = _reduce; + _self->mod_ts.tv_sec = self->red / N1e9; + _self->mod_ts.tv_nsec = self->red % N1e9; + ldebug("init mode reduce by %ld.%09ld", _self->mod_ts.tv_sec, _self->mod_ts.tv_nsec); + break; + case TIMING_MODE_MULTIPLY: + _self->timing_callback = _multiply; + ldebug("init mode multiply by %f", self->mul); + break; + case TIMING_MODE_FIXED: + _self->timing_callback = _fixed; + _self->mod_ts.tv_sec = self->fixed / N1e9; + _self->mod_ts.tv_nsec = self->fixed % N1e9; + ldebug("init mode fixed by %ld.%09ld", _self->mod_ts.tv_sec, _self->mod_ts.tv_nsec); + break; + case TIMING_MODE_REALTIME: +#if HAVE_CLOCK_NANOSLEEP + ldebug("init mode realtime"); + _self->timing_callback = _realtime; + _self->counter = 0; + _self->mod_ts.tv_sec = pkt->ts.sec; + _self->mod_ts.tv_nsec = pkt->ts.nsec; +#else + lfatal("realtime mode requires clock_nanosleep()"); +#endif + break; + default: + lfatal("invalid timing mode %d", self->mode); + } +} + +filter_timing_t* filter_timing_new() +{ + filter_timing_t* self; + mlfatal_oom(self = malloc(sizeof(_filter_timing_t))); + *self = _defaults; + _self->timing_callback = _init; + + return self; +} + +void filter_timing_free(filter_timing_t* self) +{ + mlassert_self(); + free(self); +} + +static void _receive(filter_timing_t* self, const core_object_t* obj) +{ + mlassert_self(); + lassert(obj, "obj is nil"); + + if (obj->obj_type != CORE_OBJECT_PCAP) { + lfatal("obj is not CORE_OBJECT_PCAP"); + } + + _self->timing_callback(self, (core_object_pcap_t*)obj); + self->recv(self->ctx, obj); +} + +core_receiver_t filter_timing_receiver(filter_timing_t* self) +{ + mlassert_self(); + + if (!self->recv) { + lfatal("no receiver set"); + } + + return (core_receiver_t)_receive; +} + +static const core_object_t* _produce(filter_timing_t* self) +{ + const core_object_t* obj; + mlassert_self(); + + obj = self->prod(self->prod_ctx); + if (!obj || obj->obj_type != CORE_OBJECT_PCAP) { + return 0; + } + + _self->timing_callback(self, (core_object_pcap_t*)obj); + return obj; +} + +core_producer_t filter_timing_producer(filter_timing_t* self) +{ + mlassert_self(); + + if (!self->prod) { + lfatal("no producer set"); + } + + return (core_producer_t)_produce; +} diff --git a/include/dnsjit/filter/timing.h b/include/dnsjit/filter/timing.h new file mode 100644 index 0000000..283155c --- /dev/null +++ b/include/dnsjit/filter/timing.h @@ -0,0 +1,30 @@ +/* + * 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> + +#ifndef __dnsjit_filter_timing_h +#define __dnsjit_filter_timing_h + +#include <dnsjit/filter/timing.hh> + +#endif diff --git a/include/dnsjit/filter/timing.hh b/include/dnsjit/filter/timing.hh new file mode 100644 index 0000000..8615907 --- /dev/null +++ b/include/dnsjit/filter/timing.hh @@ -0,0 +1,52 @@ +/* + * 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.timespec_h") + +typedef struct filter_timing { + core_log_t _log; + core_receiver_t recv; + void* ctx; + enum { + TIMING_MODE_KEEP = 0, + TIMING_MODE_INCREASE = 1, + TIMING_MODE_REDUCE = 2, + TIMING_MODE_MULTIPLY = 3, + TIMING_MODE_FIXED = 4, + TIMING_MODE_REALTIME = 5 + } mode; + size_t inc, red, fixed, rt_batch; + float mul; + uint64_t rt_drift; + + core_producer_t prod; + void* prod_ctx; +} filter_timing_t; + +core_log_t* filter_timing_log(); + +filter_timing_t* filter_timing_new(); +void filter_timing_free(filter_timing_t* self); + +core_receiver_t filter_timing_receiver(filter_timing_t* self); +core_producer_t filter_timing_producer(filter_timing_t* self); diff --git a/include/dnsjit/filter/timing.lua b/include/dnsjit/filter/timing.lua new file mode 100644 index 0000000..cab9574 --- /dev/null +++ b/include/dnsjit/filter/timing.lua @@ -0,0 +1,123 @@ +-- 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.filter.timing +-- Filter to pass objects to the next receiver based on timing between packets +-- local filter = require("dnsjit.filter.timing").new() +-- ... +-- filter:receiver(...) +-- +-- Filter to manipulate processing so it simulates the actual timing when +-- packets arrived or to delay processing. +module(...,package.seeall) + +require("dnsjit.filter.timing_h") +local ffi = require("ffi") +local C = ffi.C + +local Timing = {} + +-- Create a new Timing filter. +function Timing.new() + local self = { + _receiver = nil, + obj = C.filter_timing_new(), + } + ffi.gc(self.obj, C.filter_timing_free) + return setmetatable(self, { __index = Timing }) +end + +-- Return the Log object to control logging of this instance or module. +function Timing:log() + if self == nil then + return C.filter_timing_log() + end + return self.obj._log +end + +-- Set the timing mode to keep the timing between packets. +function Timing:keep() + self.obj.mode = "TIMING_MODE_KEEP" +end + +-- Set the timing mode to increase the timing between packets by the given +-- number of nanoseconds. +function Timing:increase(ns) + self.obj.mode = "TIMING_MODE_INCREASE" + self.obj.inc = ns +end + +-- Set the timing mode to reduce the timing between packets by the given +-- number of nanoseconds. +function Timing:reduce(ns) + self.obj.mode = "TIMING_MODE_REDUCE" + self.obj.red = ns +end + +-- Set the timing mode to multiply the timing between packets by the given +-- factor (float/double). +function Timing:multiply(factor) + self.obj.mode = "TIMING_MODE_MULTIPLY" + self.obj.mul = factor +end + +-- Set the timing mode to a fixed number of nanoseconds between packets. +function Timing:fixed(ns) + self.obj.mode = "TIMING_MODE_FIXED" + self.obj.fixed = ns +end + +-- Set the timing mode to simulate the timing of packets in realtime. +-- Packets are processed in batches of given size (default 128) before +-- adjusting time. Aborts if real time drifts ahead more than given +-- number of seconds (default 1.0s). +function Timing:realtime(drift, batch_size) + self.obj.mode = "TIMING_MODE_REALTIME" + if drift == nil then + drift = 1 + end + if batch_size == nil then + batch_size = 128 + end + self.obj.rt_batch = batch_size + self.obj.rt_drift = math.floor(drift * 1000000000) +end + +-- Return the C functions and context for receiving objects. +function Timing:receive() + return C.filter_timing_receiver(), self.obj +end + +-- Set the receiver to pass objects to. +function Timing:receiver(o) + self.obj.recv, self.obj.ctx = o:receive() + self._receiver = o +end + +-- Return the C functions and context for producing objects. +function Timing:produce() + return C.filter_timing_producer(self.obj), self.obj +end + +-- Set the producer to get objects from. +function Timing:producer(o) + self.obj.prod, self.obj.prod_ctx = o:produce() + self._producer = o +end + +return Timing diff --git a/include/dnsjit/gen-compat.lua b/include/dnsjit/gen-compat.lua new file mode 100644 index 0000000..65c40ec --- /dev/null +++ b/include/dnsjit/gen-compat.lua @@ -0,0 +1,34 @@ +for line in io.lines("config.h") do + local n, s = line:match("define SIZEOF_(%S*) (%d+)") + if n and s then + if n:match("^PTHREAD") or n:match("^CK_") or n:match("^GNUTLS_") then + s = math.ceil(s / 8) + print("#if !defined(SIZEOF_"..n..") || SIZEOF_"..n.." == 0") + print("#error \""..n.." is undefined or zero\"") + print("#endif") + n = n:lower() + print("typedef struct "..n:sub(1,-3).." { uint64_t a["..s.."]; } "..n..";") + elseif n:match("^STRUCT") then + n = n:match("^STRUCT_(%S*)") + if n == "SOCKADDR_STORAGE" or n == "POLLFD" then + print("#if !defined(SIZEOF_STRUCT_"..n..") || SIZEOF_STRUCT_"..n.." == 0") + print("#error \""..n.." is undefined or zero\"") + print("#endif") + n = n:lower() + print("struct "..n.." { uint8_t a["..s.."]; };") + end + end + end +end +code, err = pcall(function() + local ffi = require("ffi") + ffi.cdef[[ + ssize_t dummy; + ]] +end) +if code then + print("#include <unistd.h>") + print("typedef ssize_t luajit_ssize_t;") +else + print("typedef long luajit_ssize_t;") +end diff --git a/include/dnsjit/gen-errno.sh b/include/dnsjit/gen-errno.sh new file mode 100755 index 0000000..f9a81da --- /dev/null +++ b/include/dnsjit/gen-errno.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +includes="/usr/include/errno.h" +if [ -f /usr/include/sys/errno.h ]; then + includes="$includes /usr/include/sys/errno.h" +fi +if [ -f /usr/include/asm-generic/errno.h ]; then + includes="$includes /usr/include/asm-generic/errno.h" +fi +if [ -f /usr/include/asm-generic/errno-base.h ]; then + includes="$includes /usr/include/asm-generic/errno-base.h" +fi + +echo 'const char* core_log_errstr(int err) +{ + switch (err) {' + +egrep -Eh '^#define[ ]+E\w+[ ]+[0-9]+' $includes | + grep -v ELAST | + awk '{print $2}' | + sort -u | + awk '{print "#ifdef " $1 "\n case " $1 ":\n return \"" $1 "\";\n#endif"}' + +echo ' default: + break; + } + return "UNKNOWN"; +}' diff --git a/include/dnsjit/gen-manpage.lua b/include/dnsjit/gen-manpage.lua new file mode 100644 index 0000000..e285b1f --- /dev/null +++ b/include/dnsjit/gen-manpage.lua @@ -0,0 +1,126 @@ +print[[ +.\" 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/>. +.\"]] + +sh_syn = false +sh_desc = false +ss_func = false +doc = {} +funcs = {} +for line in io.lines(arg[1]) do + if line:match("^[-][-]") then + table.insert(doc, line:sub(4)) + elseif line:match("^module") then + if table.maxn(doc) < 2 then + error("Minimum required module doc missing") + end + print(".TH "..doc[1].." 3 \"@PACKAGE_VERSION@\" \"dnsjit\"") + print(".SH NAME") + print(doc[1].." \\- "..doc[2]) + n, line = next(doc, 2) + if n and n > 2 then + local n2 = n + while line and line > "" do + if not sh_syn then + print(".SH SYNOPSIS") + sh_syn = true + end + if line == "." then + line = "" + end + print(line) + n2 = n + n, line = next(doc, n) + end + n, line = next(doc, n) + if n and n > n2 then + while line and line > "" do + if not sh_desc then + print(".SH DESCRIPTION") + sh_desc = true + end + if line == "." then + line = "" + end + print(line) + n, line = next(doc, n) + end + end + end + elseif line:match("^function") then + if table.maxn(doc) > 0 then + if not ss_func then + if not sh_desc then + print(".SH DESCRIPTION") + sh_desc = true + end + print(".SS Functions") + ss_func = true + end + print(".TP") + local fn,fd = line:match("(%S+)(%(.+)") + if fn and fd then + print(".BR "..fn.." \""..fd.."\"") + else + print(".B "..line:sub(10)) + end + for _, line in pairs(doc) do + if line == "." then + line = "" + end + print(line) + end + end + elseif line:match("^return") then + if table.maxn(doc) > 0 then + print(".SH SEE ALSO") + for _, line in pairs(doc) do + print(".BR "..line) + end + end + else + doc = {} + end +end + +print[[ +.SH AUTHORS and CONTRIBUTORS +Jerry Lundström (DNS-OARC), +Tomáš Křížek (CZ.NIC), +Petr Špaček (ISC) +.LP +Maintained by DNS-OARC +.LP +.RS +.I https://www.dns-oarc.net/ +.RE +.LP +.SH BUGS +For issues and feature requests please use: +.LP +.RS +\fI@PACKAGE_URL@\fP +.RE +.LP +For question and help please use: +.LP +.RS +\fI@PACKAGE_BUGREPORT@\fP +.RE +.LP]] diff --git a/include/dnsjit/globals.c b/include/dnsjit/globals.c new file mode 100644 index 0000000..3f85c51 --- /dev/null +++ b/include/dnsjit/globals.c @@ -0,0 +1,60 @@ +/* + * 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 "globals.h" + +#include <lua.h> +#include <lualib.h> +#include <lauxlib.h> + +void dnsjit_globals(lua_State* L) +{ +#ifdef PACKAGE_VERSION + lua_pushstring(L, PACKAGE_VERSION); +#elif defined(VERSION) + lua_pushstring(L, VERSION); +#else +#error "No PACKAGE_VERSION or VERSION defined" +#endif + lua_setglobal(L, "DNSJIT_VERSION"); + + lua_pushinteger(L, PACKAGE_MAJOR_VERSION); + lua_setglobal(L, "DNSJIT_MAJOR_VERSION"); + lua_pushinteger(L, PACKAGE_MINOR_VERSION); + lua_setglobal(L, "DNSJIT_MINOR_VERSION"); + lua_pushinteger(L, PACKAGE_PATCH_VERSION); + lua_setglobal(L, "DNSJIT_PATCH_VERSION"); + +#ifdef PACKAGE_BUGREPORT + lua_pushstring(L, PACKAGE_BUGREPORT); +#else + lua_pushstring(L, "none"); +#endif + lua_setglobal(L, "DNSJIT_BUGREPORT"); + +#ifdef PACKAGE_URL + lua_pushstring(L, PACKAGE_URL); +#else + lua_pushstring(L, "none"); +#endif + lua_setglobal(L, "DNSJIT_URL"); +} diff --git a/include/dnsjit/globals.h b/include/dnsjit/globals.h new file mode 100644 index 0000000..48e7e68 --- /dev/null +++ b/include/dnsjit/globals.h @@ -0,0 +1,28 @@ +/* + * 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/>. + */ + +#ifndef __dnsjit_globals_h +#define __dnsjit_globals_h + +#include <lua.h> + +void dnsjit_globals(lua_State* L); + +#endif diff --git a/include/dnsjit/input.lua b/include/dnsjit/input.lua new file mode 100644 index 0000000..f791f17 --- /dev/null +++ b/include/dnsjit/input.lua @@ -0,0 +1,30 @@ +-- 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 +-- Input modules for dnsjit +-- +-- Input modules used to read DNS messages in various ways. +module(...,package.seeall) + +-- dnsjit.input.fpcap (3), +-- dnsjit.input.mmpcap (3), +-- dnsjit.input.pcap (3), +-- dnsjit.input.zero (3), +-- dnsjit.input.zpcap (3) +return diff --git a/include/dnsjit/input/fpcap.c b/include/dnsjit/input/fpcap.c new file mode 100644 index 0000000..6804608 --- /dev/null +++ b/include/dnsjit/input/fpcap.c @@ -0,0 +1,349 @@ +/* + * 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/fpcap.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> + +#define MAX_SNAPLEN 0x40000 + +static core_log_t _log = LOG_T_INIT("input.fpcap"); +static input_fpcap_t _defaults = { + LOG_T_INIT_OBJ("input.fpcap"), + 0, 0, + 0, 0, 0, + CORE_OBJECT_PCAP_INIT(0), + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0 +}; + +core_log_t* input_fpcap_log() +{ + return &_log; +} + +void input_fpcap_init(input_fpcap_t* self) +{ + mlassert_self(); + + *self = _defaults; +} + +void input_fpcap_destroy(input_fpcap_t* self) +{ + mlassert_self(); + + if (!self->extern_file && self->file) { + fclose(self->file); + } + free(self->buf); +} + +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 + || fread(&self->thiszone, 1, 4, self->file) != 4 + || fread(&self->sigfigs, 1, 4, self->file) != 4 + || fread(&self->snaplen, 1, 4, self->file) != 4 + || fread(&self->network, 1, 4, self->file) != 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.bytes = (unsigned char*)self->buf; + 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_fpcap_open(input_fpcap_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_fpcap_openfp(input_fpcap_t* self, void* fp) +{ + mlassert_self(); + + if (self->file) { + lfatal("already opened"); + } + + self->file = fp; + self->extern_file = 1; + + return _open(self); +} + +int input_fpcap_run(input_fpcap_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.bytes = (unsigned char*)self->buf; + pkt.is_swapped = self->is_swapped; + + while ((ret = fread(&hdr, 1, 16, self->file)) == 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; + } + if (fread(self->buf, 1, hdr.incl_len, self->file) != 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; +} + +static const core_object_t* _produce(input_fpcap_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 = fread(&hdr, 1, 16, self->file)) != 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; + } + if (fread(self->buf, 1, hdr.incl_len, self->file) != 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_fpcap_producer(input_fpcap_t* self) +{ + mlassert_self(); + + if (!self->file) { + lfatal("no PCAP opened"); + } + + return (core_producer_t)_produce; +} diff --git a/include/dnsjit/input/fpcap.h b/include/dnsjit/input/fpcap.h new file mode 100644 index 0000000..4e1e5ee --- /dev/null +++ b/include/dnsjit/input/fpcap.h @@ -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_fpcap_h +#define __dnsjit_input_fpcap_h + +#include <dnsjit/input/fpcap.hh> + +#endif diff --git a/include/dnsjit/input/fpcap.hh b/include/dnsjit/input/fpcap.hh new file mode 100644 index 0000000..ab06a71 --- /dev/null +++ b/include/dnsjit/input/fpcap.hh @@ -0,0 +1,62 @@ +/* + * 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 struct input_fpcap { + 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; + + 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_fpcap_t; + +core_log_t* input_fpcap_log(); + +void input_fpcap_init(input_fpcap_t* self); +void input_fpcap_destroy(input_fpcap_t* self); +int input_fpcap_open(input_fpcap_t* self, const char* file); +int input_fpcap_openfp(input_fpcap_t* self, void* fp); +int input_fpcap_run(input_fpcap_t* self); + +core_producer_t input_fpcap_producer(input_fpcap_t* self); diff --git a/include/dnsjit/input/fpcap.lua b/include/dnsjit/input/fpcap.lua new file mode 100644 index 0000000..b50fc11 --- /dev/null +++ b/include/dnsjit/input/fpcap.lua @@ -0,0 +1,140 @@ +-- 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.fpcap +-- Read input from a PCAP file using fopen() +-- local input = require("dnsjit.input.fpcap").new() +-- input:open("file.pcap") +-- input:receiver(filter_or_output) +-- input:run() +-- +-- Read input from a PCAP file using standard library function +-- .B fopen() +-- 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.fpcap_h") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "input_fpcap_t" +local input_fpcap_t = ffi.typeof(t_name) +local Fpcap = {} + +-- Create a new Fpcap input. +function Fpcap.new() + local self = { + _receiver = nil, + obj = input_fpcap_t(), + } + C.input_fpcap_init(self.obj) + ffi.gc(self.obj, C.input_fpcap_destroy) + return setmetatable(self, { __index = Fpcap }) +end + +-- Return the Log object to control logging of this instance or module. +function Fpcap:log() + if self == nil then + return C.input_fpcap_log() + end + return self.obj._log +end + +-- Set the receiver to pass objects to. +function Fpcap:receiver(o) + self.obj.recv, self.obj.ctx = o:receive() + self._receiver = o +end + +-- Return the C functions and context for producing objects. +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) + return C.input_fpcap_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 Fpcap:openfp(fp) + return C.input_fpcap_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 Fpcap:run() + return C.input_fpcap_run(self.obj) +end + +-- Return the number of packets seen. +function Fpcap:packets() + return tonumber(self.obj.pkts) +end + +return Fpcap diff --git a/include/dnsjit/input/mmpcap.c b/include/dnsjit/input/mmpcap.c new file mode 100644 index 0000000..4f3ee59 --- /dev/null +++ b/include/dnsjit/input/mmpcap.c @@ -0,0 +1,335 @@ +/* + * 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/mmpcap.h" +#include "core/assert.h" +#include "core/object/pcap.h" + +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.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> + +static core_log_t _log = LOG_T_INIT("input.mmpcap"); +static input_mmpcap_t _defaults = { + LOG_T_INIT_OBJ("input.mmpcap"), + 0, 0, + 0, 0, 0, + CORE_OBJECT_PCAP_INIT(0), + -1, 0, 0, 0, MAP_FAILED, + 0, 0, 0, 0, 0, 0, 0, + 0 +}; + +core_log_t* input_mmpcap_log() +{ + return &_log; +} + +void input_mmpcap_init(input_mmpcap_t* self) +{ + mlassert_self(); + + *self = _defaults; +} + +void input_mmpcap_destroy(input_mmpcap_t* self) +{ + mlassert_self(); + + if (self->buf != MAP_FAILED) { + munmap(self->buf, self->len); + } + if (self->fd > -1) { + close(self->fd); + } +} + +int input_mmpcap_open(input_mmpcap_t* self, const char* file) +{ + struct stat sb; + mlassert_self(); + lassert(file, "file is nil"); + + if (self->fd != -1) { + lfatal("already opened"); + } + + if ((self->fd = open(file, O_RDONLY)) < 0) { + lcritical("open(%s) error %s", file, core_log_errstr(errno)); + return -1; + } + + if (fstat(self->fd, &sb)) { + lcritical("stat(%s) error %s", file, core_log_errstr(errno)); + return -1; + } + self->len = sb.st_size; + + if ((self->buf = mmap(0, self->len, PROT_READ, MAP_PRIVATE, self->fd, 0)) == MAP_FAILED) { + lcritical("mmap(%s) error %s", file, core_log_errstr(errno)); + return -1; + } + + if (self->len < 24) { + lcritical("could not read full PCAP header"); + return -2; + } + memcpy(&self->magic_number, self->buf, 4); + memcpy(&self->version_major, self->buf + 4, 2); + memcpy(&self->version_minor, self->buf + 6, 2); + memcpy(&self->thiszone, self->buf + 8, 4); + memcpy(&self->sigfigs, self->buf + 12, 4); + memcpy(&self->snaplen, self->buf + 16, 4); + memcpy(&self->network, self->buf + 20, 4); + self->at = 24; + 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->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: /* LINKTYPE_RAW */ + 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; + } + + 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_mmpcap_run(input_mmpcap_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); + mlassert_self(); + + if (self->buf == MAP_FAILED) { + 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 (self->len - self->at > 16) { + memcpy(&hdr, &self->buf[self->at], 16); + self->at += 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; + } + if (self->len - self->at < 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.bytes = (unsigned char*)&self->buf[self->at]; + pkt.caplen = hdr.incl_len; + pkt.len = hdr.orig_len; + + self->recv(self->ctx, (core_object_t*)&pkt); + + self->at += hdr.incl_len; + } + if (self->at < self->len) { + lwarning("could not read next PCAP header, aborting"); + return -1; + } + + return 0; +} + +static const core_object_t* _produce(input_mmpcap_t* self) +{ + struct { + uint32_t ts_sec; + uint32_t ts_usec; + uint32_t incl_len; + uint32_t orig_len; + } hdr; + mlassert_self(); + + if (self->is_broken) { + lwarning("PCAP is broken, will not read next packet"); + return 0; + } + + if (self->len - self->at < 16) { + if (self->at < self->len) { + lwarning("could not read next PCAP header, aborting"); + self->is_broken = 1; + } + return 0; + } + + memcpy(&hdr, &self->buf[self->at], 16); + self->at += 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"); + self->is_broken = 1; + return 0; + } + if (self->len - self->at < 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.bytes = (unsigned char*)&self->buf[self->at]; + self->prod_pkt.caplen = hdr.incl_len; + self->prod_pkt.len = hdr.orig_len; + + self->at += hdr.incl_len; + return (core_object_t*)&self->prod_pkt; +} + +core_producer_t input_mmpcap_producer(input_mmpcap_t* self) +{ + mlassert_self(); + + if (self->buf == MAP_FAILED) { + lfatal("no PCAP opened"); + } + + return (core_producer_t)_produce; +} diff --git a/include/dnsjit/input/mmpcap.h b/include/dnsjit/input/mmpcap.h new file mode 100644 index 0000000..b4ae09a --- /dev/null +++ b/include/dnsjit/input/mmpcap.h @@ -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_mmpcap_h +#define __dnsjit_input_mmpcap_h + +#include <dnsjit/input/mmpcap.hh> + +#endif diff --git a/include/dnsjit/input/mmpcap.hh b/include/dnsjit/input/mmpcap.hh new file mode 100644 index 0000000..27ed35e --- /dev/null +++ b/include/dnsjit/input/mmpcap.hh @@ -0,0 +1,60 @@ +/* + * 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 struct input_mmpcap { + 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; + + int fd; + size_t len, at; + size_t pkts; + uint8_t* buf; + + 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_mmpcap_t; + +core_log_t* input_mmpcap_log(); + +void input_mmpcap_init(input_mmpcap_t* self); +void input_mmpcap_destroy(input_mmpcap_t* self); +int input_mmpcap_open(input_mmpcap_t* self, const char* file); +int input_mmpcap_run(input_mmpcap_t* self); + +core_producer_t input_mmpcap_producer(input_mmpcap_t* self); diff --git a/include/dnsjit/input/mmpcap.lua b/include/dnsjit/input/mmpcap.lua new file mode 100644 index 0000000..8e28e69 --- /dev/null +++ b/include/dnsjit/input/mmpcap.lua @@ -0,0 +1,120 @@ +-- 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.mmpcap +-- Read input from a PCAP file using mmap() +-- local input = require("dnsjit.input.fpcap").new() +-- input:open("file.pcap") +-- input:receiver(filter_or_output) +-- input:run() +-- +-- Read input from a PCAP file by mapping the whole file to memory using +-- .B mmap() +-- 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.mmpcap_h") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "input_mmpcap_t" +local input_mmpcap_t = ffi.typeof(t_name) +local Mmpcap = {} + +-- Create a new Mmpcap input. +function Mmpcap.new() + local self = { + _receiver = nil, + obj = input_mmpcap_t(), + } + C.input_mmpcap_init(self.obj) + ffi.gc(self.obj, C.input_mmpcap_destroy) + return setmetatable(self, { __index = Mmpcap }) +end + +-- Return the Log object to control logging of this instance or module. +function Mmpcap:log() + if self == nil then + return C.input_mmpcap_log() + end + return self.obj._log +end + +-- Set the receiver to pass objects to. +function Mmpcap:receiver(o) + self.obj.recv, self.obj.ctx = o:receive() + self._receiver = o +end + +-- Return the C functions and context for producing objects. +function Mmpcap:produce() + return C.input_mmpcap_producer(self.obj), self.obj +end + +-- Open a PCAP file for processing and read the PCAP header. +-- Returns 0 on success. +function Mmpcap:open(file) + return C.input_mmpcap_open(self.obj, file) +end + +-- Start processing packets and send each packet read to the receiver. +-- Returns 0 if all packets was read successfully. +function Mmpcap:run() + return C.input_mmpcap_run(self.obj) +end + +-- Return the number of packets seen. +function Mmpcap:packets() + return tonumber(self.obj.pkts) +end + +return Mmpcap diff --git a/include/dnsjit/input/pcap.c b/include/dnsjit/input/pcap.c new file mode 100644 index 0000000..25d6ee3 --- /dev/null +++ b/include/dnsjit/input/pcap.c @@ -0,0 +1,206 @@ +/* + * 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/pcap.h" +#include "core/assert.h" +#include "core/object/pcap.h" + +static core_log_t _log = LOG_T_INIT("input.pcap"); +static input_pcap_t _defaults = { + LOG_T_INIT_OBJ("input.pcap"), + 0, 0, + 0, + CORE_OBJECT_PCAP_INIT(0), + 0, 0, + 0, 0 +}; + +core_log_t* input_pcap_log() +{ + return &_log; +} + +void input_pcap_init(input_pcap_t* self) +{ + mlassert_self(); + + *self = _defaults; +} + +void input_pcap_destroy(input_pcap_t* self) +{ + mlassert_self(); + + if (self->pcap) { + pcap_close(self->pcap); + } +} + +int input_pcap_create(input_pcap_t* self, const char* source) +{ + char errbuf[PCAP_ERRBUF_SIZE] = { 0 }; + mlassert_self(); + lassert(source, "source is nil"); + + if (self->pcap) { + lfatal("already opened"); + } + + if (!(self->pcap = pcap_create(source, errbuf))) { + lcritical("pcap_create(%s) error: %s", source, errbuf); + return -1; + } + + return 0; +} + +int input_pcap_activate(input_pcap_t* self) +{ + int ret; + + mlassert_self(); + if (!self->pcap) { + lfatal("no PCAP opened"); + } + + if (!(ret = pcap_activate(self->pcap))) { + self->snaplen = pcap_snapshot(self->pcap); + self->linktype = pcap_datalink(self->pcap); + self->is_swapped = 0; + + 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", pcap_major_version(self->pcap), pcap_minor_version(self->pcap), self->snaplen, self->is_swapped ? " swapped" : ""); + } + + return ret; +} + +int input_pcap_open_offline(input_pcap_t* self, const char* file) +{ + char errbuf[PCAP_ERRBUF_SIZE] = { 0 }; + mlassert_self(); + lassert(file, "file is nil"); + + if (self->pcap) { + lfatal("already opened"); + } + + if (!(self->pcap = pcap_open_offline(file, errbuf))) { + lcritical("pcap_open_offline(%s) error: %s", file, errbuf); + return -1; + } + + self->snaplen = pcap_snapshot(self->pcap); + self->linktype = pcap_datalink(self->pcap); + self->is_swapped = pcap_is_swapped(self->pcap); + + 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", pcap_major_version(self->pcap), pcap_minor_version(self->pcap), self->snaplen, self->is_swapped ? " swapped" : ""); + + return 0; +} + +static void _handler(u_char* user, const struct pcap_pkthdr* h, const u_char* bytes) +{ + input_pcap_t* self = (input_pcap_t*)user; + core_object_pcap_t pkt = CORE_OBJECT_PCAP_INIT(0); + mlassert_self(); + lassert(h, "pcap_pkthdr is nil"); + lassert(bytes, "bytes is nil"); + + self->pkts++; + + pkt.snaplen = self->snaplen; + pkt.linktype = self->linktype; + pkt.ts.sec = h->ts.tv_sec; + pkt.ts.nsec = h->ts.tv_usec * 1000; + pkt.caplen = h->caplen; + pkt.len = h->len; + pkt.bytes = bytes; + pkt.is_swapped = self->is_swapped; + + self->recv(self->ctx, (core_object_t*)&pkt); +} + +int input_pcap_loop(input_pcap_t* self, int cnt) +{ + mlassert_self(); + if (!self->pcap) { + lfatal("no PCAP opened"); + } + if (!self->recv) { + lfatal("no receiver set"); + } + + return pcap_loop(self->pcap, cnt, _handler, (void*)self); +} + +int input_pcap_dispatch(input_pcap_t* self, int cnt) +{ + mlassert_self(); + if (!self->pcap) { + lfatal("no PCAP opened"); + } + if (!self->recv) { + lfatal("no receiver set"); + } + + return pcap_dispatch(self->pcap, cnt, _handler, (void*)self); +} + +static const core_object_t* _produce(input_pcap_t* self) +{ + struct pcap_pkthdr* h; + const u_char* bytes; + int ret = 0; + mlassert_self(); + + while (!(ret = pcap_next_ex(self->pcap, &h, &bytes))) + ; + if (ret == 1 && h && bytes) { + self->prod_pkt.ts.sec = h->ts.tv_sec; + self->prod_pkt.ts.nsec = h->ts.tv_usec * 1000; + self->prod_pkt.caplen = h->caplen; + self->prod_pkt.len = h->len; + self->prod_pkt.bytes = bytes; + return (core_object_t*)&self->prod_pkt; + } + + return 0; +} + +core_producer_t input_pcap_producer(input_pcap_t* self) +{ + mlassert_self(); + + if (!self->pcap) { + lfatal("no PCAP opened"); + } + + return (core_producer_t)_produce; +} diff --git a/include/dnsjit/input/pcap.h b/include/dnsjit/input/pcap.h new file mode 100644 index 0000000..cba5227 --- /dev/null +++ b/include/dnsjit/input/pcap.h @@ -0,0 +1,33 @@ +/* + * 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_pcap_h +#define __dnsjit_input_pcap_h + +#include <pcap/pcap.h> + +#include <dnsjit/input/pcap.hh> + +#endif diff --git a/include/dnsjit/input/pcap.hh b/include/dnsjit/input/pcap.hh new file mode 100644 index 0000000..a9e0a41 --- /dev/null +++ b/include/dnsjit/input/pcap.hh @@ -0,0 +1,56 @@ +/* + * 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/>. + */ + +#if 0 +typedef struct pcap {} pcap_t; +#endif + +//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 struct input_pcap { + core_log_t _log; + core_receiver_t recv; + void* ctx; + + uint8_t is_swapped; + + core_object_pcap_t prod_pkt; + + pcap_t* pcap; + size_t pkts; + + size_t snaplen; + uint32_t linktype; +} input_pcap_t; + +core_log_t* input_pcap_log(); + +void input_pcap_init(input_pcap_t* self); +void input_pcap_destroy(input_pcap_t* self); +int input_pcap_create(input_pcap_t* self, const char* source); +int input_pcap_activate(input_pcap_t* self); +int input_pcap_open_offline(input_pcap_t* self, const char* file); +int input_pcap_loop(input_pcap_t* self, int cnt); +int input_pcap_dispatch(input_pcap_t* self, int cnt); + +core_producer_t input_pcap_producer(input_pcap_t* self); diff --git a/include/dnsjit/input/pcap.lua b/include/dnsjit/input/pcap.lua new file mode 100644 index 0000000..89aabd9 --- /dev/null +++ b/include/dnsjit/input/pcap.lua @@ -0,0 +1,130 @@ +-- 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.pcap +-- Read input from an interface or PCAP file using libpcap +-- local input = require("dnsjit.input.pcap").new() +-- input:open_offline("file.pcap") +-- input:receiver(filter_or_output) +-- input:run() +-- +-- Input module for reading packets from interfaces and PCAP files. +module(...,package.seeall) + +require("dnsjit.input.pcap_h") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "input_pcap_t" +local input_pcap_t = ffi.typeof(t_name) +local Pcap = {} + +-- Create a new Pcap input. +function Pcap.new() + local self = { + _receiver = nil, + obj = input_pcap_t(), + } + C.input_pcap_init(self.obj) + ffi.gc(self.obj, C.input_pcap_destroy) + return setmetatable(self, { __index = Pcap }) +end + +-- Return the Log object to control logging of this instance or module. +function Pcap:log() + if self == nil then + return C.input_pcap_log() + end + return self.obj._log +end + +-- Set the receiver to pass objects to. +function Pcap:receiver(o) + self.obj.recv, self.obj.ctx = o:receive() + self._receiver = o +end + +-- Return the C functions and context for producing objects. +function Pcap:produce() + return C.input_pcap_producer(self.obj), self.obj +end + +-- Open a live packet capture on +-- .IR source , +-- which is an interface name or "any" (Linux) / "all" (BSD). +-- Must be activated before use. +function Pcap:create(source) + return C.input_pcap_create(self.obj, source) +end + +-- Activate a live packet capture, see +-- .BR pcap_activate (3pcap) +-- for more information and possible return values. +function Pcap:activate() + return C.input_pcap_activate(self.obj) +end + +-- Open a PCAP file for processing, see +-- .BR pcap_open_offline (3pcap) +-- for more information. +-- Returns 0 on success. +function Pcap:open_offline(file) + return C.input_pcap_open_offline(self.obj, file) +end + +-- Process packets from a live capture or savefile until +-- .I cnt +-- packets are processed, see +-- .BR pcap_loop (3pcap) +-- for more information and possible return values. +function Pcap:loop(cnt) + if cnt == nil then + cnt = -1 + end + return C.input_pcap_loop(self.obj, cnt) +end + +-- Process packets from a live capture or savefile until +-- .I cnt +-- packets are processed, see +-- .BR pcap_dispatch (3pcap) +-- for more information and possible return values. +function Pcap:dispatch(cnt) + if cnt == nil then + cnt = -1 + end + return C.input_pcap_dispatch(self.obj, cnt) +end + +-- Return the number of packets seen. +function Pcap:packets() + return tonumber(self.obj.pkts) +end + +-- Return the linktype of the opened PCAP. +function Pcap:linktype() + return self.obj.linktype +end + +-- Return the snaplen of the opened PCAP. +function Pcap:snaplen() + return self.obj.snaplen +end + +-- dnsjit.output.pcap (3) +return Pcap diff --git a/include/dnsjit/input/zero.lua b/include/dnsjit/input/zero.lua new file mode 100644 index 0000000..c6bf5a4 --- /dev/null +++ b/include/dnsjit/input/zero.lua @@ -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/>. + +-- dnsjit.input.zero +-- Dummy layer to example.input.zero +-- +-- This module has moved to example.input.zero, see examples/modules/input-example in +-- dnsjit source repository. +module(...,package.seeall) + +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 cls diff --git a/include/dnsjit/input/zpcap.c b/include/dnsjit/input/zpcap.c new file mode 100644 index 0000000..11eab9a --- /dev/null +++ b/include/dnsjit/input/zpcap.c @@ -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; +} diff --git a/include/dnsjit/input/zpcap.h b/include/dnsjit/input/zpcap.h new file mode 100644 index 0000000..7f6f304 --- /dev/null +++ b/include/dnsjit/input/zpcap.h @@ -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 diff --git a/include/dnsjit/input/zpcap.hh b/include/dnsjit/input/zpcap.hh new file mode 100644 index 0000000..bc013fa --- /dev/null +++ b/include/dnsjit/input/zpcap.hh @@ -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); diff --git a/include/dnsjit/input/zpcap.lua b/include/dnsjit/input/zpcap.lua new file mode 100644 index 0000000..9a0230f --- /dev/null +++ b/include/dnsjit/input/zpcap.lua @@ -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 diff --git a/include/dnsjit/lib.lua b/include/dnsjit/lib.lua new file mode 100644 index 0000000..d249ea8 --- /dev/null +++ b/include/dnsjit/lib.lua @@ -0,0 +1,29 @@ +-- 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.lib +-- Various Lua libraries or C library bindings +module(...,package.seeall) + +-- dnsjit.lib.base64url (3), +-- dnsjit.lib.clock (3), +-- dnsjit.lib.getopt (3), +-- dnsjit.lib.ip (3), +-- dnsjit.lib.parseconf (3), +-- dnsjit.lib.trie (3) +return diff --git a/include/dnsjit/lib/base64url.c b/include/dnsjit/lib/base64url.c new file mode 100644 index 0000000..aacd490 --- /dev/null +++ b/include/dnsjit/lib/base64url.c @@ -0,0 +1,480 @@ +/* Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "lib/base64url.h" + +#include <errno.h> +#include <stdlib.h> +#include <stdint.h> + +/*! \brief Maximal length of binary input to Base64url encoding. */ +#define MAX_BIN_DATA_LEN ((INT32_MAX / 4) * 3) + +/*! \brief Base64url padding character. */ +static const uint8_t base64url_pad = '\0'; +/*! \brief Base64 alphabet. */ +static const uint8_t base64url_enc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + +/*! \brief Indicates bad Base64 character. */ +#define KO 255 +/*! \brief Indicates Base64 padding character. */ +#define PD 64 + +/*! \brief Transformation and validation table for decoding Base64. */ +static const uint8_t base64url_dec[256] = { + [0] = PD, + [43] = KO, + ['V'] = 21, + [129] = KO, + [172] = KO, + [215] = KO, + [1] = KO, + [44] = KO, + ['W'] = 22, + [130] = KO, + [173] = KO, + [216] = KO, + [2] = KO, + ['-'] = 62, + ['X'] = 23, + [131] = KO, + [174] = KO, + [217] = KO, + [3] = KO, + [46] = KO, + ['Y'] = 24, + [132] = KO, + [175] = KO, + [218] = KO, + [4] = KO, + [47] = KO, + ['Z'] = 25, + [133] = KO, + [176] = KO, + [219] = KO, + [5] = KO, + ['0'] = 52, + [91] = KO, + [134] = KO, + [177] = KO, + [220] = KO, + [6] = KO, + ['1'] = 53, + [92] = KO, + [135] = KO, + [178] = KO, + [221] = KO, + [7] = KO, + ['2'] = 54, + [93] = KO, + [136] = KO, + [179] = KO, + [222] = KO, + [8] = KO, + ['3'] = 55, + [94] = KO, + [137] = KO, + [180] = KO, + [223] = KO, + [9] = KO, + ['4'] = 56, + ['_'] = 63, + [138] = KO, + [181] = KO, + [224] = KO, + [10] = KO, + ['5'] = 57, + [96] = KO, + [139] = KO, + [182] = KO, + [225] = KO, + [11] = KO, + ['6'] = 58, + ['a'] = 26, + [140] = KO, + [183] = KO, + [226] = KO, + [12] = KO, + ['7'] = 59, + ['b'] = 27, + [141] = KO, + [184] = KO, + [227] = KO, + [13] = KO, + ['8'] = 60, + ['c'] = 28, + [142] = KO, + [185] = KO, + [228] = KO, + [14] = KO, + ['9'] = 61, + ['d'] = 29, + [143] = KO, + [186] = KO, + [229] = KO, + [15] = KO, + [58] = KO, + ['e'] = 30, + [144] = KO, + [187] = KO, + [230] = KO, + [16] = KO, + [59] = KO, + ['f'] = 31, + [145] = KO, + [188] = KO, + [231] = KO, + [17] = KO, + [60] = KO, + ['g'] = 32, + [146] = KO, + [189] = KO, + [232] = KO, + [18] = KO, + [61] = KO, + ['h'] = 33, + [147] = KO, + [190] = KO, + [233] = KO, + [19] = KO, + [62] = KO, + ['i'] = 34, + [148] = KO, + [191] = KO, + [234] = KO, + [20] = KO, + [63] = KO, + ['j'] = 35, + [149] = KO, + [192] = KO, + [235] = KO, + [21] = KO, + [64] = KO, + ['k'] = 36, + [150] = KO, + [193] = KO, + [236] = KO, + [22] = KO, + ['A'] = 0, + ['l'] = 37, + [151] = KO, + [194] = KO, + [237] = KO, + [23] = KO, + ['B'] = 1, + ['m'] = 38, + [152] = KO, + [195] = KO, + [238] = KO, + [24] = KO, + ['C'] = 2, + ['n'] = 39, + [153] = KO, + [196] = KO, + [239] = KO, + [25] = KO, + ['D'] = 3, + ['o'] = 40, + [154] = KO, + [197] = KO, + [240] = KO, + [26] = KO, + ['E'] = 4, + ['p'] = 41, + [155] = KO, + [198] = KO, + [241] = KO, + [27] = KO, + ['F'] = 5, + ['q'] = 42, + [156] = KO, + [199] = KO, + [242] = KO, + [28] = KO, + ['G'] = 6, + ['r'] = 43, + [157] = KO, + [200] = KO, + [243] = KO, + [29] = KO, + ['H'] = 7, + ['s'] = 44, + [158] = KO, + [201] = KO, + [244] = KO, + [30] = KO, + ['I'] = 8, + ['t'] = 45, + [159] = KO, + [202] = KO, + [245] = KO, + [31] = KO, + ['J'] = 9, + ['u'] = 46, + [160] = KO, + [203] = KO, + [246] = KO, + [32] = KO, + ['K'] = 10, + ['v'] = 47, + [161] = KO, + [204] = KO, + [247] = KO, + [33] = KO, + ['L'] = 11, + ['w'] = 48, + [162] = KO, + [205] = KO, + [248] = KO, + [34] = KO, + ['M'] = 12, + ['x'] = 49, + [163] = KO, + [206] = KO, + [249] = KO, + [35] = KO, + ['N'] = 13, + ['y'] = 50, + [164] = KO, + [207] = KO, + [250] = KO, + [36] = KO, + ['O'] = 14, + ['z'] = 51, + [165] = KO, + [208] = KO, + [251] = KO, + [37] = KO, + ['P'] = 15, + [123] = KO, + [166] = KO, + [209] = KO, + [252] = KO, + [38] = KO, + ['Q'] = 16, + [124] = KO, + [167] = KO, + [210] = KO, + [253] = KO, + [39] = KO, + ['R'] = 17, + [125] = KO, + [168] = KO, + [211] = KO, + [254] = KO, + [40] = KO, + ['S'] = 18, + [126] = KO, + [169] = KO, + [212] = KO, + [255] = KO, + [41] = KO, + ['T'] = 19, + [127] = KO, + [170] = KO, + [213] = KO, + [42] = KO, + ['U'] = 20, + [128] = KO, + [171] = KO, + [214] = KO, +}; + +int32_t base64url_encode(const uint8_t* in, + const uint32_t in_len, + uint8_t* out, + const uint32_t out_len) +{ + // Checking inputs. + if (in == NULL || out == NULL) { + return -EINVAL; + } + if (in_len > MAX_BIN_DATA_LEN || out_len < ((in_len + 2) / 3) * 4) { + return -ERANGE; + } + + uint8_t rest_len = in_len % 3; + const uint8_t* stop = in + in_len - rest_len; + uint8_t* text = out; + + // Encoding loop takes 3 bytes and creates 4 characters. + while (in < stop) { + text[0] = base64url_enc[in[0] >> 2]; + text[1] = base64url_enc[(in[0] & 0x03) << 4 | in[1] >> 4]; + text[2] = base64url_enc[(in[1] & 0x0F) << 2 | in[2] >> 6]; + text[3] = base64url_enc[in[2] & 0x3F]; + text += 4; + in += 3; + } + + // Processing of padding, if any. + switch (rest_len) { + case 2: + text[0] = base64url_enc[in[0] >> 2]; + text[1] = base64url_enc[(in[0] & 0x03) << 4 | in[1] >> 4]; + text[2] = base64url_enc[(in[1] & 0x0F) << 2]; + text[3] = base64url_pad; + text += 3; + break; + case 1: + text[0] = base64url_enc[in[0] >> 2]; + text[1] = base64url_enc[(in[0] & 0x03) << 4]; + text[2] = base64url_pad; + text[3] = base64url_pad; + text += 2; + break; + } + return (text - out); +} + +int32_t base64url_encode_alloc(const uint8_t* in, + const uint32_t in_len, + uint8_t** out) +{ + // Checking inputs. + if (out == NULL) { + return -EINVAL; + } + if (in_len > MAX_BIN_DATA_LEN) { + return -ERANGE; + } + + // Compute output buffer length. + uint32_t out_len = ((in_len + 2) / 3) * 4; + + // Allocate output buffer. + *out = malloc(out_len); + if (*out == NULL) { + return -ENOMEM; + } + + // Encode data. + int32_t ret = base64url_encode(in, in_len, *out, out_len); + if (ret < 0) { + free(*out); + *out = NULL; + } + + return ret; +} + +int32_t base64url_decode(const uint8_t* in, + const uint32_t in_len, + uint8_t* out, + const uint32_t out_len) +{ + // Checking inputs. + if (in == NULL || out == NULL) { + return -EINVAL; + } + if (in_len > INT32_MAX || out_len < ((in_len + 3) / 4) * 3) { + return -ERANGE; + } + + const uint8_t* stop = in + in_len; + uint8_t* bin = out; + uint8_t pad_len = 0; + uint8_t c1, c2, c3, c4; + + // Decoding loop takes 4 characters and creates 3 bytes. + while (in < stop) { + // Filling and transforming 4 Base64 chars. + c1 = base64url_dec[in[0]]; + c2 = (in + 1 < stop) ? base64url_dec[in[1]] : PD; + c3 = (in + 2 < stop) ? base64url_dec[in[2]] : PD; + c4 = (in + 3 < stop) ? base64url_dec[in[3]] : PD; + + // Check 4. char if is bad or padding. + if (c4 >= PD) { + if (c4 == PD && pad_len == 0) { + pad_len = 1; + } else { + return -1; + } + } + + // Check 3. char if is bad or padding. + if (c3 >= PD) { + if (c3 == PD && pad_len == 1) { + pad_len = 2; + } else { + return -1; + } + } + + // Check 1. and 2. chars if are not padding. + if (c2 >= PD || c1 >= PD) { + return -1; + } + + // Computing of output data based on padding length. + switch (pad_len) { + case 0: + bin[2] = (c3 << 6) + c4; + // FALLTHROUGH + case 1: + bin[1] = (c2 << 4) + (c3 >> 2); + // FALLTHROUGH + case 2: + bin[0] = (c1 << 2) + (c2 >> 4); + } + + // Update output end. + switch (pad_len) { + case 0: + bin += 3; + break; + case 1: + bin += 2; + break; + case 2: + bin += 1; + break; + } + + in += 4; + } + + return (bin - out); +} + +int32_t base64url_decode_alloc(const uint8_t* in, + const uint32_t in_len, + uint8_t** out) +{ + // Checking inputs. + if (out == NULL) { + return -EINVAL; + } + + // Compute output buffer length. + uint32_t out_len = ((in_len + 3) / 4) * 3; + + // Allocate output buffer. + *out = malloc(out_len); + if (*out == NULL) { + return -ENOMEM; + } + + // Decode data. + int32_t ret = base64url_decode(in, in_len, *out, out_len); + if (ret < 0) { + free(*out); + *out = NULL; + } + + return ret; +} diff --git a/include/dnsjit/lib/base64url.h b/include/dnsjit/lib/base64url.h new file mode 100644 index 0000000..f2f5808 --- /dev/null +++ b/include/dnsjit/lib/base64url.h @@ -0,0 +1,28 @@ +/* + * 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 <stdint.h> + +#ifndef __dnsjit_lib_base64url_h +#define __dnsjit_lib_base64url_h + +#include <dnsjit/lib/base64url.hh> + +#endif diff --git a/include/dnsjit/lib/base64url.hh b/include/dnsjit/lib/base64url.hh new file mode 100644 index 0000000..5f19a10 --- /dev/null +++ b/include/dnsjit/lib/base64url.hh @@ -0,0 +1,99 @@ +/* Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +/*! + * \brief Base64url implementation (RFC 4648). + */ + +/*! + * \brief Encodes binary data using Base64. + * + * \note Output data buffer contains Base64 text string which isn't + * terminated with '\0'! + * + * \param in Input binary data. + * \param in_len Length of input data. + * \param out Output data buffer. + * \param out_len Size of output buffer. + * + * \retval >=0 length of output string. + * \retval KNOT_E* if error. + */ +int32_t base64url_encode(const uint8_t* in, + const uint32_t in_len, + uint8_t* out, + const uint32_t out_len); + +/*! + * \brief Encodes binary data using Base64 and output stores to own buffer. + * + * \note Output data buffer contains Base64 text string which isn't + * terminated with '\0'! + * + * \note Output buffer should be deallocated after use. + * + * \param in Input binary data. + * \param in_len Length of input data. + * \param out Output data buffer. + * + * \retval >=0 length of output string. + * \retval KNOT_E* if error. + */ +int32_t base64url_encode_alloc(const uint8_t* in, + const uint32_t in_len, + uint8_t** out); + +/*! + * \brief Decodes text data using Base64. + * + * \note Input data needn't be terminated with '\0'. + * + * \note Input data must be continuous Base64 string! + * + * \param in Input text data. + * \param in_len Length of input string. + * \param out Output data buffer. + * \param out_len Size of output buffer. + * + * \retval >=0 length of output data. + * \retval KNOT_E* if error. + */ +int32_t base64url_decode(const uint8_t* in, + const uint32_t in_len, + uint8_t* out, + const uint32_t out_len); + +/*! + * \brief Decodes text data using Base64 and output stores to own buffer. + * + * \note Input data needn't be terminated with '\0'. + * + * \note Input data must be continuous Base64 string! + * + * \note Output buffer should be deallocated after use. + * + * \param in Input text data. + * \param in_len Length of input string. + * \param out Output data buffer. + * + * \retval >=0 length of output data. + * \retval KNOT_E* if error. + */ +int32_t base64url_decode_alloc(const uint8_t* in, + const uint32_t in_len, + uint8_t** out); + +/*! @} */ diff --git a/include/dnsjit/lib/base64url.lua b/include/dnsjit/lib/base64url.lua new file mode 100644 index 0000000..8a408f5 --- /dev/null +++ b/include/dnsjit/lib/base64url.lua @@ -0,0 +1,97 @@ +-- 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/>. + +-- dnsjit.lib.base64url +-- Utility library to convert data to base64url format +-- local base64url = require("dnsjit.lib.base64url") +-- .SS Encoding and decoding lua strings +-- local encoded = base64url.encode("abcd") +-- local decoded = base64url.decode(encoded) +-- .SS Encoding C byte arrays +-- local pl -- pl is core.object.payload +-- local encoded = base64url.encode(pl.payload, pl.len) +-- +-- Encode and decode data to/from base64url format. +module(...,package.seeall) + +require("dnsjit.lib.base64url_h") +local ffi = require("ffi") +local C = ffi.C +local log = require("dnsjit.core.log") +local module_log = log.new("lib.base64url") + +Base64Url = {} + +-- Encode lua string or C byte array to base64url representation. +-- The input string may contain non-printable characters. +-- +-- .B data_len +-- is length of the input data (optional for lua strings, required for +-- C byte arrays). +function Base64Url.encode(data, data_len) + data_len = tonumber(data_len) -- in case of cdata length + if type(data) == "cdata" then + if type(data_len) ~= "number" then + module_log:fatal("encode: data_len must be specified for cdata") + return + end + elseif type(data) ~= "string" then + module_log:fatal("encode: input must be string") + return + end + + if data_len ~= nil and data_len < 0 then + module_log:fatal("encode: data_len must be greater than 0") + return + end + + local in_len = data_len or string.len(data) + local buf_len = math.ceil(4 * in_len / 3) + 2 + local buf = ffi.new("uint8_t[?]", buf_len) + local out_len = ffi.C.base64url_encode(data, in_len, buf, buf_len) + if out_len < 0 then + module_log:critical("encode: error ("..log.errstr(-out_len)..")") + return + end + return ffi.string(buf, out_len) +end + +-- Decode a base64url encoded lua string. +-- The output string may contain non-printable characters. +function Base64Url.decode(data) + if type(data) ~= "string" then + module_log:fatal("decode: input must be string") + return + end + + local in_len = string.len(data) + local buf_len = math.ceil(3 * in_len / 4) + 1 + local buf = ffi.new("uint8_t[?]", buf_len) + local out_len = ffi.C.base64url_decode(data, in_len, buf, buf_len) + if out_len == -34 then -- ERANGE + module_log:critical("decode: error "..log.errstr(-out_len).." - invalid character(s) in input string?") + return + elseif out_len < 0 then + module_log:critical("decode: error "..log.errstr(-out_len)) + return + end + return ffi.string(buf, out_len) +end + +-- dnsjit.core.object.payload (3) +return Base64Url diff --git a/include/dnsjit/lib/clock.c b/include/dnsjit/lib/clock.c new file mode 100644 index 0000000..0676648 --- /dev/null +++ b/include/dnsjit/lib/clock.c @@ -0,0 +1,75 @@ +/* + * 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 "lib/clock.h" + +#include <time.h> + +core_timespec_t lib_clock_getres(lib_clock_clkid_t clkid) +{ + struct timespec ts; + core_timespec_t ret = { 0, 0 }; + clockid_t clk_id; + + switch (clkid) { + case LIB_CLOCK_REALTIME: + clk_id = CLOCK_REALTIME; + break; + case LIB_CLOCK_MONOTONIC: + clk_id = CLOCK_MONOTONIC; + break; + default: + return ret; + } + + if (!clock_getres(clk_id, &ts)) { + ret.sec = ts.tv_sec; + ret.nsec = ts.tv_nsec; + } + + return ret; +} + +core_timespec_t lib_clock_gettime(lib_clock_clkid_t clkid) +{ + struct timespec ts; + core_timespec_t ret = { 0, 0 }; + clockid_t clk_id; + + switch (clkid) { + case LIB_CLOCK_REALTIME: + clk_id = CLOCK_REALTIME; + break; + case LIB_CLOCK_MONOTONIC: + clk_id = CLOCK_MONOTONIC; + break; + default: + return ret; + } + + if (!clock_gettime(clk_id, &ts)) { + ret.sec = ts.tv_sec; + ret.nsec = ts.tv_nsec; + } + + return ret; +} diff --git a/include/dnsjit/lib/clock.h b/include/dnsjit/lib/clock.h new file mode 100644 index 0000000..48d16ac --- /dev/null +++ b/include/dnsjit/lib/clock.h @@ -0,0 +1,28 @@ +/* + * 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/timespec.h> + +#ifndef __dnsjit_lib_clock_h +#define __dnsjit_lib_clock_h + +#include <dnsjit/lib/clock.hh> + +#endif diff --git a/include/dnsjit/lib/clock.hh b/include/dnsjit/lib/clock.hh new file mode 100644 index 0000000..9463815 --- /dev/null +++ b/include/dnsjit/lib/clock.hh @@ -0,0 +1,29 @@ +/* + * 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.timespec_h") + +typedef enum lib_clock_clkid { + LIB_CLOCK_REALTIME, + LIB_CLOCK_MONOTONIC +} lib_clock_clkid_t; + +core_timespec_t lib_clock_getres(lib_clock_clkid_t clkid); +core_timespec_t lib_clock_gettime(lib_clock_clkid_t clkid); diff --git a/include/dnsjit/lib/clock.lua b/include/dnsjit/lib/clock.lua new file mode 100644 index 0000000..60ee9f6 --- /dev/null +++ b/include/dnsjit/lib/clock.lua @@ -0,0 +1,47 @@ +-- 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.lib.clock +-- Clock and time functions +-- local clock = require("dnsjit.lib.clock") +-- local sec, nsec = clock.monotonic() +-- +-- Functions to get the time from system-wide clocks. +module(...,package.seeall) + +require("dnsjit.lib.clock_h") +local C = require("ffi").C + +Clock = {} + +-- Return the current seconds and nanoseconds (as a list) from the realtime +-- clock. +function Clock.realtime() + local ts = C.lib_clock_gettime("LIB_CLOCK_REALTIME") + return tonumber(ts.sec), tonumber(ts.nsec) +end + +-- Return the current seconds and nanoseconds (as a list) from the monotonic +-- clock. +function Clock.monotonic() + local ts = C.lib_clock_gettime("LIB_CLOCK_MONOTONIC") + return tonumber(ts.sec), tonumber(ts.nsec) +end + +-- clock_gettime (2) +return Clock diff --git a/include/dnsjit/lib/getopt.lua b/include/dnsjit/lib/getopt.lua new file mode 100644 index 0000000..ede3e12 --- /dev/null +++ b/include/dnsjit/lib/getopt.lua @@ -0,0 +1,368 @@ +-- 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.lib.getopt +-- Parse and handle arguments +-- local getopt = require("dnsjit.lib.getopt").new({ +-- { "v", "verbose", 0, "Enable verbosity", "?+" }, +-- { nil, "host", "localhost", "Set host", "?" }, +-- { "p", nil, 53, "Set port", "?" }, +-- }) +-- . +-- local left = getopt:parse() +-- . +-- print("host", getopt:val("host")) +-- print("port", getopt:val("p")) +-- +-- A "getopt long" implementation to easily handle command line arguments +-- and display usage. +-- An option is the short name (one character), long name, +-- default value (which also defines the type), help text and extensions. +-- Options are by default required, see extensions to change this. +-- .LP +-- The Lua types allowed are +-- .BR boolean , +-- .BR string , +-- .BR number . +-- .LP +-- The extensions available are: +-- .TP +-- .B ? +-- Make the option optional. +-- .TP +-- .B * +-- For string and number options this make it possible to specified it +-- multiple times and all values will be returned in a table. +-- .TP +-- .B + +-- For number options this will act as an counter increaser, the value will +-- be the default value + 1 for each time the option is given. +-- .LP +-- Option +-- .I -h +-- and +-- .I --help +-- are automatically added if the option +-- .I --help +-- is not already defined. +-- .SS Attributes +-- .TP +-- left +-- A table that contains the arguments left after parsing, same as returned by +-- .IR parse() . +-- .TP +-- usage_desc +-- A string that describes the usage of the program, if not set then the +-- default will be " +-- .I "program [options...]" +-- ". +module(...,package.seeall) + +local log = require("dnsjit.core.log") + +local module_log = log.new("lib.getopt") +Getopt = {} + +-- Create a new Getopt object. +-- .I args +-- is a table with tables that specifies the options available. +-- Each entry is unpacked and sent to +-- .BR Getopt:add() . +function Getopt.new(args) + local self = setmetatable({ + left = {}, + usage_desc = nil, + _opt = {}, + _s2l = {}, + _log = log.new("lib.getopt", module_log), + }, { __index = Getopt }) + + self._log:debug("new()") + + for k, v in pairs(args) do + local short, long, default, help, extensions = unpack(v) + self:add(short, long, default, help, extensions) + end + + return self +end + +-- Return the Log object to control logging of this instance or module. +function Getopt:log() + if self == nil then + return module_log + end + return self._log +end + +-- Add an option. +function Getopt:add(short, long, default, help, extensions) + local optional = false + local multiple = false + local counter = false + local name = long or short + + if type(name) ~= "string" then + error("long|short) need to be a string") + 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") + elseif short and self._s2l[short] then + error("option "..short.." alredy exists") + end + + local t = type(default) + if t ~= "string" and t ~= "number" and t ~= "boolean" then + error("option "..name..": invalid type "..t) + end + + if type(extensions) == "string" then + local n + for n = 1, extensions:len() do + local extension = extensions:sub(n, n) + if extension == "?" then + optional = true + elseif extension == "*" then + multiple = true + elseif extension == "+" then + counter = true + else + error("option "..name..": invalid extension "..extension) + end + end + end + + self._opt[name] = { + value = nil, + short = short, + long = long, + type = t, + default = default, + help = help, + optional = optional, + multiple = multiple, + counter = counter, + } + if long and short then + self._s2l[short] = long + elseif short and not long then + self._s2l[short] = short + end + + if not self._opt["help"] then + self._opt["help"] = { + short = nil, + long = "help", + type = "boolean", + default = false, + help = "Display this help text", + optional = true, + } + if not self._s2l["h"] then + self._opt["help"].short = "h" + self._s2l["h"] = "help" + end + end +end + +-- Print the usage. +function Getopt:usage() + if self.usage_desc then + print("usage: " .. self.usage_desc) + else + print("usage: program [options...]") + end + + local opts = {} + for k, _ in pairs(self._opt) do + if k ~= "help" then + table.insert(opts, k) + end + end + table.sort(opts) + table.insert(opts, "help") + + for _, k in pairs(opts) do + local v = self._opt[k] + local arg + if v.type == "string" then + arg = " \""..v.default.."\"" + elseif v.type == "number" and v.counter == false then + arg = " "..v.default + else + arg = "" + end + if v.long then + print("", (v.short and "-"..v.short or " ").." --"..v.long..arg, v.help) + else + print("", "-"..v.short..arg, v.help) + end + end +end + +-- Parse the options. +-- If +-- .I args +-- is not specified or nil then the global +-- .B arg +-- is used. +-- If +-- .I startn +-- is given, it will start parsing arguments in the table from that position. +-- The default position to start at is 2 for +-- .IR dnsjit , +-- see +-- .BR dnsjit.core (3). +function Getopt:parse(args, startn) + if not args then + args = arg + end + + local n + local opt = nil + local left = {} + local need_arg = false + local stop = false + local name + for n = startn or 2, table.maxn(args) do + if need_arg then + if opt.multiple then + if opt.value == nil then + opt.value = {} + end + if opt.type == "number" then + table.insert(opt.value, tonumber(args[n])) + else + table.insert(opt.value, args[n]) + end + else + if opt.type == "number" then + opt.value = tonumber(args[n]) + else + opt.value = args[n] + end + end + need_arg = false + elseif stop or args[n] == "-" then + table.insert(left, args[n]) + elseif args[n] == "--" then + stop = true + elseif args[n]:sub(1, 1) == "-" then + if args[n]:sub(1, 2) == "--" then + name = args[n]:sub(3) + else + name = args[n]:sub(2) + if name:len() > 1 then + local n2, name2 + for n2 = 1, name:len() - 1 do + name2 = name:sub(n2, n2) + opt = self._opt[self._s2l[name2]] + if not opt then + error("unknown option "..name2) + end + if opt.type == "number" and opt.counter then + if opt.value == nil then + opt.value = opt.default + end + opt.value = opt.value + 1 + elseif opt.type == "boolean" then + if opt.value == nil then + opt.value = opt.default + end + if opt.value then + opt.value = false + else + opt.value = true + end + else + error("invalid short option '"..name2.."' in multioption statement") + end + end + name = name:sub(-1) + end + end + if self._s2l[name] then + name = self._s2l[name] + end + if not self._opt[name] then + error("unknown option "..name) + end + opt = self._opt[name] + if opt.type == "string" then + need_arg = true + elseif opt.type == "number" then + if opt.counter then + if opt.value == nil then + opt.value = opt.default + end + opt.value = opt.value + 1 + else + need_arg = true + end + elseif opt.type == "boolean" then + if opt.value == nil then + opt.value = opt.default + end + if opt.value then + opt.value = false + else + opt.value = true + end + else + error("internal error, invalid option type "..opt.type) + end + else + table.insert(left, args[n]) + end + end + + if need_arg then + error("option "..name.." needs argument") + end + + for k, v in pairs(self._opt) do + if v.optional == false and v.value == nil then + error("missing required option "..k.."") + end + end + + self.left = left + return left +end + +-- Return the value of an option. +function Getopt:val(name) + local opt = self._opt[name] or self._opt[self._s2l[name]] + if not opt then + return + end + if opt.value == nil then + return opt.default + else + return opt.value + end +end + +-- dnsjit.core (3) +return Getopt diff --git a/include/dnsjit/lib/ip.lua b/include/dnsjit/lib/ip.lua new file mode 100644 index 0000000..74dc85a --- /dev/null +++ b/include/dnsjit/lib/ip.lua @@ -0,0 +1,125 @@ +-- 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.lib.ip +-- IP address utility library +-- local ip = require("dnsjit.lib.ip") +-- print(ip.ipstring(ipv4_cdata)) +-- print(ip.ip6string(ipv6_cdata), true) +-- +-- A library to help with various IP address related tasks, such as +-- printing them. +module(...,package.seeall) + +local ffi = require("ffi") + +Ip = {} + +-- Return an IPv4 or IPv6 address as a string. +-- If it's an IPv6 address the optional argument +-- .I pretty +-- is true then return an easier to read IPv6 address. +-- Return an empty string on invalid input. +function Ip.tostring(ip, pretty) + if type(ip) == "cdata" then + if ffi.sizeof(ip) == 4 then + return Ip.ipstring(ip) + elseif ffi.sizeof(ip) == 16 then + return Ip.ip6string(ip, pretty) + end + end + return "" +end + +-- Return a IPv4 address as a string. +-- The input is a 4-byte cdata array. +function Ip.ipstring(ip) + return ip[0] ..".".. ip[1] ..".".. ip[2] ..".".. ip[3] +end + +local function _pretty(ip) + local src = {} + + local n, nn + nn = 1 + for n = 0, 15, 2 do + if ip[n] ~= 0 then + src[nn] = string.format("%x%02x", ip[n], ip[n + 1]) + elseif ip[n + 1] ~= 0 then + src[nn] = string.format("%x", ip[n + 1]) + else + src[nn] = "0" + end + nn = nn + 1 + end + + local best_n, best_at, at = 0, 0, 0 + n = 0 + for nn = 1, 8 do + if src[nn] == "0" then + if n == 0 then + at = nn + end + n = n + 1 + else + if n > 0 then + if n > best_n then + best_n = n + best_at = at + end + n = 0 + end + end + end + if n > 0 then + if n > best_n then + best_n = n + best_at = at + end + end + if best_n > 1 then + for n = 2, best_n do + table.remove(src, best_at) + end + if best_at == 1 or best_at + best_n > 8 then + src[best_at] = ":" + else + src[best_at] = "" + end + end + + return table.concat(src,":") +end + +-- Return the IPv6 address as a string. +-- The input is a 16-byte cdata array. +-- If +-- .I pretty +-- is true then return an easier to read IPv6 address. +function Ip.ip6string(ip6, pretty) + if pretty == true then + return _pretty(ip6) + end + return string.format("%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", + ip6[0], ip6[1], ip6[2], ip6[3], ip6[4], ip6[5], ip6[6], ip6[7], + ip6[8], ip6[9], ip6[10], ip6[11], ip6[12], ip6[13], ip6[14], ip6[15]) +end + +-- dnsjit.core.object.ip (3), +-- dnsjit.core.object.ip6 (3) +return Ip diff --git a/include/dnsjit/lib/parseconf.lua b/include/dnsjit/lib/parseconf.lua new file mode 100644 index 0000000..638763b --- /dev/null +++ b/include/dnsjit/lib/parseconf.lua @@ -0,0 +1,181 @@ +-- 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.lib.parseconf +-- Parse simple config files +-- local conf = require("dnsjit.lib.parseconf").new() +-- . +-- conf:func("config_name", function(k,...) +-- print(k,...) +-- end) +-- . +-- conf:file(file) +-- . +-- print(conf:val("another_config_name")) +-- +-- This module parses simple config files that are based on the config +-- syntax of DSC, drool and parseconf helper library. +-- Each config begins with a +-- .B name +-- followed by +-- .B options +-- and ends with a +-- .BR ; . +-- Multiple configs can be given on the same line. +-- Valid option types are +-- .IR number , +-- .IR float , +-- .IR string , +-- .IR "quoted string" . +-- Comments can be added by prefixing the comment with +-- .BR # . +-- .SS Example +-- # Comment +-- number 12345; +-- float 123.456; +-- string string string; +-- quoted_string "string string string"; +-- multi config; on one line; +module(...,package.seeall) + +local log = require("dnsjit.core.log") + +local module_log = log.new("lib.parseconf") +Parseconf = {} + +-- Create a new Parseconf object. +function Parseconf.new() + local self = setmetatable({ + conf = {}, + cf = {}, + _log = log.new("lib.parseconf", module_log), + }, { __index = Parseconf }) + + self._log:debug("new()") + + return self +end + +-- Return the Log object to control logging of this instance or module. +function Parseconf:log() + if self == nil then + return module_log + end + return self._log +end + +-- Set a function to call when config +-- .I name +-- is found. +function Parseconf:func(name, func) + self.cf[name] = func +end + +function Parseconf:part(l, n) + local p + p = l:match("^(%d+)[%s;]", n) + if p then + return p, tonumber(p) + end + p = l:match("^(%d+%.%d+)[%s;]", n) + if p then + return p, tonumber(p) + end + p = l:match("^(\"[^\"]+\")[%s;]", n) + if p then + return p, p:sub(2, -2) + end + p = l:match("^([^%s;]+)[%s;]", n) + if p then + return p, p + end +end + +function Parseconf:next(l, n) + local eol = l:match("^%s*;%s*", n) + if eol then + return true, eol + end + local ws = l:match("^%s+", n) + if ws then + return ws + end + return false +end + +-- Parse the given file. +function Parseconf:file(fn) + local ln, l + ln = 1 + for l in io.lines(fn) do + local c = l:find("#") + if c then + l = l:sub(1, c - 1) + end + local e, m = pcall(self.line, self, l) + if e == false then + error("parse error in "..fn.."["..ln.."]: "..m) + end + ln = ln + 1 + end +end + +-- Parse the given line. +function Parseconf:line(l) + local n + n = 1 + while n <= l:len() do + local c = nil + local va = {} + while true do + local p, v = self:part(l, n) + if not p then + error("invalid config at character "..n..": "..l:sub(n)) + end + if not c then + c = p + else + table.insert(va, v) + end + n = n + p:len() + local ws, eol = self:next(l, n) + if ws == true then + if eol then + n = n + eol:len() + end + break + elseif ws == false then + error("invalid config at character "..n..": "..l:sub(n)) + end + n = n + ws:len() + end + if self.cf[c] then + self.cf[c](c, unpack(va)) + else + self.conf[c] = va + end + end +end + +-- Get the value of a config +-- .IR name . +function Parseconf:val(name) + return self.conf[name] +end + +return Parseconf diff --git a/include/dnsjit/lib/trie.c b/include/dnsjit/lib/trie.c new file mode 100644 index 0000000..158c5ca --- /dev/null +++ b/include/dnsjit/lib/trie.c @@ -0,0 +1,923 @@ +/* + * Copyright (C) 2016-2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * The code originated from https://github.com/fanf2/qp/blob/master/qp.c + * at revision 5f6d93753. + */ + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include "lib/trie.h" + +/*! \brief Error codes used in the library. */ +enum knot_error { + KNOT_EOK = 0, + + /* Directly mapped error codes. */ + KNOT_ENOMEM = -ENOMEM, + KNOT_EINVAL = -EINVAL, + KNOT_ENOENT = -ENOENT, +}; + +#if defined(__i386) || defined(__x86_64) || defined(_M_IX86) \ + || (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN) \ + && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + +/*! + * \brief Use a pointer alignment hack to save memory. + * + * When on, isbranch() relies on the fact that in leaf_t the first pointer + * is aligned on multiple of 4 bytes and that the flags bitfield is + * overlaid over the lowest two bits of that pointer. + * Neither is really guaranteed by the C standards; the second part should + * be OK with x86_64 ABI and most likely any other little-endian platform. + * It would be possible to manipulate the right bits portably, but it would + * complicate the code nontrivially. C++ doesn't even guarantee type-punning. + * In debug mode we check this works OK when creating a new trie instance. + */ +#define FLAGS_HACK 1 +#else +#define FLAGS_HACK 0 +#endif + +typedef unsigned char byte; +#ifndef uint +typedef unsigned int uint; +#define uint uint +#endif +typedef uint bitmap_t; /*! Bit-maps, using the range of 1<<0 to 1<<16 (inclusive). */ + +typedef struct { + uint32_t len; // 32 bits are enough for key lengths; probably even 16 bits would be. + uint8_t chars[]; +} tkey_t; + +/*! \brief Leaf of trie. */ +typedef struct { +#if !FLAGS_HACK + byte flags; +#endif + tkey_t* key; /*!< The pointer must be aligned to 4-byte multiples! */ + trie_val_t val; +} leaf_t; + +/*! \brief A trie node is either leaf_t or branch_t. */ +typedef union node node_t; + +/*! + * \brief Branch node of trie. + * + * - The flags distinguish whether the node is a leaf_t (0), or a branch + * testing the more-important nibble (1) or the less-important one (2). + * - It stores the index of the byte that the node tests. The combined + * value (index*4 + flags) increases in branch nodes as you go deeper + * into the trie. All the keys below a branch are identical up to the + * nibble identified by the branch. Indices have to be stored because + * we skip any branch nodes that would have a single child. + * (Consequently, the skipped parts of key have to be validated in a leaf.) + * - The bitmap indicates which subtries are present. The present child nodes + * are stored in the twigs array (with no holes between them). + * - To simplify storing keys that are prefixes of each other, the end-of-string + * position is treated as another nibble value, ordered before all others. + * That affects the bitmap and twigs fields. + * + * \note The branch nodes are never allocated individually, but they are + * always part of either the root node or the twigs array of the parent. + */ +typedef struct { +#if FLAGS_HACK + uint32_t flags : 2, + bitmap : 17; /*!< The first bitmap bit is for end-of-string child. */ +#else + byte flags; + uint32_t bitmap; +#endif + uint32_t index; + node_t* twigs; +} branch_t; + +union node { + leaf_t leaf; + branch_t branch; +}; + +struct trie { + node_t root; // undefined when weight == 0, see empty_root() + size_t weight; + knot_mm_t mm; +}; + +/* Included from other files */ + +/** Readability: avoid const-casts in code. */ +static inline void free_const(const void* what) +{ + free((void*)what); +} + +static inline void* mm_alloc(knot_mm_t* mm, size_t size) +{ + if (mm) + return mm->alloc(mm->ctx, size); + else + return malloc(size); +} + +static inline void mm_free(knot_mm_t* mm, const void* what) +{ + if (mm) { + if (mm->free) + mm->free((void*)what); + } else + free_const(what); +} + +static void* mm_malloc(void* ctx, size_t n) +{ + (void)ctx; + return malloc(n); +} + +static void* mm_realloc(knot_mm_t* mm, void* what, size_t size, size_t prev_size) +{ + if (mm) { + void* p = mm->alloc(mm->ctx, size); + if (p == NULL) { + return NULL; + } else { + if (what) { + memcpy(p, what, + prev_size < size ? prev_size : size); + } + mm_free(mm, what); + return p; + } + } else { + return realloc(what, size); + } +} + +static inline void mm_ctx_init(knot_mm_t* mm) +{ + mm->ctx = NULL; + mm->alloc = mm_malloc; + mm->free = free; +} + +/*! \brief Make the root node empty (debug-only). */ +static inline void empty_root(node_t* root) +{ +#ifndef NDEBUG + *root = (node_t) { .branch = { + .flags = 3, // invalid value that fits + .bitmap = 0, + .index = -1, + .twigs = NULL } }; +#endif +} + +/*! \brief Check that unportable code works OK (debug-only). */ +static void assert_portability(void) +{ +#if FLAGS_HACK + assert(((union node) { .leaf = { + .key = (tkey_t*)(((uint8_t*)NULL) + 1), + .val = NULL } }) + .branch.flags + == 1); +#endif +} + +/*! \brief Propagate error codes. */ +#define ERR_RETURN(x) \ + do { \ + int err_code_ = x; \ + if (unlikely(err_code_ != KNOT_EOK)) \ + return err_code_; \ + } while (false) + +/*! + * \brief Count the number of set bits. + * + * \TODO This implementation may be relatively slow on some HW. + */ +static uint bitmap_weight(bitmap_t w) +{ + assert((w & ~((1 << 17) - 1)) == 0); // using the least-important 17 bits + return __builtin_popcount(w); +} + +/*! \brief Only keep the lowest bit in the bitmap (least significant -> twigs[0]). */ +static bitmap_t bitmap_lowest_bit(bitmap_t w) +{ + assert((w & ~((1 << 17) - 1)) == 0); // using the least-important 17 bits + return 1 << __builtin_ctz(w); +} + +/*! \brief Test flags to determine type of this node. */ +static bool isbranch(const node_t* t) +{ + uint f = t->branch.flags; + assert(f <= 2); + return f != 0; +} + +/*! \brief Make a bitmask for testing a branch bitmap. */ +static bitmap_t nibbit(byte k, uint flags) +{ + uint shift = (2 - flags) << 2; + uint nibble = (k >> shift) & 0xf; + return 1 << (nibble + 1 /*because of prefix keys*/); +} + +/*! \brief Extract a nibble from a key and turn it into a bitmask. */ +static bitmap_t twigbit(const node_t* t, const uint8_t* key, uint32_t len) +{ + assert(isbranch(t)); + uint i = t->branch.index; + + if (i >= len) + return 1 << 0; // leaf position + + return nibbit((byte)key[i], t->branch.flags); +} + +/*! \brief Test if a branch node has a child indicated by a bitmask. */ +static bool hastwig(const node_t* t, bitmap_t bit) +{ + assert(isbranch(t)); + return t->branch.bitmap & bit; +} + +/*! \brief Compute offset of an existing child in a branch node. */ +static uint twigoff(const node_t* t, bitmap_t b) +{ + assert(isbranch(t)); + return bitmap_weight(t->branch.bitmap & (b - 1)); +} + +/*! \brief Get pointer to a particular child of a branch node. */ +static node_t* twig(node_t* t, uint i) +{ + assert(isbranch(t)); + return &t->branch.twigs[i]; +} + +/*! + * \brief For a branch nod, compute offset of a child and child count. + * + * Having this separate might be meaningful for performance optimization. + */ +#define TWIGOFFMAX(off, max, t, b) \ + do { \ + (off) = twigoff((t), (b)); \ + (max) = bitmap_weight((t)->branch.bitmap); \ + } while (0) + +/*! \brief Simple string comparator. */ +static int key_cmp(const uint8_t* k1, uint32_t k1_len, const uint8_t* k2, uint32_t k2_len) +{ + int ret = memcmp(k1, k2, MIN(k1_len, k2_len)); + if (ret != 0) { + return ret; + } + + /* Key string is equal, compare lengths. */ + if (k1_len == k2_len) { + return 0; + } else if (k1_len < k2_len) { + return -1; + } else { + return 1; + } +} + +trie_t* trie_create(knot_mm_t* mm) +{ + assert_portability(); + trie_t* trie = mm_alloc(mm, sizeof(trie_t)); + if (trie != NULL) { + empty_root(&trie->root); + trie->weight = 0; + if (mm != NULL) + trie->mm = *mm; + else + mm_ctx_init(&trie->mm); + } + return trie; +} + +/*! \brief Free anything under the trie node, except for the passed pointer itself. */ +static void clear_trie(node_t* trie, knot_mm_t* mm) +{ + if (!isbranch(trie)) { + mm_free(mm, trie->leaf.key); + } else { + branch_t* b = &trie->branch; + int len = bitmap_weight(b->bitmap); + int i; + for (i = 0; i < len; ++i) + clear_trie(b->twigs + i, mm); + mm_free(mm, b->twigs); + } +} + +void trie_free(trie_t* tbl) +{ + if (tbl == NULL) + return; + if (tbl->weight) + clear_trie(&tbl->root, &tbl->mm); + mm_free(&tbl->mm, tbl); +} + +void trie_clear(trie_t* tbl) +{ + assert(tbl); + if (!tbl->weight) + return; + clear_trie(&tbl->root, &tbl->mm); + empty_root(&tbl->root); + tbl->weight = 0; +} + +size_t trie_weight(const trie_t* tbl) +{ + assert(tbl); + return tbl->weight; +} + +struct found { + leaf_t* l; /**< the found leaf (NULL if not found) */ + branch_t* p; /**< the leaf's parent (if exists) */ + bitmap_t b; /**< bit-mask with a single bit marking l under p */ +}; +/** Search trie for an item with the given key (equality only). */ +static struct found find_equal(trie_t* tbl, const uint8_t* key, uint32_t len) +{ + assert(tbl); + struct found ret0; + memset(&ret0, 0, sizeof(ret0)); + if (!tbl->weight) + return ret0; + /* Current node and parent while descending (returned values basically). */ + node_t* t = &tbl->root; + branch_t* p = NULL; + bitmap_t b = 0; + while (isbranch(t)) { + __builtin_prefetch(t->branch.twigs); + b = twigbit(t, key, len); + if (!hastwig(t, b)) + return ret0; + p = &t->branch; + t = twig(t, twigoff(t, b)); + } + if (key_cmp(key, len, t->leaf.key->chars, t->leaf.key->len) != 0) + return ret0; + return (struct found) { + .l = &t->leaf, + .p = p, + .b = b, + }; +} +/** Find item with the first key (lexicographical order). */ +static struct found find_first(trie_t* tbl) +{ + assert(tbl); + if (!tbl->weight) { + struct found ret0; + memset(&ret0, 0, sizeof(ret0)); + return ret0; + } + /* Current node and parent while descending (returned values basically). */ + node_t* t = &tbl->root; + branch_t* p = NULL; + while (isbranch(t)) { + p = &t->branch; + t = &p->twigs[0]; + } + return (struct found) { + .l = &t->leaf, + .p = p, + .b = p ? bitmap_lowest_bit(p->bitmap) : 0, + }; +} + +trie_val_t* trie_get_try(trie_t* tbl, const uint8_t* key, uint32_t len) +{ + struct found found = find_equal(tbl, key, len); + return found.l ? &found.l->val : NULL; +} + +trie_val_t* trie_get_first(trie_t* tbl, uint8_t** key, uint32_t* len) +{ + struct found found = find_first(tbl); + if (!found.l) + return NULL; + if (key) + *key = found.l->key->chars; + if (len) + *len = found.l->key->len; + return &found.l->val; +} + +/*! + * \brief Stack of nodes, storing a path down a trie. + * + * The structure also serves directly as the public trie_it_t type, + * in which case it always points to the current leaf, unless we've finished + * (i.e. it->len == 0). + */ +typedef struct trie_it { + node_t** stack; /*!< The stack; malloc is used directly instead of mm. */ + uint32_t len; /*!< Current length of the stack. */ + uint32_t alen; /*!< Allocated/available length of the stack. */ + /*! \brief Initial storage for \a stack; it should fit in many use cases. */ + node_t* stack_init[60]; +} nstack_t; + +/*! \brief Create a node stack containing just the root (or empty). */ +static void ns_init(nstack_t* ns, trie_t* tbl) +{ + assert(tbl); + ns->stack = ns->stack_init; + ns->alen = sizeof(ns->stack_init) / sizeof(ns->stack_init[0]); + if (tbl->weight) { + ns->len = 1; + ns->stack[0] = &tbl->root; + } else { + ns->len = 0; + } +} + +/*! \brief Free inside of the stack, i.e. not the passed pointer itself. */ +static void ns_cleanup(nstack_t* ns) +{ + assert(ns && ns->stack); + if (likely(ns->stack == ns->stack_init)) + return; + free(ns->stack); +#ifndef NDEBUG + ns->stack = NULL; + ns->alen = 0; +#endif +} + +/*! \brief Allocate more space for the stack. */ +static int ns_longer_alloc(nstack_t* ns) +{ + ns->alen *= 2; + size_t new_size = sizeof(nstack_t) + ns->alen * sizeof(node_t*); + node_t** st; + if (ns->stack == ns->stack_init) { + st = malloc(new_size); + if (st != NULL) + memcpy(st, ns->stack, ns->len * sizeof(node_t*)); + } else { + st = realloc(ns->stack, new_size); + } + if (st == NULL) + return KNOT_ENOMEM; + ns->stack = st; + return KNOT_EOK; +} + +/*! \brief Ensure the node stack can be extended by one. */ +static inline int ns_longer(nstack_t* ns) +{ + // get a longer stack if needed + if (likely(ns->len < ns->alen)) + return KNOT_EOK; + return ns_longer_alloc(ns); // hand-split the part suitable for inlining +} + +/*! + * \brief Find the "branching point" as if searching for a key. + * + * The whole path to the point is kept on the passed stack; + * always at least the root will remain on the top of it. + * Beware: the precise semantics of this function is rather tricky. + * The top of the stack will contain: the corresponding leaf if exact match is found; + * or the immediate node below a branching-point-on-edge or the branching-point itself. + * + * \param info Set position of the point of first mismatch (in index and flags). + * \param first Set the value of the first non-matching character (from trie), + * optionally; end-of-string character has value -256 (that's why it's int). + * Note: the character is converted to *unsigned* char (i.e. 0..255), + * as that's the ordering used in the trie. + * + * \return KNOT_EOK or KNOT_ENOMEM. + */ +static int ns_find_branch(nstack_t* ns, const uint8_t* key, uint32_t len, + branch_t* info, int* first) +{ + assert(ns && ns->len && info); + // First find some leaf with longest matching prefix. + while (isbranch(ns->stack[ns->len - 1])) { + ERR_RETURN(ns_longer(ns)); + node_t* t = ns->stack[ns->len - 1]; + __builtin_prefetch(t->branch.twigs); + bitmap_t b = twigbit(t, key, len); + // Even if our key is missing from this branch we need to + // keep iterating down to a leaf. It doesn't matter which + // twig we choose since the keys are all the same up to this + // index. Note that blindly using twigoff(t, b) can cause + // an out-of-bounds index if it equals twigmax(t). + uint i = hastwig(t, b) ? twigoff(t, b) : 0; + ns->stack[ns->len++] = twig(t, i); + } + tkey_t* lkey = ns->stack[ns->len - 1]->leaf.key; + // Find index of the first char that differs. + uint32_t index = 0; + while (index < MIN(len, lkey->len)) { + if (key[index] != lkey->chars[index]) + break; + else + ++index; + } + info->index = index; + if (first) + *first = lkey->len > index ? (unsigned char)lkey->chars[index] : -256; + // Find flags: which half-byte has matched. + uint flags; + if (index == len && len == lkey->len) { // found equivalent key + info->flags = flags = 0; + goto success; + } + if (likely(index < MIN(len, lkey->len))) { + byte k2 = (byte)lkey->chars[index]; + byte k1 = (byte)key[index]; + flags = ((k1 ^ k2) & 0xf0) ? 1 : 2; + } else { // one is prefix of another + flags = 1; + } + info->flags = flags; + // now go up the trie from the current leaf + branch_t* t; + do { + if (unlikely(ns->len == 1)) + goto success; // only the root stays on the stack + t = (branch_t*)ns->stack[ns->len - 2]; + if (t->index < index || (t->index == index && t->flags < flags)) + goto success; + --ns->len; + } while (true); +success: +#ifndef NDEBUG // invariants on successful return + assert(ns->len); + if (isbranch(ns->stack[ns->len - 1])) { + t = &ns->stack[ns->len - 1]->branch; + assert(t->index > index || (t->index == index && t->flags >= flags)); + } + if (ns->len > 1) { + t = &ns->stack[ns->len - 2]->branch; + assert(t->index < index || (t->index == index && (t->flags < flags || (t->flags == 1 && flags == 0)))); + } +#endif + return KNOT_EOK; +} + +/*! + * \brief Advance the node stack to the last leaf in the subtree. + * + * \return KNOT_EOK or KNOT_ENOMEM. + */ +static int ns_last_leaf(nstack_t* ns) +{ + assert(ns); + do { + ERR_RETURN(ns_longer(ns)); + node_t* t = ns->stack[ns->len - 1]; + if (!isbranch(t)) + return KNOT_EOK; + int lasti = bitmap_weight(t->branch.bitmap) - 1; + assert(lasti >= 0); + ns->stack[ns->len++] = twig(t, lasti); + } while (true); +} + +/*! + * \brief Advance the node stack to the first leaf in the subtree. + * + * \return KNOT_EOK or KNOT_ENOMEM. + */ +static int ns_first_leaf(nstack_t* ns) +{ + assert(ns && ns->len); + do { + ERR_RETURN(ns_longer(ns)); + node_t* t = ns->stack[ns->len - 1]; + if (!isbranch(t)) + return KNOT_EOK; + ns->stack[ns->len++] = twig(t, 0); + } while (true); +} + +/*! + * \brief Advance the node stack to the leaf that is previous to the current node. + * + * \note Prefix leaf under the current node DOES count (if present; perhaps questionable). + * \return KNOT_EOK on success, KNOT_ENOENT on not-found, or possibly KNOT_ENOMEM. + */ +static int ns_prev_leaf(nstack_t* ns) +{ + assert(ns && ns->len > 0); + + node_t* t = ns->stack[ns->len - 1]; + if (hastwig(t, 1 << 0)) { // the prefix leaf + t = twig(t, 0); + ERR_RETURN(ns_longer(ns)); + ns->stack[ns->len++] = t; + return KNOT_EOK; + } + + do { + if (ns->len < 2) + return KNOT_ENOENT; // root without empty key has no previous leaf + t = ns->stack[ns->len - 1]; + node_t* p = ns->stack[ns->len - 2]; + int pindex = t - p->branch.twigs; // index in parent via pointer arithmetic + assert(pindex >= 0 && pindex <= 16); + if (pindex > 0) { // t isn't the first child -> go down the previous one + ns->stack[ns->len - 1] = twig(p, pindex - 1); + return ns_last_leaf(ns); + } + // we've got to go up again + --ns->len; + } while (true); +} + +/*! + * \brief Advance the node stack to the leaf that is successor to the current node. + * + * \note Prefix leaf or anything else under the current node DOES count. + * \return KNOT_EOK on success, KNOT_ENOENT on not-found, or possibly KNOT_ENOMEM. + */ +static int ns_next_leaf(nstack_t* ns) +{ + assert(ns && ns->len > 0); + + node_t* t = ns->stack[ns->len - 1]; + if (isbranch(t)) + return ns_first_leaf(ns); + do { + if (ns->len < 2) + return KNOT_ENOENT; // not found, as no more parent is available + t = ns->stack[ns->len - 1]; + node_t* p = ns->stack[ns->len - 2]; + int pindex = t - p->branch.twigs; // index in parent via pointer arithmetic + assert(pindex >= 0 && pindex <= 16); + int pcount = bitmap_weight(p->branch.bitmap); + if (pindex + 1 < pcount) { // t isn't the last child -> go down the next one + ns->stack[ns->len - 1] = twig(p, pindex + 1); + return ns_first_leaf(ns); + } + // we've got to go up again + --ns->len; + } while (true); +} + +int trie_get_leq(trie_t* tbl, const uint8_t* key, uint32_t len, trie_val_t** val) +{ + assert(tbl && val); + *val = NULL; // so on failure we can just return; + if (tbl->weight == 0) + return KNOT_ENOENT; + { // Intentionally un-indented; until end of function, to bound cleanup attr. + // First find a key with longest-matching prefix + __attribute__((cleanup(ns_cleanup))) + nstack_t ns_local; + ns_init(&ns_local, tbl); + nstack_t* ns = &ns_local; + branch_t bp; + int un_leaf; // first unmatched character in the leaf + ERR_RETURN(ns_find_branch(ns, key, len, &bp, &un_leaf)); + int un_key = bp.index < len ? (unsigned char)key[bp.index] : -256; + node_t* t = ns->stack[ns->len - 1]; + if (bp.flags == 0) { // found exact match + *val = &t->leaf.val; + return KNOT_EOK; + } + // Get t: the last node on matching path + if (isbranch(t) && t->branch.index == bp.index && t->branch.flags == bp.flags) { + // t is OK + } else { + // the top of the stack was the first unmatched node -> step up + if (ns->len == 1) { + // root was unmatched already + if (un_key < un_leaf) + return KNOT_ENOENT; + ERR_RETURN(ns_last_leaf(ns)); + goto success; + } + --ns->len; + t = ns->stack[ns->len - 1]; + } + // Now we re-do the first "non-matching" step in the trie + // but try the previous child if key was less (it may not exist) + bitmap_t b = twigbit(t, key, len); + int i = hastwig(t, b) + ? twigoff(t, b) - (un_key < un_leaf) + : twigoff(t, b) - 1 /*twigoff returns successor when !hastwig*/; + if (i >= 0) { + ERR_RETURN(ns_longer(ns)); + ns->stack[ns->len++] = twig(t, i); + ERR_RETURN(ns_last_leaf(ns)); + } else { + ERR_RETURN(ns_prev_leaf(ns)); + } + success: + assert(!isbranch(ns->stack[ns->len - 1])); + *val = &ns->stack[ns->len - 1]->leaf.val; + return 1; + } +} + +/*! \brief Initialize a new leaf, copying the key, and returning failure code. */ +static int mk_leaf(node_t* leaf, const uint8_t* key, uint32_t len, knot_mm_t* mm) +{ + tkey_t* k = mm_alloc(mm, sizeof(tkey_t) + len); +#if FLAGS_HACK + assert(((uintptr_t)k) % 4 == 0); // we need an aligned pointer +#endif + if (unlikely(!k)) + return KNOT_ENOMEM; + k->len = len; + memcpy(k->chars, key, len); + leaf->leaf = (leaf_t) + { +#if !FLAGS_HACK + .flags = 0, +#endif + .val = NULL, + .key = k + }; + return KNOT_EOK; +} + +trie_val_t* trie_get_ins(trie_t* tbl, const uint8_t* key, uint32_t len) +{ + assert(tbl); + // First leaf in an empty tbl? + if (unlikely(!tbl->weight)) { + if (unlikely(mk_leaf(&tbl->root, key, len, &tbl->mm))) + return NULL; + ++tbl->weight; + return &tbl->root.leaf.val; + } + { // Intentionally un-indented; until end of function, to bound cleanup attr. + // Find the branching-point + __attribute__((cleanup(ns_cleanup))) + nstack_t ns_local; + ns_init(&ns_local, tbl); + nstack_t* ns = &ns_local; + branch_t bp; // branch-point: index and flags signifying the longest common prefix + int k2; // the first unmatched character in the leaf + if (unlikely(ns_find_branch(ns, key, len, &bp, &k2))) + return NULL; + node_t* t = ns->stack[ns->len - 1]; + if (bp.flags == 0) // the same key was already present + return &t->leaf.val; + node_t leaf; + if (unlikely(mk_leaf(&leaf, key, len, &tbl->mm))) + return NULL; + + if (isbranch(t) && bp.index == t->branch.index && bp.flags == t->branch.flags) { + // The node t needs a new leaf child. + bitmap_t b1 = twigbit(t, key, len); + assert(!hastwig(t, b1)); + uint s, m; + TWIGOFFMAX(s, m, t, b1); // new child position and original child count + node_t* twigs = mm_realloc(&tbl->mm, t->branch.twigs, + sizeof(node_t) * (m + 1), sizeof(node_t) * m); + if (unlikely(!twigs)) + goto err_leaf; + memmove(twigs + s + 1, twigs + s, sizeof(node_t) * (m - s)); + twigs[s] = leaf; + t->branch.twigs = twigs; + t->branch.bitmap |= b1; + ++tbl->weight; + return &twigs[s].leaf.val; + } else { +// We need to insert a new binary branch with leaf at *t. +// Note: it works the same for the case where we insert above root t. +#ifndef NDEBUG + if (ns->len > 1) { + node_t* pt = ns->stack[ns->len - 2]; + assert(hastwig(pt, twigbit(pt, key, len))); + } +#endif + node_t* twigs = mm_alloc(&tbl->mm, sizeof(node_t) * 2); + if (unlikely(!twigs)) + goto err_leaf; + node_t t2 = *t; // Save before overwriting t. + t->branch.flags = bp.flags; + t->branch.index = bp.index; + t->branch.twigs = twigs; + bitmap_t b1 = twigbit(t, key, len); + bitmap_t b2 = unlikely(k2 == -256) ? (1 << 0) : nibbit(k2, bp.flags); + t->branch.bitmap = b1 | b2; + *twig(t, twigoff(t, b1)) = leaf; + *twig(t, twigoff(t, b2)) = t2; + ++tbl->weight; + return &twig(t, twigoff(t, b1))->leaf.val; + }; + err_leaf: + mm_free(&tbl->mm, leaf.leaf.key); + return NULL; + } +} + +/*! \brief Apply a function to every trie_val_t*, in order; a recursive solution. */ +static int apply_trie(node_t* t, int (*f)(trie_val_t*, void*), void* d) +{ + assert(t); + if (!isbranch(t)) + return f(&t->leaf.val, d); + int child_count = bitmap_weight(t->branch.bitmap); + int i; + for (i = 0; i < child_count; ++i) + ERR_RETURN(apply_trie(twig(t, i), f, d)); + return KNOT_EOK; +} + +int trie_apply(trie_t* tbl, int (*f)(trie_val_t*, void*), void* d) +{ + assert(tbl && f); + if (!tbl->weight) + return KNOT_EOK; + return apply_trie(&tbl->root, f, d); +} + +/* These are all thin wrappers around static Tns* functions. */ +trie_it_t* trie_it_begin(trie_t* tbl) +{ + assert(tbl); + trie_it_t* it = malloc(sizeof(nstack_t)); + if (!it) + return NULL; + ns_init(it, tbl); + if (it->len == 0) // empty tbl + return it; + if (ns_first_leaf(it)) { + ns_cleanup(it); + free(it); + return NULL; + } + return it; +} + +void trie_it_next(trie_it_t* it) +{ + assert(it && it->len); + if (ns_next_leaf(it) != KNOT_EOK) + it->len = 0; +} + +bool trie_it_finished(trie_it_t* it) +{ + assert(it); + return it->len == 0; +} + +void trie_it_free(trie_it_t* it) +{ + if (!it) + return; + ns_cleanup(it); + free(it); +} + +const uint8_t* trie_it_key(trie_it_t* it, size_t* len) +{ + assert(it && it->len); + node_t* t = it->stack[it->len - 1]; + assert(!isbranch(t)); + tkey_t* key = t->leaf.key; + if (len) + *len = key->len; + return key->chars; +} + +trie_val_t* trie_it_val(trie_it_t* it) +{ + assert(it && it->len); + node_t* t = it->stack[it->len - 1]; + assert(!isbranch(t)); + return &t->leaf.val; +} diff --git a/include/dnsjit/lib/trie.h b/include/dnsjit/lib/trie.h new file mode 100644 index 0000000..b8b8b78 --- /dev/null +++ b/include/dnsjit/lib/trie.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2017-2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <errno.h> +#include <stdbool.h> +#include <stdint.h> + +#ifndef __dnsjit_contrib_trie_h +#define __dnsjit_contrib_trie_h + +#include <dnsjit/lib/trie.hh> + +#ifndef likely +/*! \brief Optimize for x to be true value. */ +#define likely(x) __builtin_expect((x), 1) +#endif + +#ifndef unlikely +/*! \brief Optimize for x to be false value. */ +#define unlikely(x) __builtin_expect((x), 0) +#endif + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) /** Minimum of two numbers **/ + +#endif diff --git a/include/dnsjit/lib/trie.hh b/include/dnsjit/lib/trie.hh new file mode 100644 index 0000000..60c8f8a --- /dev/null +++ b/include/dnsjit/lib/trie.hh @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2017-2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* Memory allocation function prototypes. */ +typedef void* (*knot_mm_alloc_t)(void* ctx, size_t len); +typedef void (*knot_mm_free_t)(void* p); + +/*! \brief Memory allocation context. */ +typedef struct knot_mm { + void* ctx; /* \note Must be first */ + knot_mm_alloc_t alloc; + knot_mm_free_t free; +} knot_mm_t; + +/*! + * \brief Native API of QP-tries: + * + * - keys are uint8_t strings, not necessarily zero-terminated, + * the structure copies the contents of the passed keys + * - values are void* pointers, typically you get an ephemeral pointer to it + * - key lengths are limited by 2^32-1 ATM + */ + +/*! \brief Element value. */ +typedef void* trie_val_t; + +/*! \brief Opaque structure holding a QP-trie. */ +typedef struct trie trie_t; + +/*! \brief Opaque type for holding a QP-trie iterator. */ +typedef struct trie_it trie_it_t; + +/*! \brief Create a trie instance. Pass NULL to use malloc+free. */ +trie_t* trie_create(knot_mm_t* mm); + +/*! \brief Free a trie instance. */ +void trie_free(trie_t* tbl); + +/*! \brief Clear a trie instance (make it empty). */ +void trie_clear(trie_t* tbl); + +/*! \brief Return the number of keys in the trie. */ +size_t trie_weight(const trie_t* tbl); + +/*! \brief Search the trie, returning NULL on failure. */ +trie_val_t* trie_get_try(trie_t* tbl, const uint8_t* key, uint32_t len); + +/*! + * \brief Return pointer to the minimum. Optionally with key and its length. */ +trie_val_t* trie_get_first(trie_t* tbl, uint8_t** key, uint32_t* len); + +/*! \brief Search the trie, inserting NULL trie_val_t on failure. */ +trie_val_t* trie_get_ins(trie_t* tbl, const uint8_t* key, uint32_t len); + +/*! + * \brief Search for less-or-equal element. + * + * \param tbl Trie. + * \param key Searched key. + * \param len Key length. + * \param val Must be valid; it will be set to NULL if not found or errored. + * \return KNOT_EOK for exact match, 1 for previous, KNOT_ENOENT for not-found, + * or KNOT_E*. + */ +int trie_get_leq(trie_t* tbl, const uint8_t* key, uint32_t len, trie_val_t** val); + +/*! + * \brief Apply a function to every trie_val_t, in order. + * + * \param d Parameter passed as the second argument to f(). + * \return First nonzero from f() or zero (i.e. KNOT_EOK). + */ +int trie_apply(trie_t* tbl, int (*f)(trie_val_t*, void*), void* d); + +/*! \brief Create a new iterator pointing to the first element (if any). */ +trie_it_t* trie_it_begin(trie_t* tbl); + +/*! + * \brief Advance the iterator to the next element. + * + * Iteration is in ascending lexicographical order. + * In particular, the empty string would be considered as the very first. + * + * \note You may not use this function if the trie's key-set has been modified + * during the lifetime of the iterator (modifying values only is OK). + */ +void trie_it_next(trie_it_t* it); + +/*! \brief Test if the iterator has gone past the last element. */ +bool trie_it_finished(trie_it_t* it); + +/*! \brief Free any resources of the iterator. It's OK to call it on NULL. */ +void trie_it_free(trie_it_t* it); + +/*! + * \brief Return pointer to the key of the current element. + * + * \note The optional len is uint32_t internally but size_t is better for our usage, + * as it is without an additional type conversion. + */ +const uint8_t* trie_it_key(trie_it_t* it, size_t* len); + +/*! \brief Return pointer to the value of the current element (writable). */ +trie_val_t* trie_it_val(trie_it_t* it); diff --git a/include/dnsjit/lib/trie.lua b/include/dnsjit/lib/trie.lua new file mode 100644 index 0000000..f7fee03 --- /dev/null +++ b/include/dnsjit/lib/trie.lua @@ -0,0 +1,172 @@ +-- 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/>. + +-- dnsjit.lib.trie +-- Prefix-tree data structure which addresses values by strings or byte arrays +-- .SS Binary-key trie with integer values +-- local trie = require("dnsjit.lib.trie").new("uint64_t", true, 4) +-- -- assume we have a bunch of dnsjit.core.object.ip packets to process +-- for _, pkt in pairs(pkts) do +-- local node = trie:get_ins(pkt.src) +-- local value = node:get() -- new nodes' values are initialized to 0 +-- node:set(value + 1) +-- end +-- -- iterate over unique IPs and print number of packets received from each +-- local iter = trie:iter() +-- local node = iter:node() +-- local p = require("dnsjit.lib.ip") +-- while node ~= nil do +-- local ip_bytes = node:key() +-- local npkts = tonumber(node:get()) +-- print(ip.tostring(ip_bytes).." sent "..npkts.." packets") +-- iter:next() +-- node = iter:node() +-- end +-- .SS String-key trie with cdata values +-- local trie = require("dnsjit.lib.trie").new("core_object_t*") +-- local obj1 -- assume this contains cdata of type core_object_t* +-- local node = trie:get_ins("obj1") +-- node:set(obj1) +-- node = trie:get_try("obj1") +-- assert(node:get() == obj1) +-- +-- Prefix-tree data structure that stores values indexed by strings or byte +-- arrays, such as IP addresses. +-- Values of size up to sizeof(size_t) can be stored directly, otherwise +-- a pointer must be used. +module(...,package.seeall) + +require("dnsjit.lib.trie_h") +local ffi = require("ffi") +local C = ffi.C +local log = require("dnsjit.core.log") +local module_log = log.new("lib.trie") +local TrieNode = require("dnsjit.lib.trie.node") +local TrieIter = require("dnsjit.lib.trie.iter") + +Trie = {} + +-- Create a new Trie that stores +-- .I ctype +-- values as data. +-- By default, keys are handled as strings. +-- To use trie with byte arrays, set +-- .I binary +-- to true. +-- Optionally, +-- .I keylen +-- may be specified as a default keylen for binary keys. +-- For string keys, their string length is used by default. +function Trie.new(ctype, binary, keylen) + if ctype == nil then + module_log:fatal("missing value ctype") + end + if ffi.sizeof(ctype) > ffi.sizeof("void *") then + module_log:fatal("data type exceeds max size, use a pointer instead") + end + if keylen ~= nil and not binary then + module_log:warning("setting keylen has no effect for string-key tries") + end + + local self = setmetatable({ + obj = C.trie_create(nil), + _binary = binary, + _keylen = keylen, + _ctype = ctype, + _log = log.new("lib.trie", module_log), + }, { __index = Trie }) + + ffi.gc(self.obj, C.trie_free) + + return self +end + +function Trie:_get_keylen(key, keylen) + if keylen ~= nil then + if type(keylen) == "number" then + return keylen + else + self._log:fatal("keylen must be numeric") + end + end + if not self._binary then + if type(key) == "string" then + return string.len(key) + else + self._log:fatal("key must be string when using trie with non-binary keys") + end + end + if not self._keylen or type(self._keylen) ~= "number" then + self._log:fatal("default keylen not set or invalid") + end + return self._keylen +end + +-- Return the Log object to control logging of this instance or module. +function Trie:log() + if self == nil then + return module_log + end + return self._log +end + +-- Clear the trie instance (make it empty). +function Trie:clear() + C.trie_clear(self.obj) +end + +-- Return the number of keys in the trie. +function Trie:weight() + return tonumber(C.trie_weight(self.obj)) +end + +-- Search the trie and return nil of failure. +function Trie:get_try(key, keylen) + keylen = self:_get_keylen(key, keylen) + local val = C.trie_get_try(self.obj, key, keylen) + if val == nil then return nil end + val = ffi.cast("trie_val_t *", val) + return TrieNode.new(self, val, key, keylen) +end + +-- Search the trie and insert an empty node (with value set to 0) on failure. +function Trie:get_ins(key, keylen) + keylen = self:_get_keylen(key, keylen) + local val = C.trie_get_ins(self.obj, key, keylen) + val = ffi.cast("trie_val_t *", val) + return TrieNode.new(self, val, key, keylen) +end + +-- Return the first node (minimum). +function Trie:get_first() + local key_ptr = ffi.new("uint8_t *[1]") + local keylen_ptr = ffi.new("uint32_t[1]") + local val = C.trie_get_first(self.obj, key_ptr, keylen_ptr) + local keylen = tonumber(keylen_ptr[0]) + key = key_ptr[0] + return TrieNode.new(self, val, key, keylen) +end + +-- Return a trie iterator. +-- It is only valid as long as the key-set remains unchanged. +function Trie:iter() + return TrieIter.new(self) +end + +-- dnsjit.lib.trie.node (3), dnsjit.lib.trie.iter (3) +return Trie diff --git a/include/dnsjit/lib/trie/iter.lua b/include/dnsjit/lib/trie/iter.lua new file mode 100644 index 0000000..520cc7b --- /dev/null +++ b/include/dnsjit/lib/trie/iter.lua @@ -0,0 +1,93 @@ +-- 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/>. + +-- dnsjit.lib.trie.iter +-- Iterator of the trie. +-- .SS Iterate over all trie's key-value pairs +-- local trie = require("dnsjit.lib.trie").new("uint64_t") +-- local iter = trie:iter() +-- local node = iter:node() +-- while node ~= nil do +-- local key = node:key() +-- local value = tonumber(node:get()) +-- print(key..": "..value) +-- iter:next() +-- node = iter:node() +-- end +-- +-- Beware that iterator is only valid as long as the trie's key-set +-- remains unchanged. +module(...,package.seeall) + +require("dnsjit.lib.trie_h") +local ffi = require("ffi") +local C = ffi.C +local log = require("dnsjit.core.log") +local module_log = log.new("lib.trie.iter") +local TrieNode = require("dnsjit.lib.trie.node") + +TrieIter = {} + +-- Create a new iterator pointing to the first element (if any). +function TrieIter.new(trie) + local self = setmetatable({ + obj = C.trie_it_begin(trie.obj), + _trie = trie, + _log = log.new("lib.trie.iter", module_log), + }, { __index = TrieIter }) + + ffi.gc(self.obj, C.trie_it_free) + + return self +end + +-- Return the Log object to control logging of this instance or module. +function TrieIter:log() + if self == nil then + return module_log + end + return self._log +end + +-- Return the node pointer to by the iterator. +-- Returns nil when iterator has gone past the last element. +function TrieIter:node() + if C.trie_it_finished(self.obj) then + return nil + end + + local keylen_ptr = ffi.new("size_t[1]") + local key = C.trie_it_key(self.obj, keylen_ptr) + local keylen = tonumber(keylen_ptr[0]) + + local val = C.trie_it_val(self.obj) + return TrieNode.new(self._trie, val, key, keylen) +end + +-- Advance the iterator to the next element. +-- +-- Iteration is in ascending lexicographical order. +-- Empty string would be considered as the very first. +-- +-- You may not use this function if the trie's key-set has been modified during the lifetime of the iterator (modifying only values is OK). +function TrieIter:next() + C.trie_it_next(self.obj) +end + +-- dnsjit.lib.trie (3), dnsjit.lib.trie.node (3) +return TrieIter diff --git a/include/dnsjit/lib/trie/node.lua b/include/dnsjit/lib/trie/node.lua new file mode 100644 index 0000000..7fdc39d --- /dev/null +++ b/include/dnsjit/lib/trie/node.lua @@ -0,0 +1,84 @@ +-- 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/>. + +-- dnsjit.lib.trie.node +-- Node of trie, which contains the value and key. +-- .SS Set a node's value. +-- node:set(42) +-- .SS Get a node's key and value. +-- local key = node:key() +-- local val = node:get() +module(...,package.seeall) + +require("dnsjit.lib.trie_h") +local ffi = require("ffi") +local C = ffi.C +local log = require("dnsjit.core.log") +local module_log = log.new("lib.trie.node") + +TrieNode = {} + +-- Create a new node object. +function TrieNode.new(trie, val, key, keylen) + local self = setmetatable({ + _key = key, + _keylen = keylen, + _val = val, + _trie = trie, + _log = log.new("lib.trie.node", module_log), + }, { __index = TrieNode }) + + return self +end + +-- Return key and keylen of this node. +-- Key is string or byte array if the trie's +-- .I +-- binary +-- setting is set to true. +function TrieNode:key() + if self._trie._binary then + local key = ffi.new("uint8_t[?]", self._keylen) + ffi.copy(key, self._key, self._keylen) + return key, self._keylen + else + return ffi.string(self._key, self._keylen), self._keylen + end +end + +-- Return the Log object to control logging of this instance or module. +function TrieNode:log() + if self == nil then + return module_log + end + return self._log +end + +-- Get the value of this node. +function TrieNode:get() + return ffi.cast(self._trie._ctype, self._val[0]) +end + +-- Set the value of this node. +function TrieNode:set(value) + value = ffi.cast('void *', value) + self._val[0] = value +end + +-- dnsjit.lib.trie (3) +return TrieNode diff --git a/include/dnsjit/output.lua b/include/dnsjit/output.lua new file mode 100644 index 0000000..43f90c3 --- /dev/null +++ b/include/dnsjit/output.lua @@ -0,0 +1,33 @@ +-- 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.output +-- Output modules for dnsjit +-- +-- Output modules used to display DNS message, export to various formats or +-- replay them against other targets. +module(...,package.seeall) + +-- 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) +return diff --git a/include/dnsjit/output/dnscli.c b/include/dnsjit/output/dnscli.c new file mode 100644 index 0000000..f7c5b5e --- /dev/null +++ b/include/dnsjit/output/dnscli.c @@ -0,0 +1,888 @@ +/* + * 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/dnscli.h" +#include "core/assert.h" +#include "core/object/dns.h" +#include "core/object/payload.h" +#include "core/object/udp.h" +#include "core/object/tcp.h" + +#include <netdb.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.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 + +static inline uint16_t _need16(const void* ptr) +{ + uint16_t v; + memcpy(&v, ptr, sizeof(v)); + return be16toh(v); +} + +static core_log_t _log = LOG_T_INIT("output.dnscli"); +static output_dnscli_t _defaults = { + LOG_T_INIT_OBJ("output.dnscli"), + OUTPUT_DNSCLI_MODE_NONE, + 0, 0, 0, -1, 0, 0, + { 0, 0, 0 }, 0, + { 0 }, 0, + { 0 }, CORE_OBJECT_PAYLOAD_INIT(0), 0, 0, 0, 0, 0, + { 0, 0 }, + 0, 0 +}; + +core_log_t* output_dnscli_log() +{ + return &_log; +} + +void output_dnscli_init(output_dnscli_t* self, output_dnscli_mode_t mode) +{ + mlassert_self(); + + *self = _defaults; + self->mode = mode; + self->pkt.payload = self->recvbuf; + + switch (mode & OUTPUT_DNSCLI_MODE_MODES) { + case OUTPUT_DNSCLI_MODE_UDP: + case OUTPUT_DNSCLI_MODE_TCP: + break; + case OUTPUT_DNSCLI_MODE_TLS: { + int err; + if ((err = gnutls_certificate_allocate_credentials(&self->cred)) != GNUTLS_E_SUCCESS) { + lfatal("gnutls_certificate_allocate_credentials() error: %s", gnutls_strerror(err)); + } else if ((err = gnutls_init(&self->session, GNUTLS_CLIENT | ((mode & OUTPUT_DNSCLI_MODE_NONBLOCKING) ? GNUTLS_NONBLOCK : 0))) != GNUTLS_E_SUCCESS) { + lfatal("gnutls_init() error: %s", gnutls_strerror(err)); + } else if ((err = gnutls_set_default_priority(self->session)) != GNUTLS_E_SUCCESS) { + lfatal("gnutls_set_default_priority() error: %s", gnutls_strerror(err)); + } else if ((err = gnutls_credentials_set(self->session, GNUTLS_CRD_CERTIFICATE, self->cred)) != GNUTLS_E_SUCCESS) { + lfatal("gnutls_credentials_set() error: %s", gnutls_strerror(err)); + } + + gnutls_handshake_set_timeout(self->session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); + break; + } + default: + lfatal("Invalid mode %x", mode); + } +} + +void output_dnscli_destroy(output_dnscli_t* self) +{ + mlassert_self(); + + if (self->fd > -1) { + switch (self->mode & OUTPUT_DNSCLI_MODE_MODES) { + case OUTPUT_DNSCLI_MODE_UDP: + case OUTPUT_DNSCLI_MODE_TCP: + shutdown(self->fd, SHUT_RDWR); + close(self->fd); + break; + case OUTPUT_DNSCLI_MODE_TLS: + if (self->session) { + gnutls_bye(self->session, GNUTLS_SHUT_RDWR); + gnutls_deinit(self->session); + } + shutdown(self->fd, SHUT_RDWR); + close(self->fd); + if (self->cred) { + gnutls_certificate_free_credentials(self->cred); + } + break; + default: + break; + } + } +} + +int output_dnscli_connect(output_dnscli_t* self, const char* host, const char* port) +{ + struct addrinfo* addr; + int err; + mlassert_self(); + lassert(host, "host is nil"); + lassert(port, "port is nil"); + + if (self->fd > -1) { + lfatal("already connected"); + } + + if ((err = getaddrinfo(host, port, 0, &addr))) { + lcritical("getaddrinfo(%s, %s) error %s", host, port, gai_strerror(err)); + return -1; + } + if (!addr) { + lcritical("getaddrinfo failed, no address returned"); + return -1; + } + + switch (self->mode & OUTPUT_DNSCLI_MODE_MODES) { + case OUTPUT_DNSCLI_MODE_UDP: + memcpy(&self->addr, addr->ai_addr, addr->ai_addrlen); + self->addr_len = addr->ai_addrlen; + freeaddrinfo(addr); + + if ((self->fd = socket(((struct sockaddr*)&self->addr)->sa_family, SOCK_DGRAM, 0)) < 0) { + lcritical("socket() error %s", core_log_errstr(errno)); + return -2; + } + break; + case OUTPUT_DNSCLI_MODE_TCP: + case OUTPUT_DNSCLI_MODE_TLS: + if ((self->fd = socket(addr->ai_addr->sa_family, SOCK_STREAM, 0)) < 0) { + lcritical("socket() error %s", core_log_errstr(errno)); + freeaddrinfo(addr); + return -2; + } + + if (connect(self->fd, addr->ai_addr, addr->ai_addrlen)) { + lcritical("connect() error %s", core_log_errstr(errno)); + freeaddrinfo(addr); + return -2; + } + + freeaddrinfo(addr); + break; + default: + break; + } + + switch (self->mode & OUTPUT_DNSCLI_MODE_MODES) { + case OUTPUT_DNSCLI_MODE_UDP: + case OUTPUT_DNSCLI_MODE_TCP: + if (self->mode & OUTPUT_DNSCLI_MODE_NONBLOCKING) { + int flags; + + if ((flags = fcntl(self->fd, F_GETFL)) == -1) { + lcritical("fcntl(FL_GETFL) error %s", core_log_errstr(errno)); + return -3; + } + + if (fcntl(self->fd, F_SETFL, flags | O_NONBLOCK)) { + lcritical("fcntl(FL_SETFL, %x) error %s", flags, core_log_errstr(errno)); + return -3; + } + self->nonblocking = 1; + } + if (self->timeout.sec > 0 || self->timeout.nsec > 0) { + self->poll.fd = self->fd; + self->poll_timeout = (self->timeout.sec * 1e3) + (self->timeout.nsec / 1e6); //NOSONAR + if (!self->poll_timeout) { + self->poll_timeout = 1; + } + } + break; + case OUTPUT_DNSCLI_MODE_TLS: { + unsigned int ms; + gnutls_transport_set_int(self->session, self->fd); + ms = (self->timeout.sec * 1000) + (self->timeout.nsec / 1000000); + if (!ms && self->timeout.nsec) { + ms = 1; + } + gnutls_record_set_timeout(self->session, ms); + + /* Establish TLS */ + do { + err = gnutls_handshake(self->session); + } while (err < 0 && gnutls_error_is_fatal(err) == 0); + if (err == GNUTLS_E_PREMATURE_TERMINATION) { + lcritical("gnutls_handshake() error: %s", gnutls_strerror(err)); + return -3; + } else if (err < 0) { + lcritical("gnutls_handshake() failed: %s (%d)\n", gnutls_strerror(err), err); + return -3; + } + break; + } + default: + break; + } + + self->conn_ok = 1; + return 0; +} + +inline ssize_t _send_udp(output_dnscli_t* self, const uint8_t* payload, size_t len, size_t sent) +{ + ssize_t n; + + if (self->poll_timeout) { + self->poll.events = POLLOUT; + n = poll(&self->poll, 1, self->poll_timeout); + if (n != 1 || !(self->poll.revents & POLLOUT)) { + if (!n) { + self->timeouts++; + return -1; + } + self->errs++; + return -2; + } + } + n = sendto(self->fd, payload + sent, len - sent, 0, (struct sockaddr*)&self->addr, self->addr_len); + if (n > -1) { + return n; + } + switch (errno) { + case EAGAIN: +#if EAGAIN != EWOULDBLOCK + case EWOULDBLOCK: +#endif + case EINTR: + return -1; + default: + break; + } + return -2; +} + +static void _receive_udp(output_dnscli_t* self, const core_object_t* obj) +{ + const uint8_t* payload; + size_t len, sent = 0; + ssize_t n; + mlassert_self(); + + switch (obj->obj_type) { + case CORE_OBJECT_DNS: + payload = ((core_object_dns_t*)obj)->payload; + len = ((core_object_dns_t*)obj)->len; + + if (((core_object_dns_t*)obj)->includes_dnslen) { + if (len < 2) { + return; + } + payload += 2; + len -= 2; + } + break; + case CORE_OBJECT_PAYLOAD: + payload = ((core_object_payload_t*)obj)->payload; + len = ((core_object_payload_t*)obj)->len; + break; + default: + return; + } + + for (;;) { + n = _send_udp(self, payload, len, sent); + if (n > -1) { + sent += n; + if (sent < len) { + continue; + } + self->pkts++; + return; + } + if (n == -1) { + if (self->nonblocking) { + // TODO: warn? + return; + } + continue; + } + break; + } + self->errs++; +} + +inline ssize_t _send_tcp(output_dnscli_t* self, const uint8_t* payload, size_t len, size_t sent) +{ + ssize_t n; + + if (self->poll_timeout) { + self->poll.events = POLLOUT; + n = poll(&self->poll, 1, self->poll_timeout); + if (n != 1 || !(self->poll.revents & POLLOUT)) { + if (!n) { + self->timeouts++; + return -1; + } + self->errs++; + return -2; + } + } + n = sendto(self->fd, payload + sent, len - sent, 0, 0, 0); + if (n > -1) { + return n; + } + switch (errno) { + case EAGAIN: +#if EAGAIN != EWOULDBLOCK + case EWOULDBLOCK: +#endif + case EINTR: + return -1; + default: + break; + } + return -2; +} + +static void _receive_tcp(output_dnscli_t* self, const core_object_t* obj) +{ + const uint8_t* payload; + size_t len, sent = 0; + ssize_t n; + mlassert_self(); + + switch (obj->obj_type) { + case CORE_OBJECT_DNS: + if (!((core_object_dns_t*)obj)->includes_dnslen) { + uint16_t dnslen = htons(((core_object_dns_t*)obj)->len); + payload = (const uint8_t*)&dnslen; + len = sizeof(dnslen); + + for (;;) { + n = _send_tcp(self, payload, len, sent); + if (n > -1) { + sent += n; + if (sent < len) { + continue; + } + break; + } + if (n == -1) { + if (self->nonblocking) { + // TODO: warn? + return; + } + continue; + } + self->errs++; + return; + } + sent = 0; + } + payload = ((core_object_dns_t*)obj)->payload; + len = ((core_object_dns_t*)obj)->len; + break; + case CORE_OBJECT_PAYLOAD: + payload = ((core_object_payload_t*)obj)->payload; + len = ((core_object_payload_t*)obj)->len; + break; + default: + return; + } + + for (;;) { + n = _send_tcp(self, payload, len, sent); + if (n > -1) { + sent += n; + if (sent < len) { + continue; + } + self->pkts++; + return; + } + if (n == -1) { + if (self->nonblocking) { + // TODO: warn? + return; + } + continue; + } + break; + } + self->errs++; +} + +inline ssize_t _send_tls(output_dnscli_t* self, const uint8_t* payload, size_t len, size_t sent) +{ + ssize_t n; + + n = gnutls_record_send(self->session, payload + sent, len - sent); + if (n > -1) { + return n; + } + switch (n) { + case GNUTLS_E_AGAIN: + case GNUTLS_E_TIMEDOUT: + case GNUTLS_E_INTERRUPTED: + return -1; + default: + break; + } + return -2; +} + +static void _receive_tls(output_dnscli_t* self, const core_object_t* obj) +{ + const uint8_t* payload; + size_t len, sent = 0; + ssize_t n; + mlassert_self(); + + switch (obj->obj_type) { + case CORE_OBJECT_DNS: + if (!((core_object_dns_t*)obj)->includes_dnslen) { + uint16_t dnslen = htons(((core_object_dns_t*)obj)->len); + payload = (const uint8_t*)&dnslen; + len = sizeof(dnslen); + + for (;;) { + n = _send_tls(self, payload, len, sent); + if (n > -1) { + sent += n; + if (sent < len) { + continue; + } + break; + } + if (n == -1) { + if (self->nonblocking) { + // TODO: warn? + return; + } + continue; + } + self->errs++; + return; + } + sent = 0; + } + payload = ((core_object_dns_t*)obj)->payload; + len = ((core_object_dns_t*)obj)->len; + break; + case CORE_OBJECT_PAYLOAD: + payload = ((core_object_payload_t*)obj)->payload; + len = ((core_object_payload_t*)obj)->len; + break; + default: + return; + } + + for (;;) { + n = _send_tls(self, payload, len, sent); + if (n > -1) { + sent += n; + if (sent < len) { + continue; + } + self->pkts++; + return; + } + if (n == -1) { + if (self->nonblocking) { + // TODO: warn? + return; + } + continue; + } + break; + } + self->errs++; +} + +luajit_ssize_t output_dnscli_send(output_dnscli_t* self, const core_object_t* obj, size_t sent) +{ + const uint8_t* payload; + size_t len; + uint16_t dnslen; + mlassert_self(); + + switch (self->mode & OUTPUT_DNSCLI_MODE_MODES) { + case OUTPUT_DNSCLI_MODE_UDP: + switch (obj->obj_type) { + case CORE_OBJECT_DNS: + payload = ((core_object_dns_t*)obj)->payload; + len = ((core_object_dns_t*)obj)->len; + + if (((core_object_dns_t*)obj)->includes_dnslen) { + if (len < 2) { + return -2; + } + payload += 2; + len -= 2; + } + break; + case CORE_OBJECT_PAYLOAD: + payload = ((core_object_payload_t*)obj)->payload; + len = ((core_object_payload_t*)obj)->len; + break; + default: + return -2; + } + + return _send_udp(self, payload, len, sent); + + case OUTPUT_DNSCLI_MODE_TCP: + switch (obj->obj_type) { + case CORE_OBJECT_DNS: + if (!((core_object_dns_t*)obj)->includes_dnslen) { + if (sent < sizeof(dnslen)) { + dnslen = htons(((core_object_dns_t*)obj)->len); + payload = (const uint8_t*)&dnslen; + len = sizeof(dnslen); + + return _send_tcp(self, payload, len, sent); + } + sent -= sizeof(dnslen); + } + payload = ((core_object_dns_t*)obj)->payload; + len = ((core_object_dns_t*)obj)->len; + break; + case CORE_OBJECT_PAYLOAD: + payload = ((core_object_payload_t*)obj)->payload; + len = ((core_object_payload_t*)obj)->len; + break; + default: + return -2; + } + + return _send_tcp(self, payload, len, sent); + + case OUTPUT_DNSCLI_MODE_TLS: + switch (obj->obj_type) { + case CORE_OBJECT_DNS: + if (!((core_object_dns_t*)obj)->includes_dnslen) { + if (sent < sizeof(dnslen)) { + dnslen = htons(((core_object_dns_t*)obj)->len); + payload = (const uint8_t*)&dnslen; + len = sizeof(dnslen); + + return _send_tls(self, payload, len, sent); + } + sent -= sizeof(dnslen); + } + payload = ((core_object_dns_t*)obj)->payload; + len = ((core_object_dns_t*)obj)->len; + break; + case CORE_OBJECT_PAYLOAD: + payload = ((core_object_payload_t*)obj)->payload; + len = ((core_object_payload_t*)obj)->len; + break; + default: + return -2; + } + + return _send_tls(self, payload, len, sent); + + default: + break; + } + + return -2; +} + +core_receiver_t output_dnscli_receiver(output_dnscli_t* self) +{ + mlassert_self(); + + if (!self->conn_ok) { + lfatal("not connected"); + } + + switch (self->mode & OUTPUT_DNSCLI_MODE_MODES) { + case OUTPUT_DNSCLI_MODE_UDP: + return (core_receiver_t)_receive_udp; + case OUTPUT_DNSCLI_MODE_TCP: + return (core_receiver_t)_receive_tcp; + case OUTPUT_DNSCLI_MODE_TLS: + return (core_receiver_t)_receive_tls; + default: + break; + } + + lfatal("internal error"); + return 0; +} + +static const core_object_t* _produce_udp(output_dnscli_t* self) +{ + ssize_t n; + mlassert_self(); + + for (;;) { + if (self->poll_timeout) { + self->poll.events = POLLIN; + n = poll(&self->poll, 1, self->poll_timeout); + if (n != 1 || !(self->poll.revents & POLLIN)) { + if (!n) { + self->timeouts++; + self->pkt.len = 0; + return (core_object_t*)&self->pkt; + } else { + self->errs++; + } + return 0; + } + } + n = recvfrom(self->fd, self->recvbuf, sizeof(self->recvbuf), 0, 0, 0); + if (n > -1) { + break; + } + switch (errno) { + case EAGAIN: +#if EAGAIN != EWOULDBLOCK + case EWOULDBLOCK: +#endif + case EINTR: + if (self->nonblocking) { + self->pkt.len = 0; + return (core_object_t*)&self->pkt; + } + continue; + default: + break; + } + self->errs++; + break; + } + + if (n < 1) { + return 0; + } + + self->pkts_recv++; + self->pkt.len = n; + return (core_object_t*)&self->pkt; +} + +static const core_object_t* _produce_tcp(output_dnscli_t* self) +{ + ssize_t n; + mlassert_self(); + + if (self->have_pkt) { + if (self->recv > self->dnslen + sizeof(self->dnslen)) { + self->recv -= self->dnslen + sizeof(self->dnslen); + memmove(self->recvbuf, self->recvbuf + self->dnslen + sizeof(self->dnslen), self->recv); + } else { + self->recv = 0; + } + self->have_pkt = 0; + self->have_dnslen = 0; + } + + if (!self->have_dnslen && self->recv >= sizeof(self->dnslen)) { + self->dnslen = _need16(self->recvbuf); + self->have_dnslen = 1; + } + if (self->have_dnslen && self->recv >= self->dnslen + sizeof(self->dnslen)) { + self->pkts_recv++; + self->pkt.len = self->dnslen + sizeof(self->dnslen); + self->have_pkt = 1; + return (core_object_t*)&self->pkt; + } + + for (;;) { + if (self->poll_timeout) { + self->poll.events = POLLIN; + n = poll(&self->poll, 1, self->poll_timeout); + if (n != 1 || !(self->poll.revents & POLLIN)) { + if (!n) { + self->timeouts++; + self->pkt.len = 0; + return (core_object_t*)&self->pkt; + } else { + self->errs++; + } + return 0; + } + } + n = recvfrom(self->fd, self->recvbuf + self->recv, sizeof(self->recvbuf) - self->recv, 0, 0, 0); + if (n > 0) { + self->recv += n; + + if (!self->have_dnslen && self->recv >= sizeof(self->dnslen)) { + self->dnslen = _need16(self->recvbuf); + self->have_dnslen = 1; + } + if (self->have_dnslen && self->recv >= self->dnslen + sizeof(self->dnslen)) { + self->pkts_recv++; + self->pkt.len = self->dnslen + sizeof(self->dnslen); + self->have_pkt = 1; + return (core_object_t*)&self->pkt; + } + + if (self->nonblocking) { + break; + } + continue; + } + if (!n) { + break; + } + switch (errno) { + case EAGAIN: +#if EAGAIN != EWOULDBLOCK + case EWOULDBLOCK: +#endif + case EINTR: + if (self->nonblocking) { + self->pkt.len = 0; + return (core_object_t*)&self->pkt; + } + continue; + default: + break; + } + self->errs++; + break; + } + + if (n < 1) { + return 0; + } + + self->pkt.len = 0; + return (core_object_t*)&self->pkt; +} + +static const core_object_t* _produce_tls(output_dnscli_t* self) +{ + ssize_t n; + mlassert_self(); + + if (self->have_pkt) { + if (self->recv > self->dnslen + sizeof(self->dnslen)) { + self->recv -= self->dnslen + sizeof(self->dnslen); + memmove(self->recvbuf, self->recvbuf + self->dnslen + sizeof(self->dnslen), self->recv); + } else { + self->recv = 0; + } + self->have_pkt = 0; + self->have_dnslen = 0; + } + + if (!self->have_dnslen && self->recv >= sizeof(self->dnslen)) { + self->dnslen = _need16(self->recvbuf); + self->have_dnslen = 1; + } + if (self->have_dnslen && self->recv >= self->dnslen + sizeof(self->dnslen)) { + self->pkts_recv++; + self->pkt.len = self->dnslen + sizeof(self->dnslen); + self->have_pkt = 1; + return (core_object_t*)&self->pkt; + } + + for (;;) { + if (!gnutls_record_check_pending(self->session) && self->poll_timeout) { + self->poll.events = POLLIN; + n = poll(&self->poll, 1, self->poll_timeout); + if (n != 1 || !(self->poll.revents & POLLIN)) { + if (!n) { + self->timeouts++; + self->pkt.len = 0; + return (core_object_t*)&self->pkt; + } else { + self->errs++; + } + return 0; + } + } + n = gnutls_record_recv(self->session, self->recvbuf + self->recv, sizeof(self->recvbuf) - self->recv); + if (n > 0) { + self->recv += n; + + if (!self->have_dnslen && self->recv >= sizeof(self->dnslen)) { + self->dnslen = _need16(self->recvbuf); + self->have_dnslen = 1; + } + if (self->have_dnslen && self->recv >= self->dnslen + sizeof(self->dnslen)) { + self->pkts_recv++; + self->pkt.len = self->dnslen + sizeof(self->dnslen); + self->have_pkt = 1; + return (core_object_t*)&self->pkt; + } + + if (self->nonblocking) { + break; + } + continue; + } + if (!n) { + break; + } + switch (n) { + case GNUTLS_E_AGAIN: + case GNUTLS_E_TIMEDOUT: + case GNUTLS_E_INTERRUPTED: + if (self->nonblocking) { + self->pkt.len = 0; + return (core_object_t*)&self->pkt; + } + continue; + default: + break; + } + self->errs++; + break; + } + + if (n < 1) { + return 0; + } + + self->pkt.len = 0; + return (core_object_t*)&self->pkt; +} + +core_producer_t output_dnscli_producer(output_dnscli_t* self) +{ + mlassert_self(); + + if (!self->conn_ok) { + lfatal("not connected"); + } + + switch (self->mode & OUTPUT_DNSCLI_MODE_MODES) { + case OUTPUT_DNSCLI_MODE_UDP: + return (core_producer_t)_produce_udp; + case OUTPUT_DNSCLI_MODE_TCP: + return (core_producer_t)_produce_tcp; + case OUTPUT_DNSCLI_MODE_TLS: + return (core_producer_t)_produce_tls; + default: + break; + } + + lfatal("internal error"); + return 0; +} diff --git a/include/dnsjit/output/dnscli.h b/include/dnsjit/output/dnscli.h new file mode 100644 index 0000000..9927bd4 --- /dev/null +++ b/include/dnsjit/output/dnscli.h @@ -0,0 +1,38 @@ +/* + * 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/payload.h> +#include <dnsjit/core/timespec.h> +#include <dnsjit/core/compat.h> + +#ifndef __dnsjit_output_dnscli_h +#define __dnsjit_output_dnscli_h + +#include <sys/types.h> +#include <sys/socket.h> +#include <gnutls/gnutls.h> +#include <poll.h> + +#include <dnsjit/output/dnscli.hh> + +#endif diff --git a/include/dnsjit/output/dnscli.hh b/include/dnsjit/output/dnscli.hh new file mode 100644 index 0000000..4126423 --- /dev/null +++ b/include/dnsjit/output/dnscli.hh @@ -0,0 +1,72 @@ +/* + * 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.compat_h") +//lua:require("dnsjit.core.log") +//lua:require("dnsjit.core.receiver_h") +//lua:require("dnsjit.core.producer_h") +//lua:require("dnsjit.core.object.payload_h") +//lua:require("dnsjit.core.timespec_h") + +typedef enum output_dnscli_mode { + OUTPUT_DNSCLI_MODE_NONE = 0, + OUTPUT_DNSCLI_MODE_OPTIONS = 0xf, + OUTPUT_DNSCLI_MODE_NONBLOCKING = 0x1, + OUTPUT_DNSCLI_MODE_MODES = 0xf0, + OUTPUT_DNSCLI_MODE_UDP = 0x10, + OUTPUT_DNSCLI_MODE_TCP = 0x20, + OUTPUT_DNSCLI_MODE_TLS = 0x30, +} output_dnscli_mode_t; + +typedef struct output_dnscli { + core_log_t _log; + + output_dnscli_mode_t mode; + + size_t pkts, errs, timeouts; + int fd, nonblocking, conn_ok; + + struct pollfd poll; + int poll_timeout; + + struct sockaddr_storage addr; + size_t addr_len; + + uint8_t recvbuf[(64 * 1024) + 2]; + core_object_payload_t pkt; + uint16_t dnslen; + uint8_t have_dnslen, have_pkt; + size_t recv, pkts_recv; + + core_timespec_t timeout; + + gnutls_session_t session; + gnutls_certificate_credentials_t cred; +} output_dnscli_t; + +core_log_t* output_dnscli_log(); + +void output_dnscli_init(output_dnscli_t* self, output_dnscli_mode_t mode); +void output_dnscli_destroy(output_dnscli_t* self); +int output_dnscli_connect(output_dnscli_t* self, const char* host, const char* port); +luajit_ssize_t output_dnscli_send(output_dnscli_t* self, const core_object_t* obj, size_t sent); + +core_receiver_t output_dnscli_receiver(output_dnscli_t* self); +core_producer_t output_dnscli_producer(output_dnscli_t* self); diff --git a/include/dnsjit/output/dnscli.lua b/include/dnsjit/output/dnscli.lua new file mode 100644 index 0000000..bfdaf36 --- /dev/null +++ b/include/dnsjit/output/dnscli.lua @@ -0,0 +1,187 @@ +-- 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.output.dnscli +-- DNS aware UDP/TCP/TLS client +-- local dnscli = require("dnsjit.output.dnscli") +-- .SS UDP Receiver Chain +-- local output = dnscli.new(dnscli.UDP) +-- output:connect("127.0.0.1", "53") +-- input:receiver(output) +-- .SS TCP Nonblocking +-- local output = dnscli.new(dnscli.TCP + dnscli.NONBLOCKING) +-- output:send(object) +-- +-- The DNS client can a +-- .I core.object.dns +-- or a +-- .I core.object.payload +-- object via the receiver interface or using +-- .I send() +-- and send it as DNS query after which it can receive the response by using +-- the producer interface. +-- If the object being sent is a +-- .I core.object.dns +-- then it will look at +-- .I includes_dnslen +-- attribute and depending on the protocol it will disregard, include or send +-- the DNS length as an extra packet. +-- If the object being sent is a +-- .I core.object.payload +-- then no special handling will be done and it will be sent as is. +-- When receiving responses the producer interface will generate +-- .I core.object.payload +-- objects which may include the DNS length depending on the protocol used and +-- must be handled by the caller. +-- .SS MODES +-- These transport modes and options are available when creating a new Dnscli +-- output. +-- .TP +-- UDP +-- Create an output using UDP. +-- .TP +-- TCP +-- Create an output using TCP. +-- .TP +-- TLS +-- Create an output using TCP and encrypt it with TLS. +-- .TP +-- NONBLOCKING +-- Make the client nonblocking, see +-- .I send() +-- and +-- .IR produce() . +module(...,package.seeall) + +require("dnsjit.output.dnscli_h") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "output_dnscli_t" +local output_dnscli_t = ffi.typeof(t_name) +local Dnscli = { + NONBLOCKING = 0x1, + UDP = 0x10, + TCP = 0x20, + TLS = 0x30, +} + +-- Create a new Dnscli output. +function Dnscli.new(mode) + local self = { + obj = output_dnscli_t(), + } + C.output_dnscli_init(self.obj, mode) + ffi.gc(self.obj, C.output_dnscli_destroy) + return setmetatable(self, { __index = Dnscli }) +end + +-- Set or return the timeout used for sending and reciving, must be used before +-- .IR connect() . +function Dnscli:timeout(seconds, nanoseconds) + if seconds == nil and nanoseconds == nil then + return self.obj.timeout + end + if nanoseconds == nil then + nanoseconds = 0 + end + self.obj.timeout.sec = seconds + self.obj.timeout.nsec = nanoseconds +end + +-- Connect to the +-- .I host +-- and +-- .I port +-- and return 0 if successful. +function Dnscli:connect(host, port) + return C.output_dnscli_connect(self.obj, host, port) +end + +-- Return if nonblocking mode is on (true) or off (false). +function Dnscli:nonblocking() + if self.obj.nonblocking == 1 then + return true + end + return false +end + +-- Send an object and optionally continue sending after +-- .I sent +-- bytes. +-- Unlike the receive interface this function lets you know if the sending was +-- successful or not which might be needed on nonblocking connections. +-- Returns -2 on error, -1 if interrupted, timed out or unable to send due to +-- nonblocking, or the number of bytes sent. +-- .B Note +-- the counters for sent, received, errors and timeouts are not affected by +-- this function. +function Dnscli:send(object, sent) + if sent == nil then + sent = 0 + end + return C.output_dnscli_send(self.obj, object, sent) +end + +-- Return the C functions and context for receiving objects, these objects +-- will be sent. +function Dnscli:receive() + return C.output_dnscli_receiver(self.obj), self.obj +end + +-- Return the C functions and context for producing objects, these objects +-- are received. +-- If nonblocking mode is enabled the producer will return a payload object +-- with length zero if there was nothing to receive. +-- If nonblocking mode is disabled the producer will wait for data and if +-- timed out (see +-- .IR timeout ) +-- it will return a payload object with length zero. +-- The producer returns nil on error. +function Dnscli:produce() + return C.output_dnscli_producer(self.obj), self.obj +end + +-- Return the number of "packets" sent, actually the number of completely sent +-- payloads. +function Dnscli:packets() + return tonumber(self.obj.pkts) +end + +-- Return the number of "packets" received, actually the number of successful +-- calls to +-- .IR recvfrom (2) +-- that returned data. +function Dnscli:received() + return tonumber(self.obj.pkts_recv) +end + +-- Return the number of errors when sending or receiving. +function Dnscli:errors() + return tonumber(self.obj.errs) +end + +-- Return the number of timeouts when sending or receiving. +function Dnscli:timeouts() + return tonumber(self.obj.timeouts) +end + +-- core.object.dns (3), +-- core.object.payload (3), +-- core.timespec (3) +return Dnscli diff --git a/include/dnsjit/output/null.lua b/include/dnsjit/output/null.lua new file mode 100644 index 0000000..b0e167f --- /dev/null +++ b/include/dnsjit/output/null.lua @@ -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/>. + +-- dnsjit.output.null +-- Dummy layer to example.output.null +-- +-- This module has moved to example.output.null, see examples/modules/output-example in +-- dnsjit source repository. +module(...,package.seeall) + +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 cls diff --git a/include/dnsjit/output/pcap.c b/include/dnsjit/output/pcap.c new file mode 100644 index 0000000..ede9881 --- /dev/null +++ b/include/dnsjit/output/pcap.c @@ -0,0 +1,120 @@ +/* + * 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/pcap.h" +#include "core/assert.h" +#include "core/object/pcap.h" + +static core_log_t _log = LOG_T_INIT("output.pcap"); +static output_pcap_t _defaults = { + LOG_T_INIT_OBJ("output.pcap"), + 0, 0 +}; + +core_log_t* output_pcap_log() +{ + return &_log; +} + +void output_pcap_init(output_pcap_t* self) +{ + mlassert_self(); + + *self = _defaults; +} + +void output_pcap_destroy(output_pcap_t* self) +{ + mlassert_self(); +} + +int output_pcap_open(output_pcap_t* self, const char* file, int linktype, int snaplen) +{ + mlassert_self(); + if (self->dumper) { + lfatal("PCAP already opened"); + } + + if (!(self->pcap = pcap_open_dead(linktype, snaplen))) { + lcritical("pcap_open_dead() failed"); + return -1; + } + + if (!(self->dumper = pcap_dump_open(self->pcap, file))) { + lcritical("pcap_dump_open() error: %s", pcap_geterr(self->pcap)); + pcap_close(self->pcap); + self->pcap = 0; + return -1; + } + + return 0; +} + +void output_pcap_close(output_pcap_t* self) +{ + mlassert_self(); + if (self->dumper) { + pcap_dump_close(self->dumper); + self->dumper = 0; + } + if (self->pcap) { + pcap_close(self->pcap); + self->pcap = 0; + } +} + +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; + mlassert_self(); + + while (obj) { + if (obj->obj_type == CORE_OBJECT_PCAP) { + hdr.ts.tv_sec = ((const core_object_pcap_t*)obj)->ts.sec; + hdr.ts.tv_usec = ((const core_object_pcap_t*)obj)->ts.nsec / 1000; + hdr.caplen = ((const core_object_pcap_t*)obj)->caplen; + hdr.len = ((const core_object_pcap_t*)obj)->len; + + pcap_dump((void*)self->dumper, &hdr, ((const core_object_pcap_t*)obj)->bytes); + return; + } + obj = obj->obj_prev; + } +} + +core_receiver_t output_pcap_receiver(output_pcap_t* self) +{ + if (!self->dumper) { + lfatal("PCAP not opened"); + } + + return (core_receiver_t)_receive; +} diff --git a/include/dnsjit/output/pcap.h b/include/dnsjit/output/pcap.h new file mode 100644 index 0000000..40146c2 --- /dev/null +++ b/include/dnsjit/output/pcap.h @@ -0,0 +1,32 @@ +/* + * 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> + +#ifndef __dnsjit_output_pcap_h +#define __dnsjit_output_pcap_h + +#include <pcap/pcap.h> + +#include <dnsjit/output/pcap.hh> + +#endif diff --git a/include/dnsjit/output/pcap.hh b/include/dnsjit/output/pcap.hh new file mode 100644 index 0000000..6205333 --- /dev/null +++ b/include/dnsjit/output/pcap.hh @@ -0,0 +1,42 @@ +/* + * 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/>. + */ + +#if 0 +typedef struct pcap_dumper {} pcap_dumper_t; +#endif + +//lua:require("dnsjit.core.log") +//lua:require("dnsjit.core.receiver_h") +//lua:require("dnsjit.input.pcap_h") + +typedef struct output_pcap { + core_log_t _log; + pcap_t* pcap; + pcap_dumper_t* dumper; +} output_pcap_t; + +core_log_t* output_pcap_log(); +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); diff --git a/include/dnsjit/output/pcap.lua b/include/dnsjit/output/pcap.lua new file mode 100644 index 0000000..26ae8e7 --- /dev/null +++ b/include/dnsjit/output/pcap.lua @@ -0,0 +1,93 @@ +-- 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.output.pcap +-- Output to a PCAP using libpcap +-- local output = require("dnsjit.output.pcap").new() +-- output:open("file.pcap") +-- ... +-- output:close() +-- +-- Output module for writing +-- .I dnsjit.core.object.pcap +-- objects to a PCAP, +module(...,package.seeall) + +require("dnsjit.output.pcap_h") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "output_pcap_t" +local output_pcap_t = ffi.typeof(t_name) +local Pcap = {} + +-- Create a new Pcap output. +function Pcap.new() + local self = { + obj = output_pcap_t(), + } + C.output_pcap_init(self.obj) + ffi.gc(self.obj, C.output_pcap_destroy) + return setmetatable(self, { __index = Pcap }) +end + +-- Return the Log object to control logging of this instance or module. +function Pcap:log() + if self == nil then + return C.output_pcap_log() + end + return self.obj._log +end + +-- Open the PCAP +-- .I file +-- to write to using the +-- .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) +end + +-- Close the PCAP. +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 +end + +-- dnsjit.input.pcap (3) +return Pcap diff --git a/include/dnsjit/output/respdiff.c b/include/dnsjit/output/respdiff.c new file mode 100644 index 0000000..834a264 --- /dev/null +++ b/include/dnsjit/output/respdiff.c @@ -0,0 +1,298 @@ +/* + * 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/respdiff.h" +#include "core/assert.h" +#include "core/object/payload.h" + +#ifdef HAVE_LMDB_H +#include <lmdb.h> +#endif +#include <sys/stat.h> +#include <sys/types.h> +#include <string.h> + +static core_log_t _log = LOG_T_INIT("output.respdiff"); +static output_respdiff_t _defaults = { + LOG_T_INIT_OBJ("output.respdiff"), + 0, 0, 0, 0, 0, 0 +}; + +core_log_t* output_respdiff_log() +{ + return &_log; +} + +void output_respdiff_init(output_respdiff_t* self, const char* path, size_t mapsize) +{ + mlassert_self(); + + if (!path) { + lfatal("path is nil"); + } + + *self = _defaults; + +#ifdef HAVE_LMDB_H + if (mkdir(path, 0775) && errno != EEXIST) { + lfatal("mkdir(%s) error %s", path, core_log_errstr(errno)); + } + if (mdb_env_create((MDB_env**)&self->env)) { + lfatal("mdb_env_create failed"); + } + if (mdb_env_set_mapsize((MDB_env*)self->env, mapsize)) { + lfatal("mdb_env_set_mapsize(%lu) failed", mapsize); + } + if (mdb_env_set_maxdbs((MDB_env*)self->env, 3)) { + lfatal("mdb_env_set_maxdbs failed"); + } + if (mdb_env_open((MDB_env*)self->env, path, 0, 0664)) { + lfatal("mdb_env_open(%s) failed", path); + } + if (mdb_txn_begin((MDB_env*)self->env, 0, 0, (MDB_txn**)&self->txn)) { + lfatal("mdb_txn_begin failed for queries"); + } + lfatal_oom(self->qdb = calloc(1, sizeof(MDB_dbi))); + if (mdb_dbi_open((MDB_txn*)self->txn, "queries", MDB_CREATE, (MDB_dbi*)self->qdb)) { + lfatal("mdb_dbi_open failed for queries"); + } + lfatal_oom(self->rdb = calloc(1, sizeof(MDB_dbi))); + if (mdb_dbi_open((MDB_txn*)self->txn, "answers", MDB_CREATE, (MDB_dbi*)self->rdb)) { + lfatal("mdb_dbi_open failed for responses"); + } + lfatal_oom(self->meta = calloc(1, sizeof(MDB_dbi))); + if (mdb_dbi_open((MDB_txn*)self->txn, "meta", MDB_CREATE, (MDB_dbi*)self->meta)) { + lfatal("mdb_dbi_open failed for meta"); + } +#endif +} + +void output_respdiff_destroy(output_respdiff_t* self) +{ + mlassert_self(); + +#ifdef HAVE_LMDB_H + if (self->env) { + mdb_env_close((MDB_env*)self->env); + } + free(self->qdb); + free(self->rdb); + free(self->meta); +#endif +} + +#ifdef HAVE_LMDB_H +static const char* _meta_version = "version"; +static const char* _meta_version_val = "2018-05-21"; +static const char* _meta_servers = "servers"; +static const char* _meta_name0 = "name0"; +static const char* _meta_name1 = "name1"; +static const char* _meta_start_time = "start_time"; +static const char* _meta_end_time = "end_time"; +#endif + +void output_respdiff_commit(output_respdiff_t* self, const char* origname, const char* recvname, uint64_t start_time, uint64_t end_time) +{ +#ifdef HAVE_LMDB_H + MDB_val k, v; + uint32_t i; + int err; + mlassert_self(); + lassert(origname, "origname is nil"); + lassert(recvname, "recvname is nil"); + + k.mv_size = strlen(_meta_version); + k.mv_data = (void*)_meta_version; + v.mv_size = strlen(_meta_version_val); + v.mv_data = (void*)_meta_version_val; + if ((err = mdb_put((MDB_txn*)self->txn, (MDB_dbi) * ((MDB_dbi*)self->meta), &k, &v, 0))) { + if (err == MDB_MAP_FULL) { + lfatal("mdb_put meta.version failed, database is full"); + } else { + lfatal("mdb_put meta.version failed (%d)", err); + } + } + + k.mv_size = strlen(_meta_servers); + k.mv_data = (void*)_meta_servers; + i = 2; + v.mv_size = 4; + v.mv_data = (void*)&i; + if ((err = mdb_put((MDB_txn*)self->txn, (MDB_dbi) * ((MDB_dbi*)self->meta), &k, &v, 0))) { + if (err == MDB_MAP_FULL) { + lfatal("mdb_put meta.servers failed, database is full"); + } else { + lfatal("mdb_put meta.servers failed (%d)", err); + } + } + + k.mv_size = strlen(_meta_name0); + k.mv_data = (void*)_meta_name0; + v.mv_size = strlen(origname); + v.mv_data = (void*)origname; + if ((err = mdb_put((MDB_txn*)self->txn, (MDB_dbi) * ((MDB_dbi*)self->meta), &k, &v, 0))) { + if (err == MDB_MAP_FULL) { + lfatal("mdb_put meta.name0 failed, database is full"); + } else { + lfatal("mdb_put meta.name0 failed (%d)", err); + } + } + + k.mv_size = strlen(_meta_name1); + k.mv_data = (void*)_meta_name1; + v.mv_size = strlen(recvname); + v.mv_data = (void*)recvname; + if ((err = mdb_put((MDB_txn*)self->txn, (MDB_dbi) * ((MDB_dbi*)self->meta), &k, &v, 0))) { + if (err == MDB_MAP_FULL) { + lfatal("mdb_put meta.name1 failed, database is full"); + } else { + lfatal("mdb_put meta.name1 failed (%d)", err); + } + } + + k.mv_size = strlen(_meta_start_time); + k.mv_data = (void*)_meta_start_time; + i = start_time; + v.mv_size = 4; + v.mv_data = (void*)&i; + if ((err = mdb_put((MDB_txn*)self->txn, (MDB_dbi) * ((MDB_dbi*)self->meta), &k, &v, 0))) { + if (err == MDB_MAP_FULL) { + lfatal("mdb_put meta.start_time failed, database is full"); + } else { + lfatal("mdb_put meta.start_time failed (%d)", err); + } + } + + k.mv_size = strlen(_meta_end_time); + k.mv_data = (void*)_meta_end_time; + i = end_time; + v.mv_size = 4; + v.mv_data = (void*)&i; + if ((err = mdb_put((MDB_txn*)self->txn, (MDB_dbi) * ((MDB_dbi*)self->meta), &k, &v, 0))) { + if (err == MDB_MAP_FULL) { + lfatal("mdb_put meta.end_time failed, database is full"); + } else { + lfatal("mdb_put meta.end_time failed (%d)", err); + } + } + + if (self->txn) { + if (mdb_txn_commit((MDB_txn*)self->txn)) { + lfatal("mdb_txn_commit failed"); + } + self->txn = 0; + } +#endif +} + +#ifdef HAVE_LMDB_H +static void _receive(output_respdiff_t* self, const core_object_t* obj) +{ + const core_object_payload_t *query, *original, *response; + MDB_val k, v; + uint8_t responses[132096]; + uint32_t msec; + uint16_t dnslen; + int err; + mlassert_self(); + + if (!obj || obj->obj_type != CORE_OBJECT_PAYLOAD) { + lfatal("invalid first object"); + } + query = (core_object_payload_t*)obj; + + if (!query->obj_prev || query->obj_prev->obj_type != CORE_OBJECT_PAYLOAD) { + lfatal("invalid second object"); + } + original = (core_object_payload_t*)query->obj_prev; + + response = (core_object_payload_t*)original->obj_prev; + if (response && response->obj_type != CORE_OBJECT_PAYLOAD) { + lfatal("invalid third object"); + } + + if (12 + original->len + (response ? response->len : 0) > sizeof(responses)) { + lfatal("not enough buffer space for responses"); + } + + self->count++; + + k.mv_size = sizeof(self->id); + k.mv_data = (void*)&self->id; + v.mv_size = query->len; + v.mv_data = (void*)query->payload; + if ((err = mdb_put((MDB_txn*)self->txn, (MDB_dbi) * ((MDB_dbi*)self->qdb), &k, &v, 0))) { + if (err == MDB_MAP_FULL) { + lfatal("mdb_put query failed, database is full"); + } else { + lfatal("mdb_put query failed (%d)", err); + } + } + + msec = 1; // TODO + memcpy(responses, &msec, 4); + dnslen = original->len; + memcpy(&responses[4], &dnslen, 2); + memcpy(&responses[6], original->payload, original->len); + if (response) { + memcpy(&responses[6 + original->len], &msec, 4); + dnslen = response->len; + memcpy(&responses[10 + original->len], &dnslen, 2); + memcpy(&responses[12 + original->len], response->payload, response->len); + } else { + msec = 0xffffffff; + memcpy(&responses[6 + original->len], &msec, 4); + dnslen = 0; + memcpy(&responses[10 + original->len], &dnslen, 2); + } + + v.mv_size = 12 + original->len + (response ? response->len : 0); + v.mv_data = (void*)responses; + if ((err = mdb_put((MDB_txn*)self->txn, (MDB_dbi) * ((MDB_dbi*)self->rdb), &k, &v, 0))) { + if (err == MDB_MAP_FULL) { + lfatal("mdb_put answers failed, database is full"); + } else { + lfatal("mdb_put answers failed (%d)", err); + } + } + + self->id++; +} + +core_receiver_t output_respdiff_receiver(output_respdiff_t* self) +{ + mlassert_self(); + + if (!self->txn) { + lfatal("no LMDB opened"); + } + + return (core_receiver_t)_receive; +} +#else +core_receiver_t output_respdiff_receiver(output_respdiff_t* self) +{ + mlassert_self(); + lfatal("no LMDB support"); + return 0; +} +#endif diff --git a/include/dnsjit/output/respdiff.h b/include/dnsjit/output/respdiff.h new file mode 100644 index 0000000..207e225 --- /dev/null +++ b/include/dnsjit/output/respdiff.h @@ -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> + +#ifndef __dnsjit_output_respdiff_h +#define __dnsjit_output_respdiff_h + +#include <stdint.h> + +#include <dnsjit/output/respdiff.hh> + +#endif diff --git a/include/dnsjit/output/respdiff.hh b/include/dnsjit/output/respdiff.hh new file mode 100644 index 0000000..44f597e --- /dev/null +++ b/include/dnsjit/output/respdiff.hh @@ -0,0 +1,36 @@ +/* + * 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") + +typedef struct output_respdiff { + core_log_t _log; + void * env, *txn, *qdb, *rdb, *meta; + uint32_t id; + size_t count; +} output_respdiff_t; + +core_log_t* output_respdiff_log(); +void output_respdiff_init(output_respdiff_t* self, const char* path, size_t mapsize); +void output_respdiff_destroy(output_respdiff_t* self); +void output_respdiff_commit(output_respdiff_t* self, const char* origname, const char* recvname, uint64_t start_time, uint64_t end_time); + +core_receiver_t output_respdiff_receiver(output_respdiff_t* self); diff --git a/include/dnsjit/output/respdiff.lua b/include/dnsjit/output/respdiff.lua new file mode 100644 index 0000000..7d17b4a --- /dev/null +++ b/include/dnsjit/output/respdiff.lua @@ -0,0 +1,94 @@ +-- 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.output.respdiff +-- Output to respdiff LMDB +-- local output = require("dnsjit.output.respdiff").new("/path/to/lmdb") +-- +-- Output to an LMDB database (format 2018-05-21) that can be used by respdiff +-- to compare the responses found in the input data with the responses +-- received. +-- The receive function expects to get a chain of 2 or 3 +-- .IR core.object.payload . +-- For a completed query; The top of the chain is the query, after it the +-- original response and then the received response. +-- For a timed out query; The top of the chain is the query, after it the +-- original response. +module(...,package.seeall) + +require("dnsjit.output.respdiff_h") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "output_respdiff_t" +local output_respdiff_t = ffi.typeof(t_name) +local Respdiff = {} + +-- Create a new Respdiff output and created the LMDB database in the directory +-- .IR path . +-- The +-- .I origname +-- and +-- .I recvname +-- are used to populate the meta table, these names should be the same as +-- what is configured in +-- .IR respdiff.cfg . +-- Optional +-- .I mapsize +-- can be given to increase the database size beyond the default size of 10MB. +function Respdiff.new(path, origname, recvname, mapsize) + if mapsize == nil then + mapsize = 10485760 + end + local self = { + obj = output_respdiff_t(), + path = path, + origname = origname, + recvname = recvname, + } + C.output_respdiff_init(self.obj, path, mapsize) + ffi.gc(self.obj, C.output_respdiff_destroy) + return setmetatable(self, { __index = Respdiff }) +end + +-- Return the Log object to control logging of this instance or module. +function Respdiff:log() + if self == nil then + return C.output_respdiff_log() + end + return self.obj._log +end + +-- Return the C functions and context for receiving objects. +function Respdiff:receive() + return C.output_respdiff_receiver(self.obj), self.obj +end + +-- Commit the LMDB transactions, can not store any more objects after this +-- call. +-- The given +-- .I start_time +-- and +-- .I end_time +-- are used to fill the meta table. +function Respdiff:commit(start_time, end_time) + C.output_respdiff_commit(self.obj, self.origname, self.recvname, start_time, end_time) +end + +-- respdiff " https://gitlab.nic.cz/knot/respdiff" +return Respdiff diff --git a/include/dnsjit/output/tcpcli.c b/include/dnsjit/output/tcpcli.c new file mode 100644 index 0000000..f2b218b --- /dev/null +++ b/include/dnsjit/output/tcpcli.c @@ -0,0 +1,381 @@ +/* + * 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/tcpcli.h" +#include "core/assert.h" +#include "core/object/dns.h" +#include "core/object/payload.h" + +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <arpa/inet.h> +#include <poll.h> + +static core_log_t _log = LOG_T_INIT("output.tcpcli"); +static output_tcpcli_t _defaults = { + LOG_T_INIT_OBJ("output.tcpcli"), + 0, 0, -1, + { 0 }, CORE_OBJECT_PAYLOAD_INIT(0), + 0, 0, 0, 0, + { 5, 0 }, 1 +}; + +core_log_t* output_tcpcli_log() +{ + return &_log; +} + +void output_tcpcli_init(output_tcpcli_t* self) +{ + mlassert_self(); + + *self = _defaults; + self->pkt.payload = self->recvbuf; +} + +void output_tcpcli_destroy(output_tcpcli_t* self) +{ + mlassert_self(); + + if (self->fd > -1) { + shutdown(self->fd, SHUT_RDWR); + close(self->fd); + } +} + +int output_tcpcli_connect(output_tcpcli_t* self, const char* host, const char* port) +{ + struct addrinfo* addr; + int err; + mlassert_self(); + lassert(host, "host is nil"); + lassert(port, "port is nil"); + + if (self->fd > -1) { + lfatal("already connected"); + } + + if ((err = getaddrinfo(host, port, 0, &addr))) { + lcritical("getaddrinfo(%s, %s) error %s", host, port, gai_strerror(err)); + return -1; + } + if (!addr) { + lcritical("getaddrinfo failed, no address returned"); + return -1; + } + + if ((self->fd = socket(addr->ai_addr->sa_family, SOCK_STREAM, 0)) < 0) { + lcritical("socket() error %s", core_log_errstr(errno)); + freeaddrinfo(addr); + return -2; + } + + if (connect(self->fd, addr->ai_addr, addr->ai_addrlen)) { + lcritical("connect() error %s", core_log_errstr(errno)); + freeaddrinfo(addr); + return -2; + } + + freeaddrinfo(addr); + return 0; +} + +int output_tcpcli_nonblocking(output_tcpcli_t* self) +{ + int flags; + mlassert_self(); + + if (self->fd < 0) { + lfatal("not connected"); + } + + flags = fcntl(self->fd, F_GETFL); + if (flags != -1) { + flags = flags & O_NONBLOCK ? 1 : 0; + } + + return flags; +} + +int output_tcpcli_set_nonblocking(output_tcpcli_t* self, int nonblocking) +{ + int flags; + mlassert_self(); + + if (self->fd < 0) { + lfatal("not connected"); + } + + if ((flags = fcntl(self->fd, F_GETFL)) == -1) { + lcritical("fcntl(FL_GETFL) error %s", core_log_errstr(errno)); + return -1; + } + + if (nonblocking) { + flags |= O_NONBLOCK; + self->blocking = 0; + } else { + flags &= ~O_NONBLOCK; + self->blocking = 1; + } + + if (fcntl(self->fd, F_SETFL, flags | O_NONBLOCK)) { + lcritical("fcntl(FL_SETFL, %x) error %s", flags, core_log_errstr(errno)); + return -1; + } + + return 0; +} + +static void _receive(output_tcpcli_t* self, const core_object_t* obj) +{ + const uint8_t* payload; + size_t len, sent; + uint16_t dnslen; + mlassert_self(); + + for (; obj;) { + switch (obj->obj_type) { + case CORE_OBJECT_DNS: + obj = obj->obj_prev; + continue; + case CORE_OBJECT_PAYLOAD: + payload = ((core_object_payload_t*)obj)->payload; + len = ((core_object_payload_t*)obj)->len; + break; + default: + return; + } + + sent = 0; + dnslen = htons(len); + + for (;;) { + ssize_t ret = sendto(self->fd, ((uint8_t*)&dnslen) + sent, sizeof(dnslen) - sent, 0, 0, 0); + if (ret > -1) { + sent += ret; + if (sent < sizeof(dnslen)) + continue; + + sent = 0; + for (;;) { + ssize_t ret = sendto(self->fd, payload + sent, len - sent, 0, 0, 0); + if (ret > -1) { + sent += ret; + if (sent < len) + continue; + self->pkts++; + return; + } + switch (errno) { + case EAGAIN: +#if EAGAIN != EWOULDBLOCK + case EWOULDBLOCK: +#endif + continue; + default: + break; + } + break; + } + self->errs++; + return; + } + switch (errno) { + case EAGAIN: +#if EAGAIN != EWOULDBLOCK + case EWOULDBLOCK: +#endif + continue; + default: + break; + } + break; + } + self->errs++; + break; + } +} + +core_receiver_t output_tcpcli_receiver(output_tcpcli_t* self) +{ + mlassert_self(); + + if (self->fd < 0) { + lfatal("not connected"); + } + + return (core_receiver_t)_receive; +} + +static const core_object_t* _produce(output_tcpcli_t* self) +{ + ssize_t n, recv = 0; + uint16_t dnslen; + struct pollfd p; + int to = 0; + mlassert_self(); + + // Check if last recvfrom() got more then we needed + if (!self->have_dnslen && self->recv > self->dnslen) { + recv = self->recv - self->dnslen; + if (recv < sizeof(dnslen)) { + memcpy(((uint8_t*)&dnslen), self->recvbuf + self->dnslen, recv); + } else { + memcpy(((uint8_t*)&dnslen), self->recvbuf + self->dnslen, sizeof(dnslen)); + + if (recv > sizeof(dnslen)) { + self->recv = recv - sizeof(dnslen); + memmove(self->recvbuf, self->recvbuf + self->dnslen + sizeof(dnslen), self->recv); + } else { + self->recv = 0; + } + + self->dnslen = ntohs(dnslen); + self->have_dnslen = 1; + + if (self->recv > self->dnslen) { + self->pkts_recv++; + self->pkt.len = self->dnslen; + self->have_dnslen = 0; + return (core_object_t*)&self->pkt; + } + } + } + + if (self->blocking) { + p.fd = self->fd; + p.events = POLLIN; + p.revents = 0; + to = (self->timeout.sec * 1e3) + (self->timeout.nsec / 1e6); //NOSONAR + if (!to) { + to = 1; + } + } + + if (!self->have_dnslen) { + for (;;) { + n = poll(&p, 1, to); + if (n < 0 || (p.revents & (POLLERR | POLLHUP | POLLNVAL))) { + self->errs++; + return 0; + } + if (!n || !(p.revents & POLLIN)) { + if (recv) { + self->errs++; + return 0; + } + self->pkt.len = 0; + return (core_object_t*)&self->pkt; + } + + n = recvfrom(self->fd, ((uint8_t*)&dnslen) + recv, sizeof(dnslen) - recv, 0, 0, 0); + if (n > 0) { + recv += n; + if (recv < sizeof(dnslen)) + continue; + break; + } + if (!n) { + break; + } + switch (errno) { + case EAGAIN: +#if EAGAIN != EWOULDBLOCK + case EWOULDBLOCK: +#endif + continue; + default: + break; + } + self->errs++; + break; + } + + if (n < 1) { + return 0; + } + + self->dnslen = ntohs(dnslen); + self->have_dnslen = 1; + self->recv = 0; + } + + for (;;) { + n = poll(&p, 1, to); + if (n < 0 || (p.revents & (POLLERR | POLLHUP | POLLNVAL))) { + self->errs++; + return 0; + } + if (!n || !(p.revents & POLLIN)) { + self->pkt.len = 0; + return (core_object_t*)&self->pkt; + } + + n = recvfrom(self->fd, self->recvbuf + self->recv, sizeof(self->recvbuf) - self->recv, 0, 0, 0); + if (n > 0) { + self->recv += n; + if (self->recv < self->dnslen) + continue; + break; + } + if (!n) { + break; + } + switch (errno) { + case EAGAIN: +#if EAGAIN != EWOULDBLOCK + case EWOULDBLOCK: +#endif + self->pkt.len = 0; + return (core_object_t*)&self->pkt; + default: + break; + } + self->errs++; + break; + } + + if (n < 1) { + return 0; + } + + self->pkts_recv++; + self->pkt.len = self->dnslen; + self->have_dnslen = 0; + return (core_object_t*)&self->pkt; +} + +core_producer_t output_tcpcli_producer(output_tcpcli_t* self) +{ + mlassert_self(); + + if (self->fd < 0) { + lfatal("not connected"); + } + + return (core_producer_t)_produce; +} diff --git a/include/dnsjit/output/tcpcli.h b/include/dnsjit/output/tcpcli.h new file mode 100644 index 0000000..83b7ea4 --- /dev/null +++ b/include/dnsjit/output/tcpcli.h @@ -0,0 +1,32 @@ +/* + * 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/payload.h> +#include <dnsjit/core/timespec.h> + +#ifndef __dnsjit_output_tcpcli_h +#define __dnsjit_output_tcpcli_h + +#include <dnsjit/output/tcpcli.hh> + +#endif diff --git a/include/dnsjit/output/tcpcli.hh b/include/dnsjit/output/tcpcli.hh new file mode 100644 index 0000000..277b0dd --- /dev/null +++ b/include/dnsjit/output/tcpcli.hh @@ -0,0 +1,51 @@ +/* + * 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.payload_h") +//lua:require("dnsjit.core.timespec_h") + +typedef struct output_tcpcli { + core_log_t _log; + size_t pkts, errs; + int fd; + + uint8_t recvbuf[64 * 1024]; + core_object_payload_t pkt; + uint16_t dnslen; + uint8_t have_dnslen; + size_t recv, pkts_recv; + + core_timespec_t timeout; + int8_t blocking; +} output_tcpcli_t; + +core_log_t* output_tcpcli_log(); + +void output_tcpcli_init(output_tcpcli_t* self); +void output_tcpcli_destroy(output_tcpcli_t* self); +int output_tcpcli_connect(output_tcpcli_t* self, const char* host, const char* port); +int output_tcpcli_nonblocking(output_tcpcli_t* self); +int output_tcpcli_set_nonblocking(output_tcpcli_t* self, int nonblocking); + +core_receiver_t output_tcpcli_receiver(output_tcpcli_t* self); +core_producer_t output_tcpcli_producer(output_tcpcli_t* self); diff --git a/include/dnsjit/output/tcpcli.lua b/include/dnsjit/output/tcpcli.lua new file mode 100644 index 0000000..d57de88 --- /dev/null +++ b/include/dnsjit/output/tcpcli.lua @@ -0,0 +1,131 @@ +-- 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.output.tcpcli +-- Simple, length aware, TCP client +-- local output = require("dnsjit.output.tcpcli").new("127.0.0.1", "53") +-- +-- Simple TCP client that takes any payload you give it, sends the length of +-- the payload as an unsigned 16 bit integer and then sends the payload. +-- When receiving it will first retrieve the length of the payload as an +-- unsigned 16 bit integer and it will stall until it gets, even if +-- nonblocking mode is used. +-- Then it will retrieve at least that amount of bytes, if nonblocking mode +-- is used here then it will return a payload object with length zero if +-- there was nothing to receive or if the full payload have not been received +-- yet. +-- Additional calls will continue retrieving the payload. +-- .SS Attributes +-- .TP +-- timeout +-- A +-- .I core.timespec +-- that is used when producing objects. +module(...,package.seeall) + +require("dnsjit.output.tcpcli_h") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "output_tcpcli_t" +local output_tcpcli_t = ffi.typeof(t_name) +local Tcpcli = {} + +-- Create a new Tcpcli output. +function Tcpcli.new() + local self = { + obj = output_tcpcli_t(), + } + C.output_tcpcli_init(self.obj) + ffi.gc(self.obj, C.output_tcpcli_destroy) + return setmetatable(self, { __index = Tcpcli }) +end + +-- Set the timeout when producing objects. +function Tcpcli:timeout(seconds, nanoseconds) + self.obj.timeout.sec = seconds + self.obj.timeout.nsec = nanoseconds +end + +-- Connect to the +-- .I host +-- and +-- .I port +-- and return 0 if successful. +function Tcpcli:connect(host, port) + return C.output_tcpcli_connect(self.obj, host, port) +end + +-- Enable (true) or disable (false) nonblocking mode and +-- return 0 if successful, if +-- .I bool +-- is not specified then return if nonblocking mode is on (true) or off (false). +function Tcpcli:nonblocking(bool) + if bool == nil then + if C.output_tcpcli_nonblocking(self.obj) == 1 then + return true + end + return false + elseif bool == true then + return C.output_tcpcli_set_nonblocking(self.obj, 1) + else + return C.output_tcpcli_set_nonblocking(self.obj, 0) + end +end + +-- Return the C functions and context for receiving objects, these objects +-- will be sent. +function Tcpcli:receive() + return C.output_tcpcli_receiver(self.obj), self.obj +end + +-- Return the C functions and context for producing objects, these objects +-- are received. +-- If nonblocking mode is enabled the producer will return a payload object +-- with length zero if there was nothing to receive or if the full payload +-- have not been received yet. +-- If nonblocking mode is disabled the producer will wait for data and if +-- timed out (see +-- .IR timeout ) +-- it will return a payload object with length zero. +-- If a timeout happens during during the first stage, getting the length, it +-- will fail and return nil. +-- Additional calls will continue retrieving the payload. +-- The producer returns nil on error. +function Tcpcli:produce() + return C.output_tcpcli_producer(self.obj), self.obj +end + +-- Return the number of "packets" sent, actually the number of completely sent +-- payloads. +function Tcpcli:packets() + return tonumber(self.obj.pkts) +end + +-- Return the number of "packets" received, actually the number of completely +-- received DNS messages. +function Tcpcli:received() + return tonumber(self.obj.pkts_recv) +end + +-- Return the number of errors when sending. +function Tcpcli:errors() + return tonumber(self.obj.errs) +end + +return Tcpcli diff --git a/include/dnsjit/output/tlscli.c b/include/dnsjit/output/tlscli.c new file mode 100644 index 0000000..8c5947a --- /dev/null +++ b/include/dnsjit/output/tlscli.c @@ -0,0 +1,345 @@ +/* + * 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/tlscli.h" +#include "core/assert.h" +#include "core/object/dns.h" +#include "core/object/payload.h" + +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <arpa/inet.h> +#include <poll.h> + +static core_log_t _log = LOG_T_INIT("output.tlscli"); +static output_tlscli_t _defaults = { + LOG_T_INIT_OBJ("output.tlscli"), + 0, 0, -1, 0, + { 0 }, CORE_OBJECT_PAYLOAD_INIT(0), + 0, 0, 0, 0, + { 5, 0 }, + 0, 0 +}; + +core_log_t* output_tlscli_log() +{ + return &_log; +} + +void output_tlscli_init(output_tlscli_t* self) +{ + int err; + mlassert_self(); + + *self = _defaults; + self->pkt.payload = self->recvbuf; + + gnutls_global_init(); + if ((err = gnutls_certificate_allocate_credentials(&self->cred)) != GNUTLS_E_SUCCESS) { + lfatal("gnutls_certificate_allocate_credentials() error: %s", gnutls_strerror(err)); + } else if ((err = gnutls_init(&self->session, GNUTLS_CLIENT)) != GNUTLS_E_SUCCESS) { + lfatal("gnutls_init() error: %s", gnutls_strerror(err)); + } else if ((err = gnutls_set_default_priority(self->session)) != GNUTLS_E_SUCCESS) { + lfatal("gnutls_set_default_priority() error: %s", gnutls_strerror(err)); + } else if ((err = gnutls_credentials_set(self->session, GNUTLS_CRD_CERTIFICATE, self->cred)) != GNUTLS_E_SUCCESS) { + lfatal("gnutls_credentials_set() error: %s", gnutls_strerror(err)); + } + + gnutls_handshake_set_timeout(self->session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT); +} + +void output_tlscli_destroy(output_tlscli_t* self) +{ + mlassert_self(); + + if (self->fd > -1) { + if (self->session) { + gnutls_bye(self->session, GNUTLS_SHUT_RDWR); + gnutls_deinit(self->session); + } + shutdown(self->fd, SHUT_RDWR); + close(self->fd); + if (self->cred) { + gnutls_certificate_free_credentials(self->cred); + } + } +} + +int output_tlscli_connect(output_tlscli_t* self, const char* host, const char* port) +{ + struct addrinfo* addr; + int err; + unsigned int ms; + mlassert_self(); + lassert(host, "host is nil"); + lassert(port, "port is nil"); + + if (self->fd > -1) { + lfatal("already connected"); + } + if (self->tls_ok) { + lfatal("TLS already established"); + } + + if ((err = getaddrinfo(host, port, 0, &addr))) { + lcritical("getaddrinfo(%s, %s) error %s", host, port, gai_strerror(err)); + return -1; + } + if (!addr) { + lcritical("getaddrinfo failed, no address returned"); + return -1; + } + + if ((self->fd = socket(addr->ai_addr->sa_family, SOCK_STREAM, 0)) < 0) { + lcritical("socket() error %s", core_log_errstr(errno)); + freeaddrinfo(addr); + return -2; + } + + if (connect(self->fd, addr->ai_addr, addr->ai_addrlen)) { + lcritical("connect() error %s", core_log_errstr(errno)); + freeaddrinfo(addr); + return -2; + } + + freeaddrinfo(addr); + + gnutls_transport_set_int(self->session, self->fd); + ms = (self->timeout.sec * 1000) + (self->timeout.nsec / 1000000); + if (!ms && self->timeout.nsec) { + ms = 1; + } + gnutls_record_set_timeout(self->session, ms); + + /* Establish TLS */ + do { + err = gnutls_handshake(self->session); + } while (err < 0 && gnutls_error_is_fatal(err) == 0); + if (err == GNUTLS_E_PREMATURE_TERMINATION) { + lcritical("gnutls_handshake() error: %s", gnutls_strerror(err)); + return -3; + } else if (err < 0) { + lcritical("gnutls_handshake() failed: %s (%d)\n", gnutls_strerror(err), err); + return -3; + } + + self->tls_ok = 1; + return 0; +} + +static void _receive(output_tlscli_t* self, const core_object_t* obj) +{ + const uint8_t* payload; + size_t len, sent; + uint16_t dnslen; + ssize_t ret; + mlassert_self(); + + for (; obj;) { + switch (obj->obj_type) { + case CORE_OBJECT_DNS: + obj = obj->obj_prev; + continue; + case CORE_OBJECT_PAYLOAD: + payload = ((core_object_payload_t*)obj)->payload; + len = ((core_object_payload_t*)obj)->len; + break; + default: + return; + } + + sent = 0; + dnslen = htons(len); + + for (;;) { + ret = gnutls_record_send(self->session, ((uint8_t*)&dnslen) + sent, sizeof(dnslen) - sent); + if (ret > -1) { + sent += ret; + if (sent < sizeof(dnslen)) + continue; + + sent = 0; + for (;;) { + ret = gnutls_record_send(self->session, payload + sent, len - sent); + if (ret > -1) { + sent += ret; + if (sent < len) + continue; + self->pkts++; + return; + } + switch (ret) { + case GNUTLS_E_AGAIN: + case GNUTLS_E_TIMEDOUT: + continue; + default: + break; + } + break; + } + self->errs++; + return; + } + switch (ret) { + case GNUTLS_E_AGAIN: + case GNUTLS_E_TIMEDOUT: + continue; + default: + break; + } + break; + } + self->errs++; + break; + } +} + +core_receiver_t output_tlscli_receiver(output_tlscli_t* self) +{ + mlassert_self(); + + if (self->fd < 0) { + lfatal("not connected"); + } + if (!self->tls_ok) { + lfatal("TLS is not established"); + } + + return (core_receiver_t)_receive; +} + +static const core_object_t* _produce(output_tlscli_t* self) +{ + ssize_t n, recv = 0; + uint16_t dnslen; + mlassert_self(); + + // Check if last recvfrom() got more then we needed + if (!self->have_dnslen && self->recv > self->dnslen) { + recv = self->recv - self->dnslen; + if (recv < sizeof(dnslen)) { + memcpy(((uint8_t*)&dnslen), self->recvbuf + self->dnslen, recv); + } else { + memcpy(((uint8_t*)&dnslen), self->recvbuf + self->dnslen, sizeof(dnslen)); + + if (recv > sizeof(dnslen)) { + self->recv = recv - sizeof(dnslen); + memmove(self->recvbuf, self->recvbuf + self->dnslen + sizeof(dnslen), self->recv); + } else { + self->recv = 0; + } + + self->dnslen = ntohs(dnslen); + self->have_dnslen = 1; + + if (self->recv > self->dnslen) { + self->pkts_recv++; + self->pkt.len = self->dnslen; + self->have_dnslen = 0; + return (core_object_t*)&self->pkt; + } + } + } + + if (!self->have_dnslen) { + for (;;) { + n = gnutls_record_recv(self->session, ((uint8_t*)&dnslen) + recv, sizeof(dnslen) - recv); + if (n > 0) { + recv += n; + if (recv < sizeof(dnslen)) + continue; + break; + } + if (!n) { + break; + } + switch (n) { + case GNUTLS_E_AGAIN: + case GNUTLS_E_TIMEDOUT: + self->pkt.len = 0; + return (core_object_t*)&self->pkt; + default: + break; + } + self->errs++; + break; + } + + if (n < 1) { + return 0; + } + + self->dnslen = ntohs(dnslen); + self->have_dnslen = 1; + self->recv = 0; + } + + for (;;) { + n = gnutls_record_recv(self->session, self->recvbuf + self->recv, sizeof(self->recvbuf) - self->recv); + if (n > 0) { + self->recv += n; + if (self->recv < self->dnslen) + continue; + break; + } + if (!n) { + break; + } + switch (n) { + case GNUTLS_E_AGAIN: + case GNUTLS_E_TIMEDOUT: + self->pkt.len = 0; + return (core_object_t*)&self->pkt; + default: + break; + } + self->errs++; + break; + } + + if (n < 1) { + return 0; + } + + self->pkts_recv++; + self->pkt.len = self->dnslen; + self->have_dnslen = 0; + return (core_object_t*)&self->pkt; +} + +core_producer_t output_tlscli_producer(output_tlscli_t* self) +{ + mlassert_self(); + + if (self->fd < 0) { + lfatal("not connected"); + } + if (!self->tls_ok) { + lfatal("TLS is not established"); + } + + return (core_producer_t)_produce; +} diff --git a/include/dnsjit/output/tlscli.h b/include/dnsjit/output/tlscli.h new file mode 100644 index 0000000..72e7b9d --- /dev/null +++ b/include/dnsjit/output/tlscli.h @@ -0,0 +1,34 @@ +/* + * 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/payload.h> +#include <dnsjit/core/timespec.h> + +#ifndef __dnsjit_output_tlscli_h +#define __dnsjit_output_tlscli_h + +#include <gnutls/gnutls.h> + +#include <dnsjit/output/tlscli.hh> + +#endif diff --git a/include/dnsjit/output/tlscli.hh b/include/dnsjit/output/tlscli.hh new file mode 100644 index 0000000..4a0c142 --- /dev/null +++ b/include/dnsjit/output/tlscli.hh @@ -0,0 +1,52 @@ +/* + * 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.compat_h") +//lua:require("dnsjit.core.log") +//lua:require("dnsjit.core.receiver_h") +//lua:require("dnsjit.core.producer_h") +//lua:require("dnsjit.core.object.payload_h") +//lua:require("dnsjit.core.timespec_h") + +typedef struct output_tlscli { + core_log_t _log; + size_t pkts, errs; + int fd, tls_ok; + + uint8_t recvbuf[64 * 1024]; + core_object_payload_t pkt; + uint16_t dnslen; + uint8_t have_dnslen; + size_t recv, pkts_recv; + + core_timespec_t timeout; + + gnutls_session_t session; + gnutls_certificate_credentials_t cred; +} output_tlscli_t; + +core_log_t* output_tlscli_log(); + +void output_tlscli_init(output_tlscli_t* self); +void output_tlscli_destroy(output_tlscli_t* self); +int output_tlscli_connect(output_tlscli_t* self, const char* host, const char* port); + +core_receiver_t output_tlscli_receiver(output_tlscli_t* self); +core_producer_t output_tlscli_producer(output_tlscli_t* self); diff --git a/include/dnsjit/output/tlscli.lua b/include/dnsjit/output/tlscli.lua new file mode 100644 index 0000000..e37439b --- /dev/null +++ b/include/dnsjit/output/tlscli.lua @@ -0,0 +1,103 @@ +-- 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.output.tlscli +-- Simple TLS client +-- local output = require("dnsjit.output.tlscli").new("127.0.0.1", "853") +-- +-- Simple TLS client that attempts to do a TLS handshake (without +-- certificate verification). It behaves the same way as tcpcli, except all +-- the data is sent over the encrypted channel. +-- .SS Attributes +-- .TP +-- timeout +-- A +-- .I core.timespec +-- that is used when producing objects. +module(...,package.seeall) + +require("dnsjit.output.tlscli_h") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "output_tlscli_t" +local output_tlscli_t = ffi.typeof(t_name) +local Tlscli = {} + +-- Create a new Tlscli output. +function Tlscli.new() + local self = { + obj = output_tlscli_t(), + } + C.output_tlscli_init(self.obj) + ffi.gc(self.obj, C.output_tlscli_destroy) + return setmetatable(self, { __index = Tlscli }) +end + +-- Set the timeout when producing objects. +function Tlscli:timeout(seconds, nanoseconds) + self.obj.timeout.sec = seconds + self.obj.timeout.nsec = nanoseconds +end + +-- Connect to the +-- .I host +-- and +-- .I port +-- , perform a TLS handshake and return 0 if successful. +function Tlscli:connect(host, port) + return C.output_tlscli_connect(self.obj, host, port) +end + +-- Return the C functions and context for receiving objects, these objects +-- will be sent. +function Tlscli:receive() + return C.output_tlscli_receiver(self.obj), self.obj +end + +-- Return the C functions and context for producing objects, these objects +-- are received. +-- The producer will wait for data and if timed out (see +-- .IR timeout ) +-- it will return a payload object with length zero. +-- If a timeout happens during during the first stage, getting the length, it +-- will fail and return nil. +-- Additional calls will continue retrieving the payload. +-- The producer returns nil on error. +function Tlscli:produce() + return C.output_tlscli_producer(self.obj), self.obj +end + +-- Return the number of "packets" sent, actually the number of completely sent +-- payloads. +function Tlscli:packets() + return tonumber(self.obj.pkts) +end + +-- Return the number of "packets" received, actually the number of completely +-- received DNS messages. +function Tlscli:received() + return tonumber(self.obj.pkts_recv) +end + +-- Return the number of errors when sending. +function Tlscli:errors() + return tonumber(self.obj.errs) +end + +return Tlscli diff --git a/include/dnsjit/output/udpcli.c b/include/dnsjit/output/udpcli.c new file mode 100644 index 0000000..b207d9c --- /dev/null +++ b/include/dnsjit/output/udpcli.c @@ -0,0 +1,300 @@ +/* + * 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/udpcli.h" +#include "core/assert.h" +#include "core/object/dns.h" +#include "core/object/payload.h" + +#include <netdb.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <poll.h> + +static core_log_t _log = LOG_T_INIT("output.udpcli"); +static output_udpcli_t _defaults = { + LOG_T_INIT_OBJ("output.udpcli"), + 0, 0, -1, + { 0 }, 0, + { 0 }, CORE_OBJECT_PAYLOAD_INIT(0), 0, + { 5, 0 }, 1 +}; + +core_log_t* output_udpcli_log() +{ + return &_log; +} + +void output_udpcli_init(output_udpcli_t* self) +{ + mlassert_self(); + + *self = _defaults; + self->pkt.payload = self->recvbuf; +} + +void output_udpcli_destroy(output_udpcli_t* self) +{ + mlassert_self(); + + if (self->fd > -1) { + shutdown(self->fd, SHUT_RDWR); + close(self->fd); + } +} + +int output_udpcli_connect(output_udpcli_t* self, const char* host, const char* port) +{ + struct addrinfo* addr; + int err; + mlassert_self(); + lassert(host, "host is nil"); + lassert(port, "port is nil"); + + if (self->fd > -1) { + lfatal("already connected"); + } + + if ((err = getaddrinfo(host, port, 0, &addr))) { + lcritical("getaddrinfo(%s, %s) error %s", host, port, gai_strerror(err)); + return -1; + } + if (!addr) { + lcritical("getaddrinfo failed, no address returned"); + return -1; + } + + memcpy(&self->addr, addr->ai_addr, addr->ai_addrlen); + self->addr_len = addr->ai_addrlen; + freeaddrinfo(addr); + + if ((self->fd = socket(((struct sockaddr*)&self->addr)->sa_family, SOCK_DGRAM, 0)) < 0) { + lcritical("socket() error %s", core_log_errstr(errno)); + return -2; + } + + return 0; +} + +int output_udpcli_nonblocking(output_udpcli_t* self) +{ + int flags; + mlassert_self(); + + if (self->fd < 0) { + lfatal("not connected"); + } + + flags = fcntl(self->fd, F_GETFL); + if (flags != -1) { + flags = flags & O_NONBLOCK ? 1 : 0; + } + + return flags; +} + +int output_udpcli_set_nonblocking(output_udpcli_t* self, int nonblocking) +{ + int flags; + mlassert_self(); + + if (self->fd < 0) { + lfatal("not connected"); + } + + if ((flags = fcntl(self->fd, F_GETFL)) == -1) { + lcritical("fcntl(FL_GETFL) error %s", core_log_errstr(errno)); + return -1; + } + + if (nonblocking) { + flags |= O_NONBLOCK; + self->blocking = 0; + } else { + flags &= ~O_NONBLOCK; + self->blocking = 1; + } + + if (fcntl(self->fd, F_SETFL, flags | O_NONBLOCK)) { + lcritical("fcntl(FL_SETFL, %x) error %s", flags, core_log_errstr(errno)); + return -1; + } + + return 0; +} + +static void _receive(output_udpcli_t* self, const core_object_t* obj) +{ + const uint8_t* payload; + size_t len, sent; + mlassert_self(); + + for (; obj;) { + switch (obj->obj_type) { + case CORE_OBJECT_DNS: + obj = obj->obj_prev; + continue; + case CORE_OBJECT_PAYLOAD: + payload = ((core_object_payload_t*)obj)->payload; + len = ((core_object_payload_t*)obj)->len; + break; + default: + return; + } + + sent = 0; + for (;;) { + ssize_t ret = sendto(self->fd, payload + sent, len - sent, 0, (struct sockaddr*)&self->addr, self->addr_len); + if (ret > -1) { + sent += ret; + if (sent < len) + continue; + self->pkts++; + return; + } + switch (errno) { + case EAGAIN: +#if EAGAIN != EWOULDBLOCK + case EWOULDBLOCK: +#endif + continue; + default: + break; + } + break; + } + self->errs++; + break; + } +} + +core_receiver_t output_udpcli_receiver(output_udpcli_t* self) +{ + mlassert_self(); + + if (self->fd < 0) { + lfatal("not connected"); + } + + return (core_receiver_t)_receive; +} + +static const core_object_t* _produce(output_udpcli_t* self) +{ + ssize_t n; + mlassert_self(); + + for (;;) { + n = recvfrom(self->fd, self->recvbuf, sizeof(self->recvbuf), 0, 0, 0); + if (n > -1) { + break; + } + switch (errno) { + case EAGAIN: +#if EAGAIN != EWOULDBLOCK + case EWOULDBLOCK: +#endif + self->pkt.len = 0; + return (core_object_t*)&self->pkt; + default: + break; + } + self->errs++; + break; + } + + if (n < 1) { + return 0; + } + + self->pkts_recv++; + self->pkt.len = n; + return (core_object_t*)&self->pkt; +} + +static const core_object_t* _produce_block(output_udpcli_t* self) +{ + ssize_t n; + struct pollfd p; + int to; + mlassert_self(); + + p.fd = self->fd; + p.events = POLLIN; + p.revents = 0; + to = (self->timeout.sec * 1e3) + (self->timeout.nsec / 1e6); //NOSONAR + if (!to) { + to = 1; + } + + n = poll(&p, 1, to); + if (n < 0 || (p.revents & (POLLERR | POLLHUP | POLLNVAL))) { + self->errs++; + return 0; + } + if (!n || !(p.revents & POLLIN)) { + self->pkt.len = 0; + return (core_object_t*)&self->pkt; + } + + for (;;) { + n = recvfrom(self->fd, self->recvbuf, sizeof(self->recvbuf), 0, 0, 0); + if (n > -1) { + break; + } + switch (errno) { + case EAGAIN: +#if EAGAIN != EWOULDBLOCK + case EWOULDBLOCK: +#endif + self->pkt.len = 0; + return (core_object_t*)&self->pkt; + default: + break; + } + self->errs++; + break; + } + + if (n < 1) { + return 0; + } + + self->pkts_recv++; + self->pkt.len = n; + return (core_object_t*)&self->pkt; +} + +core_producer_t output_udpcli_producer(output_udpcli_t* self) +{ + mlassert_self(); + + if (self->fd < 0) { + lfatal("not connected"); + } + + if (self->blocking) { + return (core_producer_t)_produce_block; + } + return (core_producer_t)_produce; +} diff --git a/include/dnsjit/output/udpcli.h b/include/dnsjit/output/udpcli.h new file mode 100644 index 0000000..f783642 --- /dev/null +++ b/include/dnsjit/output/udpcli.h @@ -0,0 +1,35 @@ +/* + * 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/payload.h> +#include <dnsjit/core/timespec.h> + +#ifndef __dnsjit_output_udpcli_h +#define __dnsjit_output_udpcli_h + +#include <sys/types.h> +#include <sys/socket.h> + +#include <dnsjit/output/udpcli.hh> + +#endif diff --git a/include/dnsjit/output/udpcli.hh b/include/dnsjit/output/udpcli.hh new file mode 100644 index 0000000..084a5b6 --- /dev/null +++ b/include/dnsjit/output/udpcli.hh @@ -0,0 +1,53 @@ +/* + * 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.compat_h") +//lua:require("dnsjit.core.log") +//lua:require("dnsjit.core.receiver_h") +//lua:require("dnsjit.core.producer_h") +//lua:require("dnsjit.core.object.payload_h") +//lua:require("dnsjit.core.timespec_h") + +typedef struct output_udpcli { + core_log_t _log; + size_t pkts, errs; + int fd; + + struct sockaddr_storage addr; + size_t addr_len; + + uint8_t recvbuf[4 * 1024]; + core_object_payload_t pkt; + size_t pkts_recv; + + core_timespec_t timeout; + int8_t blocking; +} output_udpcli_t; + +core_log_t* output_udpcli_log(); + +void output_udpcli_init(output_udpcli_t* self); +void output_udpcli_destroy(output_udpcli_t* self); +int output_udpcli_connect(output_udpcli_t* self, const char* host, const char* port); +int output_udpcli_nonblocking(output_udpcli_t* self); +int output_udpcli_set_nonblocking(output_udpcli_t* self, int nonblocking); + +core_receiver_t output_udpcli_receiver(output_udpcli_t* self); +core_producer_t output_udpcli_producer(output_udpcli_t* self); diff --git a/include/dnsjit/output/udpcli.lua b/include/dnsjit/output/udpcli.lua new file mode 100644 index 0000000..0584725 --- /dev/null +++ b/include/dnsjit/output/udpcli.lua @@ -0,0 +1,121 @@ +-- 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.output.udpcli +-- Simple and dumb UDP DNS client +-- local output = require("dnsjit.output.udpcli").new("127.0.0.1", "53") +-- +-- Simple and rather dumb DNS client that takes any payload you give it and +-- sends the full payload over UDP. +-- .SS Attributes +-- .TP +-- timeout +-- A +-- .I core.timespec +-- that is used when producing objects. +module(...,package.seeall) + +require("dnsjit.output.udpcli_h") +local ffi = require("ffi") +local C = ffi.C + +local t_name = "output_udpcli_t" +local output_udpcli_t = ffi.typeof(t_name) +local Udpcli = {} + +-- Create a new Udpcli output. +function Udpcli.new() + local self = { + obj = output_udpcli_t(), + } + C.output_udpcli_init(self.obj) + ffi.gc(self.obj, C.output_udpcli_destroy) + return setmetatable(self, { __index = Udpcli }) +end + +-- Set the timeout when producing objects. +function Udpcli:timeout(seconds, nanoseconds) + self.obj.timeout.sec = seconds + self.obj.timeout.nsec = nanoseconds +end + +-- Connect to the +-- .I host +-- and +-- .I port +-- and return 0 if successful. +function Udpcli:connect(host, port) + return C.output_udpcli_connect(self.obj, host, port) +end + +-- Enable (true) or disable (false) nonblocking mode and +-- return 0 if successful, if +-- .I bool +-- is not specified then return if nonblocking mode is on (true) or off (false). +function Udpcli:nonblocking(bool) + if bool == nil then + if C.output_udpcli_nonblocking(self.obj) == 1 then + return true + end + return false + elseif bool == true then + return C.output_udpcli_set_nonblocking(self.obj, 1) + else + return C.output_udpcli_set_nonblocking(self.obj, 0) + end +end + +-- Return the C functions and context for receiving objects, these objects +-- will be sent. +function Udpcli:receive() + return C.output_udpcli_receiver(self.obj), self.obj +end + +-- Return the C functions and context for producing objects, these objects +-- are received. +-- If nonblocking mode is enabled the producer will return a payload object +-- with length zero if there was nothing to receive. +-- If nonblocking mode is disabled the producer will wait for data and if +-- timed out (see +-- .IR timeout ) +-- it will return a payload object with length zero. +-- The producer returns nil on error. +function Udpcli:produce() + return C.output_udpcli_producer(self.obj), self.obj +end + +-- Return the number of "packets" sent, actually the number of completely sent +-- payloads. +function Udpcli:packets() + return tonumber(self.obj.pkts) +end + +-- Return the number of "packets" received, actually the number of successful +-- calls to +-- .IR recvfrom (2) +-- that returned data. +function Udpcli:received() + return tonumber(self.obj.pkts_recv) +end + +-- Return the number of errors when sending or receiving. +function Udpcli:errors() + return tonumber(self.obj.errs) +end + +return Udpcli diff --git a/include/dnsjit/test/Makefile.am b/include/dnsjit/test/Makefile.am new file mode 100644 index 0000000..0556db6 --- /dev/null +++ b/include/dnsjit/test/Makefile.am @@ -0,0 +1,52 @@ +# 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 = 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 + +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 "$<" "$@" + +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 diff --git a/include/dnsjit/test/Makefile.in b/include/dnsjit/test/Makefile.in new file mode 100644 index 0000000..b03a826 --- /dev/null +++ b/include/dnsjit/test/Makefile.in @@ -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='[0;31m'; \ + grn='[0;32m'; \ + lgn='[1;32m'; \ + blu='[1;34m'; \ + mgn='[0;35m'; \ + brg='[1m'; \ + std='[m'; \ + 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: diff --git a/include/dnsjit/test/dns.pcap b/include/dnsjit/test/dns.pcap Binary files differnew file mode 100644 index 0000000..a0e585c --- /dev/null +++ b/include/dnsjit/test/dns.pcap diff --git a/include/dnsjit/test/dns.pcap.lz4 b/include/dnsjit/test/dns.pcap.lz4 Binary files differnew file mode 100644 index 0000000..d042863 --- /dev/null +++ b/include/dnsjit/test/dns.pcap.lz4 diff --git a/include/dnsjit/test/dns.pcap.zst b/include/dnsjit/test/dns.pcap.zst Binary files differnew file mode 100644 index 0000000..07b43c0 --- /dev/null +++ b/include/dnsjit/test/dns.pcap.zst diff --git a/include/dnsjit/test/pellets.pcap b/include/dnsjit/test/pellets.pcap Binary files differnew file mode 100644 index 0000000..ef39a7b --- /dev/null +++ b/include/dnsjit/test/pellets.pcap diff --git a/include/dnsjit/test/test-base64url.sh b/include/dnsjit/test/test-base64url.sh new file mode 100755 index 0000000..163f847 --- /dev/null +++ b/include/dnsjit/test/test-base64url.sh @@ -0,0 +1,20 @@ +#!/bin/sh -e +# 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/>. + +../dnsjit "$srcdir/test_base64url.lua" diff --git a/include/dnsjit/test/test-ipsplit.sh b/include/dnsjit/test/test-ipsplit.sh new file mode 100755 index 0000000..3d118d6 --- /dev/null +++ b/include/dnsjit/test/test-ipsplit.sh @@ -0,0 +1,20 @@ +#!/bin/sh -e +# 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/>. + +../dnsjit "$srcdir/test_ipsplit.lua" diff --git a/include/dnsjit/test/test-trie.sh b/include/dnsjit/test/test-trie.sh new file mode 100755 index 0000000..238eea1 --- /dev/null +++ b/include/dnsjit/test/test-trie.sh @@ -0,0 +1,20 @@ +#!/bin/sh -e +# 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/>. + +../dnsjit "$srcdir/test_trie.lua" diff --git a/include/dnsjit/test/test1.gold b/include/dnsjit/test/test1.gold new file mode 100644 index 0000000..7ded214 --- /dev/null +++ b/include/dnsjit/test/test1.gold @@ -0,0 +1,1493 @@ +udp 172.17.0.10:53199 -> 8.8.8.8:53 +id: 59311 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN A <12>google.<19>com. +udp 8.8.8.8:53 -> 172.17.0.10:53199 +id: 59311 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 1 + nscount: 4 + arcount: 4 +questions: class type labels + IN A <12>google.<19>com. +answers: class type ttl labels RR labels + IN A 44 <12> +authorities: class type ttl labels RR labels + IN NS 157880 <12> <56>ns4.<12> + IN NS 157880 <12> <74>ns3.<12> + IN NS 157880 <12> <92>ns1.<12> + IN NS 157880 <12> <110>ns2.<12> +additionals: class type ttl labels RR labels + IN A 157880 <110> + IN A 331882 <92> + IN A 157880 <74> + IN A 157880 <56> +udp 172.17.0.10:57822 -> 8.8.8.8:53 +id: 35665 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +udp 8.8.8.8:53 -> 172.17.0.10:57822 +id: 35665 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 2 + nscount: 4 + arcount: 4 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +answers: class type ttl labels RR labels + IN PTR 72125 <12> <57>dfw06s47-in-f14.<73>1e100.<79>net. + IN PTR 72125 <12> <96>dfw06s47-in-f206.<73> +authorities: class type ttl labels RR labels + IN NS 71608 <16> <127>ns2.<131>google.<138>com. + IN NS 71608 <16> <155>ns3.<131> + IN NS 71608 <16> <173>ns1.<131> + IN NS 71608 <16> <191>ns4.<131> +additionals: class type ttl labels RR labels + IN A 331882 <173> + IN A 157880 <155> + IN A 157880 <191> + IN A 157880 <127> +udp 172.17.0.10:40043 -> 8.8.8.8:53 +id: 5337 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN A <12>google.<19>com. +udp 8.8.8.8:53 -> 172.17.0.10:40043 +id: 5337 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 1 + nscount: 4 + arcount: 4 +questions: class type labels + IN A <12>google.<19>com. +answers: class type ttl labels RR labels + IN A 44 <12> +authorities: class type ttl labels RR labels + IN NS 157880 <12> <56>ns1.<12> + IN NS 157880 <12> <74>ns2.<12> + IN NS 157880 <12> <92>ns3.<12> + IN NS 157880 <12> <110>ns4.<12> +additionals: class type ttl labels RR labels + IN A 157880 <74> + IN A 331882 <56> + IN A 157880 <92> + IN A 157880 <110> +udp 172.17.0.10:37953 -> 8.8.8.8:53 +id: 22982 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN A <12>google.<19>com. +udp 8.8.8.8:53 -> 172.17.0.10:37953 +id: 22982 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 1 + nscount: 4 + arcount: 4 +questions: class type labels + IN A <12>google.<19>com. +answers: class type ttl labels RR labels + IN A 34 <12> +authorities: class type ttl labels RR labels + IN NS 157870 <12> <56>ns4.<12> + IN NS 157870 <12> <74>ns1.<12> + IN NS 157870 <12> <92>ns2.<12> + IN NS 157870 <12> <110>ns3.<12> +additionals: class type ttl labels RR labels + IN A 157870 <92> + IN A 331872 <74> + IN A 157870 <110> + IN A 157870 <56> +udp 172.17.0.10:48658 -> 8.8.8.8:53 +id: 18718 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +udp 8.8.8.8:53 -> 172.17.0.10:48658 +id: 18718 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 2 + nscount: 4 + arcount: 4 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +answers: class type ttl labels RR labels + IN PTR 72115 <12> <57>dfw06s47-in-f206.<74>1e100.<80>net. + IN PTR 72115 <12> <97>dfw06s47-in-f14.<74> +authorities: class type ttl labels RR labels + IN NS 71598 <16> <127>ns2.<131>google.<138>com. + IN NS 71598 <16> <155>ns3.<131> + IN NS 71598 <16> <173>ns4.<131> + IN NS 71598 <16> <191>ns1.<131> +additionals: class type ttl labels RR labels + IN A 331872 <191> + IN A 157870 <155> + IN A 157870 <173> + IN A 157870 <127> +udp 172.17.0.10:40953 -> 8.8.8.8:53 +id: 22531 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN A <12>google.<19>com. +udp 8.8.8.8:53 -> 172.17.0.10:40953 +id: 22531 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 1 + nscount: 4 + arcount: 4 +questions: class type labels + IN A <12>google.<19>com. +answers: class type ttl labels RR labels + IN A 297 <12> +authorities: class type ttl labels RR labels + IN NS 157828 <12> <56>ns2.<12> + IN NS 157828 <12> <74>ns4.<12> + IN NS 157828 <12> <92>ns1.<12> + IN NS 157828 <12> <110>ns3.<12> +additionals: class type ttl labels RR labels + IN A 157828 <56> + IN A 331830 <92> + IN A 157828 <110> + IN A 157828 <74> +udp 172.17.0.10:45174 -> 8.8.8.8:53 +id: 58510 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN A <12>google.<19>com. +udp 8.8.8.8:53 -> 172.17.0.10:45174 +id: 58510 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 1 + nscount: 4 + arcount: 4 +questions: class type labels + IN A <12>google.<19>com. +answers: class type ttl labels RR labels + IN A 291 <12> +authorities: class type ttl labels RR labels + IN NS 157822 <12> <56>ns2.<12> + IN NS 157822 <12> <74>ns3.<12> + IN NS 157822 <12> <92>ns1.<12> + IN NS 157822 <12> <110>ns4.<12> +additionals: class type ttl labels RR labels + IN A 157822 <56> + IN A 331824 <92> + IN A 157822 <74> + IN A 157822 <110> +udp 172.17.0.10:33916 -> 8.8.8.8:53 +id: 45248 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +udp 8.8.8.8:53 -> 172.17.0.10:33916 +id: 45248 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 2 + nscount: 4 + arcount: 4 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +answers: class type ttl labels RR labels + IN PTR 72067 <12> <57>dfw06s47-in-f14.<73>1e100.<79>net. + IN PTR 72067 <12> <96>dfw06s47-in-f206.<73> +authorities: class type ttl labels RR labels + IN NS 71550 <16> <127>ns3.<131>google.<138>com. + IN NS 71550 <16> <155>ns4.<131> + IN NS 71550 <16> <173>ns2.<131> + IN NS 71550 <16> <191>ns1.<131> +additionals: class type ttl labels RR labels + IN A 331824 <191> + IN A 157822 <127> + IN A 157822 <155> + IN A 157822 <173> +udp 172.17.0.10:43559 -> 8.8.8.8:53 +id: 49483 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN A <12>google.<19>com. +udp 8.8.8.8:53 -> 172.17.0.10:43559 +id: 49483 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 1 + nscount: 4 + arcount: 4 +questions: class type labels + IN A <12>google.<19>com. +answers: class type ttl labels RR labels + IN A 285 <12> +authorities: class type ttl labels RR labels + IN NS 157816 <12> <56>ns4.<12> + IN NS 157816 <12> <74>ns3.<12> + IN NS 157816 <12> <92>ns1.<12> + IN NS 157816 <12> <110>ns2.<12> +additionals: class type ttl labels RR labels + IN A 157816 <110> + IN A 331818 <92> + IN A 157816 <74> + IN A 157816 <56> +udp 172.17.0.10:54859 -> 8.8.8.8:53 +id: 31669 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN A <12>google.<19>com. +udp 8.8.8.8:53 -> 172.17.0.10:54859 +id: 31669 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 1 + nscount: 4 + arcount: 4 +questions: class type labels + IN A <12>google.<19>com. +answers: class type ttl labels RR labels + IN A 283 <12> +authorities: class type ttl labels RR labels + IN NS 157814 <12> <56>ns2.<12> + IN NS 157814 <12> <74>ns1.<12> + IN NS 157814 <12> <92>ns4.<12> + IN NS 157814 <12> <110>ns3.<12> +additionals: class type ttl labels RR labels + IN A 157814 <56> + IN A 331816 <74> + IN A 157814 <110> + IN A 157814 <92> +udp 172.17.0.10:58176 -> 8.8.8.8:53 +id: 25433 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +udp 8.8.8.8:53 -> 172.17.0.10:58176 +id: 25433 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 2 + nscount: 4 + arcount: 4 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +answers: class type ttl labels RR labels + IN PTR 72059 <12> <57>dfw06s47-in-f206.<74>1e100.<80>net. + IN PTR 72059 <12> <97>dfw06s47-in-f14.<74> +authorities: class type ttl labels RR labels + IN NS 71542 <16> <127>ns4.<131>google.<138>com. + IN NS 71542 <16> <155>ns1.<131> + IN NS 71542 <16> <173>ns3.<131> + IN NS 71542 <16> <191>ns2.<131> +additionals: class type ttl labels RR labels + IN A 331816 <155> + IN A 157814 <173> + IN A 157814 <127> + IN A 157814 <191> +udp 172.17.0.10:41266 -> 8.8.8.8:53 +id: 63798 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN A <12>google.<19>com. +udp 8.8.8.8:53 -> 172.17.0.10:41266 +id: 63798 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 1 + nscount: 4 + arcount: 4 +questions: class type labels + IN A <12>google.<19>com. +answers: class type ttl labels RR labels + IN A 282 <12> +authorities: class type ttl labels RR labels + IN NS 157813 <12> <56>ns4.<12> + IN NS 157813 <12> <74>ns1.<12> + IN NS 157813 <12> <92>ns3.<12> + IN NS 157813 <12> <110>ns2.<12> +additionals: class type ttl labels RR labels + IN A 157813 <110> + IN A 331815 <74> + IN A 157813 <92> + IN A 157813 <56> +udp 172.17.0.10:34607 -> 8.8.8.8:53 +id: 8470 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +udp 8.8.8.8:53 -> 172.17.0.10:34607 +id: 8470 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 2 + nscount: 4 + arcount: 4 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +answers: class type ttl labels RR labels + IN PTR 72058 <12> <57>dfw06s47-in-f14.<73>1e100.<79>net. + IN PTR 72058 <12> <96>dfw06s47-in-f206.<73> +authorities: class type ttl labels RR labels + IN NS 71541 <16> <127>ns1.<131>google.<138>com. + IN NS 71541 <16> <155>ns2.<131> + IN NS 71541 <16> <173>ns4.<131> + IN NS 71541 <16> <191>ns3.<131> +additionals: class type ttl labels RR labels + IN A 331815 <127> + IN A 157813 <191> + IN A 157813 <173> + IN A 157813 <155> +udp 172.17.0.10:60437 -> 8.8.8.8:53 +id: 60258 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN A <12>google.<19>com. +udp 8.8.8.8:53 -> 172.17.0.10:60437 +id: 60258 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 1 + nscount: 4 + arcount: 4 +questions: class type labels + IN A <12>google.<19>com. +answers: class type ttl labels RR labels + IN A 281 <12> +authorities: class type ttl labels RR labels + IN NS 157812 <12> <56>ns3.<12> + IN NS 157812 <12> <74>ns2.<12> + IN NS 157812 <12> <92>ns4.<12> + IN NS 157812 <12> <110>ns1.<12> +additionals: class type ttl labels RR labels + IN A 157812 <74> + IN A 331814 <110> + IN A 157812 <56> + IN A 157812 <92> +udp 172.17.0.10:37149 -> 8.8.8.8:53 +id: 44985 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +udp 8.8.8.8:53 -> 172.17.0.10:37149 +id: 44985 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 2 + nscount: 4 + arcount: 4 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +answers: class type ttl labels RR labels + IN PTR 72057 <12> <57>dfw06s47-in-f206.<74>1e100.<80>net. + IN PTR 72057 <12> <97>dfw06s47-in-f14.<74> +authorities: class type ttl labels RR labels + IN NS 71540 <16> <127>ns4.<131>google.<138>com. + IN NS 71540 <16> <155>ns3.<131> + IN NS 71540 <16> <173>ns1.<131> + IN NS 71540 <16> <191>ns2.<131> +additionals: class type ttl labels RR labels + IN A 331814 <173> + IN A 157812 <155> + IN A 157812 <127> + IN A 157812 <191> +udp 172.17.0.10:53820 -> 8.8.8.8:53 +id: 45512 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN A <12>google.<19>com. +udp 8.8.8.8:53 -> 172.17.0.10:53820 +id: 45512 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 1 + nscount: 4 + arcount: 4 +questions: class type labels + IN A <12>google.<19>com. +answers: class type ttl labels RR labels + IN A 280 <12> +authorities: class type ttl labels RR labels + IN NS 157811 <12> <56>ns3.<12> + IN NS 157811 <12> <74>ns4.<12> + IN NS 157811 <12> <92>ns1.<12> + IN NS 157811 <12> <110>ns2.<12> +additionals: class type ttl labels RR labels + IN A 157811 <110> + IN A 331813 <92> + IN A 157811 <56> + IN A 157811 <74> +udp 172.17.0.10:52368 -> 8.8.8.8:53 +id: 22980 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +udp 8.8.8.8:53 -> 172.17.0.10:52368 +id: 22980 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 2 + nscount: 4 + arcount: 4 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +answers: class type ttl labels RR labels + IN PTR 72056 <12> <57>dfw06s47-in-f14.<73>1e100.<79>net. + IN PTR 72056 <12> <96>dfw06s47-in-f206.<73> +authorities: class type ttl labels RR labels + IN NS 71539 <16> <127>ns2.<131>google.<138>com. + IN NS 71539 <16> <155>ns3.<131> + IN NS 71539 <16> <173>ns4.<131> + IN NS 71539 <16> <191>ns1.<131> +additionals: class type ttl labels RR labels + IN A 331813 <191> + IN A 157811 <155> + IN A 157811 <173> + IN A 157811 <127> +udp 172.17.0.10:47637 -> 8.8.8.8:53 +id: 1834 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN A <12>google.<19>com. +udp 8.8.8.8:53 -> 172.17.0.10:47637 +id: 1834 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 1 + nscount: 4 + arcount: 4 +questions: class type labels + IN A <12>google.<19>com. +answers: class type ttl labels RR labels + IN A 279 <12> +authorities: class type ttl labels RR labels + IN NS 157810 <12> <56>ns1.<12> + IN NS 157810 <12> <74>ns2.<12> + IN NS 157810 <12> <92>ns4.<12> + IN NS 157810 <12> <110>ns3.<12> +additionals: class type ttl labels RR labels + IN A 157810 <74> + IN A 331812 <56> + IN A 157810 <110> + IN A 157810 <92> +udp 172.17.0.10:34426 -> 8.8.8.8:53 +id: 25431 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +udp 8.8.8.8:53 -> 172.17.0.10:34426 +id: 25431 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 2 + nscount: 4 + arcount: 4 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +answers: class type ttl labels RR labels + IN PTR 72055 <12> <57>dfw06s47-in-f206.<74>1e100.<80>net. + IN PTR 72055 <12> <97>dfw06s47-in-f14.<74> +authorities: class type ttl labels RR labels + IN NS 71538 <16> <127>ns1.<131>google.<138>com. + IN NS 71538 <16> <155>ns4.<131> + IN NS 71538 <16> <173>ns3.<131> + IN NS 71538 <16> <191>ns2.<131> +additionals: class type ttl labels RR labels + IN A 331812 <127> + IN A 157810 <173> + IN A 157810 <155> + IN A 157810 <191> +udp 172.17.0.10:41059 -> 8.8.8.8:53 +id: 48432 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN A <12>google.<19>com. +udp 8.8.8.8:53 -> 172.17.0.10:41059 +id: 48432 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 1 + nscount: 4 + arcount: 4 +questions: class type labels + IN A <12>google.<19>com. +answers: class type ttl labels RR labels + IN A 278 <12> +authorities: class type ttl labels RR labels + IN NS 157809 <12> <56>ns3.<12> + IN NS 157809 <12> <74>ns4.<12> + IN NS 157809 <12> <92>ns2.<12> + IN NS 157809 <12> <110>ns1.<12> +additionals: class type ttl labels RR labels + IN A 157809 <92> + IN A 331811 <110> + IN A 157809 <56> + IN A 157809 <74> +udp 172.17.0.10:51181 -> 8.8.8.8:53 +id: 47411 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +udp 8.8.8.8:53 -> 172.17.0.10:51181 +id: 47411 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 2 + nscount: 4 + arcount: 4 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +answers: class type ttl labels RR labels + IN PTR 72054 <12> <57>dfw06s47-in-f14.<73>1e100.<79>net. + IN PTR 72054 <12> <96>dfw06s47-in-f206.<73> +authorities: class type ttl labels RR labels + IN NS 71537 <16> <127>ns2.<131>google.<138>com. + IN NS 71537 <16> <155>ns1.<131> + IN NS 71537 <16> <173>ns3.<131> + IN NS 71537 <16> <191>ns4.<131> +additionals: class type ttl labels RR labels + IN A 331811 <155> + IN A 157809 <173> + IN A 157809 <191> + IN A 157809 <127> +udp 172.17.0.10:32976 -> 8.8.8.8:53 +id: 12038 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN A <12>google.<19>com. +udp 8.8.8.8:53 -> 172.17.0.10:32976 +id: 12038 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 1 + nscount: 4 + arcount: 4 +questions: class type labels + IN A <12>google.<19>com. +answers: class type ttl labels RR labels + IN A 277 <12> +authorities: class type ttl labels RR labels + IN NS 157808 <12> <56>ns2.<12> + IN NS 157808 <12> <74>ns3.<12> + IN NS 157808 <12> <92>ns1.<12> + IN NS 157808 <12> <110>ns4.<12> +additionals: class type ttl labels RR labels + IN A 157808 <56> + IN A 331810 <92> + IN A 157808 <74> + IN A 157808 <110> +udp 172.17.0.10:53467 -> 8.8.8.8:53 +id: 11614 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN A <12>google.<19>com. +udp 8.8.8.8:53 -> 172.17.0.10:53467 +id: 11614 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 1 + nscount: 4 + arcount: 4 +questions: class type labels + IN A <12>google.<19>com. +answers: class type ttl labels RR labels + IN A 275 <12> +authorities: class type ttl labels RR labels + IN NS 157806 <12> <56>ns3.<12> + IN NS 157806 <12> <74>ns1.<12> + IN NS 157806 <12> <92>ns4.<12> + IN NS 157806 <12> <110>ns2.<12> +additionals: class type ttl labels RR labels + IN A 157806 <110> + IN A 331808 <74> + IN A 157806 <56> + IN A 157806 <92> +udp 172.17.0.10:41532 -> 8.8.8.8:53 +id: 59173 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN A <12>google.<19>com. +udp 8.8.8.8:53 -> 172.17.0.10:41532 +id: 59173 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 1 + nscount: 4 + arcount: 4 +questions: class type labels + IN A <12>google.<19>com. +answers: class type ttl labels RR labels + IN A 273 <12> +authorities: class type ttl labels RR labels + IN NS 157804 <12> <56>ns1.<12> + IN NS 157804 <12> <74>ns3.<12> + IN NS 157804 <12> <92>ns2.<12> + IN NS 157804 <12> <110>ns4.<12> +additionals: class type ttl labels RR labels + IN A 157804 <92> + IN A 331806 <56> + IN A 157804 <74> + IN A 157804 <110> +udp 172.17.0.10:44982 -> 8.8.8.8:53 +id: 45535 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN A <12>google.<19>com. +udp 8.8.8.8:53 -> 172.17.0.10:44982 +id: 45535 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 1 + nscount: 4 + arcount: 4 +questions: class type labels + IN A <12>google.<19>com. +answers: class type ttl labels RR labels + IN A 271 <12> +authorities: class type ttl labels RR labels + IN NS 157802 <12> <56>ns4.<12> + IN NS 157802 <12> <74>ns2.<12> + IN NS 157802 <12> <92>ns1.<12> + IN NS 157802 <12> <110>ns3.<12> +additionals: class type ttl labels RR labels + IN A 157802 <74> + IN A 331804 <92> + IN A 157802 <110> + IN A 157802 <56> +udp 172.17.0.10:40224 -> 8.8.8.8:53 +id: 60808 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +udp 8.8.8.8:53 -> 172.17.0.10:40224 +id: 60808 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 2 + nscount: 4 + arcount: 4 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +answers: class type ttl labels RR labels + IN PTR 72047 <12> <57>dfw06s47-in-f206.<74>1e100.<80>net. + IN PTR 72047 <12> <97>dfw06s47-in-f14.<74> +authorities: class type ttl labels RR labels + IN NS 71530 <16> <127>ns3.<131>google.<138>com. + IN NS 71530 <16> <155>ns4.<131> + IN NS 71530 <16> <173>ns2.<131> + IN NS 71530 <16> <191>ns1.<131> +additionals: class type ttl labels RR labels + IN A 331804 <191> + IN A 157802 <127> + IN A 157802 <155> + IN A 157802 <173> +udp 172.17.0.10:45658 -> 8.8.8.8:53 +id: 64325 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN A <12>google.<19>com. +udp 8.8.8.8:53 -> 172.17.0.10:45658 +id: 64325 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 1 + nscount: 4 + arcount: 4 +questions: class type labels + IN A <12>google.<19>com. +answers: class type ttl labels RR labels + IN A 270 <12> +authorities: class type ttl labels RR labels + IN NS 157801 <12> <56>ns1.<12> + IN NS 157801 <12> <74>ns3.<12> + IN NS 157801 <12> <92>ns4.<12> + IN NS 157801 <12> <110>ns2.<12> +additionals: class type ttl labels RR labels + IN A 157801 <110> + IN A 331803 <56> + IN A 157801 <74> + IN A 157801 <92> +udp 172.17.0.10:60457 -> 8.8.8.8:53 +id: 25543 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +udp 8.8.8.8:53 -> 172.17.0.10:60457 +id: 25543 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 2 + nscount: 4 + arcount: 4 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +answers: class type ttl labels RR labels + IN PTR 72046 <12> <57>dfw06s47-in-f14.<73>1e100.<79>net. + IN PTR 72046 <12> <96>dfw06s47-in-f206.<73> +authorities: class type ttl labels RR labels + IN NS 71529 <16> <127>ns2.<131>google.<138>com. + IN NS 71529 <16> <155>ns3.<131> + IN NS 71529 <16> <173>ns4.<131> + IN NS 71529 <16> <191>ns1.<131> +additionals: class type ttl labels RR labels + IN A 331803 <191> + IN A 157801 <155> + IN A 157801 <173> + IN A 157801 <127> +udp 172.17.0.10:59762 -> 8.8.8.8:53 +id: 20736 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN A <12>google.<19>com. +udp 8.8.8.8:53 -> 172.17.0.10:59762 +id: 20736 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 1 + nscount: 4 + arcount: 4 +questions: class type labels + IN A <12>google.<19>com. +answers: class type ttl labels RR labels + IN A 269 <12> +authorities: class type ttl labels RR labels + IN NS 157800 <12> <56>ns3.<12> + IN NS 157800 <12> <74>ns1.<12> + IN NS 157800 <12> <92>ns4.<12> + IN NS 157800 <12> <110>ns2.<12> +additionals: class type ttl labels RR labels + IN A 157800 <110> + IN A 331802 <74> + IN A 157800 <56> + IN A 157800 <92> +udp 172.17.0.10:56022 -> 8.8.8.8:53 +id: 25911 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +udp 8.8.8.8:53 -> 172.17.0.10:56022 +id: 25911 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 2 + nscount: 4 + arcount: 4 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +answers: class type ttl labels RR labels + IN PTR 72045 <12> <57>dfw06s47-in-f206.<74>1e100.<80>net. + IN PTR 72045 <12> <97>dfw06s47-in-f14.<74> +authorities: class type ttl labels RR labels + IN NS 71528 <16> <127>ns1.<131>google.<138>com. + IN NS 71528 <16> <155>ns4.<131> + IN NS 71528 <16> <173>ns2.<131> + IN NS 71528 <16> <191>ns3.<131> +additionals: class type ttl labels RR labels + IN A 331802 <127> + IN A 157800 <191> + IN A 157800 <155> + IN A 157800 <173> +udp 172.17.0.10:37669 -> 8.8.8.8:53 +id: 64358 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN A <12>google.<19>com. +udp 8.8.8.8:53 -> 172.17.0.10:37669 +id: 64358 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 1 + nscount: 4 + arcount: 4 +questions: class type labels + IN A <12>google.<19>com. +answers: class type ttl labels RR labels + IN A 268 <12> +authorities: class type ttl labels RR labels + IN NS 157799 <12> <56>ns2.<12> + IN NS 157799 <12> <74>ns1.<12> + IN NS 157799 <12> <92>ns4.<12> + IN NS 157799 <12> <110>ns3.<12> +additionals: class type ttl labels RR labels + IN A 157799 <56> + IN A 331801 <74> + IN A 157799 <110> + IN A 157799 <92> +udp 172.17.0.10:42978 -> 8.8.8.8:53 +id: 37698 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +udp 8.8.8.8:53 -> 172.17.0.10:42978 +id: 37698 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 2 + nscount: 4 + arcount: 4 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +answers: class type ttl labels RR labels + IN PTR 72044 <12> <57>dfw06s47-in-f14.<73>1e100.<79>net. + IN PTR 72044 <12> <96>dfw06s47-in-f206.<73> +authorities: class type ttl labels RR labels + IN NS 71527 <16> <127>ns1.<131>google.<138>com. + IN NS 71527 <16> <155>ns4.<131> + IN NS 71527 <16> <173>ns3.<131> + IN NS 71527 <16> <191>ns2.<131> +additionals: class type ttl labels RR labels + IN A 331801 <127> + IN A 157799 <173> + IN A 157799 <155> + IN A 157799 <191> +udp 172.17.0.10:49829 -> 8.8.8.8:53 +id: 54706 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN A <12>google.<19>com. +udp 8.8.8.8:53 -> 172.17.0.10:49829 +id: 54706 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 1 + nscount: 4 + arcount: 4 +questions: class type labels + IN A <12>google.<19>com. +answers: class type ttl labels RR labels + IN A 267 <12> +authorities: class type ttl labels RR labels + IN NS 157798 <12> <56>ns2.<12> + IN NS 157798 <12> <74>ns4.<12> + IN NS 157798 <12> <92>ns3.<12> + IN NS 157798 <12> <110>ns1.<12> +additionals: class type ttl labels RR labels + IN A 157798 <56> + IN A 331800 <110> + IN A 157798 <92> + IN A 157798 <74> +udp 172.17.0.10:50599 -> 8.8.8.8:53 +id: 32142 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +udp 8.8.8.8:53 -> 172.17.0.10:50599 +id: 32142 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 2 + nscount: 4 + arcount: 4 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +answers: class type ttl labels RR labels + IN PTR 72043 <12> <57>dfw06s47-in-f206.<74>1e100.<80>net. + IN PTR 72043 <12> <97>dfw06s47-in-f14.<74> +authorities: class type ttl labels RR labels + IN NS 71526 <16> <127>ns3.<131>google.<138>com. + IN NS 71526 <16> <155>ns1.<131> + IN NS 71526 <16> <173>ns2.<131> + IN NS 71526 <16> <191>ns4.<131> +additionals: class type ttl labels RR labels + IN A 331800 <155> + IN A 157798 <127> + IN A 157798 <191> + IN A 157798 <173> +udp 172.17.0.10:44980 -> 8.8.8.8:53 +id: 41808 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN A <12>google.<19>com. +udp 8.8.8.8:53 -> 172.17.0.10:44980 +id: 41808 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 1 + nscount: 4 + arcount: 4 +questions: class type labels + IN A <12>google.<19>com. +answers: class type ttl labels RR labels + IN A 266 <12> +authorities: class type ttl labels RR labels + IN NS 157797 <12> <56>ns2.<12> + IN NS 157797 <12> <74>ns4.<12> + IN NS 157797 <12> <92>ns1.<12> + IN NS 157797 <12> <110>ns3.<12> +additionals: class type ttl labels RR labels + IN A 157797 <56> + IN A 331799 <92> + IN A 157797 <110> + IN A 157797 <74> +udp 172.17.0.10:60063 -> 8.8.8.8:53 +id: 18886 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +udp 8.8.8.8:53 -> 172.17.0.10:60063 +id: 18886 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 2 + nscount: 4 + arcount: 4 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +answers: class type ttl labels RR labels + IN PTR 72042 <12> <57>dfw06s47-in-f14.<73>1e100.<79>net. + IN PTR 72042 <12> <96>dfw06s47-in-f206.<73> +authorities: class type ttl labels RR labels + IN NS 71525 <16> <127>ns3.<131>google.<138>com. + IN NS 71525 <16> <155>ns1.<131> + IN NS 71525 <16> <173>ns4.<131> + IN NS 71525 <16> <191>ns2.<131> +additionals: class type ttl labels RR labels + IN A 331799 <155> + IN A 157797 <127> + IN A 157797 <173> + IN A 157797 <191> +udp 172.17.0.10:42042 -> 8.8.8.8:53 +id: 10624 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN A <12>google.<19>com. +udp 8.8.8.8:53 -> 172.17.0.10:42042 +id: 10624 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 1 + nscount: 4 + arcount: 4 +questions: class type labels + IN A <12>google.<19>com. +answers: class type ttl labels RR labels + IN A 265 <12> +authorities: class type ttl labels RR labels + IN NS 157796 <12> <56>ns3.<12> + IN NS 157796 <12> <74>ns4.<12> + IN NS 157796 <12> <92>ns1.<12> + IN NS 157796 <12> <110>ns2.<12> +additionals: class type ttl labels RR labels + IN A 157796 <110> + IN A 331798 <92> + IN A 157796 <56> + IN A 157796 <74> +udp 172.17.0.10:60469 -> 8.8.8.8:53 +id: 33139 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +udp 8.8.8.8:53 -> 172.17.0.10:60469 +id: 33139 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 2 + nscount: 4 + arcount: 4 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +answers: class type ttl labels RR labels + IN PTR 72041 <12> <57>dfw06s47-in-f206.<74>1e100.<80>net. + IN PTR 72041 <12> <97>dfw06s47-in-f14.<74> +authorities: class type ttl labels RR labels + IN NS 71524 <16> <127>ns2.<131>google.<138>com. + IN NS 71524 <16> <155>ns4.<131> + IN NS 71524 <16> <173>ns3.<131> + IN NS 71524 <16> <191>ns1.<131> +additionals: class type ttl labels RR labels + IN A 331798 <191> + IN A 157796 <173> + IN A 157796 <155> + IN A 157796 <127> +udp 172.17.0.10:45703 -> 8.8.8.8:53 +id: 61415 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN A <12>google.<19>com. +udp 8.8.8.8:53 -> 172.17.0.10:45703 +id: 61415 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 1 + nscount: 4 + arcount: 4 +questions: class type labels + IN A <12>google.<19>com. +answers: class type ttl labels RR labels + IN A 264 <12> +authorities: class type ttl labels RR labels + IN NS 157795 <12> <56>ns3.<12> + IN NS 157795 <12> <74>ns4.<12> + IN NS 157795 <12> <92>ns2.<12> + IN NS 157795 <12> <110>ns1.<12> +additionals: class type ttl labels RR labels + IN A 157795 <92> + IN A 331797 <110> + IN A 157795 <56> + IN A 157795 <74> +udp 172.17.0.10:33507 -> 8.8.8.8:53 +id: 59258 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +udp 8.8.8.8:53 -> 172.17.0.10:33507 +id: 59258 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 2 + nscount: 4 + arcount: 4 +questions: class type labels + IN PTR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. +answers: class type ttl labels RR labels + IN PTR 72040 <12> <57>dfw06s47-in-f14.<73>1e100.<79>net. + IN PTR 72040 <12> <96>dfw06s47-in-f206.<73> +authorities: class type ttl labels RR labels + IN NS 71523 <16> <127>ns1.<131>google.<138>com. + IN NS 71523 <16> <155>ns4.<131> + IN NS 71523 <16> <173>ns3.<131> + IN NS 71523 <16> <191>ns2.<131> +additionals: class type ttl labels RR labels + IN A 331797 <127> + IN A 157795 <173> + IN A 157795 <155> + IN A 157795 <191> +udp 172.17.0.10:46798 -> 8.8.8.8:53 +id: 17700 + qr: 0 + opcode: QUERY + flags: RD + rcode: NOERROR + qdcount: 1 + ancount: 0 + nscount: 0 + arcount: 0 +questions: class type labels + IN A <12>google.<19>com. +udp 8.8.8.8:53 -> 172.17.0.10:46798 +id: 17700 + qr: 1 + opcode: QUERY + flags: RD RA + rcode: NOERROR + qdcount: 1 + ancount: 1 + nscount: 4 + arcount: 4 +questions: class type labels + IN A <12>google.<19>com. +answers: class type ttl labels RR labels + IN A 263 <12> +authorities: class type ttl labels RR labels + IN NS 157794 <12> <56>ns1.<12> + IN NS 157794 <12> <74>ns4.<12> + IN NS 157794 <12> <92>ns3.<12> + IN NS 157794 <12> <110>ns2.<12> +additionals: class type ttl labels RR labels + IN A 157794 <110> + IN A 331796 <56> + IN A 157794 <92> + IN A 157794 <74> diff --git a/include/dnsjit/test/test1.sh b/include/dnsjit/test/test1.sh new file mode 100755 index 0000000..1af3a21 --- /dev/null +++ b/include/dnsjit/test/test1.sh @@ -0,0 +1,31 @@ +#!/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/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 diff --git a/include/dnsjit/test/test2.gold b/include/dnsjit/test/test2.gold new file mode 100644 index 0000000..2fb62b0 --- /dev/null +++ b/include/dnsjit/test/test2.gold @@ -0,0 +1,42 @@ +src dst id rcode qname qtype +172.17.0.10 8.8.8.8 59311 NOERROR <12>google.<19>com. A +172.17.0.10 8.8.8.8 35665 NOERROR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. PTR +172.17.0.10 8.8.8.8 5337 NOERROR <12>google.<19>com. A +172.17.0.10 8.8.8.8 22982 NOERROR <12>google.<19>com. A +172.17.0.10 8.8.8.8 18718 NOERROR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. PTR +172.17.0.10 8.8.8.8 22531 NOERROR <12>google.<19>com. A +172.17.0.10 8.8.8.8 58510 NOERROR <12>google.<19>com. A +172.17.0.10 8.8.8.8 45248 NOERROR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. PTR +172.17.0.10 8.8.8.8 49483 NOERROR <12>google.<19>com. A +172.17.0.10 8.8.8.8 31669 NOERROR <12>google.<19>com. A +172.17.0.10 8.8.8.8 25433 NOERROR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. PTR +172.17.0.10 8.8.8.8 63798 NOERROR <12>google.<19>com. A +172.17.0.10 8.8.8.8 8470 NOERROR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. PTR +172.17.0.10 8.8.8.8 60258 NOERROR <12>google.<19>com. A +172.17.0.10 8.8.8.8 44985 NOERROR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. PTR +172.17.0.10 8.8.8.8 45512 NOERROR <12>google.<19>com. A +172.17.0.10 8.8.8.8 22980 NOERROR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. PTR +172.17.0.10 8.8.8.8 1834 NOERROR <12>google.<19>com. A +172.17.0.10 8.8.8.8 25431 NOERROR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. PTR +172.17.0.10 8.8.8.8 48432 NOERROR <12>google.<19>com. A +172.17.0.10 8.8.8.8 47411 NOERROR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. PTR +172.17.0.10 8.8.8.8 12038 NOERROR <12>google.<19>com. A +172.17.0.10 8.8.8.8 11614 NOERROR <12>google.<19>com. A +172.17.0.10 8.8.8.8 59173 NOERROR <12>google.<19>com. A +172.17.0.10 8.8.8.8 45535 NOERROR <12>google.<19>com. A +172.17.0.10 8.8.8.8 60808 NOERROR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. PTR +172.17.0.10 8.8.8.8 64325 NOERROR <12>google.<19>com. A +172.17.0.10 8.8.8.8 25543 NOERROR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. PTR +172.17.0.10 8.8.8.8 20736 NOERROR <12>google.<19>com. A +172.17.0.10 8.8.8.8 25911 NOERROR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. PTR +172.17.0.10 8.8.8.8 64358 NOERROR <12>google.<19>com. A +172.17.0.10 8.8.8.8 37698 NOERROR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. PTR +172.17.0.10 8.8.8.8 54706 NOERROR <12>google.<19>com. A +172.17.0.10 8.8.8.8 32142 NOERROR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. PTR +172.17.0.10 8.8.8.8 41808 NOERROR <12>google.<19>com. A +172.17.0.10 8.8.8.8 18886 NOERROR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. PTR +172.17.0.10 8.8.8.8 10624 NOERROR <12>google.<19>com. A +172.17.0.10 8.8.8.8 33139 NOERROR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. PTR +172.17.0.10 8.8.8.8 61415 NOERROR <12>google.<19>com. A +172.17.0.10 8.8.8.8 59258 NOERROR <12>206.<16>218.<20>58.<23>216.<27>in-addr.<35>arpa. PTR +172.17.0.10 8.8.8.8 17700 NOERROR <12>google.<19>com. A diff --git a/include/dnsjit/test/test2.sh b/include/dnsjit/test/test2.sh new file mode 100755 index 0000000..9a58d06 --- /dev/null +++ b/include/dnsjit/test/test2.sh @@ -0,0 +1,21 @@ +#!/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/dumpdns-qr.lua" dns.pcap-dist >test2.out +diff "$srcdir/test2.gold" test2.out diff --git a/include/dnsjit/test/test3.gold b/include/dnsjit/test/test3.gold new file mode 100644 index 0000000..cdbd0bf --- /dev/null +++ b/include/dnsjit/test/test3.gold @@ -0,0 +1,82 @@ +59311 172.17.0.10 -> 8.8.8.8 +59311 8.8.8.8 -> 172.17.0.10 +35665 172.17.0.10 -> 8.8.8.8 +35665 8.8.8.8 -> 172.17.0.10 +5337 172.17.0.10 -> 8.8.8.8 +5337 8.8.8.8 -> 172.17.0.10 +22982 172.17.0.10 -> 8.8.8.8 +22982 8.8.8.8 -> 172.17.0.10 +18718 172.17.0.10 -> 8.8.8.8 +18718 8.8.8.8 -> 172.17.0.10 +22531 172.17.0.10 -> 8.8.8.8 +22531 8.8.8.8 -> 172.17.0.10 +58510 172.17.0.10 -> 8.8.8.8 +58510 8.8.8.8 -> 172.17.0.10 +45248 172.17.0.10 -> 8.8.8.8 +45248 8.8.8.8 -> 172.17.0.10 +49483 172.17.0.10 -> 8.8.8.8 +49483 8.8.8.8 -> 172.17.0.10 +31669 172.17.0.10 -> 8.8.8.8 +31669 8.8.8.8 -> 172.17.0.10 +25433 172.17.0.10 -> 8.8.8.8 +25433 8.8.8.8 -> 172.17.0.10 +63798 172.17.0.10 -> 8.8.8.8 +63798 8.8.8.8 -> 172.17.0.10 +8470 172.17.0.10 -> 8.8.8.8 +8470 8.8.8.8 -> 172.17.0.10 +60258 172.17.0.10 -> 8.8.8.8 +60258 8.8.8.8 -> 172.17.0.10 +44985 172.17.0.10 -> 8.8.8.8 +44985 8.8.8.8 -> 172.17.0.10 +45512 172.17.0.10 -> 8.8.8.8 +45512 8.8.8.8 -> 172.17.0.10 +22980 172.17.0.10 -> 8.8.8.8 +22980 8.8.8.8 -> 172.17.0.10 +1834 172.17.0.10 -> 8.8.8.8 +1834 8.8.8.8 -> 172.17.0.10 +25431 172.17.0.10 -> 8.8.8.8 +25431 8.8.8.8 -> 172.17.0.10 +48432 172.17.0.10 -> 8.8.8.8 +48432 8.8.8.8 -> 172.17.0.10 +47411 172.17.0.10 -> 8.8.8.8 +47411 8.8.8.8 -> 172.17.0.10 +12038 172.17.0.10 -> 8.8.8.8 +12038 8.8.8.8 -> 172.17.0.10 +11614 172.17.0.10 -> 8.8.8.8 +11614 8.8.8.8 -> 172.17.0.10 +59173 172.17.0.10 -> 8.8.8.8 +59173 8.8.8.8 -> 172.17.0.10 +45535 172.17.0.10 -> 8.8.8.8 +45535 8.8.8.8 -> 172.17.0.10 +60808 172.17.0.10 -> 8.8.8.8 +60808 8.8.8.8 -> 172.17.0.10 +64325 172.17.0.10 -> 8.8.8.8 +64325 8.8.8.8 -> 172.17.0.10 +25543 172.17.0.10 -> 8.8.8.8 +25543 8.8.8.8 -> 172.17.0.10 +20736 172.17.0.10 -> 8.8.8.8 +20736 8.8.8.8 -> 172.17.0.10 +25911 172.17.0.10 -> 8.8.8.8 +25911 8.8.8.8 -> 172.17.0.10 +64358 172.17.0.10 -> 8.8.8.8 +64358 8.8.8.8 -> 172.17.0.10 +37698 172.17.0.10 -> 8.8.8.8 +37698 8.8.8.8 -> 172.17.0.10 +54706 172.17.0.10 -> 8.8.8.8 +54706 8.8.8.8 -> 172.17.0.10 +32142 172.17.0.10 -> 8.8.8.8 +32142 8.8.8.8 -> 172.17.0.10 +41808 172.17.0.10 -> 8.8.8.8 +41808 8.8.8.8 -> 172.17.0.10 +18886 172.17.0.10 -> 8.8.8.8 +18886 8.8.8.8 -> 172.17.0.10 +10624 172.17.0.10 -> 8.8.8.8 +10624 8.8.8.8 -> 172.17.0.10 +33139 172.17.0.10 -> 8.8.8.8 +33139 8.8.8.8 -> 172.17.0.10 +61415 172.17.0.10 -> 8.8.8.8 +61415 8.8.8.8 -> 172.17.0.10 +59258 172.17.0.10 -> 8.8.8.8 +59258 8.8.8.8 -> 172.17.0.10 +17700 172.17.0.10 -> 8.8.8.8 +17700 8.8.8.8 -> 172.17.0.10 diff --git a/include/dnsjit/test/test3.sh b/include/dnsjit/test/test3.sh new file mode 100755 index 0000000..b9a0b64 --- /dev/null +++ b/include/dnsjit/test/test3.sh @@ -0,0 +1,22 @@ +#!/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/filter_rcode.lua" dns.pcap-dist 0 >test3.out +../dnsjit "$srcdir/../../examples/filter_rcode.lua" dns.pcap-dist 1 >>test3.out +diff "$srcdir/test3.gold" test3.out diff --git a/include/dnsjit/test/test4.gold b/include/dnsjit/test/test4.gold new file mode 100644 index 0000000..f56e464 --- /dev/null +++ b/include/dnsjit/test/test4.gold @@ -0,0 +1,82 @@ +59311 +59311 +35665 +35665 +5337 +5337 +22982 +22982 +18718 +18718 +22531 +22531 +58510 +58510 +45248 +45248 +49483 +49483 +31669 +31669 +25433 +25433 +63798 +63798 +8470 +8470 +60258 +60258 +44985 +44985 +45512 +45512 +22980 +22980 +1834 +1834 +25431 +25431 +48432 +48432 +47411 +47411 +12038 +12038 +11614 +11614 +59173 +59173 +45535 +45535 +60808 +60808 +64325 +64325 +25543 +25543 +20736 +20736 +25911 +25911 +64358 +64358 +37698 +37698 +54706 +54706 +32142 +32142 +41808 +41808 +18886 +18886 +10624 +10624 +33139 +33139 +61415 +61415 +59258 +59258 +17700 +17700 diff --git a/include/dnsjit/test/test4.sh b/include/dnsjit/test/test4.sh new file mode 100755 index 0000000..b2d060d --- /dev/null +++ b/include/dnsjit/test/test4.sh @@ -0,0 +1,21 @@ +#!/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/readme.lua" dns.pcap-dist >test4.out +diff "$srcdir/test4.gold" test4.out diff --git a/include/dnsjit/test/test6.sh b/include/dnsjit/test/test6.sh new file mode 100755 index 0000000..67f8e25 --- /dev/null +++ b/include/dnsjit/test/test6.sh @@ -0,0 +1,23 @@ +#!/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/dumpdns.lua" "$srcdir/dns.pcap" > test6-dns.out +../dnsjit "$srcdir/../../examples/dumpdns2pcap.lua" "$srcdir/dns.pcap" test6-pcap.out +../dnsjit "$srcdir/../../examples/dumpdns.lua" test6-pcap.out > test6-dns2.out +diff test6-dns.out test6-dns2.out diff --git a/include/dnsjit/test/test_base64url.lua b/include/dnsjit/test/test_base64url.lua new file mode 100644 index 0000000..00aea6a --- /dev/null +++ b/include/dnsjit/test/test_base64url.lua @@ -0,0 +1,24 @@ +base64url = require("dnsjit.lib.base64url") +ffi = require("ffi") + +-- empty string works +assert(base64url.decode(base64url.encode("")) == "") + +-- regular string data +assert(base64url.encode("abcd") == "YWJjZA") +assert(base64url.decode(base64url.encode("abcd")) == "abcd") + +-- invalid base64 data +base64url.decode("+") + +-- check all symbols - arbitrary binary data +c_array = ffi.new("uint8_t[?]", 256) +bin_symbols = {} +for i = 0, 255 do + bin_symbols[i + 1] = string.char(i) + c_array[i] = i +end +bin_str = table.concat(bin_symbols) + +assert(base64url.decode(base64url.encode(bin_str)) == bin_str) +assert(base64url.encode(c_array, 256) == base64url.encode(bin_str)) diff --git a/include/dnsjit/test/test_compressupport.lua b/include/dnsjit/test/test_compressupport.lua new file mode 100644 index 0000000..9d4502e --- /dev/null +++ b/include/dnsjit/test/test_compressupport.lua @@ -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 diff --git a/include/dnsjit/test/test_ipsplit.lua b/include/dnsjit/test/test_ipsplit.lua new file mode 100755 index 0000000..43dc8a0 --- /dev/null +++ b/include/dnsjit/test/test_ipsplit.lua @@ -0,0 +1,294 @@ +-- Test cases for dnsjit.filter.ipsplit +-- Some checks that use ip_pkt() assume little-endian machine and will fail otherwise +local ffi = require("ffi") +local object = require("dnsjit.core.objects") +local dns = require("dnsjit.core.object.dns").new() + +local function dns_msgid(obj) + local obj = ffi.cast("core_object_t*", obj) + assert(obj, "obj is nil") + local pl = obj:cast() + assert(obj:type() == "payload" and pl.len > 0, "obj doesn't have payload") + dns.obj_prev = obj + dns:parse_header() + return dns.id +end + +local function ip_pkt(obj) + local obj = ffi.cast("core_object_t*", obj) + assert(obj, "obj is nil") + local pl = obj:cast() + assert(obj:type() == "payload" and pl.len > 0, "obj doesn't have payload") + + local pkt = obj.obj_prev + while pkt ~= nil do + if pkt.obj_type == object.IP or pkt.obj_type == object.IP6 then + return pkt:cast() + end + pkt = pkt.obj_prev + end + assert(pkt, "obj has no ip/ip6 layer") +end + + +----------------------------------------------------- +-- pellets.pcap: client detection +-- +-- All packets have IPv6 layer and are expected to +-- be sucessfully processed by ipsplit filter. +-- Clients should be identified from source ip. +----------------------------------------------------- +local input = require("dnsjit.input.pcap").new() +local layer = require("dnsjit.filter.layer").new() +local copy = require("dnsjit.filter.copy").new() +local ipsplit = require("dnsjit.filter.ipsplit").new() +local out1 = require("dnsjit.core.channel").new(256) +local out2 = require("dnsjit.core.channel").new(256) + +input:open_offline("pellets.pcap-dist") +layer:producer(input) +ipsplit:receiver(out1) +ipsplit:receiver(out2) +ipsplit:overwrite_dst() +copy:obj_type(object.IP) +copy:obj_type(object.IP6) +copy:obj_type(object.PAYLOAD) +copy:receiver(ipsplit) + +local prod, pctx = layer:produce() +local recv, rctx = copy:receive() + +-- Process entire PCAP first, channels are large enough to bufer all packets +while true do + local obj = prod(pctx) + if obj == nil then break end + recv(rctx, obj) +end +out1:close() +out2:close() + +assert(ipsplit:discarded() == 0, "some valid packets have been discarded") +assert(out1:size() == 47, "out1: some IPv6 packets lost by filter") +assert(out2:size() == 44, "out2: some IPv6 packets lost by filter") + +-- out1: test individual packets +local i = 0 +while true do + local obj = out1:get() + if obj == nil then break end + i = i + 1 + + if i == 1 then + assert(dns_msgid(obj) == 0x0a31, "pkt 1: client 1, pkt 1 -> out1") + assert(ip_pkt(obj):source() == "2001:0db8:beef:feed:0000:0000:0000:0003") + assert(ip_pkt(obj):destination() == "0100:0000:0000:0000:0000:0000:0000:0001") + end + if i == 2 then + assert(dns_msgid(obj) == 0xb3e8, "pkt 3: client 3, pkt 1 -> out1") + assert(ip_pkt(obj):source() == "2001:0db8:beef:feed:0000:0000:0000:0005") + assert(ip_pkt(obj):destination() == "0200:0000:0000:0000:0000:0000:0000:0001") + end + if i == 3 then + assert(dns_msgid(obj) == 0xb3e9, "pkt 4: client 3, pkt 2 -> out1") + assert(ip_pkt(obj):source() == "2001:0db8:beef:feed:0000:0000:0000:0005") + assert(ip_pkt(obj):destination() == "0200:0000:0000:0000:0000:0000:0000:0001") + end + if i == 13 then assert(dns_msgid(obj) == 0x4a05, "pkt 16: client 7, pkt 1 -> out1") end + if i == 14 then assert(dns_msgid(obj) == 0x4a06, "pkt 17: client 7, pkt 2 -> out1") end +end + +-- out2: test individual packets +local i = 0 +while true do + local obj = out2:get() + if obj == nil then break end + i = i + 1 + + if i == 1 then + assert(dns_msgid(obj) == 0xe6bd, "pkt 2: client 2, pkt 1 -> out2") + assert(ip_pkt(obj):source() == "2001:0db8:beef:feed:0000:0000:0000:0004") + assert(ip_pkt(obj):destination() == "0100:0000:0000:0000:0000:0000:0000:0001") + end + if i == 4 then assert(dns_msgid(obj) == 0xabfe, "pkt 18: client 8, pkt 1 -> out2") end + if i == 5 then assert(dns_msgid(obj) == 0xabff, "pkt 21: client 8, pkt 2 -> out2") end +end + + +----------------------------------------------------- +-- pellets.pcap: weighted ipsplit:sequential() +-- +-- Test sequential client assignment that respects +-- weight. +----------------------------------------------------- +local input = require("dnsjit.input.pcap").new() +local layer = require("dnsjit.filter.layer").new() +local copy = require("dnsjit.filter.copy").new() +local ipsplit = require("dnsjit.filter.ipsplit").new() +local out1 = require("dnsjit.core.channel").new(256) +local out2 = require("dnsjit.core.channel").new(256) + +input:open_offline("pellets.pcap-dist") +layer:producer(input) +ipsplit:receiver(out1, 3) +ipsplit:receiver(out2, 2) +copy:obj_type(object.IP) +copy:obj_type(object.IP6) +copy:obj_type(object.PAYLOAD) +copy:receiver(ipsplit) + +local prod, pctx = layer:produce() +local recv, rctx = copy:receive() + +-- Process entire PCAP first, channels are large enough to bufer all packets +while true do + local obj = prod(pctx) + if obj == nil then break end + recv(rctx, obj) +end +out1:close() +out2:close() + +assert(ipsplit:discarded() == 0, "some valid packets have been discarded") +assert(out1:size() + out2:size() == 91, "some IPv6 packets lost by filter") + +-- out1: test individual packets +local i = 0 +while true do + local obj = out1:get() + if obj == nil then break end + i = i + 1 + + if i == 1 then + assert(dns_msgid(obj) == 0x0a31, "pkt 1: client 1, pkt 1 -> out1") + assert(ip_pkt(obj):source() == "2001:0db8:beef:feed:0000:0000:0000:0003") + assert(ip_pkt(obj):destination() == "0000:0000:0000:0000:0000:0000:0000:0001") + end + if i == 2 then assert(dns_msgid(obj) == 0xe6bd, "pkt 2: client 2, pkt 1 -> out1") end + if i == 3 then assert(dns_msgid(obj) == 0xb3e8, "pkt 3: client 3, pkt 1 -> out1") end + if i == 4 then assert(dns_msgid(obj) == 0xb3e9, "pkt 4: client 3, pkt 2 -> out1") end + if i == 5 then assert(dns_msgid(obj) == 0x0a6f, "pkt 9: client 6, pkt 1 -> out1") end +end + +-- out2: test individual packets +local i = 0 +while true do + local obj = out2:get() + if obj == nil then break end + i = i + 1 + + if i == 1 then assert(dns_msgid(obj) == 0xaac6, "pkt 5: client 4, pkt 1 -> out2") end + if i == 2 then assert(dns_msgid(obj) == 0xaea6, "pkt 6: client 5, pkt 1 -> out2") end + if i == 3 then assert(dns_msgid(obj) == 0xaea7, "pkt 7: client 5, pkt 2 -> out2") end +end + +----------------------------------------------------- +-- pellets.pcap: weighted ipsplit:random() +-- +-- Test sequential client assignment that respects +-- weight. +----------------------------------------------------- +local input = require("dnsjit.input.pcap").new() +local layer = require("dnsjit.filter.layer").new() +local copy = require("dnsjit.filter.copy").new() +local ipsplit = require("dnsjit.filter.ipsplit").new() +local out1 = require("dnsjit.core.channel").new(256) +local out2 = require("dnsjit.core.channel").new(256) + +input:open_offline("pellets.pcap-dist") +layer:producer(input) +ipsplit:receiver(out1, 85) +ipsplit:receiver(out2, 15) +ipsplit:random() +copy:obj_type(object.IP) +copy:obj_type(object.IP6) +copy:obj_type(object.PAYLOAD) +copy:receiver(ipsplit) + +local prod, pctx = layer:produce() +local recv, rctx = copy:receive() + +-- Process entire PCAP first, channels are large enough to bufer all packets +while true do + local obj = prod(pctx) + if obj == nil then break end + recv(rctx, obj) +end +out1:close() +out2:close() + +assert(ipsplit:discarded() == 0, "some valid packets have been discarded") +assert(out1:size() == 81, "out1: some IPv6 packets lost by filter") +assert(out2:size() == 10, "out2: some IPv6 packets lost by filter") + +-- out1: test individual packets +local i = 0 +while true do + local obj = out1:get() + if obj == nil then break end + i = i + 1 + if i == 1 then assert(dns_msgid(obj) == 0xe6bd, "pkt 1: client 2, pkt 1 -> out1") end + if i == 2 then assert(dns_msgid(obj) == 0xb3e8, "pkt 2: client 3, pkt 1 -> out1") end + if i == 3 then assert(dns_msgid(obj) == 0xb3e9, "pkt 3: client 3, pkt 2 -> out1") end + if i == 5 then assert(dns_msgid(obj) == 0xaea6, "pkt 4: client 5, pkt 1 -> out1") end + if i == 29 then assert(dns_msgid(obj) == 0xaeaf, "pkt 29: client 5, pkt 10 -> out1") end +end + +-- out2: test individual packets +local i = 0 +while true do + local obj = out2:get() + if obj == nil then break end + i = i + 1 + if i == 1 then assert(dns_msgid(obj) == 0x0a31, "pkt 1: client 1, pkt 1 -> out2") end + if i == 2 then assert(dns_msgid(obj) == 0x0a6f, "pkt 2: client 6, pkt 1 -> out2") end + if i == 10 then assert(dns_msgid(obj) == 0x0a70, "pkt 10: client 6, pkt 2 -> out2") end +end + +----------------------------------------------------- +-- Tests with dns.pcap +-- +-- Packets use IPv4 and not all packets have IP layer +----------------------------------------------------- +local input = require("dnsjit.input.pcap").new() +local layer = require("dnsjit.filter.layer").new() +local copy = require("dnsjit.filter.copy").new() +local ipsplit = require("dnsjit.filter.ipsplit").new() +local out1 = require("dnsjit.core.channel").new(256) +local out2 = require("dnsjit.core.channel").new(256) + +input:open_offline("dns.pcap-dist") +layer:producer(input) +ipsplit:receiver(out1) +ipsplit:receiver(out2) +ipsplit:overwrite_src() +copy:obj_type(object.IP) +copy:obj_type(object.IP6) +copy:obj_type(object.PAYLOAD) +copy:receiver(ipsplit) + +local prod, pctx = layer:produce() +local recv, rctx = copy:receive() + +-- Process entire PCAP first, channels are large enough to bufer all packets +while true do + local obj = prod(pctx) + if obj == nil then break end + recv(rctx, obj) +end +out1:close() +out2:close() + +assert(out1:size() + out2:size() == 123, "some IPv4 packets lost by filter") + +-- out1: test individual packets +local i = 0 +while true do + local obj = out1:get() + if obj == nil then break end + i = i + 1 + if i == 1 then + assert(dns_msgid(obj) == 0xe7af) + assert(ip_pkt(obj):source() == "1.0.0.0") + assert(ip_pkt(obj):destination() == "8.8.8.8") + end +end diff --git a/include/dnsjit/test/test_trie.lua b/include/dnsjit/test/test_trie.lua new file mode 100755 index 0000000..ddaccdf --- /dev/null +++ b/include/dnsjit/test/test_trie.lua @@ -0,0 +1,134 @@ +-- Test cases for dnsjit.lib.trie + +local function key_compare(node1, node2) + local key1, keylen1 = node1:key() + local key2, keylen2 = node2:key() + if keylen1 ~= keylen2 then return false end + for i = 0, keylen1 - 1 do + if key1[i] ~= key2[i] then return false end + end + return true +end + +----------------------------------------------------- +-- binary-key trie with which stores numbers +----------------------------------------------------- +local input = require("dnsjit.input.pcap").new() +local layer = require("dnsjit.filter.layer").new() +local object = require("dnsjit.core.objects") +local ip = require("dnsjit.lib.ip") +local trie = require("dnsjit.lib.trie").new("uint32_t", true, 16) + +input:open_offline("pellets.pcap-dist") +layer:producer(input) + +local prod, pctx = layer:produce() + +-- fill trie with values +while true do + local obj = prod(pctx) + if obj == nil then break end + local pkt = obj:cast_to(object.IP6) + + if pkt ~= nil then + -- count number of packets per IP + local node = trie:get_ins(pkt.src) + node:set(node:get() + 1) + end +end + +assert(trie:weight() == 29) + +-- test iterator and check values +local iter = trie:iter() +local node = iter:node() +local npkts = 0 + +local i = 0 +while node ~= nil do + i = i + 1 + local ip6str = ip.tostring(node:key()) + local val = tonumber(node:get()) + npkts = npkts + val + + if i == 1 then assert(ip6str == "2001:0db8:beef:feed:0000:0000:0000:0003" and val == 1) end + if i == 1 then + local first = trie:get_first() + assert(key_compare(node, first)) + assert(node:get() == first:get()) + end + if i == 2 then assert(ip6str == "2001:0db8:beef:feed:0000:0000:0000:0004" and val == 1) end + if i == 2 then + local second = trie:get_try(node:key()) + assert(key_compare(node, second)) + assert(node:get() == second:get()) + end + if i == 5 then assert(ip6str == "2001:0db8:beef:feed:0000:0000:0000:0008" and val == 10) end + if i == 29 then assert(ip6str == "2001:0db8:beef:feed:0000:0000:0000:0042" and val == 1) end + + iter:next() + node = iter:node() +end + +assert(npkts == 91) + +trie:clear() +assert(trie:weight() == 0) + + +----------------------------------------------------- +-- string-key trie with which stores objects +----------------------------------------------------- +local input = require("dnsjit.input.pcap").new() +local layer = require("dnsjit.filter.layer").new() +local object = require("dnsjit.core.objects") +local trie = require("dnsjit.lib.trie").new("core_object_t*") + +input:open_offline("dns.pcap-dist") +layer:producer(input) + +local prod, pctx = layer:produce() + +-- fill trie with values +while true do + local obj = prod(pctx) + if obj == nil then break end + local pkt = obj:cast_to(object.IP) + + if pkt ~= nil then + local node = trie:get_ins(pkt:source()) + local pkt2 = node:get() + if val ~= nil then + val:free() + end + node:set(pkt:copy():uncast()) + end +end + +assert(trie:weight() == 3) + +local node +node = trie:get_first() +assert(node:key() == "172.17.0.10") +pkt = node:get():cast() +assert(pkt:source() == "172.17.0.10") +assert(pkt.id == 0x538b) +pkt:free() + +node = trie:get_try("8.8.8.8") +assert(node:key() == "8.8.8.8") +pkt = node:get():cast() +assert(pkt:source() == "8.8.8.8") +pkt:free() + +node = trie:get_try("216.58.218.206") +assert(node:key() == "216.58.218.206") +pkt = node:get():cast() +assert(pkt:source() == "216.58.218.206") +pkt:free() + +node = trie:get_try("nonexistent") +assert(node == nil) + +trie:clear() +assert(trie:weight() == 0) diff --git a/include/dnsjit/version.h b/include/dnsjit/version.h new file mode 100644 index 0000000..c53bdf3 --- /dev/null +++ b/include/dnsjit/version.h @@ -0,0 +1,28 @@ +/* + * 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/>. + */ + +#ifndef __dnsjit_version_h +#define __dnsjit_version_h + +#define DNSJIT_MAJOR_VERSION 1 +#define DNSJIT_MINOR_VERSION 2 +#define DNSJIT_PATCH_VERSION 1 + +#endif |