From: Otto Moerbeek Date: Tue, 17 Sep 2019 15:06:28 +0000 (+0200) Subject: Enable dnstap and include libfstrm X-Git-Tag: dnsdist-1.4.0-rc3~38^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e593a398ad46c2c6cff63e05f1cd146213e281e2;p=pdns Enable dnstap and include libfstrm --- diff --git a/build-scripts/travis.sh b/build-scripts/travis.sh index 9c5f9dc54..a37a2d341 100755 --- a/build-scripts/travis.sh +++ b/build-scripts/travis.sh @@ -444,6 +444,7 @@ build_recursor() { --with-libsodium \ --enable-unit-tests \ --enable-nod \ + --disable-dnstap \ --disable-silent-rules" run "make -k -j3" run "make install" diff --git a/builder-support/debian/recursor/debian-buster/control b/builder-support/debian/recursor/debian-buster/control index 0b23de49e..289190b67 100644 --- a/builder-support/debian/recursor/debian-buster/control +++ b/builder-support/debian/recursor/debian-buster/control @@ -10,6 +10,7 @@ Build-Depends: debhelper (>= 10~), libcap-dev, libluajit-5.1-dev, libprotobuf-dev, + libfstrm-dev, libsodium-dev, libssl-dev, libsystemd-dev [linux-any], diff --git a/builder-support/specs/pdns-recursor.spec b/builder-support/specs/pdns-recursor.spec index 40a0df0e1..758ae8817 100644 --- a/builder-support/specs/pdns-recursor.spec +++ b/builder-support/specs/pdns-recursor.spec @@ -35,6 +35,7 @@ BuildRequires: libatomic %if 0%{?rhel} >= 7 BuildRequires: protobuf-compiler BuildRequires: protobuf-devel +BuildRequires: fstrm-devel %endif BuildRequires: openssl-devel diff --git a/pdns/recursordist/configure.ac b/pdns/recursordist/configure.ac index 8f9849a3f..a2c14cc5b 100644 --- a/pdns/recursordist/configure.ac +++ b/pdns/recursordist/configure.ac @@ -119,7 +119,7 @@ AC_ARG_WITH([nod-cache-dir], [nodcachedir="$withval"] ) -PDNS_CHECK_DNSTAP([no]) +PDNS_CHECK_DNSTAP([auto]) AC_MSG_CHECKING([whether we will enable compiler security checks]) AC_ARG_ENABLE([hardening], diff --git a/regression-tests.recursor-dnssec/printlogs.py b/regression-tests.recursor-dnssec/printlogs.py index 9dcbdeedd..ddec98b55 100755 --- a/regression-tests.recursor-dnssec/printlogs.py +++ b/regression-tests.recursor-dnssec/printlogs.py @@ -10,19 +10,33 @@ root = e.getroot() for child in root: if len(child): + getstdout = False for elem in child: if elem.tag in ["failure", "error"]: - confdirname = child.get("classname").split('_')[1].split('.')[0] - confdir = os.path.join("configs", confdirname) - recursorlog = os.path.join(confdir, "recursor.log") - if os.path.exists(recursorlog): - print("==============> %s <==============" % recursorlog) - with open(recursorlog) as f: - print(''.join(f.readlines())) - authdirs = glob.glob(os.path.join(confdir, "auth-*")) - for authdir in authdirs: - authlog = os.path.join(authdir, "pdns.log") + cls = child.get("classname") + name = child.get("name") + if '_' not in cls or '.' not in cls: + print('Unexpected classname %s; name %s' % (cls, name)) + getstdout = True + continue + + confdirnames = [cls.split('_')[1].split('.')[0], cls.split('.')[1].split('Test')[0]] + for confdirname in confdirnames: + confdir = os.path.join("configs", confdirname) + recursorlog = os.path.join(confdir, "recursor.log") if os.path.exists(recursorlog): - print("==============> %s <==============" % authlog) - with open(authlog) as f: + print("==============> %s <==============" % recursorlog) + with open(recursorlog) as f: print(''.join(f.readlines())) + authdirs = glob.glob(os.path.join(confdir, "auth-*")) + for authdir in authdirs: + authlog = os.path.join(authdir, "pdns.log") + if os.path.exists(recursorlog): + print("==============> %s <==============" % authlog) + with open(authlog) as f: + print(''.join(f.readlines())) + if getstdout and elem.tag == 'system-out': + print("==============> STDOUT LOG FROM XML <==============") + print(elem.text) + print("==============> END STDOUT LOG FROM XML <==============") + diff --git a/regression-tests.recursor-dnssec/test_RecDnstap.py b/regression-tests.recursor-dnssec/test_RecDnstap.py index c94c1b5c2..8a8ad9a5b 100644 --- a/regression-tests.recursor-dnssec/test_RecDnstap.py +++ b/regression-tests.recursor-dnssec/test_RecDnstap.py @@ -1,14 +1,12 @@ -import dns -import dnsmessage_pb2 import os import socket import struct import sys import threading -import time - import dns import dnstap_pb2 +from nose import SkipTest +from recursortests import RecursorTest FSTRM_CONTROL_ACCEPT = 0x01 FSTRM_CONTROL_START = 0x02 @@ -18,17 +16,15 @@ FSTRM_CONTROL_FINISH = 0x05 # Python2/3 compatibility hacks try: - from queue import Queue + from queue import Queue except ImportError: - from Queue import Queue + from Queue import Queue try: - range = xrange + range = xrange except NameError: - pass + pass -from nose import SkipTest -from recursortests import RecursorTest def checkDnstapBase(testinstance, dnstap, protocol, initiator): testinstance.assertTrue(dnstap) @@ -54,7 +50,7 @@ def checkDnstapBase(testinstance, dnstap, protocol, initiator): testinstance.assertEquals(dnstap.message.response_port, 53) -def checkDnstapQuery(testinstance, dnstap, protocol, query, initiator='127.0.0.1'): +def checkDnstapQuery(testinstance, dnstap, protocol, initiator='127.0.0.1'): testinstance.assertEquals(dnstap.message.type, dnstap_pb2.Message.RESOLVER_QUERY) checkDnstapBase(testinstance, dnstap, protocol, initiator) @@ -66,7 +62,7 @@ def checkDnstapQuery(testinstance, dnstap, protocol, query, initiator='127.0.0.1 # We cannot compare the incoming query with the outgoing one # The IDs and some other fields will be different # - wire_message = dns.message.from_wire(dnstap.message.query_message) + #wire_message = dns.message.from_wire(dnstap.message.query_message) #testinstance.assertEqual(wire_message, query) @@ -101,7 +97,7 @@ def fstrm_get_control_frame_type(data): return t -def fstrm_make_control_frame_reply(cft, data): +def fstrm_make_control_frame_reply(cft): if cft == FSTRM_CONTROL_READY: # Reply with ACCEPT frame and content-type contenttype = b'protobuf:dnstap.Dnstap' @@ -122,7 +118,7 @@ def fstrm_read_and_dispatch_control_frame(conn): (datalen,) = struct.unpack("!L", data) data = conn.recv(datalen) cft = fstrm_get_control_frame_type(data) - reply = fstrm_make_control_frame_reply(cft, data) + reply = fstrm_make_control_frame_reply(cft) if reply: conn.send(reply) return cft @@ -150,13 +146,13 @@ def fstrm_handle_bidir_connection(conn, on_data): -class DNSTapServerParams: - def __init__(self, port): - self.queue = Queue() - self.port = port +class DNSTapServerParams(object): + def __init__(self, path): + self.queue = Queue() + self.path = path -DNSTapServerParameters = DNSTapServerParams(4243) +DNSTapServerParameters = DNSTapServerParams("/tmp/dnstap.sock") DNSTapListeners = [] class TestRecursorDNSTap(RecursorTest): @@ -169,35 +165,44 @@ class TestRecursorDNSTap(RecursorTest): except socket.error as e: if e.errno == 9: break - printf("Unexpected socket error %d", e) + sys.stderr.write("Unexpected socket error %s\n" % str(e)) sys.exit(1) - conn.close() + except exception as e: + sys.stderr.write("Unexpected socket error %s\n" % str(e)) + sys.exit(1) + conn.close() @classmethod def FrameStreamUnixListenerMain(cls, param): - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) try: - sock.bind(("127.0.0.1", param.port)) + try: + os.remove(param.path) + except: + pass + sock.bind(param.path) + sock.listen(100) except socket.error as e: - print("Error binding in the framestream listener: %s" % str(e)) + sys.stderr.write("Error binding/listening in the framestream listener: %s\n" % str(e)) sys.exit(1) DNSTapListeners.append(sock) - sock.listen(100) while True: - (conn, _) = sock.accept() - print("Accepting connection") - listener = threading.Thread(name='DNSTap Worker', target=cls.FrameStreamUnixListener, args=[conn, param]) - listener.setDaemon(True) - listener.start() - + try: + (conn, addr) = sock.accept() + listener = threading.Thread(name='DNSTap Worker', target=cls.FrameStreamUnixListener, args=[conn, param]) + listener.setDaemon(True) + listener.start() + except socket.error as e: + if e.errno != 9: + sys.stderr.write("Socket error on accept: %s\n" % str(e)) + else: + break sock.close() @classmethod def setUpClass(cls): - - if os.environ.get("NODNSTAPTESTS") == "1": - raise SkipTest("Not Yet Supported") + if os.environ.get("NODNSTAPTESTS") == "1": + raise SkipTest("Not Yet Supported") cls.setUpSockets() @@ -207,7 +212,6 @@ class TestRecursorDNSTap(RecursorTest): listener.setDaemon(True) listener.start() - confdir = os.path.join('configs', cls._confdir) cls.createConfigDir(confdir) @@ -258,28 +262,30 @@ class DNSTapDefaultTest(TestRecursorDNSTap): _config_template = """ auth-zones=example=configs/%s/example.zone""" % _confdir _lua_config_file = """ - dnstapFrameStreamServer({"127.0.0.1:%d"}) - """ % (DNSTapServerParameters.port) +dnstapFrameStreamServer({"%s"}) + """ % DNSTapServerParameters.path def getFirstDnstap(self): - data = DNSTapServerParameters.queue.get(True, timeout=2.0) + try: + data = DNSTapServerParameters.queue.get(True, timeout=2.0) + except: + data = False self.assertTrue(data) dnstap = dnstap_pb2.Dnstap() dnstap.ParseFromString(data) return dnstap def testA(self): - name = 'www.example.org.' query = dns.message.make_query(name, 'A', want_dnssec=True) query.flags |= dns.flags.RD res = self.sendUDPQuery(query) - - # check the DNSTap messages corresponding to the UDP query and answer + self.assertNotEquals(res, None) + # check the dnstap message corresponding to the UDP query dnstap = self.getFirstDnstap() - checkDnstapQuery(self, dnstap, dnstap_pb2.UDP, query, '127.0.0.8') + checkDnstapQuery(self, dnstap, dnstap_pb2.UDP, '127.0.0.8') # We don't expect a response checkDnstapNoExtra(self, dnstap) @@ -294,15 +300,15 @@ class DNSTapLogNoQueriesTest(TestRecursorDNSTap): _config_template = """ auth-zones=example=configs/%s/example.zone""" % _confdir _lua_config_file = """ - dnstapFrameStreamServer({"127.0.0.1:%d"}, {logQueries=false}) - """ % (DNSTapServerParameters.port) +dnstapFrameStreamServer({"%s"}, {logQueries=false}) + """ % (DNSTapServerParameters.path) def testA(self): name = 'www.example.org.' query = dns.message.make_query(name, 'A', want_dnssec=True) query.flags |= dns.flags.RD res = self.sendUDPQuery(query) + self.assertNotEquals(res, None) # We don't expect anything self.assertTrue(DNSTapServerParameters.queue.empty()) -