diff --git a/cmd/scan.go b/cmd/scan.go index 7decba6..4a1deb9 100644 --- a/cmd/scan.go +++ b/cmd/scan.go @@ -66,7 +66,7 @@ var ScanCmd = &cobra.Command{ "specified. The `--scheme` flag works similarly and the default value is 'https' in the host URL or with the\n" + "'--protocol' flag.\n\n" + "If the '--disable-probe` flag is used, the tool will not send another request to probe for available.\n" + - "Redfish services. This is not recommended, since the extra request makes the scan a bit more reliable\n" + + "Redfish and JAWS services. This is not recommended, since the extra request makes the scan a bit more reliable\n" + "for determining which hosts to collect inventory data.\n\n", Run: func(cmd *cobra.Command, args []string) { // add default ports for hosts if none are specified with flag @@ -138,6 +138,8 @@ var ScanCmd = &cobra.Command{ DisableProbing: disableProbing, Verbose: verbose, Debug: debug, + Username: username, + Password: password, }) if len(foundAssets) > 0 && debug { diff --git a/pkg/scan.go b/pkg/scan.go index 58785ca..2ef87fd 100644 --- a/pkg/scan.go +++ b/pkg/scan.go @@ -16,11 +16,12 @@ import ( ) type RemoteAsset struct { - Host string `json:"host"` - Port int `json:"port"` - Protocol string `json:"protocol"` - State bool `json:"state"` - Timestamp time.Time `json:"timestamp"` + Host string `json:"host"` + Port int `json:"port"` + Protocol string `json:"protocol"` + State bool `json:"state"` + Timestamp time.Time `json:"timestamp"` + ServiceType string `json:"service_type,omitempty"` } // ScanParams is a collection of commom parameters passed to the CLI @@ -33,6 +34,8 @@ type ScanParams struct { DisableProbing bool Verbose bool Debug bool + Username string + Password string } // ScanForAssets() performs a net scan on a network to find available services @@ -45,7 +48,7 @@ type ScanParams struct { // to be made concurrently. // // If the "disableProbing" flag is set, then the function will skip the extra -// HTTP request made to check if the response was from a Redfish service. +// HTTP request made to check if the response was from a Redfish or JAWS service. // Otherwise, not receiving a 200 OK response code from the HTTP request will // remove the service from being stored in the list of scanned results. // @@ -61,6 +64,17 @@ func ScanForAssets(params *ScanParams) []RemoteAsset { log.Info().Any("args", params).Msg("starting scan...") } + probesToRun := []struct { + Type, Path string + }{ + {Type: "Redfish", Path: "/redfish/v1/"}, + {Type: "JAWS", Path: "/jaws/monitor/outlets"}, + } + + probeClient := &http.Client{ + Timeout: time.Duration(params.Timeout) * time.Second, + } + var wg sync.WaitGroup wg.Add(params.Concurrency) for i := 0; i < params.Concurrency; i++ { @@ -78,26 +92,35 @@ func ScanForAssets(params *ScanParams) []RemoteAsset { if params.Verbose { log.Debug().Err(err).Msgf("failed to connect to host") } - wg.Done() - return + // NOTE: This was wg.Done() and return in the original, but that stops the whole worker. + // Continuing allows the worker to process other hosts in its queue. + continue } if !params.DisableProbing { assetsToAdd := []RemoteAsset{} for _, foundAsset := range foundAssets { - url := fmt.Sprintf("%s:%d/redfish/v1/", foundAsset.Host, foundAsset.Port) - res, _, err := client.MakeRequest(nil, url, http.MethodGet, nil, nil) - if err != nil || res == nil { - if params.Verbose { - log.Printf("failed to make request: %v\n", err) + for _, probe := range probesToRun { + probeURL := fmt.Sprintf("%s:%d%s", foundAsset.Host, foundAsset.Port, probe.Path) + req, err := http.NewRequest("GET", probeURL, nil) + if err != nil { + continue } - continue - } else if res.StatusCode != http.StatusOK { - if params.Verbose { - log.Printf("request returned code: %v\n", res.StatusCode) + + // Add authentication for JAWS endpoints if credentials are provided + if probe.Type == "JAWS" && params.Username != "" && params.Password != "" { + req.SetBasicAuth(params.Username, params.Password) + } + + res, err := probeClient.Do(req) + if err == nil && res != nil && res.StatusCode == http.StatusOK { + res.Body.Close() + foundAsset.ServiceType = probe.Type + assetsToAdd = append(assetsToAdd, foundAsset) + break // Found a valid service, no need to probe other types + } + if res != nil { + res.Body.Close() } - continue - } else { - assetsToAdd = append(assetsToAdd, foundAsset) } } results = append(results, assetsToAdd...)