selftests: Convert "net ads dns async" test to python
authorSamuel Cabrero <scabrero@samba.org>
Thu, 2 Jun 2022 16:39:57 +0000 (18:39 +0200)
committerJeremy Allison <jra@samba.org>
Sat, 4 Jun 2022 00:27:29 +0000 (00:27 +0000)
The current test uses the dig tool from bind9 but this tool has been
rewritten in 9.17.7 to use bind's netmgr functions instead of isc_socket
(commit 94b7988efb0f9b96415dd2966e6070450d960263).

The problem is that these 'netmgr' functions use libuv internally, and, on
systems supporting it, they end up using the sendmmsg() syscall which is not
catched by socket wrapper so the test fails.

This commit converts the test to python and uses the dnspython module
instead of the dig tool. Backtraces follow as reference.

Backtrace from dig v9.16.28 (working):

 #0  0x00007ffff778edee in sendmsg () from /lib64/libc.so.6
 #1  0x00000000005e5dee in cmsgsend (s=s@entry=12, level=level@entry=0, type=type@entry=1, res=<optimized out>) at net.c:515
 #2  0x00000000005e616c in try_dscp_v4 () at net.c:623
 #3  try_dscp () at net.c:696
 #4  0x00007ffff7708ad7 in __pthread_once_slow () from /lib64/libc.so.6
 #5  0x00000000005e66d7 in initialize_dscp () at net.c:702
 #6  isc_net_probedscp () at net.c:707
 #7  0x00000000005e8460 in socket_create (manager=0x6b49c0, pf=2, type=<optimized out>, socketp=0x7ffff0012b00, dup_socket=0x0) at socket.c:2454
 #8  0x000000000043cfcd in send_udp (query=0x7ffff00129a8) at dighost.c:2897
 #9  0x000000000043f9c7 in onrun_callback (task=<optimized out>, event=<optimized out>) at dighost.c:4271
 #10 0x00000000005dfefe in task_run (task=0x6b5c70) at task.c:851
 #11 isc_task_run (task=0x6b5c70) at task.c:944
 #12 0x00000000005ca0ce in isc__nm_async_task (worker=0x6b8970, ev0=0x716250) at netmgr.c:873
 #13 process_netievent (worker=worker@entry=0x6b8970, ievent=0x716250) at netmgr.c:952
 #14 0x00000000005ca2ba in process_queue (worker=worker@entry=0x6b8970, type=type@entry=NETIEVENT_TASK) at netmgr.c:1021
 #15 0x00000000005caa43 in process_all_queues (worker=0x6b8970) at netmgr.c:792
 #16 async_cb (handle=0x6b8cd0) at netmgr.c:821
 #17 0x00007ffff7898a4d in ?? () from /lib64/libuv.so.1
 #18 0x00007ffff78b4217 in ?? () from /lib64/libuv.so.1
 #19 0x00007ffff789e40a in uv_run () from /lib64/libuv.so.1
 #20 0x00000000005ca31e in nm_thread (worker0=0x6b8970) at netmgr.c:727
 #21 0x00000000005e2315 in isc__trampoline_run (arg=0x6b7c40) at trampoline.c:198
 #22 0x00007ffff7703767 in start_thread () from /lib64/libc.so.6
 #23 0x00007ffff778dc10 in clone3 () from /lib64/libc.so.6

