From ad6edf5ecda94ac89df8278871a29c3783ae85e4 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 3 Mar 2021 19:00:41 -0800 Subject: [PATCH] portlist: report a better process name for .Net on linux. Fixes #1440. Signed-off-by: David Anderson --- portlist/clean.go | 34 ++++++++++++++++++++++++++++++ portlist/clean_test.go | 42 ++++++++++++++++++++++++++++++++++++++ portlist/netstat.go | 8 ++------ portlist/portlist_linux.go | 9 ++++---- 4 files changed, 82 insertions(+), 11 deletions(-) create mode 100644 portlist/clean.go create mode 100644 portlist/clean_test.go diff --git a/portlist/clean.go b/portlist/clean.go new file mode 100644 index 000000000..aad350fe3 --- /dev/null +++ b/portlist/clean.go @@ -0,0 +1,34 @@ +// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package portlist + +import ( + "path/filepath" + "strings" +) + +// argvSubject takes a command and its flags, and returns the +// short/pretty name for the process. This is usually the basename of +// the binary being executed, but can sometimes vary (e.g. so that we +// don't report all Java programs as "java"). +func argvSubject(argv ...string) string { + if len(argv) == 0 { + return "" + } + ret := filepath.Base(argv[0]) + + // Handle special cases. + switch { + case ret == "mono" && len(argv) >= 2: + // .Net programs execute as `mono actualProgram.exe`. + ret = filepath.Base(argv[1]) + } + + // Remove common noise. + ret = strings.TrimSpace(ret) + ret = strings.TrimSuffix(ret, ".exe") + + return ret +} diff --git a/portlist/clean_test.go b/portlist/clean_test.go new file mode 100644 index 000000000..767071481 --- /dev/null +++ b/portlist/clean_test.go @@ -0,0 +1,42 @@ +// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package portlist + +import "testing" + +func TestArgvSubject(t *testing.T) { + tests := []struct { + in []string + want string + }{ + { + in: nil, + want: "", + }, + { + in: []string{"/usr/bin/sshd"}, + want: "sshd", + }, + { + in: []string{"/bin/mono"}, + want: "mono", + }, + { + in: []string{"/nix/store/x2cw2xjw98zdysf56bdlfzsr7cyxv0jf-mono-5.20.1.27/bin/mono", "/bin/exampleProgram.exe"}, + want: "exampleProgram", + }, + { + in: []string{"/bin/mono", "/sbin/exampleProgram.bin"}, + want: "exampleProgram.bin", + }, + } + + for _, test := range tests { + got := argvSubject(test.in...) + if got != test.want { + t.Errorf("argvSubject(%v) = %q, want %q", test.in, got, test.want) + } + } +} diff --git a/portlist/netstat.go b/portlist/netstat.go index 02b1a5957..7eb8ed973 100644 --- a/portlist/netstat.go +++ b/portlist/netstat.go @@ -101,13 +101,9 @@ func parsePortsNetstat(output string) List { delete(m, lastport) proc := trimline[1 : len(trimline)-1] if proc == "svchost.exe" && lastline != "" { - p.Process = lastline + p.Process = argvSubject(lastline) } else { - if strings.HasSuffix(proc, ".exe") { - p.Process = proc[:len(proc)-4] - } else { - p.Process = proc - } + p.Process = argvSubject(proc) } m[p] = nothing{} } else { diff --git a/portlist/portlist_linux.go b/portlist/portlist_linux.go index 8b7555872..cc22b3f1a 100644 --- a/portlist/portlist_linux.go +++ b/portlist/portlist_linux.go @@ -158,18 +158,17 @@ func addProcesses(pl []Port) ([]Port, error) { continue } - // TODO(apenwarr): use /proc/*/cmdline instead of /comm? - // Unsure right now whether users will want the extra detail - // or not. pe := pm[string(targetBuf[:n])] // m[string([]byte)] avoids alloc if pe != nil { - comm, err := ioutil.ReadFile(fmt.Sprintf("/proc/%s/comm", pid)) + bs, err := ioutil.ReadFile(fmt.Sprintf("/proc/%s/cmdline", pid)) if err != nil { // Usually shouldn't happen. One possibility is // the process has gone away, so let's skip it. continue } - pe.Process = strings.TrimSpace(string(comm)) + + argv := strings.Split(strings.TrimSuffix(string(bs), "\x00"), "\x00") + pe.Process = argvSubject(argv...) } } }