Coder Social home page Coder Social logo

atc0005 / check-whois Goto Github PK

View Code? Open in Web Editor NEW
7.0 2.0 0.0 4.31 MB

Go-based tooling to monitor WHOIS records.

License: MIT License

Makefile 43.26% Go 45.75% Dockerfile 2.59% Shell 8.39%
nagios nagios-plugin plugin go golang whois domain expiration expiry monitoring

check-whois's Introduction

check-whois

Go-based tooling to monitor WHOIS records.

Latest Release Go Reference go.mod Go version Lint and Build Project Analysis

Table of Contents

Project home

See our GitHub repo for the latest code, to file an issue or submit improvements for review and potential inclusion into the project.

Overview

This repo is intended to provide various tools used to monitor WHOIS.

Tool Name Overall Status Description
check_whois Alpha Nagios plugin used to monitor expiration of WHOIS records

check_whois

Nagios plugin used to monitor expiration of WHOIS records.

The output for this application is designed to provide the one-line summary needed by Nagios for quick identification of a problem while providing longer, more detailed information for use in email and Teams notifications (atc0005/send2teams).

Performance Data

Initial support has been added for emitting Performance Data / Metrics, but refinement suggestions are welcome.

Consult the tables below for the metrics implemented thus far.

Please add to an existing Discussion thread (if applicable) or open a new one with any feedback that you may have. Thanks in advance!

Emitted Performance Data / Metric Unit of Measurement Meaning
time seconds Runtime for plugin
expiration days Until domain expires.
since_update days Since domain was last updated.
since_creation days Since domain was first created.

Features

  • Nagios plugin for monitoring expiration of WHOIS records

  • Optional use of custom WHOIS server

  • Optional disabling of referral lookups

  • Optional branding "signature"

    • used to indicate what Nagios plugin (and what version) is responsible for the service check result
  • Optional, leveled logging using rs/zerolog package

    • logfmt format output (to stderr)
    • choice of disabled, panic, fatal, error, warn, info (the default), debug or trace.

Changelog

See the CHANGELOG.md file for the changes associated with each release of this application. Changes that have been merged to master, but not yet an official release may also be noted in the file under the Unreleased section. A helpful link to the Git commit history since the last official release is also provided for further review.

Requirements

The following is a loose guideline. Other combinations of Go and operating systems for building and running tools from this repo may work, but have not been tested.

Building source code

  • Go
    • see this project's go.mod file for preferred version
    • this project tests against officially supported Go releases
      • the most recent stable release (aka, "stable")
      • the prior, but still supported release (aka, "oldstable")
  • GCC
    • if building with custom options (as the provided Makefile does)
  • make
    • if using the provided Makefile

Running

  • Windows 10+
  • Ubuntu Linux 18.04+

Installation

From source

  1. Download Go
  2. Install Go
  3. Clone the repo
    1. cd /tmp
    2. git clone https://github.com/atc0005/check-whois
    3. cd check-whois
  4. Install dependencies (optional)
    • for Ubuntu Linux
      • sudo apt-get install make gcc
    • for CentOS Linux
      1. sudo yum install make gcc
  5. Build
    • for current operating system
      • go build -mod=vendor ./cmd/check_whois/
        • forces build to use bundled dependencies in top-level vendor folder
    • for all supported platforms (where make is installed)
      • make all
    • for Windows
      • make windows
    • for Linux
      • make linux
  6. Locate generated binaries
    • if using Makefile
      • look in /tmp/check-whois/release_assets/check_whois/
    • if using go build
      • look in /tmp/check-whois/
  7. Copy the applicable binaries to whatever systems needs to run them
  8. Deploy
    • Place check_whois in the same location where your distro's package manager has place other Nagios plugins
      • as /usr/lib/nagios/plugins/check_whois on Debian-based systems
      • as /usr/lib64/nagios/plugins/check_whois on RedHat-based systems

NOTE: Depending on which Makefile recipe you use the generated binary may be compressed and have an xz extension. If so, you should decompress the binary first before deploying it (e.g., xz -d check_whois-linux-amd64.xz).

