Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Darwin: Adding tcp inspector for Darwin #17

Merged
merged 3 commits into from
Mar 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions inspector/inspector.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ var inspectorMap = map[string]NewInspector{
`process`: NewProcess,
`custom`: NewCustom,
`loadavg`: NewLoadAvg,
`tcp`: NewTcp,
}

// Init : initializes the specified inspector using name and driver
Expand Down
219 changes: 219 additions & 0 deletions inspector/tcp.go
Original file line number Diff line number Diff line change
@@ -1,2 +1,221 @@
// Check if TCP ports are open or not
package inspector

import (
"errors"
"fmt"
"strconv"
"strings"

"github.com/bisohns/saido/driver"
log "github.com/sirupsen/logrus"
)

// TcpMetrics : Metrics obtained by tcp monitoring on darwin
type TcpMetrics struct {
// Ports map a port to a status string
// e.g {8081: "LISTEN"}
Ports map[int]string
}

type TcpDarwin struct {
Command string
Driver *driver.Driver
Values TcpMetrics
}

type TcpLinux struct {
Command string
Driver *driver.Driver
Values TcpMetrics
}

type TcpWin struct {
Command string
Driver *driver.Driver
Values TcpMetrics
}

/* Parse : parsing the following kind of output
Active Internet connections (including servers)
Proto Recv-Q Send-Q Local Address Foreign Address (state)
tcp4 0 0 127.0.0.1.53300 127.0.0.1.59972 ESTABLISHED
tcp4 0 0 192.168.1.172.59964 162.247.243.147.443 SYN_SENT
tcp4 0 0 192.168.1.172.59931 13.224.227.146.443 ESTABLISHED
tcp4 0 0 127.0.0.1.59905 127.0.0.1.53300 CLOSE_WAIT
*/
func (i *TcpDarwin) Parse(output string) {
ports := make(map[int]string)
lines := strings.Split(output, "\n")
for index, line := range lines {
// skip title lines
if index == 0 || index == 1 {
continue
}
columns := strings.Fields(line)
if len(columns) > 5 {
status := columns[5]
address := strings.Split(columns[3], ".")
portString := address[len(address)-1]
port, err := strconv.Atoi(portString)
if err != nil {
log.Fatal("Could not parse port number in TcpDarwin")
}
ports[port] = status

}
}
i.Values.Ports = ports
}

func (i *TcpDarwin) SetDriver(driver *driver.Driver) {
details := (*driver).GetDetails()
if !details.IsDarwin {
panic("Cannot use TcpDarwin on drivers outside (darwin)")
}
i.Driver = driver
}

func (i TcpDarwin) driverExec() driver.Command {
return (*i.Driver).RunCommand
}

func (i *TcpDarwin) Execute() {
output, err := i.driverExec()(i.Command)
if err == nil {
i.Parse(output)
}
}

/*
Parse for output
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 5 127.0.0.1:45481 0.0.0.0:*
LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:*
LISTEN 0 5 127.0.0.1:631 0.0.0.0:*
ESTAB 0 0 192.168.1.106:37986 198.252.206.25:443
CLOSE-WAIT 1 0 127.0.0.1:54638 127.0.0.1:45481

*/
func (i *TcpLinux) Parse(output string) {
ports := make(map[int]string)
lines := strings.Split(output, "\n")
for index, line := range lines {
// skip title lines
if index == 0 {
continue
}
columns := strings.Fields(line)
if len(columns) >= 5 {
fmt.Print(columns)
status := columns[0]
address := strings.Split(columns[3], ":")
portString := address[len(address)-1]
port, err := strconv.Atoi(portString)
if err != nil {
log.Fatal("Could not parse port number in TcpLinux")
}
ports[port] = status

}
}
i.Values.Ports = ports
}

func (i *TcpLinux) SetDriver(driver *driver.Driver) {
details := (*driver).GetDetails()
if !details.IsLinux {
panic("Cannot use TcpLinux on drivers outside (linux)")
}
i.Driver = driver
}

func (i TcpLinux) driverExec() driver.Command {
return (*i.Driver).RunCommand
}

