pingo is, currently, a simple CLI application with the intent to test the reachability of a host on an IP network. Quite similar to ping.
Between cpping and pingo, I had to learn Go to claim the latter. Learning the best ways to use the language's features everytime I tried one and it didn't quite work was a great experience (and I'm quite honest here).
It supports some features that ping supports, such as a custom timeout for the first ECHO_REQUEST
, custom interval between ECHO_REQUEST
s, a maximum amount of running time of the application, a custom TTL for packets and setting the max amount of ECHO_REQUESTS
that can be sent before stopping and flood!
It also supports both IPv4 and IPv6 addresses, along with hostnames.
To install the program executable execute:
$ go get github.com/mikaelmello/pingo/...
$ $GOPATH/bin/pingo # to execute the program
To manually build it, clone the repository and then build it
$ git clone https://github.com/mikaelmello/pingo.git
$ cd pingo
$ make install
$ make build
$ ./pingo # to execute the program
Usage:
pingo [hostname or ip address] [flags]
Flags:
-c, --count int Stop after sending count ECHO_REQUEST packets. With deadline option, ping waits for count
ECHO_REPLY packets, until the timeout expires. (default -1)
-w, --deadline int Specify a timeout, in seconds, before ping exits regardless of how many packets have been sent
or received. In this case ping does not stop after count packet are sent, it waits either for
deadline expire or until count probes are answered or for some error notification from network.
(default -1)
-f, --flood Flood ping. For every ECHO_REQUEST sent a period '.' is printed, while for ever ECHO_REPLY
received a backspace is printed. This provides a rapid display of how many packets are being
dropped. It sets interval to 0.01s between packets. Only available in privileged mode.
-h, --help help for pingo
-i, --interval float Wait interval seconds between sending each packet. The default is to wait for one second
between each packet normally. (default 1)
--log-level int Logging level, goes from top priority 0 (Panic) to lowest priority 6 (Trace). Values out of
this range log everything.
-p, --privileged Whether to use privileged mode. If yes, privileged raw ICMP endpoints are used, non-privileged
datagram-oriented otherwise. On Linux, to run unprivileged you must enable the setting 'sudo
sysctl -w net.ipv4.ping_group_range="0 2147483647"'. In order to run as a privileged user,
you can either run as sudo or execute 'setcap cap_net_raw=+ep <bin path>' to the path of the
binary. On Windows, you must run as privileged.
-W, --timeout int Time to wait for a response, in seconds. The option affects only timeout in absence of any
responses, otherwise ping waits for two RTTs. (default 10)
-t, --ttl int Set the IP Time to Live. (default 64)
Soon ™
Things are already quite decoupled at the moment, the probably necessary adaptations would not require a lot of work.
This program uses raw sockets to make the ICMP echo requests and you probably need root permissions to receive or send raw sockets.
Because of that, the default is to use a non-privileged and datagram-oriented mode, the networks "udp4" or "udp6", allowing us to send a few limited ICMP messages, exactly the echo and reply we want.
On Linux, you can enable it by setting
sudo sysctl -w net.ipv4.ping_group_range="0 2147483647"
or you can also run the CLI in the privileged mode, either as a privileged user or using setcap to allow your binary to bind raw sockets.
setcap CAP_NET_RAW+ep [binary path]
On Windows, it is not currently possible to run the program because many methods used in the implementation are not implemented for Windows in the golang/net
package, this will be resolved soon.
Warning: If you use the non-privileged mode, it is not possible to receive Time Exceeded ICMP messages, meaning that a request that exceeded its time to live will never receive a response, timing out instead.
- Refactor and use more interfaces, so that we can improve our testing, maybe DI?
- Remove our tests' dependency on net packages for better mocking, maybe DI [2]?
- Add support to be used as a package
$ ./pingo cloudflare.com
PING cloudflare.com. (104.17.175.85:0) 24 bytes of data
24 bytes from cloudflare.com. (104.17.175.85:0): icmp_seq=1 ttl=51 time=156.164ms
24 bytes from cloudflare.com. (104.17.175.85:0): icmp_seq=2 ttl=51 time=155.883ms
24 bytes from cloudflare.com. (104.17.175.85:0): icmp_seq=3 ttl=51 time=153.782ms
24 bytes from cloudflare.com. (104.17.175.85:0): icmp_seq=4 ttl=51 time=154.843ms
^C
--- cloudflare.com. ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 4.022s
rtt min/avg/max/mdev = 153.783/155.169/156.165/0.939 ms
$ sudo ./pingo cloudflare.com -c 2 -t 10 --privileged
PING cloudflare.com. (104.17.176.85) 24 bytes of data
From [redacted]: icmp_seq=1 time to live exceeded
From [redacted]: icmp_seq=2 time to live exceeded
--- cloudflare.com. ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1.53s
rtt min/avg/max/mdev = 0.000/0.000/0.000/0.000 ms
$ ./pingo localhost -c 4
PING localhost. (127.0.0.1) 24 bytes of data
24 bytes from localhost. (127.0.0.1): icmp_seq=1 ttl=64 time=289µs
24 bytes from localhost. (127.0.0.1): icmp_seq=2 ttl=64 time=312µs
24 bytes from localhost. (127.0.0.1): icmp_seq=3 ttl=64 time=266µs
24 bytes from localhost. (127.0.0.1): icmp_seq=4 ttl=64 time=279µs
--- localhost. ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3.202s
rtt min/avg/max/mdev = 0.266/0.287/0.313/0.017 ms
$ ./pingo example.com --log-level 3 -c 1
WARN[0000] You are running as non-privileged, meaning that it is not possible to receive TimeExceeded ICMP messages. Echo requests that exceed the configured TTL of 64 will be treated as timed out
PING example.com. (93.184.216.34:0) 24 bytes of data
24 bytes from example.com. (93.184.216.34:0): icmp_seq=1 ttl=54 time=135.416ms
--- example.com. ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 335ms
rtt min/avg/max/mdev = 135.416/135.416/135.416/0.000 ms