Назад | Перейти на главную страницу

Как ping определяет IP-адрес службы mDNS?

Я пытаюсь написать программу Python 3, которая при задании имени службы возвращает числовой адрес IPv4 компьютера, на котором запущена служба. (Я не хочу использовать модуль zeroconf.)

С помощью https://en.wikipedia.org/wiki/Multicast_DNS и https://pymotw.com/3/socket/multicast.html, Я смог собрать что-то, что находит IP-номер хоста, на котором есть запись / etc / hosts (т.е. запрашивает hostname.local). Однако, когда у меня есть код, работающий в этой системе (hostname.local), который регистрирует службу _osc._udp.local. "(Например, oscresponder.local)," ping oscresponder.local "возвращает IP так же, как" ping hostname.local " есть, но мой код - нет.

Другими словами:

ping hostname.local           # works
./mDNS.py hostname.local      # works
ping oscresponder.local       # works
./mDNS.py oscresponder.local  # does not work

Итак, что делает ping, что выходит за рамки того, что перечислено в статье Википедии?

(Я попытался извлечь информацию с помощью Wireshark, но моя сетевая функция довольно плохая, и я не мог определить, какой ответ был получен с помощью ping для предоставления адреса IPv4.)

P.S. Мой код:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# An attempt to construct a raw -- and VERY specific -- mDNS query
# from scratch. The adventure begins at:
#
#    https://en.wikipedia.org/wiki/Multicast_DNS
#

import socket
import struct
import sys
import time

def main():

    if len(sys.argv) > 1:
        host, domain = sys.argv[1].split(".")
        host, domain = host.encode(), domain.encode()
        hlen, dlen   = bytes([len(host)]), bytes([len(domain)])
    else:
        print("Usage:\n\n    mdns.py FQDN\n")
        print("No FQDN supplied. Exiting...")
        sys.exit(1)

    # Construct the UDP packet to be multicast
    #    
    PACKET  = b""
    PACKET += b"\x00\x00"              # Transaction ID
    PACKET += b"\x00\x00"              # Flags
    PACKET += b"\x00\x01"              # Number of questions
    PACKET += b"\x00\x00"              # Number of answers
    PACKET += b"\x00\x00"              # Number of authority  resource records
    PACKET += b"\x00\x00"              # Number of additional resource records
    PACKET += hlen                     # Prefixed host name string length
    PACKET += host                     # Host name
    PACKET += dlen                     # Prefixed domain name string length
    PACKET += domain                   # Domain name
    PACKET += b"\x00"                  # Terminator
    PACKET += b"\x00\x01"              # Type (A record, Host address)
    #PACKET += b"\x00\x1C"             # Type (AAAA record, IPv6 address)
    PACKET += b"\x00\x01"              # Class

    print(PACKET)

    multicast_group = ("224.0.0.251", 5353)

    # Create the datagram socket
    #
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    # Set a timeout so the socket does not block
    # indefinitely when trying to receive data.
    #
    sock.settimeout(0.2)

    # Set the time-to-live for messages to 1 so they do not
    # go past the local network segment.
    #
    ttl = struct.pack('b', 1)
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)

    try:
        # Send data to the multicast group
    #   print('sending {!r}'.format(message))
        sent = sock.sendto(PACKET, multicast_group)

        # Look for responses from all recipients
        #
        while True:
            print('waiting to receive')
            try:
                data, server = sock.recvfrom(4096)
            except socket.timeout:
                print('timed out, no more responses')
                break
            else:
                print('received {!r} from {}'.format(
                    data, server))

    finally:
        print('closing socket')
        sock.close()


if __name__ == "__main__":
    main()