diff --git a/config/config.go b/config/config.go index 2a980468..30255f2b 100644 --- a/config/config.go +++ b/config/config.go @@ -474,6 +474,10 @@ type ServerInfo struct { LogMsgAnsiColor string // DebugLog Color Container Container Distro Distro + + // IP addresses + IPv4Addrs []string + IPv6Addrs []string } // GetServerName returns ServerName if this serverInfo is about host. diff --git a/models/scanresults.go b/models/scanresults.go index 60df1661..8c89b156 100644 --- a/models/scanresults.go +++ b/models/scanresults.go @@ -40,6 +40,8 @@ type ScanResult struct { Release string Container Container Platform Platform + IPv4Addrs []string // only global unicast address (https://golang.org/pkg/net/#IP.IsGlobalUnicast) + IPv6Addrs []string // only global unicast address (https://golang.org/pkg/net/#IP.IsGlobalUnicast) // Scanned Vulns by SSH scan + CPE + OVAL ScannedCves VulnInfos diff --git a/scan/alpine.go b/scan/alpine.go index 3c0201f1..c68dd4ca 100644 --- a/scan/alpine.go +++ b/scan/alpine.go @@ -82,6 +82,23 @@ func (o *alpine) apkUpdate() error { return nil } +func (o *alpine) preCure() error { + if err := o.detectIPAddr(); err != nil { + o.log.Debugf("Failed to detect IP addresses: %s", err) + } + // Ignore this error as it just failed to detect the IP addresses + return nil +} + +func (o *alpine) postScan() error { + return nil +} + +func (o *alpine) detectIPAddr() (err error) { + o.ServerInfo.IPv4Addrs, o.ServerInfo.IPv6Addrs, err = o.ip() + return err +} + func (o *alpine) scanPackages() error { if err := o.apkUpdate(); err != nil { return err diff --git a/scan/base.go b/scan/base.go index 81a461d7..f29b1a9a 100644 --- a/scan/base.go +++ b/scan/base.go @@ -19,6 +19,7 @@ package scan import ( "fmt" + "net" "regexp" "strings" "time" @@ -256,6 +257,44 @@ func (l *base) parseLxcPs(stdout string) (containers []config.Container, err err return } +// ip executes ip command and returns IP addresses +func (l *base) ip() ([]string, []string, error) { + // e.g. + // 2: eth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000\ link/ether 52:54:00:2a:86:4c brd ff:ff:ff:ff:ff:ff + // 2: eth0 inet 10.0.2.15/24 brd 10.0.2.255 scope global eth0 + // 2: eth0 inet6 fe80::5054:ff:fe2a:864c/64 scope link \ valid_lft forever preferred_lft forever + r := l.exec("/sbin/ip -o addr", noSudo) + if !r.isSuccess() { + return nil, nil, fmt.Errorf("Failed to detect IP address: %v", r) + } + ipv4Addrs, ipv6Addrs := l.parseIP(r.Stdout) + return ipv4Addrs, ipv6Addrs, nil +} + +// parseIP parses the results of ip command +func (l *base) parseIP(stdout string) (ipv4Addrs []string, ipv6Addrs []string) { + lines := strings.Split(stdout, "\n") + for _, line := range lines { + fields := strings.Fields(line) + if len(fields) < 4 { + continue + } + ip, _, err := net.ParseCIDR(fields[3]) + if err != nil { + continue + } + if !ip.IsGlobalUnicast() { + continue + } + if ipv4 := ip.To4(); ipv4 != nil { + ipv4Addrs = append(ipv4Addrs, ipv4.String()) + } else { + ipv6Addrs = append(ipv6Addrs, ip.String()) + } + } + return +} + func (l *base) detectPlatform() { ok, instanceID, err := l.detectRunningOnAws() if err != nil { @@ -352,6 +391,8 @@ func (l *base) convertToModel() models.ScanResult { Release: l.Distro.Release, Container: container, Platform: l.Platform, + IPv4Addrs: l.ServerInfo.IPv4Addrs, + IPv6Addrs: l.ServerInfo.IPv6Addrs, ScannedCves: l.VulnInfos, RunningKernel: l.Kernel, Packages: l.Packages, diff --git a/scan/base_test.go b/scan/base_test.go index 808d5058..bb617f75 100644 --- a/scan/base_test.go +++ b/scan/base_test.go @@ -97,6 +97,36 @@ func TestParseLxdPs(t *testing.T) { } } +func TestParseIp(t *testing.T) { + + var test = struct { + in string + expected4 []string + expected6 []string + }{ + in: `1: lo: mtu 65536 qdisc noqueue state UNKNOWN \ link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 +1: lo inet 127.0.0.1/8 scope host lo +1: lo inet6 ::1/128 scope host \ valid_lft forever preferred_lft forever +2: eth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000\ link/ether 52:54:00:2a:86:4c brd ff:ff:ff:ff:ff:ff +2: eth0 inet 10.0.2.15/24 brd 10.0.2.255 scope global eth0 +2: eth0 inet6 fe80::5054:ff:fe2a:864c/64 scope link \ valid_lft forever preferred_lft forever +3: eth1: mtu 1500 qdisc pfifo_fast state UP qlen 1000\ link/ether 08:00:27:36:76:60 brd ff:ff:ff:ff:ff:ff +3: eth1 inet 192.168.33.11/24 brd 192.168.33.255 scope global eth1 +3: eth1 inet6 2001:db8::68/64 scope link \ valid_lft forever preferred_lft forever `, + expected4: []string{"10.0.2.15", "192.168.33.11"}, + expected6: []string{"2001:db8::68"}, + } + + r := newRedhat(config.ServerInfo{}) + actual4, actual6 := r.parseIP(test.in) + if !reflect.DeepEqual(test.expected4, actual4) { + t.Errorf("expected %v, actual %v", test.expected4, actual4) + } + if !reflect.DeepEqual(test.expected6, actual6) { + t.Errorf("expected %v, actual %v", test.expected6, actual6) + } +} + func TestIsAwsInstanceID(t *testing.T) { var tests = []struct { in string diff --git a/scan/debian.go b/scan/debian.go index bbea2adc..528b7d37 100644 --- a/scan/debian.go +++ b/scan/debian.go @@ -186,6 +186,23 @@ func (o *debian) checkDependencies() error { return nil } +func (o *debian) preCure() error { + if err := o.detectIPAddr(); err != nil { + o.log.Debugf("Failed to detect IP addresses: %s", err) + } + // Ignore this error as it just failed to detect the IP addresses + return nil +} + +func (o *debian) postScan() error { + return nil +} + +func (o *debian) detectIPAddr() (err error) { + o.ServerInfo.IPv4Addrs, o.ServerInfo.IPv6Addrs, err = o.ip() + return err +} + func (o *debian) scanPackages() error { // collect the running kernel information release, version, err := o.runningKernel() diff --git a/scan/freebsd.go b/scan/freebsd.go index 8ac648fa..5446b801 100644 --- a/scan/freebsd.go +++ b/scan/freebsd.go @@ -19,6 +19,7 @@ package scan import ( "fmt" + "net" "strings" "github.com/future-architect/vuls/config" @@ -77,6 +78,51 @@ func (o *bsd) checkDependencies() error { return nil } +func (o *bsd) preCure() error { + if err := o.detectIPAddr(); err != nil{ + o.log.Debugf("Failed to detect IP addresses: %s", err) + } + // Ignore this error as it just failed to detect the IP addresses + return nil +} + +func (o *bsd) postScan() error { + return nil +} + +func (o *bsd) detectIPAddr() (err error) { + r := o.exec("/sbin/ifconfig", noSudo) + if !r.isSuccess() { + return fmt.Errorf("Failed to detect IP address: %v", r) + } + o.ServerInfo.IPv4Addrs, o.ServerInfo.IPv6Addrs = o.parseIfconfig(r.Stdout) + return nil +} + +func (l *base) parseIfconfig(stdout string) (ipv4Addrs []string, ipv6Addrs []string) { + lines := strings.Split(stdout, "\n") + for _, line := range lines { + line = strings.TrimSpace(line) + fields := strings.Fields(line) + if len(fields) < 4 || !strings.HasPrefix(fields[0], "inet") { + continue + } + ip := net.ParseIP(fields[1]) + if ip == nil { + continue + } + if !ip.IsGlobalUnicast() { + continue + } + if ipv4 := ip.To4(); ipv4 != nil { + ipv4Addrs = append(ipv4Addrs, ipv4.String()) + } else { + ipv6Addrs = append(ipv6Addrs, ip.String()) + } + } + return +} + func (o *bsd) scanPackages() error { // collect the running kernel information release, version, err := o.runningKernel() diff --git a/scan/freebsd_test.go b/scan/freebsd_test.go index 8e1e6f96..e5343abb 100644 --- a/scan/freebsd_test.go +++ b/scan/freebsd_test.go @@ -9,6 +9,45 @@ import ( "github.com/k0kubun/pp" ) +func TestParseIfconfig(t *testing.T) { + var tests = []struct { + in string + expected4 []string + expected6 []string + }{ + { + in: `em0: flags=8843 metric 0 mtu 1500 + options=9b + ether 08:00:27:81:82:fa + hwaddr 08:00:27:81:82:fa + inet 10.0.2.15 netmask 0xffffff00 broadcast 10.0.2.255 + inet6 2001:db8::68 netmask 0xffffff00 broadcast 10.0.2.255 + nd6 options=29 + media: Ethernet autoselect (1000baseT ) + status: active + lo0: flags=8049 metric 0 mtu 16384 + options=600003 + inet6 ::1 prefixlen 128 + inet6 fe80::1%lo0 prefixlen 64 scopeid 0x2 + inet 127.0.0.1 netmask 0xff000000 + nd6 options=21`, + expected4: []string{"10.0.2.15"}, + expected6: []string{"2001:db8::68"}, + }, + } + + d := newBsd(config.ServerInfo{}) + for _, tt := range tests { + actual4, actual6 := d.parseIfconfig(tt.in) + if !reflect.DeepEqual(tt.expected4, actual4) { + t.Errorf("expected %s, actual %s", tt.expected4, actual4) + } + if !reflect.DeepEqual(tt.expected6, actual6) { + t.Errorf("expected %s, actual %s", tt.expected6, actual6) + } + } +} + func TestParsePkgVersion(t *testing.T) { var tests = []struct { in string diff --git a/scan/pseudo.go b/scan/pseudo.go index 0b99d8d2..692a4a45 100644 --- a/scan/pseudo.go +++ b/scan/pseudo.go @@ -56,6 +56,14 @@ func (o *pseudo) checkDependencies() error { return nil } +func (o *pseudo) preCure() error { + return nil +} + +func (o *pseudo) postScan() error { + return nil +} + func (o *pseudo) scanPackages() error { return nil } diff --git a/scan/redhat.go b/scan/redhat.go index d048651c..712f25dd 100644 --- a/scan/redhat.go +++ b/scan/redhat.go @@ -246,6 +246,23 @@ func (o *redhat) checkDependencies() error { return nil } +func (o *redhat) preCure() error { + if err := o.detectIPAddr(); err != nil { + o.log.Debugf("Failed to detect IP addresses: %s", err) + } + // Ignore this error as it just failed to detect the IP addresses + return nil +} + +func (o *redhat) postScan() error { + return nil +} + +func (o *redhat) detectIPAddr() (err error) { + o.ServerInfo.IPv4Addrs, o.ServerInfo.IPv6Addrs, err = o.ip() + return err +} + func (o *redhat) scanPackages() error { installed, err := o.scanInstalledPackages() if err != nil { diff --git a/scan/serverapi.go b/scan/serverapi.go index ffb04fdc..ed6daee3 100644 --- a/scan/serverapi.go +++ b/scan/serverapi.go @@ -44,6 +44,8 @@ type osTypeInterface interface { checkDependencies() error checkIfSudoNoPasswd() error + preCure() error + postScan() error scanPackages() error convertToModel() models.ScanResult @@ -454,8 +456,14 @@ func setupChangelogCache() error { func scanVulns(jsonDir string, scannedAt time.Time, timeoutSec int) error { var results models.ScanResults - parallelExec(func(o osTypeInterface) error { - return o.scanPackages() + parallelExec(func(o osTypeInterface) (err error) { + if err = o.preCure(); err != nil { + return err + } + if err = o.scanPackages(); err != nil { + return err + } + return o.postScan() }, timeoutSec) for _, s := range append(servers, errServers...) { diff --git a/scan/unknownDistro.go b/scan/unknownDistro.go index cceaef35..c0fbd863 100644 --- a/scan/unknownDistro.go +++ b/scan/unknownDistro.go @@ -30,6 +30,14 @@ func (o *unknown) checkDependencies() error { return nil } +func (o *unknown) preCure() error { + return nil +} + +func (o *unknown) postScan() error { + return nil +} + func (o *unknown) scanPackages() error { return nil }