11package scanner
22
33import (
4+ "runtime"
45 "sort"
56 "testing"
67
@@ -9,26 +10,31 @@ import (
910
1011func TestParseNetstatOutput (t * testing.T ) {
1112 testLogger := testutil .NewTestLogger ()
13+ runningStyle := netstatStyleForOS (runtime .GOOS )
1214
1315 tests := []struct {
1416 name string
17+ style string
1518 input string
1619 expectedPorts []int
1720 }{
1821 {
1922 name : "empty output returns empty ports" ,
23+ style : "any" ,
2024 input : "" ,
2125 expectedPorts : []int {},
2226 },
2327 {
24- name : "single tcp LISTEN line extracts correct port" ,
28+ name : "single tcp LISTEN line extracts correct port" ,
29+ style : "bsd" ,
2530 input : `Active Internet connections (including servers)
2631Proto Recv-Q Send-Q Local Address Foreign Address (state)
2732tcp4 0 0 127.0.0.1.8080 *.* LISTEN` ,
2833 expectedPorts : []int {8080 },
2934 },
3035 {
31- name : "multiple LISTEN lines with duplicate are deduplicated" ,
36+ name : "multiple LISTEN lines with duplicate are deduplicated" ,
37+ style : "bsd" ,
3238 input : `Active Internet connections (including servers)
3339Proto Recv-Q Send-Q Local Address Foreign Address (state)
3440tcp4 0 0 127.0.0.1.8080 *.* LISTEN
@@ -37,7 +43,8 @@ tcp4 0 0 127.0.0.1.3000 *.* LISTEN`,
3743 expectedPorts : []int {3000 , 8080 },
3844 },
3945 {
40- name : "ignore non-LISTEN lines like ESTABLISHED and TIME_WAIT" ,
46+ name : "ignore non-LISTEN lines like ESTABLISHED and TIME_WAIT" ,
47+ style : "bsd" ,
4148 input : `Active Internet connections (including servers)
4249Proto Recv-Q Send-Q Local Address Foreign Address (state)
4350tcp4 0 0 127.0.0.1.8080 *.* LISTEN
@@ -46,21 +53,44 @@ tcp4 0 0 192.168.1.5.52342 93.184.216.34.80 TIME_WAIT`,
4653 expectedPorts : []int {8080 },
4754 },
4855 {
49- name : "tcp46 format is parsed correctly" ,
56+ name : "tcp46 format is parsed correctly" ,
57+ style : "bsd" ,
5058 input : `Active Internet connections (including servers)
5159Proto Recv-Q Send-Q Local Address Foreign Address (state)
5260tcp46 0 0 *.9090 *.* LISTEN` ,
5361 expectedPorts : []int {9090 },
5462 },
5563 {
56- name : "udp LISTEN line is parsed correctly" ,
64+ name : "udp LISTEN line is parsed correctly" ,
65+ style : "bsd" ,
5766 input : `Active Internet connections (including servers)
5867Proto Recv-Q Send-Q Local Address Foreign Address (state)
5968udp4 0 0 127.0.0.1.5353 *.* LISTEN` ,
6069 expectedPorts : []int {5353 },
6170 },
6271 {
63- name : "no LISTEN lines at all returns empty ports" ,
72+ name : "linux netstat format parses ipv4 and ipv6 LISTEN lines" ,
73+ style : "linux" ,
74+ input : `tcp 0 0 0.0.0.0:11211 0.0.0.0:* LISTEN
75+ tcp6 0 0 :::11211 :::* LISTEN` ,
76+ expectedPorts : []int {11211 },
77+ },
78+ {
79+ name : "linux ipv6 single LISTEN line is parsed correctly" ,
80+ style : "linux" ,
81+ input : `tcp6 0 0 :::443 :::* LISTEN` ,
82+ expectedPorts : []int {443 },
83+ },
84+ {
85+ name : "linux format ignores non-LISTEN and keeps LISTEN port only" ,
86+ style : "linux" ,
87+ input : `tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN
88+ tcp 0 0 10.0.2.15:52341 93.184.216.34:443 ESTABLISHED` ,
89+ expectedPorts : []int {8080 },
90+ },
91+ {
92+ name : "no LISTEN lines at all returns empty ports" ,
93+ style : "any" ,
6494 input : `Active Internet connections (including servers)
6595Proto Recv-Q Send-Q Local Address Foreign Address (state)
6696tcp4 0 0 192.168.1.5.52341 93.184.216.34.443 ESTABLISHED
@@ -69,7 +99,8 @@ tcp4 0 0 192.168.1.5.52343 93.184.216.34.80 CLOSE_WAIT`,
6999 expectedPorts : []int {},
70100 },
71101 {
72- name : "mixed LISTEN and non-LISTEN returns only LISTEN ports" ,
102+ name : "mixed LISTEN and non-LISTEN returns only LISTEN ports" ,
103+ style : "bsd" ,
73104 input : `Active Internet connections (including servers)
74105Proto Recv-Q Send-Q Local Address Foreign Address (state)
75106tcp4 0 0 127.0.0.1.5432 *.* LISTEN
@@ -84,6 +115,10 @@ tcp4 0 0 192.168.1.5.52343 93.184.216.34.80 CLOSE_WAIT`,
84115
85116 for _ , tt := range tests {
86117 t .Run (tt .name , func (t * testing.T ) {
118+ if tt .style != "any" && tt .style != runningStyle {
119+ t .Skipf ("skipping %s-only case on %s" , tt .style , runningStyle )
120+ }
121+
87122 detector := NewNetstatPortDetector (testLogger )
88123 ports , err := detector .parseNetstatOutput (tt .input )
89124 if err != nil {
@@ -110,3 +145,16 @@ tcp4 0 0 192.168.1.5.52343 93.184.216.34.80 CLOSE_WAIT`,
110145 })
111146 }
112147}
148+
149+ func netstatStyleForOS (goos string ) string {
150+ switch goos {
151+ case "linux" :
152+ return "linux"
153+ case "windows" :
154+ return "linux"
155+ case "darwin" , "freebsd" , "openbsd" , "netbsd" :
156+ return "bsd"
157+ default :
158+ return "bsd"
159+ }
160+ }
0 commit comments