Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

check-dns: add expected-string option #715

Merged
merged 10 commits into from
Feb 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 41 additions & 21 deletions check-dns/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,45 @@

Monitor DNS response.

## Synopsis
## Usage

### Options

```
check-dns -H example.com -s 8.8.8.8
-H, --host= The name or address you want to query
-s, --server= DNS server you want to use for the lookup
-p, --port= Port number you want to use (default: 53)
-q, --querytype= DNS record query type (default: A)
--norec Set not recursive mode
-e, --expected-string= IP-ADDRESS string you expect the DNS server to return. If multiple IP-ADDRESS are returned at once, you have to specify whole string
```

- query class is always IN.
- Punycode is not supported.

### Check DNS server status

If DNS server returns `NOERROR` in status of HEADER, then the checker result becomes `OK`, if not `NOERROR`, then `CRITICAL`

```
check-dns -H a.root-servers.net -s 8.8.8.8
```

### Check string DNS server returns

- The currently supported query types are A, AAAA.

If DNS server returns 1.1.1.1 and 2.2.2.2
```
-e 1.1.1.1 -e 2.2.2.2 -> OK
-e 1.1.1.1 -e 2.2.2.2 -e 3.3.3.3 -> WARNING
-e 1.1.1.1 -> WARNING
-e 1.1.1.1 -e 3.3.3.3 -> WARNING
-e 3.3.3.3 -> CRITICAL
-e 3.3.3.3 -e 4.4.4.4 -e 5.5.5.5 -> CRITICAL
```
```
check-dns -H a.root-servers.net -s 8.8.8.8 -e 198.41.0.4
```

## Installation
Expand All @@ -25,7 +61,7 @@ Or you can use this program by installing the official Mackerel package. See [Us
Next, you can execute this program :-)

```
check-dns -H example.com -s 8.8.8.8
check-dns -H a.root-servers.net -s 8.8.8.8
```


Expand All @@ -34,22 +70,6 @@ check-dns -H example.com -s 8.8.8.8
If there are no problems in the execution result, add a setting in mackerel-agent.conf .

```
[plugin.checks.fileage-sample]
command = ["check-dns", "-H", "example.com", "-s", "8.8.8.8"]
```

## Usage
### Options

```
-H, --host= The name or address you want to query
-s, --server= DNS server you want to use for the lookup
-p, --port= Port number you want to use (default: 53)
-q, --querytype= DNS record query type where TYPE =(A, AAAA, SRV, TXT, MX, ANY) (default: A)
-c, --queryclass= DNS record class type where TYPE =(IN, CS, CH, HS, NONE, ANY) (default: IN)
--norec Set not recursive mode
[plugin.checks.dns-sample]
command = ["check-dns", "-H", "a.root-servers.net", "-s", "8.8.8.8"]
```

## For more information

Please execute `check-dns -h` and you can get command line options.
69 changes: 57 additions & 12 deletions check-dns/lib/check_dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ import (
)

type dnsOpts struct {
Host string `short:"H" long:"host" required:"true" description:"The name or address you want to query"`
Server string `short:"s" long:"server" description:"DNS server you want to use for the lookup"`
Port int `short:"p" long:"port" default:"53" description:"Port number you want to use"`
QueryType string `short:"q" long:"querytype" default:"A" description:"DNS record query type where TYPE =(A, AAAA, SRV, TXT, MX, ANY)"`
QueryClass string `short:"c" long:"queryclass" default:"IN" description:"DNS record class type where TYPE =(IN, CS, CH, HS, NONE, ANY)"`
Norec bool `long:"norec" description:"Set not recursive mode"`
Host string `short:"H" long:"host" required:"true" description:"The name or address you want to query"`
Server string `short:"s" long:"server" description:"DNS server you want to use for the lookup"`
Port int `short:"p" long:"port" default:"53" description:"Port number you want to use"`
QueryType string `short:"q" long:"querytype" default:"A" description:"DNS record query type"`
Norec bool `long:"norec" description:"Set not recursive mode"`
ExpectedString []string `short:"e" long:"expected-string" description:"IP-ADDRESS string you expect the DNS server to return. If multiple IP-ADDRESS are returned at once, you have to specify whole string"`
}

