📜 ⬆️ ⬇️

Bash: autodetection of the enemy for online play on Macs

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:

New service


which you can then search online by running the same command with the key “-B”:

We are looking for a created service


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:
#             dns-sd #         — dns-sd,    function _ClearServer { ps -f | awk"\$2==$1 && /_bolk-fileshare._tcp/ { print \$2 }" | xargs kill } dns-sd -R "$myownip $checksum" "_bolk-fileshare._tcp" . 1 >/dev/null & trap "_ClearServer $!" EXIT 

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.

Source: https://habr.com/ru/post/147238/


All Articles