123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- package process
- import (
- "encoding/binary"
- "net/netip"
- "strconv"
- "strings"
- "syscall"
- "unsafe"
- "golang.org/x/sys/unix"
- )
- const (
- procpidpathinfo = 0xb
- procpidpathinfosize = 1024
- proccallnumpidinfo = 0x2
- )
- var structSize = func() int {
- value, _ := syscall.Sysctl("kern.osrelease")
- major, _, _ := strings.Cut(value, ".")
- n, _ := strconv.ParseInt(major, 10, 64)
- switch true {
- case n >= 22:
- return 408
- default:
-
-
-
-
- return 384
- }
- }()
- func findProcessName(network string, ip netip.Addr, port int) (uint32, string, error) {
- var spath string
- switch network {
- case TCP:
- spath = "net.inet.tcp.pcblist_n"
- case UDP:
- spath = "net.inet.udp.pcblist_n"
- default:
- return 0, "", ErrInvalidNetwork
- }
- isIPv4 := ip.Is4()
- value, err := unix.SysctlRaw(spath)
- if err != nil {
- return 0, "", err
- }
- buf := value
- itemSize := structSize
- if network == TCP {
-
- itemSize += 208
- }
- var fallbackUDPProcess string
-
- for i := 24; i+itemSize <= len(buf); i += itemSize {
-
- inp, so := i, i+104
- srcPort := binary.BigEndian.Uint16(buf[inp+18 : inp+20])
- if uint16(port) != srcPort {
- continue
- }
-
- flag := buf[inp+44]
- var (
- srcIP netip.Addr
- srcIsIPv4 bool
- )
- switch {
- case flag&0x1 > 0 && isIPv4:
-
- srcIP, _ = netip.AddrFromSlice(buf[inp+76 : inp+80])
- srcIsIPv4 = true
- case flag&0x2 > 0 && !isIPv4:
-
- srcIP, _ = netip.AddrFromSlice(buf[inp+64 : inp+80])
- default:
- continue
- }
- if ip == srcIP {
-
- pid := readNativeUint32(buf[so+68 : so+72])
- pp, err := getExecPathFromPID(pid)
- return 0, pp, err
- }
-
- if network == UDP && srcIP.IsUnspecified() && isIPv4 == srcIsIPv4 {
- fallbackUDPProcess, _ = getExecPathFromPID(readNativeUint32(buf[so+68 : so+72]))
- }
- }
- if network == UDP && fallbackUDPProcess != "" {
- return 0, fallbackUDPProcess, nil
- }
- return 0, "", ErrNotFound
- }
- func getExecPathFromPID(pid uint32) (string, error) {
- buf := make([]byte, procpidpathinfosize)
- _, _, errno := syscall.Syscall6(
- syscall.SYS_PROC_INFO,
- proccallnumpidinfo,
- uintptr(pid),
- procpidpathinfo,
- 0,
- uintptr(unsafe.Pointer(&buf[0])),
- procpidpathinfosize)
- if errno != 0 {
- return "", errno
- }
- return unix.ByteSliceToString(buf), nil
- }
- func readNativeUint32(b []byte) uint32 {
- return *(*uint32)(unsafe.Pointer(&b[0]))
- }
|