誰かがまだこれに興味を持っている場合は、次のようにdnspythonを使用して、Windows と Linux でタスクを実行できます。
import dns.resolver
myRes=dns.resolver.Resolver()
myRes.nameservers=['224.0.0.251'] #mdns multicast address
myRes.port=5353 #mdns port
a=myRes.query('microknoppix.local','A')
print a[0].to_text()
#'10.0.0.7'
a=myRes.query('7.0.0.10.in-addr.arpa','PTR')
print a[0].to_text()
#'Microknoppix.local.'
このコードは、ターゲット コンピューターが avahi を実行している場合は機能しますが、ターゲット コンピューターがpython zeroconf または esp8266 mdns 実装を実行している場合は失敗します。興味深いことに、avahi を実行している Linux システムは、そのようなターゲットを正常に解決します (avahi は明らかに nssswitch.conf mdns プラグインを実装し、mdns プロトコルのより完全な実装です)
。次のコード (Linux および Windows で実行され、Linux avahi、hp プリンター、および esp8266 ターゲットを解決する) が機能します: (また、MDNS ポートを使用してクエリを送信するため、非準拠ですが、明らかに完全な実装ではありません)
import socket
import struct
import dpkt, dpkt.dns
UDP_IP="0.0.0.0"
UDP_PORT=5353
MCAST_GRP = '224.0.0.251'
sock = socket.socket( socket.AF_INET, socket.SOCK_DGRAM )
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind( (UDP_IP,UDP_PORT) )
#join the multicast group
mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
for host in ['esp01','microknoppix','pvknoppix','hprinter'][::-1]:
# the string in the following statement is an empty query packet
dns = dpkt.dns.DNS('\x00\x00\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01')
dns.qd[0].name=host+'.local'
sock.sendto(dns.pack(),(MCAST_GRP,UDP_PORT))
sock.settimeout(5)
while True:
try:
m=sock.recvfrom( 1024 );#print '%r'%m[0],m[1]
dns = dpkt.dns.DNS(m[0])
if len(dns.qd)>0:print dns.__repr__(),dns.qd[0].name
if len(dns.an)>0 and dns.an[0].type == dpkt.dns.DNS_A:print dns.__repr__(),dns.an[0].name,socket.inet_ntoa(dns.an[0].rdata)
except socket.timeout:
break
#DNS(qd=[Q(name='hprinter.local')]) hprinter.local
#DNS(qd=[Q(name='pvknoppix.local')]) pvknoppix.local
#DNS(qd=[Q(name='microknoppix.local')]) microknoppix.local
#DNS(qd=[Q(name='esp01.local')]) esp01.local
#DNS(an=[RR(name='esp01.local', rdata='\n\x00\x00\x04', ttl=120, cls=32769)], op=33792) esp01.local 10.0.0.4
#DNS(an=[RR(name='PVknoppix.local', rdata='\n\x00\x00\xc2', ttl=120, cls=32769)], op=33792) PVknoppix.local 10.0.0.194
空の dns オブジェクトは、コンストラクターにネットワークから収集された文字列を渡すことによって、上記のコードで作成されました。
m0=sock.recvfrom( 1024 );print '%r'%m0[0]
#'\xf6\xe8\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x05esp01\x05local\x00\x00\x01\x00\x01'
このクエリは nslookup によって生成されたため、esp01.local を解決しようとして、その ID はゼロ以外 (この場合は \xf6\xe8) でした。次に、空のクエリを含む dns オブジェクトが次のように作成されました。
dns = dpkt.dns.DNS(m0[0])
dns.id=0
dns.qd[0].name=''
print '%r'%dns.pack()
#'\x00\x00\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01'
同じ結果は、次の方法でも作成できます。
dns=dpkt.dns.DNS(qd=[dpkt.dns.DNS.Q(name='')])
空でないクエリを使用して dns オブジェクトを作成することもできます。
dns=dpkt.dns.DNS(qd=[dpkt.dns.DNS.Q(name='esp01.local')])
または複数のクエリでも:
dns=dpkt.dns.DNS(qd=[dpkt.dns.DNS.Q(name='esp01.local'),dpkt.dns.DNS.Q(name='esp02.local')])
ただし、最小限のレスポンダーは、複数のクエリを含む dns メッセージの処理に失敗する可能性があります
また、python zeroconf のドキュメントにも不満があります。コードと tcpdump を使用したパケット監視をざっと読んだだけでは、(登録の例が実行されている場合) zeroconf はアドレス クエリに応答しますが、nslookup は応答を無視 (または受信しない) しているようです。