go-ping / ping

ICMP Ping library for Go
MIT License
1.32k stars 344 forks source link

"permission denied" error when pinging subnet ID address or broadcast address with non-privileged pinger #167

Closed andig closed 1 year ago

andig commented 3 years ago

Users reported

ping: write udp 0.0.0.0:64->192.168.178.0:0: sendto: permission denied 

in https://github.com/andig/evcc/pull/986#issuecomment-835888385 for current go-ping on Linux. Known good version is e4e642a95741.

/cc @premultiply

CHTJonas commented 3 years ago

Thanks for the report! I can't replicated this myself so could you please provide a short snippet of code (and maybe the shell commands used) which reliably demonstrate the issue?

Here is what I tried using the built-in cmd/ping/ping.go demo application:

chtjonas@castor:~$ file ping
ping: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, not stripped
chtjonas@castor:~$ sysctl net.ipv4.ping_group_range
net.ipv4.ping_group_range = 0   2147483647
chtjonas@castor:~$ sudo ./ping -c 4 ipv4.google.com
PING ipv4.google.com (172.217.22.142):
24 bytes from 172.217.22.142: icmp_seq=0 time=8.99337ms ttl=107
24 bytes from 172.217.22.142: icmp_seq=1 time=7.938053ms ttl=107
24 bytes from 172.217.22.142: icmp_seq=2 time=8.005211ms ttl=107
24 bytes from 172.217.22.142: icmp_seq=3 time=8.012771ms ttl=107

--- ipv4.google.com ping statistics ---
4 packets transmitted, 4 packets received, 0 duplicates, 0% packet loss
round-trip min/avg/max/stddev = 7.938053ms/8.237352ms/8.99337ms/437.455µs
chtjonas@castor:~$ ./ping -c 4 ipv4.google.com
PING ipv4.google.com (172.217.22.142):
24 bytes from 172.217.22.142: icmp_seq=0 time=7.925695ms ttl=107
24 bytes from 172.217.22.142: icmp_seq=1 time=7.871193ms ttl=107
24 bytes from 172.217.22.142: icmp_seq=2 time=7.901569ms ttl=107
24 bytes from 172.217.22.142: icmp_seq=3 time=7.915567ms ttl=107

--- ipv4.google.com ping statistics ---
4 packets transmitted, 4 packets received, 0 duplicates, 0% packet loss
round-trip min/avg/max/stddev = 7.871193ms/7.903505ms/7.925695ms/20.528µs
chtjonas@castor:~$ sudo ./ping -c 4 ipv6.google.com
PING ipv6.google.com (2a00:1450:4007:809::200e):
24 bytes from 2a00:1450:4007:809::200e: icmp_seq=0 time=8.870537ms ttl=107
24 bytes from 2a00:1450:4007:809::200e: icmp_seq=1 time=8.300181ms ttl=107
24 bytes from 2a00:1450:4007:809::200e: icmp_seq=2 time=8.320312ms ttl=107
24 bytes from 2a00:1450:4007:809::200e: icmp_seq=3 time=8.32382ms ttl=107

--- ipv6.google.com ping statistics ---
4 packets transmitted, 4 packets received, 0 duplicates, 0% packet loss
round-trip min/avg/max/stddev = 8.300181ms/8.453713ms/8.870537ms/240.822µs
chtjonas@castor:~$ ./ping -c 4 ipv6.google.com
PING ipv6.google.com (2a00:1450:4007:809::200e):
24 bytes from 2a00:1450:4007:809::200e: icmp_seq=0 time=9.040099ms ttl=107
24 bytes from 2a00:1450:4007:809::200e: icmp_seq=1 time=8.339378ms ttl=107
24 bytes from 2a00:1450:4007:809::200e: icmp_seq=2 time=8.344845ms ttl=107
24 bytes from 2a00:1450:4007:809::200e: icmp_seq=3 time=8.377961ms ttl=107

--- ipv6.google.com ping statistics ---
4 packets transmitted, 4 packets received, 0 duplicates, 0% packet loss
round-trip min/avg/max/stddev = 8.339378ms/8.525572ms/9.040099ms/297.43µs
andig commented 3 years ago

The code is horribly simple:

pinger, err := ping.NewPinger(in.IP)
if err != nil {
    panic(err)
}

if runtime.GOOS == "windows" {
    pinger.SetPrivileged(true)
}

pinger.Count = h.Count
pinger.Timeout = h.Timeout

if err = pinger.Run(); err != nil {
    log.FATAL.Println("ping:", err)

    if runtime.GOOS != "windows" {
        log.FATAL.Println("")
        log.FATAL.Println("In order to run evcc in discovery mode, make sure to allow ping:")
        log.FATAL.Println("")
        log.FATAL.Println(" sudo sysctl -w net.ipv4.ping_group_range=\"0 2147483647\"")
    }

    log.FATAL.Fatalln("")
}

stat := pinger.Statistics()

Being on OSX I can't repro either, asked user to comment here.

Sillium007 commented 3 years ago

I am not the initial reporter that @andig mentioned but I just tried his evcc on my TinkerBoard (running raspbian) and I see the same thing. Therefore I wanted to try your @CHTJonas commands and wanted to install ping.. but it seems not to be happy:

