go-ping / ping

ICMP Ping library for Go
MIT License
1.33k stars 345 forks source link

go-ping loses 100% of packets while vanilla ping works #173

Closed we11adam closed 3 years ago

we11adam commented 3 years ago

This looks pretty odd to me...

Can anyone please point me a direction?

I'm on macOS 15.1.1, if this helps.

○ $GOPATH/bin/ping -c 10  1.1.1.1
PING 1.1.1.1 (1.1.1.1):
^C
--- 1.1.1.1 ping statistics ---
10 packets transmitted, 0 packets received, 0 duplicates, 100% packet loss
round-trip min/avg/max/stddev = 0s/0s/0s/0s

○ ping -c 10 1.1.1.1
PING 1.1.1.1 (1.1.1.1): 56 data bytes
64 bytes from 1.1.1.1: icmp_seq=0 ttl=47 time=243.834 ms
64 bytes from 1.1.1.1: icmp_seq=1 ttl=47 time=221.254 ms
64 bytes from 1.1.1.1: icmp_seq=2 ttl=47 time=243.035 ms
Request timeout for icmp_seq 3
64 bytes from 1.1.1.1: icmp_seq=4 ttl=47 time=239.598 ms
64 bytes from 1.1.1.1: icmp_seq=5 ttl=47 time=230.944 ms
64 bytes from 1.1.1.1: icmp_seq=6 ttl=47 time=243.211 ms
64 bytes from 1.1.1.1: icmp_seq=7 ttl=47 time=243.139 ms
64 bytes from 1.1.1.1: icmp_seq=8 ttl=47 time=243.639 ms
64 bytes from 1.1.1.1: icmp_seq=9 ttl=47 time=217.155 ms

--- 1.1.1.1 ping statistics ---
10 packets transmitted, 9 packets received, 10.0% packet loss
round-trip min/avg/max/stddev = 217.155/236.201/243.834/9.905 ms
CHTJonas commented 3 years ago

Strange. This works perfectlyfor me using macOS 11.5.1 -- is 15.1.1 your actual version or a typo?

Can you please update to the latest version (go get -u github.com/go-ping/ping/...) and then try again? If that fails please could you try using --privileged?

we11adam commented 3 years ago

Strange. This works perfectlyfor me using macOS 11.5.1 -- is 15.1.1 your actual version or a typo?

Can you please update to the latest version (go get -u github.com/go-ping/ping/...) and then try again? If that fails please could you try using --privileged?

Sorry it was a typo :-P. I'm on Big Sur 11.5.1.

So this is my further test as you suggest:

○ $GOPATH/bin/ping --privileged -c 10  1.1.1.1
PING 1.1.1.1 (1.1.1.1):
Failed to ping target host: listen ip4:icmp : socket: operation not permitted%

○ sudo $GOPATH/bin/ping  -c 10  1.1.1.1
PING 1.1.1.1 (1.1.1.1):
^C
--- 1.1.1.1 ping statistics ---
7 packets transmitted, 0 packets received, 0 duplicates, 100% packet loss
round-trip min/avg/max/stddev = 0s/0s/0s/0s

○ sudo $GOPATH/bin/ping --privileged -c 10  1.1.1.1
Password:
PING 1.1.1.1 (1.1.1.1):
24 bytes from 1.1.1.1: icmp_seq=0 time=181.035ms ttl=47
24 bytes from 1.1.1.1: icmp_seq=1 time=175.065ms ttl=47
24 bytes from 1.1.1.1: icmp_seq=2 time=190.877ms ttl=47
24 bytes from 1.1.1.1: icmp_seq=3 time=174.28ms ttl=47
24 bytes from 1.1.1.1: icmp_seq=4 time=177.18ms ttl=47
24 bytes from 1.1.1.1: icmp_seq=5 time=156.328ms ttl=47
24 bytes from 1.1.1.1: icmp_seq=6 time=190.286ms ttl=47
24 bytes from 1.1.1.1: icmp_seq=7 time=172.787ms ttl=47
24 bytes from 1.1.1.1: icmp_seq=8 time=161.163ms ttl=47
24 bytes from 1.1.1.1: icmp_seq=9 time=175.175ms ttl=47

--- 1.1.1.1 ping statistics ---
10 packets transmitted, 10 packets received, 0 duplicates, 0% packet loss
round-trip min/avg/max/stddev = 156.328ms/175.417601ms/190.877ms/10.347596ms

It's clear that go-ping works only when sudo and --privileged are both applied.

After digging into my system configuration for a while, I found that deleting/deactivating the content filter provided by a corporation EDR software in System Preference -> Network fixes the issue.

So the next question is why vanilla ping has the magic power to go through the content filter? I checked the system builtin ping binary and it's not setuided as I have originally speculated.

○ ll /sbin/ping
-r-xr-xr-x  1 root  wheel   169K Jan  1  2020 /sbin/ping
○ [ -u /sbin/ping ] && echo SUID-bit is set || echo SUID-bit is not set
SUID-bit is not set

OK I'm confused here. :-P

we11adam commented 3 years ago

It turned out go-ping uses UDP instead of ICMP when --privileged flag is not provided (see code here). This explains why all packets timed out because EDR software tends to block UDP traffic.

The rest of question is not related to go-ping, but still interesting enough. What makes macOS vanilla ping so special that it doesn't require privilege or getting setuided to create a raw socket? Really curious about this.

CHTJonas commented 3 years ago

It turned out go-ping uses UDP instead of ICMP when --privileged flag is not provided

Yep, that's exactly right. We only ping using actual ICMP if the pinger.SetPrivileged(true) API method is called. On some operating systems this is nothing special but on most *NIX systems, it requires root or special capabilities. If we're unprivileged then we ping using UDP packets instead, although this isn't supported by all operating systems. This is well-documented in the README here.

EDR software tends to block UDP traffic

Cursed. Cursed. Cursed. Cursed. Cursed.

What makes macOS vanilla ping so special that it doesn't require privilege or getting setuided to create a raw socket?

With regards to macOS's builtin /sbin/ping, take a look at https://apple.stackexchange.com/a/312861. You learn something new everyday! 😄