Using release binaries

  1. Download the latest release binaries
  2. Decompress binaries
    • e.g., xz -d check_whois-linux-amd64.xz
  3. Deploy
    • Place check_whois in the same location where your distro's package manager places other Nagios plugins
      • as /usr/lib/nagios/plugins/check_whois on Debian-based systems
      • as /usr/lib64/nagios/plugins/check_whois on RedHat-based systems

NOTE:

DEB and RPM packages are provided as an alternative to manually deploying binaries.

Configuration

Command-line arguments

  • Use the -h or --help flag to display current usage information.
  • Flags marked as required must be set via CLI flag.
  • Flags not marked as required are for settings where a useful default is already defined, but may be overridden if desired.

check_whois

Flag Required Default Repeat Possible Description
branding No false No branding Toggles emission of branding details with plugin status details. This output is disabled by default.
h, help No false No h, help Show Help text along with the list of supported flags.
v, version No false No v, version Whether to display application version and then immediately exit application.
c, age-critical No 15 No positive whole number of days The number of days remaining before domain expiration when a CRITICAL state is triggered.
w, age-warning No 30 No positive whole number of days The number of days remaining before domain expiration when a WARNING state is triggered.
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.
d, domain Yes No domain name The name of the domain whose WHOIS records will be evaluated.
s, server No No valid WHOIS server fqdn The name of the optional domain registrar WHOIS server to use for queries.
disable-ref-lookups No false No true, false Disables WHOIS server referral lookups. Lookups are enabled by default.

Examples

OK result

This example uses default age thresholds to check the expiration date for the specified domain. Since the expiration occurs after those default thresholds, the result is considered OK.

$ ./check_whois --domain "google.com"
OK: "google.com" domain registration has 2602d 18h remaining


**ERRORS**

* None

**THRESHOLDS**

* CRITICAL: Expires before 2021-08-14 09:31:39 +0000 UTC (15 days)
* WARNING: Expires before 2021-08-29 09:31:39 +0000 UTC (30 days)

**DETAILED INFO**

WHOIS metadata for "google.com" domain:

* Status: [clientdeleteprohibited, clienttransferprohibited, clientupdateprohibited, serverdeleteprohibited, servertransferprohibited, serverupdateprohibited]
* Creation Date: 2028-09-14 04:00:00 +0000 UTC
* Updated Date: 2019-09-09 15:39:04 +0000 UTC
* Expiration Date: 2028-09-14 04:00:00 +0000 UTC
* Registrar Name: MarkMonitor Inc.
* Registrant Name:
* Registrant Email: select request email form at https://domains.markmonitor.com/whois/google.com

WARNING result

This example uses explicit age thresholds to simulate a domain that is expiring soon, but hasn't yet crossed the final CRITICAL age threshold. The result is considered to be a WARNING state.

$ ./check_whois --domain "microsoft.com" --age-warning 365 --age-critical 120
{"level":"warn","version":"check-whois x.y.z (https://github.com/atc0005/check-whois)","logging_level":"info","domain":"microsoft.com","time":"2021-07-30T04:40:08-05:00","caller":"/mnt/t/github/check-whois/cmd/check_whois/main.go:142","message":"Domain is expiring"}
WARNING: "microsoft.com" domain registration has 276d 18h remaining


**ERRORS**

* domain is expiring

**THRESHOLDS**

* CRITICAL: Expires before 2021-11-27 09:40:08 +0000 UTC (120 days)
* WARNING: Expires before 2022-07-30 09:40:08 +0000 UTC (365 days)

**DETAILED INFO**

WHOIS metadata for "microsoft.com" domain:

* Status: [clientdeleteprohibited, clienttransferprohibited, clientupdateprohibited, serverdeleteprohibited, servertransferprohibited, serverupdateprohibited]
* Creation Date: 2022-05-03 04:00:00 +0000 UTC
* Updated Date: 2021-03-12 23:25:32 +0000 UTC
* Expiration Date: 2022-05-03 04:00:00 +0000 UTC
* Registrar Name: MarkMonitor Inc.
* Registrant Name: Domain Administrator
* Registrant Email: [email protected]

CRITICAL result

This example uses explicit age thresholds to simulate a domain that is expiring soon and has crossed the final CRITICAL age threshold. The result is considered to be a CRITICAL state.

The domain is expected to expire soon without direct intervention from the current domain owner.

