Skip to content

Commit

Permalink
Merge pull request #17 from bisohns/feature/tcp-inspector
Browse files Browse the repository at this point in the history
Darwin: Adding tcp inspector for Darwin
  • Loading branch information
deven96 authored Mar 25, 2022
2 parents e265656 + c0e4eaa commit 0956734
Show file tree
Hide file tree
Showing 4 changed files with 253 additions and 0 deletions.
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)
}
}

0 comments on commit 0956734

Please sign in to comment.