Created
November 9, 2018 02:47
-
-
Save averagesecurityguy/d9309e729dd54b2c3c69b304a0f24967 to your computer and use it in GitHub Desktop.
Concurrently parse a Nessus file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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