$ ./check_whois --domain "godaddy.com" --age-warning 365 --age-critical 120
{"level":"warn","version":"check-whois x.y.z (https://github.com/atc0005/check-whois)","logging_level":"info","domain":"godaddy.com","time":"2021-07-30T04:41:06-05:00","caller":"/mnt/t/github/check-whois/cmd/check_whois/main.go:142","message":"Domain is expiring"}
CRITICAL: "godaddy.com" domain registration has 94d 2h remaining


**ERRORS**

* domain is expiring

**THRESHOLDS**

* CRITICAL: Expires before 2021-11-27 09:41:06 +0000 UTC (120 days)
* WARNING: Expires before 2022-07-30 09:41:06 +0000 UTC (365 days)

**DETAILED INFO**

WHOIS metadata for "godaddy.com" domain:

* Status: [clientdeleteprohibited, clientrenewprohibited, clienttransferprohibited, clientupdateprohibited, serverdeleteprohibited, servertransferprohibited, serverupdateprohibited]
* Creation Date: 2021-11-01 11:59:59 +0000 UTC
* Updated Date: 2020-04-07 14:26:27 +0000 UTC
* Expiration Date: 2021-11-01 11:59:59 +0000 UTC
* Registrar Name: GoDaddy.com, LLC
* Registrant Name:
* Registrant Email: select contact domain holder link at https://www.godaddy.com/whois/results.aspx?domain=godaddy.com

License

MIT License

Copyright 2021 Adam Chalkley

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

References

Related projects

Dependencies

General

check-whois's People

Contributors

