Detecting Internet on macOS

My app (Lightwright) needs to know whether or not the user has internet access. I’ve been doing it using a Shell to ping Google. In this code, “Me” is a subclass of Shell:

Me.ExecuteMode=Shell.ExecuteModes.ASynchronous

Dim Astr as String = "ping -c 2 google.com" Me.Execute(Astr) -------------

In the .DataAvailable event, I check the .Result property to see if it contains “google”, which it would if it was able to connect to Google
If .Result contains “cannot resolve” or “could not find host” or “unknown host”, then I know it failed. This works great for 99% of my users, but recently there have been a few where it fails.

Today I had a really good bug report on this from, which said:

“I have an internet connection (en8, wired, through a USB-C dock, is primary in service order, then WiFi, en0). Both are working correctly, but Lightwright says it doesn’t have an internet connection. I tried turning WiFi off to limit to just one wired connection, same error persists. For reference, I’ve attached my ifconfig report. Is it possible that Lightwright isn’t fully enumerating all connections and checking for status active?”

I have no idea what an ifconfig report is, but here’s a snippet:

lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP>
inet 127.0.0.1 netmask 0xff000000
inet6 ::1 prefixlen 128
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
nd6 options=201<PERFORMNUD,DAD>
gif0: flags=8010<POINTOPOINT,MULTICAST> mtu 1280
stf0: flags=0<> mtu 1280
XHC20: flags=0<> mtu 0
XHC1: flags=0<> mtu 0
XHC0: flags=0<> mtu 0
VHC128: flags=0<> mtu 0
en5: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
ether ac:de:48:00:11:22
inet6 fe80::aede:48ff:fe00:1122%en5 prefixlen 64 scopeid 0x8
nd6 options=201<PERFORMNUD,DAD>
media: autoselect (100baseTX )
status: active
ap1: flags=8802<BROADCAST,SIMPLEX,MULTICAST> mtu 1500
ether 3a:f9:d3:dd:b5:ec
media: autoselect
status: inactive
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
ether 38:f9:d3:dd:b5:ec
inet6 fe80::102c:8b4c:5ea6:808f%en0 prefixlen 64 secured scopeid 0xa
inet 10.120.20.63 netmask 0xfffffc00 broadcast 10.120.23.255
nd6 options=201<PERFORMNUD,DAD>
media: autoselect
status: active

Does anyone have a clue why ping doesn’t work for this user? is there a better way to test for a connection? I could just try to download something from a known location (as if web pages never move), would that be more reliable?

Thanks!

  • John

It would be valuable to know what the response your app is getting actually is. The user could try ping in terminal, but the result could be different. Both are valuable bits of information though.

Using the framework sockets can cause unavoidable hangs in some situations. I think this ping approach is pretty decent unless we find a problem with Shell. Do you know if the user is running Catalina?

Did you ask the user to perform the same ping in terminal and did it work? Do you know if they block any connections from your app?

If they block ping (ICMP) with little snitch you’ll get a “Host is down” (at least thats what I see in a quick Mojave test I just did), I’m not sure if you check for that? I’m not sure what you get if ICMP is blocked at the modem as I don’t want to tweak that just before going to bed, this might be a similar message.

If you let us know why you need to check for an internet connection we might be able to suggest an alternate method that could be less prone to being blocked/stopped. Like, is there a reason you check for internet, e.g. for connection to your update service or licence service? If you check for a connection to a web service, it might just be better to try that connection and catch the failure.

I use this code to check internet connection :

[code]Public Function CheckOnline() as Boolean
Dim ret As Boolean = False
Dim sh As New Shell

sh.Mode = 2

If TargetWin32 Then
sh.Timeout = -1
sh.Execute “ping -w 5000 -n 1 www.google.com
Else
sh.Execute “ping -n -q -W 5 -c 1 www.google.com
End If
Do
App.DoEvents(25)
Loop Until Not sh.IsRunning
If sh.Errorcode=0 Then // success
ret = True
End If

Return ret

End Function
[/code]

https://forum.xojo.com/36891-best-way-to-determine-internet-connection-vote-advice

the result is :

Dim http As New TCPSocket http.Address = "www.apple.com" http.port = 80 http.Connect dim okapple as Boolean = (http.LastErrorCode = 0) http.close

works on any platform.

But with your solution @Jean-Yves Pochez , you have to wait the time out. And it can freeze you app for too long time. doing a ping with command shell can be done in a few

right, but I recall that using a shell command does prevent you from selling through mac app store ?

