diff options
Diffstat (limited to 'cmd/silent-ctmoon')
-rw-r--r-- | cmd/silent-ctmoon/main.go | 224 |
1 files changed, 0 insertions, 224 deletions
diff --git a/cmd/silent-ctmoon/main.go b/cmd/silent-ctmoon/main.go deleted file mode 100644 index c651e68..0000000 --- a/cmd/silent-ctmoon/main.go +++ /dev/null @@ -1,224 +0,0 @@ -package main - -import ( - "context" - "errors" - "flag" - "fmt" - "log" - "os" - "os/signal" - "strings" - "sync" - "syscall" - "time" - - "rgdd.se/silent-ct/internal/feedback" - "rgdd.se/silent-ct/internal/flagopt" - "rgdd.se/silent-ct/internal/ioutil" - "rgdd.se/silent-ct/internal/logger" - "rgdd.se/silent-ct/internal/manager" - "rgdd.se/silent-ct/internal/monitor" - "rgdd.se/silent-ct/pkg/policy" -) - -const usage = ` -A utility that follows relevant Certificate Transparency logs to -discover certificates that may be mis-issued. To be silent, any -legitimately issued certificates are pulled from trusted nodes. - -Usage: - - silent-ctmoon --help - silent-ctmoon [Opts] -d DIRECTORY -f POLICY_FILE - -Options: - - -h, --help: Output usage message and exit - -v, --verbosity: Leveled logging output (default: NOTICE) - - -b, --bootstrap: Initializate a new state directory (Default: false) - -c, --contact: A string that helps log operators know who you are (Default: "") - -d, --directory: Path to a directory where all state will be stored - -e, --please-exit Toggle to only run until up-to-date (Default: false) - -f, --policy-file: Path to the monitor's policy file in JSON format - -o, --output-file File that all output will be written to (Default: stdout) - -p, --pull-interval: How often nodes are pulled for certificates (Default: 15m) - -w, --num-workers: Number of parallel workers to fetch each log with (Default: 1) -` - -type config struct { - // Options - verbosity string - bootstrap bool - contact string - directory string - pleaseExit bool - policyFile string - outputFile string - pullInterval time.Duration - numWorkers uint - - // Extracted - log *logger.Logger - policy policy.Policy -} - -func configure(cmd string, args []string) (cfg config, err error) { - fs := flag.NewFlagSet(cmd, flag.ContinueOnError) - fs.Usage = func() {} - flagopt.StringOpt(fs, &cfg.verbosity, "verbosity", "v", logger.LevelNotice.String()) - flagopt.BoolOpt(fs, &cfg.bootstrap, "bootstrap", "b", false) - flagopt.StringOpt(fs, &cfg.contact, "contact", "c", "") - flagopt.StringOpt(fs, &cfg.directory, "directory", "d", "") - flagopt.BoolOpt(fs, &cfg.pleaseExit, "please-exit", "e", false) - flagopt.StringOpt(fs, &cfg.policyFile, "policy-file", "f", "") - flagopt.StringOpt(fs, &cfg.outputFile, "output-file", "o", "") - flagopt.DurationOpt(fs, &cfg.pullInterval, "pull-interval", "p", 15*time.Minute) - flagopt.UintOpt(fs, &cfg.numWorkers, "num-workers", "w", 1) - if err = fs.Parse(args); err != nil { - return cfg, err - } - - // Options - lv, err := logger.NewLevel(cfg.verbosity) - if err != nil { - return cfg, fmt.Errorf("invalid verbosity: %v", err) - } - if cfg.directory == "" { - return cfg, fmt.Errorf("directory is a required option") - } - if cfg.policyFile == "" { - return cfg, fmt.Errorf("policy file is a required option") - } - output := os.Stdout - if cfg.outputFile != "" { - if output, err = os.OpenFile(cfg.outputFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644); err != nil { - return cfg, fmt.Errorf("failed to open output file: %v", err) - } - } - if cfg.numWorkers == 0 || cfg.numWorkers > 4 { - return cfg, fmt.Errorf("number of workers must be in [1, 4]") - } - - cfg.log = logger.New(logger.Config{Level: lv, File: output}) - if err := ioutil.ReadJSON(cfg.policyFile, &cfg.policy); err != nil { - return cfg, err - } - if len(cfg.policy.Monitor) == 0 { - return cfg, fmt.Errorf("policy: need at least one wildcard to monitor") - } - - // Arguments - if len(fs.Args()) != 0 { - return cfg, fmt.Errorf("trailing arguments are not permitted") - } - - return cfg, nil -} - -func main() { - cfg, err := configure(os.Args[0], os.Args[1:]) - if err != nil { - if errors.Is(err, flag.ErrHelp) { - fmt.Fprintf(os.Stderr, "%s", usage[1:]) - os.Exit(0) - } - if !strings.Contains(err.Error(), "flag provided but not defined") { - fmt.Fprintf(os.Stderr, "%v\n", err) - } - os.Exit(1) - } - - feventCh := make(chan []feedback.Event) - defer close(feventCh) - - mconfigCh := make(chan monitor.MonitoredLog) - defer close(mconfigCh) - - meventCh := make(chan monitor.Event) - defer close(meventCh) - - errorCh := make(chan error) - defer close(errorCh) - - mgr, err := manager.New(manager.Config{ - Policy: cfg.policy, - Bootstrap: cfg.bootstrap, - Directory: cfg.directory, - Logger: cfg.log, - AlertDelay: cfg.pullInterval * 3 / 2, - }, feventCh, meventCh, mconfigCh, errorCh) - if err != nil { - cfg.log.Dief("manager: %v\n", err) - } - mon, err := monitor.New(monitor.Config{ - Matcher: &cfg.policy.Monitor, - Logger: cfg.log, - Contact: cfg.contact, - NumWorkers: cfg.numWorkers, - }, meventCh, mconfigCh, errorCh) - if err != nil { - cfg.log.Dief("monitor: %v\n", err) - } - fb, err := feedback.New(feedback.Config{ - Policy: cfg.policy, - Logger: cfg.log, - PullInterval: cfg.pullInterval, - }, feventCh) - if err != nil { - cfg.log.Dief("feedback: %v\n", err) - } - - if cfg.bootstrap { - os.Exit(0) - } - if cfg.pleaseExit { - cfg.log.Dief("the --please-exit option is not supported yet\n") - } - - var wg sync.WaitGroup - ctx, cancel := context.WithCancel(context.Background()) - - wg.Add(1) - go func() { - defer wg.Done() - defer cancel() - await(ctx) - }() - - wg.Add(1) - go func() { - defer wg.Done() - defer cancel() - mon.RunForever(ctx) - }() - - wg.Add(1) - go func() { - defer wg.Done() - defer cancel() - fb.RunForever(ctx) - }() - - os.Exit(func() int { - defer wg.Wait() - defer cancel() - if err := mgr.Run(ctx); err != nil { - log.Fatalf("manager: %v\n", err) - return 1 - } - return 0 - }()) -} - -func await(ctx context.Context) { - sigs := make(chan os.Signal, 1) - defer close(sigs) - - signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) - select { - case <-sigs: - case <-ctx.Done(): - } -} |