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
|
|
|
"reflect"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
2015-12-03 20:01:46 +00:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2016-02-03 04:03:03 +00:00
|
|
|
var lookupNameserversTestsOK = []struct {
|
|
|
|
fqdn string
|
|
|
|
nss []string
|
|
|
|
}{
|
|
|
|
{"books.google.com.ng.",
|
|
|
|
[]string{"ns1.google.com.", "ns2.google.com.", "ns3.google.com.", "ns4.google.com."},
|
|
|
|
},
|
|
|
|
{"www.google.com.",
|
|
|
|
[]string{"ns1.google.com.", "ns2.google.com.", "ns3.google.com.", "ns4.google.com."},
|
|
|
|
},
|
|
|
|
{"physics.georgetown.edu.",
|
|
|
|
[]string{"ns1.georgetown.edu.", "ns2.georgetown.edu.", "ns3.georgetown.edu."},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var lookupNameserversTestsErr = []struct {
|
|
|
|
fqdn string
|
|
|
|
error string
|
|
|
|
}{
|
|
|
|
// invalid tld
|
|
|
|
{"_null.n0n0.",
|
2016-02-29 07:46:15 +00:00
|
|
|
"Could not determine zone authoritatively",
|
2016-02-03 04:03:03 +00:00
|
|
|
},
|
|
|
|
// invalid domain
|
|
|
|
{"_null.com.",
|
2016-02-29 07:46:15 +00:00
|
|
|
"Could not determine zone authoritatively",
|
|
|
|
},
|
|
|
|
// invalid domain
|
|
|
|
{"in-valid.co.uk.",
|
|
|
|
"Could not determine zone authoritatively",
|
2016-02-03 04:03:03 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var checkAuthoritativeNssTests = []struct {
|
|
|
|
fqdn, value string
|
|
|
|
ns []string
|
|
|
|
ok bool
|
|
|
|
}{
|
|
|
|
// TXT RR w/ expected value
|
|
|
|
{"8.8.8.8.asn.routeviews.org.", "151698.8.8.024", []string{"asnums.routeviews.org."},
|
|
|
|
true,
|
|
|
|
},
|
|
|
|
// No TXT RR
|
|
|
|
{"ns1.google.com.", "", []string{"ns2.google.com."},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var checkAuthoritativeNssTestsErr = []struct {
|
|
|
|
fqdn, value string
|
|
|
|
ns []string
|
|
|
|
error string
|
|
|
|
}{
|
|
|
|
// TXT RR /w unexpected value
|
|
|
|
{"8.8.8.8.asn.routeviews.org.", "fe01=", []string{"asnums.routeviews.org."},
|
|
|
|
"did not return the expected TXT record",
|
|
|
|
},
|
|
|
|
// No TXT RR
|
|
|
|
{"ns1.google.com.", "fe01=", []string{"ns2.google.com."},
|
|
|
|
"did not return the expected TXT record",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2015-12-03 20:01:46 +00:00
|
|
|
func TestDNSValidServerResponse(t *testing.T) {
|
2016-02-10 14:52:53 +00:00
|
|
|
preCheckDNS = func(fqdn, value string) (bool, error) {
|
|
|
|
return true, nil
|
2016-01-22 00:38:15 +00:00
|
|
|
}
|
2016-01-27 01:01:58 +00:00
|
|
|
privKey, _ := rsa.GenerateKey(rand.Reader, 512)
|
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\"}"))
|
|
|
|
}))
|
|
|
|
|
|
|
|
manualProvider, _ := NewDNSProviderManual()
|
2016-01-27 01:01:58 +00:00
|
|
|
jws := &jws{privKey: privKey, directoryURL: ts.URL}
|
2016-01-24 23:23:21 +00:00
|
|
|
solver := &dnsChallenge{jws: jws, validate: validate, provider: manualProvider}
|
2015-12-03 20:01:46 +00:00
|
|
|
clientChallenge := challenge{Type: "dns01", Status: "pending", URI: ts.URL, Token: "http8"}
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
time.Sleep(time.Second * 2)
|
|
|
|
f := bufio.NewWriter(os.Stdout)
|
|
|
|
defer f.Flush()
|
|
|
|
f.WriteString("\n")
|
|
|
|
}()
|
|
|
|
|
|
|
|
if err := solver.Solve(clientChallenge, "example.com"); err != nil {
|
|
|
|
t.Errorf("VALID: Expected Solve to return no error but the error was -> %v", err)
|
|
|
|
}
|
|
|
|
}
|
2016-01-30 18:39:10 +00:00
|
|
|
|
|
|
|
func TestPreCheckDNS(t *testing.T) {
|
2016-02-10 14:52:53 +00:00
|
|
|
ok, err := preCheckDNS("acme-staging.api.letsencrypt.org", "fe01=")
|
|
|
|
if err != nil || !ok {
|
2016-01-30 18:39:10 +00:00
|
|
|
t.Errorf("preCheckDNS failed for acme-staging.api.letsencrypt.org")
|
|
|
|
}
|
|
|
|
}
|
2016-02-03 04:03:03 +00:00
|
|
|
|
|
|
|
func TestLookupNameserversOK(t *testing.T) {
|
|
|
|
for _, tt := range lookupNameserversTestsOK {
|
|
|
|
nss, err := lookupNameservers(tt.fqdn)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("#%s: got %q; want nil", tt.fqdn, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
sort.Strings(nss)
|
|
|
|
sort.Strings(tt.nss)
|
|
|
|
|
|
|
|
if !reflect.DeepEqual(nss, tt.nss) {
|
|
|
|
t.Errorf("#%s: got %v; want %v", tt.fqdn, nss, tt.nss)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestLookupNameserversErr(t *testing.T) {
|
|
|
|
for _, tt := range lookupNameserversTestsErr {
|
|
|
|
_, err := lookupNameservers(tt.fqdn)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("#%s: expected %q (error); got <nil>", tt.fqdn, tt.error)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !strings.Contains(err.Error(), tt.error) {
|
|
|
|
t.Errorf("#%s: expected %q (error); got %q", tt.fqdn, tt.error, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCheckAuthoritativeNss(t *testing.T) {
|
|
|
|
for _, tt := range checkAuthoritativeNssTests {
|
|
|
|
ok, _ := checkAuthoritativeNss(tt.fqdn, tt.value, tt.ns)
|
|
|
|
if ok != tt.ok {
|
2016-02-19 10:19:03 +00:00
|
|
|
t.Errorf("%s: got %t; want %t", tt.fqdn, ok, tt.ok)
|
2016-02-03 04:03:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCheckAuthoritativeNssErr(t *testing.T) {
|
|
|
|
for _, tt := range checkAuthoritativeNssTestsErr {
|
|
|
|
_, err := checkAuthoritativeNss(tt.fqdn, tt.value, tt.ns)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("#%s: expected %q (error); got <nil>", tt.fqdn, tt.error)
|
|
|
|
}
|
|
|
|
if !strings.Contains(err.Error(), tt.error) {
|
|
|
|
t.Errorf("#%s: expected %q (error); got %q", tt.fqdn, tt.error, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestWaitForTimeout(t *testing.T) {
|
|
|
|
c := make(chan error)
|
|
|
|
go func() {
|
|
|
|
err := waitFor(3, 1, func() (bool, error) {
|
|
|
|
return false, nil
|
|
|
|
})
|
|
|
|
c <- err
|
|
|
|
}()
|
|
|
|
|
|
|
|
timeout := time.After(4 * time.Second)
|
|
|
|
select {
|
|
|
|
case <-timeout:
|
|
|
|
t.Fatal("timeout exceeded")
|
|
|
|
case err := <-c:
|
|
|
|
if err == nil {
|
2016-02-14 06:24:19 +00:00
|
|
|
t.Errorf("expected timeout error; got %v", err)
|
2016-02-03 04:03:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|