Network diagnostics with Go
First Round
On first entering the loop, the firstTime
variable is set to true
. Line 25 then returns the Pinging ...
string to the caller via the ch
channel, informing the caller that the test is still in progress. The Run()
function in line 30 executes three pings to the network target specified in line 15 and blocks the program flow as long as the operation is running. If an error occurs, line 33 forwards it to the caller via the channel, and – after a 10-second pause – continue
in line 35 starts the next round.
If there is a response to the ICMP packets sent, the network is obviously fine. The call to Statistics()
in line 38 then retrieves the statistical data for the completed tests. The response times of each ping request are stored in stats.Rtts
as an array slice of seconds in floating-point format. Line 39 unceremoniously bundles all three values into a string with the %v
placeholder in the format string, and the same line immediately pushes this into the channel. The caller at the other end grabs the values and displays them in the graphical interface.
Connection OK?
When a WiFi client connects to the router, it is assigned an IP address, which it can display with commands like ifconfig
. When you're troubleshooting, it helps to know if that worked. This is why the plugin from Listing 6 searches for local IP addresses on the network interfaces assigned by the operating system.
Listing 6
eth.go
¤¤nonumber 01 package main 02 03 import ( 04 "net" 05 "sort" 06 "strings" 07 "time" 08 ) 09 10 func nifs(arg ...string) chan string { 11 ch := make(chan string) 12 13 go func() { 14 for { 15 eths, err := ifconfig() 16 17 if err != nil { 18 ch <- err.Error() 19 time.Sleep(10 * time.Second) 20 continue 21 } 22 23 ch <- strings.Join(eths, ", ") 24 time.Sleep(10 * time.Second) 25 } 26 }() 27 28 return ch 29 } 30 31 func ifconfig() ([]string, error) { 32 var list []string 33 ifaces, err := net.Interfaces() 34 if err != nil { 35 return list, err 36 } 37 38 for _, iface := range ifaces { 39 addrs, err := iface.Addrs() 40 if err != nil { 41 return list, err 42 } 43 44 if len(addrs) == 0 { 45 continue 46 } 47 48 for _, addr := range addrs { 49 ip := strings.Split(addr.String(), "/")[0] 50 if net.ParseIP(ip).To4() != nil { 51 list = append(list, iface.Name+" "+ip) 52 } 53 } 54 } 55 56 sort.Strings(list) 57 return list, nil 58 }
The net package from the Go standard library offers the Interfaces()
function, which returns all of the computer's network interfaces in line 33. For a laptop on a WiFi network, there are usually two interfaces: the WiFi adapter and the loopback interface. If your system is wired to the network, there are often more. Each of these interfaces, if connected, now has one or more IP addresses. Addrs()
in line 39 fetches them; the for
loop starting in line 48 checks them.
Hardly anyone in the US has IPv6 addresses at home. For this reason, line 50 filters out anything that doesn't look like IPv4 before appending the interface name
(e.g., en0
) and the IP address (without the subnet suffix) to the list
array slice. Line 56 sorts all of them alphabetically, while line 57 returns it to the caller of the ifconfig()
function in line 15.
The plugin works like all the others. Results such as error messages or successfully obtained IP address lists are fed into the channel as comma-separated strings, and the main program fields and displays incoming messages in the assigned table column. If there is an entry in the Ifconfig
line of the terminal UI in the private IP range of 192.168.0.x, then – obviously – the connection to the router is working. If, on the other hand, only the loopback interface appears in the column, something is wrong with the assignment of the IP addresses, and you need to verify your DHCP settings.
Full Round Trip
Finally, Listing 7 provides an end-to-end test by loading the YouTube title page off the web. If this test also works, everything should be fine. Because it also measures the time taken to retrieve the page in seconds in the last line of the UI, you can guesstimate the speed of the ISP connection. Figure 1 shows that the page was loaded after 0.142 seconds in the test – perfect.
Listing 7
www.go
¤¤nonumber 01 package main 02 03 import ( 04 "fmt" 05 "net/http" 06 "time" 07 ) 08 09 func httpGet(arg ...string) chan string { 10 ch := make(chan string) 11 12 firstTime := true 13 go func() { 14 for { 15 if firstTime { 16 ch <- "Fetching ..." 17 firstTime = false 18 } 19 20 now := time.Now() 21 _, err := http.Get(arg[0]) 22 if err != nil { 23 ch <- err.Error() 24 time.Sleep(10 * time.Second) 25 continue 26 } 27 28 dur := time.Since(now) 29 ch <- fmt.Sprintf("%.3f OK ", dur.Seconds()) 30 time.Sleep(10 * time.Second) 31 } 32 }() 33 34 return ch 35 }
To obtain this number, Listing 7 in line 21 uses the Get()
function to send an HTTP request; the function then blocks until the data arrives or the server returns an error. If the display in the table column gets stuck at Fetching ...
, then something is wrong with the connection. In that case, the other tests should give you some clues to the cause. On the other hand, if the hostname resolution fails due to incorrect DNS configuration, line 23 pushes the error message into the provided channel, where the main program picks it up to show you the results.
If everything is working, line 28 measures how long the process took. To do this, it subtracts the start time of the request set in line 20 from the current time and pushes the resulting duration in seconds into the channel as a floating-point number. The value then appears with an OK message in the table column.
The three commands in Listing 8 create the wifi
binary from the source code of the main program (Listing 4), the test plugins (Listings 5 to 7), the clock (Listing 1), and the GitHub packages and their dependencies. Calling the wifi
binary starts the terminal UI and shows the network status. If needed, you can add DIY plugins following the same approach and display them in additional table rows.
Listing 8
build-wifi.sh
¤¤nonumber $ go mod init wifi $ go mod tidy $ go build wifi.go clock.go eth.go ping.go www.go
Infos
- tview: https://github.com/rivo/tview
- Source code for this article: https://linuxnewmedia.thegood.cloud/s/5Rzx9tQW2FJ6N3Z
- Formatting date and time statements in Go: https://pkg.go.dev/time#pkg-constants
« Previous 1 2 3
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.
News
-
ESET Discovers New Linux Malware
WolfsBane is an all-in-one malware that has hit the Linux operating system and includes a dropper, a launcher, and a backdoor.
-
New Linux Kernel Patch Allows Forcing a CPU Mitigation
Even when CPU mitigations can consume precious CPU cycles, it might not be a bad idea to allow users to enable them, even if your machine isn't vulnerable.
-
Red Hat Enterprise Linux 9.5 Released
Notify your friends, loved ones, and colleagues that the latest version of RHEL is available with plenty of enhancements.
-
Linux Sees Massive Performance Increase from a Single Line of Code
With one line of code, Intel was able to increase the performance of the Linux kernel by 4,000 percent.
-
Fedora KDE Approved as an Official Spin
If you prefer the Plasma desktop environment and the Fedora distribution, you're in luck because there's now an official spin that is listed on the same level as the Fedora Workstation edition.
-
New Steam Client Ups the Ante for Linux
The latest release from Steam has some pretty cool tricks up its sleeve.
-
Gnome OS Transitioning Toward a General-Purpose Distro
If you're looking for the perfectly vanilla take on the Gnome desktop, Gnome OS might be for you.
-
Fedora 41 Released with New Features
If you're a Fedora fan or just looking for a Linux distribution to help you migrate from Windows, Fedora 41 might be just the ticket.
-
AlmaLinux OS Kitten 10 Gives Power Users a Sneak Preview
If you're looking to kick the tires of AlmaLinux's upstream version, the developers have a purrfect solution.
-
Gnome 47.1 Released with a Few Fixes
The latest release of the Gnome desktop is all about fixing a few nagging issues and not about bringing new features into the mix.