Repository: go
Issue: x/net/icmp: bind fails SOCK_DGRAM IPPROTO_ICMP
Labels: NeedsInvestigation

<!--
Please answer these questions before submitting your issue. Thanks!
For questions please use one of our forums: https://github.com/golang/go/wiki/Questions
-->

### What version of Go are you using (`go version`)?

<pre>
$ go version
go version go1.14.2 linux/amd64
</pre>

### Does this issue reproduce with the latest release?

Yes (tested against go1.14.4)

### What operating system and processor architecture are you using (`go env`)?

<details><summary><code>go env</code> Output</summary><br><pre>
$ go env
GO111MODULE=""
GOARCH="amd64"
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build062765693=/tmp/go-build -gno-record-gcc-switches"
</pre></details>

### What did you do?
<!--
If possible, provide a recipe for reproducing the error.
A complete runnable program is good.
A link on play.golang.org is best.
-->

The following simple test program fails with "bind: permission denied" on Linux 5.0.16-100.fc28.x86_64.

```
package main

import (
	"fmt"
	"os"
	"time"

	"github.com/sparrc/go-ping"
)

func main() {
	pinger, err := ping.NewPinger("www.google.com")
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	}

	pinger.Count = 5
	pinger.Timeout = 1500 * time.Millisecond
	pinger.Interval = 200 * time.Millisecond
	pinger.Source = "192.168.0.36"
	pinger.SetPrivileged(false)
	pinger.Run()

	s := pinger.Statistics()
	fmt.Printf("Packets send    : %d\n", s.PacketsSent)
	fmt.Printf("Packets received: %d\n", s.PacketsRecv)
	fmt.Printf("Min roundtrip   : %.2fms\n", float64(s.MinRtt.Microseconds())/1000.0)
	fmt.Printf("Max roundtrip   : %.2fms\n", float64(s.MaxRtt.Microseconds())/1000.0)
}
```

The ping library used above depends on golang.org/x/net/icmp.

Not sure if this is relevant or not, but the system where the above was tested uses a bridge interface with an IP address configured and the physical network interface is attached to the bridge:

```
2: enp32s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master phy0 state UP group default qlen 1000
    link/ether 00:26:b9:a3:5a:b9 brd ff:ff:ff:ff:ff:ff
3: phy0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 00:26:b9:a3:5a:b9 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.36/24 brd 192.168.0.255 scope global dynamic noprefixroute phy0
       valid_lft 77073sec preferred_lft 77073sec
```

### What did you expect to see?
```
$ go build .
$ ./ping
Packets send    : 5                                                                                                              
Packets received: 5                                                                                                              
Min roundtrip   : 9.89ms                                                                                                         
Max roundtrip   : 10.72ms                                                                                                        
```

### What did you see instead?
```
$ go build .
$ ./ping
Error listening for ICMP packets: bind: permission denied                           
Packets send    : 0                                                      
Packets received: 0                                           
Min roundtrip   : 0.00ms                                       
Max roundtrip   : 0.00ms                                                                                                         
```

Making the following change to x/net/icmp/listen_posix.go results in expected behaviour:

```
--- listen_posix.go.orig	2020-06-27 17:27:59.013649798 +0100
+++ listen_posix.go	2020-06-27 17:28:38.219901503 +0100
@@ -74,15 +74,17 @@
 				return nil, os.NewSyscallError("setsockopt", err)
 			}
 		}
-		sa, err := sockaddr(family, address)
-		if err != nil {
-			syscall.Close(s)
-			return nil, err
-		}
-		if err := syscall.Bind(s, sa); err != nil {
-			syscall.Close(s)
-			return nil, os.NewSyscallError("bind", err)
-		}
+		/*
+			sa, err := sockaddr(family, address)
+			if err != nil {
+				syscall.Close(s)
+				return nil, err
+			}
+			if err := syscall.Bind(s, sa); err != nil {
+				syscall.Close(s)
+				return nil, os.NewSyscallError("bind", err)
+			}
+		*/
 		f := os.NewFile(uintptr(s), "datagram-oriented icmp")
 		c, cerr = net.FilePacketConn(f)
 		f.Close()
```

Using "0.0.0.0" or "" as source address makes no difference.