summaryrefslogtreecommitdiffhomepage
path: root/portlist/portlist_linux_test.go
blob: 4b541f8e7dd70e661f7c5fbe2ba2ac547c4b831d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Copyright (c) Tailscale Inc & contributors
// SPDX-License-Identifier: BSD-3-Clause

package portlist

import (
	"bufio"
	"bytes"
	"io"
	"testing"

	"github.com/google/go-cmp/cmp"
)

func TestFieldIndex(t *testing.T) {
	tests := []struct {
		in    string
		field int
		want  int
	}{
		{"foo", 0, 0},
		{"  foo", 0, 2},
		{"foo  bar", 1, 5},
		{" foo  bar", 1, 6},
		{" foo  bar", 2, -1},
		{" foo  bar ", 2, -1},
		{" foo  bar x", 2, 10},
		{"  1: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 34062 1 0000000000000000 100 0 0 10 0",
			2, 19},
	}
	for _, tt := range tests {
		if got := fieldIndex([]byte(tt.in), tt.field); got != tt.want {
			t.Errorf("fieldIndex(%q, %v) = %v; want %v", tt.in, tt.field, got, tt.want)
		}
	}
}

func TestParsePorts(t *testing.T) {
	tests := []struct {
		name string
		in   string
		file string
		want map[string]*portMeta
	}{
		{
			name: "empty",
			in:   "header line (ignored)\n",
			want: map[string]*portMeta{},
		},
		{
			name: "ipv4",
			file: "tcp",
			in: `header line
  0: 0100007F:0277 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 22303 1 0000000000000000 100 0 0 10 0
  1: 00000000:0016 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 34062 1 0000000000000000 100 0 0 10 0
  2: 5501A8C0:ADD4 B25E9536:01BB 01 00000000:00000000 02:00000B2B 00000000  1000        0 155276677 2 0000000000000000 22 4 30 10 -1
`,
			want: map[string]*portMeta{
				"socket:[34062]": {
					port: Port{Proto: "tcp", Port: 22},
				},
			},
		},
		{
			name: "ipv6",
			file: "tcp6",
			in: `  sl  local_address                         remote_address                        st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode
   0: 00000000000000000000000001000000:0277 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 35720 1 0000000000000000 100 0 0 10 0
   1: 00000000000000000000000000000000:1F91 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000  1000        0 142240557 1 0000000000000000 100 0 0 10 0
   2: 00000000000000000000000000000000:0016 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 34064 1 0000000000000000 100 0 0 10 0
   3: 69050120005716BC64906EBE009ECD4D:D506 0047062600000000000000006E171268:01BB 01 00000000:00000000 02:0000009E 00000000  1000        0 151042856 2 0000000000000000 21 4 28 10 -1
`,
			want: map[string]*portMeta{
				"socket:[142240557]": {
					port: Port{Proto: "tcp", Port: 8081},
				},
				"socket:[34064]": {
					port: Port{Proto: "tcp", Port: 22},
				},
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			buf := bytes.NewBufferString(tt.in)
			r := bufio.NewReader(buf)
			file := "tcp"
			if tt.file != "" {
				file = tt.file
			}
			li := newLinuxImplBase(false)
			err := li.parseProcNetFile(r, file)
			if err != nil {
				t.Fatal(err)
			}
			for _, pm := range tt.want {
				pm.keep = true
				pm.needsProcName = true
			}
			if diff := cmp.Diff(li.known, tt.want, cmp.AllowUnexported(Port{}), cmp.AllowUnexported(portMeta{})); diff != "" {
				t.Errorf("unexpected parsed ports (-got+want):\n%s", diff)
			}
		})
	}
}

func BenchmarkParsePorts(b *testing.B) {
	b.ReportAllocs()

	var contents bytes.Buffer
	contents.WriteString(`  sl  local_address                         remote_address                        st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode
   0: 00000000000000000000000001000000:0277 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 35720 1 0000000000000000 100 0 0 10 0
   1: 00000000000000000000000000000000:1F91 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000  1000        0 142240557 1 0000000000000000 100 0 0 10 0
   2: 00000000000000000000000000000000:0016 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 34064 1 0000000000000000 100 0 0 10 0
`)
	for range 50000 {
		contents.WriteString("   3: 69050120005716BC64906EBE009ECD4D:D506 0047062600000000000000006E171268:01BB 01 00000000:00000000 02:0000009E 00000000  1000        0 151042856 2 0000000000000000 21 4 28 10 -1\n")
	}

	li := newLinuxImplBase(false)

	r := bytes.NewReader(contents.Bytes())
	br := bufio.NewReader(&contents)
	b.ResetTimer()
	for range b.N {
		r.Seek(0, io.SeekStart)
		br.Reset(r)
		err := li.parseProcNetFile(br, "tcp6")
		if err != nil {
			b.Fatal(err)
		}
		if len(li.known) != 2 {
			b.Fatalf("wrong results; want 2 parsed got %d", len(li.known))
		}
	}
}

func BenchmarkFindProcessNames(b *testing.B) {
	b.ReportAllocs()
	li := &linuxImpl{}
	need := map[string]*portMeta{
		"something-we'll-never-find": new(portMeta),
	}
	for range b.N {
		if err := li.findProcessNames(need); err != nil {
			b.Fatal(err)
		}
	}
}