sillium@tinkerboard:~/evcc$ go get -u github.com/go-ping/ping
# github.com/go-ping/ping
../go/src/github.com/go-ping/ping/ping.go:106:48: undefined: log.Writer
../go/src/github.com/go-ping/ping/ping.go:538:50: invalid operation: 1 << b.c (shift count type int64, must be unsigned integer)

I have no experience with go.. therefore I am not sure what I could do to fix this.

According to a quick google search this could be related to the go version?

sillium@tinkerboard:~/evcc$ go version
go version go1.11.6 linux/arm

sillium@tinkerboard:~/evcc$ cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 10 (buster)"
NAME="Debian GNU/Linux"
VERSION_ID="10"
VERSION="10 (buster)"
VERSION_CODENAME=buster
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
Sillium007 commented 3 years ago

Ok, I updated golang and now it is working:

sillium@tinkerboard:~/evcc$ go version
go version go1.16.5 linux/arm
sillium@tinkerboard:~/go/src/github.com/go-ping/ping/cmd/ping$ file ping
ping: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, Go BuildID=oo7eyJ3RcpYZlvfAJ8Pb/-nSCfI7c2hqG6I4FDps0/oNVlxbI4w3zScgF6utN7/gKEuRE0csmlZWrsu6swq, not stripped

sillium@tinkerboard:~/go/src/github.com/go-ping/ping/cmd/ping$ ./ping -c 4 ipv6.google.com
PING ipv6.google.com (2a00:1450:4001:82b::200e):
24 bytes from 2a00:1450:4001:82b::200e: icmp_seq=0 time=15.357829ms ttl=119
24 bytes from 2a00:1450:4001:82b::200e: icmp_seq=1 time=16.849424ms ttl=119
24 bytes from 2a00:1450:4001:82b::200e: icmp_seq=2 time=14.649366ms ttl=119
24 bytes from 2a00:1450:4001:82b::200e: icmp_seq=3 time=14.771283ms ttl=119

--- ipv6.google.com ping statistics ---
4 packets transmitted, 4 packets received, 0 duplicates, 0% packet loss
round-trip min/avg/max/stddev = 14.649366ms/15.406976ms/16.849424ms/874.807µs

sillium@tinkerboard:~/go/src/github.com/go-ping/ping/cmd/ping$ ./ping -c 4 ipv4.google.com
PING ipv4.google.com (216.58.212.142):
24 bytes from 216.58.212.142: icmp_seq=0 time=15.127703ms ttl=119
24 bytes from 216.58.212.142: icmp_seq=1 time=13.74665ms ttl=119
24 bytes from 216.58.212.142: icmp_seq=2 time=13.448857ms ttl=119
24 bytes from 216.58.212.142: icmp_seq=3 time=13.641357ms ttl=119

--- ipv4.google.com ping statistics ---
4 packets transmitted, 4 packets received, 0 duplicates, 0% packet loss
round-trip min/avg/max/stddev = 13.448857ms/13.991142ms/15.127703ms/664.825µs

sillium@tinkerboard:~/go/src/github.com/go-ping/ping/cmd/ping$ sudo ./ping -c 4 ipv4.google.com
PING ipv4.google.com (216.58.212.142):
24 bytes from 216.58.212.142: icmp_seq=0 time=14.351571ms ttl=119
24 bytes from 216.58.212.142: icmp_seq=1 time=13.583607ms ttl=119
24 bytes from 216.58.212.142: icmp_seq=2 time=13.783109ms ttl=119
24 bytes from 216.58.212.142: icmp_seq=3 time=13.971819ms ttl=119

--- ipv4.google.com ping statistics ---
4 packets transmitted, 4 packets received, 0 duplicates, 0% packet loss
round-trip min/avg/max/stddev = 13.583607ms/13.922526ms/14.351571ms/283.201µs

but still:

sillium@tinkerboard:~/evcc$ ./evcc detect

Auto detection will now start to scan the network for available devices.
Scanning focuses on devices that are commonly used that are detectable with reasonable efforts.
On successful detection, suggestions for EVCC configuration can be made. The suggestions should simplify
configuring EVCC but are probably not sufficient for fully automatic configuration.

[main  ] FATAL 2021/06/29 11:41:26 ping: write udp 0.0.0.0:176->192.168.188.0:0: sendto: permission denied
[main  ] FATAL 2021/06/29 11:41:26
[main  ] FATAL 2021/06/29 11:41:26 In order to run evcc in discovery mode, make sure to allow ping:
[main  ] FATAL 2021/06/29 11:41:26
[main  ] FATAL 2021/06/29 11:41:26      sudo sysctl -w net.ipv4.ping_group_range="0 2147483647"
[main  ] FATAL 2021/06/29 11:41:26
sillium@tinkerboard:~/evcc$ sudo ./evcc detect

Auto detection will now start to scan the network for available devices.
Scanning focuses on devices that are commonly used that are detectable with reasonable efforts.
On successful detection, suggestions for EVCC configuration can be made. The suggestions should simplify
configuring EVCC but are probably not sufficient for fully automatic configuration.

