Bladeren bron

portlist: add Plan 9 support

Updates #5794

Change-Id: I77df1eb9bea9f079a25337cb7bbd498cf8a19135
Signed-off-by: Brad Fitzpatrick <[email protected]>
Brad Fitzpatrick 11 maanden geleden
bovenliggende
commit
5e305032a9
1 gewijzigde bestanden met toevoegingen van 122 en 0 verwijderingen
  1. 122 0
      portlist/portlist_plan9.go

+ 122 - 0
portlist/portlist_plan9.go

@@ -0,0 +1,122 @@
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+package portlist
+
+import (
+	"bufio"
+	"bytes"
+	"os"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func init() {
+	newOSImpl = newPlan9Impl
+
+	pollInterval = 5 * time.Second
+}
+
+type plan9Impl struct {
+	known map[protoPort]*portMeta // inode string => metadata
+
+	br               *bufio.Reader // reused
+	portsBuf         []Port
+	includeLocalhost bool
+}
+
+type protoPort struct {
+	proto string
+	port  uint16
+}
+
+type portMeta struct {
+	port Port
+	keep bool
+}
+
+func newPlan9Impl(includeLocalhost bool) osImpl {
+	return &plan9Impl{
+		known:            map[protoPort]*portMeta{},
+		br:               bufio.NewReader(bytes.NewReader(nil)),
+		includeLocalhost: includeLocalhost,
+	}
+}
+
+func (*plan9Impl) Close() error { return nil }
+
+func (im *plan9Impl) AppendListeningPorts(base []Port) ([]Port, error) {
+	ret := base
+
+	des, err := os.ReadDir("/proc")
+	if err != nil {
+		return nil, err
+	}
+	for _, de := range des {
+		if !de.IsDir() {
+			continue
+		}
+		pidStr := de.Name()
+		pid, err := strconv.Atoi(pidStr)
+		if err != nil {
+			continue
+		}
+		st, _ := os.ReadFile("/proc/" + pidStr + "/fd")
+		if !bytes.Contains(st, []byte("/net/tcp/clone")) {
+			continue
+		}
+		args, _ := os.ReadFile("/proc/" + pidStr + "/args")
+		procName := string(bytes.TrimSpace(args))
+		// term% cat /proc/417/fd
+		// /usr/glenda
+		//   0 r  M   35 (0000000000000001 0 00) 16384      260 /dev/cons
+		//   1 w  c    0 (000000000000000a 0 00)     0      471 /dev/null
+		//   2 w  M   35 (0000000000000001 0 00) 16384      108 /dev/cons
+		//   3 rw I    0 (000000000000002c 0 00)     0       14 /net/tcp/clone
+		for line := range bytes.Lines(st) {
+			if !bytes.Contains(line, []byte("/net/tcp/clone")) {
+				continue
+			}
+			f := strings.Fields(string(line))
+			if len(f) < 10 {
+				continue
+			}
+			if f[9] != "/net/tcp/clone" {
+				continue
+			}
+			qid, err := strconv.ParseUint(strings.TrimPrefix(f[4], "("), 16, 64)
+			if err != nil {
+				continue
+			}
+			tcpN := (qid >> 5) & (1<<12 - 1)
+			tcpNStr := strconv.FormatUint(tcpN, 10)
+			st, _ := os.ReadFile("/net/tcp/" + tcpNStr + "/status")
+			if !bytes.Contains(st, []byte("Listen ")) {
+				// Unexpected. Or a race.
+				continue
+			}
+			bl, _ := os.ReadFile("/net/tcp/" + tcpNStr + "/local")
+			i := bytes.LastIndexByte(bl, '!')
+			if i == -1 {
+				continue
+			}
+			if bytes.HasPrefix(bl, []byte("127.0.0.1!")) && !im.includeLocalhost {
+				continue
+			}
+			portStr := strings.TrimSpace(string(bl[i+1:]))
+			port, _ := strconv.Atoi(portStr)
+			if port == 0 {
+				continue
+			}
+			ret = append(ret, Port{
+				Proto:   "tcp",
+				Port:    uint16(port),
+				Process: procName,
+				Pid:     pid,
+			})
+		}
+	}
+
+	return sortAndDedup(ret), nil
+}