This repository has been archived by the owner on Mar 21, 2022. It is now read-only.
forked from cloudflare/cfssl
/
scan.go
123 lines (107 loc) · 2.59 KB
/
scan.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package scan
import (
"encoding/csv"
"encoding/json"
"fmt"
"io"
"os"
"sync"
"github.com/cloudflare/cfssl/cli"
"github.com/cloudflare/cfssl/log"
"github.com/cloudflare/cfssl/scan"
)
var scanUsageText = `cfssl scan -- scan a host for issues
Usage of scan:
cfssl scan [-family regexp] [-scanner regexp] [-timeout duration] [-ip IPAddr] [-num-workers num] [-max-hosts num] [-csv hosts.csv] HOST+
cfssl scan -list
Arguments:
HOST: Host(s) to scan (including port)
Flags:
`
var scanFlags = []string{"list", "family", "scanner", "timeout", "ip", "ca-bundle", "num-workers", "csv", "max-hosts"}
func printJSON(v interface{}) {
b, err := json.MarshalIndent(v, "", " ")
if err != nil {
fmt.Println(err)
}
fmt.Printf("%s\n\n", b)
}
type context struct {
sync.WaitGroup
c cli.Config
hosts chan string
}
func newContext(c cli.Config, numWorkers int) *context {
ctx := &context{
c: c,
hosts: make(chan string, numWorkers),
}
ctx.Add(numWorkers)
for i := 0; i < numWorkers; i++ {
go ctx.runWorker()
}
return ctx
}
func (ctx *context) runWorker() {
for host := range ctx.hosts {
fmt.Printf("Scanning %s...\n", host)
results, err := scan.Default.RunScans(host, ctx.c.IP, ctx.c.Family, ctx.c.Scanner, ctx.c.Timeout)
fmt.Printf("=== %s ===\n", host)
if err != nil {
log.Error(err)
} else {
printJSON(results)
}
}
ctx.Done()
}
func parseCSV(hosts []string, csvFile string, maxHosts int) ([]string, error) {
f, err := os.Open(csvFile)
if err != nil {
return nil, err
}
defer f.Close()
r := csv.NewReader(f)
for err == nil && len(hosts) < maxHosts {
var record []string
record, err = r.Read()
hosts = append(hosts, record[len(record)-1])
}
if err == io.EOF {
err = nil
}
return hosts, err
}
func scanMain(args []string, c cli.Config) (err error) {
if c.List {
printJSON(scan.Default)
} else {
if err = scan.LoadRootCAs(c.CABundleFile); err != nil {
return
}
if len(args) >= c.MaxHosts {
log.Warningf("Only scanning max-hosts=%d out of %d args given", c.MaxHosts, len(args))
args = args[:c.MaxHosts]
} else if c.CSVFile != "" {
args, err = parseCSV(args, c.CSVFile, c.MaxHosts)
if err != nil {
return
}
}
ctx := newContext(c, c.NumWorkers)
// Execute for each HOST argument given
for len(args) > 0 {
var host string
host, args, err = cli.PopFirstArgument(args)
if err != nil {
return
}
ctx.hosts <- host
}
close(ctx.hosts)
ctx.Wait()
}
return
}
// Command assembles the definition of Command 'scan'
var Command = &cli.Command{UsageText: scanUsageText, Flags: scanFlags, Main: scanMain}