2017-08-01 23:13:28 +00:00
package zgrab2
2017-07-14 20:44:36 +00:00
import (
2017-08-04 20:20:32 +00:00
"bufio"
2017-07-14 20:44:36 +00:00
"encoding/json"
2018-01-15 19:24:57 +00:00
"fmt"
2017-07-14 20:44:36 +00:00
"io"
2017-08-04 20:20:32 +00:00
"net"
2017-09-26 18:15:15 +00:00
"strings"
2017-07-14 20:44:36 +00:00
"sync"
2018-01-15 19:24:57 +00:00
"time"
2017-08-03 19:55:15 +00:00
log "github.com/sirupsen/logrus"
2017-07-14 20:44:36 +00:00
)
2017-10-04 03:57:56 +00:00
// Grab contains all scan responses for a single host
2017-07-17 21:28:10 +00:00
type Grab struct {
2017-09-26 18:02:27 +00:00
IP string ` json:"ip,omitempty" `
Domain string ` json:"domain,omitempty" `
Data map [ string ] ScanResponse ` json:"data,omitempty" `
2017-07-14 20:44:36 +00:00
}
2017-10-04 03:57:56 +00:00
// ScanTarget is the host that will be scanned
2017-09-26 18:02:27 +00:00
type ScanTarget struct {
2017-08-04 20:20:32 +00:00
IP net . IP
Domain string
}
2018-01-15 19:24:57 +00:00
// scanTargetConnection wraps an existing net.Conn connection, overriding the Read/Write methods to use the configured timeouts
type scanTargetConnection struct {
net . Conn
Timeout time . Duration
}
func ( c * scanTargetConnection ) Read ( b [ ] byte ) ( n int , err error ) {
if c . Timeout > 0 {
if err = c . Conn . SetReadDeadline ( time . Now ( ) . Add ( c . Timeout ) ) ; err != nil {
return 0 , err
}
}
return c . Conn . Read ( b )
}
func ( c * scanTargetConnection ) Write ( b [ ] byte ) ( n int , err error ) {
if c . Timeout > 0 {
if err = c . Conn . SetWriteDeadline ( time . Now ( ) . Add ( c . Timeout ) ) ; err != nil {
return 0 , err
}
}
return c . Conn . Write ( b )
}
// ScanTarget.Open connects to the ScanTarget using the configured flags, and returns a net.Conn that uses the configured timeouts for Read/Write operations.
func ( t * ScanTarget ) Open ( flags * BaseFlags ) ( net . Conn , error ) {
timeout := time . Second * time . Duration ( flags . Timeout )
target := fmt . Sprintf ( "%s:%d" , t . IP . String ( ) , flags . Port )
var conn net . Conn
var err error
if timeout > 0 {
conn , err = net . DialTimeout ( "tcp" , target , timeout )
} else {
conn , err = net . Dial ( "tcp" , target )
}
if err != nil {
if conn != nil {
conn . Close ( )
}
return nil , err
}
return & scanTargetConnection {
Conn : conn ,
Timeout : timeout ,
} , nil
}
2017-08-30 19:39:25 +00:00
// grabTarget calls handler for each action
2017-09-26 18:02:27 +00:00
func grabTarget ( input ScanTarget , m * Monitor ) [ ] byte {
moduleResult := make ( map [ string ] ScanResponse )
2017-08-01 23:13:28 +00:00
2017-09-26 18:02:27 +00:00
for _ , scannerName := range orderedScanners {
scanner := scanners [ scannerName ]
2017-10-04 15:32:42 +00:00
name , res := RunScanner ( * scanner , m , input )
2017-08-09 20:13:18 +00:00
moduleResult [ name ] = res
2017-08-09 18:56:05 +00:00
if res . Error != nil && ! config . Multiple . ContinueOnError {
2017-08-01 23:13:28 +00:00
break
2017-07-14 20:44:36 +00:00
}
}
2017-08-30 19:39:25 +00:00
var ipstr string
if input . IP == nil {
ipstr = ""
2017-08-04 20:20:32 +00:00
} else {
s := input . IP . String ( )
2017-08-30 19:39:25 +00:00
ipstr = s
2017-08-04 20:20:32 +00:00
}
2017-08-09 20:13:18 +00:00
a := Grab { IP : ipstr , Domain : input . Domain , Data : moduleResult }
2017-08-04 20:20:32 +00:00
result , err := json . Marshal ( a )
if err != nil {
2017-08-30 19:39:25 +00:00
log . Fatalf ( "unable to marshal data: %s" , err )
2017-08-04 20:20:32 +00:00
}
2017-07-14 20:44:36 +00:00
return result
}
// Process sets up an output encoder, input reader, and starts grab workers
2017-08-16 16:09:20 +00:00
func Process ( mon * Monitor ) {
2017-08-03 19:55:15 +00:00
workers := config . Senders
2017-09-26 18:02:27 +00:00
processQueue := make ( chan ScanTarget , workers * 4 )
2017-08-16 16:09:20 +00:00
outputQueue := make ( chan [ ] byte , workers * 4 )
2017-07-14 20:44:36 +00:00
//Create wait groups
var workerDone sync . WaitGroup
var outputDone sync . WaitGroup
workerDone . Add ( int ( workers ) )
outputDone . Add ( 1 )
// Start the output encoder
go func ( ) {
2017-08-14 18:13:18 +00:00
out := bufio . NewWriter ( config . outputFile )
2017-08-31 21:24:05 +00:00
defer outputDone . Done ( )
2017-08-14 18:13:18 +00:00
defer out . Flush ( )
2017-07-14 20:44:36 +00:00
for result := range outputQueue {
if _ , err := out . Write ( result ) ; err != nil {
2017-08-09 18:56:05 +00:00
log . Fatal ( err )
2017-07-14 20:44:36 +00:00
}
2017-08-31 21:24:05 +00:00
if err := out . WriteByte ( '\n' ) ; err != nil {
2017-08-09 18:56:05 +00:00
log . Fatal ( err )
2017-07-14 20:44:36 +00:00
}
}
} ( )
//Start all the workers
2017-07-17 21:28:10 +00:00
for i := 0 ; i < workers ; i ++ {
2017-12-15 14:25:17 +00:00
go func ( i int ) {
for _ , scannerName := range orderedScanners {
scanner := * scanners [ scannerName ]
scanner . InitPerSender ( i )
}
2017-07-14 20:44:36 +00:00
for obj := range processQueue {
2017-09-05 02:31:44 +00:00
for run := uint ( 0 ) ; run < uint ( config . ConnectionsPerHost ) ; run ++ {
2017-09-04 22:44:58 +00:00
result := grabTarget ( obj , mon )
outputQueue <- result
}
2017-07-14 20:44:36 +00:00
}
workerDone . Done ( )
2017-12-15 14:25:17 +00:00
} ( i )
2017-07-14 20:44:36 +00:00
}
// Read the input, send to workers
2017-08-04 20:20:32 +00:00
input := bufio . NewReader ( config . inputFile )
2017-07-14 20:44:36 +00:00
for {
2017-08-04 20:20:32 +00:00
obj , err := input . ReadBytes ( '\n' )
if err == io . EOF {
break
} else if err != nil {
log . Error ( err )
}
2017-09-26 18:15:15 +00:00
st := strings . TrimSpace ( string ( obj ) )
ipnet , domain , err := ParseTarget ( st )
2017-08-04 20:20:32 +00:00
if err != nil {
log . Error ( err )
2017-08-09 18:56:05 +00:00
continue
}
2017-09-03 03:14:33 +00:00
var ip net . IP
2017-08-14 18:13:18 +00:00
if ipnet != nil {
2017-09-03 03:14:33 +00:00
if ipnet . Mask != nil {
for ip = ipnet . IP . Mask ( ipnet . Mask ) ; ipnet . Contains ( ip ) ; incrementIP ( ip ) {
2017-09-26 18:02:27 +00:00
processQueue <- ScanTarget { IP : duplicateIP ( ip ) , Domain : domain }
2017-09-03 03:14:33 +00:00
}
continue
} else {
ip = ipnet . IP
2017-08-04 20:20:32 +00:00
}
2017-07-14 20:44:36 +00:00
}
2017-09-26 18:02:27 +00:00
processQueue <- ScanTarget { IP : ip , Domain : domain }
2017-07-14 20:44:36 +00:00
}
close ( processQueue )
workerDone . Wait ( )
close ( outputQueue )
outputDone . Wait ( )
}