Skip to content

Commit

Permalink
Merge pull request #12 from atc0005/add-timeout-support
Browse files Browse the repository at this point in the history
Add timeout support for connection attempt
  • Loading branch information
atc0005 authored Jun 7, 2020
2 parents 2160c8c + a63bb94 commit 9cb3d80
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ certificate chain, expiration dates, etc).
- choice of `disabled`, `panic`, `fatal`, `error`, `warn`, `info` (the
default), `debug` or `trace`.

- Optional, user-specified timeout value for TCP connection attempt

- Go modules support (vs classic `GOPATH` setup)

[Unreleased]: https://github.com/atc0005/check-cert/compare/v0.1.0...HEAD
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ failing.
- choice of `disabled`, `panic`, `fatal`, `error`, `warn`, `info` (the
default), `debug` or `trace`.

- Optional, user-specified timeout value for TCP connection attempt

- Go modules support (vs classic `GOPATH` setup)

## Changelog
Expand Down Expand Up @@ -215,6 +217,7 @@ been tested.
| `w`, `age-warning` | No | 30 | No | *positive whole number* | The number of days remaining before certificate expiration when this application will will flag the NotAfter certificate field as a WARNING state. |
| `ll`, `log-level` | No | `info` | No | `disabled`, `panic`, `fatal`, `error`, `warn`, `info`, `debug`, `trace` | Log message priority filter. Log messages with a lower level are ignored. |
| `p`, `port` | No | `443` | No | *positive whole number between 1-65535, inclusive* | TCP port of the remote certificate-enabled service. This is usually 443 (HTTPS) or 636 (LDAPS). |
| `t`, `timeout` | No | `10` | No | *positive whole number* | Timeout value in seconds allowed before the connection attempt to a remote certificate-enabled service is abandoned and an error returned. |
| `se`, `sans-entries` | No | | | *comma-separated list of values* | One or many Subject Alternate Names (SANs) expected for the certificate used by the remote service. If provided, this list of comma-separated (optional) values is required for the certificate to pass validation. If the case-insensitive SKIPSANSCHECKS keyword is provided this validation will be skipped, effectively turning the use of this flag into a NOOP. |
| `s`, `server` | **Yes** | | | *fully-qualified domain name or IP Address* | The fully-qualified domain name or IP Address of the remote system whose cert(s) will be monitored. The value provided will be validated against the Common Name and Subject Alternate Names fields *unless* the `dns-name` flag is also specified, in which case *this* value is only used for making the initial connection. |
| `dn`, `dns-name` | No | | | *fully-qualified domain name or IP Address* | The fully-qualified domain name of the remote system to be used for hostname verification. This option can be used for cases where the initial connection is made using a name or IP Address not associated with the certificate. |
Expand All @@ -231,6 +234,7 @@ been tested.
| `text` | No | `false` | No | `true`, `false` | Toggles emission of x509 TLS certificates in an OpenSSL-inspired text format. This output is disabled by default. |
| `ll`, `log-level` | No | `info` | No | `disabled`, `panic`, `fatal`, `error`, `warn`, `info`, `debug`, `trace` | Log message priority filter. Log messages with a lower level are ignored. |
| `p`, `port` | No | `443` | No | *positive whole number between 1-65535, inclusive* | TCP port of the remote certificate-enabled service. This is usually 443 (HTTPS) or 636 (LDAPS). |
| `t`, `timeout` | No | `10` | No | *positive whole number* | Timeout value in seconds allowed before the connection attempt to a remote certificate-enabled service is abandoned and an error returned. |
| `se`, `sans-entries` | No | | | *comma-separated list of values* | One or many Subject Alternate Names (SANs) expected for the certificate used by the remote service. If provided, this list of comma-separated (optional) values is required for the certificate to pass validation. If the case-insensitive SKIPSANSCHECKS keyword is provided this validation will be skipped, effectively turning the use of this flag into a NOOP. |
| `s`, `server` | **Yes** | | | *fully-qualified domain name or IP Address* | The fully-qualified domain name or IP Address of the remote system whose cert(s) will be monitored. The value provided will be validated against the Common Name and Subject Alternate Names fields *unless* the `dns-name` flag is also specified, in which case *this* value is only used for making the initial connection. |
| `dn`, `dns-name` | No | | | *fully-qualified domain name or IP Address* | The fully-qualified domain name of the remote system to be used for hostname verification. This option can be used for cases where the initial connection is made using a name or IP Address not associated with the certificate. |
Expand Down Expand Up @@ -471,6 +475,7 @@ SOFTWARE.
- <https://github.com/grantae/certinfo>
- <https://github.com/rs/zerolog>
- <https://github.com/atc0005/go-nagios>
- <https://nagios-plugins.org/doc/guidelines.html>

