diff --git a/README.md b/README.md index 1df2e2e..bada4b1 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,8 @@ certcheck badssl.com certcheck go run . -domain badssl.com -port 443 -format long certcheck -domain self-signed.badssl.com -insecure -format long + +certcheck -domain badssl.com -timeout 5s ``` ## Notes diff --git a/main.go b/main.go index 1140ff9..6625330 100644 --- a/main.go +++ b/main.go @@ -5,6 +5,7 @@ import ( "crypto/x509" "flag" "fmt" + "net" "os" "time" ) @@ -21,6 +22,7 @@ type Config struct { Port int Insecure bool Format OutputFormat + Timeout time.Duration } func main() { @@ -31,6 +33,7 @@ func main() { flag.IntVar(&config.Port, "port", 443, "Port to check") flag.BoolVar(&config.Insecure, "insecure", false, "Accept invalid certificate") flag.StringVar(&formatStr, "format", "short", "Output format (short|long)") + flag.DurationVar(&config.Timeout, "timeout", 10*time.Second, "Connection timeout") flag.Parse() if config.Domain == "" { @@ -52,7 +55,7 @@ func main() { os.Exit(1) } - cert, err := getCertificate(config.Domain, config.Port, config.Insecure) + cert, err := getCertificate(config.Domain, config.Port, config.Insecure, config.Timeout) if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) @@ -61,7 +64,7 @@ func main() { printCertificate(cert, config.Format) } -func getCertificate(domain string, port int, insecure bool) (*x509.Certificate, error) { +func getCertificate(domain string, port int, insecure bool, timeout time.Duration) (*x509.Certificate, error) { address := fmt.Sprintf("%s:%d", domain, port) tlsConfig := &tls.Config{ @@ -69,7 +72,8 @@ func getCertificate(domain string, port int, insecure bool) (*x509.Certificate, InsecureSkipVerify: insecure, } - conn, err := tls.Dial("tcp", address, tlsConfig) + dialer := &net.Dialer{Timeout: timeout} + conn, err := tls.DialWithDialer(dialer, "tcp", address, tlsConfig) if err != nil { return nil, fmt.Errorf("failed to connect to %s: %w", address, err) } diff --git a/main_test.go b/main_test.go new file mode 100644 index 0000000..595a31d --- /dev/null +++ b/main_test.go @@ -0,0 +1,19 @@ +package main + +import ( + "testing" + "time" +) + +func TestGetCertificateTimeout(t *testing.T) { + start := time.Now() + _, err := getCertificate("10.255.255.1", 443, false, 200*time.Millisecond) + elapsed := time.Since(start) + + if err == nil { + t.Fatal("expected an error dialing a non-routable address, got nil") + } + if elapsed > 2*time.Second { + t.Fatalf("getCertificate took %s, expected it to time out quickly", elapsed) + } +}