mirror of
https://github.com/hanzoai/mail.git
synced 2026-09-23 23:53:02 +00:00
Fork of github.com/mjl-/mox at 5656ca6d1b
(upstream v0.0.15 plus 55 commits).
Rename the module path in go.mod and the import paths in 268 Go files. Also
update the five scripts that "go install" the module (genwebsite.sh,
docker-release.sh, apidiff.sh, test-upgrade.sh, Dockerfile.release), which
would otherwise build upstream rather than this fork.
Add NOTICE recording the upstream project, author, license, and fork point,
and stating which license covers which files: MIT for the mox source and our
changes, MPL-2.0 for publicsuffix/public_suffix_list.txt alone, and the
vendored dependencies' own licenses under licenses/. Embed NOTICE so
"mail licenses" prints the lineage from the running binary. LICENSE.MIT,
LICENSE.MPLv2.0 and the licenses/ tree are preserved verbatim; no code is
relicensed.
The mox command name, config keys, data directory layout and website content
are unchanged. LLM.md records the fork point, the rename, what was left alone,
and the steps to stand the server up.
Co-authored-by: Hanzo Dev <[email protected]>
87 lines
2.8 KiB
Go
87 lines
2.8 KiB
Go
// Package iprev checks if an IP has a reverse DNS name configured and that the
|
|
// reverse DNS name resolves back to the IP (RFC 8601, Section 3).
|
|
package iprev
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"log/slog"
|
|
"net"
|
|
"slices"
|
|
"time"
|
|
|
|
"github.com/hanzoai/mail/dns"
|
|
"github.com/hanzoai/mail/mlog"
|
|
"github.com/hanzoai/mail/stub"
|
|
)
|
|
|
|
var xlog = mlog.New("iprev", nil)
|
|
|
|
var (
|
|
MetricIPRev stub.HistogramVec = stub.HistogramVecIgnore{}
|
|
)
|
|
|
|
// Lookup errors.
|
|
var (
|
|
ErrNoRecord = errors.New("iprev: no reverse dns record")
|
|
ErrDNS = errors.New("iprev: dns lookup") // Temporary error.
|
|
)
|
|
|
|
// ../rfc/8601:1082
|
|
|
|
// Status is the result of a lookup.
|
|
type Status string
|
|
|
|
const (
|
|
StatusPass Status = "pass" // Reverse and forward lookup results were in agreement.
|
|
StatusFail Status = "fail" // Reverse and forward lookup results were not in agreement, but at least the reverse name does exist.
|
|
StatusTemperror Status = "temperror" // Temporary error, e.g. DNS timeout.
|
|
StatusPermerror Status = "permerror" // Permanent error and later retry is unlikely to succeed. E.g. no PTR record.
|
|
)
|
|
|
|
// Lookup checks whether an IP has a proper reverse & forward
|
|
// DNS configuration. I.e. that it is explicitly associated with its domain name.
|
|
//
|
|
// A PTR lookup is done on the IP, resulting in zero or more names. These names are
|
|
// forward resolved (A or AAAA) until the original IP address is found. The first
|
|
// matching name is returned as "name". All names, matching or not, are returned as
|
|
// "names".
|
|
//
|
|
// If a temporary error occurred, rerr is set.
|
|
func Lookup(ctx context.Context, resolver dns.Resolver, ip net.IP) (rstatus Status, name string, names []string, authentic bool, rerr error) {
|
|
log := xlog.WithContext(ctx)
|
|
start := time.Now()
|
|
defer func() {
|
|
MetricIPRev.ObserveLabels(float64(time.Since(start))/float64(time.Second), string(rstatus))
|
|
log.Debugx("iprev lookup result", rerr,
|
|
slog.Any("ip", ip),
|
|
slog.Any("status", rstatus),
|
|
slog.Duration("duration", time.Since(start)))
|
|
}()
|
|
|
|
revNames, result, revErr := dns.WithPackage(resolver, "iprev").LookupAddr(ctx, ip.String())
|
|
if dns.IsNotFound(revErr) {
|
|
return StatusPermerror, "", nil, result.Authentic, ErrNoRecord
|
|
} else if revErr != nil {
|
|
return StatusTemperror, "", nil, result.Authentic, fmt.Errorf("%w: %s", ErrDNS, revErr)
|
|
}
|
|
|
|
var lastErr error
|
|
authentic = result.Authentic
|
|
for _, rname := range revNames {
|
|
ips, result, err := dns.WithPackage(resolver, "iprev").LookupIP(ctx, "ip", rname)
|
|
authentic = authentic && result.Authentic
|
|
if slices.ContainsFunc(ips, ip.Equal) {
|
|
return StatusPass, rname, revNames, authentic, nil
|
|
}
|
|
if err != nil && !dns.IsNotFound(err) {
|
|
lastErr = err
|
|
}
|
|
}
|
|
if lastErr != nil {
|
|
return StatusTemperror, "", revNames, authentic, fmt.Errorf("%w: %s", ErrDNS, lastErr)
|
|
}
|
|
return StatusFail, "", revNames, authentic, nil
|
|
}
|