I need to list all available SMB hosts with their network addresses on the local network on a Mac. Any method works (BSD API, (Core)Foundation API or shell command).
When using the macOS Finder, Go -> Network (shift-cmd-K), it is able to list systems running Windows or Linux that share volumes via smb. This proves that the servers are discoverable somehow.
I've tried to see if the servers are advertised over Bonjour or SSDP, but that's not the case.
How does Apple's code find them and how can I do this, too?
Does Windows/SMB perhaps use yet-another service announcement protocol for this? If so, what is it?
Could it be WINS or some Microsoft proprietary stuff?
Ok, I've researched a bit more: this is done via NetBIOS. If you check out this answer it'll use nmblookup __SAMBA__
, which is something you can also do on macOS via smbutil view //__SAMBA__
.
So you may need to find a NetBIOS library to do the lookup from within your app.
Edit: Further investigation shows that it's indeed the WINS protocol that's used here. nmblookup
performs an UDP broadcast, which I've captured with Wireshark (in this case via nmblookup WORKGROUP
, which in my setup returns the same information as nmblookup "*"
):
The answers come in one after the other and their UDP packets contain the IP-Addressed in their last for bytes:
I've tried creating an example Python script that opens an UDP socket and sends the request, but receiving turned out to be a bit more difficult.
Another update: I've found a UDP broadcast example and adapted it a WINS request: GitHub Gist.
Basically you create a socket via socket()
, enable broadcasts via setsockopt()
and then you send the packet via sendto()
.
To read the various responses, use select()
and recvfrom()
multiple times. Provide a reasonable timeout to not wait indefinitely, in case no further responses have been received.
Sockets are weird API for sure.