[quote=475363:@Jean-Yves Pochez]http.port = 80
works on any platform.[/quote]
Doesn’t macOS require Entitlements or whatever to connect to “insecure http websites”?
Or does that only apply when creating a http request and does not apply to TCPSocket?

What will happens if the service (google.com, www.apple.com) is down ?

The world ends :stuck_out_tongue:

@John McKernon — Maybe his network or a firewall just blocks ICMP traffic so ping does not work.

I heard back from him tonight, he’s on macOS 10.14.6.

Since he’s obviously pretty savvy, I asked him to try using Terminal to send some pings and see what they return - or not.

I’m also asking him if they’re blocking ICMP traffic. He works at a school which might be very locked down…

Would seem this is the righ way to test things

https://developer.apple.com/documentation/systemconfiguration/scnetworkreachability?language=objc

Couple words on bad and unsecure programming habits:

To ping a target is stupid, let me explain why. Firstly, in normal secure networks - not those shitty ones - access to the internet is controlled. At least there is some sort of transparent or non transparent webproxy blocking everything outgoing. Secondly any IDS/IPS will be triggered immediatly when inside the secured network any hosts or software starts pinging around. In best case the ping is just blocked, in worst cases the pinging host is banned from the internal network. Last but not least: How to explain it to the customer that your software is contacting Google or Apple when a personal firewall (e.g. LittleSnitch) pops up?

As a rule of thumb:

  1. Do not access the web without consent or at least without prior information.
  2. Dont use PING/ICMP better use http/https with system default’s proxy settings or as Norman said, native OS API.
  3. Don’t use Google or Apple. Don’t you have an own Website?

The free internet returns…

[quote=475664:@Norman Palardy]Would seem this is the righ way to test things

https://developer.apple.com/documentation/systemconfiguration/scnetworkreachability?language=objc[/quote]

“Reachability does not guarantee that the data packet will actually be received by the host.” so pretty pointless for a web based check, much like similar routines on windows.

A ping is also not guaranteed to reach the intended host
It can / could be blocked as Tomas already noted

[quote=475676:@Tomas Jakobs]Do not access the web without consent or at least without prior information.
Dont use PING/ICMP better use http/https with system default’s proxy settings or as Norman said, native OS API.
Don’t use Google or Apple. Don’t you have an own Website?
[/quote]

Users are made well aware that the app is going to access the internet if it has the chance, there are multiple features that take advantage of it (though it’s not required). I went the ping route because many people on this site appear to be using and recommending it. I can try the APIs, though my experience with them is essentially zero. Still worth a try.

And yes, I have a web site, but this app may well outlive me (this is its 40th year, my 68th), it would be best if it didn’t rely on my web site being available.

Thanks!

Just another thought: Think about what your customer, a pentester, security or data protection auditor will see. A piece of software trying to communicate with a 3rd party without consent, in this case with the biggest data violator, Google. None of them knows that you’re just pinging them. If you want to check internet connectivity than please check this with the hosts you really need.

[quote=475787:@Norman Palardy]A ping is also not guaranteed to reach the intended host
It can / could be blocked as Tomas already noted[/quote]

You remind me to the fact, that it not only can be done by the customer but by the site operator aswell in order to reduce the background noise. Try to ping my website jakobssystems.net, you will fail. And in addition to that. For my internal Cloud Host cloud.jakobssystems.de I am blocking any regions with GeoIP filters where I know, that I wont do any business there. Basically everything outside and south and east of Europe. This reduces the attack surface significantly and improves bandwith for my cloud host next to me in my office which is only connected with 20 MBit with the internet.

Well the possibility that Google will be among us in, let’s say, 10-20 years is equal with the chance your site will be there. Just think 20 years back. Do Altavista, Lycos or Yahoo exist - the big search engines of the 90ies? Well Yahoo might still be there but it’s more like a zombie, dying a long till really vanished. But you and me are still here, heck we are talking with each other :wink:

Here is one more for the list:

Return (Len(DNSNameToAddressMBS("www.google.com")) > 0)

[quote=475826:@David Cox]Here is one more for the list:

Return (Len(DNSNameToAddressMBS("www.google.com")) > 0)

Sorry, again. In corporate and secured networks a simple DNS Query does not mean that you have Internet accessible. This request might be answered by DNS correctly but any further communication might be rejected at your Gateway or Firewall.

Lightwrite is a famous theater software, isn’t it? I hardly can’t believe that theaters in the US are so unprotected.