Backtrace from dig v9.17.7 (not working):

 #0  0x00007ffff7684480 in syscall () from /lib64/libc.so.6
 #1  0x00007ffff754aed0 in uv__sendmmsg (vlen=0, mmsg=0x0, fd=10) at src/unix/linux-syscalls.c:163
 #2  uv__udp_mmsg_init () at src/unix/udp.c:74
 #3  0x00007ffff7606ad7 in __pthread_once_slow () from /lib64/libc.so.6
 #4  0x00007ffff7541bd9 in uv_once (guard=<optimized out>, callback=<optimized out>) at src/unix/thread.c:440
 #5  0x00007ffff7539e9b in uv__udp_sendmsg (handle=0x7ffff50535b8) at src/unix/udp.c:415
 #6  uv__udp_send (send_cb=0x7ffff7a41db0 <udp_send_cb>, addrlen=<optimized out>, addr=<optimized out>, nbufs=1, bufs=0x7ffff506c720, handle=0x7ffff50535b8, req=0x7ffff506c878) at src/unix/udp.c:773
 #7  uv_udp_send (req=req@entry=0x7ffff506c878, handle=handle@entry=0x7ffff50535b8, bufs=bufs@entry=0x7ffff506c720, nbufs=nbufs@entry=1, addr=<optimized out>, send_cb=send_cb@entry=0x7ffff7a41db0 <udp_send_cb>) at src/uv-common.c:464
 #8  0x00007ffff7a42308 in udp_send_direct (peer=0x7ffff5dfa988, req=0x7ffff506c700, sock=0x7ffff5053000) at netmgr/udp.c:839
 #9  isc__nm_async_udpsend (worker=<optimized out>, ev0=0x7ffff5dfa950) at netmgr/udp.c:780
 #10 0x00007ffff7a47de7 in isc__nm_udp_send (handle=<optimized out>, region=0x7ffff5dfaa90, cb=0x555555566250 <send_done>, cbarg=<optimized out>) at netmgr/udp.c:749
 #11 0x0000555555562ac2 in send_udp (query=0x7ffff502a000) at /usr/src/debug/bind-9.18.2-1.1.x86_64/bin/dig/dighost.c:2899
 #12 udp_ready (handle=0x7ffff5026180, eresult=ISC_R_SUCCESS, arg=<optimized out>) at /usr/src/debug/bind-9.18.2-1.1.x86_64/bin/dig/dighost.c:2974
 #13 0x00007ffff7a37d34 in isc__nm_async_connectcb (worker=worker@entry=0x7ffff622f000, ev0=ev0@entry=0x7ffff5026480) at netmgr/netmgr.c:2704
 #14 0x00007ffff7a3ca20 in process_netievent (worker=worker@entry=0x7ffff622f000, ievent=0x7ffff5026480) at netmgr/netmgr.c:940
 #15 0x00007ffff7a3d027 in process_queue (worker=worker@entry=0x7ffff622f000, type=type@entry=NETIEVENT_NORMAL) at netmgr/netmgr.c:977
 #16 0x00007ffff7a3d203 in process_all_queues (worker=0x7ffff622f000) at netmgr/netmgr.c:733
 #17 async_cb (handle=0x7ffff622f360) at netmgr/netmgr.c:762
 #18 0x00007ffff7531a4d in uv__async_io (loop=0x7ffff622f010, w=<optimized out>, events=<optimized out>) at src/unix/async.c:163
 #19 0x00007ffff754d217 in uv__io_poll (loop=0x7ffff622f010, timeout=<optimized out>) at src/unix/epoll.c:374
 #20 0x00007ffff753740a in uv__io_poll (timeout=<optimized out>, loop=0x7ffff622f010) at src/unix/udp.c:122
 #21 uv_run (loop=loop@entry=0x7ffff622f010, mode=mode@entry=UV_RUN_DEFAULT) at src/unix/core.c:391
 #22 0x00007ffff7a3d624 in nm_thread (worker0=0x7ffff622f000) at netmgr/netmgr.c:664
 #23 0x00007ffff7a6c915 in isc__trampoline_run (arg=0x555555599210) at /usr/src/debug/bind-9.18.2-1.1.x86_64/lib/isc/trampoline.c:187
 #24 0x00007ffff7601767 in start_thread () from /lib64/libc.so.6
 #25 0x00007ffff768bc10 in clone3 () from /lib64/libc.so.6

Signed-off-by: Samuel Cabrero <scabrero@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Autobuild-User(master): Jeremy Allison <jra@samba.org>
Autobuild-Date(master): Sat Jun  4 00:27:29 UTC 2022 on sn-devel-184

python/samba/tests/blackbox/netads_dns.py [new file with mode: 0644]
source4/selftest/tests.py
testprogs/blackbox/test_net_ads_dns_async.sh [deleted file]

