Fix AirPrint

- Keep TXT record order
- Force replies with more than 512 bytes to go over TCP
This commit is contained in:
Michael Kuron
2021-02-24 18:50:25 +01:00
parent 9adb3454a7
commit be42b16652
+26 -8
View File
@@ -39,12 +39,15 @@ class DynamicResolver(object):
time.sleep(timeout) time.sleep(timeout)
sb.cancel() sb.cancel()
answers = [] answers, additional = [], []
for service in services: for service in services:
answers.append(dns.RRHeader(name=query.name.name, ttl=ttl, type=dns.PTR, payload=dns.Record_PTR( answers.append(dns.RRHeader(name=localname[:-6] + domain, ttl=ttl, type=dns.PTR, payload=dns.Record_PTR(
name=service[:-6] + domain name=service[:-6] + domain
))) )))
return answers, [], [] #txt_ans, _, _ = txt(service)
#srv_ans, _, a_ans = srv(service)
#additional += a_ans + txt_ans + srv_ans
return answers, [], additional
def txt(localname): def txt(localname):
if localname.endswith('._device-info._tcp.local.'): if localname.endswith('._device-info._tcp.local.'):
@@ -57,8 +60,17 @@ class DynamicResolver(object):
if info is None: if info is None:
return [], [], [] return [], [], []
data = [b"%s=%s" % (p, info.properties[p]) for p in info.properties] order = []
answers = [dns.RRHeader(name=query.name.name, ttl=ttl, type=dns.TXT, payload=dns.Record_TXT( i = 0
while i < len(info.text):
length = info.text[i]
i += 1
kv = info.text[i : i + length].split(b'=')
order.append(kv[0])
i += length
data = [b"%s=%s" % (p, info.properties[p]) for p in sorted(info.properties, key=lambda k: order.index(k) if k in order else 1000)]
answers = [dns.RRHeader(name=localname[:-6] + domain, ttl=ttl, type=dns.TXT, payload=dns.Record_TXT(
*data *data
))] ))]
return answers, [], [] return answers, [], []
@@ -68,13 +80,12 @@ class DynamicResolver(object):
if info is None: if info is None:
return [], [], [] return [], [], []
answers = [dns.RRHeader(name=query.name.name, ttl=ttl, type=dns.SRV, payload=dns.Record_SRV( answers = [dns.RRHeader(name=localname[:-6] + domain, ttl=ttl, type=dns.SRV, payload=dns.Record_SRV(
info.priority, info.weight, info.port, info.server[:-6] + domain info.priority, info.weight, info.port, info.server[:-6] + domain
))] ))]
additional = [dns.RRHeader(name=info.server[:-6] + domain, ttl=ttl, type=dns.A, payload=dns.Record_A( additional = [dns.RRHeader(name=info.server[:-6] + domain, ttl=ttl, type=dns.A, payload=dns.Record_A(
socket.inet_ntop(socket.AF_INET, addr) socket.inet_ntop(socket.AF_INET, addr)
)) for addr in info.addresses] )) for addr in info.addresses]
return answers, [], additional return answers, [], additional
def host(localname): def host(localname):
@@ -127,13 +138,20 @@ class DynamicResolver(object):
else: else:
return defer.fail(error.DomainError()) return defer.fail(error.DomainError())
class TruncatingDNSDatagramProtocol(dns.DNSDatagramProtocol):
def writeMessage(self, message, address):
if type(message) is dns.Message and len(message.toStr()) > 512:
message.trunc = 1
message.answers = message.additional = []
dns.DNSDatagramProtocol.writeMessage(self, message, address)
def main(): def main():
factory = server.DNSServerFactory( factory = server.DNSServerFactory(
clients=[DynamicResolver()], clients=[DynamicResolver()],
verbose=0 verbose=0
) )
protocol = dns.DNSDatagramProtocol(controller=factory) protocol = TruncatingDNSDatagramProtocol(controller=factory)
reactor.listenUDP(port, protocol) reactor.listenUDP(port, protocol)
reactor.listenTCP(port, factory) reactor.listenTCP(port, factory)