Files
cameradar/vendor/github.com/Ullaakut/nmap/xml.go
T
Brendan LE GLAUNEC 5849898283 Cameradar 3.0.0: Uses ullaakut/nmap, runs faster, removed legacy code (#188)
Unit tests functional and coverage back to 100%

Add more routes to dictionary, add more credentials, add default port 5554, rename cameradar logs ENV variable, improve unit test readability, remove tmp file
2019-01-22 21:16:16 +01:00

509 lines
16 KiB
Go

package nmap
import (
"encoding/xml"
"io/ioutil"
"strconv"
"time"
family "github.com/Ullaakut/nmap/pkg/osfamilies"
)
// Run represents an nmap scanning run.
type Run struct {
XMLName xml.Name `xml:"nmaprun"`
Args string `xml:"args,attr" json:"args"`
ProfileName string `xml:"profile_name,attr" json:"profile_name"`
Scanner string `xml:"scanner,attr" json:"scanner"`
StartStr string `xml:"startstr,attr" json:"start_str"`
Version string `xml:"version,attr" json:"version"`
XMLOutputVersion string `xml:"xmloutputversion,attr" json:"xml_output_version"`
Debugging Debugging `xml:"debugging" json:"debugging"`
Stats Stats `xml:"runstats" json:"run_stats"`
ScanInfo ScanInfo `xml:"scaninfo" json:"scan_info"`
Start Timestamp `xml:"start,attr" json:"start"`
Verbose Verbose `xml:"verbose" json:"verbose"`
Hosts []Host `xml:"host" json:"hosts"`
PostScripts []Script `xml:"postscript>script" json:"post_scripts"`
PreScripts []Script `xml:"prescript>script" json:"pre_scripts"`
Targets []Target `xml:"target" json:"targets"`
TaskBegin []Task `xml:"taskbegin" json:"task_begin"`
TaskProgress []TaskProgress `xml:"taskprogress" json:"task_progress"`
TaskEnd []Task `xml:"taskend" json:"task_end"`
rawXML []byte
}
// ToFile writes a Run as XML into the specified file path.
func (r Run) ToFile(filePath string) error {
return ioutil.WriteFile(filePath, r.rawXML, 0666)
}
// ScanInfo represents the scan information.
type ScanInfo struct {
NumServices int `xml:"numservices,attr" json:"num_services"`
Protocol string `xml:"protocol,attr" json:"protocol"`
ScanFlags string `xml:"scanflags,attr" json:"scan_flags"`
Services string `xml:"services,attr" json:"services"`
Type string `xml:"type,attr" json:"type"`
}
// Verbose contains the verbosity level of the scan.
type Verbose struct {
Level int `xml:"level,attr" json:"level"`
}
// Debugging contains the debugging level of the scan.
type Debugging struct {
Level int `xml:"level,attr" json:"level"`
}
// Task contains information about a task.
type Task struct {
Time Timestamp `xml:"time,attr" json:"time"`
Task string `xml:"task,attr" json:"task"`
ExtraInfo string `xml:"extrainfo,attr" json:"extra_info"`
}
// TaskProgress contains information about the progression of a task.
type TaskProgress struct {
Percent float32 `xml:"percent,attr" json:"percent"`
Remaining int `xml:"remaining,attr" json:"remaining"`
Task string `xml:"task,attr" json:"task"`
Etc Timestamp `xml:"etc,attr" json:"etc"`
Time Timestamp `xml:"time,attr" json:"time"`
}
// Target represents a target, how it was specified when passed to nmap,
// its status and the reason for its status. Example:
// <target specification="domain.does.not.exist" status="skipped" reason="invalid"/>
type Target struct {
Specification string `xml:"specification,attr" json:"specification"`
Status string `xml:"status,attr" json:"status"`
Reason string `xml:"reason,attr" json:"reason"`
}
// Host represents a host that was scanned.
type Host struct {
Distance Distance `xml:"distance" json:"distance"`
EndTime Timestamp `xml:"endtime,attr,omitempty" json:"end_time"`
IPIDSequence IPIDSequence `xml:"ipidsequence" json:"ip_id_sequence"`
OS OS `xml:"os" json:"os"`
StartTime Timestamp `xml:"starttime,attr,omitempty" json:"start_time"`
Status Status `xml:"status" json:"status"`
TCPSequence TCPSequence `xml:"tcpsequence" json:"tcp_sequence"`
TCPTSSequence TCPTSSequence `xml:"tcptssequence" json:"tcp_ts_sequence"`
Times Times `xml:"times" json:"times"`
Trace Trace `xml:"trace" json:"trace"`
Uptime Uptime `xml:"uptime" json:"uptime"`
Comment string `xml:"comment,attr" json:"comment"`
Addresses []Address `xml:"address" json:"addresses"`
ExtraPorts []ExtraPort `xml:"ports>extraports" json:"extra_ports"`
Hostnames []Hostname `xml:"hostnames>hostname" json:"hostnames"`
HostScripts []Script `xml:"hostscript>script" json:"host_scripts"`
Ports []Port `xml:"ports>port" json:"ports"`
Smurfs []Smurf `xml:"smurf" json:"smurfs"`
}
// Status represents a host's status.
type Status struct {
State string `xml:"state,attr" json:"state"`
Reason string `xml:"reason,attr" json:"reason"`
ReasonTTL float32 `xml:"reason_ttl,attr" json:"reason_ttl"`
}
func (s Status) String() string {
return s.State
}
// Address contains a IPv4 or IPv6 address for a host.
type Address struct {
Addr string `xml:"addr,attr" json:"addr"`
AddrType string `xml:"addrtype,attr" json:"addr_type"`
Vendor string `xml:"vendor,attr" json:"vendor"`
}
func (a Address) String() string {
return a.Addr
}
// Hostname is a name for a host.
type Hostname struct {
Name string `xml:"name,attr" json:"name"`
Type string `xml:"type,attr" json:"type"`
}
func (h Hostname) String() string {
return h.Name
}
// Smurf contains repsonses from a smurf attack.
type Smurf struct {
Responses string `xml:"responses,attr" json:"responses"`
}
// ExtraPort contains the information about the closed and filtered ports.
type ExtraPort struct {
State string `xml:"state,attr" json:"state"`
Count int `xml:"count,attr" json:"count"`
Reasons []Reason `xml:"extrareasons" json:"reasons"`
}
// Reason represents a reason why a port is closed or filtered.
// This won't be in the scan results unless WithReason is used.
type Reason struct {
Reason string `xml:"reason,attr" json:"reason"`
Count int `xml:"count,attr" json:"count"`
}
// Port contains all the information about a scanned port.
type Port struct {
ID uint16 `xml:"portid,attr" json:"id"`
Protocol string `xml:"protocol,attr" json:"protocol"`
Owner Owner `xml:"owner" json:"owner"`
Service Service `xml:"service" json:"service"`
State State `xml:"state" json:"state"`
Scripts []Script `xml:"script" json:"scripts"`
}
// PortStatus represents a port's state.
type PortStatus string
// Enumerates the different possible state values.
const (
Open PortStatus = "open"
Closed PortStatus = "closed"
Filtered PortStatus = "filtered"
Unfiltered PortStatus = "unfiltered"
)
// Status returns the status of a port.
func (p Port) Status() PortStatus {
return PortStatus(p.State.State)
}
// State contains information about a given port's status.
// State will be open, closed, etc.
type State struct {
State string `xml:"state,attr" json:"state"`
Reason string `xml:"reason,attr" json:"reason"`
ReasonIP string `xml:"reason_ip,attr" json:"reason_ip"`
ReasonTTL float32 `xml:"reason_ttl,attr" json:"reason_ttl"`
}
func (s State) String() string {
return s.State
}
// Owner contains the name of a port's owner.
type Owner struct {
Name string `xml:"name,attr" json:"name"`
}
func (o Owner) String() string {
return o.Name
}
// Service contains detailed information about a service on an open port.
type Service struct {
DeviceType string `xml:"devicetype,attr" json:"device_type"`
ExtraInfo string `xml:"extrainfo,attr" json:"extra_info"`
HighVersion string `xml:"highver,attr" json:"high_version"`
Hostname string `xml:"hostname,attr" json:"hostname"`
LowVersion string `xml:"lowver,attr" json:"low_version"`
Method string `xml:"method,attr" json:"method"`
Name string `xml:"name,attr" json:"name"`
OSType string `xml:"ostype,attr" json:"os_type"`
Product string `xml:"product,attr" json:"product"`
Proto string `xml:"proto,attr" json:"proto"`
RPCNum string `xml:"rpcnum,attr" json:"rpc_num"`
ServiceFP string `xml:"servicefp,attr" json:"service_fp"`
Tunnel string `xml:"tunnel,attr" json:"tunnel"`
Version string `xml:"version,attr" json:"version"`
Configuration int `xml:"conf,attr" json:"configuration"`
CPEs []CPE `xml:"cpe" json:"cpes"`
}
func (s Service) String() string {
return s.Name
}
// CPE (Common Platform Enumeration) is a standardized way to name software
// applications, operating systems and hardware platforms.
type CPE string
// Script represents an Nmap Scripting Engine script.
type Script struct {
ID string `xml:"id,attr" json:"id"`
Output string `xml:"output,attr" json:"output"`
Tables Table `xml:"table" json:"tables"`
}
// Table contains the output of the script in an easily parsable form.
type Table map[string]string
// MarshalXML implements the xml.Marshaler interface.
func (t Table) MarshalXML(e *xml.Encoder, startElem xml.StartElement) error {
tokens := []xml.Token{startElem}
// Add all key/value pairs as entries in the XML array.
for key, value := range t {
// Start of the XML element.
start := xml.StartElement{
Name: xml.Name{
Local: "elem",
},
Attr: []xml.Attr{
{
Name: xml.Name{
Local: "key",
},
Value: key,
},
},
}
// End of the XML element.
end := xml.EndElement{
Name: start.Name,
}
// Append the start, content and end of the new element to the list of XML tokens.
tokens = append(tokens, start, xml.CharData(value), end)
}
tokens = append(tokens, xml.EndElement{
Name: startElem.Name,
})
// Encode all tokens.
for _, t := range tokens {
err := e.EncodeToken(t)
if err != nil {
return err
}
}
// Flush the encoder to ensure that the tokens are written.
err := e.Flush()
if err != nil {
return err
}
return nil
}
// UnmarshalXML implements the xml.Unmarshaler interface.
func (t *Table) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
table := make(map[string]string)
var (
currentKey string
currentValue string
)
for {
token, err := d.Token()
if err != nil {
break
}
switch element := token.(type) {
case xml.StartElement:
for _, attribute := range element.Attr {
if attribute.Name.Local == "key" {
currentKey = attribute.Value
break
}
}
case xml.CharData:
currentValue = string(element)
case xml.EndElement:
// Insert the current key/value pair.
table[currentKey] = currentValue
// Reset the temporary variables for the next pair.
currentKey = ""
currentValue = ""
}
}
*t = table
return nil
}
// OS contains the fingerprinted operating system for a host.
type OS struct {
PortsUsed []PortUsed `xml:"portused" json:"ports_used"`
Matches []OSMatch `xml:"osmatch" json:"os_matches"`
Fingerprints []OSFingerprint `xml:"osfingerprint" json:"os_fingerprints"`
Classes []OSClass `xml:"osclass" json:"os_classes"`
}
// PortUsed is the port used to fingerprint an operating system.
type PortUsed struct {
State string `xml:"state,attr" json:"state"`
Proto string `xml:"proto,attr" json:"proto"`
ID int `xml:"portid,attr" json:"port_id"`
}
// OSMatch contains detailed information regarding an operating system fingerprint.
type OSMatch struct {
Name string `xml:"name,attr" json:"name"`
Accuracy int `xml:"accuracy,attr" json:"accuracy"`
Line int `xml:"line,attr" json:"line"`
}
// OSClass contains vendor information about an operating system.
type OSClass struct {
Vendor string `xml:"vendor,attr" json:"vendor"`
OSGeneration string `xml:"osgen,attr" json:"os_generation"`
Type string `xml:"type,attr" json:"type"`
Accuracy int `xml:"accuracy,attr" json:"accuracy"`
Family string `xml:"osfamily,attr" json:"os_family"`
CPEs []CPE `xml:"cpe" json:"cpes"`
}
// OSFamily returns the OS family in an enumerated format.
func (o OSClass) OSFamily() family.OSFamily {
return family.OSFamily(o.Family)
}
// OSFingerprint is the actual fingerprint string of an operating system.
type OSFingerprint struct {
Fingerprint string `xml:"fingerprint,attr" json:"fingerprint"`
}
// Distance is the amount of hops to a particular host.
type Distance struct {
Value int `xml:"value,attr" json:"value"`
}
// Uptime is the amount of time the host has been up.
type Uptime struct {
Seconds int `xml:"seconds,attr" json:"seconds"`
Lastboot string `xml:"lastboot,attr" json:"last_boot"`
}
// Sequence represents a detected sequence.
type Sequence struct {
Class string `xml:"class,attr" json:"class"`
Values string `xml:"values,attr" json:"values"`
}
// TCPSequence represents a detected TCP sequence.
type TCPSequence struct {
Index int `xml:"index,attr" json:"index"`
Difficulty string `xml:"difficulty,attr" json:"difficulty"`
Values string `xml:"values,attr" json:"values"`
}
// IPIDSequence represents a detected IP ID sequence.
type IPIDSequence Sequence
// TCPTSSequence represents a detected TCP TS sequence.
type TCPTSSequence Sequence
// Trace represents the trace to a host, including the hops.
type Trace struct {
Proto string `xml:"proto,attr" json:"proto"`
Port int `xml:"port,attr" json:"port"`
Hops []Hop `xml:"hop" json:"hops"`
}
// Hop is an IP hop to a host.
type Hop struct {
TTL float32 `xml:"ttl,attr" json:"ttl"`
RTT string `xml:"rtt,attr" json:"rtt"`
IPAddr string `xml:"ipaddr,attr" json:"ip_addr"`
Host string `xml:"host,attr" json:"host"`
}
// Times contains time statistics for an nmap scan.
type Times struct {
SRTT string `xml:"srtt,attr" json:"srtt"`
RTT string `xml:"rttvar,attr" json:"rttv"`
To string `xml:"to,attr" json:"to"`
}
// Stats contains statistics for an nmap scan.
type Stats struct {
Finished Finished `xml:"finished" json:"finished"`
Hosts HostStats `xml:"hosts" json:"hosts"`
}
// Finished contains detailed statistics regarding a finished scan.
type Finished struct {
Time Timestamp `xml:"time,attr" json:"time"`
TimeStr string `xml:"timestr,attr" json:"time_str"`
Elapsed float32 `xml:"elapsed,attr" json:"elapsed"`
Summary string `xml:"summary,attr" json:"summary"`
Exit string `xml:"exit,attr" json:"exit"`
ErrorMsg string `xml:"errormsg,attr" json:"error_msg"`
}
// HostStats contains the amount of up and down hosts and the total count.
type HostStats struct {
Up int `xml:"up,attr" json:"up"`
Down int `xml:"down,attr" json:"down"`
Total int `xml:"total,attr" json:"total"`
}
// Timestamp represents time as a UNIX timestamp in seconds.
type Timestamp time.Time
// ParseTime converts a UNIX timestamp string to a time.Time.
func (t *Timestamp) ParseTime(s string) error {
timestamp, err := strconv.ParseInt(s, 10, 64)
if err != nil {
return err
}
*t = Timestamp(time.Unix(timestamp, 0))
return nil
}
// FormatTime formats the time.Time value as a UNIX timestamp string.
func (t Timestamp) FormatTime() string {
return strconv.FormatInt(time.Time(t).Unix(), 10)
}
// MarshalJSON implements the json.Marshaler interface.
func (t Timestamp) MarshalJSON() ([]byte, error) {
return []byte(t.FormatTime()), nil
}
// UnmarshalJSON implements the json.Unmarshaler interface.
func (t *Timestamp) UnmarshalJSON(b []byte) error {
return t.ParseTime(string(b))
}
// MarshalXMLAttr implements the xml.MarshalerAttr interface.
func (t Timestamp) MarshalXMLAttr(name xml.Name) (xml.Attr, error) {
if time.Time(t).IsZero() {
return xml.Attr{}, nil
}
return xml.Attr{Name: name, Value: t.FormatTime()}, nil
}
// UnmarshalXMLAttr implements the xml.UnmarshalXMLAttr interface.
func (t *Timestamp) UnmarshalXMLAttr(attr xml.Attr) (err error) {
return t.ParseTime(attr.Value)
}
// Parse takes a byte array of nmap xml data and unmarshals it into a
// Run struct.
func Parse(content []byte) (*Run, error) {
r := &Run{
rawXML: content,
}
err := xml.Unmarshal(content, r)
return r, err
}