2015-12-03 20:01:46 +00:00
|
|
|
package acme
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
2016-01-27 01:01:58 +00:00
|
|
|
"crypto/rand"
|
2015-12-03 20:01:46 +00:00
|
|
|
"crypto/rsa"
|
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
|
|
|
"os"
|
2016-02-03 04:03:03 +00:00
|
|
|
"sort"
|
2015-12-03 20:01:46 +00:00
|
|
|
"testing"
|
|
|
|
"time"
|
2016-07-29 17:41:07 +00:00
|
|
|
|
2018-09-15 17:16:35 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
2016-11-03 18:37:15 +00:00
|
|
|
|
2015-12-03 20:01:46 +00:00
|
|
|
func TestDNSValidServerResponse(t *testing.T) {
|
2016-08-10 05:15:54 +00:00
|
|
|
PreCheckDNS = func(fqdn, value string) (bool, error) {
|
2016-02-10 14:52:53 +00:00
|
|
|
return true, nil
|
2016-01-22 00:38:15 +00:00
|
|
|
}
|
2018-09-15 17:16:35 +00:00
|
|
|
|
|
|
|
privKey, err := rsa.GenerateKey(rand.Reader, 512)
|
|
|
|
require.NoError(t, err)
|
2015-12-03 20:01:46 +00:00
|
|
|
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
w.Header().Add("Replay-Nonce", "12345")
|
|
|
|
w.Write([]byte("{\"type\":\"dns01\",\"status\":\"valid\",\"uri\":\"http://some.url\",\"token\":\"http8\"}"))
|
|
|
|
}))
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
time.Sleep(time.Second * 2)
|
|
|
|
f := bufio.NewWriter(os.Stdout)
|
|
|
|
defer f.Flush()
|
|
|
|
f.WriteString("\n")
|
|
|
|
}()
|
|
|
|
|
2018-09-15 17:16:35 +00:00
|
|
|
manualProvider, err := NewDNSProviderManual()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
clientChallenge := challenge{Type: "dns01", Status: "pending", URL: ts.URL, Token: "http8"}
|
|
|
|
|
|
|
|
solver := &dnsChallenge{
|
|
|
|
jws: &jws{privKey: privKey, getNonceURL: ts.URL},
|
|
|
|
validate: validate,
|
|
|
|
provider: manualProvider,
|
2015-12-03 20:01:46 +00:00
|
|
|
}
|
2018-09-15 17:16:35 +00:00
|
|
|
|
|
|
|
err = solver.Solve(clientChallenge, "example.com")
|
|
|
|
require.NoError(t, err)
|
2015-12-03 20:01:46 +00:00
|
|
|
}
|
2016-01-30 18:39:10 +00:00
|
|
|
|
|
|
|
func TestPreCheckDNS(t *testing.T) {
|
2016-08-10 05:15:54 +00:00
|
|
|
ok, err := PreCheckDNS("acme-staging.api.letsencrypt.org", "fe01=")
|
2016-02-10 14:52:53 +00:00
|
|
|
if err != nil || !ok {
|
2018-09-15 17:16:35 +00:00
|
|
|
t.Errorf("PreCheckDNS failed for acme-staging.api.letsencrypt.org")
|
2016-01-30 18:39:10 +00:00
|
|
|
}
|
|
|
|
}
|
2016-02-03 04:03:03 +00:00
|
|
|
|
|
|
|
func TestLookupNameserversOK(t *testing.T) {
|
2018-09-15 17:16:35 +00:00
|
|
|
testCases := []struct {
|
|
|
|
fqdn string
|
|
|
|
nss []string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
fqdn: "books.google.com.ng.",
|
|
|
|
nss: []string{"ns1.google.com.", "ns2.google.com.", "ns3.google.com.", "ns4.google.com."},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
fqdn: "www.google.com.",
|
|
|
|
nss: []string{"ns1.google.com.", "ns2.google.com.", "ns3.google.com.", "ns4.google.com."},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
fqdn: "physics.georgetown.edu.",
|
|
|
|
nss: []string{"ns1.georgetown.edu.", "ns2.georgetown.edu.", "ns3.georgetown.edu."},
|
|
|
|
},
|
|
|
|
}
|
2016-02-03 04:03:03 +00:00
|
|
|
|
2018-09-15 17:16:35 +00:00
|
|
|
for _, test := range testCases {
|
|
|
|
test := test
|
|
|
|
t.Run(test.fqdn, func(t *testing.T) {
|
|
|
|
t.Parallel()
|
2016-02-03 04:03:03 +00:00
|
|
|
|
2018-09-15 17:16:35 +00:00
|
|
|
nss, err := lookupNameservers(test.fqdn)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
sort.Strings(nss)
|
|
|
|
sort.Strings(test.nss)
|
|
|
|
|
|
|
|
assert.EqualValues(t, test.nss, nss)
|
|
|
|
})
|
2016-02-03 04:03:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestLookupNameserversErr(t *testing.T) {
|
2018-09-15 17:16:35 +00:00
|
|
|
testCases := []struct {
|
|
|
|
desc string
|
|
|
|
fqdn string
|
|
|
|
error string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
desc: "invalid tld",
|
|
|
|
fqdn: "_null.n0n0.",
|
|
|
|
error: "could not determine the zone",
|
|
|
|
},
|
|
|
|
}
|
2016-02-03 04:03:03 +00:00
|
|
|
|
2018-09-15 17:16:35 +00:00
|
|
|
for _, test := range testCases {
|
|
|
|
test := test
|
|
|
|
t.Run(test.desc, func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
_, err := lookupNameservers(test.fqdn)
|
|
|
|
require.Error(t, err)
|
|
|
|
assert.Contains(t, err.Error(), test.error)
|
|
|
|
})
|
2016-02-03 04:03:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-29 17:41:07 +00:00
|
|
|
func TestFindZoneByFqdn(t *testing.T) {
|
2018-09-15 17:16:35 +00:00
|
|
|
testCases := []struct {
|
|
|
|
desc string
|
|
|
|
fqdn string
|
|
|
|
zone string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
desc: "domain is a CNAME",
|
|
|
|
fqdn: "mail.google.com.",
|
|
|
|
zone: "google.com.",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "domain is a non-existent subdomain",
|
|
|
|
fqdn: "foo.google.com.",
|
|
|
|
zone: "google.com.",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "domain is a eTLD",
|
|
|
|
fqdn: "example.com.ac.",
|
|
|
|
zone: "ac.",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "domain is a cross-zone CNAME",
|
|
|
|
fqdn: "cross-zone-example.assets.sh.",
|
|
|
|
zone: "assets.sh.",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, test := range testCases {
|
|
|
|
test := test
|
|
|
|
t.Run(test.desc, func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
zone, err := FindZoneByFqdn(test.fqdn, RecursiveNameservers)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
assert.Equal(t, test.zone, zone)
|
|
|
|
})
|
2016-07-29 17:41:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-03 04:03:03 +00:00
|
|
|
func TestCheckAuthoritativeNss(t *testing.T) {
|
2018-09-15 17:16:35 +00:00
|
|
|
testCases := []struct {
|
|
|
|
desc string
|
|
|
|
fqdn, value string
|
|
|
|
ns []string
|
|
|
|
expected bool
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
desc: "TXT RR w/ expected value",
|
|
|
|
fqdn: "8.8.8.8.asn.routeviews.org.",
|
|
|
|
value: "151698.8.8.024",
|
|
|
|
ns: []string{"asnums.routeviews.org."},
|
|
|
|
expected: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "No TXT RR",
|
|
|
|
fqdn: "ns1.google.com.",
|
|
|
|
ns: []string{"ns2.google.com."},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, test := range testCases {
|
|
|
|
test := test
|
|
|
|
t.Run(test.desc, func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
ok, _ := checkAuthoritativeNss(test.fqdn, test.value, test.ns)
|
|
|
|
assert.Equal(t, test.expected, ok, test.fqdn)
|
|
|
|
})
|
2016-02-03 04:03:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCheckAuthoritativeNssErr(t *testing.T) {
|
2018-09-15 17:16:35 +00:00
|
|
|
testCases := []struct {
|
|
|
|
desc string
|
|
|
|
fqdn, value string
|
|
|
|
ns []string
|
|
|
|
error string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
desc: "TXT RR /w unexpected value",
|
|
|
|
fqdn: "8.8.8.8.asn.routeviews.org.",
|
|
|
|
value: "fe01=",
|
|
|
|
ns: []string{"asnums.routeviews.org."},
|
|
|
|
error: "did not return the expected TXT record",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "No TXT RR",
|
|
|
|
fqdn: "ns1.google.com.",
|
|
|
|
value: "fe01=",
|
|
|
|
ns: []string{"ns2.google.com."},
|
|
|
|
error: "did not return the expected TXT record",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, test := range testCases {
|
|
|
|
test := test
|
|
|
|
t.Run(test.desc, func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
_, err := checkAuthoritativeNss(test.fqdn, test.value, test.ns)
|
|
|
|
require.Error(t, err)
|
|
|
|
assert.Contains(t, err.Error(), test.error)
|
|
|
|
})
|
2016-02-03 04:03:03 +00:00
|
|
|
}
|
|
|
|
}
|
2016-11-03 18:37:15 +00:00
|
|
|
|
|
|
|
func TestResolveConfServers(t *testing.T) {
|
2018-09-15 17:16:35 +00:00
|
|
|
var testCases = []struct {
|
|
|
|
fixture string
|
|
|
|
expected []string
|
|
|
|
defaults []string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
fixture: "testdata/resolv.conf.1",
|
|
|
|
defaults: []string{"127.0.0.1:53"},
|
|
|
|
expected: []string{"10.200.3.249:53", "10.200.3.250:5353", "[2001:4860:4860::8844]:53", "[10.0.0.1]:5353"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
fixture: "testdata/resolv.conf.nonexistant",
|
|
|
|
defaults: []string{"127.0.0.1:53"},
|
|
|
|
expected: []string{"127.0.0.1:53"},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, test := range testCases {
|
|
|
|
t.Run(test.fixture, func(t *testing.T) {
|
|
|
|
|
|
|
|
result := getNameservers(test.fixture, test.defaults)
|
|
|
|
|
|
|
|
sort.Strings(result)
|
|
|
|
sort.Strings(test.expected)
|
|
|
|
|
|
|
|
assert.Equal(t, test.expected, result)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestToFqdn(t *testing.T) {
|
|
|
|
testCases := []struct {
|
|
|
|
desc string
|
|
|
|
domain string
|
|
|
|
expected string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
desc: "simple",
|
|
|
|
domain: "foo.bar.com",
|
|
|
|
expected: "foo.bar.com.",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "already FQDN",
|
|
|
|
domain: "foo.bar.com.",
|
|
|
|
expected: "foo.bar.com.",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, test := range testCases {
|
|
|
|
test := test
|
|
|
|
t.Run(test.desc, func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
fqdn := ToFqdn(test.domain)
|
|
|
|
assert.Equal(t, test.expected, fqdn)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUnFqdn(t *testing.T) {
|
|
|
|
testCases := []struct {
|
|
|
|
desc string
|
|
|
|
fqdn string
|
|
|
|
expected string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
desc: "simple",
|
|
|
|
fqdn: "foo.bar.com.",
|
|
|
|
expected: "foo.bar.com",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "already domain",
|
|
|
|
fqdn: "foo.bar.com",
|
|
|
|
expected: "foo.bar.com",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, test := range testCases {
|
|
|
|
test := test
|
|
|
|
t.Run(test.desc, func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
domain := UnFqdn(test.fqdn)
|
|
|
|
|
|
|
|
assert.Equal(t, test.expected, domain)
|
|
|
|
})
|
2016-11-03 18:37:15 +00:00
|
|
|
}
|
|
|
|
}
|