diff --git a/python/samba/tests/dns_forwarder_helpers/dns_hub.py b/python/samba/tests/dns_forwarder_helpers/dns_hub.py new file mode 100755 index 00000000000..81aa478f4ba --- /dev/null +++ b/python/samba/tests/dns_forwarder_helpers/dns_hub.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python +# +# Unix SMB/CIFS implementation. +# Copyright (C) Volker Lendecke 2017 +# +# 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 . +# +# Based on the EchoServer example from python docs + +import threading +import sys +import os +import select +import socket +from samba.dcerpc import dns +from samba.tests.dns_base import DNSTest +import samba.ndr as ndr + +if sys.version_info[0] < 3: + import SocketServer + sserver = SocketServer +else: + import socketserver + sserver = socketserver + +class DnsHandler(sserver.BaseRequestHandler): + def dns_transaction_udp(self, packet, host): + "send a DNS query and read the reply" + s = None + try: + send_packet = ndr.ndr_pack(packet) + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0) + s.settimeout(5) + s.connect((host, 53)) + s.sendall(send_packet, 0) + recv_packet = s.recv(2048, 0) + return ndr.ndr_unpack(dns.name_packet, recv_packet) + except socket.error as err: + print("Error sending to host %s for name %s: %s\n" % + (host, packet.questions[0].name, err.errno)) + raise + finally: + if s is not None: + s.close() + return None + + def forwarder(self, name): + lname = name.lower() + + if lname.endswith('an-address-that-will-not-resolve'): + return 'ignore' + if lname.endswith('dsfsdfs'): + return 'fail' + if lname.endswith('adnonssdom.samba.example.com'): + return '127.0.0.17' + if lname.endswith('adnontlmdom.samba.example.com'): + return '127.0.0.18' + if lname.endswith('samba2000.example.com'): + return '127.0.0.25' + if lname.endswith('samba2003.example.com'): + return '127.0.0.26' + if lname.endswith('samba2008r2.example.com'): + return '127.0.0.27' + if lname.endswith('addom.samba.example.com'): + return '127.0.0.30' + if lname.endswith('sub.samba.example.com'): + return '127.0.0.31' + if lname.endswith('chgdcpassword.samba.example.com'): + return '127.0.0.32' + if lname.endswith('backupdom.samba.example.com'): + return '127.0.0.40' + if lname.endswith('renamedom.samba.example.com'): + return '127.0.0.42' + if lname.endswith('labdom.samba.example.com'): + return '127.0.0.43' + if lname.endswith('samba.example.com'): + return '127.0.0.21' + return None + + def handle(self): + data, socket = self.request + query = ndr.ndr_unpack(dns.name_packet, data); + name = query.questions[0].name + forwarder = self.forwarder(name) + response = None + + if forwarder is 'ignore': + return + elif forwarder is 'fail': + pass + elif forwarder is not None: + response = self.dns_transaction_udp(query, forwarder) + else: + response = query + response.operation |= dns.DNS_FLAG_REPLY + response.operation |= dns.DNS_FLAG_RECURSION_AVAIL + response.operation |= dns.DNS_RCODE_NXDOMAIN + + if response is None: + response = query + response.operation |= dns.DNS_FLAG_REPLY + response.operation |= dns.DNS_FLAG_RECURSION_AVAIL + response.operation |= dns.DNS_RCODE_SERVFAIL + + send_packet = ndr.ndr_pack(response) + + print("dns_hub: sending %s to address %s for name %s\n" % + (forwarder, self.client_address, name)) + + try: + socket.sendto(send_packet, self.client_address) + except socket.error as err: + print("Error sending %s to address %s for name %s: %s\n" % + (forwarder, self.client_address, name, err.errno)) + raise + + socket.sendto(send_packet, self.client_address) + +class server_thread(threading.Thread): + def __init__(self, server): + threading.Thread.__init__(self) + self.server = server + + def run(self): + self.server.serve_forever() + print("dns_hub: after serve_forever()") + +def main(): + timeout = int(sys.argv[1])*1000 + timeout = min(timeout, 2**31-1) # poll with 32-bit int can't take more + host = sys.argv[2] + server = sserver.UDPServer((host, int(53)), DnsHandler) + t = server_thread(server) + t.start() + p = select.poll() + stdin = sys.stdin.fileno() + p.register(stdin, select.POLLIN) + p.poll(timeout) + print("dns_hub: after poll()") + server.shutdown() + t.join() + print("dns_hub: before exit()") + sys.exit(0) + +main()