[main  ] FATAL 2021/06/29 11:45:19 ping: write udp 0.0.0.0:203->192.168.188.0:0: sendto: permission denied
[main  ] FATAL 2021/06/29 11:45:19
[main  ] FATAL 2021/06/29 11:45:19 In order to run evcc in discovery mode, make sure to allow ping:
[main  ] FATAL 2021/06/29 11:45:19
[main  ] FATAL 2021/06/29 11:45:19      sudo sysctl -w net.ipv4.ping_group_range="0 2147483647"
[main  ] FATAL 2021/06/29 11:45:19

Also tried compiling evcc myself to see if it makes any difference:

sillium@tinkerboard:~/go/bin$ file evcc
evcc: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, Go BuildID=lYYZDxKUGrRTydJM6P36/iotVMJ08zzJ_7sX8xewK/9DzA0LcKYCK0fBX8KY4A/OgAfxqGWG1rBYL9z_k5w, not stripped

sillium@tinkerboard:~/go/bin$ sudo ./evcc -l trace detect

Auto detection will now start to scan the network for available devices.
Scanning focuses on devices that are commonly used that are detectable with reasonable efforts.
On successful detection, suggestions for EVCC configuration can be made. The suggestions should simplify
configuring EVCC but are probably not sufficient for fully automatic configuration.

[main  ] INFO 2021/06/30 07:55:59 my ip: 192.168.188.38
[main  ] DEBUG 2021/06/30 07:55:59 task: ping {192.168.188.38 0  <nil> <nil> <nil>} -> true
[main  ] DEBUG 2021/06/30 07:55:59 task: ping {127.0.0.1 0  <nil> <nil> <nil>} -> true
[main  ] FATAL 2021/06/30 07:55:59 ping: write udp 0.0.0.0:428->192.168.188.0:0: sendto: permission denied
[main  ] FATAL 2021/06/30 07:55:59
[main  ] FATAL 2021/06/30 07:55:59 In order to run evcc in discovery mode, make sure to allow ping:
[main  ] FATAL 2021/06/30 07:55:59
[main  ] FATAL 2021/06/30 07:55:59      sudo sysctl -w net.ipv4.ping_group_range="0 2147483647"
[main  ] FATAL 2021/06/30 07:55:59
Sillium007 commented 3 years ago

Just noticed that evcc is trying to ping an address ending in "0". Therefore I tried the same thing with ping:

sillium@tinkerboard:~/evcc/compile/ping/cmd/ping$ git checkout ff8be33
Previous HEAD position was e4e642a Use exponential backoff for read deadline (#162)
HEAD is now at ff8be33 Provide an abstraction over icmp.PacketConn (#166)

sillium@tinkerboard:~/evcc/compile/ping/cmd/ping$ go build -o ptest

sillium@tinkerboard:~/evcc/compile/ping/cmd/ping$ ./ptest -c 2 -i 500ms 192.168.188.0
PING 192.168.188.0 (192.168.188.0):

--- 192.168.188.0 ping statistics ---
0 packets transmitted, 0 packets received, 0 duplicates, NaN% packet loss
round-trip min/avg/max/stddev = 0s/0s/0s/0s
Failed to ping target host: write udp 0.0.0.0:1088->192.168.188.0:0: sendto: permission denied
sillium@tinkerboard:~/evcc/compile/ping/cmd/ping$ git checkout e4e642a95741c494990b0c8126988d1fd3a5449c
Previous HEAD position was ff8be33 Provide an abstraction over icmp.PacketConn (#166)
HEAD is now at e4e642a Use exponential backoff for read deadline (#162)

sillium@tinkerboard:~/evcc/compile/ping/cmd/ping$ go build -o ptest

sillium@tinkerboard:~/evcc/compile/ping/cmd/ping$ ./ptest -c 2 -i 500ms 192.168.188.0
PING 192.168.188.0 (192.168.188.0):
^C
--- 192.168.188.0 ping statistics ---
2 packets transmitted, 0 packets received, 0 duplicates, 100% packet loss
round-trip min/avg/max/stddev = 0s/0s/0s/0s

So the latest commit (ff8be33) changed something when it comes to "0" and "255" addresses. Which to my understanding are broadcast addresses. I guess the question is if this is really an error or not intended to be used as a ping target :)

andig commented 3 years ago

@CHTJonas so root cause is understood- different handling of subnet and broadcast IP addresses. Do you want to close this? Would it make sense to provide an option for the iterator to only output "addressable" IPs?

CHTJonas commented 3 years ago

I see what's going on here and I can replicate it. Thanks for the good investigative bug reporting!

We should probably look into whether we can add some kind of detection for this when the pinger is non-privileged, though I'm not sure how easy it will be to detect if the destination IP is the start or end of the subnet.

Sillium007 commented 3 years ago

Don't know if it could be of any use for you but this is how we implemented the detection if it is the start or end of a subnet: https://github.com/evcc-io/evcc/blob/master/cmd/detect.go#L46 Using github.com/korylprince/ipnetgen we get the subnet addresses and drop the first and last address.