Add OVAL HTTP health check

This commit is contained in:
Kota Kanbe
2017-06-16 16:40:33 +09:00
committed by kota kanbe
parent f7aa85746d
commit c442a433b0
7 changed files with 100 additions and 54 deletions

View File

@@ -26,6 +26,7 @@ import (
c "github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/oval"
"github.com/future-architect/vuls/report"
"github.com/future-architect/vuls/util"
"github.com/google/subcommands"
@@ -395,7 +396,7 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
if !c.Conf.ValidateOnReport() {
return subcommands.ExitUsageError
}
if ok, err := report.CveClient.CheckHealth(); !ok {
if err := report.CveClient.CheckHealth(); err != nil {
util.Log.Errorf("CVE HTTP server is not running. err: %s", err)
util.Log.Errorf("Run go-cve-dictionary as server mode before reporting or run with --cvedb-path option")
return subcommands.ExitFailure
@@ -408,6 +409,15 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
}
}
if c.Conf.OvalDBURL != "" {
err := oval.Base{}.CheckHealth()
if err != nil {
util.Log.Errorf("OVAL HTTP server is not running. err: %s", err)
util.Log.Errorf("Run goval-dictionary as server mode before reporting or run with --ovaldb-path option")
return subcommands.ExitFailure
}
}
var res models.ScanResults
if res, err = report.LoadScanResults(dir); err != nil {
util.Log.Error(err)

View File

@@ -13,7 +13,7 @@ import (
)
// DebianBase is the base struct of Debian and Ubuntu
type DebianBase struct{}
type DebianBase struct{ Base }
// fillFromOvalDB returns scan result after updating CVE info by OVAL
func (o DebianBase) fillFromOvalDB(r *models.ScanResult) error {
@@ -109,7 +109,7 @@ func NewDebian() Debian {
// FillWithOval returns scan result after updating CVE info by OVAL
func (o Debian) FillWithOval(r *models.ScanResult) error {
if config.Conf.OvalDBURL != "" {
if o.isFetchViaHTTP() {
defs, err := getDefsByPackNameViaHTTP(r)
if err != nil {
return err
@@ -144,9 +144,20 @@ func NewUbuntu() Ubuntu {
// FillWithOval returns scan result after updating CVE info by OVAL
func (o Ubuntu) FillWithOval(r *models.ScanResult) error {
if err := o.fillFromOvalDB(r); err != nil {
return err
if o.isFetchViaHTTP() {
defs, err := getDefsByPackNameViaHTTP(r)
if err != nil {
return err
}
for _, def := range defs {
o.update(r, &def)
}
} else {
if err := o.fillFromOvalDB(r); err != nil {
return err
}
}
for _, vuln := range r.ScannedCves {
if cont, ok := vuln.CveContents[models.Ubuntu]; ok {
cont.SourceLink = "http://people.ubuntu.com/~ubuntu-security/cve/" + cont.CveID

View File

@@ -17,9 +17,40 @@ import (
// Client is the interface of OVAL client.
type Client interface {
CheckHealth() error
FillWithOval(r *models.ScanResult) error
}
// Base is a base struct
type Base struct{}
// CheckHealth do health check
func (b Base) CheckHealth() error {
if !b.isFetchViaHTTP() {
return nil
}
url := fmt.Sprintf("%s/health", config.Conf.OvalDBURL)
var errs []error
var resp *http.Response
resp, _, errs = gorequest.New().Get(url).End()
// resp, _, errs = gorequest.New().SetDebug(config.Conf.Debug).Get(url).End()
// resp, _, errs = gorequest.New().Proxy(api.httpProxy).Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return fmt.Errorf("Failed to request to OVAL server. url: %s, errs: %v",
url, errs)
}
return nil
}
func (b Base) isFetchViaHTTP() bool {
// Default value of OvalDBType is sqlite3
if config.Conf.OvalDBURL != "" && config.Conf.OvalDBType == "sqlite3" {
return true
}
return false
}
type request struct {
pack models.Package
}
@@ -33,7 +64,6 @@ type response struct {
func getDefsByPackNameViaHTTP(r *models.ScanResult) (
relatedDefs []ovalmodels.Definition, err error) {
//TODO Health Check
reqChan := make(chan request, len(r.Packages))
resChan := make(chan response, len(r.Packages))
errChan := make(chan error, len(r.Packages))

View File

@@ -15,11 +15,11 @@ import (
)
// RedHatBase is the base struct for RedHat and CentOS
type RedHatBase struct{}
type RedHatBase struct{ Base }
// FillWithOval returns scan result after updating CVE info by OVAL
func (o RedHatBase) FillWithOval(r *models.ScanResult) error {
if config.Conf.OvalDBURL != "" {
if o.isFetchViaHTTP() {
defs, err := getDefsByPackNameViaHTTP(r)
if err != nil {
return err

View File

@@ -45,10 +45,10 @@ func (api *cvedictClient) initialize() {
api.baseURL = config.Conf.CveDBURL
}
func (api cvedictClient) CheckHealth() (ok bool, err error) {
if config.Conf.CveDBURL == "" || config.Conf.CveDBType == "mysql" || config.Conf.CveDBType == "postgres" {
func (api cvedictClient) CheckHealth() error {
if !api.isFetchViaHTTP() {
util.Log.Debugf("get cve-dictionary from %s", config.Conf.CveDBType)
return true, nil
return nil
}
api.initialize()
@@ -58,9 +58,10 @@ func (api cvedictClient) CheckHealth() (ok bool, err error) {
resp, _, errs = gorequest.New().SetDebug(config.Conf.Debug).Get(url).End()
// resp, _, errs = gorequest.New().Proxy(api.httpProxy).Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return false, fmt.Errorf("Failed to request to CVE server. url: %s, errs: %v", url, errs)
return fmt.Errorf("Failed to request to CVE server. url: %s, errs: %v",
url, errs)
}
return true, nil
return nil
}
type response struct {
@@ -69,8 +70,7 @@ type response struct {
}
func (api cvedictClient) FetchCveDetails(cveIDs []string) (cveDetails cve.CveDetails, err error) {
switch config.Conf.CveDBType {
case "sqlite3", "mysql", "postgres":
if !api.isFetchViaHTTP() {
return api.FetchCveDetailsFromCveDB(cveIDs)
}
@@ -195,21 +195,28 @@ type responseGetCveDetailByCpeName struct {
CveDetails []cve.CveDetail
}
func (api cvedictClient) isFetchViaHTTP() bool {
// Default value of CveDBType is sqlite3
if config.Conf.CveDBURL != "" && config.Conf.CveDBType == "sqlite3" {
return true
}
return false
}
func (api cvedictClient) FetchCveDetailsByCpeName(cpeName string) ([]cve.CveDetail, error) {
switch config.Conf.CveDBType {
case "sqlite3", "mysql", "postgres":
return api.FetchCveDetailsByCpeNameFromDB(cpeName)
if api.isFetchViaHTTP() {
api.baseURL = config.Conf.CveDBURL
url, err := util.URLPathJoin(api.baseURL, "cpes")
if err != nil {
return []cve.CveDetail{}, err
}
query := map[string]string{"name": cpeName}
util.Log.Debugf("HTTP Request to %s, query: %#v", url, query)
return api.httpPost(cpeName, url, query)
}
api.baseURL = config.Conf.CveDBURL
url, err := util.URLPathJoin(api.baseURL, "cpes")
if err != nil {
return []cve.CveDetail{}, err
}
query := map[string]string{"name": cpeName}
util.Log.Debugf("HTTP Request to %s, query: %#v", url, query)
return api.httpPost(cpeName, url, query)
return api.FetchCveDetailsByCpeNameFromDB(cpeName)
}
func (api cvedictClient) httpPost(key, url string, query map[string]string) ([]cve.CveDetail, error) {
@@ -217,7 +224,8 @@ func (api cvedictClient) httpPost(key, url string, query map[string]string) ([]c
var errs []error
var resp *http.Response
f := func() (err error) {
req := gorequest.New().SetDebug(config.Conf.Debug).Post(url)
// req := gorequest.New().SetDebug(config.Conf.Debug).Post(url)
req := gorequest.New().Post(url)
for key := range query {
req = req.Send(fmt.Sprintf("%s=%s", key, query[key])).Type("json")
}

View File

@@ -70,44 +70,31 @@ func FillCveInfos(rs []models.ScanResult, dir string) ([]models.ScanResult, erro
}
}
//TODO remove debug code
// for _, r := range filled {
// pp.Printf("filled: %d\n", len(r.ScannedCves))
// }
filtered := []models.ScanResult{}
for _, r := range filled {
filtered = append(filtered, r.FilterByCvssOver(c.Conf.CvssScoreOver))
}
//TODO remove debug code
// for _, r := range filtered {
// pp.Printf("filtered: %d\n", len(r.ScannedCves))
// }
return filtered, nil
}
func fillCveInfo(r *models.ScanResult) error {
util.Log.Debugf("need to refresh")
if c.Conf.CveDBType == "sqlite3" {
if c.Conf.CveDBURL == "" {
if _, err := os.Stat(c.Conf.CveDBPath); os.IsNotExist(err) {
return fmt.Errorf("SQLite3 DB(CVE-Dictionary) is not exist: %s",
c.Conf.CveDBPath)
}
if c.Conf.CveDBType == "sqlite3" && c.Conf.CveDBURL == "" {
if _, err := os.Stat(c.Conf.CveDBPath); os.IsNotExist(err) {
return fmt.Errorf("SQLite3 DB(CVE-Dictionary) is not exist: %s",
c.Conf.CveDBPath)
}
if c.Conf.OvalDBURL == "" {
if _, err := os.Stat(c.Conf.OvalDBPath); os.IsNotExist(err) {
//TODO Warning
return fmt.Errorf("SQLite3 DB(OVAL-Dictionary) is not exist: %s",
c.Conf.OvalDBPath)
}
}
if c.Conf.OvalDBType == "sqlite3" && c.Conf.OvalDBURL == "" {
if _, err := os.Stat(c.Conf.OvalDBPath); os.IsNotExist(err) {
// TODO Warning??
return fmt.Errorf("SQLite3 DB(OVAL-Dictionary) is not exist: %s",
c.Conf.OvalDBPath)
}
}
util.Log.Debugf("Fill CVE detailed information with OVAL")
if err := fillWithOvalDB(r); err != nil {
if err := fillWithOval(r); err != nil {
return fmt.Errorf("Failed to fill OVAL information: %s", err)
}
@@ -166,7 +153,7 @@ func fillWithCveDB(r *models.ScanResult) error {
return nil
}
func fillWithOvalDB(r *models.ScanResult) error {
func fillWithOval(r *models.ScanResult) error {
var ovalClient oval.Client
switch r.Family {
case "debian":

View File

@@ -60,7 +60,7 @@ func detectDebian(c config.ServerInfo) (itsMe bool, deb osTypeInterface, err err
return false, deb, nil
}
if r.ExitStatus == 255 {
return false, deb, fmt.Errorf("Unable to connect via SSH. Check SSH settings. If you have never SSH to the host to be scanned, SSH to the host before scanning in order to add a HostKey. %s", r)
return false, deb, fmt.Errorf("Unable to connect via SSH. Check SSH settings. If you have never SSH to the host to be scanned, SSH to the host before scanning in order to add the HostKey. %s@%s port: %s\n%s", c.User, c.Host, c.Port, r)
}
util.Log.Debugf("Not Debian like Linux. %s", r)
return false, deb, nil