1
0

Fix: process resolving for udp (#2806)

This commit is contained in:
Kr328 2023-06-25 09:19:06 +08:00 committed by GitHub
parent e26bed43de
commit 5212aaf445
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 80 additions and 43 deletions

View File

@ -23,32 +23,32 @@ type InEndpoints12 struct {
type XTcpcb12 struct { type XTcpcb12 struct {
Len uint32 // offset 0 Len uint32 // offset 0
Padding1 [20]byte // offset 4 _ [20]byte // offset 4
SocketAddr uint64 // offset 24 SocketAddr uint64 // offset 24
Padding2 [84]byte // offset 32 _ [84]byte // offset 32
Family uint32 // offset 116 Family uint32 // offset 116
Padding3 [140]byte // offset 120 _ [140]byte // offset 120
InEndpoints InEndpoints12 // offset 260 InEndpoints InEndpoints12 // offset 260
Padding4 [444]byte // offset 300 _ [444]byte // offset 300
} // size 744 } // size 744
type XInpcb12 struct { type XInpcb12 struct {
Len uint32 // offset 0 Len uint32 // offset 0
Padding1 [12]byte // offset 4 _ [12]byte // offset 4
SocketAddr uint64 // offset 16 SocketAddr uint64 // offset 16
Padding2 [84]byte // offset 24 _ [84]byte // offset 24
Family uint32 // offset 108 Family uint32 // offset 108
Padding3 [140]byte // offset 112 _ [140]byte // offset 112
InEndpoints InEndpoints12 // offset 252 InEndpoints InEndpoints12 // offset 252
Padding4 [108]byte // offset 292 _ [108]byte // offset 292
} // size 400 } // size 400
type XFile12 struct { type XFile12 struct {
Size uint64 // offset 0 Size uint64 // offset 0
Pid uint32 // offset 8 Pid uint32 // offset 8
Padding1 [44]byte // offset 12 _ [44]byte // offset 12
DataAddr uint64 // offset 56 DataAddr uint64 // offset 56
Padding2 [64]byte // offset 64 _ [64]byte // offset 64
} // size 128 } // size 128
var majorVersion = func() int { var majorVersion = func() int {
@ -144,7 +144,6 @@ func findProcessPath12(network string, from netip.AddrPort, to netip.AddrPort) (
data = data[icb.Len:] data = data[icb.Len:]
var connFromAddr netip.Addr var connFromAddr netip.Addr
if icb.Family == unix.AF_INET { if icb.Family == unix.AF_INET {
connFromAddr = netip.AddrFrom4([4]byte(icb.InEndpoints.LAddr[12:16])) connFromAddr = netip.AddrFrom4([4]byte(icb.InEndpoints.LAddr[12:16]))
} else if icb.Family == unix.AF_INET6 { } else if icb.Family == unix.AF_INET6 {
@ -153,9 +152,9 @@ func findProcessPath12(network string, from netip.AddrPort, to netip.AddrPort) (
continue continue
} }
connFrom := netip.AddrPortFrom(connFromAddr, binary.BigEndian.Uint16(icb.InEndpoints.LPort[:])) connFromPort := binary.BigEndian.Uint16(icb.InEndpoints.LPort[:])
if connFrom == from { if (connFromAddr == from.Addr() || connFromAddr.IsUnspecified()) && connFromPort == from.Port() {
pid, err := findPidBySocketAddr12(icb.SocketAddr) pid, err := findPidBySocketAddr12(icb.SocketAddr)
if err != nil { if err != nil {
return "", err return "", err
@ -208,7 +207,8 @@ func findExecutableByPid(pid uint32) (string, error) {
uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&buf[0])),
uintptr(unsafe.Pointer(&size)), uintptr(unsafe.Pointer(&size)),
0, 0,
0) 0,
)
if errno != 0 || size == 0 { if errno != 0 || size == 0 {
return "", fmt.Errorf("sysctl: get proc name: %w", errno) return "", fmt.Errorf("sysctl: get proc name: %w", errno)
} }

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"net"
"net/netip" "net/netip"
"os" "os"
"unsafe" "unsafe"
@ -59,40 +60,65 @@ func findProcessPath(network string, from netip.AddrPort, to netip.AddrPort) (st
} }
func resolveSocketByNetlink(network string, from netip.AddrPort, to netip.AddrPort) (inode uint32, uid uint32, err error) { func resolveSocketByNetlink(network string, from netip.AddrPort, to netip.AddrPort) (inode uint32, uid uint32, err error) {
request := &inetDiagRequest{ var families []byte
States: 0xffffffff, if from.Addr().Unmap().Is4() {
Cookie: [2]uint32{0xffffffff, 0xffffffff}, families = []byte{unix.AF_INET, unix.AF_INET6}
}
if from.Addr().Is4() {
request.Family = unix.AF_INET
} else { } else {
request.Family = unix.AF_INET6 families = []byte{unix.AF_INET6, unix.AF_INET}
} }
// Swap src & dst for udp var protocol byte
// See also https://www.mail-archive.com/netdev@vger.kernel.org/msg248638.html
switch network { switch network {
case TCP: case TCP:
request.Protocol = unix.IPPROTO_TCP protocol = unix.IPPROTO_TCP
copy(request.Src[:], from.Addr().AsSlice())
copy(request.Dst[:], to.Addr().AsSlice())
binary.BigEndian.PutUint16(request.SrcPort[:], from.Port())
binary.BigEndian.PutUint16(request.DstPort[:], to.Port())
case UDP: case UDP:
request.Protocol = unix.IPPROTO_UDP protocol = unix.IPPROTO_UDP
copy(request.Dst[:], from.Addr().AsSlice())
copy(request.Src[:], to.Addr().AsSlice())
binary.BigEndian.PutUint16(request.DstPort[:], from.Port())
binary.BigEndian.PutUint16(request.SrcPort[:], to.Port())
default: default:
return 0, 0, ErrInvalidNetwork return 0, 0, ErrInvalidNetwork
} }
if protocol == unix.IPPROTO_UDP {
// Swap from & to for udp
// See also https://www.mail-archive.com/netdev@vger.kernel.org/msg248638.html
from, to = to, from
}
for _, family := range families {
inode, uid, err = resolveSocketByNetlinkExact(family, protocol, from, to, netlink.Request)
if err == nil {
return inode, uid, err
}
}
return 0, 0, ErrNotFound
}
func resolveSocketByNetlinkExact(family byte, protocol byte, from netip.AddrPort, to netip.AddrPort, flags netlink.HeaderFlags) (inode uint32, uid uint32, err error) {
request := &inetDiagRequest{
Family: family,
Protocol: protocol,
States: 0xffffffff,
Cookie: [2]uint32{0xffffffff, 0xffffffff},
}
var (
fromAddr []byte
toAddr []byte
)
if family == unix.AF_INET {
fromAddr = net.IP(from.Addr().AsSlice()).To4()
toAddr = net.IP(to.Addr().AsSlice()).To4()
} else {
fromAddr = net.IP(from.Addr().AsSlice()).To16()
toAddr = net.IP(to.Addr().AsSlice()).To16()
}
copy(request.Src[:], fromAddr)
copy(request.Dst[:], toAddr)
binary.BigEndian.PutUint16(request.SrcPort[:], from.Port())
binary.BigEndian.PutUint16(request.DstPort[:], to.Port())
conn, err := netlink.Dial(unix.NETLINK_INET_DIAG, nil) conn, err := netlink.Dial(unix.NETLINK_INET_DIAG, nil)
if err != nil { if err != nil {
return 0, 0, err return 0, 0, err
@ -102,7 +128,7 @@ func resolveSocketByNetlink(network string, from netip.AddrPort, to netip.AddrPo
message := netlink.Message{ message := netlink.Message{
Header: netlink.Header{ Header: netlink.Header{
Type: 20, // SOCK_DIAG_BY_FAMILY Type: 20, // SOCK_DIAG_BY_FAMILY
Flags: netlink.Request, Flags: flags,
}, },
Data: (*(*[unsafe.Sizeof(*request)]byte)(unsafe.Pointer(request)))[:], Data: (*(*[unsafe.Sizeof(*request)]byte)(unsafe.Pointer(request)))[:],
} }

View File

@ -28,7 +28,7 @@ func testConn(t *testing.T, network, address string) {
} }
defer rConn.Close() defer rConn.Close()
path, err := FindProcessPath(TCP, netip.MustParseAddrPort(conn.LocalAddr().String()), netip.MustParseAddrPort(conn.RemoteAddr().String())) path, err := FindProcessPath(TCP, conn.LocalAddr().(*net.TCPAddr).AddrPort(), conn.RemoteAddr().(*net.TCPAddr).AddrPort())
if err != nil { if err != nil {
assert.FailNow(t, "Find process path failed", err) assert.FailNow(t, "Find process path failed", err)
} }
@ -68,7 +68,12 @@ func testPacketConn(t *testing.T, network, lAddress, rAddress string) {
assert.FailNow(t, "Send message failed", err) assert.FailNow(t, "Send message failed", err)
} }
path, err := FindProcessPath(UDP, netip.MustParseAddrPort(lConn.LocalAddr().String()), netip.MustParseAddrPort(rConn.LocalAddr().String())) _, lAddr, err := rConn.ReadFrom([]byte{0})
if err != nil {
assert.FailNow(t, "Receive message failed", err)
}
path, err := FindProcessPath(UDP, lAddr.(*net.UDPAddr).AddrPort(), rConn.LocalAddr().(*net.UDPAddr).AddrPort())
if err != nil { if err != nil {
assert.FailNow(t, "Find process path", err) assert.FailNow(t, "Find process path", err)
} }
@ -88,6 +93,12 @@ func TestFindProcessPathUDP(t *testing.T) {
t.Run("v6", func(t *testing.T) { t.Run("v6", func(t *testing.T) {
testPacketConn(t, "udp6", "[::1]:0", "[::1]:0") testPacketConn(t, "udp6", "[::1]:0", "[::1]:0")
}) })
t.Run("v4AnyLocal", func(t *testing.T) {
testPacketConn(t, "udp4", "0.0.0.0:0", "127.0.0.1:0")
})
t.Run("v6AnyLocal", func(t *testing.T) {
testPacketConn(t, "udp6", "[::]:0", "[::1]:0")
})
} }
func BenchmarkFindProcessName(b *testing.B) { func BenchmarkFindProcessName(b *testing.B) {

View File

@ -168,7 +168,7 @@ loop:
localAddr := netip.AddrFrom4(entry.LocalAddr) localAddr := netip.AddrFrom4(entry.LocalAddr)
localPort := windows.Ntohs(uint16(entry.LocalPort)) localPort := windows.Ntohs(uint16(entry.LocalPort))
if localAddr == from.Addr() && localPort == from.Port() { if (localAddr == from.Addr() || localAddr.IsUnspecified()) && localPort == from.Port() {
return entry.OwningPid, nil return entry.OwningPid, nil
} }
} }
@ -189,7 +189,7 @@ loop:
localAddr := netip.AddrFrom16(entry.LocalAddr) localAddr := netip.AddrFrom16(entry.LocalAddr)
localPort := windows.Ntohs(uint16(entry.LocalPort)) localPort := windows.Ntohs(uint16(entry.LocalPort))
if localAddr == from.Addr() && localPort == from.Port() { if (localAddr == from.Addr() || localAddr.IsUnspecified()) && localPort == from.Port() {
return entry.OwningPid, nil return entry.OwningPid, nil
} }
} }