This commit is contained in:
Michael Kuron
2020-08-02 19:48:23 +02:00
parent ad7d2c9f05
commit 2a260313de
+81 -17
View File
@@ -3,12 +3,14 @@
from zeroconf import Zeroconf, ServiceBrowser, ServiceStateChange from zeroconf import Zeroconf, ServiceBrowser, ServiceStateChange
import sys import sys
import time import time
from twisted.internet import reactor, defer from twisted.internet import reactor, defer, threads
from twisted.names import client, dns, error, server from twisted.names import client, dns, error, server
from twisted.python import log from twisted.python import log
domain = sys.argv[1] domain = sys.argv[1]
port = int(sys.argv[2]) port = int(sys.argv[2])
ttl = 120
timeout = 2
class DynamicResolver(object): class DynamicResolver(object):
def _dynamicResponseRequired(self, query): def _dynamicResponseRequired(self, query):
@@ -19,34 +21,96 @@ class DynamicResolver(object):
def _doDynamicResponse(self, query): def _doDynamicResponse(self, query):
if query.type == dns.SOA: if query.type == dns.SOA:
return [], [], [] return defer.succeed(([], [], []))
localname = str(query.name)[:-len(domain)] + "local." localname = str(query.name)[:-len(domain)] + "local."
services = [] def browse(localname):
def handler(zeroconf, service_type, name, state_change): services = []
if state_change is ServiceStateChange.Added: def handler(zeroconf, service_type, name, state_change):
services.append(name) if state_change is ServiceStateChange.Added:
services.append(name)
answers = []
if query.type == dns.PTR: zeroconf = Zeroconf(ip_version=4) # TODO: move out?
zeroconf = Zeroconf(ip_version=4)
sb = ServiceBrowser(zeroconf, localname, [handler]) sb = ServiceBrowser(zeroconf, localname, [handler])
time.sleep(2) # TODO: non-blocking print("waiting for", localname) # TODO: remove
time.sleep(timeout)
sb.cancel() sb.cancel()
print("done waiting for", localname) # TODO: remove
answers = []
for service in services: for service in services:
answers.append(dns.RRHeader(name=query.name.name, type=query.type, payload=dns.Record_PTR( answers.append(dns.RRHeader(name=query.name.name, ttl=ttl, type=dns.PTR, payload=dns.Record_PTR(
name=service[:-6] + domain name=service[:-6] + domain
))) )))
else: return answers
# TODO: other types
print(query)
return answers, [], [] def txt(localname):
zeroconf = Zeroconf(ip_version=4) # TODO: move out?
print("waiting for txt", localname) # TODO: remove
info = zeroconf.get_service_info(localname, localname)
print("done waiting for txt", localname) # TODO: remove
if info.text == b"\0":
answers = []
else:
answers = [dns.RRHeader(name=query.name.name, ttl=ttl, type=dns.TXT, payload=dns.Record_TXT(
info.text # TODO: something wrong here?
))]
print(answers, type(info.text), info.text)
return answers
def srv(localname):
zeroconf = Zeroconf(ip_version=4) # TODO: move out?
print("waiting for srv", localname)
info = zeroconf.get_service_info(localname, localname)
print("done waiting for srv", localname)
answers = [dns.RRHeader(name=query.name.name, ttl=ttl, type=dns.SRV, payload=dns.Record_SRV(
info.priority, info.weight, info.port, info.server[:-6] + domain
))]
print(answers)
return answers
def host(localname):
answers = [dns.RRHeader(name=query.name.name, ttl=ttl, type=dns.A, payload=dns.Record_A(
"192.0.2.1" # TODO
))]
print(answers)
return answers
d = defer.Deferred()
if query.type == dns.PTR:
d = threads.deferToThread(browse, localname)
d.addCallback(lambda a: (a, [], []))
return d
elif query.type == dns.TXT:
d = threads.deferToThread(txt, localname)
d.addCallback(lambda a: (a, [], []))
return d
elif query.type == dns.SRV:
d = threads.deferToThread(srv, localname)
d.addCallback(lambda a: (a, [], []))
return d
elif query.type == dns.A:
d = threads.deferToThread(host, localname)
d.addCallback(lambda a: (a, [], []))
return d
else:
answers = []
d.callback((answers, [], []))
if query.type != dns.AAAA:
print("Unsupported request", query)
return d
def query(self, query, timeout=None): def query(self, query, timeout=None):
if self._dynamicResponseRequired(query): if self._dynamicResponseRequired(query):
return defer.succeed(self._doDynamicResponse(query)) return self._doDynamicResponse(query)
else: else:
return defer.fail(error.DomainError()) return defer.fail(error.DomainError())