<!-- Footnotes here -->

Expand Down
14 changes: 14 additions & 0 deletions cmd/check_cert/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const (
logLevelFlagHelp string = "Sets log level to one of disabled, panic, fatal, error, warn, info, debug or trace."
serverFlagHelp string = "The fully-qualified domain name or IP Address of the remote system whose cert(s) will be monitored. The value provided will be validated against the Common Name and Subject Alternate Names fields."
portFlagHelp string = "TCP port of the remote certificate-enabled service. This is usually 443 (HTTPS) or 636 (LDAPS)."
timeoutFlagHelp string = "Timeout value in seconds allowed before the connection attempt to a remote certificate-enabled service is abandoned and an error returned."
certExpireAgeWarningFlagHelp string = "The number of days remaining before certificate expiration when Nagios will return a WARNING state"
certExpireAgeCriticalFlagHelp string = "The number of days remaining before certificate expiration when Nagios will return a CRITICAL state"
brandingFlagHelp string = "Toggles emission of branding details with plugin status details. This output is disabled by default."
Expand All @@ -50,6 +51,7 @@ const (
defaultServer string = ""
defaultDNSName string = ""
defaultPort int = 443
defaultTimeout int = 10
defaultBranding bool = false
defaultDisplayVersionAndExit bool = false

Expand Down Expand Up @@ -127,6 +129,11 @@ type Config struct {
// field as a CRITICAL state.
AgeCritical int

// Timeout is the number of seconds allowed before the connection attempt
// to a remote certificate-enabled service is abandoned and an error
// returned.
Timeout int

// EmitBranding controls whether "generated by" text is included at the
// bottom of application output. This output is included in the Nagios
// dashboard and notifications. This output may not mix well with branding
Expand Down Expand Up @@ -182,6 +189,9 @@ func (c *Config) handleFlagsConfig() {
flag.IntVar(&c.Port, "p", defaultPort, portFlagHelp)
flag.IntVar(&c.Port, "port", defaultPort, portFlagHelp)

flag.IntVar(&c.Timeout, "t", defaultTimeout, timeoutFlagHelp)
flag.IntVar(&c.Timeout, "timeout", defaultTimeout, timeoutFlagHelp)

flag.StringVar(&c.LoggingLevel, "ll", defaultLogLevel, logLevelFlagHelp)
flag.StringVar(&c.LoggingLevel, "log-level", defaultLogLevel, logLevelFlagHelp)

Expand All @@ -206,6 +216,10 @@ func (c Config) Validate() error {
return fmt.Errorf("invalid TCP port number %d", c.Port)
}

if c.Timeout < 0 {
return fmt.Errorf("invalid timeout value %d provided", c.Timeout)
}

if c.AgeWarning < 0 {
return fmt.Errorf(
"invalid value for warning age: %d",
Expand Down
9 changes: 8 additions & 1 deletion cmd/check_cert/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ package main
import (
"crypto/tls"
"fmt"
"net"
"os"
"strings"
"time"
Expand Down Expand Up @@ -98,7 +99,13 @@ func main() {
// nolint:gosec
InsecureSkipVerify: true,
}
conn, err := tls.Dial("tcp", server, &cfg)

// Create custom dialer with user-specified timeout value
dialer := &net.Dialer{
Timeout: time.Duration(config.Timeout) * time.Second,
}

conn, err := tls.DialWithDialer(dialer, "tcp", server, &cfg)
if err != nil {
nagiosExitState.LastError = err
nagiosExitState.ServiceOutput = "Error connecting to " + server
Expand Down
14 changes: 14 additions & 0 deletions cmd/lscert/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const (
logLevelFlagHelp string = "Sets log level to one of disabled, panic, fatal, error, warn, info, debug or trace."
serverFlagHelp string = "The fully-qualified domain name or IP Address of the remote system whose cert(s) will be monitored. The value provided will be validated against the Common Name and Subject Alternate Names fields."
portFlagHelp string = "TCP port of the remote certificate-enabled service. This is usually 443 (HTTPS) or 636 (LDAPS)."
timeoutFlagHelp string = "Timeout value in seconds allowed before the connection attempt to a remote certificate-enabled service is abandoned and an error returned."
emitCertTextFlagHelp string = "Toggles emission of x509 TLS certificates in an OpenSSL-inspired text format. This output is disabled by default."
filenameFlagHelp string = "Fully-qualified path to a file containing one or more certificates."
certExpireAgeWarningFlagHelp string = "The number of days remaining before certificate expiration when this application will will flag the NotAfter certificate field as a WARNING state."
Expand All @@ -51,6 +52,7 @@ const (
defaultServer string = ""
defaultDNSName string = ""
defaultPort int = 443
defaultTimeout int = 10
defaultEmitCertText bool = false
defaultFilename string = ""
defaultDisplayVersionAndExit bool = false
Expand Down Expand Up @@ -142,6 +144,11 @@ type Config struct {
// field as a CRITICAL state.
AgeCritical int

// Timeout is the number of seconds allowed before the connection attempt
// to a remote certificate-enabled service is abandoned and an error
// returned.
Timeout int

// EmitBranding controls whether "generated by" text is included at the
// bottom of application output. This output is included in the Nagios
// dashboard and notifications. This output may not mix well with branding
Expand Down Expand Up @@ -192,6 +199,9 @@ func (c *Config) handleFlagsConfig() {
flag.IntVar(&c.Port, "p", defaultPort, portFlagHelp)
flag.IntVar(&c.Port, "port", defaultPort, portFlagHelp)

flag.IntVar(&c.Timeout, "t", defaultTimeout, timeoutFlagHelp)
flag.IntVar(&c.Timeout, "timeout", defaultTimeout, timeoutFlagHelp)

flag.StringVar(&c.LoggingLevel, "ll", defaultLogLevel, logLevelFlagHelp)
flag.StringVar(&c.LoggingLevel, "log-level", defaultLogLevel, logLevelFlagHelp)

Expand Down Expand Up @@ -234,6 +244,10 @@ func (c Config) Validate() error {
return fmt.Errorf("invalid TCP port number %d", c.Port)
}

if c.Timeout < 0 {
return fmt.Errorf("invalid timeout value %d provided", c.Timeout)
}

if c.AgeWarning < 0 {
return fmt.Errorf(
"invalid cert expiration WARNING threshold number: %d",
Expand Down
9 changes: 8 additions & 1 deletion cmd/lscert/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"crypto/x509"
"flag"
"fmt"
"net"
"os"
"strings"
"time"
Expand Down Expand Up @@ -104,7 +105,13 @@ func main() {
// nolint:gosec
InsecureSkipVerify: true,
}
conn, err := tls.Dial("tcp", server, &cfg)

// Create custom dialer with user-specified timeout value
dialer := &net.Dialer{
Timeout: time.Duration(config.Timeout) * time.Second,
}

conn, err := tls.DialWithDialer(dialer, "tcp", server, &cfg)
if err != nil {
log.Error().Err(err).Msgf("error connecting to server")
os.Exit(1)
Expand Down

0 comments on commit 9cb3d80

Please sign in to comment.