//go:build linux package agentssh import ( "errors" "fmt" "os" "github.com/cakturk/go-netstat/netstat" "golang.org/x/xerrors" ) func getListeningPortProcessCmdline(port uint32) (string, error) { acceptFn := func(s *netstat.SockTabEntry) bool { return s.LocalAddr != nil && uint32(s.LocalAddr.Port) == port } tabs4, err4 := netstat.TCPSocks(acceptFn) tabs6, err6 := netstat.TCP6Socks(acceptFn) // In the common case, we want to check ipv4 listening addresses. If this // fails, we should return an error. We also need to check ipv6. The // assumption is, if we have an err4, and 0 ipv6 addresses listed, then we are // interested in the err4 (and vice versa). So return both errors (at least 1 // is non-nil) if the other list is empty. if (err4 != nil && len(tabs6) == 0) || (err6 != nil && len(tabs4) == 0) { return "", xerrors.Errorf("inspect port %d: %w", port, errors.Join(err4, err6)) } var proc *netstat.Process if len(tabs4) > 0 { proc = tabs4[0].Process } else if len(tabs6) > 0 { proc = tabs6[0].Process } if proc == nil { // Either nothing is listening on this port or we were unable to read the // process details (permission issues reading /proc/$pid/* potentially). // Or, perhaps /proc/net/tcp{,6} is not listing the port for some reason. return "", nil } // The process name provided by go-netstat does not include the full command // line so grab that instead. pid := proc.Pid data, err := os.ReadFile(fmt.Sprintf("/proc/%d/cmdline", pid)) if err != nil { return "", xerrors.Errorf("read /proc/%d/cmdline: %w", pid, err) } return string(data), nil }