2018-01-15 19:24:57 +00:00
package zgrab2
import (
"io"
"net"
2018-02-07 17:25:46 +00:00
"runtime/debug"
log "github.com/sirupsen/logrus"
2018-01-15 19:24:57 +00:00
)
// ScanStatus is the enum value that states how the scan ended.
type ScanStatus string
// TODO: Conform to standard string const format (names, capitalization, hyphens/underscores, etc)
// TODO: Enumerate further status types
2018-03-21 14:36:58 +00:00
// TODO: lump connection closed / io timeout?
// TODO: Add SCAN_TLS_PROTOCOL_ERROR? For purely TLS-wrapped protocols, SCAN_PROTOCOL_ERROR is fine -- but for protocols that have a non-TLS bootstrap (e.g. a STARTTLS procedure), SCAN_PROTOCOL_ERROR is misleading, since it did get far-enough into the application protocol to start TLS handshaking -- but a garbled TLS handshake is certainly not a SCAN_APPLICATION_ERROR
2018-01-15 19:24:57 +00:00
const (
2018-03-21 14:36:58 +00:00
SCAN_SUCCESS ScanStatus = "success" // The protocol in question was positively identified and the scan encountered no errors
SCAN_CONNECTION_REFUSED = "connection-refused" // TCP connection was actively rejected
SCAN_CONNECTION_TIMEOUT = "connection-timeout" // No response to TCP connection request
SCAN_CONNECTION_CLOSED = "connection-closed" // The TCP connection was unexpectedly closed
SCAN_IO_TIMEOUT = "io-timeout" // Timed out waiting on data
SCAN_PROTOCOL_ERROR = "protocol-error" // Received data incompatible with the target protocol
SCAN_APPLICATION_ERROR = "application-error" // The application reported an error
SCAN_UNKNOWN_ERROR = "unknown-error" // Catch-all for unrecognized errors
2018-01-15 19:24:57 +00:00
)
// ScanError an error that also includes a ScanStatus.
type ScanError struct {
Status ScanStatus
Err error
}
// Error is an implementation of the builtin.error interface -- just forward the wrapped error's Error() method
func ( err * ScanError ) Error ( ) string {
if err . Err == nil {
return "<nil>"
}
return err . Err . Error ( )
}
func ( err * ScanError ) Unpack ( results interface { } ) ( ScanStatus , interface { } , error ) {
return err . Status , results , err . Err
}
// NewScanError returns a ScanError with the given status and error.
func NewScanError ( status ScanStatus , err error ) * ScanError {
return & ScanError { Status : status , Err : err }
}
// DetectScanError returns a ScanError that attempts to detect the status from the given error.
func DetectScanError ( err error ) * ScanError {
return & ScanError { Status : TryGetScanStatus ( err ) , Err : err }
}
// TryGetScanStatus attempts to get the ScanStatus enum value corresponding to the given error.
// Mostly supports network errors. A nil error is interpreted as SCAN_SUCCESS.
// An unrecognized error is interpreted as SCAN_UNKNOWN_ERROR.
func TryGetScanStatus ( err error ) ScanStatus {
if err == nil {
return SCAN_SUCCESS
}
if err == io . EOF {
// Presumably the caller did not call TryGetScanStatus if the EOF was expected
return SCAN_IO_TIMEOUT
}
switch e := err . ( type ) {
case * ScanError :
return e . Status
case * net . OpError :
switch e . Op {
case "dial" :
// TODO: Distinguish connection timeout / connection refused
// Windows examples:
// "dial tcp 192.168.30.3:22: connectex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond."
// "dial tcp 127.0.0.1:22: connectex: No connection could be made because the target machine actively refused it."
return SCAN_CONNECTION_TIMEOUT
case "read" :
// TODO: Distinguish connection reset vs timeout
return SCAN_IO_TIMEOUT
case "write" :
// TODO: Distinguish connection reset vs timeout
return SCAN_IO_TIMEOUT
default :
// TODO: Do we need a generic network error?
2018-02-07 17:25:46 +00:00
log . Debugf ( "Failed to detect error from net.OpError %v, op = %s at %s" , e , e . Op , string ( debug . Stack ( ) ) )
2018-01-15 19:24:57 +00:00
return SCAN_UNKNOWN_ERROR
}
// TODO: More error types
default :
2018-02-07 17:25:46 +00:00
log . Debugf ( "Failed to detect error from %v at %s" , e , string ( debug . Stack ( ) ) )
2018-01-15 19:24:57 +00:00
return SCAN_UNKNOWN_ERROR
}
}