
From time to time I like to write some not too trivial things on
bash . It seems to be a network chess, which I already
talked about at Habré.
Recently, I mentally returned to them and thought how cool it would be if the game itself would find a partner to play on the network. Those. being launched, the toy must somehow search the network for those who are ready for the fight.
It is impossible to scan all addresses for a long time. There are two ugly “head-on” solutions - scan the current subnet or look at the
ARP table, connect to those who are there. But, firstly, such a search will still be slow, and secondly, it will not find all potential rivals (rivals may be on other subnets, and in the
ARP table, not all network members at all).
')
In general, a similar problem was solved long ago in OSes - for example, when I set up a network printer at home, the operating system found it myself, I did not specify
IP or something else. In the "Macs" for this is the technology "
Bonjour " (implementation of "
Zerokonfa ").
Is it possible to use this technology in the "Bash"?
I didn’t rewrite network chess, the thought about which it all started, instead I made a goal to make a file transfer utility that would work according to the following algorithm: it runs on two machines, indicating which file to transfer if computers see each other network, the file is transferred. All this without specifying the
IP of these machines or their names.
On Macs, there is the
dns-sd utility (or its older version of
mDNS ), which advertises and discovers network services. Those. being launched with the same keys, she says “this computer can do this,” with others, she is not looking for the indicated any computer on the network.
This is how it happens.
Services are specified by name, the service name is a unicode string (in
UTF-8 format), up to 63 bytes in length (not characters), specified in the form “
_app-proto._tcp ” or “
_app-proto._udp ”, where the string (which and is the name of the service) “
app-proto ” needs to be registered on a special site, but since the utility takes any value, it will come down without this step.
In general, if you run
dns-sd with the "-R" key, then it will register a new service on the network:
which you can then search online by running the same command with the key “-B”:
As you can see, besides the name of the service there are other parameters, but besides the line “Hello!” There is actually nothing interesting there, they do not affect anything in this implementation. Instead of saying “hello”, something more useful can be written on this line. I write there information about the
IP of the machine that announced the service and checksum of the file being transferred.
Some code.
It looks like this in my server announcement code:
As you can see, I am launching an announcement of the service in the background, and at the exit from the utility I beat the
dns-sd working in the background. If I would not use the launch in the background, then the execution of my script stopped at this place -
dns-sd after launch does not return control and removes the service from the announced ones upon exit.
Now the discovery service. In this mode,
dns-sd is similar to the
top utility — the console is also not released, and events about the advertised and de-advertised services appear on the screen. Therefore, I had to use the
expect utility that is very useful in such cases:
local info=($(expect <<CMDS | awk 'NR>2 {print $7 " " $8}' | sort -u | tr -d '\r' | head -n1 spawn -noecho dns-sd -B _bolk-fileshare._tcp expect Timestamp expect -- "_bolk-fileshare._tcp" exit CMDS))
The point is this: I ask
expect to return control to me when
dns-sd prints a string with the name of my service. After that, I select the right for me - the very line where I transmit the server's
IP address and the checksum of the file being transferred. In the variable
info , I get an array of two elements - the sum and
IP .
The rest is not very interesting, on the “GitHub”
is the resulting code - then I just connect to the specified address and get the file with the utility
netcat .
I summarize, the idea is this: a network game, to search for an opponent, announces a service with some given name, scanning simultaneously announced services to ask the player with whom he wants to play. The player chooses someone, then the machines are connected to the specified addresses and the game begins.