func (t *CertificateCheck) RunCheck(r *reporter.Reporter) error { u, err := url.Parse(t.URL) if err != nil { return err } port := "443" host := u.Host if strings.Contains(host, ":") { parts := strings.Split(u.Host, ":") host = parts[0] port = parts[1] } conn, err := tls.Dial("tcp", host+":"+port, nil) if err != nil { return err } if t.Days == 0 { t.Days = 15 } res := r.Report("Certificate expires > %d days", t.Days) cert := conn.ConnectionState().PeerCertificates[0] conn.Close() exp := time.Since(cert.NotAfter) * -1 days := uint64(math.Floor(exp.Hours() / 24)) if days < t.Days { res.Fail("Certificate expires in %d days (< %d)", days, t.Days) } else { res.Pass("Certificate expires in %d days", days) } return nil }
func (core *Core) DoWarnings(r *reporter.Reporter, i *Informants) { warnings := r.CollectWarnings() if len(warnings) < 1 { return } body := strings.Join(warnings, "\n") hostname, _ := os.Hostname() body = body + hostname errId := r.ID params := map[string]string{ "subject": r.Name, "hostname": hostname, "body": body, "id": errId, } for _, method := range i.Methods { if len(method.Channel) > 0 { DoChannel(core, method.Channel, params) } } }
func (t *RedirectCheck) RunCheck(r *reporter.Reporter) error { res := r.Report("CHECK REDIRECT %s => %s", t.From, t.To) client := &http.Client{} finalAddress := "" client.CheckRedirect = func(req *http.Request, via []*http.Request) error { if !t.AllowMultiple { if finalAddress != "" { res.Fail("Redirected to subsequent address %s", req.URL.String()) } } finalAddress = req.URL.String() return nil } resp, err := client.Get(t.From) if finalAddress != t.To { res.Fail("Redirect to wrong address %s", finalAddress) } if err != nil { res.Fail("Redirect %s => %s failed:\n %s", t.From, t.To, err.Error()) return nil } if finalAddress == "" { res.Fail("Redirect %s => %s did not redirect", t.From, t.To) } resp.Body.Close() return nil }
func (s *Server) RunChecks(r *reporter.Reporter) { if s.SSH.HostName == "" { s.SSH.HostName = s.Name } err := s.RunDiskCheck(r) if err != nil { r.AddError(err) } }
func (s *Server) RunDiskCheck(reporter *reporter.Reporter) (err error) { disks, err := s.GetDisks() if err != nil { return err } log.Println(disks) checkDisks: for _, checkDisk := range s.Disks { for _, disk := range disks { if disk.Filesystem == checkDisk.Filesystem { if checkDisk.MinBytes != nil { res := reporter.Report("Check disk %s has > %d bytes free", disk.Filesystem, *checkDisk.MinBytes) if disk.Available < *checkDisk.MinBytes { res.Fail("%d bytes free", disk.Available) } else { res.Pass("%d bytes free", disk.Available) } } if checkDisk.MinPercent != nil { res := reporter.Report("Check disk %s has > %.2f%% free", disk.Filesystem, *checkDisk.MinPercent) fAvail := float64(disk.Available) fUsed := float64(disk.Used) fTotal := fUsed + fAvail availPercent := fAvail / fTotal * 100 if availPercent < *checkDisk.MinPercent { res.Fail("%.2f%% free", availPercent) } else { res.Pass("%.2f%% free", availPercent) } } continue checkDisks } } res := reporter.Report("Check disk %s", checkDisk.Filesystem) res.Fail("Disk not found") } return }
func (t *LogCheck) RunCheck(r *reporter.Reporter) error { resp, err := t.Request.DoRequest() if err != nil { return err } defer resp.Body.Close() scanner := bufio.NewScanner(resp.Body) reTimePart, err := regexp.Compile(t.Regexp) if err != nil { return err } lastTime := time.Unix(0, 0) for scanner.Scan() { str := scanner.Text() timeString := reTimePart.FindString(str) t, _ := time.Parse(t.Format, timeString) if t.After(lastTime) { lastTime = t } } if len(t.QuietPeriod) > 0 { res := r.Report("LOG CHECK %s", t.GetName()) duration, err := time.ParseDuration(t.QuietPeriod) if err != nil { return err } since := time.Since(lastTime) if since > duration { res.Fail("FAIL Last log was %s ago at %s", since, lastTime.Format(time.RFC1123)) } else { res.Pass("Last log was %s ago", since) } } return nil }
func (jfc *JSONFieldCheck) DoChecks(ctx *JSONContext, r *reporter.Reporter) { res := r.Report("Elem: %s", jfc.GetName()) je := &JSONElem{ ctx: ctx, Fails: []string{}, JSONElemDef: jfc.GetElemDef(), } err := jfc.JSONFieldCheckDef.Check(je) if err != nil { res.Fail(err.Error()) return } if len(je.Fails) > 0 { for _, f := range je.Fails { res.Fail(f) } } else { res.Pass(je.GetString()) } }
func (t *TextCheck) RunCheck(r *reporter.Reporter) error { reader, err := t.GetReader() if err != nil { return err } defer reader.Close() bodyBytes, err := ioutil.ReadAll(reader) bodyString := string(bodyBytes) for _, ss := range t.Contains { res := r.Report("SEARCH %s for %s", t.URL, ss) if !strings.Contains(bodyString, ss) { res.Fail("Did not contain '%s'\n\n%s", ss, bodyString) return nil } else { res.Pass("Found") } } return nil }
func (t *JSONCheck) RunCheck(r *reporter.Reporter) error { rChild := r.Spawn("JSON Check %s", t.GetName()) reader, err := t.Request.GetReader() if err != nil { return err } defer reader.Close() dec := json.NewDecoder(reader) data := map[string]interface{}{} dec.Decode(&data) ctx := &JSONContext{ Data: data, Reporter: rChild, } for _, test := range t.CheckFields { test.DoChecks(ctx, rChild) } return nil }
func (t *CommandCheck) RunCheck(reporter *reporter.Reporter) error { res := reporter.Report("Run command %s", t.Command) c := exec.Command(t.Command, t.Args...) c.Dir = t.WorkingDirectory for _, envVar := range t.Environment { c.Env = append(c.Env, fmt.Sprintf("%s=%s", envVar.Name, envVar.Value)) } output, err := c.CombinedOutput() if err != nil { res.Fail("Error running %s: %s Dump: \n%s\n", t.Command, err.Error(), string(output)) } return nil }
func Crosscheck(cfg *CXConfig, configHash string, r *reporter.Reporter) bool { if cfg.MaxTries == 0 { cfg.MaxTries = 3 } b := make([]byte, 21, 21) rand.Read(b) myID := base64.URLEncoding.EncodeToString(b) log.Printf("My ID: %s\n", myID) waitForOthers := &sync.WaitGroup{} waitForOthers.Add(len(cfg.Remotes)) mux := http.NewServeMux() // Serve and dial mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { id := r.URL.Query().Get("id") log.Printf("Was pinged by %s\n", id) waitForOthers.Done() fmt.Fprintf(w, "%s\n%s", myID, configHash) }) closeListener := make(chan struct{}) go func() { var listener net.Listener defer func() { <-closeListener if listener != nil { listener.Close() } }() listener, err := net.Listen("tcp", cfg.Bind) if err != nil { log.Printf("Can't listen for CX: %s\n", err.Error()) return } go func() { err = http.Serve(listener, mux) if err != nil { log.Printf("Can't serve for CX: %s\n", err.Error()) } }() }() isLowest := true allSuccess := true remotes: for _, remote := range cfg.Remotes { reportRes := r.Report("CX %s", remote) success := false for try := 0; try < cfg.MaxTries; try += 1 { time.Sleep(time.Second * time.Duration(1+(5*try))) res, err := http.Get(fmt.Sprintf("%s?id=%s", remote, myID)) if err != nil { log.Printf("Checking %s fail %d/%d\n%s", remote, try+1, cfg.MaxTries, err.Error()) continue } bodyBytes, _ := ioutil.ReadAll(res.Body) parts := strings.Split(string(bodyBytes), "\n") if len(parts) != 2 { log.Println(string(bodyBytes)) reportRes.Fail("Didn't understand response") allSuccess = false continue remotes } remoteID := parts[0] remoteConfig := parts[1] reportRes.Pass("Got ID %s", remoteID) if remoteConfig != configHash { reportRes.Fail("Config mismach") allSuccess = false continue remotes } success = true if remoteID == myID { log.Printf("Remote %s is me (%s)\n", remote, remoteID) break } log.Printf("Remote %s answered (%s)\n", remote, remoteID) if remoteID < myID { isLowest = false } break } if !success { reportRes.Fail("No connection established") allSuccess = false } } if !allSuccess { log.Printf("At least one host failed, running checks locally") return true } log.Println("Waiting for other servers") waitForOthers.Wait() log.Println("Wait complete, Stop Server") closeListener <- struct{}{} log.Println("Stopped Server") if isLowest { log.Printf("I am the lowest: %s\n", myID) return true } log.Println("Not elected, I'm done") return false }