From c08b25382d8cd33c1feef46b37245284c70e76f5 Mon Sep 17 00:00:00 2001 From: Emilio <10257120+ekiojp@users.noreply.github.com> Date: Fri, 5 Jun 2020 23:39:11 +0900 Subject: [PATCH] [FEATURE] add option for output json file, --json --- main.go | 265 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 143 insertions(+), 122 deletions(-) diff --git a/main.go b/main.go index 88420aa..0c59422 100644 --- a/main.go +++ b/main.go @@ -1,91 +1,93 @@ package main import ( - "encoding/json" - "flag" - "fmt" - "golang.org/x/time/rate" - "os" - "runtime" - "sync" - "time" + "encoding/json" + "flag" + "fmt" + "golang.org/x/time/rate" + "os" + "runtime" + "sync" + "time" ) type ScanResult struct { - Host string `json:"host"` - Port string `json:"port,omitempty"` - Proto string `json:"proto,omitempty"` - Probe string `json:"probe,omitempty"` - Name string `json:"name,omitempty"` - Nets []string `json:"nets,omitempty"` - Info map[string]string `json:"info"` + Host string `json:"host"` + Port string `json:"port,omitempty"` + Proto string `json:"proto,omitempty"` + Probe string `json:"probe,omitempty"` + Name string `json:"name,omitempty"` + Nets []string `json:"nets,omitempty"` + Info map[string]string `json:"info"` } +type ScanResults []ScanResult + type Prober interface { - Setup() - Initialize() - Wait() - AddTarget(string) - CloseInput() - SetOutput(chan<- ScanResult) - CheckRateLimit() - SetLimiter(*rate.Limiter) + Setup() + Initialize() + Wait() + AddTarget(string) + CloseInput() + SetOutput(chan<- ScanResult) + CheckRateLimit() + SetLimiter(*rate.Limiter) } type Probe struct { - name string - options map[string]string - waiter sync.WaitGroup - input chan string - output chan<- ScanResult - limiter *rate.Limiter + name string + options map[string]string + waiter sync.WaitGroup + input chan string + output chan<- ScanResult + limiter *rate.Limiter } func (this *Probe) String() string { - return fmt.Sprintf("%s", this.name) + return fmt.Sprintf("%s", this.name) } func (this *Probe) Wait() { - this.waiter.Wait() - return + this.waiter.Wait() + return } func (this *Probe) Setup() { - this.name = "generic" - this.input = make(chan string) - return + this.name = "generic" + this.input = make(chan string) + return } func (this *Probe) Initialize() { - this.Setup() - this.name = "generic" - return + this.Setup() + this.name = "generic" + return } func (this *Probe) SetOutput(c_out chan<- ScanResult) { - this.output = c_out - return + this.output = c_out + return } func (this *Probe) AddTarget(t string) { - this.input <- t - return + this.input <- t + return } func (this *Probe) CloseInput() { - close(this.input) - return + close(this.input) + return } func (this *Probe) SetLimiter(limiter *rate.Limiter) { - this.limiter = limiter - return + this.limiter = limiter + return } func (this *Probe) CheckRateLimit() { - for this.limiter.Allow() == false { - time.Sleep(10 * time.Millisecond) - } + for this.limiter.Allow() == false { + time.Sleep(10 * time.Millisecond) + } } var limiter *rate.Limiter @@ -95,106 +97,125 @@ var wi sync.WaitGroup var wo sync.WaitGroup func usage() { - fmt.Println("Usage: " + os.Args[0] + " [cidr] ... [cidr]") - fmt.Println("") - fmt.Println("Probes a list of networks for potential pivot points.") - fmt.Println("") - fmt.Println("Options:") - flag.PrintDefaults() -} - -func outputWriter(o <-chan ScanResult) { - - for found := range o { - j, err := json.Marshal(found) - if err != nil { - fmt.Fprintf(os.Stderr, "Error marshaling result: '%v' : %s\n", found, err) - continue - } - os.Stdout.Write(j) - os.Stdout.Write([]byte("\n")) - } - wo.Done() + fmt.Println("Usage: " + os.Args[0] + " [cidr] ... [cidr]") + fmt.Println("") + fmt.Println("Probes a list of networks for potential pivot points.") + fmt.Println("") + fmt.Println("Options:") + flag.PrintDefaults() +} + +func outputWriter(o <-chan ScanResult, f *os.File) { + var total ScanResults + for found := range o { + jout, err := json.Marshal(found) + if err != nil { + fmt.Fprintf(os.Stderr, "Error marshaling result: '%v' : %s\n", found, err) + } + os.Stdout.Write(jout) + os.Stdout.Write([]byte("\n")) + total = append(total, found) + } + j, err := json.Marshal(total) + if err != nil { + fmt.Fprintf(os.Stderr, "Error marshaling result: '%v' : %s\n", total, err) + } + f.Write(j) + f.Write([]byte("\n")) + f.Close() + wo.Done() } func initializeProbes(c_out chan<- ScanResult) { - for _, probe := range probes { - probe.Initialize() - probe.SetOutput(c_out) - probe.SetLimiter(limiter) - } + for _, probe := range probes { + probe.Initialize() + probe.SetOutput(c_out) + probe.SetLimiter(limiter) + } } func waitProbes() { - for _, probe := range probes { - probe.Wait() - } + for _, probe := range probes { + probe.Wait() + } } func processAddress(i <-chan string, o chan<- ScanResult) { - for addr := range i { - for _, probe := range probes { - probe.AddTarget(addr) - } - } + for addr := range i { + for _, probe := range probes { + probe.AddTarget(addr) + } + } - for _, probe := range probes { - probe.CloseInput() - } - wi.Done() + for _, probe := range probes { + probe.CloseInput() + } + wi.Done() } func main() { - runtime.GOMAXPROCS(runtime.NumCPU()) + runtime.GOMAXPROCS(runtime.NumCPU()) + + flag.Usage = func() { usage() } + var jsonfile string + version := flag.Bool("version", false, "Show the application version") + ppsrate = flag.Int("rate", 1000, "Set the maximum packets per second rate") + flag.StringVar(&jsonfile, "json", "", "output json `file`") - flag.Usage = func() { usage() } - version := flag.Bool("version", false, "Show the application version") - ppsrate = flag.Int("rate", 1000, "Set the maximum packets per second rate") + flag.Parse() - flag.Parse() + if *version { + PrintVersion("nextnet") + os.Exit(0) + } - if *version { - PrintVersion("nextnet") - os.Exit(0) - } + limiter = rate.NewLimiter(rate.Limit(*ppsrate), *ppsrate*3) - limiter = rate.NewLimiter(rate.Limit(*ppsrate), *ppsrate*3) + // Input addresses + c_addr := make(chan string) - // Input addresses - c_addr := make(chan string) + // Output structs + c_out := make(chan ScanResult) - // Output structs - c_out := make(chan ScanResult) + // Configure the probes + initializeProbes(c_out) - // Configure the probes - initializeProbes(c_out) + // Launch a single input address processor + wi.Add(1) + go processAddress(c_addr, c_out) - // Launch a single input address processor - wi.Add(1) - go processAddress(c_addr, c_out) + // Launch a single output writer + wo.Add(1) + if jsonfile != "" { + fd,err := os.Create(jsonfile) + if err != nil { + fmt.Fprintf(os.Stderr, "Error creating output file: %s\n", err) + os.Exit(1) + } + go outputWriter(c_out, fd) + } else { + go outputWriter(c_out, nil) + } - // Launch a single output writer - wo.Add(1) - go outputWriter(c_out) - // Parse CIDRs and feed IPs to the input channel - for _, cidr := range flag.Args() { - AddressesFromCIDR(cidr, c_addr) - } + // Parse CIDRs and feed IPs to the input channel + for _, cidr := range flag.Args() { + AddressesFromCIDR(cidr, c_addr) + } - // Close the cidr input channel - close(c_addr) + // Close the cidr input channel + close(c_addr) - // Wait for the input feed to complete - wi.Wait() + // Wait for the input feed to complete + wi.Wait() - // Wait for pending probes - waitProbes() + // Wait for pending probes + waitProbes() - // Close the output handle - close(c_out) + // Close the output handle + close(c_out) - // Wait for the output goroutine - wo.Wait() + // Wait for the output goroutine + wo.Wait() }