Add offline option to scan and configtest (#588)
Add offline option to scan and configtest
This commit is contained in:
@@ -36,11 +36,14 @@ type ConfigtestCmd struct {
|
||||
logDir string
|
||||
askKeyPassword bool
|
||||
containersOnly bool
|
||||
deep bool
|
||||
sshNative bool
|
||||
httpProxy string
|
||||
timeoutSec int
|
||||
|
||||
fast bool
|
||||
offline bool
|
||||
deep bool
|
||||
|
||||
debug bool
|
||||
}
|
||||
|
||||
@@ -54,6 +57,8 @@ func (*ConfigtestCmd) Synopsis() string { return "Test configuration" }
|
||||
func (*ConfigtestCmd) Usage() string {
|
||||
return `configtest:
|
||||
configtest
|
||||
[-fast]
|
||||
[-offline]
|
||||
[-deep]
|
||||
[-config=/path/to/config.toml]
|
||||
[-log-dir=/path/to/log]
|
||||
@@ -88,6 +93,18 @@ func (p *ConfigtestCmd) SetFlags(f *flag.FlagSet) {
|
||||
"Ask ssh privatekey password before scanning",
|
||||
)
|
||||
|
||||
f.BoolVar(
|
||||
&p.fast,
|
||||
"fast",
|
||||
false,
|
||||
"Config test for online fast scan mode")
|
||||
|
||||
f.BoolVar(
|
||||
&p.offline,
|
||||
"offline",
|
||||
false,
|
||||
"Config test for offline scan mode")
|
||||
|
||||
f.BoolVar(&p.deep, "deep", false, "Config test for deep scan mode")
|
||||
|
||||
f.StringVar(
|
||||
@@ -137,7 +154,13 @@ func (p *ConfigtestCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interfa
|
||||
c.Conf.SSHNative = p.sshNative
|
||||
c.Conf.HTTPProxy = p.httpProxy
|
||||
c.Conf.ContainersOnly = p.containersOnly
|
||||
|
||||
c.Conf.Fast = p.fast
|
||||
c.Conf.Offline = p.offline
|
||||
c.Conf.Deep = p.deep
|
||||
if !(c.Conf.Fast || c.Conf.Offline || c.Conf.Deep) {
|
||||
c.Conf.Fast = true
|
||||
}
|
||||
|
||||
var servernames []string
|
||||
if 0 < len(f.Args()) {
|
||||
|
||||
@@ -43,6 +43,8 @@ type ScanCmd struct {
|
||||
httpProxy string
|
||||
askKeyPassword bool
|
||||
containersOnly bool
|
||||
fast bool
|
||||
offline bool
|
||||
deep bool
|
||||
skipBroken bool
|
||||
sshNative bool
|
||||
@@ -61,6 +63,8 @@ func (*ScanCmd) Synopsis() string { return "Scan vulnerabilities" }
|
||||
func (*ScanCmd) Usage() string {
|
||||
return `scan:
|
||||
scan
|
||||
[-fast]
|
||||
[-offline]
|
||||
[-deep]
|
||||
[-config=/path/to/config.toml]
|
||||
[-results-dir=/path/to/results]
|
||||
@@ -134,6 +138,18 @@ func (p *ScanCmd) SetFlags(f *flag.FlagSet) {
|
||||
"Ask ssh privatekey password before scanning",
|
||||
)
|
||||
|
||||
f.BoolVar(
|
||||
&p.fast,
|
||||
"fast",
|
||||
false,
|
||||
"Online fast scan mode.")
|
||||
|
||||
f.BoolVar(
|
||||
&p.offline,
|
||||
"offline",
|
||||
false,
|
||||
"Offline scan mode. Unable to get updatable packages information.")
|
||||
|
||||
f.BoolVar(
|
||||
&p.deep,
|
||||
"deep",
|
||||
@@ -163,7 +179,6 @@ func (p *ScanCmd) SetFlags(f *flag.FlagSet) {
|
||||
|
||||
// Execute execute
|
||||
func (p *ScanCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
|
||||
|
||||
// Setup Logger
|
||||
c.Conf.Debug = p.debug
|
||||
c.Conf.LogDir = p.logDir
|
||||
@@ -231,9 +246,15 @@ func (p *ScanCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{})
|
||||
c.Conf.SSHNative = p.sshNative
|
||||
c.Conf.HTTPProxy = p.httpProxy
|
||||
c.Conf.ContainersOnly = p.containersOnly
|
||||
c.Conf.Deep = p.deep
|
||||
c.Conf.SkipBroken = p.skipBroken
|
||||
|
||||
c.Conf.Fast = p.fast
|
||||
c.Conf.Offline = p.offline
|
||||
c.Conf.Deep = p.deep
|
||||
if !(c.Conf.Fast || c.Conf.Offline || c.Conf.Deep) {
|
||||
c.Conf.Fast = true
|
||||
}
|
||||
|
||||
util.Log.Info("Validating config...")
|
||||
if !c.Conf.ValidateOnScan() {
|
||||
return subcommands.ExitUsageError
|
||||
|
||||
@@ -103,6 +103,8 @@ type Config struct {
|
||||
|
||||
SSHNative bool
|
||||
ContainersOnly bool
|
||||
Fast bool
|
||||
Offline bool
|
||||
Deep bool
|
||||
SkipBroken bool
|
||||
|
||||
@@ -198,6 +200,16 @@ func (c Config) ValidateOnScan() bool {
|
||||
}
|
||||
}
|
||||
|
||||
numTrue := 0
|
||||
for _, b := range []bool{c.Fast, c.Offline, c.Deep} {
|
||||
if b {
|
||||
numTrue++
|
||||
}
|
||||
}
|
||||
if numTrue != 1 {
|
||||
errs = append(errs, fmt.Errorf("Specify only one of -fast, -fast-offline, -deep"))
|
||||
}
|
||||
|
||||
_, err := valid.ValidateStruct(c)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
|
||||
@@ -21,6 +21,8 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/future-architect/vuls/config"
|
||||
)
|
||||
|
||||
// Packages is Map of Package
|
||||
@@ -62,13 +64,17 @@ func (ps Packages) Merge(other Packages) Packages {
|
||||
|
||||
// FormatUpdatablePacksSummary returns a summary of updatable packages
|
||||
func (ps Packages) FormatUpdatablePacksSummary() string {
|
||||
if config.Conf.Offline {
|
||||
return fmt.Sprintf("%d installed", len(ps))
|
||||
}
|
||||
|
||||
nUpdatable := 0
|
||||
for _, p := range ps {
|
||||
if p.NewVersion != "" {
|
||||
nUpdatable++
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("%d updatable packages", nUpdatable)
|
||||
return fmt.Sprintf("%d installed, %d updatable", len(ps), nUpdatable)
|
||||
}
|
||||
|
||||
// FindOne search a element by name-newver-newrel-arch
|
||||
|
||||
@@ -164,7 +164,7 @@ func (o *debian) checkDependencies() error {
|
||||
// https://askubuntu.com/a/742844
|
||||
packNames = append(packNames, "reboot-notifier")
|
||||
|
||||
if !config.Conf.Deep {
|
||||
if config.Conf.Deep {
|
||||
// Debian needs aptitude to get changelogs.
|
||||
// Because unable to get changelogs via apt-get changelog on Debian.
|
||||
packNames = append(packNames, "aptitude")
|
||||
@@ -212,6 +212,10 @@ func (o *debian) scanPackages() error {
|
||||
o.Packages = installed
|
||||
o.SrcPackages = srcPacks
|
||||
|
||||
if config.Conf.Offline {
|
||||
return nil
|
||||
}
|
||||
|
||||
if config.Conf.Deep || o.Distro.Family == config.Raspbian {
|
||||
unsecures, err := o.scanUnsecurePackages(updatable)
|
||||
if err != nil {
|
||||
@@ -300,6 +304,13 @@ func (o *debian) scanInstalledPackages() (models.Packages, models.Packages, mode
|
||||
delete(srcPacks, name)
|
||||
}
|
||||
|
||||
if config.Conf.Offline {
|
||||
return installed, updatable, srcPacks, nil
|
||||
}
|
||||
|
||||
if err := o.aptGetUpdate(); err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
updatableNames, err := o.getUpdatablePackNames()
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
@@ -346,14 +357,12 @@ func (o *debian) aptGetUpdate() error {
|
||||
o.log.Infof("apt-get update...")
|
||||
cmd := util.PrependProxyEnv("apt-get update")
|
||||
if r := o.exec(cmd, sudo); !r.isSuccess() {
|
||||
return fmt.Errorf("Failed to SSH: %s", r)
|
||||
return fmt.Errorf("Failed to apt-get update: %s", r)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *debian) scanUnsecurePackages(updatable models.Packages) (models.VulnInfos, error) {
|
||||
o.aptGetUpdate()
|
||||
|
||||
// Setup changelog cache
|
||||
current := cache.Meta{
|
||||
Name: o.getServerInfo().GetServerName(),
|
||||
|
||||
@@ -177,9 +177,12 @@ func (o *redhat) checkIfSudoNoPasswd() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// - Fast scan mode
|
||||
// - Fast offline scan mode
|
||||
// Amazon ... yum-utils
|
||||
//
|
||||
// - Fast scan mode
|
||||
// All ... yum-utils
|
||||
//
|
||||
// - Deep scan mode
|
||||
// CentOS 6,7 ... yum-utils, yum-plugin-changelog
|
||||
// RHEL 5 (U1-) ... yum-utils, yum-security, yum-changelog
|
||||
@@ -203,11 +206,13 @@ func (o *redhat) checkDependencies() error {
|
||||
}
|
||||
|
||||
packNames := []string{}
|
||||
|
||||
if !config.Conf.Deep {
|
||||
// Fast Scan
|
||||
if config.Conf.Fast {
|
||||
// Online fast scan needs yum-utils to issue repoquery cmd
|
||||
packNames = append(packNames, "yum-utils")
|
||||
} else if config.Conf.Offline {
|
||||
switch o.Distro.Family {
|
||||
case config.Amazon:
|
||||
// Offline scan doesn't support Amazon Linux
|
||||
packNames = append(packNames, "yum-utils")
|
||||
}
|
||||
} else {
|
||||
@@ -255,7 +260,7 @@ func (o *redhat) scanPackages() error {
|
||||
}
|
||||
o.Kernel.RebootRequired = rebootRequired
|
||||
|
||||
if !config.Conf.Deep {
|
||||
if config.Conf.Offline {
|
||||
switch o.Distro.Family {
|
||||
case config.Amazon:
|
||||
// nop
|
||||
|
||||
Reference in New Issue
Block a user