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
This commit is contained in:
Brendan LE GLAUNEC
2019-01-22 21:16:16 +01:00
committed by GitHub
parent 878ca9f032
commit 5849898283
973 changed files with 401790 additions and 1002 deletions
+123
View File
@@ -0,0 +1,123 @@
## Golang
### Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
### Test binary, built with `go test -c`
*.test
### Output of the go coverage tool, specifically when used with LiteIDE
*.out
## MacOS
### General
.DS_Store
.AppleDouble
.LSOverride
### Icon must end with two \r
Icon
### Thumbnails
._*
### Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
### Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
## IDEs
### VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
### JetBrains
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
+159
View File
@@ -0,0 +1,159 @@
# This file contains all available configuration options
# with their default values.
# options for analysis running
run:
# timeout for analysis, e.g. 30s, 5m, default is 1m
deadline: 1m
tests: false
# which dirs to skip: they won't be analyzed;
# can use regexp here: generated.*, regexp is applied on full path;
# default value is empty list, but next dirs are always skipped independently
# from this option's value:
# vendor$, third_party$, testdata$, examples$, Godeps$, builtin$
skip-dirs:
- pkg/osfamilies
# output configuration options
output:
# colored-line-number|line-number|json|tab|checkstyle, default is "colored-line-number"
format: colored-line-number
# print lines of code with issue, default is true
print-issued-lines: true
# print linter name in the end of issue text, default is true
print-linter-name: true
# all available settings of specific linters
linters-settings:
errcheck:
# report about not checking of errors in type assetions: `a := b.(MyStruct)`;
# default is false: such cases aren't reported by default.
check-type-assertions: false
# report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`;
# default is false: such cases aren't reported by default.
check-blank: false
# [deprecated] comma-separated list of pairs of the form pkg:regex
# the regex is used to ignore names within pkg. (default "fmt:.*").
# see https://github.com/kisielk/errcheck#the-deprecated-method for details
ignore: fmt:.*,io/ioutil:^Read.*,os/exec:^Kill.*
govet:
# report about shadowed variables
check-shadowing: true
golint:
# minimal confidence for issues, default is 0.8
min-confidence: 0.8
gofmt:
# simplify code: gofmt with `-s` option, true by default
simplify: true
goimports:
# put imports beginning with prefix after 3rd-party packages;
# it's a comma-separated list of prefixes
local-prefixes: github.com/org/project
gocyclo:
# minimal code complexity to report, 30 by default (but we recommend 10-20)
min-complexity: 10
maligned:
# print struct with more effective memory layout or not, false by default
suggest-new: true
dupl:
# tokens count to trigger issue, 150 by default
threshold: 150
goconst:
# minimal length of string constant, 3 by default
min-len: 3
# minimal occurrences count to trigger, 3 by default
min-occurrences: 3
depguard:
list-type: blacklist
include-go-root: false
packages:
- github.com/davecgh/go-spew/spew
misspell:
# Correct spellings using locale preferences for US or UK.
# Default is to use a neutral variety of English.
# Setting locale to US will correct the British spelling of 'colour' to 'color'.
locale: US
lll:
# max line length, lines longer will be reported. Default is 120.
# '\t' is counted as 1 character by default, and can be changed with the tab-width option
line-length: 120
# tab width in spaces. Default to 1.
tab-width: 1
unused:
# treat code as a program (not a library) and report unused exported identifiers; default is false.
# XXX: if you enable this setting, unused will report a lot of false-positives in text editors:
# if it's called for subdir of a project it can't find funcs usages. All text editor integrations
# with golangci-lint call it on a directory with the changed file.
check-exported: false
unparam:
# call graph construction algorithm (cha, rta). In general, use cha for libraries,
# and rta for programs with main packages. Default is cha.
algo: cha
# Inspect exported functions, default is false. Set to true if no external program/library imports your code.
# XXX: if you enable this setting, unparam will report a lot of false-positives in text editors:
# if it's called for subdir of a project it can't find external interfaces. All text editor integrations
# with golangci-lint call it on a directory with the changed file.
check-exported: false
nakedret:
# make an issue if func has more lines of code than this setting and it has naked returns; default is 30
max-func-lines: 30
prealloc:
# XXX: we don't recommend using this linter before doing performance profiling.
# For most programs usage of prealloc will be a premature optimization.
# Report preallocation suggestions only on simple loops that have no returns/breaks/continues/gotos in them.
# True by default.
simple: true
range-loops: true # Report preallocation suggestions on range loops, true by default
for-loops: false # Report preallocation suggestions on for loops, false by default
gocritic:
# Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint` run to see all tags and checks.
# Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags".
enabled-tags:
- performance
linters:
enable:
- megacheck
- govet
enable-all: false
disable:
- maligned
- prealloc
disable-all: false
presets:
- bugs
- unused
fast: false
issues:
# List of regexps of issue texts to exclude, empty list by default.
# But independently from this option we use default exclude patterns,
# it can be disabled by `exclude-use-default: false`. To list all
# excluded by default patterns execute `golangci-lint run --help`
exclude:
- "Subprocess launching should be audited"
# Maximum issues count per one linter. Set to 0 to disable. Default is 50.
max-per-linter: 0
# Maximum count of issues with the same text. Set to 0 to disable. Default is 3.
max-same-issues: 0
# Show only new issues: if there are unstaged changes or untracked files,
# only those changes are analyzed, else only changes in HEAD~ are analyzed.
# It's a super-useful option for integration of golangci-lint into existing
# large codebase. It's not practical to fix all existing issues at the moment
# of integration: much better don't allow issues in new code.
# Default is false.
new: false
+20
View File
@@ -0,0 +1,20 @@
dist: trusty
sudo: required
language: go
before_install:
- sudo apt-get install -y nmap
- go get github.com/mattn/goveralls
script:
# Run unit tests
- go test -v -covermode=count -coverprofile=coverage.out
- $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci -repotoken=$COVERALLS_TOKEN
# Ensure the examples compile
- for dir in examples/*/; do go build -o $dir/bin $dir/main.go; done
notifications:
email:
recipients:
- brendan.le-glaunec@epitech.eu
on_success: never
on_failure: always
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Ullaakut
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+114
View File
@@ -0,0 +1,114 @@
# nmap
<p align="center">
<img width="350" src="img/logo.png"/>
<p>
<p align="center">
<a href="LICENSE">
<img src="https://img.shields.io/badge/license-MIT-blue.svg?style=flat" />
</a>
<a href="https://godoc.org/github.com/Ullaakut/nmap">
<img src="https://godoc.org/github.com/Ullaakut/cameradar?status.svg" />
</a>
<a href="https://goreportcard.com/report/github.com/ullaakut/nmap">
<img src="https://goreportcard.com/badge/github.com/ullaakut/nmap">
</a>
<a href="https://travis-ci.org/Ullaakut/nmap">
<img src="https://travis-ci.org/Ullaakut/nmap.svg?branch=master">
</a>
<a href="https://coveralls.io/github/Ullaakut/nmap?branch=master">
<img src="https://coveralls.io/repos/github/Ullaakut/nmap/badge.svg?branch=master">
</a>
<p>
This library aims at providing idiomatic `nmap` bindings for go developers, in order to make it easier to write security audit tools using golang.
<!-- It allows not only to parse the XML output of nmap, but also to get the output of nmap as it is running, through a channel. This can be useful for computing a scan's progress, or simply displaying live information to your users. -->
## It's currently a work in progress
This paragraph won't be removed until the library is ready to be used and properly documented.
## Supported features
- [x] All of `nmap`'s options as `WithXXX` methods.
- [x] Cancellable contexts support.
- [x] [Idiomatic go filters](examples/service_detection/main.go#L19).
- [x] Helpful enums for most nmap commands. (time templates, os families, port states, etc.)
- [x] Complete documentation of each option, mostly insipred from nmap's documentation.
## TODO
- [ ] Examples of usage - Work in progress (4/7 examples so far)
- [ ] Complete unit tests - Work in progress (95% coverage so far)
- [ ] Asynchronous scan
## Example
```go
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/Ullaakut/nmap"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
// Equivalent to `/usr/local/bin/nmap -p 80,443,843 google.com facebook.com youtube.com`,
// with a 5 minute timeout.
scanner, err := nmap.NewScanner(
nmap.WithTargets("google.com", "facebook.com", "youtube.com"),
nmap.WithPorts("80,443,843"),
nmap.WithContext(ctx),
)
if err != nil {
log.Fatalf("unable to create nmap scanner: %v", err)
}
result, err := scanner.Run()
if err != nil {
log.Fatalf("unable to run nmap scan: %v", err)
}
// Use the results to print an example output
for _, host := range result.Hosts {
if len(host.Ports) == 0 || len(host.Addresses) == 0 {
continue
}
fmt.Printf("Host %q:\n", host.Addresses[0])
for _, port := range host.Ports {
fmt.Printf("\tPort %d/%s %s %s\n", port.ID, port.Protocol, port.State, port.Service.Name)
}
}
fmt.Printf("Nmap done: %d hosts up scanned in %3f seconds\n", len(result.Hosts), result.Stats.Finished.Elapsed)
}
```
The program above outputs:
```bash
Host "172.217.16.46":
Port 80/tcp open http
Port 443/tcp open https
Port 843/tcp filtered unknown
Host "31.13.81.36":
Port 80/tcp open http
Port 443/tcp open https
Port 843/tcp open unknown
Host "216.58.215.110":
Port 80/tcp open http
Port 443/tcp open https
Port 843/tcp filtered unknown
Nmap done: 3 hosts up scanned in 1.29 seconds
```
+18
View File
@@ -0,0 +1,18 @@
package nmap
import (
"errors"
)
var (
// ErrNmapNotInstalled means that upon trying to manually locate nmap in the user's path,
// it was not found. Either use the WithBinaryPath method to set it manually, or make sure that
// the nmap binary is present in the user's $PATH.
ErrNmapNotInstalled = errors.New("'nmap' binary was not found")
// ErrScanTimeout means that the provided context was done before the scanner finished its scan.
ErrScanTimeout = errors.New("nmap scan timed out")
// ErrNoTargetsSpecified means that no targets were specified.
ErrNoTargetsSpecified = errors.New("no targets specified")
)
+64
View File
@@ -0,0 +1,64 @@
package nmap
import (
"fmt"
"log"
)
// A scanner can be instanciated with options to set the arguments
// that are given to nmap.
func ExampleScanner_simple() {
s, err := NewScanner(
WithTargets("google.com", "facebook.com", "youtube.com"),
WithCustomDNSServers("8.8.8.8", "8.8.4.4"),
WithTimingTemplate(TimingFastest),
WithTCPScanFlags(FlagACK, FlagNULL, FlagRST),
)
if err != nil {
log.Fatalf("unable to create nmap scanner: %v", err)
}
scanResult, err := s.Run()
if err != nil {
log.Fatalf("nmap encountered an error: %v", err)
}
fmt.Printf(
"Scan successful: %d hosts up\n",
scanResult.Stats.Hosts.Up,
)
// Output: Scan successful: 3 hosts up
}
// A scanner can be given custom idiomatic filters for both hosts
// and ports.
func ExampleScanner_filters() {
s, err := NewScanner(
WithTargets("google.com", "facebook.com"),
WithPorts("843"),
WithFilterHost(func(h Host) bool {
// Filter out hosts with no open ports.
for idx := range h.Ports {
if h.Ports[idx].Status() == "open" {
return true
}
}
return false
}),
)
if err != nil {
log.Fatalf("unable to create nmap scanner: %v", err)
}
scanResult, err := s.Run()
if err != nil {
log.Fatalf("nmap encountered an error: %v", err)
}
fmt.Printf(
"Filtered out hosts %d / Original number of hosts: %d\n",
len(scanResult.Hosts),
scanResult.Stats.Hosts.Total,
)
// Output: Filtered out hosts 1 / Original number of hosts: 2
}
+1216
View File
File diff suppressed because it is too large Load Diff
+1781
View File
File diff suppressed because it is too large Load Diff
+644
View File
@@ -0,0 +1,644 @@
package osfamilies
// OSFamily describes an OS Family, usually from a constructor or
// a kernel.
type OSFamily string
// OSFamily definitions.
const (
TwoN OSFamily = "2N"
TwoWire OSFamily = "2Wire"
ThreeCom OSFamily = "3Com"
ThreeM OSFamily = "3M"
FourG OSFamily = "4G"
ATec OSFamily = "A-Tec"
ADIC OSFamily = "ADIC"
AKCP OSFamily = "AKCP"
AMX OSFamily = "AMX"
APC OSFamily = "APC"
ARCA OSFamily = "ARCA"
ATandT OSFamily = "AT&T"
AVM OSFamily = "AVM"
AVtech OSFamily = "AVtech"
AXIS OSFamily = "AXIS"
Aastra OSFamily = "Aastra"
AcBel OSFamily = "AcBel"
Aceex OSFamily = "Aceex"
Acer OSFamily = "Acer"
Acme OSFamily = "Acme"
Acorp OSFamily = "Acorp"
Actiontec OSFamily = "Actiontec"
Adaptec OSFamily = "Adaptec"
Adtran OSFamily = "Adtran"
Adva OSFamily = "Adva"
Advanced OSFamily = "Advanced"
Aerohive OSFamily = "Aerohive"
Aethra OSFamily = "Aethra"
Agfa OSFamily = "Agfa"
AirLive OSFamily = "AirLive"
AirMagnet OSFamily = "AirMagnet"
AirSpan OSFamily = "AirSpan"
Airaya OSFamily = "Airaya"
Airlink101 OSFamily = "Airlink101"
Airnet OSFamily = "Airnet"
Airvana OSFamily = "Airvana"
Alaxala OSFamily = "Alaxala"
Alcatel OSFamily = "Alcatel"
AlcatelLucent OSFamily = "Alcatel-Lucent"
Alice OSFamily = "Alice"
AllenBradley OSFamily = "Allen-Bradley"
Allied OSFamily = "Allied"
Allnet OSFamily = "Allnet"
Allworx OSFamily = "Allworx"
Alvarion OSFamily = "Alvarion"
Amazon OSFamily = "Amazon"
Ambit OSFamily = "Ambit"
Amiga OSFamily = "Amiga"
Anue OSFamily = "Anue"
Apple OSFamily = "Apple"
Arcor OSFamily = "Arcor"
Areca OSFamily = "Areca"
Argon OSFamily = "Argon"
Argosy OSFamily = "Argosy"
Arris OSFamily = "Arris"
Aruba OSFamily = "Aruba"
Asmax OSFamily = "Asmax"
Asus OSFamily = "Asus"
Atari OSFamily = "Atari"
Atcom OSFamily = "Atcom"
AudioCodes OSFamily = "AudioCodes"
AudioControl OSFamily = "AudioControl"
Avaya OSFamily = "Avaya"
Avocent OSFamily = "Avocent"
Axcient OSFamily = "Axcient"
AzBox OSFamily = "AzBox"
BECK OSFamily = "BECK"
BSD OSFamily = "BSD"
BSDI OSFamily = "BSDI"
BT OSFamily = "BT"
Barracuda OSFamily = "Barracuda"
Barrelfish OSFamily = "Barrelfish"
Basler OSFamily = "Basler"
Bay OSFamily = "Bay"
BeaconMedaes OSFamily = "BeaconMedaes"
Beat OSFamily = "Beat"
Belkin OSFamily = "Belkin"
Bell OSFamily = "Bell"
Billion OSFamily = "Billion"
BinTec OSFamily = "BinTec"
BlackBox OSFamily = "BlackBox"
Blackboard OSFamily = "Blackboard"
Blue OSFamily = "Blue"
BlueArc OSFamily = "BlueArc"
Bluebird OSFamily = "Bluebird"
Bomara OSFamily = "Bomara"
Bosch OSFamily = "Bosch"
Bose OSFamily = "Bose"
Boundless OSFamily = "Boundless"
Bowers OSFamily = "Bowers"
British OSFamily = "British"
BroadMax OSFamily = "BroadMax"
Brocade OSFamily = "Brocade"
Brother OSFamily = "Brother"
Buffalo OSFamily = "Buffalo"
Burny OSFamily = "Burny"
Bush OSFamily = "Bush"
CNav OSFamily = "C-Nav"
CAEN OSFamily = "CAEN"
CMI OSFamily = "CMI"
Cabletron OSFamily = "Cabletron"
Caldera OSFamily = "Caldera"
Calix OSFamily = "Calix"
Cameo OSFamily = "Cameo"
Canon OSFamily = "Canon"
Casio OSFamily = "Casio"
Cayman OSFamily = "Cayman"
Ceedtec OSFamily = "Ceedtec"
Check OSFamily = "Check"
Chip OSFamily = "Chip"
CipherLab OSFamily = "CipherLab"
Cisco OSFamily = "Cisco"
Citrix OSFamily = "Citrix"
CoRAID OSFamily = "CoRAID"
Cobalt OSFamily = "Cobalt"
Cognex OSFamily = "Cognex"
Comau OSFamily = "Comau"
Compal OSFamily = "Compal"
Compaq OSFamily = "Compaq"
Comtrend OSFamily = "Comtrend"
Conceptronic OSFamily = "Conceptronic"
Control4 OSFamily = "Control4"
Coyote OSFamily = "Coyote"
Cray OSFamily = "Cray"
Crestron OSFamily = "Crestron"
CyanogenMod OSFamily = "CyanogenMod"
Cyberoam OSFamily = "Cyberoam"
Cymphonix OSFamily = "Cymphonix"
DLink OSFamily = "D-Link"
DEC OSFamily = "DEC"
DMP OSFamily = "DMP"
DTE OSFamily = "DTE"
DVTel OSFamily = "DVTel"
DYMO OSFamily = "DYMO"
Data OSFamily = "Data"
Datalogic OSFamily = "Datalogic"
Daysequerra OSFamily = "Daysequerra"
Decru OSFamily = "Decru"
Dedicated OSFamily = "Dedicated"
Dell OSFamily = "Dell"
Denon OSFamily = "Denon"
Denver OSFamily = "Denver"
Develop OSFamily = "Develop"
Dick OSFamily = "Dick"
Digi OSFamily = "Digi"
Digital OSFamily = "Digital"
Digitus OSFamily = "Digitus"
Digium OSFamily = "Digium"
DirecTV OSFamily = "DirecTV"
Dish OSFamily = "Dish"
Dolby OSFamily = "Dolby"
DragonFly OSFamily = "DragonFly"
DragonWave OSFamily = "DragonWave"
DrayTek OSFamily = "DrayTek"
Draytek OSFamily = "Draytek"
Drayton OSFamily = "Drayton"
Dream OSFamily = "Dream"
Drobo OSFamily = "Drobo"
EMC OSFamily = "EMC"
ESI OSFamily = "ESI"
ETH OSFamily = "ETH"
EasyPath OSFamily = "EasyPath"
Eaton OSFamily = "Eaton"
Efficient OSFamily = "Efficient"
Eicon OSFamily = "Eicon"
Elfiq OSFamily = "Elfiq"
Elk OSFamily = "Elk"
Elsag OSFamily = "Elsag"
Ember OSFamily = "Ember"
Emerson OSFamily = "Emerson"
EnGenius OSFamily = "EnGenius"
Encore OSFamily = "Encore"
Endian OSFamily = "Endian"
Enerdis OSFamily = "Enerdis"
Engetron OSFamily = "Engetron"
Enistic OSFamily = "Enistic"
Enlogic OSFamily = "Enlogic"
Enterasys OSFamily = "Enterasys"
Epson OSFamily = "Epson"
Ericsson OSFamily = "Ericsson"
Espressif OSFamily = "Espressif"
Essentia OSFamily = "Essentia"
EtherWerX OSFamily = "EtherWerX"
Exabyte OSFamily = "Exabyte"
Excito OSFamily = "Excito"
Express OSFamily = "Express"
Exterity OSFamily = "Exterity"
Extreme OSFamily = "Extreme"
F5 OSFamily = "F5"
FORE OSFamily = "FORE"
Fatek OSFamily = "Fatek"
FireBrick OSFamily = "FireBrick"
Force10 OSFamily = "Force10"
Fortinet OSFamily = "Fortinet"
Foscam OSFamily = "Foscam"
Foundry OSFamily = "Foundry"
Free OSFamily = "Free"
FreeBSD OSFamily = "FreeBSD"
FreeNAS OSFamily = "FreeNAS"
Freecom OSFamily = "Freecom"
Fronius OSFamily = "Fronius"
Frontier OSFamily = "Frontier"
Fuji OSFamily = "Fuji"
Fujian OSFamily = "Fujian"
Fujitsu OSFamily = "Fujitsu"
Funkwerk OSFamily = "Funkwerk"
GNU OSFamily = "GNU"
GalaxyMetalGear OSFamily = "GalaxyMetalGear"
Gargoyle OSFamily = "Gargoyle"
Garmin OSFamily = "Garmin"
GbE2c OSFamily = "GbE2c"
Geist OSFamily = "Geist"
Gemtek OSFamily = "Gemtek"
General OSFamily = "General"
Generex OSFamily = "Generex"
Gennet OSFamily = "Gennet"
Genua OSFamily = "Genua"
George OSFamily = "George"
Geovision OSFamily = "Geovision"
GlobespanVirata OSFamily = "GlobespanVirata"
GoPro OSFamily = "GoPro"
Google OSFamily = "Google"
Grace OSFamily = "Grace"
Grandstream OSFamily = "Grandstream"
Green OSFamily = "Green"
H3C OSFamily = "H3C"
HID OSFamily = "HID"
HP OSFamily = "HP"
HW OSFamily = "HW"
Haiku OSFamily = "Haiku"
Hamlet OSFamily = "Hamlet"
Harris OSFamily = "Harris"
Hawking OSFamily = "Hawking"
Hay OSFamily = "Hay"
Head OSFamily = "Head"
Henry OSFamily = "Henry"
HighFlying OSFamily = "High-Flying"
Hikvision OSFamily = "Hikvision"
Hioki OSFamily = "Hioki"
Hirschmann OSFamily = "Hirschmann"
Hitron OSFamily = "Hitron"
Hotway OSFamily = "Hotway"
Huawei OSFamily = "Huawei"
Hybertone OSFamily = "Hybertone"
IBM OSFamily = "IBM"
IEI OSFamily = "IEI"
IGEL OSFamily = "IGEL"
IHome OSFamily = "IHome"
IOData OSFamily = "IO-Data"
IOGear OSFamily = "IOGear"
ION OSFamily = "ION"
IPAD OSFamily = "IPAD"
IPCop OSFamily = "IPCop"
IPFire OSFamily = "IPFire"
ISS OSFamily = "ISS"
ITW OSFamily = "ITW"
Icom OSFamily = "Icom"
Icy OSFamily = "Icy"
Imperva OSFamily = "Imperva"
Infoblox OSFamily = "Infoblox"
Infomir OSFamily = "Infomir"
Infrant OSFamily = "Infrant"
Inova OSFamily = "Inova"
Instar OSFamily = "Instar"
Intel OSFamily = "Intel"
Interbell OSFamily = "Interbell"
Interflex OSFamily = "Interflex"
Intermec OSFamily = "Intermec"
Interpeak OSFamily = "Interpeak"
Intertex OSFamily = "Intertex"
Intracom OSFamily = "Intracom"
Inventel OSFamily = "Inventel"
Iomega OSFamily = "Iomega"
IronPort OSFamily = "IronPort"
Isilon OSFamily = "Isilon"
Iskratel OSFamily = "Iskratel"
JTEKT OSFamily = "JTEKT"
Joyent OSFamily = "Joyent"
Juniper OSFamily = "Juniper"
KA9Q OSFamily = "KA9Q"
KCorp OSFamily = "KCorp"
KWSoftware OSFamily = "KW-Software"
KabaBenzing OSFamily = "Kaba-Benzing"
Kaiomy OSFamily = "Kaiomy"
Kapsch OSFamily = "Kapsch"
Kartina OSFamily = "Kartina"
Kemp OSFamily = "Kemp"
Keyence OSFamily = "Keyence"
Kodak OSFamily = "Kodak"
Kongsberg OSFamily = "Kongsberg"
Konica OSFamily = "Konica"
Koukaam OSFamily = "Koukaam"
Kronos OSFamily = "Kronos"
Kyocera OSFamily = "Kyocera"
LG OSFamily = "LG"
LaCie OSFamily = "LaCie"
LaCrosse OSFamily = "LaCrosse"
LaSAT OSFamily = "LaSAT"
Lancom OSFamily = "Lancom"
Lanier OSFamily = "Lanier"
Lantronix OSFamily = "Lantronix"
Larus OSFamily = "Larus"
Leica OSFamily = "Leica"
Lenel OSFamily = "Lenel"
Leolink OSFamily = "Leolink"
LevelOne OSFamily = "LevelOne"
Lexmark OSFamily = "Lexmark"
Liebert OSFamily = "Liebert"
LifeSize OSFamily = "LifeSize"
Linksys OSFamily = "Linksys"
Linux OSFamily = "Linux"
LogiLink OSFamily = "LogiLink"
Logitech OSFamily = "Logitech"
Lorex OSFamily = "Lorex"
Lucent OSFamily = "Lucent"
Luminary OSFamily = "Luminary"
Luxul OSFamily = "Luxul"
Lyngsoe OSFamily = "Lyngsoe"
MGE OSFamily = "MGE"
MOXA OSFamily = "MOXA"
MPI OSFamily = "MPI"
Macsense OSFamily = "Macsense"
Maipu OSFamily = "Maipu"
Mapower OSFamily = "Mapower"
Marantz OSFamily = "Marantz"
McAfee OSFamily = "McAfee"
Meinberg OSFamily = "Meinberg"
Meru OSFamily = "Meru"
Metrix OSFamily = "Metrix"
MicroNet OSFamily = "MicroNet"
Microsoft OSFamily = "Microsoft"
Microware OSFamily = "Microware"
MikroTik OSFamily = "MikroTik"
Milight OSFamily = "Milight"
Minix OSFamily = "Minix"
Minolta OSFamily = "Minolta"
Mirapoint OSFamily = "Mirapoint"
Mitel OSFamily = "Mitel"
Mitrastar OSFamily = "Mitrastar"
Mitsubishi OSFamily = "Mitsubishi"
Modtronix OSFamily = "Modtronix"
Motorola OSFamily = "Motorola"
MusicianLink OSFamily = "MusicianLink"
NCR OSFamily = "NCR"
NEC OSFamily = "NEC"
NOXON OSFamily = "NOXON"
NRG OSFamily = "NRG"
NSFOCUS OSFamily = "NSFOCUS"
NTI OSFamily = "NTI"
NTT OSFamily = "NTT"
Nashuatec OSFamily = "Nashuatec"
National OSFamily = "National"
NeXT OSFamily = "NeXT"
Neopost OSFamily = "Neopost"
Ness OSFamily = "Ness"
Nest OSFamily = "Nest"
NetApp OSFamily = "NetApp"
NetBSD OSFamily = "NetBSD"
NetBurner OSFamily = "NetBurner"
NetOptics OSFamily = "NetOptics"
Netasq OSFamily = "Netasq"
Netcomm OSFamily = "Netcomm"
Netgear OSFamily = "Netgear"
Netgem OSFamily = "Netgem"
Netopia OSFamily = "Netopia"
Network OSFamily = "Network"
NetworkAlchemy OSFamily = "NetworkAlchemy"
NetworksAOK OSFamily = "NetworksAOK"
Neuf OSFamily = "Neuf"
Newave OSFamily = "Newave"
NexStor OSFamily = "NexStor"
Nexenta OSFamily = "Nexenta"
Nexsan OSFamily = "Nexsan"
Nibe OSFamily = "Nibe"
Nintendo OSFamily = "Nintendo"
NodeMCU OSFamily = "NodeMCU"
Nokia OSFamily = "Nokia"
Nomadix OSFamily = "Nomadix"
Nortel OSFamily = "Nortel"
Novatel OSFamily = "Novatel"
Novell OSFamily = "Novell"
NutOS OSFamily = "Nut/OS"
OSRAM OSFamily = "OSRAM"
Obihai OSFamily = "Obihai"
Ocean OSFamily = "Ocean"
Oki OSFamily = "Oki"
Olivetti OSFamily = "Olivetti"
Olympus OSFamily = "Olympus"
Omron OSFamily = "Omron"
On OSFamily = "On"
OnStor OSFamily = "OnStor"
Onboard OSFamily = "Onboard"
OneAccess OSFamily = "OneAccess"
OpenBSD OSFamily = "OpenBSD"
OpenBox OSFamily = "OpenBox"
Opto OSFamily = "Opto"
Oracle OSFamily = "Oracle"
Orange OSFamily = "Orange"
Osmosys OSFamily = "Osmosys"
Ouya OSFamily = "Ouya"
PCBSD OSFamily = "PC-BSD"
PCMeasure OSFamily = "PCMeasure"
PORTech OSFamily = "PORTech"
Packard OSFamily = "Packard"
Packet8 OSFamily = "Packet8"
PacketFront OSFamily = "PacketFront"
Packeteer OSFamily = "Packeteer"
Palmmicro OSFamily = "Palmmicro"
Palo OSFamily = "Palo"
Panasas OSFamily = "Panasas"
Panasonic OSFamily = "Panasonic"
Papouch OSFamily = "Papouch"
Patton OSFamily = "Patton"
Peplink OSFamily = "Peplink"
Perfectone OSFamily = "Perfectone"
Perle OSFamily = "Perle"
Phar OSFamily = "Phar"
PheeNet OSFamily = "PheeNet"
Philips OSFamily = "Philips"
Phoenix OSFamily = "Phoenix"
Pingtel OSFamily = "Pingtel"
Pioneer OSFamily = "Pioneer"
Pirelli OSFamily = "Pirelli"
Planet OSFamily = "Planet"
Polycom OSFamily = "Polycom"
Precise OSFamily = "Precise"
Printronix OSFamily = "Printronix"
Priva OSFamily = "Priva"
Promise OSFamily = "Promise"
Proxim OSFamily = "Proxim"
QEMU OSFamily = "QEMU"
QNAP OSFamily = "QNAP"
QNX OSFamily = "QNX"
QTech OSFamily = "QTech"
Qualisys OSFamily = "Qualisys"
Quantum OSFamily = "Quantum"
Quarterdeck OSFamily = "Quarterdeck"
RAD OSFamily = "RAD"
RCA OSFamily = "RCA"
RF OSFamily = "RF"
RFSpace OSFamily = "RF-Space"
RGB OSFamily = "RGB"
RIM OSFamily = "RIM"
RISCOS OSFamily = "RISCOS"
RISE OSFamily = "RISE"
RSA OSFamily = "RSA"
Rabbit OSFamily = "Rabbit"
Radware OSFamily = "Radware"
Raritan OSFamily = "Raritan"
ReactOS OSFamily = "ReactOS"
RedM OSFamily = "Red-M"
Redback OSFamily = "Redback"
Reliable OSFamily = "Reliable"
Repotech OSFamily = "Repotech"
Revo OSFamily = "Revo"
Ricoh OSFamily = "Ricoh"
Rigol OSFamily = "Rigol"
Rio OSFamily = "Rio"
Riverbed OSFamily = "Riverbed"
Roberts OSFamily = "Roberts"
Rockwell OSFamily = "Rockwell"
Roku OSFamily = "Roku"
Ruckus OSFamily = "Ruckus"
RuggedCom OSFamily = "RuggedCom"
Ruijie OSFamily = "Ruijie"
SCO OSFamily = "SCO"
SEH OSFamily = "SEH"
SGI OSFamily = "SGI"
SMA OSFamily = "SMA"
SMC OSFamily = "SMC"
SNR OSFamily = "SNR"
Sagem OSFamily = "Sagem"
Sagemcom OSFamily = "Sagemcom"
Samsung OSFamily = "Samsung"
Sandstrom OSFamily = "Sandstrom"
Sanyo OSFamily = "Sanyo"
Sapling OSFamily = "Sapling"
Satel OSFamily = "Satel"
Savin OSFamily = "Savin"
Schneider OSFamily = "Schneider"
Schrack OSFamily = "Schrack"
Schweitzer OSFamily = "Schweitzer"
Scientific OSFamily = "Scientific"
Seagate OSFamily = "Seagate"
Secure OSFamily = "Secure"
Seiko OSFamily = "Seiko"
Senao OSFamily = "Senao"
Sensatronics OSFamily = "Sensatronics"
Sequent OSFamily = "Sequent"
Sharp OSFamily = "Sharp"
Shenzhen OSFamily = "Shenzhen"
ShoreTel OSFamily = "ShoreTel"
Siemens OSFamily = "Siemens"
Silicondust OSFamily = "Silicondust"
Sinus OSFamily = "Sinus"
Sipura OSFamily = "Sipura"
Sitecom OSFamily = "Sitecom"
Sling OSFamily = "Sling"
Slingbox OSFamily = "Slingbox"
Smart OSFamily = "Smart"
Smartlink OSFamily = "Smartlink"
Snom OSFamily = "Snom"
Solwise OSFamily = "Solwise"
SonicWALL OSFamily = "SonicWALL"
Sonos OSFamily = "Sonos"
Sonus OSFamily = "Sonus"
Sony OSFamily = "Sony"
Source OSFamily = "Source"
Specialix OSFamily = "Specialix"
Sphairon OSFamily = "Sphairon"
Star OSFamily = "Star"
Starbridge OSFamily = "Starbridge"
Stonewater OSFamily = "Stonewater"
StorageTek OSFamily = "StorageTek"
Stratus OSFamily = "Stratus"
Suga OSFamily = "Suga"
Sun OSFamily = "Sun"
SunPower OSFamily = "SunPower"
Supermicro OSFamily = "Supermicro"
Syllable OSFamily = "Syllable"
Symantec OSFamily = "Symantec"
Symbian OSFamily = "Symbian"
Symbol OSFamily = "Symbol"
Symmetricon OSFamily = "Symmetricon"
Synology OSFamily = "Synology"
THome OSFamily = "T-Home"
TMarc OSFamily = "T-Marc"
TPLINK OSFamily = "TP-LINK"
TPLink OSFamily = "TP-Link"
TRENDnet OSFamily = "TRENDnet"
Tadiran OSFamily = "Tadiran"
Tahoe OSFamily = "Tahoe"
Tandberg OSFamily = "Tandberg"
Tandem OSFamily = "Tandem"
TechniSat OSFamily = "TechniSat"
Tektronix OSFamily = "Tektronix"
Telco OSFamily = "Telco"
Teldat OSFamily = "Teldat"
Telekom OSFamily = "Telekom"
Telewell OSFamily = "Telewell"
Telex OSFamily = "Telex"
Telsey OSFamily = "Telsey"
Teltronics OSFamily = "Teltronics"
TenAsys OSFamily = "TenAsys"
Tenda OSFamily = "Tenda"
Teradici OSFamily = "Teradici"
Terratec OSFamily = "Terratec"
Texas OSFamily = "Texas"
Thales OSFamily = "Thales"
Thecus OSFamily = "Thecus"
Thomson OSFamily = "Thomson"
Tiandy OSFamily = "Tiandy"
Tibbo OSFamily = "Tibbo"
Tigo OSFamily = "Tigo"
Tintri OSFamily = "Tintri"
TippingPoint OSFamily = "TippingPoint"
Tizen OSFamily = "Tizen"
Topfield OSFamily = "Topfield"
Toptech OSFamily = "Toptech"
Toshiba OSFamily = "Toshiba"
Trane OSFamily = "Trane"
TransAct OSFamily = "TransAct"
Tranzeo OSFamily = "Tranzeo"
Trapeze OSFamily = "Trapeze"
Tripp OSFamily = "Tripp"
Tut OSFamily = "Tut"
Tyco OSFamily = "Tyco"
USRobotics OSFamily = "USRobotics"
UTStarcom OSFamily = "UTStarcom"
Ubee OSFamily = "Ubee"
Ubicom OSFamily = "Ubicom"
Ubiquiti OSFamily = "Ubiquiti"
Universal OSFamily = "Universal"
VBrick OSFamily = "VBrick"
VIPA OSFamily = "VIPA"
VMware OSFamily = "VMware"
VTrak OSFamily = "VTrak"
Vantage OSFamily = "Vantage"
Vegastream OSFamily = "Vegastream"
Viasat OSFamily = "Viasat"
Vilar OSFamily = "Vilar"
Virdi OSFamily = "Virdi"
Visual OSFamily = "Visual"
Vocality OSFamily = "Vocality"
Vodafone OSFamily = "Vodafone"
Vodavi OSFamily = "Vodavi"
Vonage OSFamily = "Vonage"
WandT OSFamily = "W&T"
WAGO OSFamily = "WAGO"
WIZnet OSFamily = "WIZnet"
Wago OSFamily = "Wago"
Walker OSFamily = "Walker"
WatchGuard OSFamily = "WatchGuard"
WebSense OSFamily = "WebSense"
Welltech OSFamily = "Welltech"
Westell OSFamily = "Westell"
Westermo OSFamily = "Westermo"
Western OSFamily = "Western"
Wind OSFamily = "Wind"
Windows OSFamily = "Windows"
World OSFamily = "World"
WowWee OSFamily = "WowWee"
Wyse OSFamily = "Wyse"
XAVi OSFamily = "XAVi"
XEUdotCom OSFamily = "XEU.com"
XMOS OSFamily = "XMOS"
Xerox OSFamily = "Xerox"
Xiaomi OSFamily = "Xiaomi"
Xirrus OSFamily = "Xirrus"
Xylan OSFamily = "Xylan"
Xyplex OSFamily = "Xyplex"
Yamaha OSFamily = "Yamaha"
Yealink OSFamily = "Yealink"
ZKTeco OSFamily = "ZKTeco"
ZTE OSFamily = "ZTE"
Zebra OSFamily = "Zebra"
Zelax OSFamily = "Zelax"
Zerto OSFamily = "Zerto"
Zhone OSFamily = "Zhone"
Zipato OSFamily = "Zipato"
ZoneAlarm OSFamily = "ZoneAlarm"
Zoom OSFamily = "Zoom"
ZyXEL OSFamily = "ZyXEL"
Zyfer OSFamily = "Zyfer"
cab OSFamily = "cab"
eCosCentric OSFamily = "eCosCentric"
iDirect OSFamily = "iDirect"
iPXE OSFamily = "iPXE"
iRobot OSFamily = "iRobot"
illumos OSFamily = "illumos"
ipTIME OSFamily = "ipTIME"
lwIP OSFamily = "lwIP"
m3 OSFamily = "m3"
mbNet OSFamily = "mbNet"
nCircle OSFamily = "nCircle"
)
+508
View File
@@ -0,0 +1,508 @@
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
}
+939
View File
@@ -0,0 +1,939 @@
package nmap
import (
"bytes"
"encoding/xml"
"fmt"
"io/ioutil"
"reflect"
"testing"
"time"
family "github.com/Ullaakut/nmap/pkg/osfamilies"
)
func TestParseTime(t *testing.T) {
ts := Timestamp{}
err := ts.ParseTime("invalid")
if err == nil {
t.Errorf("expected strconv.ParseInt: parsing \"invalid\": invalid syntax got %v", err)
}
}
func TestFormatTime(t *testing.T) {
originalStr := "123456789"
ts := Timestamp{}
err := ts.ParseTime(originalStr)
if err != nil {
panic(err)
}
result := ts.FormatTime()
if result != originalStr {
t.Errorf("expected %s got %s", originalStr, result)
}
}
func TestOSFamily(t *testing.T) {
osc := OSClass{
Family: "Linux",
}
if osc.OSFamily() != family.Linux {
t.Errorf("expected OSClass.OSFamily() to be equal to %v, got %v", family.Linux, osc.OSFamily())
}
}
func TestParseTableXML(t *testing.T) {
expectedTable := map[string]string{
"key": "AAAAB3NzaC1yc2EAAAABIwAAAQEAwVKoTY/7GFG7BmKkG6qFAHY/f3ciDX2MXTBLMEJP0xyUJsoy/CVRYw2b4qUB/GCJ5lh2InP+LVnPD3ZdtpyIvbS0eRZs/BH+mVLGh9xA/wOEUiiCfzQRsHj1xn7cqeWViAzQtdGluk/5CVAvr1FU3HNaaWkg7KQOSiKAzgDwCBtQhlgI40xdXgbqMkrHeP4M1p4MxoEVpZMe4oObACWwazeHP/Xas1vy5rbnmE59MpEZaA8t7AfGlW4MrVMhAB1JsFMdd0qFLpy/l93H3ptSlx1+6PQ5gUyjhmDUjMR+k6fb0yOeGdOrjN8IrWPmebZRFBjK5aCJwubgY/03VsSBMQ==",
"fingerprint": "79f809acd4e232421049d3bd208285ec",
"type": "ssh-rsa",
"bits": "2048",
}
input := []byte(fmt.Sprintf(
`<table><elem key="key">%s</elem><elem key="fingerprint">%s</elem><elem key="type">%s</elem><elem key="bits">%s</elem></table>`,
expectedTable["key"],
expectedTable["fingerprint"],
expectedTable["type"],
expectedTable["bits"],
))
var table Table
err := xml.Unmarshal(input, &table)
if err != nil {
panic(err)
}
if table["key"] != expectedTable["key"] {
t.Errorf("expected %v got %v", expectedTable["key"], table["key"])
}
if table["fingerprint"] != expectedTable["fingerprint"] {
t.Errorf("expected %v got %v", expectedTable["fingerprint"], table["fingerprint"])
}
if table["type"] != expectedTable["type"] {
t.Errorf("expected %v got %v", expectedTable["type"], table["type"])
}
if table["bits"] != expectedTable["bits"] {
t.Errorf("expected %v got %v", expectedTable["bits"], table["bits"])
}
}
func TestFormatTableXML(t *testing.T) {
table := Table(map[string]string{
"key": "AAAAB3NzaC1yc2EAAAABIwAAAQEAwVKoTY/7GFG7BmKkG6qFAHY/f3ciDX2MXTBLMEJP0xyUJsoy/CVRYw2b4qUB/GCJ5lh2InP+LVnPD3ZdtpyIvbS0eRZs/BH+mVLGh9xA/wOEUiiCfzQRsHj1xn7cqeWViAzQtdGluk/5CVAvr1FU3HNaaWkg7KQOSiKAzgDwCBtQhlgI40xdXgbqMkrHeP4M1p4MxoEVpZMe4oObACWwazeHP/Xas1vy5rbnmE59MpEZaA8t7AfGlW4MrVMhAB1JsFMdd0qFLpy/l93H3ptSlx1+6PQ5gUyjhmDUjMR+k6fb0yOeGdOrjN8IrWPmebZRFBjK5aCJwubgY/03VsSBMQ==",
"fingerprint": "79f809acd4e232421049d3bd208285ec",
"type": "ssh-rsa",
"bits": "2048",
})
expectedXML := [][]byte{
[]byte("<Table>"),
[]byte(fmt.Sprintf(`<elem key="key">%s</elem>`, table["key"])),
[]byte(fmt.Sprintf(`<elem key="fingerprint">%s</elem>`, table["fingerprint"])),
[]byte(fmt.Sprintf(`<elem key="type">%s</elem>`, table["type"])),
[]byte(fmt.Sprintf(`<elem key="bits">%s</elem>`, table["bits"])),
[]byte("</Table>"),
}
XML, err := xml.Marshal(table)
if err != nil {
panic(err)
}
for _, expectedXMLElement := range expectedXML {
if !bytes.Contains(XML, expectedXMLElement) {
t.Errorf("missing %s in %s", expectedXMLElement, XML)
}
}
}
func TestParseRunXML(t *testing.T) {
tests := []struct {
inputFile string
expectedResult *Run
expectedError error
}{
{
inputFile: "test_xml/scan01.xml",
expectedResult: &Run{
Args: "nmap -A -v -oX sample-03.xml freshmeat.net sourceforge.net nmap.org kernel.org openbsd.org netbsd.org google.com gmail.com",
Scanner: "nmap",
StartStr: "Sun Jan 27 21:10:02 2008",
Version: "4.53",
XMLOutputVersion: "1.01",
ScanInfo: ScanInfo{
NumServices: 1714,
Protocol: "tcp",
Services: "1-1027,1029-1033,1040,1043,1050,1058-1059,1067-1068,1076,1080,1083-1084,1103,1109-1110,1112,1127,1139,1155,1158,1178,1212,1214,1220,1222,1234,1241,1248,1270,1337,1346-1381,1383-1552,1600,1650-1652,1661-1672,1680,1720,1723,1755,1761-1764,1827,1900,1935,1984,1986-2028,2030,2032-2035,2038,2040-2049,2053,2064-2065,2067-2068,2105-2106,2108,2111-2112,2120-2121,2201,2232,2241,2301,2307,2401,2430-2433,2500-2501,2564,2600-2605,2627-2628,2638,2766,2784,2809,2903,2998,3000-3001,3005-3006,3025,3045,3049,3052,3064,3086,3128,3141,3264,3268-3269,3292,3299,3306,3333,3372,3389,3397-3399,3421,3455-3457,3462,3531,3632,3689,3900,3984-3986,3999-4000,4002,4008,4045,4125,4132-4133,4144,4199,4224,4321,4333,4343,4444,4480,4500,4557,4559,4660,4662,4672,4899,4987,4998,5000-5003,5009-5011,5050,5060,5100-5102,5145,5190-5193,5232,5236,5300-5305,5308,5400,5405,5432,5490,5500,5510,5520,5530,5540,5550,5555,5560,5631-5632,5679-5680,5713-5717,5800-5803,5900-5903,5977-5979,5997-6009,6017,6050,6101,6103,6105-6106,6110-6112,6141-6148,6222,6346-6347,6400-6401,6502,6543-6544,6547-6548,6558,6588,6662,6665-6670,6699-6701,6881,6969,7000-7010,7070,7100,7200-7201,7273,7326,7464,7597,7937-7938,8000,8007,8009,8021,8076,8080-8082,8118,8123,8443,8770,8888,8892,9040,9050-9051,9090,9100-9107,9111,9152,9535,9876,9991-9992,9999-10000,10005,10082-10083,11371,12000,12345-12346,13701-13702,13705-13706,13708-13718,13720-13722,13782-13783,14141,15126,15151,16080,16444,16959,17007,17300,18000,18181-18185,18187,19150,20005,22273,22289,22305,22321,22370,26208,27000-27010,27374,27665,31337,31416,32770-32780,32786-32787,38037,38292,43188,44334,44442-44443,47557,49400,50000,50002,54320,61439-61441,65301",
Type: "syn",
},
Start: Timestamp(time.Unix(1201479002, 0)),
Verbose: Verbose{
Level: 1,
},
Stats: Stats{
Finished: Finished{
Time: Timestamp(time.Unix(1201481569, 0)),
TimeStr: "Sun Jan 27 21:52:49 2008",
},
Hosts: HostStats{
Up: 8,
Total: 8,
Down: 0,
},
},
Hosts: []Host{
{
IPIDSequence: IPIDSequence{
Class: "All zeros",
Values: "0,0,0,0,0,0",
},
OS: OS{
PortsUsed: []PortUsed{
{
State: "open",
Proto: "tcp",
ID: 80,
},
{
State: "closed",
Proto: "tcp",
ID: 443,
},
},
Matches: []OSMatch{
{
Name: "MicroTik RouterOS 2.9.46",
Accuracy: 94,
Line: 14788,
},
{
Name: "Linksys WRT54GS WAP (Linux kernel)",
Accuracy: 94,
Line: 8292,
},
{
Name: "Linux 2.4.18 - 2.4.32 (likely embedded)",
Accuracy: 94,
Line: 8499,
},
{
Name: "Linux 2.4.21 - 2.4.33",
Accuracy: 94,
Line: 8624,
},
{
Name: "Linux 2.4.27",
Accuracy: 94,
Line: 8675,
},
{
Name: "Linux 2.4.28 - 2.4.30",
Accuracy: 94,
Line: 8693,
},
{
Name: "Linux 2.6.5 - 2.6.18",
Accuracy: 94,
Line: 11411,
},
{
Name: "Linux 2.6.8",
Accuracy: 94,
Line: 11485,
},
{
Name: "WebVOIZE 120 IP phone",
Accuracy: 94,
Line: 18921,
},
{
Name: "Linux 2.4.2 (Red Hat 7.1)",
Accuracy: 91,
Line: 8533,
},
},
Fingerprints: []OSFingerprint{
{
Fingerprint: fingerprint,
},
},
Classes: []OSClass{
{
Vendor: "MikroTik",
OSGeneration: "2.X",
Type: "software router",
Accuracy: 94,
Family: "RouterOS",
},
{
Vendor: "Linksys",
OSGeneration: "2.4.X",
Type: "WAP",
Accuracy: 94,
Family: "Linux",
},
{
Vendor: "Linux",
OSGeneration: "2.4.X",
Type: "general purpose",
Accuracy: 94,
Family: "Linux",
},
{
Vendor: "Linux",
OSGeneration: "2.6.X",
Type: "general purpose",
Accuracy: 94,
Family: "Linux",
},
{
Vendor: "WebVOIZE",
Type: "VoIP phone",
Accuracy: 94,
Family: "embedded",
},
{
Vendor: "D-Link",
OSGeneration: "2.4.X",
Type: "WAP",
Accuracy: 91,
Family: "Linux",
},
{
Vendor: "Inventel",
Type: "WAP",
Accuracy: 91,
Family: "embedded",
},
{
Vendor: "USRobotics",
Type: "broadband router",
Accuracy: 91,
Family: "embedded",
},
{
Vendor: "Linux",
OSGeneration: "2.4.X",
Type: "broadband router",
Accuracy: 91,
Family: "Linux",
},
{
Vendor: "Linux",
OSGeneration: "2.4.X",
Type: "WAP",
Accuracy: 91,
Family: "Linux",
},
{
Vendor: "Linux",
OSGeneration: "2.4.X",
Type: "media device",
Accuracy: 91,
Family: "Linux",
},
{
Vendor: "Linux",
OSGeneration: "2.4.X",
Type: "VoIP gateway",
Accuracy: 91,
Family: "Linux",
},
{
Vendor: "Netgear",
Type: "WAP",
Accuracy: 91,
Family: "embedded",
},
{
Vendor: "QLogic",
Type: "switch",
Accuracy: 91,
Family: "embedded",
},
{
Vendor: "Sharp",
OSGeneration: "2.4.X",
Type: "PDA",
Accuracy: 91,
Family: "Linux",
},
{
Vendor: "FON",
OSGeneration: "2.6.X",
Type: "WAP",
Accuracy: 91,
Family: "Linux",
},
{
Vendor: "FON",
OSGeneration: "2.4.X",
Type: "WAP",
Accuracy: 90,
Family: "Linux",
},
{
Vendor: "Belkin",
Type: "WAP",
Accuracy: 90,
Family: "embedded",
},
{
Vendor: "Asus",
Type: "WAP",
Accuracy: 90,
Family: "embedded",
},
{
Vendor: "Netgear",
OSGeneration: "2.4.X",
Type: "WAP",
Accuracy: 90,
Family: "Linux",
},
{
Vendor: "Xerox",
Type: "printer",
Accuracy: 90,
Family: "embedded",
},
{
Vendor: "Aladdin",
OSGeneration: "2.4.X",
Type: "security-misc",
Accuracy: 89,
Family: "Linux",
},
{
Vendor: "Occam",
Type: "VoIP gateway",
Accuracy: 89,
Family: "embedded",
},
{
Vendor: "Roku",
Type: "media device",
Accuracy: 89,
Family: "embedded",
},
{
Vendor: "Siemens",
Type: "WAP",
Accuracy: 89,
Family: "Linux",
},
{
Vendor: "3Com",
OSGeneration: "2.4.X",
Type: "broadband router",
Accuracy: 89,
Family: "Linux",
},
{
Vendor: "Dream Multimedia",
OSGeneration: "2.6.X",
Type: "media device",
Accuracy: 89,
Family: "Linux",
},
{
Vendor: "Iomega",
OSGeneration: "2.6.X",
Type: "storage-misc",
Accuracy: 89,
Family: "Linux",
},
},
},
Status: Status{
State: "up",
Reason: "reset",
},
TCPSequence: TCPSequence{
Index: 242,
Difficulty: "Good luck!",
Values: "457B276,4584FC8,161C122C,161B185F,1605EA95,1614C498",
},
TCPTSSequence: TCPTSSequence{
Class: "other",
Values: "3FB03AA9,3FB03C75,45B26360,45B2636A,45B26374,45B2637E",
},
Times: Times{
SRTT: "269788",
RTT: "41141",
To: "434352",
},
Trace: Trace{
Proto: "tcp",
Port: 80,
Hops: []Hop{
{
TTL: 1,
RTT: "1.83",
IPAddr: "192.168.254.254",
},
{
TTL: 2,
RTT: "18.95",
IPAddr: "200.217.89.32",
},
{
TTL: 3,
RTT: "18.33",
IPAddr: "200.217.30.250",
Host: "gigabitethernet5-1.80-cto-rn-rotd-02.telemar.net.br",
},
{
TTL: 4,
RTT: "45.05",
IPAddr: "200.97.65.250",
Host: "pos15-1-nbv-pe-rotd-03.telemar.net.br",
},
{
TTL: 5,
RTT: "43.49",
IPAddr: "200.223.131.13",
Host: "pos6-0-nbv-pe-rotn-01.telemar.net.br",
},
{
TTL: 6,
RTT: "91.27",
IPAddr: "200.223.131.205",
Host: "so-0-2-0-0-arc-rj-rotn-01.telemar.net.br",
},
{
TTL: 8,
RTT: "191.87",
IPAddr: "200.223.131.110",
Host: "PO0-3.ARC-RJ-ROTN-01.telemar.net.br",
},
{
TTL: 9,
RTT: "177.30",
IPAddr: "208.173.90.89",
Host: "bpr2-so-5-2-0.miamimit.savvis.net",
},
{
TTL: 10,
RTT: "181.50",
IPAddr: "208.172.97.169",
Host: "cr2-pos-0-3-1-0.miami.savvis.net",
},
{
TTL: 11,
RTT: "336.43",
IPAddr: "206.24.210.70",
Host: "cr1-loopback.sfo.savvis.net",
},
{
TTL: 12,
RTT: "245.32",
IPAddr: "204.70.200.229",
Host: "er1-te-1-0-1.SanJose3Equinix.savvis.net",
},
{
TTL: 13,
RTT: "238.47",
IPAddr: "204.70.200.210",
Host: "hr1-te-2-0-0.santaclarasc4.savvis.net",
},
{
TTL: 14,
RTT: "322.90",
IPAddr: "204.70.200.217",
Host: "hr1-te-2-0-0.santaclarasc9.savvis.net",
},
{
TTL: 15,
RTT: "330.96",
IPAddr: "204.70.203.146",
},
{
TTL: 16,
RTT: "342.57",
IPAddr: "66.35.194.59",
Host: "csr2-ve242.santaclarasc8.savvis.net",
},
{
TTL: 17,
RTT: "248.22",
IPAddr: "66.35.210.202",
},
{
TTL: 18,
RTT: "238.36",
IPAddr: "66.35.250.168",
Host: "freshmeat.net",
},
},
},
Uptime: Uptime{
Seconds: 206,
Lastboot: "Sun Jan 27 21:43:11 2008",
},
Addresses: []Address{
{
Addr: "66.35.250.168",
AddrType: "ipv4",
},
},
ExtraPorts: []ExtraPort{
{
State: "filtered",
Count: 1712,
Reasons: []Reason{
{
Reason: "host-prohibiteds",
Count: 1712,
},
},
},
},
Hostnames: []Hostname{
{
Name: "freshmeat.net",
Type: "PTR",
},
},
Ports: []Port{
{
ID: 80,
Protocol: "tcp",
Service: Service{
Name: "http",
ExtraInfo: "(Unix) PHP/4.4.7",
Method: "probed",
Product: "Apache httpd",
Version: "1.3.39",
Configuration: 10,
},
State: State{
State: "open",
Reason: "syn-ack",
ReasonTTL: 45,
},
Scripts: []Script{
{
ID: "robots.txt",
Output: "User-Agent: * /img/ /redir/ ",
},
{
ID: "HTML title",
Output: "freshmeat.net: Welcome to freshmeat.net",
},
},
},
{
ID: 443,
Protocol: "tcp",
Service: Service{
Name: "https",
Method: "table",
Configuration: 3,
},
State: State{
State: "closed",
Reason: "reset",
ReasonTTL: 46,
},
},
},
},
},
TaskBegin: []Task{
{
Time: Timestamp(time.Unix(1201479013, 0)),
Task: "Ping Scan",
},
{
Time: Timestamp(time.Unix(1201479014, 0)),
Task: "Parallel DNS resolution of 8 hosts.",
},
{
Time: Timestamp(time.Unix(1201479015, 0)),
Task: "System CNAME DNS resolution of 4 hosts.",
},
{
Time: Timestamp(time.Unix(1201479016, 0)),
Task: "SYN Stealth Scan",
},
{
Time: Timestamp(time.Unix(1201480879, 0)),
Task: "Service scan",
},
{
Time: Timestamp(time.Unix(1201481006, 0)),
Task: "Traceroute",
},
{
Time: Timestamp(time.Unix(1201481028, 0)),
Task: "Traceroute",
},
{
Time: Timestamp(time.Unix(1201481059, 0)),
Task: "Parallel DNS resolution of 85 hosts.",
},
{
Time: Timestamp(time.Unix(1201481070, 0)),
Task: "System CNAME DNS resolution of 8 hosts.",
},
{
Time: Timestamp(time.Unix(1201481086, 0)),
Task: "SCRIPT ENGINE",
},
},
TaskProgress: []TaskProgress{
{
Percent: 3.22,
Remaining: 903,
Task: "SYN Stealth Scan",
Etc: Timestamp(time.Unix(1201479949, 0)),
Time: Timestamp(time.Unix(1201479046, 0)),
},
{
Percent: 56.66,
Remaining: 325,
Task: "SYN Stealth Scan",
Etc: Timestamp(time.Unix(1201479767, 0)),
Time: Timestamp(time.Unix(1201479442, 0)),
},
{
Percent: 77.02,
Remaining: 225,
Task: "SYN Stealth Scan",
Etc: Timestamp(time.Unix(1201479995, 0)),
Time: Timestamp(time.Unix(1201479770, 0)),
},
{
Percent: 81.95,
Remaining: 215,
Task: "SYN Stealth Scan",
Etc: Timestamp(time.Unix(1201480212, 0)),
Time: Timestamp(time.Unix(1201479996, 0)),
},
{
Percent: 86.79,
Remaining: 182,
Task: "SYN Stealth Scan",
Etc: Timestamp(time.Unix(1201480395, 0)),
Time: Timestamp(time.Unix(1201480213, 0)),
},
{
Percent: 87.84,
Remaining: 172,
Task: "SYN Stealth Scan",
Etc: Timestamp(time.Unix(1201480433, 0)),
Time: Timestamp(time.Unix(1201480260, 0)),
},
{
Percent: 91.65,
Remaining: 129,
Task: "SYN Stealth Scan",
Etc: Timestamp(time.Unix(1201480564, 0)),
Time: Timestamp(time.Unix(1201480435, 0)),
},
{
Percent: 94.43,
Remaining: 91,
Task: "SYN Stealth Scan",
Etc: Timestamp(time.Unix(1201480656, 0)),
Time: Timestamp(time.Unix(1201480565, 0)),
},
{
Percent: 96.35,
Remaining: 62,
Task: "SYN Stealth Scan",
Etc: Timestamp(time.Unix(1201480720, 0)),
Time: Timestamp(time.Unix(1201480658, 0)),
},
{
Percent: 97.76,
Remaining: 39,
Task: "SYN Stealth Scan",
Etc: Timestamp(time.Unix(1201480760, 0)),
Time: Timestamp(time.Unix(1201480721, 0)),
},
},
TaskEnd: []Task{
{
Time: Timestamp(time.Unix(1201479014, 0)),
Task: "Ping Scan",
ExtraInfo: "8 total hosts",
},
{
Time: Timestamp(time.Unix(1201479015, 0)),
Task: "Parallel DNS resolution of 8 hosts.",
},
{
Time: Timestamp(time.Unix(1201479016, 0)),
Task: "System CNAME DNS resolution of 4 hosts.",
},
{
Time: Timestamp(time.Unix(1201480878, 0)),
Task: "SYN Stealth Scan",
ExtraInfo: "8570 total ports",
},
{
Time: Timestamp(time.Unix(1201480984, 0)),
Task: "Service scan",
ExtraInfo: "20 services on 5 hosts",
},
{
Time: Timestamp(time.Unix(1201481028, 0)),
Task: "Traceroute",
},
{
Time: Timestamp(time.Unix(1201481059, 0)),
Task: "Traceroute",
},
{
Time: Timestamp(time.Unix(1201481070, 0)),
Task: "Parallel DNS resolution of 85 hosts.",
},
{
Time: Timestamp(time.Unix(1201481086, 0)),
Task: "System CNAME DNS resolution of 8 hosts.",
},
{
Time: Timestamp(time.Unix(1201481197, 0)),
Task: "SCRIPT ENGINE",
},
},
},
expectedError: nil,
},
}
for _, test := range tests {
t.Run(test.inputFile, func(t *testing.T) {
rawXML, err := ioutil.ReadFile(test.inputFile)
if err != nil {
t.Fatal(err)
}
result, err := Parse(rawXML)
// Remove rawXML before comparing
result.rawXML = []byte{}
compareResults(t, test.expectedResult, result)
if err != test.expectedError {
t.Errorf("expected %v got %v", test.expectedError, err)
}
})
}
}
func compareResults(t *testing.T, expected, got *Run) {
if got.Args != expected.Args {
t.Errorf("unexpected arguments, expected %v got %v", expected.Args, got.Args)
}
if got.ProfileName != expected.ProfileName {
t.Errorf("unexpected arguments, expected %v got %v", expected.ProfileName, got.ProfileName)
}
if got.Scanner != expected.Scanner {
t.Errorf("unexpected arguments, expected %v got %v", expected.Scanner, got.Scanner)
}
if got.StartStr != expected.StartStr {
t.Errorf("unexpected arguments, expected %v got %v", expected.StartStr, got.StartStr)
}
if !reflect.DeepEqual(got.Debugging, expected.Debugging) {
t.Errorf("unexpected debugging, expected %+v got %+v", expected.Debugging, got.Debugging)
}
if !reflect.DeepEqual(got.ScanInfo, expected.ScanInfo) {
t.Errorf("unexpected scan info, expected %+v got %+v", expected.ScanInfo, got.ScanInfo)
}
if !reflect.DeepEqual(got.Start, expected.Start) {
t.Errorf("unexpected start time, expected %+v got %+v", expected.Start, got.Start)
}
if !reflect.DeepEqual(got.Targets, expected.Targets) {
t.Errorf("unexpected targets, expected %+v got %+v", expected.Targets, got.Targets)
}
if len(expected.TaskBegin) != len(got.TaskBegin) {
t.Errorf("unexpected tasks begin entries, expected to have %d entries, got %d instead", len(expected.TaskBegin), len(got.TaskBegin))
} else {
for idx := range expected.TaskBegin {
if !reflect.DeepEqual(got.TaskBegin[idx], expected.TaskBegin[idx]) {
t.Errorf("unexpected task begin entry, expected %+v got %+v", expected.TaskBegin[idx], got.TaskBegin[idx])
}
}
}
if len(expected.TaskProgress) != len(got.TaskProgress) {
t.Errorf("unexpected tasks progress entries, expected to have %d entries, got %d instead", len(expected.TaskProgress), len(got.TaskProgress))
} else {
for idx := range expected.TaskProgress {
if !reflect.DeepEqual(got.TaskProgress[idx], expected.TaskProgress[idx]) {
t.Errorf("unexpected task progress entry, expected %+v got %+v", expected.TaskProgress[idx], got.TaskProgress[idx])
}
}
}
if len(expected.TaskEnd) != len(got.TaskEnd) {
t.Errorf("unexpected tasks end entries, expected to have %d entries, got %d instead", len(expected.TaskEnd), len(got.TaskEnd))
} else {
for idx := range expected.TaskEnd {
if !reflect.DeepEqual(got.TaskEnd[idx], expected.TaskEnd[idx]) {
t.Errorf("unexpected task end entry, expected %+v got %+v", expected.TaskEnd[idx], got.TaskEnd[idx])
}
}
}
if len(expected.Hosts) != len(got.Hosts) {
t.Errorf("unexpected number of hosts, expected to have %d hosts, got %d instead", len(expected.Hosts), len(got.Hosts))
} else {
for idx := range expected.Hosts {
if expected.Hosts[idx].Comment != got.Hosts[idx].Comment {
t.Errorf("unexpected host comment, expected %v got %v", expected.Hosts[idx].Comment, got.Hosts[idx].Comment)
}
if !reflect.DeepEqual(expected.Hosts[idx].Addresses, got.Hosts[idx].Addresses) {
t.Errorf("unexpected host addresses, expected %+v got %+v", expected.Hosts[idx].Addresses, got.Hosts[idx].Addresses)
}
if !reflect.DeepEqual(expected.Hosts[idx].Distance, got.Hosts[idx].Distance) {
t.Errorf("unexpected host distance, expected %+v got %+v", expected.Hosts[idx].Distance, got.Hosts[idx].Distance)
}
if !reflect.DeepEqual(expected.Hosts[idx].ExtraPorts, got.Hosts[idx].ExtraPorts) {
t.Errorf("unexpected host extra ports, expected %+v got %+v", expected.Hosts[idx].ExtraPorts, got.Hosts[idx].ExtraPorts)
}
if !reflect.DeepEqual(expected.Hosts[idx].HostScripts, got.Hosts[idx].HostScripts) {
t.Errorf("unexpected host host scripts, expected %+v got %+v", expected.Hosts[idx].HostScripts, got.Hosts[idx].HostScripts)
}
if !reflect.DeepEqual(expected.Hosts[idx].Hostnames, got.Hosts[idx].Hostnames) {
t.Errorf("unexpected host host names, expected %+v got %+v", expected.Hosts[idx].Hostnames, got.Hosts[idx].Hostnames)
}
if !reflect.DeepEqual(expected.Hosts[idx].IPIDSequence, got.Hosts[idx].IPIDSequence) {
t.Errorf("unexpected host IPIDSequence, expected %+v got %+v", expected.Hosts[idx].IPIDSequence, got.Hosts[idx].IPIDSequence)
}
if !reflect.DeepEqual(expected.Hosts[idx].OS, got.Hosts[idx].OS) {
t.Errorf("unexpected host OS, expected %+v got %+v", expected.Hosts[idx].OS, got.Hosts[idx].OS)
}
if !reflect.DeepEqual(expected.Hosts[idx].Ports, got.Hosts[idx].Ports) {
t.Errorf("unexpected host ports, expected %+v got %+v", expected.Hosts[idx].Ports, got.Hosts[idx].Ports)
}
if !reflect.DeepEqual(expected.Hosts[idx].Smurfs, got.Hosts[idx].Smurfs) {
t.Errorf("unexpected host smurfs, expected %+v got %+v", expected.Hosts[idx].Smurfs, got.Hosts[idx].Smurfs)
}
if !reflect.DeepEqual(expected.Hosts[idx].StartTime, got.Hosts[idx].StartTime) {
t.Errorf("unexpected host start time, expected %+v got %+v", expected.Hosts[idx].StartTime, got.Hosts[idx].StartTime)
}
if !reflect.DeepEqual(expected.Hosts[idx].Status, got.Hosts[idx].Status) {
t.Errorf("unexpected host status, expected %+v got %+v", expected.Hosts[idx].Status, got.Hosts[idx].Status)
}
if !reflect.DeepEqual(expected.Hosts[idx].TCPSequence, got.Hosts[idx].TCPSequence) {
t.Errorf("unexpected host TCPSequence, expected %+v got %+v", expected.Hosts[idx].TCPSequence, got.Hosts[idx].TCPSequence)
}
if !reflect.DeepEqual(expected.Hosts[idx].TCPTSSequence, got.Hosts[idx].TCPTSSequence) {
t.Errorf("unexpected host TCPTSSequence, expected %+v got %+v", expected.Hosts[idx].TCPTSSequence, got.Hosts[idx].TCPTSSequence)
}
if !reflect.DeepEqual(expected.Hosts[idx].Times, got.Hosts[idx].Times) {
t.Errorf("unexpected host times, expected %+v got %+v", expected.Hosts[idx].Times, got.Hosts[idx].Times)
}
if !reflect.DeepEqual(expected.Hosts[idx].Trace, got.Hosts[idx].Trace) {
t.Errorf("unexpected host trace, expected %+v got %+v", expected.Hosts[idx].Trace, got.Hosts[idx].Trace)
}
if !reflect.DeepEqual(expected.Hosts[idx].Uptime, got.Hosts[idx].Uptime) {
t.Errorf("unexpected host uptime, expected %+v got %+v", expected.Hosts[idx].Uptime, got.Hosts[idx].Uptime)
}
}
}
}
const fingerprint = "SCAN(V=4.53%D=1/27%OT=80%CT=443%CU=%PV=N%G=N%TM=479D25ED%P=i686-pc-linux-gnu)\nSEQ(SP=F2%GCD=1%ISR=E9%TI=Z%TS=1C)\nOPS(O1=M5B4ST11NW0%O2=M5B4ST11NW0%O3=M5B4NNT11NW0%O4=M5B4ST11NW0%O5=M5B4ST11NW0%O6=M5B4ST11)\nWIN(W1=16A0%W2=16A0%W3=16A0%W4=16A0%W5=16A0%W6=16A0)\nECN(R=Y%DF=Y%TG=40%W=16D0%O=M5B4NNSNW0%CC=N%Q=)\nT1(R=Y%DF=Y%TG=40%S=O%A=S+%F=AS%RD=0%Q=)\nT2(R=N)\nT3(R=Y%DF=Y%TG=40%W=16A0%S=O%A=S+%F=AS%O=M5B4ST11NW0%RD=0%Q=)\nT4(R=Y%DF=Y%TG=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)\nT5(R=Y%DF=Y%TG=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)\nT6(R=Y%DF=Y%TG=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)\nT7(R=Y%DF=Y%TG=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)\nU1(R=N)\nIE(R=N)\n"