selftest: Move dns_hub.py into selftest directory
[metze/samba/wip.git] / selftest / target / dns_hub.py
1 #!/usr/bin/env python
2 #
3 # Unix SMB/CIFS implementation.
4 # Copyright (C) Volker Lendecke 2017
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 #
19 # Based on the EchoServer example from python docs
20
21 import threading
22 import sys
23 import select
24 import socket
25 from samba.dcerpc import dns
26 import samba.ndr as ndr
27
28 if sys.version_info[0] < 3:
29     import SocketServer
30     sserver = SocketServer
31 else:
32     import socketserver
33     sserver = socketserver
34
35
36 class DnsHandler(sserver.BaseRequestHandler):
37     def dns_transaction_udp(self, packet, host):
38         "send a DNS query and read the reply"
39         s = None
40         try:
41             send_packet = ndr.ndr_pack(packet)
42             s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
43             s.settimeout(5)
44             s.connect((host, 53))
45             s.sendall(send_packet, 0)
46             recv_packet = s.recv(2048, 0)
47             return ndr.ndr_unpack(dns.name_packet, recv_packet)
48         except socket.error as err:
49             print("Error sending to host %s for name %s: %s\n" %
50                   (host, packet.questions[0].name, err.errno))
51             raise
52         finally:
53             if s is not None:
54                 s.close()
55         return None
56
57     def forwarder(self, name):
58         lname = name.lower()
59
60         if lname.endswith('an-address-that-will-not-resolve'):
61             return 'ignore'
62         if lname.endswith('dsfsdfs'):
63             return 'fail'
64         if lname.endswith('adnonssdom.samba.example.com'):
65             return '127.0.0.17'
66         if lname.endswith('adnontlmdom.samba.example.com'):
67             return '127.0.0.18'
68         if lname.endswith('samba2000.example.com'):
69             return '127.0.0.25'
70         if lname.endswith('samba2003.example.com'):
71             return '127.0.0.26'
72         if lname.endswith('samba2008r2.example.com'):
73             return '127.0.0.27'
74         if lname.endswith('addom.samba.example.com'):
75             return '127.0.0.30'
76         if lname.endswith('sub.samba.example.com'):
77             return '127.0.0.31'
78         if lname.endswith('chgdcpassword.samba.example.com'):
79             return '127.0.0.32'
80         if lname.endswith('backupdom.samba.example.com'):
81             return '127.0.0.40'
82         if lname.endswith('renamedom.samba.example.com'):
83             return '127.0.0.42'
84         if lname.endswith('labdom.samba.example.com'):
85             return '127.0.0.43'
86         if lname.endswith('samba.example.com'):
87             return '127.0.0.21'
88         return None
89
90     def handle(self):
91         data, sock = self.request
92         query = ndr.ndr_unpack(dns.name_packet, data)
93         name = query.questions[0].name
94         forwarder = self.forwarder(name)
95         response = None
96
97         if forwarder is 'ignore':
98             return
99         elif forwarder is 'fail':
100             pass
101         elif forwarder is not None:
102             response = self.dns_transaction_udp(query, forwarder)
103         else:
104             response = query
105             response.operation |= dns.DNS_FLAG_REPLY
106             response.operation |= dns.DNS_FLAG_RECURSION_AVAIL
107             response.operation |= dns.DNS_RCODE_NXDOMAIN
108
109         if response is None:
110             response = query
111             response.operation |= dns.DNS_FLAG_REPLY
112             response.operation |= dns.DNS_FLAG_RECURSION_AVAIL
113             response.operation |= dns.DNS_RCODE_SERVFAIL
114
115         send_packet = ndr.ndr_pack(response)
116
117         print("dns_hub: sending %s to address %s for name %s\n" %
118             (forwarder, self.client_address, name))
119
120         try:
121             sock.sendto(send_packet, self.client_address)
122         except socket.error as err:
123             print("Error sending %s to address %s for name %s: %s\n" %
124                 (forwarder, self.client_address, name, err))
125
126
127 class server_thread(threading.Thread):
128     def __init__(self, server):
129         threading.Thread.__init__(self)
130         self.server = server
131
132     def run(self):
133         self.server.serve_forever()
134         print("dns_hub: after serve_forever()")
135
136
137 def main():
138     timeout = int(sys.argv[1]) * 1000
139     timeout = min(timeout, 2**31 - 1)  # poll with 32-bit int can't take more
140     host = sys.argv[2]
141     server = sserver.UDPServer((host, int(53)), DnsHandler)
142     t = server_thread(server)
143     t.start()
144     p = select.poll()
145     stdin = sys.stdin.fileno()
146     p.register(stdin, select.POLLIN)
147     p.poll(timeout)
148     print("dns_hub: after poll()")
149     server.shutdown()
150     t.join()
151     print("dns_hub: before exit()")
152     sys.exit(0)
153
154 main()