diff --git a/va/va.go b/va/va.go index 3399bb7b7..95ad58819 100644 --- a/va/va.go +++ b/va/va.go @@ -14,9 +14,11 @@ import ( "net" "net/http" "net/url" + "os" "strconv" "strings" "sync" + "syscall" "time" "github.com/jmhodges/clock" @@ -662,9 +664,12 @@ func detailedError(err error) *probs.ProblemDetails { if netErr, ok := err.(*net.OpError); ok { if fmt.Sprintf("%T", netErr.Err) == "tls.alert" { - // As of Go 1.8, all the tls.alert error strings are reasonable to hand back to a - // user. + // All the tls.alert error strings are reasonable to hand back to a + // user. Confirmed against Go 1.8. return probs.TLSError(netErr.Error()) + } else if syscallErr, ok := netErr.Err.(*os.SyscallError); ok && + syscallErr.Err == syscall.ECONNREFUSED { + return probs.ConnectionFailure("Connection refused") } } if err, ok := err.(net.Error); ok && err.Timeout() { diff --git a/va/va_test.go b/va/va_test.go index a0aa932b2..6170f1acd 100644 --- a/va/va_test.go +++ b/va/va_test.go @@ -17,10 +17,12 @@ import ( "net/http" "net/http/httptest" "net/url" + "os" "regexp" "strconv" "strings" "sync" + "syscall" "testing" "time" @@ -241,6 +243,9 @@ func TestHTTPBadPort(t *testing.T) { t.Fatalf("Server's down; expected refusal. Where did we connect?") } test.AssertEquals(t, prob.Type, probs.ConnectionProblem) + if !strings.Contains(prob.Detail, "Connection refused") { + t.Errorf("Expected a connection refused error, got %q", prob.Detail) + } } func TestHTTP(t *testing.T) { @@ -404,7 +409,7 @@ func TestHTTPRedirectLookup(t *testing.T) { setChallengeToken(&chall, pathRedirectToFailingURL) _, prob = va.validateHTTP01(ctx, ident, chall) test.AssertNotNil(t, prob, "Problem Details should not be nil") - test.AssertEquals(t, prob.Detail, "Fetching http://other.valid/500: Error getting validation data") + test.AssertEquals(t, prob.Detail, "Fetching http://other.valid/500: Connection refused") } func TestHTTPRedirectLoop(t *testing.T) { @@ -1476,3 +1481,19 @@ func TestPerformRemoteValidation(t *testing.T) { t.Errorf("PerformValidation didn't return early on failure: took %s, expected <5s", took) } } + +func TestDetailedError(t *testing.T) { + err := &net.OpError{ + Op: "dial", + Net: "tcp", + Err: &os.SyscallError{ + Syscall: "getsockopt", + Err: syscall.ECONNREFUSED, + }, + } + expected := "Connection refused" + actual := detailedError(err).Detail + if actual != expected { + t.Errorf("Wrong detail for connection refused. Got %q, expected %q", actual, expected) + } +}