Skip to content

Instantly share code, notes, and snippets.

@averagesecurityguy
Created November 9, 2018 02:47
Show Gist options
  • Save averagesecurityguy/d9309e729dd54b2c3c69b304a0f24967 to your computer and use it in GitHub Desktop.
Save averagesecurityguy/d9309e729dd54b2c3c69b304a0f24967 to your computer and use it in GitHub Desktop.
Concurrently parse a Nessus file.
/*
Copyright (c) 2018, AverageSecurityGuy
# All rights reserved.
Created: 2018-11-08
Modified: 2018-11-08
Author: Stephen Haywood
Sources: http://blog.davidsingleton.org/parsing-huge-xml-files-with-go/
*/
package main
import (
"encoding/xml"
"fmt"
"os"
)
type Tag struct {
Name string `xml:"name,attr"`
Value string `xml:",chardata"`
}
type Host struct {
IpAddr string
Fqdn string
Os string
Properties []Tag `xml:"HostProperties>tag"`
Items []Item `xml:"ReportItem"`
}
type Item struct {
Port string `xml:"port,attr"`
Protocol string `xml: "protocol,attr"`
PluginId string `xml:"pluginID,attr"`
PluginName string `xml:"pluginName,attr"`
Description string `xml:description`
Output string `xml:plugin_output`
}
func check(e error) {
if e != nil {
fmt.Printf("Error: %s\n", e.Error())
os.Exit(0)
}
}
// parseFile extracts the ReportHosts from a Nessus file.
// The Nessus file is parsed in a stream and each ReportHost is added to a
// channel for later processing.
func parseFile(fn string, hc chan<- *Host) {
reader, err := os.Open(fn)
check(err)
decoder := xml.NewDecoder(reader)
for {
tkn, err := decoder.Token()
if tkn == nil {
break
}
if err != nil {
fmt.Printf("Parse Error: %s", err)
continue
}
switch ele := tkn.(type) {
case xml.StartElement:
if ele.Name.Local == "ReportHost" {
var hst Host
decoder.DecodeElement(&hst, &ele)
hc <- &hst
}
default:
continue
}
}
close(hc)
}
func processHost(hst *Host) {
for _, prop := range hst.Properties {
if prop.Name == "host-ip" {
hst.IpAddr = prop.Value
}
if prop.Name == "operating-system" {
hst.Os = prop.Value
}
if prop.Name == "host-fqdn" {
hst.Fqdn = prop.Value
}
}
fmt.Println(hst.IpAddr, hst.Fqdn, hst.Os)
}
func main() {
if len(os.Args) != 2 {
fmt.Println("Usage: go run parse_nessus.go nessus_file")
os.Exit(1)
}
// Build our processing Channel
hostChan := make(chan *Host, 100)
processSem := make(chan struct{}, 10)
go parseFile(os.Args[1], hostChan)
for host := range hostChan {
processSem <- struct{}{}
processHost(host)
<-processSem
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment