mirror of https://github.com/coder/coder.git
52 lines
1.6 KiB
Go
52 lines
1.6 KiB
Go
//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
|
|
}
|