From 4e5f54c45a167a77d26018ed49d2f9db8c98172b Mon Sep 17 00:00:00 2001 From: Asher Date: Tue, 16 Jan 2024 11:51:30 -0900 Subject: [PATCH 1/2] fix: detect JetBrains running on local ipv6 --- agent/agentssh/portinspection_supported.go | 28 +++++++++++++++------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/agent/agentssh/portinspection_supported.go b/agent/agentssh/portinspection_supported.go index d45847bd6f0b6..600651ab09c65 100644 --- a/agent/agentssh/portinspection_supported.go +++ b/agent/agentssh/portinspection_supported.go @@ -3,6 +3,7 @@ package agentssh import ( + "errors" "fmt" "os" @@ -11,24 +12,33 @@ import ( ) func getListeningPortProcessCmdline(port uint32) (string, error) { - tabs, err := netstat.TCPSocks(func(s *netstat.SockTabEntry) bool { + acceptFn := func(s *netstat.SockTabEntry) bool { return s.LocalAddr != nil && uint32(s.LocalAddr.Port) == port - }) - if err != nil { - return "", xerrors.Errorf("inspect port %d: %w", port, err) } - if len(tabs) == 0 { - return "", nil + tabs, err := netstat.TCPSocks(acceptFn) + tabs6, err6 := netstat.TCP6Socks(acceptFn) + + // Only return the error if the other method found nothing. + if (err != nil && len(tabs6) == 0) || (err6 != nil && len(tabs) == 0) { + return "", xerrors.Errorf("inspect port %d: %w", port, errors.Join(err, err6)) } - // Defensive check. - if tabs[0].Process == nil { + var proc *netstat.Process + if len(tabs) > 0 { + proc = tabs[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 := tabs[0].Process.Pid + 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) From 9ca9c3ed5a45fc4f8c70ce3408af582cb2adcf7b Mon Sep 17 00:00:00 2001 From: Asher Date: Wed, 17 Jan 2024 13:49:29 -0900 Subject: [PATCH 2/2] fixup! fix: detect JetBrains running on local ipv6 --- agent/agentssh/portinspection_supported.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/agent/agentssh/portinspection_supported.go b/agent/agentssh/portinspection_supported.go index 600651ab09c65..f8c379cecc73f 100644 --- a/agent/agentssh/portinspection_supported.go +++ b/agent/agentssh/portinspection_supported.go @@ -15,17 +15,21 @@ func getListeningPortProcessCmdline(port uint32) (string, error) { acceptFn := func(s *netstat.SockTabEntry) bool { return s.LocalAddr != nil && uint32(s.LocalAddr.Port) == port } - tabs, err := netstat.TCPSocks(acceptFn) + tabs4, err4 := netstat.TCPSocks(acceptFn) tabs6, err6 := netstat.TCP6Socks(acceptFn) - // Only return the error if the other method found nothing. - if (err != nil && len(tabs6) == 0) || (err6 != nil && len(tabs) == 0) { - return "", xerrors.Errorf("inspect port %d: %w", port, errors.Join(err, err6)) + // 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(tabs) > 0 { - proc = tabs[0].Process + if len(tabs4) > 0 { + proc = tabs4[0].Process } else if len(tabs6) > 0 { proc = tabs6[0].Process }