func (i *TcpLinux) Execute() {
output, err := i.driverExec()(i.Command)
if err == nil {
i.Parse(output)
}
}

/* Parse for output

Active Connections

Proto Local Address Foreign Address State
TCP 0.0.0.0:135 0.0.0.0:0 LISTENING
TCP 0.0.0.0:445 0.0.0.0:0 LISTENING
TCP 0.0.0.0:5040 0.0.0.0:0 LISTENING
TCP 0.0.0.0:5700 0.0.0.0:0 LISTENING
TCP 0.0.0.0:6646 0.0.0.0:0 LISTENING
TCP 0.0.0.0:49664 0.0.0.0:0 LISTENING
*/
func (i *TcpWin) Parse(output string) {
ports := make(map[int]string)
lines := strings.Split(output, "\n")
for index, line := range lines {
// skip title lines
if index == 0 || index == 1 || index == 3 {
continue
}
columns := strings.Fields(line)
if len(columns) > 3 {
status := columns[3]
address := strings.Split(columns[1], ":")
portString := address[len(address)-1]
port, err := strconv.Atoi(portString)
if err != nil {
log.Fatal("Could not parse port number in TcpWin")
}
ports[port] = status

}
}
i.Values.Ports = ports
}

func (i *TcpWin) SetDriver(driver *driver.Driver) {
details := (*driver).GetDetails()
if !details.IsWindows {
panic("Cannot use TcpWin on drivers outside (windows)")
}
i.Driver = driver
}

func (i TcpWin) driverExec() driver.Command {
return (*i.Driver).RunCommand
}

func (i *TcpWin) Execute() {
output, err := i.driverExec()(i.Command)
if err == nil {
i.Parse(output)
}
}

// NewTcp: Initialize a new Tcp instance
func NewTcp(driver *driver.Driver, _ ...string) (Inspector, error) {
var tcp Inspector
details := (*driver).GetDetails()
if !(details.IsLinux || details.IsDarwin || details.IsWindows) {
return nil, errors.New("Cannot use Tcp on drivers outside (linux, darwin, windows)")
}
if details.IsDarwin {
tcp = &TcpDarwin{
Command: `netstat -anp tcp`,
}
} else if details.IsLinux {
tcp = &TcpLinux{
Command: `ss -tan`,
}
} else if details.IsWindows {
tcp = &TcpWin{
Command: `netstat -anp tcp`,
}
}
tcp.SetDriver(driver)
return tcp, nil
}
20 changes: 20 additions & 0 deletions integration/integration_unix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,23 @@ func TestUptimeonLocal(t *testing.T) {
fmt.Printf("%#v", iConcreteDarwin.Values)
}
}

func TestTcponLocal(t *testing.T) {
d := NewLocalForTest()
i, _ := inspector.Init(`tcp`, &d)
i.Execute()
iConcreteDarwin, ok := i.(*inspector.TcpDarwin)
if ok {
if len(iConcreteDarwin.Values.Ports) == 0 {
t.Errorf("%#v", iConcreteDarwin.Values.Ports)
}
fmt.Printf("%#v", iConcreteDarwin.Values.Ports)
}
iConcreteLinux, ok := i.(*inspector.TcpLinux)
if ok {
if len(iConcreteLinux.Values.Ports) == 0 {
t.Errorf("%#v", iConcreteLinux.Values.Ports)
}
fmt.Printf("%#v", iConcreteLinux.Values.Ports)
}
}
13 changes: 13 additions & 0 deletions integration/integration_windows_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,16 @@ func TestDFonLocal(t *testing.T) {
}
}
}

func TestTcponLocal(t *testing.T) {
d := NewLocalForTest()
i, _ := inspector.Init(`tcp`, &d)
i.Execute()
iConcreteWindows, ok := i.(*inspector.TcpWin)
if ok {
if len(iConcreteWindows.Values.Ports) == 0 {
t.Errorf("%#v", iConcreteWindows.Values.Ports)
}
fmt.Printf("%#v", iConcreteWindows.Values.Ports)
}
}