// Do the plugin
Expand Down Expand Up @@ -53,11 +53,7 @@ func (opts *dnsOpts) run() *checkers.Checker {

queryType, ok := dns.StringToType[strings.ToUpper(opts.QueryType)]
if !ok {
return checkers.Critical(fmt.Sprintf("%s is invalid queryType", opts.QueryType))
}
queryClass, ok := dns.StringToClass[strings.ToUpper(opts.QueryClass)]
if !ok {
return checkers.Critical(fmt.Sprintf("%s is invalid queryClass", opts.QueryClass))
return checkers.Critical(fmt.Sprintf("%s is invalid query type", opts.QueryType))
}

c := new(dns.Client)
Expand All @@ -66,7 +62,7 @@ func (opts *dnsOpts) run() *checkers.Checker {
RecursionDesired: !opts.Norec,
Opcode: dns.OpcodeQuery,
},
Question: []dns.Question{{Name: dns.Fqdn(opts.Host), Qtype: queryType, Qclass: uint16(queryClass)}},
Question: []dns.Question{{Name: dns.Fqdn(opts.Host), Qtype: queryType, Qclass: dns.StringToClass["IN"]}},
}
m.Id = dns.Id()

Expand All @@ -76,9 +72,58 @@ func (opts *dnsOpts) run() *checkers.Checker {
}

checkSt := checkers.OK
/**
if DNS server return 1.1.1.1, 2.2.2.2
1: -e 1.1.1.1 -e 2.2.2.2 -> OK
2: -e 1.1.1.1 -e 2.2.2.2 -e 3.3.3.3 -> WARNING
3: -e 1.1.1.1 -> WARNING
4: -e 1.1.1.1 -e 3.3.3.3 -> WARNING
5: -e 3.3.3.3 -> CRITICAL
6: -e 3.3.3.3 -e 4.4.4.4 -e 5.5.5.5 -> CRITICAL
**/
if len(opts.ExpectedString) != 0 {
supportedQueryType := map[string]int{"A": 1, "AAAA": 1}
_, ok := supportedQueryType[strings.ToUpper(opts.QueryType)]
if !ok {
return checkers.Critical(fmt.Sprintf("%s is not supported query type. Only A, AAAA is supported for expectation.", opts.QueryType))
}
match := 0
for _, expectedString := range opts.ExpectedString {
for _, answer := range r.Answer {
var anserWithoutHeader string
expectMatch := expectedString
switch t := answer.(type) {
case *dns.A:
anserWithoutHeader = t.A.String()
case *dns.AAAA:
anserWithoutHeader = t.AAAA.String()
default:
return checkers.Critical(fmt.Sprintf("%s is not supported query type. Only A, AAAA is supported for expectation.", opts.QueryType))
}
if anserWithoutHeader == expectMatch {
match += 1
}
}
}
if match == len(r.Answer) {
if len(opts.ExpectedString) == len(r.Answer) { // case 1
checkSt = checkers.OK
} else { // case 2
checkSt = checkers.WARNING
}
} else {
if match > 0 { // case 3,4
checkSt = checkers.WARNING
} else { // case 5,6
checkSt = checkers.CRITICAL
}
}
}

if r.MsgHdr.Rcode != dns.RcodeSuccess {
checkSt = checkers.CRITICAL
}

