Have a Bash with the Zing network utility
Zinger
Zing is a zero-packet network utility similar to Ping that I first introduced in December 2022 [1]. Zing has the distinct advantage that hosts without Ping capability can be zinged without sending network packets. Thus, zinging a remote host with multiple zing
requests is not a "Ping flood" [2] attack, making Zing a network-safe utility that does not add network traffic.
Zing is implemented in a variety of programming languages, is open source, and is available for download [3]. Yet the idea occurred to me to implement zing
as a Bash shell script, which has the advantage of avoiding recompilation and of customization or tailoring for specific idiosyncrasies of a system platform or application.
Netcat
The netcat utility (nc
) is a key command-line application and "Swiss army knife" of network utilities [4]. Netcat is described as a simple Unix utility that reads and writes data across network connections by the TCP or UDP protocol [5]. Originally developed for Unix, netcat has since been ported to many other computer platforms. Thus, netcat has the advantage of being somewhat ubiquitous across different operating systems.
The decision to implement zing
with netcat in a shell script left one major design consideration decision. Put simply: Which shell to use? I develop on macOS, so Zsh seemed a likely obvious choice. However, I also work with Linux, so other shells were possible.
Ultimately I opted to go with Bash because it is ubiquitous, and I have done much more scripting for work and tinkering with the Bash shell. Moreover, Bash scripting is powerful, and with many users and a large pool of questions and answers on many tech boards, I was likely to find the solutions to unexpected problems, errors, and anomalies quickly. Thus, a Zing Bash script was the final choice.
Bash Shell Script for Zing
Having settled on netcat as the core of a Bash shell script to implement zing
, two design principles were determined:
- Explicit specified parameters to eliminate ambiguity; an erroneous parameter then terminates the script.
- Early Failure; when a required explicit parameter is missing, the Bash script terminates and exits.
The Bash implementation with netcat has four essential sections: (1) initialize, check, and process command-line interface (CLI) arguments; (2) check for the host and get the hostname and host address; (3) echo and perform the zing
operation and accumulate time; and (4) calculate simple statistics and report the results. Each section can then be broken down into specific operations and functions. To keep the code and design simple, all of these operations are centered on netcat as the only network tool.
Initializing sets the zing
variable defaults for the count, operations limit, network timeout, port list, and remote host. After initialization, the CLI arguments then re-initialize specific zing
parameters. This re-initialization requires some checks on the CLI arguments and number of arguments.
The initialization section also checks for at least one parameter and whether the argument is asking for help. If the CLI argument is not -h
or --help
, then the arguments submitted are processed. The processing is a loop to identify the argument and its value and then to reinitialize the particular zing
parameter as a variable. Any unknown CLI arguments will cause immediate error and exit from the script.
Netcat is used initially to get the name and address of the network host. HTTP port 80 is used per the netcat report:
localhost [127.0.0.1] 80 (http): Connection refused
The result in the hosttext
variable is then checked for warnings and errors, which are reported if detected, and the script exits. Again the Fail Early principle for warnings or errors causes the script to abort and exit rather than continuing with a problematic host or port.
The original script extracted the hostname and address from the hosttext
variable, but that was dependent on the netcat utility on macOS. The netcat utility returns information differently for macOS, Linux, and the Windows Linux subsystem; thus, the name and address of the host is obtained by netcat to avoid greater coupling to the idiosyncrasies of the network utilities of each platform.
This information of the host, hostname, and host address is later used in the fourth section of the Bash script. The report of the simple statistics also uses the hostname and address as part of the text datum for output.
The Bash script uses three nested loops that work in tandem to perform the zing
operation and accumulate and store the network throughput time. The outermost loop iterates through the port list, getting each port specified from the port list. The default port list is for port 80 (HTTP) and port 443 (HTTPS).
The second loop iterates through the count of the number of operations driving the third, innermost loop. The third loop limits the number of individual operations to perform for a single overall operation, which allows for an accumulated average time for network throughput to be determined, because network performance times are often in flux when considering operations from one computer system to another.
The three loops then perform the total zing
operation to a network host on the port list. Thus, the number of netcat calls is simply the product of the number of ports, the count, and the limit of the operation. The defaults are ports = 2, count = 6, and limit = 4, so the product, 2x6x4=48, is the total number of netcat operations.
The fourth and final section of the Bash script summarizes the zing
operation for a host on a port, which involves two subsections that calculate some simple statistics and report the results of the zing
operation before exiting.
The first part, calculating the statistics, is very straightforward and determines the minimums, maximums, averages, and standard deviations. The one challenging statistic to compute is the standard deviation of the timing values. Ultimately it requires an Awk script within the Bash script to make this computation.
The second part reports the statistics and the timing values, along with the hostname and host address. The only difficulty was in ensuring that the formatting worked and was consistent. After reporting the summary information of the zing
operation, the script exits.
Among the challenges and difficulties in implementing the Zing network utility as a Bash script was developing the original script on macOS and then running and using it on several different Linux systems with different distributions (e.g., Debian, Ubuntu, etc.).
Some notable "gotchas" in writing and porting the Bash script from macOS to Linux were:
- GNU
gdate
vs.date
for timing on Linux and macOS, respectively. - Awk script double asterisk exponentiation notation vs. the
^
operator forstddev
. - The use of
mawk
for Windows Linux subsystem with Bash instead ofawk
. - Format of the text returned by netcat on the various operating systems, which required adjusting the
cut
text utility field to extract the correct information, depending on whether the address information was in parenthesis (e.g., (127.0.0.1)) or brackets (e.g., [127.0.0.1]).
With some online searching and several technical discussion boards, I found the answers for these minor variations.
Zing CLI Parameters
The zing
parameters are enumerated at the command line as:
zing [-c <count>][-op <limit>][-p <port>][-t timeout] <hostname> | (-h|--help)
The parameters for the Zing Bash script are mostly the same as those for the binary compiled version. The one absent parameter in this implementation is for TCP/IPv4 or TCP/IPv6 addresses.
The implementation of zing
uses netcat [6], which does not support that particular feature or option; thus, the kind of IP address is dependent on netcat. However, TCP/IPv4 or TCP/IPv6 network addresses can be used along with a hostname for a computer system on the network.
The CLI parameters for the Zing Bash script network utility are:
- count
– the number of
zing
operations to perform on a host - limit
– the limit or operations limit per
zing
operation - port – list of ports on which to zing the host
- timeout – the timeout of the network connecting to a host
- host , hostname , or host IP address – the host computer system on a network
- help – a list of the command-line parameters
When the -h
or --help
parameter is used, the help text for the Zing Bash shell script is printed and then exits. The minimum parameter is the hostname for the computer system on a network.
The working examples of the Zing network utility are Bash scripts running on macOS Ventura version 13.4. Both as success and failure, zings to a host on a network illustrate the operation of the Zing Bash script.
Two working examples of a Zing Bash script (1) address an internal home network with a printer scanner that has no hostname and (2) zing a host on the Internet that cannot be pinged.
In the first example, the internal home network has an IPv4 address but no hostname. This device is a multifunction laser printer that resides on an IPv4 address in the internal private IPv4 address range from 10.0.0.1 to 10.255.255.255. Thus, it has no DNS entry and no hostname.
The command (Listing 1) zings the two HTTP ports: one for unsecured HTTP (port 80) and the other for secure HTTPS (port 443). The Error: message indicates the lack of a hostname for the IPv4 address. However, the Zing Bash script is able to detect and determine the throughput time across the local home network.
Listing 1
Zing an IPv4 Address for Internal Network
zing.bash -c 4 -op 2 -p 80,443 10.0.0.23 ZING:80/ 10.0.0.23 / Warning: Error: on 80 is: Active. Continue. Port: 80: op 1.1. 10.0.0.23 80 Time: 28 ms. Port: 80: op 1.2. 10.0.0.23 80 Time: 55 ms. Port: 80: op 2.1. 10.0.0.23 80 Time: 26 ms. Port: 80: op 2.2. 10.0.0.23 80 Time: 56 ms. Port: 80: op 3.1. 10.0.0.23 80 Time: 25 ms. Port: 80: op 3.2. 10.0.0.23 80 Time: 48 ms. Port: 80: op 4.1. 10.0.0.23 80 Time: 101 ms. Port: 80: op 4.2. 10.0.0.23 80 Time: 128 ms. ZING:80/ 10.0.0.23 / Warning: Error: on 443 is: Active. Continue. Port: 443: op 1.1. 10.0.0.23 443 Time: 27 ms. Port: 443: op 1.2. 10.0.0.23 443 Time: 56 ms. Port: 443: op 2.1. 10.0.0.23 443 Time: 28 ms. Port: 443: op 2.2. 10.0.0.23 443 Time: 55 ms. Port: 443: op 3.1. 10.0.0.23 443 Time: 27 ms. Port: 443: op 3.2. 10.0.0.23 443 Time: 58 ms. Port: 443: op 4.1. 10.0.0.23 443 Time: 27 ms. Port: 443: op 4.2. 10.0.0.23 443 Time: 53 ms. --- ZING: the host at IP address:80 --- hostname: 10.0.0.23 / Warning: Error: --- for 4 ops at a limit of 2 per op; statistics: Time for min/avg/max/stddev=24/63/64/12.32-ms
The next example is an Internet host that does not respond to a ping
Internet Control Message Protocol (ICMP) packet (Listing 2).
Listing 2
Pinging an Internet Host
ping -c 4 nist.gov PING nist.gov (129.6.13.49): 56 data bytes Request timeout for icmp_seq 0 Request timeout for icmp_seq 1 Request timeout for icmp_seq 2 --- nist.gov ping statistics --- 4 packets transmitted, 0 packets received, 100.0% packet loss
The host is the National Institute for Standards and Technology (NIST), a US government agency at host nist.gov
. The ping
command fails, but the Zing Bash script succeeds, giving the timing for Internet throughput (Listing 3).
Listing 3
Zinging an Internet Host
zing.bash -c 4 -op 2 -p 80,443 nist.gov ZING: 129.6.13.49 / nist.gov / disasterhub.nist.gov on 80 is: Active. Continue. Port: 80: op 1.1. nist.gov [129.6.13.49] Time: 103 ms. Port: 80: op 1.2. nist.gov [129.6.13.49] Time: 205 ms. [...] ZING: 129.6.13.49 / nist.gov / disasterhub.nist.gov on 443 is: Active. Continue. Port: 443: op 1.1. nist.gov [129.6.13.49] Time: 105 ms. Port: 443: op 1.2. nist.gov [129.6.13.49] Time: 209 ms. [...] --- ZING: the host at IP address: 129.6.13.49 --- host name: nist.gov / disasterhub.nist.gov --- for 4 ops at limit of 2 per op; statistics: Time for min/avg/max/stddev=101/207/110/2.59-ms
Buy this article as PDF
(incl. VAT)