diff --git a/nmap.go b/nmap.go index 5d10427..f5a04a3 100644 --- a/nmap.go +++ b/nmap.go @@ -2,6 +2,7 @@ package nmap import ( + "bufio" "bytes" "context" "encoding/xml" @@ -15,9 +16,12 @@ import ( "golang.org/x/sync/errgroup" ) +var _ ScanRunner = (*Scanner)(nil) + // ScanRunner represents something that can run a scan. type ScanRunner interface { - Run() (result *Run, warnings []string, err error) + Run() (result *Run, warnings *[]string, err error) + Version() (any, error) } // Scanner represents n Nmap scanner. @@ -94,6 +98,55 @@ func (s *Scanner) Streamer(stream io.Writer) *Scanner { return s } +// Version returns the version of the installed nmap binary +func (s *Scanner) Version() (result any, err error) { + s.args = append(s.args, "-V") + args := s.args + cmd := exec.CommandContext(s.ctx, s.binaryPath, args...) + + stdout, err := cmd.StdoutPipe() + if err != nil { + return nil, err + } + stderr, err := cmd.StderrPipe() + if err != nil { + return nil, err + } + + err = cmd.Start() + if err != nil { + return nil, err + } + + scanner := bufio.NewScanner(stdout) + for scanner.Scan() { + m := scanner.Text() + splitted := strings.Split(m, " ") + if len(splitted) >= 2 { + result = splitted[2] + break + } + } + + errScanner := bufio.NewScanner(stderr) + var errorOutput = []string{} + for errScanner.Scan() { + m := errScanner.Text() + errorOutput = append(errorOutput, m) + } + + err = cmd.Wait() + if err != nil { + return + } + + if len(errorOutput) > 0 { + return nil, fmt.Errorf("%v", errorOutput) + } + + return result, nil +} + // Run will run the Scanner with the enabled options. // You need to create a Run struct and warnings array first so the function can parse it. func (s *Scanner) Run() (result *Run, warnings *[]string, err error) { diff --git a/xml_test.go b/xml_test.go index d84759b..92eba1f 100644 --- a/xml_test.go +++ b/xml_test.go @@ -224,20 +224,20 @@ func TestFormatTableXML(t *testing.T) { expectedXML := [][]byte{ []byte(fmt.Sprintf(``, table.Key)), - []byte(fmt.Sprintf(`
`)), + []byte(`
`), []byte(fmt.Sprintf(`%s`, table.Tables[0].Elements[0].Key, table.Tables[0].Elements[0].Value)), []byte(fmt.Sprintf(`%s`, table.Tables[0].Elements[1].Value)), - []byte(fmt.Sprintf(`
`)), + []byte(``), []byte(fmt.Sprintf(``, table.Tables[1].Key)), []byte(fmt.Sprintf(`%s`, table.Tables[1].Elements[0].Value)), []byte(fmt.Sprintf(`%s`, table.Tables[1].Elements[1].Value)), - []byte(fmt.Sprintf(`
`)), + []byte(``), []byte(fmt.Sprintf(`%s`, table.Elements[0].Key, table.Elements[0].Value)), []byte(fmt.Sprintf(`%s`, table.Elements[1].Key, table.Elements[1].Value)), []byte(fmt.Sprintf(`%s`, table.Elements[2].Key, table.Elements[2].Value)), []byte(fmt.Sprintf(`%s`, table.Elements[3].Key, table.Elements[3].Value)), []byte(fmt.Sprintf(`%s`, table.Elements[4].Value)), - []byte(fmt.Sprintf(``)), + []byte(``), } XML, err := xml.Marshal(table)