refactor(detector): standardize db.NewDB to db.CloseDB (#1380)

* feat(subcmds/report,server): read environment variables when configPath is ""

* refactor: standardize db.NewDB to db.CloseDB

* chore: clean up import

* chore: error wrap

* chore: update goval-dictionary

* fix(oval): return Pseudo instead of nil for client

* chore: fix comment

* fix: lint error
This commit is contained in:
MaineK00n
2022-02-19 09:20:45 +09:00
committed by GitHub
parent 7750347010
commit 7d8a24ee1a
23 changed files with 610 additions and 494 deletions

View File

@@ -22,40 +22,27 @@ import (
)
type goCveDictClient struct {
cnf config.VulnDictInterface
driver cvedb.DB
driver cvedb.DB
baseURL string
}
func newGoCveDictClient(cnf config.VulnDictInterface, o logging.LogOpts) (*goCveDictClient, error) {
if err := cvelog.SetLogger(o.LogToFile, o.LogDir, o.Debug, o.LogJSON); err != nil {
return nil, err
return nil, xerrors.Errorf("Failed to set go-cve-dictionary logger. err: %w", err)
}
driver, locked, err := newCveDB(cnf)
if locked {
return nil, xerrors.Errorf("SQLite3 is locked: %s", cnf.GetSQLite3Path())
} else if err != nil {
return nil, err
driver, err := newCveDB(cnf)
if err != nil {
return nil, xerrors.Errorf("Failed to newCveDB. err: %w", err)
}
return &goCveDictClient{cnf: cnf, driver: driver}, nil
return &goCveDictClient{driver: driver, baseURL: cnf.GetURL()}, nil
}
func (api goCveDictClient) closeDB() error {
if api.driver == nil {
func (client goCveDictClient) closeDB() error {
if client.driver == nil {
return nil
}
return api.driver.CloseDB()
}
func (api goCveDictClient) fetchCveDetails(cveIDs []string) (cveDetails []cvemodels.CveDetail, err error) {
m, err := api.driver.GetMulti(cveIDs)
if err != nil {
return nil, xerrors.Errorf("Failed to GetMulti. err: %w", err)
}
for _, v := range m {
cveDetails = append(cveDetails, v)
}
return cveDetails, nil
return client.driver.CloseDB()
}
type response struct {
@@ -63,57 +50,67 @@ type response struct {
CveDetail cvemodels.CveDetail
}
func (api goCveDictClient) fetchCveDetailsViaHTTP(cveIDs []string) (cveDetails []cvemodels.CveDetail, err error) {
reqChan := make(chan string, len(cveIDs))
resChan := make(chan response, len(cveIDs))
errChan := make(chan error, len(cveIDs))
defer close(reqChan)
defer close(resChan)
defer close(errChan)
func (client goCveDictClient) fetchCveDetails(cveIDs []string) (cveDetails []cvemodels.CveDetail, err error) {
if client.driver == nil {
reqChan := make(chan string, len(cveIDs))
resChan := make(chan response, len(cveIDs))
errChan := make(chan error, len(cveIDs))
defer close(reqChan)
defer close(resChan)
defer close(errChan)
go func() {
for _, cveID := range cveIDs {
reqChan <- cveID
}
}()
go func() {
for _, cveID := range cveIDs {
reqChan <- cveID
}
}()
concurrency := 10
tasks := util.GenWorkers(concurrency)
for range cveIDs {
tasks <- func() {
select {
case cveID := <-reqChan:
url, err := util.URLPathJoin(api.cnf.GetURL(), "cves", cveID)
if err != nil {
errChan <- err
} else {
logging.Log.Debugf("HTTP Request to %s", url)
api.httpGet(cveID, url, resChan, errChan)
concurrency := 10
tasks := util.GenWorkers(concurrency)
for range cveIDs {
tasks <- func() {
select {
case cveID := <-reqChan:
url, err := util.URLPathJoin(client.baseURL, "cves", cveID)
if err != nil {
errChan <- err
} else {
logging.Log.Debugf("HTTP Request to %s", url)
httpGet(cveID, url, resChan, errChan)
}
}
}
}
}
timeout := time.After(2 * 60 * time.Second)
var errs []error
for range cveIDs {
select {
case res := <-resChan:
cveDetails = append(cveDetails, res.CveDetail)
case err := <-errChan:
errs = append(errs, err)
case <-timeout:
return nil, xerrors.New("Timeout Fetching CVE")
timeout := time.After(2 * 60 * time.Second)
var errs []error
for range cveIDs {
select {
case res := <-resChan:
cveDetails = append(cveDetails, res.CveDetail)
case err := <-errChan:
errs = append(errs, err)
case <-timeout:
return nil, xerrors.New("Timeout Fetching CVE")
}
}
if len(errs) != 0 {
return nil,
xerrors.Errorf("Failed to fetch CVE. err: %w", errs)
}
} else {
m, err := client.driver.GetMulti(cveIDs)
if err != nil {
return nil, xerrors.Errorf("Failed to GetMulti. err: %w", err)
}
for _, v := range m {
cveDetails = append(cveDetails, v)
}
}
if len(errs) != 0 {
return nil,
xerrors.Errorf("Failed to fetch CVE. err: %w", errs)
}
return
return cveDetails, nil
}
func (api goCveDictClient) httpGet(key, url string, resChan chan<- response, errChan chan<- error) {
func httpGet(key, url string, resChan chan<- response, errChan chan<- error) {
var body string
var errs []error
var resp *http.Response
@@ -144,21 +141,21 @@ func (api goCveDictClient) httpGet(key, url string, resChan chan<- response, err
}
}
func (api goCveDictClient) detectCveByCpeURI(cpeURI string, useJVN bool) (cves []cvemodels.CveDetail, err error) {
if api.cnf.IsFetchViaHTTP() {
url, err := util.URLPathJoin(api.cnf.GetURL(), "cpes")
func (client goCveDictClient) detectCveByCpeURI(cpeURI string, useJVN bool) (cves []cvemodels.CveDetail, err error) {
if client.driver == nil {
url, err := util.URLPathJoin(client.baseURL, "cpes")
if err != nil {
return nil, err
return nil, xerrors.Errorf("Failed to join URLPath. err: %w", err)
}
query := map[string]string{"name": cpeURI}
logging.Log.Debugf("HTTP Request to %s, query: %#v", url, query)
if cves, err = api.httpPost(url, query); err != nil {
return nil, err
if cves, err = httpPost(url, query); err != nil {
return nil, xerrors.Errorf("Failed to post HTTP Request. err: %w", err)
}
} else {
if cves, err = api.driver.GetByCpeURI(cpeURI); err != nil {
return nil, err
if cves, err = client.driver.GetByCpeURI(cpeURI); err != nil {
return nil, xerrors.Errorf("Failed to get CVEs by CPEURI. err: %w", err)
}
}
@@ -177,7 +174,7 @@ func (api goCveDictClient) detectCveByCpeURI(cpeURI string, useJVN bool) (cves [
return nvdCves, nil
}
func (api goCveDictClient) httpPost(url string, query map[string]string) ([]cvemodels.CveDetail, error) {
func httpPost(url string, query map[string]string) ([]cvemodels.CveDetail, error) {
var body string
var errs []error
var resp *http.Response
@@ -208,18 +205,20 @@ func (api goCveDictClient) httpPost(url string, query map[string]string) ([]cvem
return cveDetails, nil
}
func newCveDB(cnf config.VulnDictInterface) (driver cvedb.DB, locked bool, err error) {
func newCveDB(cnf config.VulnDictInterface) (cvedb.DB, error) {
if cnf.IsFetchViaHTTP() {
return nil, false, nil
return nil, nil
}
path := cnf.GetURL()
if cnf.GetType() == "sqlite3" {
path = cnf.GetSQLite3Path()
}
driver, locked, err = cvedb.NewDB(cnf.GetType(), path, cnf.GetDebugSQL(), cvedb.Option{})
driver, locked, err := cvedb.NewDB(cnf.GetType(), path, cnf.GetDebugSQL(), cvedb.Option{})
if err != nil {
err = xerrors.Errorf("Failed to init CVE DB. err: %w, path: %s", err, path)
return nil, locked, err
if locked {
return nil, xerrors.Errorf("Failed to init CVE DB. SQLite3: %s is locked. err: %w", cnf.GetSQLite3Path(), err)
}
return nil, xerrors.Errorf("Failed to init CVE DB. DB Path: %s, err: %w", path, err)
}
return driver, false, nil
return driver, nil
}

View File

@@ -8,6 +8,8 @@ import (
"strings"
"time"
"golang.org/x/xerrors"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/contrib/owasp-dependency-check/parser"
@@ -19,7 +21,6 @@ import (
"github.com/future-architect/vuls/reporter"
"github.com/future-architect/vuls/util"
cvemodels "github.com/vulsio/go-cve-dictionary/models"
"golang.org/x/xerrors"
)
// Cpe :
@@ -47,7 +48,7 @@ func Detect(rs []models.ScanResult, dir string) ([]models.ScanResult, error) {
return nil, xerrors.Errorf("Failed to fill with Library dependency: %w", err)
}
if err := DetectPkgCves(&r, config.Conf.OvalDict, config.Conf.Gost); err != nil {
if err := DetectPkgCves(&r, config.Conf.OvalDict, config.Conf.Gost, config.Conf.LogOpts); err != nil {
return nil, xerrors.Errorf("Failed to detect Pkg CVE: %w", err)
}
@@ -91,7 +92,7 @@ func Detect(rs []models.ScanResult, dir string) ([]models.ScanResult, error) {
return nil, xerrors.Errorf("Failed to detect WordPress Cves: %w", err)
}
if err := gost.FillCVEsWithRedHat(&r, config.Conf.Gost); err != nil {
if err := gost.FillCVEsWithRedHat(&r, config.Conf.Gost, config.Conf.LogOpts); err != nil {
return nil, xerrors.Errorf("Failed to fill with gost: %w", err)
}
@@ -99,19 +100,19 @@ func Detect(rs []models.ScanResult, dir string) ([]models.ScanResult, error) {
return nil, xerrors.Errorf("Failed to fill with CVE: %w", err)
}
nExploitCve, err := FillWithExploit(&r, config.Conf.Exploit)
nExploitCve, err := FillWithExploit(&r, config.Conf.Exploit, config.Conf.LogOpts)
if err != nil {
return nil, xerrors.Errorf("Failed to fill with exploit: %w", err)
}
logging.Log.Infof("%s: %d PoC are detected", r.FormatServerName(), nExploitCve)
nMetasploitCve, err := FillWithMetasploit(&r, config.Conf.Metasploit)
nMetasploitCve, err := FillWithMetasploit(&r, config.Conf.Metasploit, config.Conf.LogOpts)
if err != nil {
return nil, xerrors.Errorf("Failed to fill with metasploit: %w", err)
}
logging.Log.Infof("%s: %d exploits are detected", r.FormatServerName(), nMetasploitCve)
if err := FillWithKEVuln(&r, config.Conf.KEVuln); err != nil {
if err := FillWithKEVuln(&r, config.Conf.KEVuln, config.Conf.LogOpts); err != nil {
return nil, xerrors.Errorf("Failed to fill with Known Exploited Vulnerabilities: %w", err)
}
@@ -143,7 +144,7 @@ func Detect(rs []models.ScanResult, dir string) ([]models.ScanResult, error) {
if config.Conf.DiffPlus || config.Conf.DiffMinus {
prevs, err := loadPrevious(rs, config.Conf.ResultsDir)
if err != nil {
return nil, err
return nil, xerrors.Errorf("Failed to load previous results. err: %w", err)
}
rs = diff(rs, prevs, config.Conf.DiffPlus, config.Conf.DiffMinus)
}
@@ -205,7 +206,7 @@ func Detect(rs []models.ScanResult, dir string) ([]models.ScanResult, error) {
// DetectPkgCves detects OS pkg cves
// pass 2 configs
func DetectPkgCves(r *models.ScanResult, ovalCnf config.GovalDictConf, gostCnf config.GostConf) error {
func DetectPkgCves(r *models.ScanResult, ovalCnf config.GovalDictConf, gostCnf config.GostConf, logOpts logging.LogOpts) error {
// Pkg Scan
if r.Release != "" {
if len(r.Packages)+len(r.SrcPackages) > 0 {
@@ -215,12 +216,12 @@ func DetectPkgCves(r *models.ScanResult, ovalCnf config.GovalDictConf, gostCnf c
}
// OVAL
if err := detectPkgsCvesWithOval(ovalCnf, r); err != nil {
if err := detectPkgsCvesWithOval(ovalCnf, r, logOpts); err != nil {
return xerrors.Errorf("Failed to detect CVE with OVAL: %w", err)
}
// gost
if err := detectPkgsCvesWithGost(gostCnf, r); err != nil {
if err := detectPkgsCvesWithGost(gostCnf, r, logOpts); err != nil {
return xerrors.Errorf("Failed to detect CVE with gost: %w", err)
}
} else {
@@ -308,7 +309,7 @@ func FillCvesWithNvdJvn(r *models.ScanResult, cnf config.GoCveDictConf, logOpts
client, err := newGoCveDictClient(&cnf, logOpts)
if err != nil {
return err
return xerrors.Errorf("Failed to newGoCveDictClient. err: %w", err)
}
defer func() {
if err := client.closeDB(); err != nil {
@@ -316,14 +317,9 @@ func FillCvesWithNvdJvn(r *models.ScanResult, cnf config.GoCveDictConf, logOpts
}
}()
var ds []cvemodels.CveDetail
if cnf.IsFetchViaHTTP() {
ds, err = client.fetchCveDetailsViaHTTP(cveIDs)
} else {
ds, err = client.fetchCveDetails(cveIDs)
}
ds, err := client.fetchCveDetails(cveIDs)
if err != nil {
return err
return xerrors.Errorf("Failed to fetchCveDetails. err: %w", err)
}
for _, d := range ds {
@@ -391,37 +387,43 @@ func fillCertAlerts(cvedetail *cvemodels.CveDetail) (dict models.AlertDict) {
}
// detectPkgsCvesWithOval fetches OVAL database
func detectPkgsCvesWithOval(cnf config.GovalDictConf, r *models.ScanResult) error {
ovalClient, err := oval.NewOVALClient(r.Family, cnf)
func detectPkgsCvesWithOval(cnf config.GovalDictConf, r *models.ScanResult, logOpts logging.LogOpts) error {
client, err := oval.NewOVALClient(r.Family, cnf, logOpts)
if err != nil {
return err
}
if ovalClient == nil {
return nil
}
defer func() {
if err := client.CloseDB(); err != nil {
logging.Log.Errorf("Failed to close the OVAL DB. err: %+v", err)
}
}()
logging.Log.Debugf("Check if oval fetched: %s %s", r.Family, r.Release)
ok, err := ovalClient.CheckIfOvalFetched(r.Family, r.Release)
ok, err := client.CheckIfOvalFetched(r.Family, r.Release)
if err != nil {
return err
}
if !ok {
if r.Family == constant.Debian {
switch r.Family {
case constant.Debian:
logging.Log.Infof("Skip OVAL and Scan with gost alone.")
logging.Log.Infof("%s: %d CVEs are detected with OVAL", r.FormatServerName(), 0)
return nil
case constant.Windows, constant.FreeBSD, constant.ServerTypePseudo:
return nil
default:
return xerrors.Errorf("OVAL entries of %s %s are not found. Fetch OVAL before reporting. For details, see `https://github.com/vulsio/goval-dictionary#usage`", r.Family, r.Release)
}
return xerrors.Errorf("OVAL entries of %s %s are not found. Fetch OVAL before reporting. For details, see `https://github.com/vulsio/goval-dictionary#usage`", r.Family, r.Release)
}
logging.Log.Debugf("Check if oval fresh: %s %s", r.Family, r.Release)
_, err = ovalClient.CheckIfOvalFresh(r.Family, r.Release)
_, err = client.CheckIfOvalFresh(r.Family, r.Release)
if err != nil {
return err
}
logging.Log.Debugf("Fill with oval: %s %s", r.Family, r.Release)
nCVEs, err := ovalClient.FillWithOval(r)
nCVEs, err := client.FillWithOval(r)
if err != nil {
return err
}
@@ -430,12 +432,11 @@ func detectPkgsCvesWithOval(cnf config.GovalDictConf, r *models.ScanResult) erro
return nil
}
func detectPkgsCvesWithGost(cnf config.GostConf, r *models.ScanResult) error {
client, err := gost.NewClient(cnf, r.Family)
func detectPkgsCvesWithGost(cnf config.GostConf, r *models.ScanResult, logOpts logging.LogOpts) error {
client, err := gost.NewGostClient(cnf, r.Family, logOpts)
if err != nil {
return xerrors.Errorf("Failed to new a gost client: %w", err)
}
defer func() {
if err := client.CloseDB(); err != nil {
logging.Log.Errorf("Failed to close the gost DB. err: %+v", err)
@@ -464,7 +465,7 @@ func detectPkgsCvesWithGost(cnf config.GostConf, r *models.ScanResult) error {
func DetectCpeURIsCves(r *models.ScanResult, cpes []Cpe, cnf config.GoCveDictConf, logOpts logging.LogOpts) error {
client, err := newGoCveDictClient(&cnf, logOpts)
if err != nil {
return err
return xerrors.Errorf("Failed to newGoCveDictClient. err: %w", err)
}
defer func() {
if err := client.closeDB(); err != nil {
@@ -476,7 +477,7 @@ func DetectCpeURIsCves(r *models.ScanResult, cpes []Cpe, cnf config.GoCveDictCon
for _, cpe := range cpes {
details, err := client.detectCveByCpeURI(cpe.CpeURI, cpe.UseJVN)
if err != nil {
return err
return xerrors.Errorf("Failed to detectCveByCpeURI. err: %w", err)
}
for _, detail := range details {

View File

@@ -9,33 +9,73 @@ import (
"time"
"github.com/cenkalti/backoff"
"github.com/parnurzeal/gorequest"
"golang.org/x/xerrors"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
"github.com/parnurzeal/gorequest"
exploitdb "github.com/vulsio/go-exploitdb/db"
exploitmodels "github.com/vulsio/go-exploitdb/models"
"golang.org/x/xerrors"
exploitlog "github.com/vulsio/go-exploitdb/util"
)
// goExploitDBClient is a DB Driver
type goExploitDBClient struct {
driver exploitdb.DB
baseURL string
}
// closeDB close a DB connection
func (client goExploitDBClient) closeDB() error {
if client.driver == nil {
return nil
}
return client.driver.CloseDB()
}
func newGoExploitDBClient(cnf config.VulnDictInterface, o logging.LogOpts) (*goExploitDBClient, error) {
if err := exploitlog.SetLogger(o.LogToFile, o.LogDir, o.Debug, o.LogJSON); err != nil {
return nil, xerrors.Errorf("Failed to set go-exploitdb logger. err: %w", err)
}
db, err := newExploitDB(cnf)
if err != nil {
return nil, xerrors.Errorf("Failed to newExploitDB. err: %w", err)
}
return &goExploitDBClient{driver: db, baseURL: cnf.GetURL()}, nil
}
// FillWithExploit fills exploit information that has in Exploit
func FillWithExploit(r *models.ScanResult, cnf config.ExploitConf) (nExploitCve int, err error) {
if cnf.IsFetchViaHTTP() {
func FillWithExploit(r *models.ScanResult, cnf config.ExploitConf, logOpts logging.LogOpts) (nExploitCve int, err error) {
client, err := newGoExploitDBClient(&cnf, logOpts)
if err != nil {
return 0, xerrors.Errorf("Failed to newGoExploitDBClient. err: %w", err)
}
defer func() {
if err := client.closeDB(); err != nil {
logging.Log.Errorf("Failed to close DB. err: %+v", err)
}
}()
if client.driver == nil {
var cveIDs []string
for cveID := range r.ScannedCves {
cveIDs = append(cveIDs, cveID)
}
prefix, _ := util.URLPathJoin(cnf.GetURL(), "cves")
prefix, err := util.URLPathJoin(client.baseURL, "cves")
if err != nil {
return 0, xerrors.Errorf("Failed to join URLPath. err: %w", err)
}
responses, err := getExploitsViaHTTP(cveIDs, prefix)
if err != nil {
return 0, err
return 0, xerrors.Errorf("Failed to get Exploits via HTTP. err: %w", err)
}
for _, res := range responses {
exps := []exploitmodels.Exploit{}
if err := json.Unmarshal([]byte(res.json), &exps); err != nil {
return 0, err
return 0, xerrors.Errorf("Failed to unmarshal json. err: %w", err)
}
exploits := ConvertToModelsExploit(exps)
v, ok := r.ScannedCves[res.request.cveID]
@@ -46,25 +86,13 @@ func FillWithExploit(r *models.ScanResult, cnf config.ExploitConf) (nExploitCve
nExploitCve++
}
} else {
driver, locked, err := newExploitDB(&cnf)
if locked {
return 0, xerrors.Errorf("SQLite3 is locked: %s", cnf.GetSQLite3Path())
} else if err != nil {
return 0, err
}
defer func() {
if err := driver.CloseDB(); err != nil {
logging.Log.Errorf("Failed to close DB. err: %+v", err)
}
}()
for cveID, vuln := range r.ScannedCves {
if cveID == "" {
continue
}
es, err := driver.GetExploitByCveID(cveID)
es, err := client.driver.GetExploitByCveID(cveID)
if err != nil {
return 0, err
return 0, xerrors.Errorf("Failed to get Exploits by CVE-ID. err: %w", err)
}
if len(es) == 0 {
continue
@@ -203,19 +231,20 @@ func httpGetExploit(url string, req exploitRequest, resChan chan<- exploitRespon
}
}
func newExploitDB(cnf config.VulnDictInterface) (driver exploitdb.DB, locked bool, err error) {
func newExploitDB(cnf config.VulnDictInterface) (driver exploitdb.DB, err error) {
if cnf.IsFetchViaHTTP() {
return nil, false, nil
return nil, nil
}
path := cnf.GetURL()
if cnf.GetType() == "sqlite3" {
path = cnf.GetSQLite3Path()
}
if driver, locked, err = exploitdb.NewDB(cnf.GetType(), path, cnf.GetDebugSQL(), exploitdb.Option{}); err != nil {
driver, locked, err := exploitdb.NewDB(cnf.GetType(), path, cnf.GetDebugSQL(), exploitdb.Option{})
if err != nil {
if locked {
return nil, true, xerrors.Errorf("exploitDB is locked. err: %w", err)
return nil, xerrors.Errorf("Failed to init exploit DB. SQLite3: %s is locked. err: %w", cnf.GetSQLite3Path(), err)
}
return nil, false, err
return nil, xerrors.Errorf("Failed to init exploit DB. DB Path: %s, err: %w", path, err)
}
return driver, false, nil
return driver, nil
}

View File

@@ -9,25 +9,62 @@ import (
"time"
"github.com/cenkalti/backoff"
"github.com/parnurzeal/gorequest"
"golang.org/x/xerrors"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
"github.com/parnurzeal/gorequest"
"golang.org/x/xerrors"
kevulndb "github.com/vulsio/go-kev/db"
kevulnmodels "github.com/vulsio/go-kev/models"
kevulnlog "github.com/vulsio/go-kev/utils"
)
// goKEVulnDBClient is a DB Driver
type goKEVulnDBClient struct {
driver kevulndb.DB
baseURL string
}
// closeDB close a DB connection
func (client goKEVulnDBClient) closeDB() error {
if client.driver == nil {
return nil
}
return client.driver.CloseDB()
}
func newGoKEVulnDBClient(cnf config.VulnDictInterface, o logging.LogOpts) (*goKEVulnDBClient, error) {
if err := kevulnlog.SetLogger(o.LogToFile, o.LogDir, o.Debug, o.LogJSON); err != nil {
return nil, xerrors.Errorf("Failed to set go-kev logger. err: %w", err)
}
db, err := newKEVulnDB(cnf)
if err != nil {
return nil, xerrors.Errorf("Failed to newKEVulnDB. err: %w", err)
}
return &goKEVulnDBClient{driver: db, baseURL: cnf.GetURL()}, nil
}
// FillWithKEVuln :
func FillWithKEVuln(r *models.ScanResult, cnf config.KEVulnConf) error {
if cnf.IsFetchViaHTTP() {
func FillWithKEVuln(r *models.ScanResult, cnf config.KEVulnConf, logOpts logging.LogOpts) error {
client, err := newGoKEVulnDBClient(&cnf, logOpts)
if err != nil {
return err
}
defer func() {
if err := client.closeDB(); err != nil {
logging.Log.Errorf("Failed to close DB. err: %+v", err)
}
}()
if client.driver == nil {
var cveIDs []string
for cveID := range r.ScannedCves {
cveIDs = append(cveIDs, cveID)
}
prefix, err := util.URLPathJoin(cnf.GetURL(), "cves")
prefix, err := util.URLPathJoin(client.baseURL, "cves")
if err != nil {
return err
}
@@ -57,23 +94,11 @@ func FillWithKEVuln(r *models.ScanResult, cnf config.KEVulnConf) error {
r.ScannedCves[res.request.cveID] = v
}
} else {
driver, locked, err := newKEVulnDB(&cnf)
if locked {
return xerrors.Errorf("SQLite3 is locked: %s", cnf.GetSQLite3Path())
} else if err != nil {
return err
}
defer func() {
if err := driver.CloseDB(); err != nil {
logging.Log.Errorf("Failed to close DB. err: %+v", err)
}
}()
for cveID, vuln := range r.ScannedCves {
if cveID == "" {
continue
}
kevulns, err := driver.GetKEVulnByCveID(cveID)
kevulns, err := client.driver.GetKEVulnByCveID(cveID)
if err != nil {
return err
}
@@ -196,19 +221,20 @@ func httpGetKEVuln(url string, req kevulnRequest, resChan chan<- kevulnResponse,
}
}
func newKEVulnDB(cnf config.VulnDictInterface) (driver kevulndb.DB, locked bool, err error) {
func newKEVulnDB(cnf config.VulnDictInterface) (kevulndb.DB, error) {
if cnf.IsFetchViaHTTP() {
return nil, false, nil
return nil, nil
}
path := cnf.GetURL()
if cnf.GetType() == "sqlite3" {
path = cnf.GetSQLite3Path()
}
if driver, locked, err = kevulndb.NewDB(cnf.GetType(), path, cnf.GetDebugSQL(), kevulndb.Option{}); err != nil {
driver, locked, err := kevulndb.NewDB(cnf.GetType(), path, cnf.GetDebugSQL(), kevulndb.Option{})
if err != nil {
if locked {
return nil, true, xerrors.Errorf("kevulnDB is locked. err: %w", err)
return nil, xerrors.Errorf("Failed to init kevuln DB. SQLite3: %s is locked. err: %w", cnf.GetSQLite3Path(), err)
}
return nil, false, err
return nil, xerrors.Errorf("Failed to init kevuln DB. DB Path: %s, err: %w", path, err)
}
return driver, false, nil
return driver, nil
}

View File

@@ -9,35 +9,73 @@ import (
"time"
"github.com/cenkalti/backoff"
"github.com/parnurzeal/gorequest"
"golang.org/x/xerrors"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
"github.com/parnurzeal/gorequest"
metasploitdb "github.com/vulsio/go-msfdb/db"
metasploitmodels "github.com/vulsio/go-msfdb/models"
"golang.org/x/xerrors"
metasploitlog "github.com/vulsio/go-msfdb/utils"
)
// goMetasploitDBClient is a DB Driver
type goMetasploitDBClient struct {
driver metasploitdb.DB
baseURL string
}
// closeDB close a DB connection
func (client goMetasploitDBClient) closeDB() error {
if client.driver == nil {
return nil
}
return client.driver.CloseDB()
}
func newGoMetasploitDBClient(cnf config.VulnDictInterface, o logging.LogOpts) (*goMetasploitDBClient, error) {
if err := metasploitlog.SetLogger(o.LogToFile, o.LogDir, o.Debug, o.LogJSON); err != nil {
return nil, xerrors.Errorf("Failed to set go-msfdb logger. err: %w", err)
}
db, err := newMetasploitDB(cnf)
if err != nil {
return nil, xerrors.Errorf("Failed to newMetasploitDB. err: %w", err)
}
return &goMetasploitDBClient{driver: db, baseURL: cnf.GetURL()}, nil
}
// FillWithMetasploit fills metasploit module information that has in module
func FillWithMetasploit(r *models.ScanResult, cnf config.MetasploitConf) (nMetasploitCve int, err error) {
if cnf.IsFetchViaHTTP() {
func FillWithMetasploit(r *models.ScanResult, cnf config.MetasploitConf, logOpts logging.LogOpts) (nMetasploitCve int, err error) {
client, err := newGoMetasploitDBClient(&cnf, logOpts)
if err != nil {
return 0, xerrors.Errorf("Failed to newGoMetasploitDBClient. err: %w", err)
}
defer func() {
if err := client.closeDB(); err != nil {
logging.Log.Errorf("Failed to close DB. err: %+v", err)
}
}()
if client.driver == nil {
var cveIDs []string
for cveID := range r.ScannedCves {
cveIDs = append(cveIDs, cveID)
}
prefix, err := util.URLPathJoin(cnf.GetURL(), "cves")
prefix, err := util.URLPathJoin(client.baseURL, "cves")
if err != nil {
return 0, err
return 0, xerrors.Errorf("Failed to join URLPath. err: %w", err)
}
responses, err := getMetasploitsViaHTTP(cveIDs, prefix)
if err != nil {
return 0, err
return 0, xerrors.Errorf("Failed to get Metasploits via HTTP. err: %w", err)
}
for _, res := range responses {
msfs := []metasploitmodels.Metasploit{}
if err := json.Unmarshal([]byte(res.json), &msfs); err != nil {
return 0, err
return 0, xerrors.Errorf("Failed to unmarshal json. err: %w", err)
}
metasploits := ConvertToModelsMsf(msfs)
v, ok := r.ScannedCves[res.request.cveID]
@@ -48,25 +86,13 @@ func FillWithMetasploit(r *models.ScanResult, cnf config.MetasploitConf) (nMetas
nMetasploitCve++
}
} else {
driver, locked, err := newMetasploitDB(&cnf)
if locked {
return 0, xerrors.Errorf("SQLite3 is locked: %s", cnf.GetSQLite3Path())
} else if err != nil {
return 0, err
}
defer func() {
if err := driver.CloseDB(); err != nil {
logging.Log.Errorf("Failed to close DB. err: %+v", err)
}
}()
for cveID, vuln := range r.ScannedCves {
if cveID == "" {
continue
}
ms, err := driver.GetModuleByCveID(cveID)
ms, err := client.driver.GetModuleByCveID(cveID)
if err != nil {
return 0, err
return 0, xerrors.Errorf("Failed to get Metasploits by CVE-ID. err: %w", err)
}
if len(ms) == 0 {
continue
@@ -199,19 +225,20 @@ func ConvertToModelsMsf(ms []metasploitmodels.Metasploit) (modules []models.Meta
return modules
}
func newMetasploitDB(cnf config.VulnDictInterface) (driver metasploitdb.DB, locked bool, err error) {
func newMetasploitDB(cnf config.VulnDictInterface) (metasploitdb.DB, error) {
if cnf.IsFetchViaHTTP() {
return nil, false, nil
return nil, nil
}
path := cnf.GetURL()
if cnf.GetType() == "sqlite3" {
path = cnf.GetSQLite3Path()
}
if driver, locked, err = metasploitdb.NewDB(cnf.GetType(), path, cnf.GetDebugSQL(), metasploitdb.Option{}); err != nil {
driver, locked, err := metasploitdb.NewDB(cnf.GetType(), path, cnf.GetDebugSQL(), metasploitdb.Option{})
if err != nil {
if locked {
return nil, true, xerrors.Errorf("metasploitDB is locked. err: %w", err)
return nil, xerrors.Errorf("Failed to init metasploit DB. SQLite3: %s is locked. err: %w", cnf.GetSQLite3Path(), err)
}
return nil, false, err
return nil, xerrors.Errorf("Failed to init metasploit DB. DB Path: %s, err: %w", path, err)
}
return driver, false, nil
return driver, nil
}

3
go.mod
View File

@@ -29,7 +29,6 @@ require (
github.com/gosuri/uitable v0.0.4
github.com/hashicorp/go-uuid v1.0.2
github.com/hashicorp/go-version v1.4.0
github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c
github.com/jesseduffield/gocui v0.3.0
github.com/k0kubun/pp v3.0.1+incompatible
github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f
@@ -56,7 +55,7 @@ require (
github.com/vulsio/go-kev v0.1.0
github.com/vulsio/go-msfdb v0.2.1-0.20211028071756-4a9759bd9f14
github.com/vulsio/gost v0.4.1-0.20211028071837-7ad032a6ffa8
github.com/vulsio/goval-dictionary v0.7.1-0.20220212015000-031fc960b77c
github.com/vulsio/goval-dictionary v0.7.1-0.20220215081041-a472884d0afa
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce // indirect
golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d // indirect
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8

6
go.sum
View File

@@ -999,8 +999,6 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J
github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
github.com/hashicorp/uuid v0.0.0-20160311170451-ebb0a03e909c/go.mod h1:fHzc09UnyJyqyW+bFuq864eh+wC7dj65aXmXLRe5to0=
github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c h1:aY2hhxLhjEAbfXOx2nRJxCXezC6CO2V/yN+OCr1srtk=
github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/htcat/htcat v1.0.2/go.mod h1:i8ViQbjSi2+lJzM6Lx20FIxHENCz6mzJglK3HH06W3s=
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
@@ -1763,8 +1761,8 @@ github.com/vulsio/go-msfdb v0.2.1-0.20211028071756-4a9759bd9f14 h1:2uYZw2gQ0kymw
github.com/vulsio/go-msfdb v0.2.1-0.20211028071756-4a9759bd9f14/go.mod h1:NGdcwWxCK/ES8vZ/crzREqI69S5gH1MivCpSp1pa2Rc=
github.com/vulsio/gost v0.4.1-0.20211028071837-7ad032a6ffa8 h1:jqsECpLRp1EAXGOdhPxHzqYjWP5l980GjJ8s/AUYH/4=
github.com/vulsio/gost v0.4.1-0.20211028071837-7ad032a6ffa8/go.mod h1:DaWLus8dJ4DdhVsBe5TAEEZ3IdoTMIb/z2StR4Bhb7Q=
github.com/vulsio/goval-dictionary v0.7.1-0.20220212015000-031fc960b77c h1:LV/HjQRJGhJiKq6huf6ywF09OW+btoo0Y96y01vVp7o=
github.com/vulsio/goval-dictionary v0.7.1-0.20220212015000-031fc960b77c/go.mod h1:BEvFNaiPCKwYWtITjn+hGJQT9N8WfigSd7NXHNnbxkI=
github.com/vulsio/goval-dictionary v0.7.1-0.20220215081041-a472884d0afa h1:WU96+6NY7WOPcZBt52ySI3SXd0RHnCBpSBC5F/VL4i8=
github.com/vulsio/goval-dictionary v0.7.1-0.20220215081041-a472884d0afa/go.mod h1:BEvFNaiPCKwYWtITjn+hGJQT9N8WfigSd7NXHNnbxkI=
github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug=

View File

@@ -6,12 +6,13 @@ package gost
import (
"encoding/json"
debver "github.com/knqyf263/go-deb-version"
"golang.org/x/xerrors"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
debver "github.com/knqyf263/go-deb-version"
gostmodels "github.com/vulsio/gost/models"
"golang.org/x/xerrors"
)
// Debian is Gost client for Debian GNU/Linux
@@ -67,7 +68,7 @@ func (deb Debian) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err error
}
nFixedCVEs, err := deb.detectCVEsWithFixState(r, "resolved")
if err != nil {
return 0, err
return 0, xerrors.Errorf("Failed to detect fixed CVEs. err: %w", err)
}
if stashLinuxPackage.Name != "" {
@@ -75,7 +76,7 @@ func (deb Debian) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err error
}
nUnfixedCVEs, err := deb.detectCVEsWithFixState(r, "open")
if err != nil {
return 0, err
return 0, xerrors.Errorf("Failed to detect unfixed CVEs. err: %w", err)
}
return (nFixedCVEs + nUnfixedCVEs), nil
@@ -87,22 +88,25 @@ func (deb Debian) detectCVEsWithFixState(r *models.ScanResult, fixStatus string)
}
packCvesList := []packCves{}
if deb.DBDriver.Cnf.IsFetchViaHTTP() {
url, _ := util.URLPathJoin(deb.DBDriver.Cnf.GetURL(), "debian", major(r.Release), "pkgs")
if deb.driver == nil {
url, err := util.URLPathJoin(deb.baseURL, "debian", major(r.Release), "pkgs")
if err != nil {
return 0, xerrors.Errorf("Failed to join URLPath. err: %w", err)
}
s := "unfixed-cves"
if s == "resolved" {
s = "fixed-cves"
}
responses, err := getCvesWithFixStateViaHTTP(r, url, s)
if err != nil {
return 0, err
return 0, xerrors.Errorf("Failed to get CVEs via HTTP. err: %w", err)
}
for _, res := range responses {
debCves := map[string]gostmodels.DebianCVE{}
if err := json.Unmarshal([]byte(res.json), &debCves); err != nil {
return 0, err
return 0, xerrors.Errorf("Failed to unmarshal json. err: %w", err)
}
cves := []models.CveContent{}
fixes := []models.PackageFixStatus{}
@@ -118,13 +122,10 @@ func (deb Debian) detectCVEsWithFixState(r *models.ScanResult, fixStatus string)
})
}
} else {
if deb.DBDriver.DB == nil {
return 0, nil
}
for _, pack := range r.Packages {
cves, fixes, err := deb.getCvesDebianWithfixStatus(fixStatus, major(r.Release), pack.Name)
if err != nil {
return 0, err
return 0, xerrors.Errorf("Failed to get CVEs for Package. err: %w", err)
}
packCvesList = append(packCvesList, packCves{
packName: pack.Name,
@@ -138,7 +139,7 @@ func (deb Debian) detectCVEsWithFixState(r *models.ScanResult, fixStatus string)
for _, pack := range r.SrcPackages {
cves, fixes, err := deb.getCvesDebianWithfixStatus(fixStatus, major(r.Release), pack.Name)
if err != nil {
return 0, err
return 0, xerrors.Errorf("Failed to get CVEs for SrcPackage. err: %w", err)
}
packCvesList = append(packCvesList, packCves{
packName: pack.Name,
@@ -239,11 +240,11 @@ func (deb Debian) detectCVEsWithFixState(r *models.ScanResult, fixStatus string)
func isGostDefAffected(versionRelease, gostVersion string) (affected bool, err error) {
vera, err := debver.NewVersion(versionRelease)
if err != nil {
return false, err
return false, xerrors.Errorf("Failed to parse version. version: %s, err: %w", versionRelease, err)
}
verb, err := debver.NewVersion(gostVersion)
if err != nil {
return false, err
return false, xerrors.Errorf("Failed to parse version. version: %s, err: %w", gostVersion, err)
}
return vera.LessThan(verb), nil
}
@@ -251,13 +252,13 @@ func isGostDefAffected(versionRelease, gostVersion string) (affected bool, err e
func (deb Debian) getCvesDebianWithfixStatus(fixStatus, release, pkgName string) ([]models.CveContent, []models.PackageFixStatus, error) {
var f func(string, string) (map[string]gostmodels.DebianCVE, error)
if fixStatus == "resolved" {
f = deb.DBDriver.DB.GetFixedCvesDebian
f = deb.driver.GetFixedCvesDebian
} else {
f = deb.DBDriver.DB.GetUnfixedCvesDebian
f = deb.driver.GetUnfixedCvesDebian
}
debCves, err := f(release, pkgName)
if err != nil {
return nil, nil, err
return nil, nil, xerrors.Errorf("Failed to get CVEs. fixStatus: %s, release: %s, src package: %s, err: %w", fixStatus, release, pkgName, err)
}
cves := []models.CveContent{}

View File

@@ -4,22 +4,17 @@
package gost
import (
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
"github.com/vulsio/gost/db"
"golang.org/x/xerrors"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
gostdb "github.com/vulsio/gost/db"
gostlog "github.com/vulsio/gost/util"
)
// DBDriver is a DB Driver
type DBDriver struct {
DB db.DB
Cnf config.VulnDictInterface
}
// Client is the interface of OVAL client.
// Client is the interface of Gost client.
type Client interface {
DetectCVEs(*models.ScanResult, bool) (int, error)
CloseDB() error
@@ -27,74 +22,79 @@ type Client interface {
// Base is a base struct
type Base struct {
DBDriver DBDriver
driver gostdb.DB
baseURL string
}
// CloseDB close a DB connection
func (b Base) CloseDB() error {
if b.DBDriver.DB == nil {
if b.driver == nil {
return nil
}
return b.DBDriver.DB.CloseDB()
return b.driver.CloseDB()
}
// FillCVEsWithRedHat fills CVE detailed with Red Hat Security
func FillCVEsWithRedHat(r *models.ScanResult, cnf config.GostConf) error {
db, locked, err := newGostDB(cnf)
if locked {
return xerrors.Errorf("SQLite3 is locked: %s", cnf.GetSQLite3Path())
} else if err != nil {
func FillCVEsWithRedHat(r *models.ScanResult, cnf config.GostConf, o logging.LogOpts) error {
if err := gostlog.SetLogger(o.LogToFile, o.LogDir, o.Debug, o.LogJSON); err != nil {
return err
}
db, err := newGostDB(&cnf)
if err != nil {
return xerrors.Errorf("Failed to newGostDB. err: %w", err)
}
client := RedHat{Base{driver: db, baseURL: cnf.GetURL()}}
defer func() {
if db != nil {
if err := db.CloseDB(); err != nil {
logging.Log.Errorf("Failed to close DB. err: %+v", err)
}
if err := client.CloseDB(); err != nil {
logging.Log.Errorf("Failed to close DB. err: %+v", err)
}
}()
return RedHat{Base{DBDriver{DB: db, Cnf: &cnf}}}.fillCvesWithRedHatAPI(r)
return client.fillCvesWithRedHatAPI(r)
}
// NewClient make Client by family
func NewClient(cnf config.GostConf, family string) (Client, error) {
db, locked, err := newGostDB(cnf)
if locked {
return nil, xerrors.Errorf("SQLite3 is locked: %s", cnf.GetSQLite3Path())
} else if err != nil {
return nil, err
func NewGostClient(cnf config.GostConf, family string, o logging.LogOpts) (Client, error) {
if err := gostlog.SetLogger(o.LogToFile, o.LogDir, o.Debug, o.LogJSON); err != nil {
return nil, xerrors.Errorf("Failed to set gost logger. err: %w", err)
}
driver := DBDriver{DB: db, Cnf: &cnf}
db, err := newGostDB(&cnf)
if err != nil {
return nil, xerrors.Errorf("Failed to newGostDB. err: %w", err)
}
base := Base{driver: db, baseURL: cnf.GetURL()}
switch family {
case constant.RedHat, constant.CentOS, constant.Rocky, constant.Alma:
return RedHat{Base{DBDriver: driver}}, nil
return RedHat{base}, nil
case constant.Debian, constant.Raspbian:
return Debian{Base{DBDriver: driver}}, nil
return Debian{base}, nil
case constant.Ubuntu:
return Ubuntu{Base{DBDriver: driver}}, nil
return Ubuntu{base}, nil
case constant.Windows:
return Microsoft{Base{DBDriver: driver}}, nil
return Microsoft{base}, nil
default:
return Pseudo{Base{DBDriver: driver}}, nil
return Pseudo{base}, nil
}
}
// NewGostDB returns db client for Gost
func newGostDB(cnf config.GostConf) (driver db.DB, locked bool, err error) {
func newGostDB(cnf config.VulnDictInterface) (gostdb.DB, error) {
if cnf.IsFetchViaHTTP() {
return nil, false, nil
return nil, nil
}
path := cnf.GetURL()
if cnf.GetType() == "sqlite3" {
path = cnf.GetSQLite3Path()
}
if driver, locked, err = db.NewDB(cnf.GetType(), path, cnf.GetDebugSQL(), db.Option{}); err != nil {
driver, locked, err := gostdb.NewDB(cnf.GetType(), path, cnf.GetDebugSQL(), gostdb.Option{})
if err != nil {
if locked {
return nil, true, xerrors.Errorf("gostDB is locked. err: %w", err)
return nil, xerrors.Errorf("Failed to init gost DB. SQLite3: %s is locked. err: %w", cnf.GetSQLite3Path(), err)
}
return nil, false, err
return nil, xerrors.Errorf("Failed to init gost DB. DB Path: %s, err: %w", path, err)
}
return driver, false, nil
return driver, nil
}

View File

@@ -18,14 +18,14 @@ type Microsoft struct {
// DetectCVEs fills cve information that has in Gost
func (ms Microsoft) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err error) {
if ms.DBDriver.DB == nil {
if ms.driver == nil {
return 0, nil
}
cveIDs := []string{}
for cveID := range r.ScannedCves {
cveIDs = append(cveIDs, cveID)
}
msCves, err := ms.DBDriver.DB.GetMicrosoftMulti(cveIDs)
msCves, err := ms.driver.GetMicrosoftMulti(cveIDs)
if err != nil {
return 0, nil
}
@@ -34,7 +34,7 @@ func (ms Microsoft) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err err
continue
}
cveCont, mitigations := ms.ConvertToModel(&msCve)
v, _ := r.ScannedCves[cveID]
v := r.ScannedCves[cveID]
if v.CveContents == nil {
v.CveContents = models.CveContents{}
}

View File

@@ -7,7 +7,7 @@ import (
"github.com/future-architect/vuls/models"
)
// Pseudo is Gost client except for RedHat family and Debian
// Pseudo is Gost client except for RedHat family, Debian, Ubuntu and Windows
type Pseudo struct {
Base
}

View File

@@ -8,7 +8,8 @@ import (
"strconv"
"strings"
"github.com/future-architect/vuls/config"
"golang.org/x/xerrors"
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
@@ -26,17 +27,20 @@ func (red RedHat) DetectCVEs(r *models.ScanResult, ignoreWillNotFix bool) (nCVEs
if r.Family == constant.CentOS {
gostRelease = strings.TrimPrefix(r.Release, "stream")
}
if red.DBDriver.Cnf.IsFetchViaHTTP() {
prefix, _ := util.URLPathJoin(red.DBDriver.Cnf.GetURL(), "redhat", major(gostRelease), "pkgs")
if red.driver == nil {
prefix, err := util.URLPathJoin(red.baseURL, "redhat", major(gostRelease), "pkgs")
if err != nil {
return 0, xerrors.Errorf("Failed to join URLPath. err: %w", err)
}
responses, err := getAllUnfixedCvesViaHTTP(r, prefix)
if err != nil {
return 0, err
return 0, xerrors.Errorf("Failed to get Unfixed CVEs via HTTP. err: %w", err)
}
for _, res := range responses {
// CVE-ID: RedhatCVE
cves := map[string]gostmodels.RedhatCVE{}
if err := json.Unmarshal([]byte(res.json), &cves); err != nil {
return 0, err
return 0, xerrors.Errorf("Failed to unmarshal json. err: %w", err)
}
for _, cve := range cves {
if newly := red.setUnfixedCveToScanResult(&cve, r); newly {
@@ -45,14 +49,11 @@ func (red RedHat) DetectCVEs(r *models.ScanResult, ignoreWillNotFix bool) (nCVEs
}
}
} else {
if red.DBDriver.DB == nil {
return 0, nil
}
for _, pack := range r.Packages {
// CVE-ID: RedhatCVE
cves, err := red.DBDriver.DB.GetUnfixedCvesRedhat(major(gostRelease), pack.Name, ignoreWillNotFix)
cves, err := red.driver.GetUnfixedCvesRedhat(major(gostRelease), pack.Name, ignoreWillNotFix)
if err != nil {
return 0, err
return 0, xerrors.Errorf("Failed to get Unfixed CVEs. err: %w", err)
}
for _, cve := range cves {
if newly := red.setUnfixedCveToScanResult(&cve, r); newly {
@@ -73,8 +74,11 @@ func (red RedHat) fillCvesWithRedHatAPI(r *models.ScanResult) error {
cveIDs = append(cveIDs, cveID)
}
if red.DBDriver.Cnf.IsFetchViaHTTP() {
prefix, _ := util.URLPathJoin(config.Conf.Gost.URL, "redhat", "cves")
if red.driver == nil {
prefix, err := util.URLPathJoin(red.baseURL, "redhat", "cves")
if err != nil {
return err
}
responses, err := getCvesViaHTTP(cveIDs, prefix)
if err != nil {
return err
@@ -90,10 +94,7 @@ func (red RedHat) fillCvesWithRedHatAPI(r *models.ScanResult) error {
red.setFixedCveToScanResult(&redCve, r)
}
} else {
if red.DBDriver.DB == nil {
return nil
}
redCves, err := red.DBDriver.DB.GetRedhatMulti(cveIDs)
redCves, err := red.driver.GetRedhatMulti(cveIDs)
if err != nil {
return err
}

View File

@@ -7,6 +7,8 @@ import (
"encoding/json"
"strings"
"golang.org/x/xerrors"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
@@ -53,17 +55,20 @@ func (ubu Ubuntu) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err error
}
packCvesList := []packCves{}
if ubu.DBDriver.Cnf.IsFetchViaHTTP() {
url, _ := util.URLPathJoin(ubu.DBDriver.Cnf.GetURL(), "ubuntu", ubuReleaseVer, "pkgs")
if ubu.driver == nil {
url, err := util.URLPathJoin(ubu.baseURL, "ubuntu", ubuReleaseVer, "pkgs")
if err != nil {
return 0, xerrors.Errorf("Failed to join URLPath. err: %w", err)
}
responses, err := getAllUnfixedCvesViaHTTP(r, url)
if err != nil {
return 0, err
return 0, xerrors.Errorf("Failed to get Unfixed CVEs via HTTP. err: %w", err)
}
for _, res := range responses {
ubuCves := map[string]gostmodels.UbuntuCVE{}
if err := json.Unmarshal([]byte(res.json), &ubuCves); err != nil {
return 0, err
return 0, xerrors.Errorf("Failed to unmarshal json. err: %w", err)
}
cves := []models.CveContent{}
for _, ubucve := range ubuCves {
@@ -76,13 +81,10 @@ func (ubu Ubuntu) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err error
})
}
} else {
if ubu.DBDriver.DB == nil {
return 0, nil
}
for _, pack := range r.Packages {
ubuCves, err := ubu.DBDriver.DB.GetUnfixedCvesUbuntu(ubuReleaseVer, pack.Name)
ubuCves, err := ubu.driver.GetUnfixedCvesUbuntu(ubuReleaseVer, pack.Name)
if err != nil {
return 0, nil
return 0, xerrors.Errorf("Failed to get Unfixed CVEs For Package. err: %w", err)
}
cves := []models.CveContent{}
for _, ubucve := range ubuCves {
@@ -97,9 +99,9 @@ func (ubu Ubuntu) DetectCVEs(r *models.ScanResult, _ bool) (nCVEs int, err error
// SrcPack
for _, pack := range r.SrcPackages {
ubuCves, err := ubu.DBDriver.DB.GetUnfixedCvesUbuntu(ubuReleaseVer, pack.Name)
ubuCves, err := ubu.driver.GetUnfixedCvesUbuntu(ubuReleaseVer, pack.Name)
if err != nil {
return 0, nil
return 0, xerrors.Errorf("Failed to get Unfixed CVEs For SrcPackage. err: %w", err)
}
cves := []models.CveContent{}
for _, ubucve := range ubuCves {

View File

@@ -4,10 +4,12 @@
package oval
import (
"github.com/future-architect/vuls/config"
"golang.org/x/xerrors"
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
ovaldb "github.com/vulsio/goval-dictionary/db"
)
// Alpine is the struct of Alpine Linux
@@ -16,11 +18,12 @@ type Alpine struct {
}
// NewAlpine creates OVAL client for SUSE
func NewAlpine(cnf config.VulnDictInterface) Alpine {
func NewAlpine(driver ovaldb.DB, baseURL string) Alpine {
return Alpine{
Base{
family: constant.Alpine,
Cnf: cnf,
driver: driver,
baseURL: baseURL,
family: constant.Alpine,
},
}
}
@@ -28,23 +31,13 @@ func NewAlpine(cnf config.VulnDictInterface) Alpine {
// FillWithOval returns scan result after updating CVE info by OVAL
func (o Alpine) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
var relatedDefs ovalResult
if o.Cnf.IsFetchViaHTTP() {
if relatedDefs, err = getDefsByPackNameViaHTTP(r, o.Cnf.GetURL()); err != nil {
return 0, err
if o.driver == nil {
if relatedDefs, err = getDefsByPackNameViaHTTP(r, o.baseURL); err != nil {
return 0, xerrors.Errorf("Failed to get Definitions via HTTP. err: %w", err)
}
} else {
driver, err := newOvalDB(o.Cnf)
if err != nil {
return 0, err
}
defer func() {
if err := driver.CloseDB(); err != nil {
logging.Log.Errorf("Failed to close DB. err: %+v", err)
}
}()
if relatedDefs, err = getDefsByPackNameFromOvalDB(driver, r); err != nil {
return 0, err
if relatedDefs, err = getDefsByPackNameFromOvalDB(r, o.driver); err != nil {
return 0, xerrors.Errorf("Failed to get Definitions from DB. err: %w", err)
}
}
for _, defPacks := range relatedDefs.entries {

View File

@@ -7,11 +7,13 @@ import (
"fmt"
"strings"
"github.com/future-architect/vuls/config"
"golang.org/x/xerrors"
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
ovaldb "github.com/vulsio/goval-dictionary/db"
ovalmodels "github.com/vulsio/goval-dictionary/models"
)
@@ -122,12 +124,13 @@ type Debian struct {
}
// NewDebian creates OVAL client for Debian
func NewDebian(cnf config.VulnDictInterface) Debian {
func NewDebian(driver ovaldb.DB, baseURL string) Debian {
return Debian{
DebianBase{
Base{
family: constant.Debian,
Cnf: cnf,
driver: driver,
baseURL: baseURL,
family: constant.Debian,
},
},
}
@@ -157,23 +160,13 @@ func (o Debian) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
}
var relatedDefs ovalResult
if o.Cnf.IsFetchViaHTTP() {
if relatedDefs, err = getDefsByPackNameViaHTTP(r, o.Cnf.GetURL()); err != nil {
return 0, err
if o.driver == nil {
if relatedDefs, err = getDefsByPackNameViaHTTP(r, o.baseURL); err != nil {
return 0, xerrors.Errorf("Failed to get Definitions via HTTP. err: %w", err)
}
} else {
driver, err := newOvalDB(o.Cnf)
if err != nil {
return 0, err
}
defer func() {
if err := driver.CloseDB(); err != nil {
logging.Log.Errorf("Failed to close DB. err: %+v", err)
}
}()
if relatedDefs, err = getDefsByPackNameFromOvalDB(driver, r); err != nil {
return 0, err
if relatedDefs, err = getDefsByPackNameFromOvalDB(r, o.driver); err != nil {
return 0, xerrors.Errorf("Failed to get Definitions from DB. err: %w", err)
}
}
@@ -213,12 +206,13 @@ type Ubuntu struct {
}
// NewUbuntu creates OVAL client for Debian
func NewUbuntu(cnf config.VulnDictInterface) Ubuntu {
func NewUbuntu(driver ovaldb.DB, baseURL string) Ubuntu {
return Ubuntu{
DebianBase{
Base{
family: constant.Ubuntu,
Cnf: cnf,
driver: driver,
baseURL: baseURL,
family: constant.Ubuntu,
},
},
}
@@ -471,23 +465,13 @@ func (o Ubuntu) fillWithOval(r *models.ScanResult, kernelNamesInOval []string) (
}
var relatedDefs ovalResult
if o.Cnf.IsFetchViaHTTP() {
if relatedDefs, err = getDefsByPackNameViaHTTP(r, o.Cnf.GetURL()); err != nil {
return 0, err
if o.driver == nil {
if relatedDefs, err = getDefsByPackNameViaHTTP(r, o.baseURL); err != nil {
return 0, xerrors.Errorf("Failed to get Definitions via HTTP. err: %w", err)
}
} else {
driver, err := newOvalDB(o.Cnf)
if err != nil {
return 0, err
}
defer func() {
if err := driver.CloseDB(); err != nil {
logging.Log.Errorf("Failed to close DB. err: %+v", err)
}
}()
if relatedDefs, err = getDefsByPackNameFromOvalDB(driver, r); err != nil {
return 0, err
if relatedDefs, err = getDefsByPackNameFromOvalDB(r, o.driver); err != nil {
return 0, xerrors.Errorf("Failed to get Definitions from DB. err: %w", err)
}
}

View File

@@ -8,14 +8,15 @@ import (
"strings"
"time"
"github.com/parnurzeal/gorequest"
"golang.org/x/xerrors"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
"github.com/parnurzeal/gorequest"
"github.com/vulsio/goval-dictionary/db"
"golang.org/x/xerrors"
ovaldb "github.com/vulsio/goval-dictionary/db"
)
// Client is the interface of OVAL client.
@@ -23,51 +24,56 @@ type Client interface {
FillWithOval(*models.ScanResult) (int, error)
CheckIfOvalFetched(string, string) (bool, error)
CheckIfOvalFresh(string, string) (bool, error)
CloseDB() error
}
// Base is a base struct
type Base struct {
family string
Cnf config.VulnDictInterface
driver ovaldb.DB
baseURL string
family string
}
// CloseDB close a DB connection
func (b Base) CloseDB() error {
if b.driver == nil {
return nil
}
return b.driver.CloseDB()
}
// CheckIfOvalFetched checks if oval entries are in DB by family, release.
func (b Base) CheckIfOvalFetched(osFamily, release string) (fetched bool, err error) {
func (b Base) CheckIfOvalFetched(osFamily, release string) (bool, error) {
ovalFamily, err := GetFamilyInOval(osFamily)
if err != nil {
return false, xerrors.Errorf("Failed to GetFamilyInOval. err: %w", err)
}
if ovalFamily == "" {
return false, nil
}
ovalRelease := release
if osFamily == constant.CentOS {
ovalRelease = strings.TrimPrefix(release, "stream")
}
if !b.Cnf.IsFetchViaHTTP() {
driver, err := newOvalDB(b.Cnf)
if err != nil {
return false, err
}
defer func() {
if err := driver.CloseDB(); err != nil {
logging.Log.Errorf("Failed to close DB. err: %+v", err)
}
}()
count, err := driver.CountDefs(ovalFamily, ovalRelease)
var count int
if b.driver == nil {
url, err := util.URLPathJoin(b.baseURL, "count", ovalFamily, ovalRelease)
if err != nil {
return false, xerrors.Errorf("Failed to join URLPath. err: %w", err)
}
resp, body, errs := gorequest.New().Timeout(10 * time.Second).Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return false, xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %+v", url, resp, errs)
}
if err := json.Unmarshal([]byte(body), &count); err != nil {
return false, xerrors.Errorf("Failed to Unmarshal. body: %s, err: %w", body, err)
}
} else {
count, err = b.driver.CountDefs(ovalFamily, ovalRelease)
if err != nil {
return false, xerrors.Errorf("Failed to count OVAL defs: %s, %s, %w", ovalFamily, ovalRelease, err)
}
logging.Log.Infof("OVAL %s %s found. defs: %d", ovalFamily, ovalRelease, count)
return 0 < count, nil
}
url, _ := util.URLPathJoin(config.Conf.OvalDict.URL, "count", ovalFamily, ovalRelease)
resp, body, errs := gorequest.New().Timeout(10 * time.Second).Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return false, xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %+v", url, resp, errs)
}
count := 0
if err := json.Unmarshal([]byte(body), &count); err != nil {
return false, xerrors.Errorf("Failed to Unmarshal. body: %s, err: %w", body, err)
}
logging.Log.Infof("OVAL %s %s found. defs: %d", ovalFamily, ovalRelease, count)
return 0 < count, nil
@@ -79,35 +85,32 @@ func (b Base) CheckIfOvalFresh(osFamily, release string) (ok bool, err error) {
if err != nil {
return false, xerrors.Errorf("Failed to GetFamilyInOval. err: %w", err)
}
if ovalFamily == "" {
return false, nil
}
ovalRelease := release
if osFamily == constant.CentOS {
ovalRelease = strings.TrimPrefix(release, "stream")
}
var lastModified time.Time
if !b.Cnf.IsFetchViaHTTP() {
driver, err := newOvalDB(b.Cnf)
if b.driver == nil {
url, err := util.URLPathJoin(b.baseURL, "lastmodified", ovalFamily, ovalRelease)
if err != nil {
return false, err
return false, xerrors.Errorf("Failed to join URLPath. err: %w", err)
}
defer func() {
if err := driver.CloseDB(); err != nil {
logging.Log.Errorf("Failed to close DB. err: %+v", err)
}
}()
lastModified, err = driver.GetLastModified(ovalFamily, ovalRelease)
if err != nil {
return false, xerrors.Errorf("Failed to GetLastModified: %w", err)
}
} else {
url, _ := util.URLPathJoin(config.Conf.OvalDict.URL, "lastmodified", ovalFamily, ovalRelease)
resp, body, errs := gorequest.New().Timeout(10 * time.Second).Get(url).End()
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
return false, xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %+v", url, resp, errs)
}
if err := json.Unmarshal([]byte(body), &lastModified); err != nil {
return false, xerrors.Errorf("Failed to Unmarshal. body: %s, err: %w", body, err)
}
} else {
lastModified, err = b.driver.GetLastModified(ovalFamily, ovalRelease)
if err != nil {
return false, xerrors.Errorf("Failed to GetLastModified: %w", err)
}
}
since := time.Now()
@@ -122,23 +125,20 @@ func (b Base) CheckIfOvalFresh(osFamily, release string) (ok bool, err error) {
}
// NewOvalDB returns oval db client
func newOvalDB(cnf config.VulnDictInterface) (driver db.DB, err error) {
func newOvalDB(cnf config.VulnDictInterface) (ovaldb.DB, error) {
if cnf.IsFetchViaHTTP() {
return nil, nil
}
path := cnf.GetURL()
if cnf.GetType() == "sqlite3" {
path = cnf.GetSQLite3Path()
}
driver, locked, err := db.NewDB(cnf.GetType(), path, cnf.GetDebugSQL(), db.Option{})
driver, locked, err := ovaldb.NewDB(cnf.GetType(), path, cnf.GetDebugSQL(), ovaldb.Option{})
if err != nil {
if locked {
err = xerrors.Errorf("SQLite3: %s is locked. err: %w", cnf.GetSQLite3Path(), err)
return nil, xerrors.Errorf("Failed to init OVAL DB. SQLite3: %s is locked. err: %w, ", cnf.GetSQLite3Path(), err)
}
err = xerrors.Errorf("Failed to new OVAL DB. err: %w", err)
return nil, err
return nil, xerrors.Errorf("Failed to init OVAL DB. DB Path: %s, err: %w", path, err)
}
return driver, nil
}

23
oval/pseudo.go Normal file
View File

@@ -0,0 +1,23 @@
package oval
import "github.com/future-architect/vuls/models"
// Pseudo is OVAL client for Windows, FreeBSD and Pseudo
type Pseudo struct {
Base
}
// NewPseudo creates OVAL client for Windows, FreeBSD and Pseudo
func NewPseudo(family string) Pseudo {
return Pseudo{
Base{
driver: nil,
baseURL: "",
family: family,
},
}
}
func (pse Pseudo) FillWithOval(_ *models.ScanResult) (int, error) {
return 0, nil
}

View File

@@ -7,10 +7,12 @@ import (
"fmt"
"strings"
"github.com/future-architect/vuls/config"
"golang.org/x/xerrors"
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
ovaldb "github.com/vulsio/goval-dictionary/db"
ovalmodels "github.com/vulsio/goval-dictionary/models"
)
@@ -22,23 +24,13 @@ type RedHatBase struct {
// FillWithOval returns scan result after updating CVE info by OVAL
func (o RedHatBase) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
var relatedDefs ovalResult
if o.Cnf.IsFetchViaHTTP() {
if relatedDefs, err = getDefsByPackNameViaHTTP(r, o.Cnf.GetURL()); err != nil {
return 0, err
if o.driver == nil {
if relatedDefs, err = getDefsByPackNameViaHTTP(r, o.baseURL); err != nil {
return 0, xerrors.Errorf("Failed to get Definitions via HTTP. err: %w", err)
}
} else {
driver, err := newOvalDB(o.Cnf)
if err != nil {
return 0, err
}
defer func() {
if err := driver.CloseDB(); err != nil {
logging.Log.Errorf("Failed to close DB. err: %+v", err)
}
}()
if relatedDefs, err = getDefsByPackNameFromOvalDB(driver, r); err != nil {
return 0, err
if relatedDefs, err = getDefsByPackNameFromOvalDB(r, o.driver); err != nil {
return 0, xerrors.Errorf("Failed to get Definitions from DB. err: %w", err)
}
}
@@ -267,12 +259,13 @@ type RedHat struct {
}
// NewRedhat creates OVAL client for Redhat
func NewRedhat(cnf config.VulnDictInterface) RedHat {
func NewRedhat(driver ovaldb.DB, baseURL string) RedHat {
return RedHat{
RedHatBase{
Base{
family: constant.RedHat,
Cnf: cnf,
driver: driver,
baseURL: baseURL,
family: constant.RedHat,
},
},
}
@@ -284,12 +277,13 @@ type CentOS struct {
}
// NewCentOS creates OVAL client for CentOS
func NewCentOS(cnf config.VulnDictInterface) CentOS {
func NewCentOS(driver ovaldb.DB, baseURL string) CentOS {
return CentOS{
RedHatBase{
Base{
family: constant.CentOS,
Cnf: cnf,
driver: driver,
baseURL: baseURL,
family: constant.CentOS,
},
},
}
@@ -301,12 +295,13 @@ type Oracle struct {
}
// NewOracle creates OVAL client for Oracle
func NewOracle(cnf config.VulnDictInterface) Oracle {
func NewOracle(driver ovaldb.DB, baseURL string) Oracle {
return Oracle{
RedHatBase{
Base{
family: constant.Oracle,
Cnf: cnf,
driver: driver,
baseURL: baseURL,
family: constant.Oracle,
},
},
}
@@ -319,12 +314,13 @@ type Amazon struct {
}
// NewAmazon creates OVAL client for Amazon Linux
func NewAmazon(cnf config.VulnDictInterface) Amazon {
func NewAmazon(driver ovaldb.DB, baseURL string) Amazon {
return Amazon{
RedHatBase{
Base{
family: constant.Amazon,
Cnf: cnf,
driver: driver,
baseURL: baseURL,
family: constant.Amazon,
},
},
}
@@ -337,12 +333,13 @@ type Alma struct {
}
// NewAlma creates OVAL client for Alma Linux
func NewAlma(cnf config.VulnDictInterface) Alma {
func NewAlma(driver ovaldb.DB, baseURL string) Alma {
return Alma{
RedHatBase{
Base{
family: constant.Alma,
Cnf: cnf,
driver: driver,
baseURL: baseURL,
family: constant.Alma,
},
},
}
@@ -355,12 +352,13 @@ type Rocky struct {
}
// NewRocky creates OVAL client for Rocky Linux
func NewRocky(cnf config.VulnDictInterface) Rocky {
func NewRocky(driver ovaldb.DB, baseURL string) Rocky {
return Rocky{
RedHatBase{
Base{
family: constant.Rocky,
Cnf: cnf,
driver: driver,
baseURL: baseURL,
family: constant.Rocky,
},
},
}
@@ -373,12 +371,13 @@ type Fedora struct {
}
// NewFedora creates OVAL client for Fedora Linux
func NewFedora(cnf config.VulnDictInterface) Fedora {
func NewFedora(driver ovaldb.DB, baseURL string) Fedora {
return Fedora{
RedHatBase{
Base{
family: constant.Fedora,
Cnf: cnf,
driver: driver,
baseURL: baseURL,
family: constant.Fedora,
},
},
}

View File

@@ -6,9 +6,11 @@ package oval
import (
"fmt"
"github.com/future-architect/vuls/config"
"golang.org/x/xerrors"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
ovaldb "github.com/vulsio/goval-dictionary/db"
ovalmodels "github.com/vulsio/goval-dictionary/models"
)
@@ -18,11 +20,13 @@ type SUSE struct {
}
// NewSUSE creates OVAL client for SUSE
func NewSUSE(cnf config.VulnDictInterface, family string) SUSE {
func NewSUSE(driver ovaldb.DB, baseURL, family string) SUSE {
// TODO implement other family
return SUSE{
Base{
family: family,
Cnf: cnf,
driver: driver,
baseURL: baseURL,
family: family,
},
}
}
@@ -30,23 +34,13 @@ func NewSUSE(cnf config.VulnDictInterface, family string) SUSE {
// FillWithOval returns scan result after updating CVE info by OVAL
func (o SUSE) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
var relatedDefs ovalResult
if o.Cnf.IsFetchViaHTTP() {
if relatedDefs, err = getDefsByPackNameViaHTTP(r, o.Cnf.GetURL()); err != nil {
return 0, err
if o.driver == nil {
if relatedDefs, err = getDefsByPackNameViaHTTP(r, o.baseURL); err != nil {
return 0, xerrors.Errorf("Failed to get Definitions via HTTP. err: %w", err)
}
} else {
driver, err := newOvalDB(o.Cnf)
if err != nil {
return 0, err
}
defer func() {
if err := driver.CloseDB(); err != nil {
logging.Log.Errorf("Failed to close DB. err: %+v", err)
}
}()
if relatedDefs, err = getDefsByPackNameFromOvalDB(driver, r); err != nil {
return 0, err
if relatedDefs, err = getDefsByPackNameFromOvalDB(r, o.driver); err != nil {
return 0, xerrors.Errorf("Failed to get Definitions from DB. err: %w", err)
}
}
for _, defPacks := range relatedDefs.entries {

View File

@@ -14,18 +14,20 @@ import (
"time"
"github.com/cenkalti/backoff"
apkver "github.com/knqyf263/go-apk-version"
debver "github.com/knqyf263/go-deb-version"
rpmver "github.com/knqyf263/go-rpm-version"
"github.com/parnurzeal/gorequest"
"golang.org/x/xerrors"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/constant"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/models"
"github.com/future-architect/vuls/util"
apkver "github.com/knqyf263/go-apk-version"
debver "github.com/knqyf263/go-deb-version"
rpmver "github.com/knqyf263/go-rpm-version"
"github.com/parnurzeal/gorequest"
"github.com/vulsio/goval-dictionary/db"
ovaldb "github.com/vulsio/goval-dictionary/db"
ovallog "github.com/vulsio/goval-dictionary/log"
ovalmodels "github.com/vulsio/goval-dictionary/models"
"golang.org/x/xerrors"
)
type ovalResult struct {
@@ -245,7 +247,7 @@ func httpGet(url string, req request, resChan chan<- response, errChan chan<- er
}
}
func getDefsByPackNameFromOvalDB(driver db.DB, r *models.ScanResult) (relatedDefs ovalResult, err error) {
func getDefsByPackNameFromOvalDB(r *models.ScanResult, driver ovaldb.DB) (relatedDefs ovalResult, err error) {
requests := []request{}
for _, pack := range r.Packages {
requests = append(requests, request{
@@ -441,22 +443,22 @@ func lessThan(family, newVer string, packInOVAL ovalmodels.Package) (bool, error
constant.Raspbian:
vera, err := debver.NewVersion(newVer)
if err != nil {
return false, err
return false, xerrors.Errorf("Failed to parse version. version: %s, err: %w", newVer, err)
}
verb, err := debver.NewVersion(packInOVAL.Version)
if err != nil {
return false, err
return false, xerrors.Errorf("Failed to parse version. version: %s, err: %w", packInOVAL.Version, err)
}
return vera.LessThan(verb), nil
case constant.Alpine:
vera, err := apkver.NewVersion(newVer)
if err != nil {
return false, err
return false, xerrors.Errorf("Failed to parse version. version: %s, err: %w", newVer, err)
}
verb, err := apkver.NewVersion(packInOVAL.Version)
if err != nil {
return false, err
return false, xerrors.Errorf("Failed to parse version. version: %s, err: %w", packInOVAL.Version, err)
}
return vera.LessThan(verb), nil
@@ -491,40 +493,49 @@ func rhelRebuildOSVersionToRHEL(ver string) string {
}
// NewOVALClient returns a client for OVAL database
func NewOVALClient(family string, cnf config.GovalDictConf) (Client, error) {
func NewOVALClient(family string, cnf config.GovalDictConf, o logging.LogOpts) (Client, error) {
if err := ovallog.SetLogger(o.LogToFile, o.LogDir, o.Debug, o.LogJSON); err != nil {
return nil, xerrors.Errorf("Failed to set goval-dictionary logger. err: %w", err)
}
driver, err := newOvalDB(&cnf)
if err != nil {
return nil, xerrors.Errorf("Failed to newOvalDB. err: %w", err)
}
switch family {
case constant.Debian, constant.Raspbian:
return NewDebian(&cnf), nil
return NewDebian(driver, cnf.GetURL()), nil
case constant.Ubuntu:
return NewUbuntu(&cnf), nil
return NewUbuntu(driver, cnf.GetURL()), nil
case constant.RedHat:
return NewRedhat(&cnf), nil
return NewRedhat(driver, cnf.GetURL()), nil
case constant.CentOS:
return NewCentOS(&cnf), nil
return NewCentOS(driver, cnf.GetURL()), nil
case constant.Alma:
return NewAlma(&cnf), nil
return NewAlma(driver, cnf.GetURL()), nil
case constant.Rocky:
return NewRocky(&cnf), nil
return NewRocky(driver, cnf.GetURL()), nil
case constant.Oracle:
return NewOracle(&cnf), nil
return NewOracle(driver, cnf.GetURL()), nil
case constant.OpenSUSE:
return NewSUSE(&cnf, constant.OpenSUSE), nil
return NewSUSE(driver, cnf.GetURL(), constant.OpenSUSE), nil
case constant.OpenSUSELeap:
return NewSUSE(&cnf, constant.OpenSUSELeap), nil
return NewSUSE(driver, cnf.GetURL(), constant.OpenSUSELeap), nil
case constant.SUSEEnterpriseServer:
return NewSUSE(&cnf, constant.SUSEEnterpriseServer), nil
return NewSUSE(driver, cnf.GetURL(), constant.SUSEEnterpriseServer), nil
case constant.SUSEEnterpriseDesktop:
return NewSUSE(&cnf, constant.SUSEEnterpriseDesktop), nil
return NewSUSE(driver, cnf.GetURL(), constant.SUSEEnterpriseDesktop), nil
case constant.Alpine:
return NewAlpine(&cnf), nil
return NewAlpine(driver, cnf.GetURL()), nil
case constant.Amazon:
return NewAmazon(&cnf), nil
return NewAmazon(driver, cnf.GetURL()), nil
case constant.Fedora:
return NewFedora(&cnf), nil
return NewFedora(driver, cnf.GetURL()), nil
case constant.FreeBSD, constant.Windows:
return nil, nil
return NewPseudo(family), nil
case constant.ServerTypePseudo:
return nil, nil
return NewPseudo(family), nil
default:
if family == "" {
return nil, xerrors.New("Probably an error occurred during scanning. Check the error message")

View File

@@ -62,14 +62,14 @@ func (h VulsHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
if err := detector.DetectPkgCves(&r, config.Conf.OvalDict, config.Conf.Gost); err != nil {
if err := detector.DetectPkgCves(&r, config.Conf.OvalDict, config.Conf.Gost, config.Conf.LogOpts); err != nil {
logging.Log.Errorf("Failed to detect Pkg CVE: %+v", err)
http.Error(w, err.Error(), http.StatusServiceUnavailable)
return
}
logging.Log.Infof("Fill CVE detailed with gost")
if err := gost.FillCVEsWithRedHat(&r, config.Conf.Gost); err != nil {
if err := gost.FillCVEsWithRedHat(&r, config.Conf.Gost, config.Conf.LogOpts); err != nil {
logging.Log.Errorf("Failed to fill with gost: %+v", err)
http.Error(w, err.Error(), http.StatusServiceUnavailable)
}
@@ -80,21 +80,21 @@ func (h VulsHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
http.Error(w, err.Error(), http.StatusServiceUnavailable)
}
nExploitCve, err := detector.FillWithExploit(&r, config.Conf.Exploit)
nExploitCve, err := detector.FillWithExploit(&r, config.Conf.Exploit, config.Conf.LogOpts)
if err != nil {
logging.Log.Errorf("Failed to fill with exploit: %+v", err)
http.Error(w, err.Error(), http.StatusServiceUnavailable)
}
logging.Log.Infof("%s: %d PoC detected", r.FormatServerName(), nExploitCve)
nMetasploitCve, err := detector.FillWithMetasploit(&r, config.Conf.Metasploit)
nMetasploitCve, err := detector.FillWithMetasploit(&r, config.Conf.Metasploit, config.Conf.LogOpts)
if err != nil {
logging.Log.Errorf("Failed to fill with metasploit: %+v", err)
http.Error(w, err.Error(), http.StatusServiceUnavailable)
}
logging.Log.Infof("%s: %d exploits are detected", r.FormatServerName(), nMetasploitCve)
if err := detector.FillWithKEVuln(&r, config.Conf.KEVuln); err != nil {
if err := detector.FillWithKEVuln(&r, config.Conf.KEVuln, config.Conf.LogOpts); err != nil {
logging.Log.Errorf("Failed to fill with Known Exploited Vulnerabilities: %+v", err)
http.Error(w, err.Error(), http.StatusServiceUnavailable)
}

View File

@@ -175,10 +175,24 @@ func (p *ReportCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}
logging.Log = logging.NewCustomLogger(config.Conf.Debug, config.Conf.Quiet, config.Conf.LogToFile, config.Conf.LogDir, "", "")
logging.Log.Infof("vuls-%s-%s", config.Version, config.Revision)
if err := config.Load(p.configPath); err != nil {
logging.Log.Errorf("Error loading %s, %+v", p.configPath, err)
return subcommands.ExitUsageError
if p.configPath == "" {
for _, cnf := range []config.VulnDictInterface{
&config.Conf.CveDict,
&config.Conf.OvalDict,
&config.Conf.Gost,
&config.Conf.Exploit,
&config.Conf.Metasploit,
&config.Conf.KEVuln,
} {
cnf.Init()
}
} else {
if err := config.Load(p.configPath); err != nil {
logging.Log.Errorf("Error loading %s. err: %+v", p.configPath, err)
return subcommands.ExitUsageError
}
}
config.Conf.Slack.Enabled = p.toSlack
config.Conf.ChatWork.Enabled = p.toChatWork
config.Conf.GoogleChat.Enabled = p.toGoogleChat

View File

@@ -11,10 +11,11 @@ import (
"os"
"path/filepath"
"github.com/google/subcommands"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/logging"
"github.com/future-architect/vuls/server"
"github.com/google/subcommands"
)
// ServerCmd is subcommand for server
@@ -93,9 +94,23 @@ func (p *ServerCmd) SetFlags(f *flag.FlagSet) {
func (p *ServerCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
logging.Log = logging.NewCustomLogger(config.Conf.Debug, config.Conf.Quiet, config.Conf.LogToFile, config.Conf.LogDir, "", "")
logging.Log.Infof("vuls-%s-%s", config.Version, config.Revision)
if err := config.Load(p.configPath); err != nil {
logging.Log.Errorf("Error loading %s. err: %+v", p.configPath, err)
return subcommands.ExitUsageError
if p.configPath == "" {
for _, cnf := range []config.VulnDictInterface{
&config.Conf.CveDict,
&config.Conf.OvalDict,
&config.Conf.Gost,
&config.Conf.Exploit,
&config.Conf.Metasploit,
&config.Conf.KEVuln,
} {
cnf.Init()
}
} else {
if err := config.Load(p.configPath); err != nil {
logging.Log.Errorf("Error loading %s. err: %+v", p.configPath, err)
return subcommands.ExitUsageError
}
}
logging.Log.Info("Validating config...")