mirror of
https://blitiri.com.ar/repos/chasquid
synced 2025-12-17 14:37:02 +00:00
The spf library has gained support for macros, but to process them properly, a new function needs to be called with the full sender address, spf.CheckHostWithSender. This patch updates chasquid's calls to the new API.
119 lines
2.4 KiB
Go
119 lines
2.4 KiB
Go
// smtp-check is a command-line too for checking SMTP setups.
|
|
//
|
|
// +build !coverage
|
|
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"flag"
|
|
"log"
|
|
"net"
|
|
"net/smtp"
|
|
"time"
|
|
|
|
"blitiri.com.ar/go/chasquid/internal/sts"
|
|
"blitiri.com.ar/go/chasquid/internal/tlsconst"
|
|
"blitiri.com.ar/go/spf"
|
|
|
|
"golang.org/x/net/idna"
|
|
)
|
|
|
|
var (
|
|
port = flag.String("port", "smtp",
|
|
"port to use for connecting to the MX servers")
|
|
skipTLSCheck = flag.Bool("skip_tls_check", false,
|
|
"skip TLS check (useful if connections are blocked)")
|
|
)
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
|
|
domain := flag.Arg(0)
|
|
if domain == "" {
|
|
log.Fatal("Use: smtp-check <domain>")
|
|
}
|
|
|
|
domain, err := idna.ToASCII(domain)
|
|
if err != nil {
|
|
log.Fatalf("IDNA conversion failed: %v", err)
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
|
|
log.Printf("=== STS policy")
|
|
policy, err := sts.UncheckedFetch(ctx, domain)
|
|
if err != nil {
|
|
log.Printf("Not available (%s)", err)
|
|
} else {
|
|
log.Printf("Parsed contents: [%+v]\n", *policy)
|
|
if err := policy.Check(); err != nil {
|
|
log.Fatalf("Invalid: %v", err)
|
|
}
|
|
log.Printf("OK")
|
|
}
|
|
|
|
mxs, err := net.LookupMX(domain)
|
|
if err != nil {
|
|
log.Fatalf("MX lookup: %v", err)
|
|
}
|
|
|
|
if len(mxs) == 0 {
|
|
log.Fatalf("MX lookup returned no results")
|
|
}
|
|
|
|
for _, mx := range mxs {
|
|
log.Printf("=== Testing MX: %2d %s", mx.Pref, mx.Host)
|
|
|
|
ips, err := net.LookupIP(mx.Host)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
for _, ip := range ips {
|
|
result, err := spf.CheckHostWithSender(ip, domain, "test@"+domain)
|
|
if result != spf.Pass {
|
|
log.Printf("SPF check != pass for IP %s: %s - %s",
|
|
ip, result, err)
|
|
}
|
|
}
|
|
|
|
if *skipTLSCheck {
|
|
log.Printf("TLS check skipped")
|
|
} else {
|
|
c, err := smtp.Dial(mx.Host + ":" + *port)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
config := &tls.Config{
|
|
// Expect the server to have a certificate valid for the MX
|
|
// we're connecting to.
|
|
ServerName: mx.Host,
|
|
}
|
|
err = c.StartTLS(config)
|
|
if err != nil {
|
|
log.Fatalf("TLS error: %v", err)
|
|
}
|
|
|
|
cstate, _ := c.TLSConnectionState()
|
|
log.Printf("TLS OK: %s - %s", tlsconst.VersionName(cstate.Version),
|
|
tlsconst.CipherSuiteName(cstate.CipherSuite))
|
|
|
|
c.Close()
|
|
}
|
|
|
|
if policy != nil {
|
|
if !policy.MXIsAllowed(mx.Host) {
|
|
log.Fatalf("NOT allowed by STS policy")
|
|
}
|
|
log.Printf("Allowed by policy")
|
|
}
|
|
|
|
log.Printf("")
|
|
}
|
|
|
|
log.Printf("=== Success")
|
|
}
|