Repository: go
Issue: syscall: Peername() does not work on socketpair sockets on Illumos
Labels: OS-Solaris,NeedsInvestigation,OS-illumos,compiler/runtime

### What version of Go are you using (`go version`)?

<pre>
$ go version
go version go1.17.5 linux/amd64
</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
O111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/cs/.cache/go-build"
GOENV="/home/cs/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/cs/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/cs/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/home/cs/go1.17.5"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/home/cs/go1.17.5/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.17.5"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/home/cs/zrepl/zrepl/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-build1505417924=/tmp/go-build -gno-record-gcc-switches"
</pre></details>

### What did you do?

(This is the presumed root cause for https://github.com/zrepl/zrepl/issues/598 )

Take the following code snippet:

```
package main

import (
	"log"
	"syscall"
)

func main() {
	fds, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
	if err != nil {
		panic(err)
	}

	sockname, err := syscall.Getsockname(fds[0])
	if err != nil {
		panic(err)
	}

	peername, err := syscall.Getpeername(fds[0])
	if err != nil {
		panic(err)
	}

	log.Printf("socketname=%T %#v", sockname, sockname)
	log.Printf("peername=%T %#v", peername, peername)
}
```

### What did you expect to see?

On Linux, it prints

```
2022/07/08 00:30:11 socketname=*syscall.SockaddrUnix &syscall.SockaddrUnix{Name:"@", raw:syscall.RawSockaddrUnix{Family:0x0, Path:[108]int8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}}
2022/07/08 00:30:11 peername=*syscall.SockaddrUnix &syscall.SockaddrUnix{Name:"@", raw:syscall.RawSockaddrUnix{Family:0x0, Path:[108]int8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}}
```

On Illumos (`SunOS openindiana 5.11 illumos-e302d6af52 i86pc i386 i86pc`), `Getpeername` appears to not work

```
root@openindiana:~# /opt/iss-589-repro 
panic: address family not supported by protocol family

goroutine 1 [running]:
main.main()
        /home/cs/zrepl/zrepl/iss-589/iss-589-repro.go:21 +0x237
```

Ccompiled with
```
GOARCH=amd64 GOOS=illumos go build -o iss-589-repro ./iss-589
scp iss-589-repro root@192.168.122.33:/opt/
```

However, a corresponding C program works fine on both platforms, i.e., the `getpeername` libc call returns no error.

```
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <aio.h>

int main() {

    int fds[2];
    int err = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
    if (err != 0)
        abort();

    struct sockaddr_un name;
    socklen_t len = sizeof(name);
    err = getpeername(fds[0], (struct sockaddr *)&name, &len);
    if (err != 0)
        abort();

    printf("sun_path=%s\n", name.sun_path);

    return 0;
}
```

Compiled with:

```
gcc -lsocket test.c
```

Relevant `truss` of the Go program:

```
/1:     so_socket(PF_UNIX, SOCK_STREAM, 0, 0x00000000, SOV_XPG4_2) = 3
/1:     so_socket(PF_UNIX, SOCK_STREAM, 0, 0x00000000, SOV_XPG4_2) = 4
/1:     so_socketpair(0xC00004EEC8)                     = 0
/1:     close(3)                                        = 0
/1:     getsockname(5, 0xC00004EDD4, 0xC00004EDD0, SOV_DEFAULT) = 0
/1:     getpeername(5, 0xC00004EDD4, 0xC00004EDD0, SOV_DEFAULT) = 0
```

Relevant `truss` of the C program:

```
so_socket(PF_UNIX, SOCK_STREAM, 0, 0x00000000, SOV_DEFAULT) = 3
so_socket(PF_UNIX, SOCK_STREAM, 0, 0x00000000, SOV_DEFAULT) = 4
so_socketpair(0x7FFFBFFFD4D4)                   = 0
close(3)                                        = 0
getpeername(5, 0x7FFFBFFFD460, 0x7FFFBFFFD45C, SOV_DEFAULT) = 0
```