atc0005 avatar dependabot[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

check-whois's Issues

Add version metadata to Windows executables

Overview

Use github.com/tc-hib/go-winres and winres.json file to apply version details to Windows executables provided by this project.

Background

While this project currently does not provide Windows binaries as part of the normal release workflow, it may do so again in the future. Others may also wish to generate Windows binaries locally and could benefit from having version metadata embedded in the binaries for easier tracking and inventory management (e.g., SCCM deployments).

References

Add domain performance data metrics

Ideas:

  • expires
    • uom: day
    • rounded down
  • updated
    • uom: day
    • rounded down
  • created
    • uom: year
    • float, one decimal place

The time metric is already provided (by default per the package I'm using).

Add flag to explicitly disable referral lookups

Ran into a situation today where a registrar updated one of their records to provide a web UI in place of the expected WHOIS server FQDN.

At some point the https://github.com/likexian/whois-parser library may add an explicit workaround for the invalid Registrar WHOIS Server value in this registrar's records.

Until then, and because the "base" WHOIS record has all of the needed information, we could dig up exactly what that domain's WHOIS server (e.g., perform a whois query on the registrar's domain itself) and query that WHOIS server. This would work with the latest release already available from this project.

That said, the likexian/whois project has recently added support for disabling referral lookups:

We could modify the deferral lookup behavior of the plugin to disable referral lookup logic by default and provide a new flag to allow sysadmins to re-enable as desired.

Because deferral lookups have been problematic in the past (look at the number of explicit workarounds provided by the parsing library for malformed WHOIS records), this should be a useful new default behavior. As noted if a sysadmin wants to use a custom WHOIS server they can continue to do so and if they wish to use referral lookups they will be able to opt into that behavior.

Gave it some more thought. Better to just add the new flag to explicitly disable referral lookups and retain existing behavior.

Add optional support for specifying WHOIS server associated with a domain

If you don't specify a WHOIS server associated with a domain, the associated library will attempt to parse the server name from initial WHOIS data retrieved. In many cases, this seems to work well. In one case I came across, it fails completely.

Example WHOIS response (using the standard whois CLI tool):

Registrar WHOIS Server: whois.godaddy

When the whois.Whois() function attempted to parse this, it failed with a message like this one:

whois: connect to whois server failed: dial tcp: lookup whois.godaddy on 1.1.1.1:53: no such host

To resolve this, an additional (optional) flag would be needed to specify whois.godaddy.com for that domain.

refs https://pkg.go.dev/github.com/likexian/[email protected]

Research/test new WHOIS record format

https://centralnicregistry.com/about/news/archive/2016/changes-to-whois

The format of WHOIS records will be changed to comply with the Registry Registration Data Directory Services Consistent Labeling and Display Policy on March 1, 2017. This will affect all gTLDs, ccTLDs and SLDs on our main registry platform, with the exception of .com.de and .com.se, which use WHOIS record formats similar to those of their parent TLD.

This stands out:

Those wishing to these their whois client implementations are directed towards the OT&E WHOIS service at ote-whois.centralnic.com, which already uses the new format

Replace bundled ServiceState type

Replace local copy of type with recently added upstream version.

// ServiceState represents the status label and exit code for a service check.
type ServiceState struct {
// Label maps directly to one of the supported Nagios state labels.
Label string
// ExitCode is the exit or exit status code associated with a Nagios
// service check.
ExitCode int
}

// ServiceState returns the appropriate Service Check Status label and exit
// code for the evaluated certificate chain.
func (m Metadata) ServiceState() ServiceState {
var stateLabel string
var stateExitCode int
switch {
case m.IsCriticalState():
stateLabel = nagios.StateCRITICALLabel
stateExitCode = nagios.StateCRITICALExitCode
case m.IsWarningState():
stateLabel = nagios.StateWARNINGLabel
stateExitCode = nagios.StateWARNINGExitCode
case m.IsOKState():
stateLabel = nagios.StateOKLabel
stateExitCode = nagios.StateOKExitCode
default:
stateLabel = nagios.StateUNKNOWNLabel
stateExitCode = nagios.StateUNKNOWNExitCode
}
return ServiceState{
Label: stateLabel,
ExitCode: stateExitCode,
}
}

Makefile: Refresh recipes to add "standard" set, new package-related options

Overview

Update/sync this project's Makefile against recent changes to the atc0005/check-cert project Makefile to provide the same functionality.

TODO

  • arch and OS-specific builds
  • release-build
    • used to generate just the binaries provided by a specific project (e.g., skip Windows (all), skip Linux x86)
  • links (and arch-specific variations)
    • used to generate download links for easier bulk retrieval of release assets
  • quick
    • go build without any custom settings applied
    • it is a quick build to test/prototype binaries without waiting for release-level optimizations to be applied
  • depsinstall
    • install build related dependencies
  • package generation
    • packages-stable
    • packages-dev

Branding flag is a NOOP

The flag is accepted and sets a value, but otherwise does not appear to do anything with it.

Explicitly list the WHOIS server/source used to perform query

The plugin currently performs referral lookups automatically, but also supports the use of a custom server and disabling referral lookups.

It would be useful to note in the output what was done.

Something like:

  • custom WHOIS server specified: true/false
  • referral lookups enabled: true/false
  • WHOIS server (FQDN/IP) queried: whois.example.com

Update go.mod file, canary Dockerfile to reflect Go 1.17

Summary

The Go 1.16 series is going EOL in ~ 2 months, so will need to update the Go version used for this project to reflect this.

TODO

  • Update README "requirements" to generically indicate "recent Go release" since this project doesn't (at present) have a fixed version requirement.
  • Update go.mod file to reflect Go 1.17
  • Update Dependabot (dependabot.yml) configuration to ignore Go versions greater than or less than 1.17.x
  • Update "canary" Dockerfile to reflect Go 1.17.6, the latest in the 1.17.x series
  • Run go mod tidy && go mod vendor

Failure to parse date fields in WHOIS record: `parsing time "2022-06-03" as "2006-01-02T15:04:05Z07:00": cannot parse "" as "T"`

Overview

While troubleshooting #115 I opted to explicitly specify the WHOIS server for a particular domain and received this error:

failed to parse domain updated date: parsing time "2022-06-03" as "2006-01-02T15:04:05Z07:00": cannot parse "" as "T"

Relevant code block:

updatedDate, err := time.Parse(time.RFC3339, whoisInfo.Domain.UpdatedDate)
if err != nil {
return nil, fmt.Errorf(
"failed to parse domain updated date: %w",
err,
)
}

References

Add flag to allow specifying domain owner / contact

For example, suppose you have a central monitoring instance that monitors domains for multiple units. When a domain approaches expiration, it would be useful to explicitly note in the generated output who should be contacted about the expiring domain.

This could be implied by the name of the service check, but that supposes that unique service checks are used for each domain.

You might have one service check that targets a hostgroup. If using a hostgroup-based service check you could define Custom Object Variables on the host entry and reference them from the service check.

If using unique service checks, you have the option of inferring the service owner or technical contact for a domain registration based on the service check name, but could also explicitly note that detail using a flag so that the information appears in the generated output (LongServiceOutput).

`runtime error: invalid memory address or nil pointer dereference` error for domains missing WhoIS record fields

While spot-checking a domain's WhoIS record the plugin paniced when attempting to access field data not provided by the record.

Example:

runtime error: invalid memory address or nil pointer dereference

goroutine 1 [running]:
runtime/debug.Stack()
        /usr/local/go/src/runtime/debug/stack.go:24 +0x65
github.com/atc0005/go-nagios.(*Plugin).ReturnCheckResults(0xc000175e88)
        /mnt/t/github/check-whois/vendor/github.com/atc0005/go-nagios/nagios.go:283 +0x253
panic({0x543de0, 0x675d70})
        /usr/local/go/src/runtime/panic.go:884 +0x213
github.com/atc0005/check-whois/internal/domain.Metadata.Report({{0xc00021a000, 0x0, 0xc00021a1c0, 0xc00021a2a0, 0xc00021a380, 0x0}, {0xc0000185c0, 0xa}, {0x0, 0xee01ca900, ...}, ...})
        /mnt/t/github/check-whois/internal/domain/domain.go:230 +0x300
main.main()
        /mnt/t/github/check-whois/cmd/check_whois/main.go:161 +0x1685

Add flag to disable listing thresholds

Example output currently emitted:

**ERRORS** 

* domain is expiring 

**THRESHOLDS** 

* CRITICAL: Expires before 2023-10-28 20:10:36 +0000 UTC (30 days) 
* WARNING: Expires before 2023-11-27 20:10:36 +0000 UTC (60 days) 

**DETAILED INFO** 

WHOIS metadata for example.org domain: 

...

Output if using a new flag to disable listing thresholds:

**ERRORS** 

* domain is expiring 

**DETAILED INFO** 

WHOIS metadata for example.org domain: 

...

Audit plugin exit states to determine if another state (e.g., UNKNOWN) would be more applicable

Overview

While implementing performance data handling as part of atc0005/check-cert#445 I found myself choosing to do one of:

  • emitting an error and continuing
  • exiting with an UNKNOWN status

Either seemed more appropriate than exiting with either of CRITICAL or WARNING state.

To keep mostly current logic intact I opted to just emit the error as a log message and continue:

	pd, perfDataErr := getPerfData(certChain, cfg.AgeCritical, cfg.AgeWarning)
	if perfDataErr != nil {
		log.Error().
			Err(perfDataErr).
			Msg("failed to generate performance data")

		// Surface the error in plugin output.
		plugin.AddError(perfDataErr)

		// TODO: Abort plugin execution with UNKNOWN status?
	}

	if err := plugin.AddPerfData(false, pd...); err != nil {
		log.Error().
			Err(err).
			Msg("failed to add performance data")

		// Surface the error in plugin output.
		plugin.AddError(err)

		// TODO: Abort plugin execution with UNKNOWN status?
	}

I'm filing this GH issue as a reminder to revisit that decision in the larger context of current plugin logic as it pertains to the Nagios Plugin Guidelines (see refs):

Numeric Value Service Status Status Description
0 OK The plugin was able to check the service and it appeared to be functioning properly
1 Warning The plugin was able to check the service, but it appeared to be above some "warning" threshold or did not appear to be working properly
2 Critical The plugin detected that either the service was not running or it was above some "critical" threshold
3 Unknown Invalid command line arguments were supplied to the plugin or low-level failures internal to the plugin (such as unable to fork, or open a tcp socket) that prevent it from performing the specified operation. Higher-level errors (such as name resolution errors, socket timeouts, etc) are outside of the control of plugins and should generally NOT be reported as UNKNOWN states.

References

Fix various typos, incomplete copy/paste/modify operations

I used large portions of the atc0005/check-cert project when setting up this one, replacing much of the cert-specific doc comments, variables and other details with ones specific to monitoring domain expirations.

From a quick review, I see that I didn't get them all. I also see several typos sprinkled about, presumably due to the hectic pace I had when spinning up this project.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.