Repository: go
Issue: x/net/ipv6: ControlMessage considers HopLimit==0 as missing
Labels: NeedsInvestigation

### What version of Go are you using (`go version`)?

<pre>
$ go version
go1.14.9
</pre>

### Does this issue reproduce with the latest release?

Yes

### 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"
GOBIN=""
GOCACHE="/home/luizluca/.cache/go-build"
GOENV="/home/luizluca/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/luizluca/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/lib64/go/1.14"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/lib64/go/1.14/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/home/luizluca/prog/blackbox_exporter/go.mod"
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-build078173291=/tmp/go-build -gno-record-gcc-switches"
</pre></details>

### What did you do?

According to [RFC8200](https://tools.ietf.org/html/rfc8200)

      Hop Limit           8-bit unsigned integer.  Decremented by 1 by
                          each node that forwards the packet.  When
                          forwarding, the packet is discarded if Hop
                          Limit was zero when received or is decremented
                          to zero.  A node that is the destination of a
                          packet should not discard a packet with Hop
                          Limit equal to zero; it should process the
                          packet normally.

So, HopLimit == 0 is perfectly valid for sending to targets inside the same subnet or even receiving a packet with HopLimit 0. In, practice, sending both HopLimit==1 or HopLimit==0 are equals as both avoid it to be forwarded to a different network. The difference is when it is received. If a host receives a packet with HopLimit==0, it can say it was never forwarded while HopLimit==1 might simply be using the last permitted hop.

However, ipv6.ControlMessage tells me that it must be between 1 and 255.

	HopLimit     int    // hop limit, must be 1 <= value <= 255 when specifying
        https://github.com/golang/net/blob/a7d1128ccaa05167332a625f69773af1a0c6b39c/ipv6/control.go#L57

So, it should accept HopLimit as 0 <= value <= 255. This brings a seconds issue: the initial value of HopLimit (as for any non explicitly initialized integer inside go) is 0. There is no direct way to tell if ControlMessage HopLimit is missing or defined as zero.
Go also ignores when I set it as 0 for WriteTo().

Maybe an easy fix would be to set it initially to -1.

BTW, IPv4 TTL does not have the same issue as a packet with TTL==0 must be destroyed unconditionally.

### What did you expect to see?

Something like:

```
+++ https://github.com/golang/net/blob/a7d1128ccaa05167332a625f69773af1a0c6b39c/ipv6/control.go#L57
-        	HopLimit     int    // hop limit, must be 1 <= value <= 255 when specifying
+        	HopLimit     int = -1 // hop limit, must be 0 <= value <= 255 when specifying

+++ https://github.com/golang/net/blob/a7d1128ccaa05167332a625f69773af1a0c6b39c/ipv6/control.go#L84
-	if ctlOpts[ctlHopLimit].name > 0 && cm.HopLimit > 0 {
+	if ctlOpts[ctlHopLimit].name > 0 && cm.HopLimit >= 0 {  
```

Should I submit a PR?

### What did you see instead?

I cannot set ControlMessage.HopLimit as 0 in ipv6.WriteTo() nor I can tell that ControlMessage.HopLimit in ipv6.ReadFrom() is missing or zero.