diff --git a/python/samba/tests/blackbox/netads_dns.py b/python/samba/tests/blackbox/netads_dns.py
new file mode 100644 (file)
index 0000000..0a49150
--- /dev/null
@@ -0,0 +1,81 @@
+# Blackbox tests for the "net ads dns async" commands
+#
+# Copyright (C) Samuel Cabrero <scabrero@samba.org> 2022
+#
+# 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/>.
+
+import os
+import dns.resolver
+import re
+
+from samba.tests import BlackboxTestCase
+
+SERVER = os.environ["DC_SERVER"]
+REALM = os.environ["REALM"]
+COMMAND = "bin/net ads"
+
+class NetAdsDnsTests(BlackboxTestCase):
+
+    def setUp(self):
+        super(NetAdsDnsTests, self).setUp()
+        nameserver = os.environ["DC_SERVER_IP"]
+        self.resolver = dns.resolver.Resolver()
+        self.resolver.nameservers = [nameserver]
+
+    def parse_output(self, output):
+        v4 = []
+        v6 = []
+        for line in output.split("\n"):
+            m = re.search(r'^.*IPv4addr = (.*)$', line)
+            if m:
+                v4.append(m.group(1))
+            m = re.search(r'^.*IPv6addr = (.*)$', line)
+            if m:
+                v6.append(m.group(1))
+        return (v4, v6)
+
+    def test_async_dns(self):
+        host = "%s.%s" % (SERVER, REALM)
+
+        sync_v4 = []
+        answers = self.resolver.query(host, 'A')
+        for rdata in answers:
+            sync_v4.append(rdata.address)
+        self.assertGreaterEqual(len(sync_v4), 1)
+
+        sync_v6 = []
+        answers = self.resolver.query(host, 'AAAA')
+        for rdata in answers:
+            sync_v6.append(rdata.address)
+        self.assertGreaterEqual(len(sync_v6), 1)
+
+        async_v4 = []
+        async_v6 = []
+        argv = "%s dns async %s.%s " % (COMMAND, SERVER, REALM)
+        try:
+            out = self.check_output(argv)
+            (async_v4, async_v6) = self.parse_output(out.decode('utf-8'))
+        except samba.tests.BlackboxProcessError as e:
+            self.fail("Error calling [%s]: %s" % (argv, e))
+
+        self.assertGreaterEqual(len(async_v4), 1)
+        self.assertGreaterEqual(len(async_v6), 1)
+
+        sync_v4.sort()
+        async_v4.sort()
+        self.assertStringsEqual(' '.join(sync_v4), ' '.join(async_v4))
+
+        sync_v6.sort()
+        async_v6.sort()
+        self.assertStringsEqual(' '.join(sync_v6), ' '.join(async_v6))
index a01e188bcd177585bcd200b3b19288a83efd5d3b..32de26a9d23af9c63275a02063ee3dbe2fa32694 100755 (executable)
@@ -654,12 +654,6 @@ plantestsuite("samba4.blackbox.client_etypes_all(ad_dc:client)", "ad_dc:client",
 plantestsuite("samba4.blackbox.client_etypes_legacy(ad_dc:client)", "ad_dc:client", [os.path.join(bbdir, "test_client_etypes.sh"), '$DC_SERVER', '$DC_USERNAME', '$DC_PASSWORD', '$PREFIX_ABS', 'legacy', '23'])
 plantestsuite("samba4.blackbox.client_etypes_strong(ad_dc:client)", "ad_dc:client", [os.path.join(bbdir, "test_client_etypes.sh"), '$DC_SERVER', '$DC_USERNAME', '$DC_PASSWORD', '$PREFIX_ABS', 'strong', '17_18'])
 plantestsuite("samba4.blackbox.net_ads_dns(ad_member:local)", "ad_member:local", [os.path.join(bbdir, "test_net_ads_dns.sh"), '$DC_SERVER', '$DC_USERNAME', '$DC_PASSWORD', '$REALM', '$USERNAME', '$PASSWORD'])
-plantestsuite("samba4.blackbox.net_ads_dns_async(ad_member:local)",
-        "ad_member:local",
-        [os.path.join(bbdir,
-            "test_net_ads_dns_async.sh"),
-            '$DC_SERVER',
-            '$REALM'])
 plantestsuite("samba4.blackbox.samba-tool_ntacl(ad_member:local)", "ad_member:local", [os.path.join(bbdir, "test_samba-tool_ntacl.sh"), '$PREFIX', '$DOMSID'])
 
 if have_gnutls_fips_mode_support:
@@ -1219,6 +1213,8 @@ for env in ["ad_dc_ntvfs:local", "ad_dc:local",
 
 planoldpythontestsuite("none", "samba.tests.blackbox.downgradedatabase")
 
+planpythontestsuite("ad_member:local", "samba.tests.blackbox.netads_dns")
+
 plantestsuite_loadlist("samba4.ldap.python(ad_dc_default)", "ad_dc_default", [python, os.path.join(DSDB_PYTEST_DIR, "ldap.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT'])
 
 plantestsuite_loadlist("samba4.ldap_modify_order.python(ad_dc_default)",
diff --git a/testprogs/blackbox/test_net_ads_dns_async.sh b/testprogs/blackbox/test_net_ads_dns_async.sh
deleted file mode 100755 (executable)
index b993ab2..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-#!/bin/sh
-# Blackbox tests for net ads dns async
-# Copyright (C) 2020 Jeremy Allison <jra@samba.org>
-
-if [ $# -lt 2 ]; then
-cat <<EOF
-Usage: test_net_ads_dns_async.sh SERVER REALM
-EOF
-exit 1;
-fi
-
-SERVER=$1
-REALM=$2
-shift 2
-failed=0
-
-samba4bindir="$BINDIR"
-net_tool="$samba4bindir/net"
-
-. `dirname $0`/subunit.sh
-
-# Test looking up SERVER.REALM on server give the
-# same IP via async and non-async DNS.
-echo "Starting ..."
-
-test_async_dns() {
-       cmd_sync='dig @$SERVER +short -t a $SERVER.$REALM'
-       eval echo "$cmd_sync"
-       ipv4_sync=$(eval $cmd_sync)
-       if [ -z "$ipv4_sync" ]; then
-               return 1
-       fi
-       cmd_sync='dig @$SERVER +short -t aaaa $SERVER.$REALM'
-       eval echo "$cmd_sync"
-       ipv6_sync=$(eval $cmd_sync)
-       if [ -z "$ipv6_sync" ]; then
-               return 1
-       fi
-
-       #
-       # Do the async request. This prints out info like:
-       #
-       # Async A record lookup - got 1 names for addc.ADDOM.SAMBA.EXAMPLE.COM
-       # hostname[0] = addc.ADDOM.SAMBA.EXAMPLE.COM, IPv4addr = 10.53.57.30
-       # Async AAAA record lookup - got 1 names for addc.ADDOM.SAMBA.EXAMPLE.COM
-       # hostname[0] = addc.ADDOM.SAMBA.EXAMPLE.COM, IPv6addr = fd00::5357:5f1e
-       #
-       # So we must grep and sed to extract the matching IPv4 address
-       #
-       cmd_async='$net_tool ads dns async $SERVER.$REALM'
-       eval echo "$cmd_async"
-       out_async=$(eval $cmd_async)
-
-       # Drop everything but the IPv4 address.
-       ipv4_async=`echo "$out_async" | grep IPv4addr | sed -e 's/^.*IPv4addr = //'`
-       ipv6_async=`echo "$out_async" | grep IPv6addr | sed -e 's/^.*IPv6addr = //'`
-
-       if [ -z "$ipv4_async" -o -z "$ipv6_async" ]; then
-               return 1
-       fi
-       if [ "$ipv4_sync" != "$ipv4_async" ]; then
-               echo "DNS lookup mismatch. Sync $ipv4_sync, async $ipv4_async"
-               echo "DNS commands output. out1=$ipv4_sync, out2=$out_async"
-               return 1
-       fi
-       if [ "$ipv6_sync" != "$ipv6_async" ]; then
-               echo "DNS lookup mismatch. Sync $ipv6_sync, async $ipv6_async"
-               echo "DNS commands output. out1=$ipv6_sync, out2=$out_async"
-               return 1
-       fi
-       return 0
-}
-
-testit "Check async and non async DNS lookups match " test_async_dns || failed=`expr $failed + 1`
-
-exit $failed