My target is to discover the IP address of a Linux computer "server" in the local network from a Windows computer. From another Linux computer "client" I can do:
ping -c1 server.local
and get a reply. Both "server" and "client" run Avahi, so this is easy. However, I would like to discover the IP address of "server" from a Python application of mine, which runs on both MS Windows and Linux computers. Note: on MS Windows computers that do not run mDNS software, there is no hostname resolution (and obviously ping
does not work on said Windows systems).
I know of the existence of pyzeroconf, and this is the module I tried to use; however, the documentation is scarce and not very helpful to me. Using tools like avahi-discover
, I figured that computers publish records of the service type _workstation._tcp.local.
(with the obviously dummy port 9, the discard service) of mDNS type PTR
that might be the equivalent of a DNS A record. Or I might have misunderstood completely the mDNS mechanism.
How can I discover the IP address of a computer (or get a list of IP addresses of computers) through mDNS from Python?
The obvious socket.gethostbyname
works on a computer running and configured to use mDNS software (like Avahi):
Python 2.6.5 (r265:79063, Apr 16 2010, 13:09:56)
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket
>>> socket.gethostbyname('server.local')
'192.168.42.42'
However, on Windows computers not running mDNS software (the default), I get:
Python 2.7.1 (r271:86832, Nov 27 2010, 18:30:46) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket
>>> socket.gethostbyname('server.local')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
socket.gaierror: [Errno 11001] getaddrinfo failed
First, click on your Start Menu and type cmd in the search box and press enter. A black and white window will open where you will type ipconfig /all and press enter. There is a space between the command ipconfig and the switch of /all. Your ip address will be the IPv4 address.
Multicast DNS or mDNS is a protocol that helps resolve hostnames on local networks that do not have a name server. The protocol specifies the resolution of hostnames ending in .local. Simply put, mDNS allows you to perform a hostname/IP mapping.
Service Discovery Using mDNSmDNS can be used to discover services like MQTT on your local network. An mDNS client issues a query for that service as shown by using the avahi-browse utility below: You can see that this service is available on machine called pi2 and on both IPv4 and IPv6.
mDNS is also involved in the resolution of domain names to the IP addresses, similar to DNS. Unlike the conventional DNS, the operation of mDNS is up to the level of local network since the operation of DNS takes place at global level. In the Zeroconf network, it works in the combination of the protocol DNS-SD.
If you just wanted a one liner for bash in Linux:
getent hosts HOSTNAME.local | awk '{ print $1 }'
Make sure to replace HOSTNAME with the hostname you are looking for.
Sticking to the letter of the original question, the answer is a qualified yes. Targets running avahi can be discovered with python zeroconf provided that they advertise some service. By default the avahi-deamon advertises the _workstation._tcp.local
service. In order to discover such servers modify the browser.py example coming with zeroconf so that it looks for this service (or any other service advertised by the targets of interest) instead of (or in addition to) _http._tcp.local
. browser.py will also discover targets using zeroconf's registration.py example to advertise their services, but not esp8266 targets (esp8266 responds with a malformed message to TXT (16) query).
#!/usr/bin/env python
from __future__ import absolute_import, division, print_function, unicode_literals
""" Example of resolving local hosts"""
# a stripped down verssion of browser.py example
# zeroconf may have issues with ipv6 addresses and mixed case hostnames
from time import sleep
from zeroconf import ServiceBrowser, ServiceStateChange, Zeroconf,DNSAddress
def on_service_state_change(zeroconf, service_type, name, state_change):
if state_change is ServiceStateChange.Added:
zeroconf.get_service_info(service_type, name)
zeroconf = Zeroconf()
ServiceBrowser(zeroconf, "_workstation._tcp.local.", handlers=[on_service_state_change])
ServiceBrowser(zeroconf, "_telnet._tcp.local.", handlers=[on_service_state_change])
ServiceBrowser(zeroconf, "_http._tcp.local.", handlers=[on_service_state_change])
ServiceBrowser(zeroconf, "_printer._tcp.local.", handlers=[on_service_state_change])
sleep(2)
#lookup specific hosts
print(zeroconf.cache.entries_with_name('esp01.local.'))
print(zeroconf.cache.entries_with_name('microknoppix.local.'))
print(zeroconf.cache.entries_with_name('pvknoppix.local.'))
print(zeroconf.cache.entries_with_name('debian.local.'))
cache=zeroconf.cache.cache
zeroconf.close()
# list all known hosts in .local
for key in cache.keys():
if isinstance(cache[key][0],DNSAddress):
print(key,cache[key])
sleep(1)
#output follows
#[10.0.0.4]
#[10.0.0.7]
#[]
#[3ffe:501:ffff:100:a00:27ff:fe6f:1bfb, 10.0.0.6]
#debian.local. [3ffe:501:ffff:100:a00:27ff:fe6f:1bfb, 10.0.0.6]
#esp01.local. [10.0.0.4]
#microknoppix.local. [10.0.0.7]
But to be honest I would not use zeroconf for this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With