msg := fmt.Sprintf("HEADER-> %s\n", r.MsgHdr.String())
for _, answer := range r.Answer {
msg += fmt.Sprintf("ANSWER-> %s\n", answer)
Expand Down
51 changes: 38 additions & 13 deletions check-dns/lib/check_dns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,54 +29,79 @@ func TestCheckDns(t *testing.T) {
want_msg []string
}{
{
[]string{"-H", "example.com"},
[]string{"-H", "a.root-servers.net"},
checkers.OK,
[]string{"status: NOERROR"},
},
{
[]string{"-H", "example.com", "--norec"},
[]string{"-H", "a.root-servers.net", "--norec"},
checkers.OK,
[]string{"status: NOERROR"},
},
{
[]string{"-H", "exampleeeee.com"},
[]string{"-H", "a.root-servers.invalid"},
checkers.CRITICAL,
[]string{"status: NXDOMAIN"},
},
{
[]string{"-H", "example.com", "-s", "8.8.8.8"},
[]string{"-H", "a.root-servers.net", "-s", "8.8.8.8"},
checkers.OK,
[]string{"status: NOERROR"},
},
{
[]string{"-H", "exampleeeee.com", "-s", "8.8.8.8"},
[]string{"-H", "a.root-servers.invalid", "-s", "8.8.8.8"},
checkers.CRITICAL,
[]string{"status: NXDOMAIN"},
},
{
[]string{"-H", "example.com", "-s", "8.8.8"},
[]string{"-H", "a.root-servers.net", "-s", "8.8.8"},
checkers.CRITICAL,
[]string{""},
},
{
[]string{"-H", "example.com", "-s", "8.8.8.8", "-q", "AAAA"},
[]string{"-H", "a.root-servers.net", "-s", "8.8.8.8", "-q", "AAAA"},
checkers.OK,
[]string{"status: NOERROR", "AAAA"},
},
{
[]string{"-H", "example.com", "-s", "8.8.8.8", "-q", "AAA"},
[]string{"-H", "a.root-servers.net", "-s", "8.8.8.8", "-q", "AAA"},
checkers.CRITICAL,
[]string{"AAA is invalid queryType"},
[]string{"AAA is invalid query type"},
},
{
[]string{"-H", "example.com", "-s", "8.8.8.8", "-c", "IN"},
[]string{"-H", "a.root-servers.net", "-s", "8.8.8.8", "-e", "198.41.0.4"},
checkers.OK,
[]string{"status: NOERROR"},
[]string{"status: NOERROR", "198.41.0.4"},
},
{
[]string{"-H", "a.root-servers.net", "-s", "8.8.8.8", "-q", "AAAA", "--expected-string", "2001:503:ba3e::2:30"},
checkers.OK,
[]string{"status: NOERROR", "2001:503:ba3e::2:30"},
},
{
[]string{"-H", "a.root-servers.net", "-s", "8.8.8.8", "-q", "TXT", "-e", ""},
checkers.CRITICAL,
[]string{"is not supported query type. Only A, AAAA is supported for expectation."},
},
{
[]string{"-H", "a.root-servers.net", "-s", "8.8.8.8", "-e", "198.41.0.3"},
checkers.CRITICAL,
[]string{"status: NOERROR", "198.41.0.4"},
},
{
[]string{"-H", "a.root-servers.invalid", "-s", "8.8.8.8", "-e", "198.41.0.4"},
checkers.CRITICAL,
[]string{"status: NXDOMAIN"},
},
{
[]string{"-H", "a.root-servers.net", "-s", "8.8.8.8", "-e", "198.41.0.3", "-e", "198.41.0.4"},
checkers.WARNING,
[]string{"status: NOERROR", "198.41.0.4"},
},
{
[]string{"-H", "example.com", "-s", "8.8.8.8", "-c", "INN"},
[]string{"-H", "a.root-servers.net", "-s", "8.8.8.8", "-e", "198.41.0.3", "-e", " 198.41.0.4 "},
checkers.CRITICAL,
[]string{"INN is invalid queryClass"},
[]string{"status: NOERROR", "198.41.0.4"},
},
}

Expand Down