package server import ( "context" "net/http" "time" "jarl/internal/auth" "jarl/internal/mailcheck" ) // mailCheckEvery is how often jarld checks the reverse DNS of the // addresses that send and receive mail (docs/exposure.md#mail). const mailCheckEvery = 6 * time.Hour // checkMail checks the reverse DNS of the public zones' mail addresses and // keeps the report; it logs addresses that became wrong. func (s *Server) checkMail(ctx context.Context) *mailcheck.Report { st, err := s.store.LoadState(ctx) if err != nil { s.log.Warn("mail reverse DNS check: loading state", "err", err) return nil } public := map[int64]bool{} for _, x := range s.eng.Exposures(st) { public[x.ViewID] = x.Public } if len(st.Views) == 0 { public[0] = true } ctx, cancel := context.WithTimeout(ctx, 2*time.Minute) defer cancel() rep := mailcheck.Check(ctx, st, func(id int64) bool { return public[id] }, mailcheck.Resolver{Servers: s.cfg.Resolvers}) s.mail.Lock() prev := s.mail.r s.mail.r = rep s.mail.Unlock() was := map[string]bool{} if prev != nil { for _, r := range prev.Results { was[r.Zone+"|"+r.Address] = r.OK } } for _, r := range rep.Results { if ok, seen := was[r.Zone+"|"+r.Address]; !r.OK && (ok || !seen) { s.log.Warn("mail reverse DNS", "zone", r.Zone, "address", r.Address, "problem", r.Message) } } return rep } func (s *Server) mailReport() *mailcheck.Report { s.mail.Lock() defer s.mail.Unlock() return s.mail.r } // mailCheckNow: POST /exposure/mail checks now and returns the report. func (s *Server) mailCheckNow(w http.ResponseWriter, r *http.Request, p *auth.Principal) error { if err := require(p, auth.Action{Resource: auth.ResOptions}); err != nil { return err } rep := s.checkMail(r.Context()) if rep == nil { rep = &mailcheck.Report{Checked: time.Now(), Results: []mailcheck.Result{}} } writeJSON(w, http.StatusOK, rep) return nil } // mailLoop checks a minute after the start, then every mailCheckEvery. func (s *Server) mailLoop(ctx context.Context) { wait := time.Minute for { select { case <-ctx.Done(): return case <-time.After(wait): s.checkMail(ctx) wait = mailCheckEvery } } }