ullaakut / nmap Goto Github PK
View Code? Open in Web Editor NEWIdiomatic nmap library for go developers
License: MIT License
Idiomatic nmap library for go developers
License: MIT License
It would be a minor breaking change, but would it be worth adding something like the below type?
type Option func(*Scanner)
The use case I'm seeing is two-fold:
type CallOption
on grpc's Index)For the latter case, I'm currently doing something like so:
type X struct {
baseOptions []func(*nmap.Scanner)
}
func newX() X {
return X{
baseOptions: []func(*nmap.Scanner){
nmap.With1(),
nmap.With2(),
nmap.With3(),
},
}
}
func doTheThing(host string) {
s, _ := nmap.NewScanner(ne.baseOptions...)
scanner.AddOptions(nmap.WithTargets(host))
if isIP6(host) {
scanner.AddOptions(nmap.WithIPv6Scanning())
}
The key improvement to the above code would be mainly in clarity, as the type a user is writing out is a bit less abstract, and it doesn't require a later reader to go cross-reference the docs to verify its accuracy.
Thanks for the time and consideration.
package main
import (
"fmt"
"log"
"github.com/Ullaakut/nmap/v2"
)
func main() {
scanner, err := nmap.NewScanner(
nmap.WithTargets("127.0.0.1"),
nmap.WithPorts("1", "3389", "3390", "9040", "9050"),
nmap.WithServiceInfo(),
nmap.WithTimingTemplate(nmap.TimingAggressive),
nmap.WithFilterHost(func(h nmap.Host) bool {
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)
}
result, _, err := scanner.Run()
if err != nil {
log.Fatalf("nmap scan failed: %v", err)
}
for _, host := range result.Hosts {
fmt.Printf("Host %s\n", host.Addresses[0])
for _, port := range host.Ports {
fmt.Printf("\tPort %d open, service %s\n", port.ID, port.Service.Name)
}
}
}
Result
Host 127.0.0.1
Port 1 open, service tcpmux
Port 3389 open, service ms-wbt-server
Port 3390 open, service dsc
Port 9040 open, service tcpwrapped
Port 9050 open, service tor-socks
And nmap
scan
nmap -A -sV -sC -Pn -T4 -p1,3389,3390,9040,9050 127.0.0.1
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2020-11-16 16:53 MSK
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00012s latency).
PORT STATE SERVICE VERSION
1/tcp closed tcpmux
3389/tcp closed ms-wbt-server
3390/tcp closed dsc
9040/tcp open tcpwrapped
9050/tcp open tor-socks Tor SOCKS proxy
| socks-auth-info:
| No authentication
|_ Username and password
| socks-open-proxy:
| status: open
| versions:
|_ socks4
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 17.96 seconds
There does not appear to be a way to also create standard nmap output files while using this library. Is that something that could be considered for a feature or was it conscious omission?
Hello.
nmap.WithDefaultScript()
I can get all methods from port.* etc but cant see to get the output of the Script.
example:
for _, host := range result.Hosts {
fmt.Printf("Host %s\n", host.Addresses[0])
for _, port := range host.Ports {
fmt.Printf("\tPort %d/%s %s %s %s %s %s\n", port.ID, port.Protocol, port.State, port.Service.Name, port.Service.Product, port.Service.Version, port.Service.ExtraInfo)
for _, script := range port.Scripts {
fmt.Printf("%s", script.Output)
}
}
}
trying to get the script.Output from the scripts slice.
Im sure im doing something wrong.
I'm submitting a ...
What is the current behavior?
The library does not provide support for adding in verbosity and debugging levels.
What is the expected behavior?
Allow WithVerbosity
and WithDebugging
options to be called to increase Nmap verbosity and debugging.
Level 10 Verbosity -vvvvv -ddddd
Level 8 Verbosity -vvvvv -ddd
Level 5 Verbosity -vvvvv
Level 5 Debugging -ddddd
AsyncRun
usage.Hi, in /examples/basic_scan_progress/main.go, the scanner.RunWithProgress can not be found in the project.
Currently https://pkg.go.dev/github.com/Ullaakut/nmap?tab=versions shows the package as v2.0.0+incompatible
with the version from Nov 30, 2019. Please make a new semver release - it should help to fix this error:
$ go get -v github.com/Ullaakut/nmap/v2
go get github.com/Ullaakut/nmap/v2: module github.com/Ullaakut/nmap@upgrade found (v1.0.1-0.20200929125141-8d64c8e1eb96), but does not contain package github.com/Ullaakut/nmap/v2
Thanks.
Add .idea to the gitignore
Hi,
I'm sorry for asking this!
But while we resolved that issue #65 we got a new problem with go module versions.
go clean -modcache
go get github.com/Ullaakut/nmap/v2
=> The official Go Proxy does not recognize the changes.
=> You can try this by calling the function RunWithProgress
in version v2.0.2.
So I'm asking you to set a new Tag (v2.0.3) so hopefully the changes will be cached by Go.
Hi, I recently had many issues with go complaining about checksum mismatches when trying to "go get" this module with version v2 or greater.
I think I found the issue:
Go got the checksum mismatch because v2.0.0 does not contain a go.mod file and then got "incompatible"
https://stackoverflow.com/questions/57355929/what-does-incompatible-in-go-mod-mean-will-it-cause-harm
So I ask you to set the tag v2.0.0 to a commit where the go.mod is correct.
You may set tag v2.0.0 to the same commit as v2.0.1.
I would like to be able to pass a raw IP to be scanned, rather than a fqdn. Passing a raw IP currently returns:
Host "10.10.10.191":
Port 21/tcp closed ftp
Port 80/tcp open http
Nmap done: 1 hosts up scanned in 104.269997 seconds
2020/11/18 17:59:20 Warnings:
[Failed to resolve "". WARNING: No targets were specified, so 0 hosts scanned.]
Nmap done: 0 hosts up scanned in 0.030000 seconds
Hi, would it be possible to use the output of the nmap scripts vuln
using this library?
I don't see it appearing in the XML output.
Hi there!
First of all: awesome library, thank you very much!
It appears to me that parsing Nmap output does not read the osclass data correctly. I've seen there is a solved issue regarding the same thing ( ##7). However I still have the problem, even though I'm running on your latest version.
"osmatch" data is read correctly. "osclass" data is always empty. Looking at the original Nmap XML data, "osclass" is a child of each "osmatch". In your xml.go specification, they are on the same level.
Moving
Classes []OSClass 'xml:"osclass" json:"os_classes"'
from the "OS" struct to the "OSMatch" struct would solve the issue... if that was an acceptable solution to you
best regards!
I'm submitting a ...
What is the current behavior?
AsyncRun returns bufio reader, allowing users to manipulate the data to have it perform in several different manners. However some users might only want to use AsyncRun for being able to stream progress. It would be nice to have a Progress
function that would allow streaming progress without having a bunch of code to accompany it.
What is the expected behavior?
Call range Progress(content) {}
and have progress updates printed to screen
What is the motivation / use case for changing the behavior?
Allow an easier to use Progress implementation allowing straight forward implementation of parsing Nmap xml bytes from the stream and getting progress status.
nmap.WithServiceInfo(), not returning service version details.
Add WithFilterHost
, WithFilterPort
, WithFilterService
etc. methods to be used like so:
scanner, err := nmap.New(
nmap.WithTarget("172.17.100.0/24"),
// Filter out hosts that do not have any open port
nmap.WithFilterHost(func(h nmap.Host) bool {
for _, port := range h.Ports {
if port.Status() == nmap.Open {
return true
}
}
return false
})
)
if err != nil {
log.Fatalf("unable to create nmap scanner: %v", err)
}
result, err := scanner.Run()
if err != nil {
log.Fatalf("nmap scan failed: %v", err)
}
It is currently difficult to check whether an Nmap scan failed, due to two reasons:
Examples generated by Run():
Examples returned via stderr:
Example found in result.Stats.Finished.ErrorMsg:
I'm suggesting to change the signature of the Run() method to:
func (s *Scanner) Run() (*Run, []strings, []error) { }
This is a breaking change on purpose. It will prevent people from compiling their old code with the updated package. We do not want to affect their application behaviour without them noticing. Ideally, they should reconsider their error handling too.
With this suggestion we can return an intuitive set of result data: result, list of warnings and list of errors.
=> Result may exist as soon as the XML could be parsed (even if there are errors returned in parallel)
=> Warnings may be there and can be used if desired.
=> The list of errors can aggregate the error messages from our run method, stderr and a copy of those from the xml output.
I'ts tricky, but mybe we want to introdcue (more) error constants (in errors.go) for whatever we run across. So that other developers directly are aware of them and can handle them as they need.
I'm creating a custom build script for Pentoo using standard Gentoo ebuild and golang-vcs-snapshot eclass.
Currently, Cameradar fails to build due to the following error:
WORK=/var/tmp/portage/net-analyzer/cameradar-5.0.1-r1/temp/go-build4077822569
src/github.com/ullaakut/cameradar/vendor/github.com/Ullaakut/nmap/xml.go:11:2: cannot find package "github.com/Ullaakut/nmap/v2/pkg/osfamilies" in any of:
/var/tmp/portage/net-analyzer/cameradar-5.0.1-r1/work/cameradar-5.0.1/src/github.com/ullaakut/cameradar/vendor/github.com/Ullaakut/nmap/v2/pkg/osfamilies (vendor tree)
/usr/lib/go/src/github.com/Ullaakut/nmap/v2/pkg/osfamilies (from $GOROOT)
/var/tmp/portage/net-analyzer/cameradar-5.0.1-r1/work/cameradar-5.0.1/src/github.com/Ullaakut/nmap/v2/pkg/osfamilies (from $GOPATH)
/usr/lib/go-gentoo/src/github.com/Ullaakut/nmap/v2/pkg/osfamilies
src/github.com/ullaakut/cameradar/cmd/cameradar/cameradar.go:10:2: cannot find package "github.com/Ullaakut/cameradar/v5" in any of:
/var/tmp/portage/net-analyzer/cameradar-5.0.1-r1/work/cameradar-5.0.1/src/github.com/ullaakut/cameradar/vendor/github.com/Ullaakut/cameradar/v5 (vendor tree)
/usr/lib/go/src/github.com/Ullaakut/cameradar/v5 (from $GOROOT)
/var/tmp/portage/net-analyzer/cameradar-5.0.1-r1/work/cameradar-5.0.1/src/github.com/Ullaakut/cameradar/v5 (from $GOPATH)
/usr/lib/go-gentoo/src/github.com/Ullaakut/cameradar/v5
* ERROR: net-analyzer/cameradar-5.0.1-r1::pentoo failed (compile phase):
There are few references which seems broken:
https://github.com/Ullaakut/nmap/blob/master/xml.go#L11
https://github.com/Ullaakut/nmap/blob/master/go.mod#L1
can you create both directories (v2/pkg/osfamilies) or remove v2 and v5 completely?
This might be more complicated than it sounds, as I'm not sure where to get a complete list of the OS families supported by nmap
, but once it's done it would make it possible to replace this code:
if strings.Contains(strings.ToLower(class.Family), "linux") {
linux++
} else if strings.Contains(strings.ToLower(class.Family), "windows") {
windows++
} else if strings.Contains(strings.ToLower(class.Family), "macos") {
macOS++
}
with a cleaner (and more idiomatic) switch
statement like such:
switch class.Family {
case nmap.OSFamilyLinux:
linux++
case nmap.OSFamilyWindows:
windows++
case nmap.OSFamilyMacOS:
macOS++
}
Allowing the users to run nmap
asnchronously makes it possible to parse the live nmap
output, for example for building a UI on top, or computing a progress bar.
I'm not sure if many people have this use-case though, so I won't prioritize this for now, but I find it really cool.
func (s *Scanner) RunAsync() (stdout chan <-[]byte, stderr chan <-[]byte, error)
nmap
process could not be started.nmap.Result
structure once the scan is doneHi,
I further improved our error handling by
Previously, our first check was whether we can parse the Nmap XML output. That XML is inevitably broken if Nmap terminated with an error. We always returned 'ErrParseOutput' and the details of the error could be revealed by looking at the warnings.
In the picutre above, you can see how the returned error is 'ErrParseOutput', although, the primary issue was 'malloc failed'.
Now, we can check for common/known errors before trying to parse the output XML and return with more accurate errors.
Best regards!
fullfil
-> fulfill
diables
-> disables
repsonses
-> responses
Etc.
Would you consider adding a go.mod
file (can be created with: go mod init github.com/Ullaakut/nmap
and after merging, creating a release (even if v0.x.x-numbered like v0.5.0 or similar)? It would make it easier to use as dependency. Thanks.
If we try to scan for example a /24, the nmap package will tell that every host is up, even if they not.
If this can help, I think it's because you fallback on a "up" status if you can't find any "status" tag in the XML, because nmap doesn't put any info about the host in the XML if it is down.
Hey there,
I stumbled upon a probable memory leak in the Run
function. If the Command is killed, because the timeout is reached, the goroutine waiting for cmd.Wait() to return will never finish.
This is because the done channel is not buffered and the error is never retrieved in the select statement.
Here's an example I put together. I also found this related stackoverflow post (see comments).
I did not create a PR, because the solution is pretty straight forward - Simply make a buffered channel.
// Make a goroutine to notify the select when the scan is done.
done := make(chan error, 1)
go func() {
done <- cmd.Wait()
}()
Have a nice day
Hi, is there a way of using the library to detect whether a host responds to ICMP?
At the moment I have something along the lines of:
switch mode {
case "tcp":
typeScanner = []func(*nmap.Scanner){
nmap.WithServiceInfo(),
nmap.WithSYNScan(),
nmap.WithOSDetection(),
nmap.WithOSScanGuess(),
nmap.WithOSScanLimit(),
}
break
case "udp":
typeScanner = []func(*nmap.Scanner){
nmap.WithServiceInfo(),
nmap.WithUDPScan(),
}
break
case "icmp":
typeScanner = []func(*nmap.Scanner){
nmap.WithServiceInfo(),
nmap.WithICMPEchoDiscovery(),
nmap.WithOSDetection(),
nmap.WithOSScanGuess(),
}
break
default:
return errors.New("unknown scan mode: " + mode)
}
...
nmap.WithContext(ctx),
nmap.WithTargets(ip.String()),
nmap.WithDisabledDNSResolution(),
nmap.WithPrivileged(),
nmap.WithTimingTemplate(nmap.TimingAggressive),
But not sure if ServiceInfo and OSDetection do anything at the ICMP scanning phase.
Hi all,
I'm a contributor to ToRat and I'm in the process of using this module to add service and port detection features to the ToRat client. So far I have been unable to get this module to work when compiling to Windows.
Does this package support Windows?
Review current Bufio
Async implementation vs Async channel implementation.
The below is fully working AsyncRun with Channels
// RunAsync runs nmap asynchronously and returns error.
func (s *Scanner) RunAsync() (<-chan []byte, <-chan []byte, error) {
stdoutChannel := make(chan []byte)
stderrChannel := make(chan []byte)
// Enable XML output.
s.args = append(s.args, "-oX")
// Get XML output in stdout instead of writing it in a file.
s.args = append(s.args, "-")
s.cmd = exec.Command(s.binaryPath, s.args...)
// Get CMD Stderr Pipe
stderr, err := s.cmd.StderrPipe()
if err != nil {
return nil, nil, fmt.Errorf("unable to get error output from asynchronous nmap run: %v", err)
}
// Get CMD Stdout Pipe
stdout, err := s.cmd.StdoutPipe()
if err != nil {
return nil, nil, fmt.Errorf("unable to get standard output from asynchronous nmap run: %v", err)
}
if err := s.cmd.Start(); err != nil {
return nil, nil, fmt.Errorf("unable to execute asynchronous nmap run: %v", err)
}
// Stream stdout to the stdoutChannel
go func() {
defer close(stdoutChannel)
for {
buf := make([]byte, 1024)
n, err := stdout.Read(buf)
if err != nil {
if err != io.EOF {
log.Fatal(err)
}
if n == 0 {
break
}
}
stdoutChannel <- buf[:n]
}
}()
// Stream stderr to the stderrChannel
go func() {
defer close(stderrChannel)
for {
buf := make([]byte, 2048)
n, err := stderr.Read(buf)
if err != nil {
if err != io.EOF {
log.Fatal(err)
}
if n == 0 {
break
}
}
stderrChannel <- buf[:n]
}
}()
go func() {
<-s.ctx.Done()
_ = s.cmd.Process.Kill()
}()
return stdoutChannel, stderrChannel, nil
}
How can I use this library to scan for all the live hosts on the network 182.168.0.0/24 ?
Hi,
Thanks for this lib!
Could you please add a func that return all the nmap options/params passed to the scanner?
Regards,
Hi@
when a scan finishes before timeout you firstly check if something went to stderr.
Lets assume the following:
nmap -p 80,443 asdasasdasdasasdaasdassad.com google.de
First host goes to stderr with message Failed to resolve "asdasasdasdasasdaasdassad.com".
and the second one finishes just fine.
The early error exit (currently https://github.com/Ullaakut/nmap/blob/master/nmap.go#L87)
from your done channel prevents access to any other successful results if just one fails :/
I'm seeing a few issues with the count_hosts_by_os
example in this repository.
I get this error when I run the program without sudo
. Does this example require to be ran with sudo or root?
$ ./count_hosts_by_os
2021/05/23 07:03:44 nmap scan failed: unable to parse nmap output, see warnings for details
When I run the example, the number of Linux hosts is more than the number of hosts seen on the network.
$ sudo ./count_hosts_by_os
Discovered 25 linux hosts and 0 windows hosts out of 18 total up hosts.
The range of the port number is 0-65535. Why do you use int16 instead of uint16?
Line 1317 in 4e11e55
95% coverage reached.
Left to test:
nmap
is not installed. Can be done by manipulating the $PATH
during this test case.os.Exec
, and I'm not going to do that. Might just remove the error check for the cmd.Process.Kill()
call since I think it's useless anyway.ToFile
method.e.EncodeToken()
fails and e.Flush()
fails, but I have no clue how to test them. The first one would require creating invalid tokens, which this function never would, and the second would require having a closed encoder, which would probably make it fail upstream.I think you interpreted the "conf" nmap parameter as "Configuration" while it means "Confidence".
The attribute : https://pkg.go.dev/github.com/Ullaakut/nmap/v2#Service.Configuration
Nmap documentation : https://nmap.org/book/output-formats-xml-output.html#output-formats-xml-port-elements
I'll provide a PR !
My work in progress on the unit tests led me to discover a few issues with the current XML parsing:
nmap.Run.Host.EndTime
and nmap.Run.Host.StartTime
values are parsed as -62135596800
nmap.Run.Host.OS.OSClass
entries are missingI use nmap library to continuosly scan network so I call Run() method repeatedly for single nmap.Scanner structure.
After several invocations Run() starts returning "nmap scan timed out" error.
Using strace utility I found following command line for nmap:
execve("/usr/bin/nmap", ["/usr/bin/nmap", "192.168.xx.xxx/29", "xxx.xxx.xxx.xx", "-p", "443", "-T4", "--script=xxxxxxxxxxx", "-oX", "-", "-oX", "-", "-oX", "-", "-oX", "-", "-oX", "-", "-oX", "-", "-oX", "-", "-oX", "-", "-oX", "-", "-oX", "-", "-oX", "-", "-oX", "-", "-oX", ...], 0xc0003ce040 /* 6 vars */ <unfinished ...>
I think that's extra command line arguments are causing this timeout. Looking at https://github.com/Ullaakut/nmap/blob/master/nmap.go#L87 I see that every Run() invocations adds to args slice that causes timeout error after some time.
n/a
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.