150 lines
3.9 KiB
Go
150 lines
3.9 KiB
Go
//go:build standalone
|
|
|
|
package checker
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/miekg/dns"
|
|
)
|
|
|
|
// stubTLSA returns a synthetic TLSA RR with the given fields, avoiding the
|
|
// textual-parse boilerplate of dns.NewRR.
|
|
func stubTLSA(owner string, usage, selector, matching uint8, cert string) *dns.TLSA {
|
|
return &dns.TLSA{
|
|
Hdr: dns.RR_Header{Name: dns.Fqdn(owner), Rrtype: dns.TypeTLSA, Class: dns.ClassINET, Ttl: 3600},
|
|
Usage: usage,
|
|
Selector: selector,
|
|
MatchingType: matching,
|
|
Certificate: cert,
|
|
}
|
|
}
|
|
|
|
func withStubLookup(t *testing.T, records []*dns.TLSA, err error) {
|
|
t.Helper()
|
|
withStubLookupValidated(t, records, true, err)
|
|
}
|
|
|
|
func withStubLookupValidated(t *testing.T, records []*dns.TLSA, validated bool, err error) {
|
|
t.Helper()
|
|
prev := tlsaLookup
|
|
tlsaLookup = func(_ context.Context, _ string) ([]*dns.TLSA, bool, error) {
|
|
return records, validated, err
|
|
}
|
|
t.Cleanup(func() { tlsaLookup = prev })
|
|
}
|
|
|
|
func postForm(values url.Values) *http.Request {
|
|
req := httptest.NewRequest("POST", "/check", strings.NewReader(values.Encode()))
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
req.ParseForm()
|
|
return req
|
|
}
|
|
|
|
func TestParseForm_PopulatesServiceFromDNS(t *testing.T) {
|
|
withStubLookup(t, []*dns.TLSA{
|
|
stubTLSA("_443._tcp.example.com", 3, 1, 1, "DEADBEEF"),
|
|
stubTLSA("_443._tcp.example.com", 2, 0, 1, "cafebabe"),
|
|
}, nil)
|
|
|
|
p := &daneProvider{}
|
|
opts, err := p.ParseForm(postForm(url.Values{
|
|
"domain_name": {"example.com"},
|
|
"port": {"443"},
|
|
"proto": {"tcp"},
|
|
}))
|
|
if err != nil {
|
|
t.Fatalf("ParseForm: %v", err)
|
|
}
|
|
svc, ok := opts[OptionService].(serviceMessage)
|
|
if !ok {
|
|
t.Fatalf("service option has wrong type: %#v", opts[OptionService])
|
|
}
|
|
if svc.Type != serviceType {
|
|
t.Errorf("service type = %q, want %q", svc.Type, serviceType)
|
|
}
|
|
if svc.Domain != "example.com" {
|
|
t.Errorf("service domain = %q, want example.com", svc.Domain)
|
|
}
|
|
|
|
var body struct {
|
|
TLSA []struct {
|
|
Hdr struct {
|
|
Name string
|
|
}
|
|
Usage uint8
|
|
Selector uint8
|
|
MatchingType uint8
|
|
Certificate string
|
|
} `json:"tlsa"`
|
|
}
|
|
if err := json.Unmarshal(svc.Service, &body); err != nil {
|
|
t.Fatalf("decode service body: %v", err)
|
|
}
|
|
if len(body.TLSA) != 2 {
|
|
t.Fatalf("got %d TLSA entries, want 2", len(body.TLSA))
|
|
}
|
|
if body.TLSA[0].Certificate != "deadbeef" {
|
|
t.Errorf("expected lowercased cert, got %q", body.TLSA[0].Certificate)
|
|
}
|
|
if body.TLSA[0].Hdr.Name != "_443._tcp.example.com" {
|
|
t.Errorf("owner = %q, want _443._tcp.example.com", body.TLSA[0].Hdr.Name)
|
|
}
|
|
}
|
|
|
|
func TestParseForm_NoRecordsIsError(t *testing.T) {
|
|
withStubLookup(t, nil, nil)
|
|
|
|
p := &daneProvider{}
|
|
_, err := p.ParseForm(postForm(url.Values{
|
|
"domain_name": {"example.com"},
|
|
"port": {"443"},
|
|
"proto": {"tcp"},
|
|
}))
|
|
if err == nil {
|
|
t.Fatal("expected error when no TLSA records found, got nil")
|
|
}
|
|
if !strings.Contains(err.Error(), "no TLSA records") {
|
|
t.Errorf("unexpected error %v", err)
|
|
}
|
|
}
|
|
|
|
func TestParseForm_StartTLSOverride(t *testing.T) {
|
|
withStubLookup(t, []*dns.TLSA{stubTLSA("_25._tcp.mail.example.com", 3, 1, 1, "aa")}, nil)
|
|
|
|
p := &daneProvider{}
|
|
opts, err := p.ParseForm(postForm(url.Values{
|
|
"domain_name": {"mail.example.com"},
|
|
"port": {"25"},
|
|
"proto": {"tcp"},
|
|
"starttls": {"smtp"},
|
|
}))
|
|
if err != nil {
|
|
t.Fatalf("ParseForm: %v", err)
|
|
}
|
|
override, ok := opts[OptionSTARTTLS].(map[string]string)
|
|
if !ok {
|
|
t.Fatalf("starttls option type = %T", opts[OptionSTARTTLS])
|
|
}
|
|
if override["25/tcp"] != "smtp" {
|
|
t.Errorf("override[25/tcp] = %q, want smtp", override["25/tcp"])
|
|
}
|
|
}
|
|
|
|
func TestParseForm_InvalidPort(t *testing.T) {
|
|
p := &daneProvider{}
|
|
_, err := p.ParseForm(postForm(url.Values{
|
|
"domain_name": {"example.com"},
|
|
"port": {"0"},
|
|
"proto": {"tcp"},
|
|
}))
|
|
if err == nil {
|
|
t.Fatal("expected error for port 0")
|
|
}
|
|
}
|