Checking if we are connected to the Internet

Hi,

I’m new to Zig and programming in general. How do you check if the system is connected to the Internet?

1 Like

Hi @bilva_patra welcome to ziggit :slight_smile:

Technically what is the meaning of “Connected to internet”?
For most people not connected mean “when I cannot google”.
With that definition:

const std = @import("std");

pub fn connected(allocator: std.mem.Allocator) bool {
    const s = std.net.tcpConnectToHost(allocator, "google.com", 443) catch return false;
    s.close();
    return true;
}

test "connected to internet" {
    try std.testing.expect(connected(std.testing.allocator));
}
6 Likes

@dimdin is right, “connected to the Internet” is too vague a term. I would personally go with “I can ping something like 1.1.1.1” (but I don’t know how to do that in zig).

1 Like

Thanks for the advice. Actually, the reason I asked was I wanted to know if there was a way to interpret ‘connected to the Internet’ in a way that can both avoid trying to connect to something specific (such as ‘google.com’ or ‘1.1.1.1’) and also give reasonably accurate results.

What I tried doing in C was to use if_nameindex() from <net/if.h> to get a list of network interfaces and doing an ioctl(). I used the IFF_RUNNING interface flag. When I tested it multiple times, it gave the right answer. There was however, a slight delay. The interface was up and running a couple of seconds before I was actually able to open a website in a browser. Which led me to wonder if it could fail to correspond sometimes and whether there was actually a reliable way to do this without simply trying to use the network interface to connect to something. But when I tried to recreate this in Zig, the available functions were very different (although pleasantly more straightforward), so I felt a bit lost.

As a side note, is there any way to get a list of network interfaces available on the system, similar to if_nameindex() in Zig?

Testing if the interface is up or down does not mean that DNS or routing works. But if all the interfaces are down for sure there is no internet connection.

std.c.if_nametoindex exists, but you can import from C or declare whatever you want to call.

Moreover, an interface being up does not mean that a cable (I mean ethernet) is physically connected:

ls -1 /sys/class/net/
enp1s0
enp2s0
lo
tun0
cat /sys/class/net/enp1s0/carrier
1 // => cable connected
cat /sys/class/net/enp2s0/carrier
0 // => cable not connected

Should be:

const s = std.net.tcpConnectToAddress(address: Address) catch return false;

Note that this requires address to be listening. (so, for example, google.com on port 80, and not 1.1.1.1 since I’m pretty sure that doesn’t listen on TCP at all)

1 Like

I think that’s for connecting over a regular socket. ping does not require establishing a connection; moreover it uses, if I recall correctly, ICMP packets.

As far as I know there is no API in the standard library to do this. On Linux I’ve gotten something working using rtnetctl interface, but I had to port some data structures from c to zig.

I believe there is no standard ICMP mechanism in Linux either, so one would need to use raw sockets.

I believe that my first answer is the correct way: Checking if we are connected to the Internet - #2 by dimdin
Since you are still looking for another solution I will post a second here.

To have internet connection we need to have packets going and coming back to a well known place in internet. Typically this is done using ICMP echo packages as @gonzo said, and the way to send an ICMP packet is IP sockets as @cancername said. The problem with the raw IP socket API is that it requires special privileges on all operating systems.

An alternative IP protocol is UDP, this is a datagram, a packet that you send and there is no delivery guarantee. Any intermediate node can drop the packet. Think of the protocol as a post pigeon carrying your message while hunters shoot the pigeon.

DNS is an application that uses UDP, and 8.8.8.8 is a google service that responds to public DNS requests. The idea is to send few DNS request packets to 8.8.8.8 and wait for a response. If you get a response before timeout, internet is working otherwise internet does not work.

const sock = try std.os.socket(std.os.AF.INET, std.os.SOCK.DGRAM, std.os.IPPROTO.UDP);
defer std.os.close(sock);

Using the above socket call we create a UDP datagram communication port for IPv4.
We can use the sendto (or connect and send) to send the DNS packet to port 53 at 8.8.8.8 and the recvfrom to wait for a response.

An easy way to create the DNS packet content is to use dig or nslookup to send a DNS packet and use tcpdump or wireshark to capture the packet.
The following statements capture on DNS packet from interface eth0 and display it.

sudo tcpdump -c 1 -w dns.pcap -i eth0 udp port 53 &
dig A google.com @8.8.8.8
tcpdump -r dns.pcap -nvXA
2 Likes

Just a little note - a UDP packet can be dropped even on initial node in cases of heavy load when software is generating a lot of outgoing packets, but underlying driver/hardware is not capable to send them all. I observed this once, but with a bit specific network interface (Nanonet).

2 Likes