142 lines
4.4 KiB
Go
142 lines
4.4 KiB
Go
package setup
|
|
|
|
import (
|
|
stdcontext "context"
|
|
"net"
|
|
"testing"
|
|
|
|
"git.pcux.cn/xuans/Smail/config"
|
|
)
|
|
|
|
func TestBuildSPFRecordIncludesPublicIPv4AndIPv6(t *testing.T) {
|
|
value := buildSPFRecord("203.0.113.15", "2001:db8::15")
|
|
want := "v=spf1 ip4:203.0.113.15 ip6:2001:db8::15 ~all"
|
|
if value != want {
|
|
t.Fatalf("SPF record = %q, want %q", value, want)
|
|
}
|
|
}
|
|
|
|
func TestBuildSPFRecordSkipsUnsafeAddresses(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
ipv4 string
|
|
ipv6 string
|
|
want string
|
|
}{
|
|
{name: "empty", want: "v=spf1 ~all"},
|
|
{name: "private IPv4", ipv4: "192.168.1.20", want: "v=spf1 ~all"},
|
|
{name: "link local IPv6", ipv6: "fe80::1", want: "v=spf1 ~all"},
|
|
{name: "only IPv4", ipv4: "198.51.100.9", want: "v=spf1 ip4:198.51.100.9 ~all"},
|
|
{name: "only IPv6", ipv6: "2001:db8::9", want: "v=spf1 ip6:2001:db8::9 ~all"},
|
|
}
|
|
for _, item := range cases {
|
|
t.Run(item.name, func(t *testing.T) {
|
|
if value := buildSPFRecord(item.ipv4, item.ipv6); value != item.want {
|
|
t.Fatalf("SPF record = %q, want %q", value, item.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBuildDNSItemsIncludesSPFAndQuarantineDMARC(t *testing.T) {
|
|
cfg := &config.Config{
|
|
Domain: "example.com",
|
|
WebDomain: "mail.example.com",
|
|
}
|
|
items := buildDNSItems(cfg, "example.com", "v=DKIM1; k=rsa; p=test", "203.0.113.10", "2001:db8::10", "")
|
|
|
|
values := make(map[string]string)
|
|
for _, item := range items {
|
|
if item.Type == "TXT" {
|
|
values[item.Host] = item.Value
|
|
}
|
|
}
|
|
if value := values["@"]; value != "v=spf1 ip4:203.0.113.10 ip6:2001:db8::10 ~all" {
|
|
t.Fatalf("SPF TXT value = %q", value)
|
|
}
|
|
if value := values["_dmarc"]; value != "v=DMARC1; p=quarantine; rua=mailto:admin@example.com" {
|
|
t.Fatalf("DMARC TXT value = %q", value)
|
|
}
|
|
if value := values["default._domainkey"]; value != "v=DKIM1; k=rsa; p=test" {
|
|
t.Fatalf("DKIM TXT value = %q", value)
|
|
}
|
|
}
|
|
|
|
func TestBuildDNSItemsCreatesExpectedRecordShape(t *testing.T) {
|
|
cfg := &config.Config{
|
|
Domain: "example.com",
|
|
WebDomain: "panel.example.com",
|
|
}
|
|
items := buildDNSItemsWithWebIPv4(cfg, "example.com", "v=DKIM1; k=rsa; p=test", "198.51.100.20", "2001:db8::20", "", []string{"203.0.113.20"})
|
|
|
|
if len(items) != 10 {
|
|
t.Fatalf("DNS item count = %d, want 10", len(items))
|
|
}
|
|
if items[0].Host != "panel" || items[0].Type != "A" || items[0].Value != "203.0.113.20" {
|
|
t.Fatalf("web A record = %#v", items[0])
|
|
}
|
|
if items[4].Host != "@" || items[4].Type != "A" || items[4].Value != "198.51.100.20" {
|
|
t.Fatalf("root A record = %#v", items[4])
|
|
}
|
|
if items[5].Type != "AAAA" || items[5].Host != "@" || items[5].Value != "2001:db8::20" {
|
|
t.Fatalf("root AAAA record = %#v", items[5])
|
|
}
|
|
if items[6].Value != "smtp.example.com | 1" || items[6].TTL != dnsRecordTTL {
|
|
t.Fatalf("MX record = %#v", items[6])
|
|
}
|
|
}
|
|
|
|
func TestBuildDNSItemsDoesNotReuseMailIPForUnresolvedWebDomain(t *testing.T) {
|
|
cfg := &config.Config{
|
|
Domain: "example.net",
|
|
WebDomain: "panel.example.net",
|
|
}
|
|
items := buildDNSItemsWithWebIPv4(cfg, "example.net", "v=DKIM1; k=rsa; p=test", "198.51.100.30", "", "", nil)
|
|
|
|
if items[0].Host != "panel" || items[0].Value != unresolvedWebIPv4 {
|
|
t.Fatalf("unresolved web A record = %#v", items[0])
|
|
}
|
|
if items[1].Host != "smtp" || items[1].Value != "198.51.100.30" {
|
|
t.Fatalf("mail A record = %#v", items[1])
|
|
}
|
|
}
|
|
|
|
func TestResolvePublicIPv4UsesActualLookupResults(t *testing.T) {
|
|
lookup := func(ctx stdcontext.Context, host string) ([]net.IP, error) {
|
|
if host != "panel.example.org" {
|
|
t.Fatalf("lookup host = %q", host)
|
|
}
|
|
return []net.IP{
|
|
net.ParseIP("203.0.113.40"),
|
|
net.ParseIP("192.168.1.40"),
|
|
net.ParseIP("203.0.113.40"),
|
|
}, nil
|
|
}
|
|
|
|
values := resolvePublicIPv4WithLookup("Panel.Example.Org.", lookup)
|
|
if len(values) != 1 || values[0] != "203.0.113.40" {
|
|
t.Fatalf("resolved public IPv4 = %#v", values)
|
|
}
|
|
}
|
|
|
|
func TestDNSHostForDomain(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
web string
|
|
domain string
|
|
want string
|
|
}{
|
|
{name: "subdomain", web: "mail.example.com", domain: "example.com", want: "mail"},
|
|
{name: "root", web: "example.com", domain: "example.com", want: "@"},
|
|
{name: "trailing dot", web: "mail.example.com.", domain: "example.com.", want: "mail"},
|
|
{name: "external domain", web: "panel.other.example", domain: "example.com", want: "panel.other.example"},
|
|
}
|
|
for _, item := range cases {
|
|
t.Run(item.name, func(t *testing.T) {
|
|
if value := dnsHostForDomain(item.web, item.domain); value != item.want {
|
|
t.Fatalf("DNS host = %q, want %q", value, item.want)
|
|
}
|
|
})
|
|
}
|
|
}
|