mirror of
https://github.com/SSLMate/certspotter.git
synced 2025-12-18 12:54:18 +01:00
New and simplified multi-log operation
This commit is contained in:
160
cmd/common.go
160
cmd/common.go
@@ -5,7 +5,11 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/user"
|
||||
"bufio"
|
||||
"sync"
|
||||
"strings"
|
||||
"path/filepath"
|
||||
|
||||
"src.agwa.name/ctwatch"
|
||||
"github.com/google/certificate-transparency/go"
|
||||
@@ -16,14 +20,53 @@ var batchSize = flag.Int("batch_size", 1000, "Max number of entries to request a
|
||||
var numWorkers = flag.Int("num_workers", 2, "Number of concurrent matchers")
|
||||
var parallelFetch = flag.Int("parallel_fetch", 2, "Number of concurrent GetEntries fetches")
|
||||
var script = flag.String("script", "", "Script to execute when a matching certificate is found")
|
||||
var repo = flag.String("repo", "", "Directory of scanned certificates")
|
||||
var logsFilename = flag.String("logs", "", "File containing log URLs")
|
||||
var noSave = flag.Bool("no_save", false, "Do not save a copy of matching certificates")
|
||||
var verbose = flag.Bool("verbose", false, "Be verbose")
|
||||
var stateDir string
|
||||
|
||||
var printMutex sync.Mutex
|
||||
|
||||
func logCallback (entry *ct.LogEntry) {
|
||||
if *repo != "" {
|
||||
alreadyPresent, err := ctwatch.WriteCertRepository(*repo, entry)
|
||||
var defaultLogs = []string{
|
||||
"https://log.certly.io",
|
||||
"https://ct1.digicert-ct.com/log",
|
||||
"https://ct.googleapis.com/aviator",
|
||||
"https://ct.googleapis.com/pilot",
|
||||
"https://ct.googleapis.com/rocketeer",
|
||||
"https://ct.izenpe.com",
|
||||
"https://ct.ws.symantec.com",
|
||||
"https://vega.ws.symantec.com",
|
||||
"https://ctlog.api.venafi.com",
|
||||
"https://ct.wosign.com",
|
||||
}
|
||||
|
||||
func isRoot () bool {
|
||||
return os.Geteuid() == 0
|
||||
}
|
||||
|
||||
func homedir () string {
|
||||
home := os.Getenv("HOME")
|
||||
if home != "" {
|
||||
return home
|
||||
}
|
||||
user, err := user.Current()
|
||||
if err == nil {
|
||||
return user.HomeDir
|
||||
}
|
||||
panic("Unable to determine home directory")
|
||||
}
|
||||
|
||||
func DefaultStateDir (programName string) string {
|
||||
if isRoot() {
|
||||
return filepath.Join("/var/lib", programName)
|
||||
} else {
|
||||
return filepath.Join(homedir(), "." + programName)
|
||||
}
|
||||
}
|
||||
|
||||
func logCallback (scanner *ctwatch.Scanner, entry *ct.LogEntry) {
|
||||
if !*noSave {
|
||||
alreadyPresent, err := ctwatch.WriteCertRepository(filepath.Join(stateDir, "certs"), entry)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
@@ -33,51 +76,96 @@ func logCallback (entry *ct.LogEntry) {
|
||||
}
|
||||
|
||||
if *script != "" {
|
||||
if err := ctwatch.InvokeHookScript(*script, entry); err != nil {
|
||||
if err := ctwatch.InvokeHookScript(*script, scanner.LogUri, entry); err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
} else {
|
||||
printMutex.Lock()
|
||||
ctwatch.DumpLogEntry(os.Stdout, entry)
|
||||
ctwatch.DumpLogEntry(os.Stdout, scanner.LogUri, entry)
|
||||
fmt.Fprintf(os.Stdout, "\n")
|
||||
printMutex.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
func Main(logUri string, stateFile string, matcher ctwatch.Matcher) {
|
||||
startIndex, err := ctwatch.ReadStateFile(stateFile)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s: Error reading state file: %s: %s\n", os.Args[0], stateFile, err)
|
||||
func defangLogUri (logUri string) string {
|
||||
return strings.Replace(strings.Replace(logUri, "://", "_", 1), "/", "_", -1)
|
||||
}
|
||||
|
||||
func Main (argStateDir string, matcher ctwatch.Matcher) {
|
||||
stateDir = argStateDir
|
||||
|
||||
var logs []string
|
||||
if *logsFilename != "" {
|
||||
logFile, err := os.Open(*logsFilename)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s: Error opening logs file for reading: %s: %s\n", os.Args[0], *logsFilename, err)
|
||||
os.Exit(3)
|
||||
}
|
||||
defer logFile.Close()
|
||||
scanner := bufio.NewScanner(logFile)
|
||||
for scanner.Scan() {
|
||||
logs = append(logs, scanner.Text())
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s: Error reading logs file: %s: %s\n", os.Args[0], *logsFilename, err)
|
||||
os.Exit(3)
|
||||
}
|
||||
} else {
|
||||
logs = defaultLogs
|
||||
}
|
||||
|
||||
if err := os.Mkdir(stateDir, 0777); err != nil && !os.IsExist(err) {
|
||||
fmt.Fprintf(os.Stderr, "%s: Error creating state directory: %s: %s\n", os.Args[0], stateDir, err)
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
os.Setenv("LOG_URI", logUri)
|
||||
|
||||
logClient := client.New(logUri)
|
||||
opts := ctwatch.ScannerOptions{
|
||||
Matcher: matcher,
|
||||
BatchSize: *batchSize,
|
||||
NumWorkers: *numWorkers,
|
||||
ParallelFetch: *parallelFetch,
|
||||
Quiet: !*verbose,
|
||||
}
|
||||
scanner := ctwatch.NewScanner(logClient, opts)
|
||||
|
||||
endIndex, err := scanner.TreeSize()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s: Error contacting log: %s: %s\n", os.Args[0], logUri, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if startIndex != -1 {
|
||||
if err := scanner.Scan(startIndex, endIndex, logCallback); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s: Error scanning log: %s: %s\n", os.Args[0], logUri, err)
|
||||
os.Exit(1)
|
||||
for _, subdir := range []string{"certs", "logs"} {
|
||||
path := filepath.Join(stateDir, subdir)
|
||||
if err := os.Mkdir(path, 0777); err != nil && !os.IsExist(err) {
|
||||
fmt.Fprintf(os.Stderr, "%s: Error creating state directory: %s: %s\n", os.Args[0], path, err)
|
||||
os.Exit(3)
|
||||
}
|
||||
}
|
||||
|
||||
if err := ctwatch.WriteStateFile(stateFile, endIndex); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s: Error writing state file: %s: %s\n", os.Args[0], stateFile, err)
|
||||
os.Exit(3)
|
||||
exitCode := 0
|
||||
|
||||
for _, logUri := range logs {
|
||||
stateFilename := filepath.Join(stateDir, "logs", defangLogUri(logUri))
|
||||
startIndex, err := ctwatch.ReadStateFile(stateFilename)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s: Error reading state file: %s: %s\n", os.Args[0], stateFilename, err)
|
||||
os.Exit(3)
|
||||
}
|
||||
|
||||
logClient := client.New(logUri)
|
||||
opts := ctwatch.ScannerOptions{
|
||||
Matcher: matcher,
|
||||
BatchSize: *batchSize,
|
||||
NumWorkers: *numWorkers,
|
||||
ParallelFetch: *parallelFetch,
|
||||
Quiet: !*verbose,
|
||||
}
|
||||
scanner := ctwatch.NewScanner(logUri, logClient, opts)
|
||||
|
||||
endIndex, err := scanner.TreeSize()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s: Error contacting log: %s: %s\n", os.Args[0], logUri, err)
|
||||
exitCode = 1
|
||||
continue
|
||||
}
|
||||
|
||||
if startIndex != -1 {
|
||||
if err := scanner.Scan(startIndex, endIndex, logCallback); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s: Error scanning log: %s: %s\n", os.Args[0], logUri, err)
|
||||
exitCode = 1
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if err := ctwatch.WriteStateFile(stateFilename, endIndex); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s: Error writing state file: %s: %s\n", os.Args[0], stateFilename, err)
|
||||
os.Exit(3)
|
||||
}
|
||||
}
|
||||
|
||||
os.Exit(exitCode)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user