Skip to content

Commit

Permalink
uid auth: fixed to run on systems with disabled IPv6 support
Browse files Browse the repository at this point in the history
  • Loading branch information
alexpevzner committed Jul 22, 2024
1 parent 0f6a45c commit df9f47f
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 10 deletions.
28 changes: 22 additions & 6 deletions tcpuid_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ func TCPClientUIDSupported() bool {
// TCPClientUID obtains UID of client process that created
// TCP connection over the loopback interface
func TCPClientUID(client, server *net.TCPAddr) (int, error) {
// Obtain protocol family. Check for mismatch.
clientIs4 := client.IP.To4() != nil
serverIs4 := server.IP.To4() != nil

if clientIs4 != serverIs4 {
return -1, fmt.Errorf("TCPClientUID: IP4/IP6 mismatchh")
}

// Open NETLINK_SOCK_DIAG socket
sock, err := sockDiagOpen()
if err != nil {
Expand All @@ -59,19 +67,27 @@ func TCPClientUID(client, server *net.TCPAddr) (int, error) {
rq.hdr.nlmsg_type = C.uint16_t(C.SOCK_DIAG_BY_FAMILY)
rq.hdr.nlmsg_flags = C.uint16_t(C.NLM_F_REQUEST)

rq.data.sdiag_family = C.AF_INET6
if clientIs4 {
rq.data.sdiag_family = C.AF_INET
copy((*[16]byte)(unsafe.Pointer(&rq.data.id.idiag_src))[:],
client.IP.To4())
copy((*[16]byte)(unsafe.Pointer(&rq.data.id.idiag_dst))[:],
server.IP.To4())
} else {
rq.data.sdiag_family = C.AF_INET6
copy((*[16]byte)(unsafe.Pointer(&rq.data.id.idiag_src))[:],
client.IP.To16())
copy((*[16]byte)(unsafe.Pointer(&rq.data.id.idiag_dst))[:],
server.IP.To16())
}

rq.data.sdiag_protocol = C.IPPROTO_TCP
rq.data.idiag_states = 1 << C.TCP_ESTABLISHED
rq.data.id.idiag_sport = C.uint16_t(toBE16((uint16(client.Port))))
rq.data.id.idiag_dport = C.uint16_t(toBE16((uint16(server.Port))))
rq.data.id.idiag_cookie[0] = C.INET_DIAG_NOCOOKIE
rq.data.id.idiag_cookie[1] = C.INET_DIAG_NOCOOKIE

copy((*[16]byte)(unsafe.Pointer(&rq.data.id.idiag_src))[:],
client.IP.To16())
copy((*[16]byte)(unsafe.Pointer(&rq.data.id.idiag_dst))[:],
server.IP.To16())

// Send request
rqData := (*[unsafe.Sizeof(rq)]byte)(unsafe.Pointer(&rq))
rqAddr := &syscall.SockaddrNetlink{Family: syscall.AF_NETLINK}
Expand Down
35 changes: 31 additions & 4 deletions tcpuid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,52 @@ import (

// doTestTCPClientUID performs TCPClientUID for the specified
// network and loopback address
func doTestTCPClientUID(t *testing.T, network, loopback string) {
func doTestTCPClientUID(t *testing.T, ip4 bool) {
// Do nothing if TCPClientUID is not supported by the platform
if !TCPClientUIDSupported() {
return
}

// Log local addresses
// Log local addresses. Check that we have appropriate
// address family support, configured in the system.
var haveIP4, haveIP6 bool

if ift, err := net.Interfaces(); err == nil {
for _, ifi := range ift {
if addrs, err := ifi.Addrs(); err == nil {
t.Logf("%s:", ifi.Name)
for _, addr := range addrs {
t.Logf(" %s", addr)

if ipnet, ok := addr.(*net.IPNet); ok {
if ipnet.IP.To4() != nil {
haveIP4 = true
} else {
haveIP6 = true
}
}
}
}
}
}

// Skip incompatible address families
if ip4 && !haveIP4 {
return
}

if !ip4 && !haveIP6 {
return
}

// Create loopback listener -- it gives us a port
network := "tcp4"
loopback := "127.0.0.1"
if !ip4 {
loopback = "[::1]"
network = "tcp6"
}

l, err := net.Listen(network, loopback+":")
if err != nil {
t.Fatalf("net.Listen(%q,%q): %s", network, loopback+":", err)
Expand Down Expand Up @@ -76,10 +103,10 @@ func doTestTCPClientUID(t *testing.T, network, loopback string) {

// TestTCPClientUIDIp4 performs TCPClientUID test for IPv4
func TestTCPClientUIDIp4(t *testing.T) {
doTestTCPClientUID(t, "tcp", "127.0.0.1")
doTestTCPClientUID(t, true)
}

// TestTCPClientUIDIp6 performs TCPClientUID test for IPv6
func TestTCPClientUIDIp6(t *testing.T) {
doTestTCPClientUID(t, "tcp6", "[::1]")
doTestTCPClientUID(t, false)
}

0 comments on commit df9f47f

Please sign in to comment.