summaryrefslogtreecommitdiffstats
path: root/plugins/check_dns.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/check_dns.c')
-rw-r--r--plugins/check_dns.c1162
1 files changed, 587 insertions, 575 deletions
diff --git a/plugins/check_dns.c b/plugins/check_dns.c
index 468bc958..95f33083 100644
--- a/plugins/check_dns.c
+++ b/plugins/check_dns.c
@@ -1,36 +1,36 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_dns plugin 3 * Monitoring check_dns plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2008 Monitoring Plugins Development Team 6 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_dns plugin 10 * This file contains the check_dns plugin
11* 11 *
12* LIMITATION: nslookup on Solaris 7 can return output over 2 lines, which 12 * LIMITATION: nslookup on Solaris 7 can return output over 2 lines, which
13* will not be picked up by this plugin 13 * will not be picked up by this plugin
14* 14 *
15* 15 *
16* This program is free software: you can redistribute it and/or modify 16 * This program is free software: you can redistribute it and/or modify
17* it under the terms of the GNU General Public License as published by 17 * it under the terms of the GNU General Public License as published by
18* the Free Software Foundation, either version 3 of the License, or 18 * the Free Software Foundation, either version 3 of the License, or
19* (at your option) any later version. 19 * (at your option) any later version.
20* 20 *
21* This program is distributed in the hope that it will be useful, 21 * This program is distributed in the hope that it will be useful,
22* but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24* GNU General Public License for more details. 24 * GNU General Public License for more details.
25* 25 *
26* You should have received a copy of the GNU General Public License 26 * You should have received a copy of the GNU General Public License
27* along with this program. If not, see <http://www.gnu.org/licenses/>. 27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28* 28 *
29* 29 *
30*****************************************************************************/ 30 *****************************************************************************/
31 31
32const char *progname = "check_dns"; 32const char *progname = "check_dns";
33const char *copyright = "2000-2008"; 33const char *copyright = "2000-2024";
34const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
35 35
36#include "common.h" 36#include "common.h"
@@ -39,579 +39,591 @@ const char *email = "devel@monitoring-plugins.org";
39#include "netutils.h" 39#include "netutils.h"
40#include "runcmd.h" 40#include "runcmd.h"
41 41
42int process_arguments (int, char **); 42#include "states.h"
43int validate_arguments (void); 43#include "check_dns.d/config.h"
44int error_scan (char *, bool *); 44
45bool ip_match_cidr(const char *, const char *); 45typedef struct {
46unsigned long ip2long(const char *); 46 int errorcode;
47void print_help (void); 47 check_dns_config config;
48void print_usage (void); 48} check_dns_config_wrapper;
49 49static check_dns_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
50#define ADDRESS_LENGTH 256 50static check_dns_config_wrapper validate_arguments(check_dns_config_wrapper /*config_wrapper*/);
51char query_address[ADDRESS_LENGTH] = ""; 51static mp_state_enum error_scan(char * /*input_buffer*/, bool * /*is_nxdomain*/, const char /*dns_server*/[ADDRESS_LENGTH]);
52char dns_server[ADDRESS_LENGTH] = ""; 52static bool ip_match_cidr(const char * /*addr*/, const char * /*cidr_ro*/);
53char ptr_server[ADDRESS_LENGTH] = ""; 53static unsigned long ip2long(const char * /*src*/);
54bool verbose = false; 54static void print_help(void);
55char **expected_address = NULL; 55void print_usage(void);
56int expected_address_cnt = 0; 56
57bool expect_nxdomain = false; 57static bool verbose = false;
58 58
59bool expect_authority = false; 59static int qstrcmp(const void *p1, const void *p2) {
60bool all_match = false;
61thresholds *time_thresholds = NULL;
62
63static int
64qstrcmp(const void *p1, const void *p2)
65{
66 /* The actual arguments to this function are "pointers to 60 /* The actual arguments to this function are "pointers to
67 pointers to char", but strcmp() arguments are "pointers 61 pointers to char", but strcmp() arguments are "pointers
68 to char", hence the following cast plus dereference */ 62 to char", hence the following cast plus dereference */
69 return strcmp(* (char * const *) p1, * (char * const *) p2); 63 return strcmp(*(char *const *)p1, *(char *const *)p2);
70} 64}
71 65
66int main(int argc, char **argv) {
67 setlocale(LC_ALL, "");
68 bindtextdomain(PACKAGE, LOCALEDIR);
69 textdomain(PACKAGE);
70
71 /* Set signal handling and alarm */
72 if (signal(SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) {
73 usage_va(_("Cannot catch SIGALRM"));
74 }
75
76 /* Parse extra opts if any */
77 argv = np_extra_opts(&argc, argv, progname);
78
79 check_dns_config_wrapper tmp = process_arguments(argc, argv);
80
81 if (tmp.errorcode == ERROR) {
82 usage_va(_("Could not parse arguments"));
83 }
84
85 const check_dns_config config = tmp.config;
86
87 char *command_line = NULL;
88 /* get the command to run */
89 xasprintf(&command_line, "%s %s %s", NSLOOKUP_COMMAND, config.query_address, config.dns_server);
90
91 struct timeval tv;
92 alarm(timeout_interval);
93 gettimeofday(&tv, NULL);
94
95 if (verbose) {
96 printf("%s\n", command_line);
97 }
98
99 output chld_out;
100 output chld_err;
101 char *msg = NULL;
102 mp_state_enum result = STATE_UNKNOWN;
103 /* run the command */
104 if ((np_runcmd(command_line, &chld_out, &chld_err, 0)) != 0) {
105 msg = (char *)_("nslookup returned an error status");
106 result = STATE_WARNING;
107 }
108
109 /* =====
110 * scan stdout, main results get retrieved here
111 * =====
112 */
113 char *address = NULL; /* comma separated str with addrs/ptrs (sorted) */
114 char **addresses = NULL; // All addresses parsed from stdout
115 size_t n_addresses = 0; // counter for retrieved addresses
116 bool non_authoritative = false;
117 bool is_nxdomain = false;
118 bool parse_address = false; /* This flag scans for Address: but only after Name: */
119 for (size_t i = 0; i < chld_out.lines; i++) {
120 if (addresses == NULL) {
121 addresses = malloc(sizeof(*addresses) * 10);
122 } else if (!(n_addresses % 10)) {
123 addresses = realloc(addresses, sizeof(*addresses) * (n_addresses + 10));
124 }
125
126 if (verbose) {
127 puts(chld_out.line[i]);
128 }
129
130 if (strcasestr(chld_out.line[i], ".in-addr.arpa") || strcasestr(chld_out.line[i], ".ip6.arpa")) {
131 if ((strstr(chld_out.line[i], "canonical name = ") != NULL)) {
132 continue;
133 }
134 char *temp_buffer = NULL;
135 if ((temp_buffer = strstr(chld_out.line[i], "name = "))) {
136 addresses[n_addresses++] = strdup(temp_buffer + 7);
137 } else {
138 msg = (char *)_("Warning plugin error");
139 result = STATE_WARNING;
140 }
141 }
142
143 /* bug ID: 2946553 - Older versions of bind will use all available dns
144 servers, we have to match the one specified */
145 if (strstr(chld_out.line[i], "Server:") && strlen(config.dns_server) > 0) {
146 char *temp_buffer = strchr(chld_out.line[i], ':');
147 if (temp_buffer == NULL) {
148 die(STATE_UNKNOWN, _("'%s' returned a weirdly formatted Server line\n"), NSLOOKUP_COMMAND);
149 }
150
151 temp_buffer++;
152
153 /* Strip leading tabs */
154 for (; *temp_buffer != '\0' && *temp_buffer == '\t'; temp_buffer++) {
155 /* NOOP */;
156 }
157
158 strip(temp_buffer);
159 if (strlen(temp_buffer) == 0) {
160 die(STATE_CRITICAL, _("DNS CRITICAL - '%s' returned empty server string\n"), NSLOOKUP_COMMAND);
161 }
162
163 if (strcmp(temp_buffer, config.dns_server) != 0) {
164 die(STATE_CRITICAL, _("DNS CRITICAL - No response from DNS %s\n"), config.dns_server);
165 }
166 }
167
168 /* the server is responding, we just got the host name... */
169 if (strstr(chld_out.line[i], "Name:")) {
170 parse_address = true;
171 } else if (parse_address && (strstr(chld_out.line[i], "Address:") || strstr(chld_out.line[i], "Addresses:"))) {
172 char *temp_buffer = strchr(chld_out.line[i], ':');
173 if (temp_buffer == NULL) {
174 die(STATE_UNKNOWN, _("'%s' returned a weirdly formatted Address line\n"), NSLOOKUP_COMMAND);
175 }
176
177 temp_buffer++;
178
179 /* Strip leading spaces */
180 while (*temp_buffer == ' ') {
181 temp_buffer++;
182 }
183
184 strip(temp_buffer);
185 if (strlen(temp_buffer) == 0) {
186 die(STATE_CRITICAL, _("DNS CRITICAL - '%s' returned empty host name string\n"), NSLOOKUP_COMMAND);
187 }
188
189 addresses[n_addresses++] = strdup(temp_buffer);
190 } else if (strstr(chld_out.line[i], _("Non-authoritative answer:"))) {
191 non_authoritative = true;
192 }
193
194 result = error_scan(chld_out.line[i], &is_nxdomain, config.dns_server);
195 if (result != STATE_OK) {
196 msg = strchr(chld_out.line[i], ':');
197 if (msg) {
198 msg++;
199 }
200 break;
201 }
202 }
203
204 char input_buffer[MAX_INPUT_BUFFER];
205 /* scan stderr */
206 for (size_t i = 0; i < chld_err.lines; i++) {
207 if (verbose) {
208 puts(chld_err.line[i]);
209 }
210
211 if (error_scan(chld_err.line[i], &is_nxdomain, config.dns_server) != STATE_OK) {
212 result = max_state(result, error_scan(chld_err.line[i], &is_nxdomain, config.dns_server));
213 msg = strchr(input_buffer, ':');
214 if (msg) {
215 msg++;
216 } else {
217 msg = input_buffer;
218 }
219 }
220 }
221
222 if (is_nxdomain && !config.expect_nxdomain) {
223 die(STATE_CRITICAL, _("Domain '%s' was not found by the server\n"), config.query_address);
224 }
225
226 if (addresses) {
227 size_t slen = 1;
228 char *adrp = NULL;
229 qsort(addresses, n_addresses, sizeof(*addresses), qstrcmp);
230 for (size_t i = 0; i < n_addresses; i++) {
231 slen += strlen(addresses[i]) + 1;
232 }
233
234 // Temporary pointer adrp gets moved, address stays on the beginning
235 adrp = address = malloc(slen);
236 for (size_t i = 0; i < n_addresses; i++) {
237 if (i) {
238 *adrp++ = ',';
239 }
240 strcpy(adrp, addresses[i]);
241 adrp += strlen(addresses[i]);
242 }
243 *adrp = 0;
244 } else {
245 die(STATE_CRITICAL, _("DNS CRITICAL - '%s' msg parsing exited with no address\n"), NSLOOKUP_COMMAND);
246 }
247
248 /* compare to expected address */
249 if (result == STATE_OK && config.expected_address_cnt > 0) {
250 result = STATE_CRITICAL;
251 char *temp_buffer = "";
252 unsigned long expect_match = (1 << config.expected_address_cnt) - 1;
253 unsigned long addr_match = (1 << n_addresses) - 1;
254
255 for (size_t i = 0; i < config.expected_address_cnt; i++) {
256 /* check if we get a match on 'raw' ip or cidr */
257 for (size_t j = 0; j < n_addresses; j++) {
258 if (strcmp(addresses[j], config.expected_address[i]) == 0 || ip_match_cidr(addresses[j], config.expected_address[i])) {
259 result = STATE_OK;
260 addr_match &= ~(1 << j);
261 expect_match &= ~(1 << i);
262 }
263 }
264
265 /* prepare an error string */
266 xasprintf(&temp_buffer, "%s%s; ", temp_buffer, config.expected_address[i]);
267 }
268 /* check if expected_address must cover all in addresses and none may be missing */
269 if (config.all_match && (expect_match != 0 || addr_match != 0)) {
270 result = STATE_CRITICAL;
271 }
272 if (result == STATE_CRITICAL) {
273 /* Strip off last semicolon... */
274 temp_buffer[strlen(temp_buffer) - 2] = '\0';
275 xasprintf(&msg, _("expected '%s' but got '%s'"), temp_buffer, address);
276 }
277 }
278
279 if (config.expect_nxdomain) {
280 if (!is_nxdomain) {
281 result = STATE_CRITICAL;
282 xasprintf(&msg, _("Domain '%s' was found by the server: '%s'\n"), config.query_address, address);
283 } else {
284 if (address != NULL) {
285 free(address);
286 }
287 address = "NXDOMAIN";
288 }
289 }
290
291 /* check if authoritative */
292 if (result == STATE_OK && config.expect_authority && non_authoritative) {
293 result = STATE_CRITICAL;
294 xasprintf(&msg, _("server %s is not authoritative for %s"), config.dns_server, config.query_address);
295 }
296
297 long microsec = deltime(tv);
298 double elapsed_time = (double)microsec / 1.0e6;
299
300 if (result == STATE_OK) {
301 result = get_status(elapsed_time, config.time_thresholds);
302 if (result == STATE_OK) {
303 printf("DNS %s: ", _("OK"));
304 } else if (result == STATE_WARNING) {
305 printf("DNS %s: ", _("WARNING"));
306 } else if (result == STATE_CRITICAL) {
307 printf("DNS %s: ", _("CRITICAL"));
308 }
309 printf(ngettext("%.3f second response time", "%.3f seconds response time", elapsed_time), elapsed_time);
310 printf(_(". %s returns %s"), config.query_address, address);
311 if ((config.time_thresholds->warning != NULL) && (config.time_thresholds->critical != NULL)) {
312 printf("|%s\n", fperfdata("time", elapsed_time, "s", true, config.time_thresholds->warning->end, true,
313 config.time_thresholds->critical->end, true, 0, false, 0));
314 } else if ((config.time_thresholds->warning == NULL) && (config.time_thresholds->critical != NULL)) {
315 printf("|%s\n", fperfdata("time", elapsed_time, "s", false, 0, true, config.time_thresholds->critical->end, true, 0, false, 0));
316 } else if ((config.time_thresholds->warning != NULL) && (config.time_thresholds->critical == NULL)) {
317 printf("|%s\n", fperfdata("time", elapsed_time, "s", true, config.time_thresholds->warning->end, false, 0, true, 0, false, 0));
318 } else {
319 printf("|%s\n", fperfdata("time", elapsed_time, "s", false, 0, false, 0, true, 0, false, 0));
320 }
321 } else if (result == STATE_WARNING) {
322 printf(_("DNS WARNING - %s\n"), !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg);
323 } else if (result == STATE_CRITICAL) {
324 printf(_("DNS CRITICAL - %s\n"), !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg);
325 } else {
326 printf(_("DNS UNKNOWN - %s\n"), !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg);
327 }
72 328
73int 329 exit(result);
74main (int argc, char **argv)
75{
76 char *command_line = NULL;
77 char input_buffer[MAX_INPUT_BUFFER];
78 char *address = NULL; /* comma separated str with addrs/ptrs (sorted) */
79 char **addresses = NULL;
80 int n_addresses = 0;
81 char *msg = NULL;
82 char *temp_buffer = NULL;
83 bool non_authoritative = false;
84 int result = STATE_UNKNOWN;
85 double elapsed_time;
86 long microsec;
87 struct timeval tv;
88 bool parse_address = false; /* This flag scans for Address: but only after Name: */
89 output chld_out, chld_err;
90 bool is_nxdomain = false;
91
92 setlocale (LC_ALL, "");
93 bindtextdomain (PACKAGE, LOCALEDIR);
94 textdomain (PACKAGE);
95
96 /* Set signal handling and alarm */
97 if (signal (SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) {
98 usage_va(_("Cannot catch SIGALRM"));
99 }
100
101 /* Parse extra opts if any */
102 argv=np_extra_opts (&argc, argv, progname);
103
104 if (process_arguments (argc, argv) == ERROR) {
105 usage_va(_("Could not parse arguments"));
106 }
107
108 /* get the command to run */
109 xasprintf (&command_line, "%s %s %s", NSLOOKUP_COMMAND, query_address, dns_server);
110
111 alarm (timeout_interval);
112 gettimeofday (&tv, NULL);
113
114 if (verbose)
115 printf ("%s\n", command_line);
116
117 /* run the command */
118 if((np_runcmd(command_line, &chld_out, &chld_err, 0)) != 0) {
119 msg = (char *)_("nslookup returned an error status");
120 result = STATE_WARNING;
121 }
122
123 /* scan stdout */
124 for(size_t i = 0; i < chld_out.lines; i++) {
125 if (addresses == NULL)
126 addresses = malloc(sizeof(*addresses)*10);
127 else if (!(n_addresses % 10))
128 addresses = realloc(addresses,sizeof(*addresses) * (n_addresses + 10));
129
130 if (verbose)
131 puts(chld_out.line[i]);
132
133 if (strcasestr (chld_out.line[i], ".in-addr.arpa") || strcasestr (chld_out.line[i], ".ip6.arpa")) {
134 if ((temp_buffer = strstr (chld_out.line[i], "name = ")))
135 addresses[n_addresses++] = strdup (temp_buffer + 7);
136 else {
137 msg = (char *)_("Warning plugin error");
138 result = STATE_WARNING;
139 }
140 }
141
142 /* bug ID: 2946553 - Older versions of bind will use all available dns
143 servers, we have to match the one specified */
144 if (strstr (chld_out.line[i], "Server:") && strlen(dns_server) > 0) {
145 temp_buffer = strchr (chld_out.line[i], ':');
146 temp_buffer++;
147
148 /* Strip leading tabs */
149 for (; *temp_buffer != '\0' && *temp_buffer == '\t'; temp_buffer++)
150 /* NOOP */;
151
152 strip(temp_buffer);
153 if (temp_buffer==NULL || strlen(temp_buffer)==0) {
154 die (STATE_CRITICAL,
155 _("DNS CRITICAL - '%s' returned empty server string\n"),
156 NSLOOKUP_COMMAND);
157 }
158
159 if (strcmp(temp_buffer, dns_server) != 0) {
160 die (STATE_CRITICAL, _("DNS CRITICAL - No response from DNS %s\n"), dns_server);
161 }
162 }
163
164 /* the server is responding, we just got the host name... */
165 if (strstr (chld_out.line[i], "Name:"))
166 parse_address = true;
167 else if (parse_address && (strstr (chld_out.line[i], "Address:") ||
168 strstr (chld_out.line[i], "Addresses:"))) {
169 temp_buffer = index (chld_out.line[i], ':');
170 temp_buffer++;
171
172 /* Strip leading spaces */
173 while (*temp_buffer == ' ')
174 temp_buffer++;
175
176 strip(temp_buffer);
177 if (temp_buffer==NULL || strlen(temp_buffer)==0) {
178 die (STATE_CRITICAL,
179 _("DNS CRITICAL - '%s' returned empty host name string\n"),
180 NSLOOKUP_COMMAND);
181 }
182
183 addresses[n_addresses++] = strdup(temp_buffer);
184 }
185 else if (strstr (chld_out.line[i], _("Non-authoritative answer:"))) {
186 non_authoritative = true;
187 }
188
189
190 result = error_scan (chld_out.line[i], &is_nxdomain);
191 if (result != STATE_OK) {
192 msg = strchr (chld_out.line[i], ':');
193 if(msg) msg++;
194 break;
195 }
196 }
197
198 /* scan stderr */
199 for(size_t i = 0; i < chld_err.lines; i++) {
200 if (verbose)
201 puts(chld_err.line[i]);
202
203 if (error_scan (chld_err.line[i], &is_nxdomain) != STATE_OK) {
204 result = max_state (result, error_scan (chld_err.line[i], &is_nxdomain));
205 msg = strchr(input_buffer, ':');
206 if(msg)
207 msg++;
208 else
209 msg = input_buffer;
210 }
211 }
212
213 if (is_nxdomain && !expect_nxdomain) {
214 die (STATE_CRITICAL, _("Domain '%s' was not found by the server\n"), query_address);
215 }
216
217 if (addresses) {
218 int i,slen;
219 char *adrp;
220 qsort(addresses, n_addresses, sizeof(*addresses), qstrcmp);
221 for(i=0, slen=1; i < n_addresses; i++) {
222 slen += strlen(addresses[i])+1;
223 }
224 adrp = address = malloc(slen);
225 for(i=0; i < n_addresses; i++) {
226 if (i) *adrp++ = ',';
227 strcpy(adrp, addresses[i]);
228 adrp += strlen(addresses[i]);
229 }
230 *adrp = 0;
231 } else
232 die (STATE_CRITICAL,
233 _("DNS CRITICAL - '%s' msg parsing exited with no address\n"),
234 NSLOOKUP_COMMAND);
235
236 /* compare to expected address */
237 if (result == STATE_OK && expected_address_cnt > 0) {
238 result = STATE_CRITICAL;
239 temp_buffer = "";
240 unsigned long expect_match = (1 << expected_address_cnt) - 1;
241 unsigned long addr_match = (1 << n_addresses) - 1;
242
243 for (int i=0; i<expected_address_cnt; i++) {
244 int j;
245 /* check if we get a match on 'raw' ip or cidr */
246 for (j=0; j<n_addresses; j++) {
247 if ( strcmp(addresses[j], expected_address[i]) == 0
248 || ip_match_cidr(addresses[j], expected_address[i]) ) {
249 result = STATE_OK;
250 addr_match &= ~(1 << j);
251 expect_match &= ~(1 << i);
252 }
253 }
254
255 /* prepare an error string */
256 xasprintf(&temp_buffer, "%s%s; ", temp_buffer, expected_address[i]);
257 }
258 /* check if expected_address must cover all in addresses and none may be missing */
259 if (all_match && (expect_match != 0 || addr_match != 0))
260 result = STATE_CRITICAL;
261 if (result == STATE_CRITICAL) {
262 /* Strip off last semicolon... */
263 temp_buffer[strlen(temp_buffer)-2] = '\0';
264 xasprintf(&msg, _("expected '%s' but got '%s'"), temp_buffer, address);
265 }
266 }
267
268 if (expect_nxdomain) {
269 if (!is_nxdomain) {
270 result = STATE_CRITICAL;
271 xasprintf(&msg, _("Domain '%s' was found by the server: '%s'\n"), query_address, address);
272 } else {
273 if (address != NULL) free(address);
274 address = "NXDOMAIN";
275 }
276 }
277
278 /* check if authoritative */
279 if (result == STATE_OK && expect_authority && non_authoritative) {
280 result = STATE_CRITICAL;
281 xasprintf(&msg, _("server %s is not authoritative for %s"), dns_server, query_address);
282 }
283
284 microsec = deltime (tv);
285 elapsed_time = (double)microsec / 1.0e6;
286
287 if (result == STATE_OK) {
288 result = get_status(elapsed_time, time_thresholds);
289 if (result == STATE_OK) {
290 printf ("DNS %s: ", _("OK"));
291 } else if (result == STATE_WARNING) {
292 printf ("DNS %s: ", _("WARNING"));
293 } else if (result == STATE_CRITICAL) {
294 printf ("DNS %s: ", _("CRITICAL"));
295 }
296 printf (ngettext("%.3f second response time", "%.3f seconds response time", elapsed_time), elapsed_time);
297 printf (_(". %s returns %s"), query_address, address);
298 if ((time_thresholds->warning != NULL) && (time_thresholds->critical != NULL)) {
299 printf ("|%s\n", fperfdata ("time", elapsed_time, "s",
300 true, time_thresholds->warning->end,
301 true, time_thresholds->critical->end,
302 true, 0, false, 0));
303 } else if ((time_thresholds->warning == NULL) && (time_thresholds->critical != NULL)) {
304 printf ("|%s\n", fperfdata ("time", elapsed_time, "s",
305 false, 0,
306 true, time_thresholds->critical->end,
307 true, 0, false, 0));
308 } else if ((time_thresholds->warning != NULL) && (time_thresholds->critical == NULL)) {
309 printf ("|%s\n", fperfdata ("time", elapsed_time, "s",
310 true, time_thresholds->warning->end,
311 false, 0,
312 true, 0, false, 0));
313 } else
314 printf ("|%s\n", fperfdata ("time", elapsed_time, "s", false, 0, false, 0, true, 0, false, 0));
315 }
316 else if (result == STATE_WARNING)
317 printf (_("DNS WARNING - %s\n"),
318 !strcmp (msg, "") ? _(" Probably a non-existent host/domain") : msg);
319 else if (result == STATE_CRITICAL)
320 printf (_("DNS CRITICAL - %s\n"),
321 !strcmp (msg, "") ? _(" Probably a non-existent host/domain") : msg);
322 else
323 printf (_("DNS UNKNOWN - %s\n"),
324 !strcmp (msg, "") ? _(" Probably a non-existent host/domain") : msg);
325
326 return result;
327} 330}
328 331
329bool ip_match_cidr(const char *addr, const char *cidr_ro) { 332bool ip_match_cidr(const char *addr, const char *cidr_ro) {
330 char *subnet, *mask_c, *cidr = strdup(cidr_ro); 333 char *subnet;
331 int mask; 334 char *mask_c;
332 subnet = strtok(cidr, "/"); 335 char *cidr = strdup(cidr_ro);
333 mask_c = strtok(NULL, "\0"); 336 int mask;
334 if (!subnet || !mask_c) { 337 subnet = strtok(cidr, "/");
335 return false; 338 mask_c = strtok(NULL, "\0");
339 if (!subnet || !mask_c) {
340 return false;
336 } 341 }
337 mask = atoi(mask_c); 342 mask = atoi(mask_c);
338 343
339 /* https://www.cryptobells.com/verifying-ips-in-a-subnet-in-php/ */ 344 /* https://www.cryptobells.com/verifying-ips-in-a-subnet-in-php/ */
340 return (ip2long(addr) & ~((1 << (32 - mask)) - 1)) == (ip2long(subnet) >> (32 - mask)) << (32 - mask); 345 return (ip2long(addr) & ~((1 << (32 - mask)) - 1)) == (ip2long(subnet) >> (32 - mask)) << (32 - mask);
341} 346}
342 347
343unsigned long 348unsigned long ip2long(const char *src) {
344ip2long(const char* src) { 349 unsigned long ip[4];
345 unsigned long ip[4]; 350 /* http://computer-programming-forum.com/47-c-language/1376ffb92a12c471.htm */
346 /* http://computer-programming-forum.com/47-c-language/1376ffb92a12c471.htm */ 351 return (sscanf(src, "%3lu.%3lu.%3lu.%3lu", &ip[0], &ip[1], &ip[2], &ip[3]) == 4 && ip[0] < 256 && ip[1] < 256 && ip[2] < 256 &&
347 return (sscanf(src, "%3lu.%3lu.%3lu.%3lu", 352 ip[3] < 256)
348 &ip[0], &ip[1], &ip[2], &ip[3]) == 4 && 353 ? ip[0] << 24 | ip[1] << 16 | ip[2] << 8 | ip[3]
349 ip[0] < 256 && ip[1] < 256 && 354 : 0;
350 ip[2] < 256 && ip[3] < 256)
351 ? ip[0] << 24 | ip[1] << 16 | ip[2] << 8 | ip[3]
352 : 0;
353} 355}
354 356
355int 357mp_state_enum error_scan(char *input_buffer, bool *is_nxdomain, const char dns_server[ADDRESS_LENGTH]) {
356error_scan (char *input_buffer, bool *is_nxdomain)
357{
358
359 const int nxdomain = strstr (input_buffer, "Non-existent") ||
360 strstr (input_buffer, "** server can't find") ||
361 strstr (input_buffer, "** Can't find") ||
362 strstr (input_buffer, "NXDOMAIN");
363 if (nxdomain) *is_nxdomain = true;
364
365 /* the DNS lookup timed out */
366 if (strstr (input_buffer, _("Note: nslookup is deprecated and may be removed from future releases.")) ||
367 strstr (input_buffer, _("Consider using the `dig' or `host' programs instead. Run nslookup with")) ||
368 strstr (input_buffer, _("the `-sil[ent]' option to prevent this message from appearing.")))
369 return STATE_OK;
370
371 /* DNS server is not running... */
372 else if (strstr (input_buffer, "No response from server"))
373 die (STATE_CRITICAL, _("No response from DNS %s\n"), dns_server);
374 else if (strstr (input_buffer, "no servers could be reached"))
375 die (STATE_CRITICAL, _("No response from DNS %s\n"), dns_server);
376
377 /* Host name is valid, but server doesn't have records... */
378 else if (strstr (input_buffer, "No records"))
379 die (STATE_CRITICAL, _("DNS %s has no records\n"), dns_server);
380
381 /* Connection was refused */
382 else if (strstr (input_buffer, "Connection refused") ||
383 strstr (input_buffer, "Couldn't find server") ||
384 strstr (input_buffer, "Refused") ||
385 (strstr (input_buffer, "** server can't find") &&
386 strstr (input_buffer, ": REFUSED")))
387 die (STATE_CRITICAL, _("Connection to DNS %s was refused\n"), dns_server);
388
389 /* Query refused (usually by an ACL in the namserver) */
390 else if (strstr (input_buffer, "Query refused"))
391 die (STATE_CRITICAL, _("Query was refused by DNS server at %s\n"), dns_server);
392
393 /* No information (e.g. nameserver IP has two PTR records) */
394 else if (strstr (input_buffer, "No information"))
395 die (STATE_CRITICAL, _("No information returned by DNS server at %s\n"), dns_server);
396
397 /* Network is unreachable */
398 else if (strstr (input_buffer, "Network is unreachable"))
399 die (STATE_CRITICAL, _("Network is unreachable\n"));
400
401 /* Internal server failure */
402 else if (strstr (input_buffer, "Server failure"))
403 die (STATE_CRITICAL, _("DNS failure for %s\n"), dns_server);
404
405 /* Request error or the DNS lookup timed out */
406 else if (strstr (input_buffer, "Format error") ||
407 strstr (input_buffer, "Timed out"))
408 return STATE_WARNING;
409
410 return STATE_OK;
411 358
412} 359 const int nxdomain = strstr(input_buffer, "Non-existent") || strstr(input_buffer, "** server can't find") ||
360 strstr(input_buffer, "** Can't find") || strstr(input_buffer, "NXDOMAIN");
361 if (nxdomain) {
362 *is_nxdomain = true;
363 }
413 364
365 /* the DNS lookup timed out */
366 if (strstr(input_buffer, _("Note: nslookup is deprecated and may be removed from future releases.")) ||
367 strstr(input_buffer, _("Consider using the `dig' or `host' programs instead. Run nslookup with")) ||
368 strstr(input_buffer, _("the `-sil[ent]' option to prevent this message from appearing."))) {
369 return STATE_OK;
370 }
414 371
415/* process command-line arguments */ 372 /* DNS server is not running... */
416int 373 else if (strstr(input_buffer, "No response from server")) {
417process_arguments (int argc, char **argv) 374 die(STATE_CRITICAL, _("No response from DNS %s\n"), dns_server);
418{ 375 } else if (strstr(input_buffer, "no servers could be reached")) {
419 int c; 376 die(STATE_CRITICAL, _("No response from DNS %s\n"), dns_server);
420 char *warning = NULL; 377 }
421 char *critical = NULL; 378
422 379 /* Host name is valid, but server doesn't have records... */
423 int opt_index = 0; 380 else if (strstr(input_buffer, "No records")) {
424 static struct option long_opts[] = { 381 die(STATE_CRITICAL, _("DNS %s has no records\n"), dns_server);
425 {"help", no_argument, 0, 'h'}, 382 }
426 {"version", no_argument, 0, 'V'}, 383
427 {"verbose", no_argument, 0, 'v'}, 384 /* Connection was refused */
428 {"timeout", required_argument, 0, 't'}, 385 else if (strstr(input_buffer, "Connection refused") || strstr(input_buffer, "Couldn't find server") ||
429 {"hostname", required_argument, 0, 'H'}, 386 strstr(input_buffer, "Refused") || (strstr(input_buffer, "** server can't find") && strstr(input_buffer, ": REFUSED"))) {
430 {"server", required_argument, 0, 's'}, 387 die(STATE_CRITICAL, _("Connection to DNS %s was refused\n"), dns_server);
431 {"reverse-server", required_argument, 0, 'r'}, 388 }
432 {"expected-address", required_argument, 0, 'a'}, 389
433 {"expect-nxdomain", no_argument, 0, 'n'}, 390 /* Query refused (usually by an ACL in the namserver) */
434 {"expect-authority", no_argument, 0, 'A'}, 391 else if (strstr(input_buffer, "Query refused")) {
435 {"all", no_argument, 0, 'L'}, 392 die(STATE_CRITICAL, _("Query was refused by DNS server at %s\n"), dns_server);
436 {"warning", required_argument, 0, 'w'}, 393 }
437 {"critical", required_argument, 0, 'c'}, 394
438 {0, 0, 0, 0} 395 /* No information (e.g. nameserver IP has two PTR records) */
439 }; 396 else if (strstr(input_buffer, "No information")) {
440 397 die(STATE_CRITICAL, _("No information returned by DNS server at %s\n"), dns_server);
441 if (argc < 2) 398 }
442 return ERROR; 399
443 400 /* Network is unreachable */
444 for (c = 1; c < argc; c++) 401 else if (strstr(input_buffer, "Network is unreachable")) {
445 if (strcmp ("-to", argv[c]) == 0) 402 die(STATE_CRITICAL, _("Network is unreachable\n"));
446 strcpy (argv[c], "-t"); 403 }
447 404
448 while (1) { 405 /* Internal server failure */
449 c = getopt_long (argc, argv, "hVvALnt:H:s:r:a:w:c:", long_opts, &opt_index); 406 else if (strstr(input_buffer, "Server failure")) {
450 407 die(STATE_CRITICAL, _("DNS failure for %s\n"), dns_server);
451 if (c == -1 || c == EOF)
452 break;
453
454 switch (c) {
455 case 'h': /* help */
456 print_help ();
457 exit (STATE_UNKNOWN);
458 case 'V': /* version */
459 print_revision (progname, NP_VERSION);
460 exit (STATE_UNKNOWN);
461 case 'v': /* version */
462 verbose = true;
463 break;
464 case 't': /* timeout period */
465 timeout_interval = atoi (optarg);
466 break;
467 case 'H': /* hostname */
468 if (strlen (optarg) >= ADDRESS_LENGTH)
469 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
470 strcpy (query_address, optarg);
471 break;
472 case 's': /* server name */
473 /* TODO: this host_or_die check is probably unnecessary.
474 * Better to confirm nslookup response matches */
475 host_or_die(optarg);
476 if (strlen (optarg) >= ADDRESS_LENGTH)
477 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
478 strcpy (dns_server, optarg);
479 break;
480 case 'r': /* reverse server name */
481 /* TODO: Is this host_or_die necessary? */
482 host_or_die(optarg);
483 if (strlen (optarg) >= ADDRESS_LENGTH)
484 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
485 strcpy (ptr_server, optarg);
486 break;
487 case 'a': /* expected address */
488 if (strlen (optarg) >= ADDRESS_LENGTH)
489 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
490 if (strchr(optarg, ',') != NULL) {
491 char *comma = strchr(optarg, ',');
492 while (comma != NULL) {
493 expected_address = (char **)realloc(expected_address, (expected_address_cnt+1) * sizeof(char**));
494 expected_address[expected_address_cnt] = strndup(optarg, comma - optarg);
495 expected_address_cnt++;
496 optarg = comma + 1;
497 comma = strchr(optarg, ',');
498 } 408 }
499 expected_address = (char **)realloc(expected_address, (expected_address_cnt+1) * sizeof(char**)); 409
500 expected_address[expected_address_cnt] = strdup(optarg); 410 /* Request error or the DNS lookup timed out */
501 expected_address_cnt++; 411 else if (strstr(input_buffer, "Format error") || strstr(input_buffer, "Timed out")) {
502 } else { 412 return STATE_WARNING;
503 expected_address = (char **)realloc(expected_address, (expected_address_cnt+1) * sizeof(char**)); 413 }
504 expected_address[expected_address_cnt] = strdup(optarg); 414
505 expected_address_cnt++; 415 return STATE_OK;
506 }
507 break;
508 case 'n': /* expect NXDOMAIN */
509 expect_nxdomain = true;
510 break;
511 case 'A': /* expect authority */
512 expect_authority = true;
513 break;
514 case 'L': /* all must match */
515 all_match = true;
516 break;
517 case 'w':
518 warning = optarg;
519 break;
520 case 'c':
521 critical = optarg;
522 break;
523 default: /* args not parsable */
524 usage5();
525 }
526 }
527
528 c = optind;
529 if (strlen(query_address)==0 && c<argc) {
530 if (strlen(argv[c])>=ADDRESS_LENGTH)
531 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
532 strcpy (query_address, argv[c++]);
533 }
534
535 if (strlen(dns_server)==0 && c<argc) {
536 /* TODO: See -s option */
537 host_or_die(argv[c]);
538 if (strlen(argv[c]) >= ADDRESS_LENGTH)
539 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
540 strcpy (dns_server, argv[c++]);
541 }
542
543 set_thresholds(&time_thresholds, warning, critical);
544
545 return validate_arguments ();
546} 416}
547 417
418/* process command-line arguments */
419check_dns_config_wrapper process_arguments(int argc, char **argv) {
420 static struct option long_opts[] = {{"help", no_argument, 0, 'h'},
421 {"version", no_argument, 0, 'V'},
422 {"verbose", no_argument, 0, 'v'},
423 {"timeout", required_argument, 0, 't'},
424 {"hostname", required_argument, 0, 'H'},
425 {"server", required_argument, 0, 's'},
426 {"reverse-server", required_argument, 0, 'r'},
427 {"expected-address", required_argument, 0, 'a'},
428 {"expect-nxdomain", no_argument, 0, 'n'},
429 {"expect-authority", no_argument, 0, 'A'},
430 {"all", no_argument, 0, 'L'},
431 {"warning", required_argument, 0, 'w'},
432 {"critical", required_argument, 0, 'c'},
433 {0, 0, 0, 0}};
434
435 check_dns_config_wrapper result = {
436 .config = check_dns_config_init(),
437 .errorcode = OK,
438 };
439
440 if (argc < 2) {
441 result.errorcode = ERROR;
442 return result;
443 }
444
445 for (int index = 1; index < argc; index++) {
446 if (strcmp("-to", argv[index]) == 0) {
447 strcpy(argv[index], "-t");
448 }
449 }
450
451 char *warning = NULL;
452 char *critical = NULL;
453 int opt_index = 0;
454 int index = 0;
455 while (true) {
456 index = getopt_long(argc, argv, "hVvALnt:H:s:r:a:w:c:", long_opts, &opt_index);
457
458 if (index == -1 || index == EOF) {
459 break;
460 }
461
462 switch (index) {
463 case 'h': /* help */
464 print_help();
465 exit(STATE_UNKNOWN);
466 case 'V': /* version */
467 print_revision(progname, NP_VERSION);
468 exit(STATE_UNKNOWN);
469 case 'v': /* version */
470 verbose = true;
471 break;
472 case 't': /* timeout period */
473 timeout_interval = atoi(optarg);
474 break;
475 case 'H': /* hostname */
476 if (strlen(optarg) >= ADDRESS_LENGTH) {
477 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
478 }
479 strcpy(result.config.query_address, optarg);
480 break;
481 case 's': /* server name */
482 /* TODO: this host_or_die check is probably unnecessary.
483 * Better to confirm nslookup response matches */
484 host_or_die(optarg);
485 if (strlen(optarg) >= ADDRESS_LENGTH) {
486 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
487 }
488 strcpy(result.config.dns_server, optarg);
489 break;
490 case 'r': /* reverse server name */
491 /* TODO: Is this host_or_die necessary? */
492 // TODO This does not do anything!!! 2025-03-08 rincewind
493 host_or_die(optarg);
494 if (strlen(optarg) >= ADDRESS_LENGTH) {
495 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
496 }
497 static char ptr_server[ADDRESS_LENGTH] = "";
498 strcpy(ptr_server, optarg);
499 break;
500 case 'a': /* expected address */
501 if (strlen(optarg) >= ADDRESS_LENGTH) {
502 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
503 }
504 if (strchr(optarg, ',') != NULL) {
505 char *comma = strchr(optarg, ',');
506 while (comma != NULL) {
507 result.config.expected_address =
508 (char **)realloc(result.config.expected_address, (result.config.expected_address_cnt + 1) * sizeof(char **));
509 result.config.expected_address[result.config.expected_address_cnt] = strndup(optarg, comma - optarg);
510 result.config.expected_address_cnt++;
511 optarg = comma + 1;
512 comma = strchr(optarg, ',');
513 }
514 result.config.expected_address =
515 (char **)realloc(result.config.expected_address, (result.config.expected_address_cnt + 1) * sizeof(char **));
516 result.config.expected_address[result.config.expected_address_cnt] = strdup(optarg);
517 result.config.expected_address_cnt++;
518 } else {
519 result.config.expected_address =
520 (char **)realloc(result.config.expected_address, (result.config.expected_address_cnt + 1) * sizeof(char **));
521 result.config.expected_address[result.config.expected_address_cnt] = strdup(optarg);
522 result.config.expected_address_cnt++;
523 }
524 break;
525 case 'n': /* expect NXDOMAIN */
526 result.config.expect_nxdomain = true;
527 break;
528 case 'A': /* expect authority */
529 result.config.expect_authority = true;
530 break;
531 case 'L': /* all must match */
532 result.config.all_match = true;
533 break;
534 case 'w':
535 warning = optarg;
536 break;
537 case 'c':
538 critical = optarg;
539 break;
540 default: /* args not parsable */
541 usage5();
542 }
543 }
544
545 index = optind;
546 if (strlen(result.config.query_address) == 0 && index < argc) {
547 if (strlen(argv[index]) >= ADDRESS_LENGTH) {
548 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
549 }
550 strcpy(result.config.query_address, argv[index++]);
551 }
548 552
549int 553 if (strlen(result.config.dns_server) == 0 && index < argc) {
550validate_arguments () 554 /* TODO: See -s option */
551{ 555 host_or_die(argv[index]);
552 if (query_address[0] == 0) { 556 if (strlen(argv[index]) >= ADDRESS_LENGTH) {
553 printf ("missing --host argument\n"); 557 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
554 return ERROR; 558 }
555 } 559 strcpy(result.config.dns_server, argv[index++]);
560 }
556 561
557 if (expected_address_cnt > 0 && expect_nxdomain) { 562 set_thresholds(&result.config.time_thresholds, warning, critical);
558 printf ("--expected-address and --expect-nxdomain cannot be combined\n");
559 return ERROR;
560 }
561 563
562 return OK; 564 return validate_arguments(result);
563} 565}
564 566
567check_dns_config_wrapper validate_arguments(check_dns_config_wrapper config_wrapper) {
568 if (config_wrapper.config.query_address[0] == 0) {
569 printf("missing --host argument\n");
570 config_wrapper.errorcode = ERROR;
571 return config_wrapper;
572 }
573
574 if (config_wrapper.config.expected_address_cnt > 0 && config_wrapper.config.expect_nxdomain) {
575 printf("--expected-address and --expect-nxdomain cannot be combined\n");
576 config_wrapper.errorcode = ERROR;
577 return config_wrapper;
578 }
565 579
566void 580 return config_wrapper;
567print_help (void)
568{
569 print_revision (progname, NP_VERSION);
570
571 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
572 printf (COPYRIGHT, copyright, email);
573
574 printf ("%s\n", _("This plugin uses the nslookup program to obtain the IP address for the given host/domain query."));
575 printf ("%s\n", _("An optional DNS server to use may be specified."));
576 printf ("%s\n", _("If no DNS server is specified, the default server(s) specified in /etc/resolv.conf will be used."));
577
578 printf ("\n\n");
579
580 print_usage ();
581
582 printf (UT_HELP_VRSN);
583 printf (UT_EXTRA_OPTS);
584
585 printf (" -H, --hostname=HOST\n");
586 printf (" %s\n", _("The name or address you want to query"));
587 printf (" -s, --server=HOST\n");
588 printf (" %s\n", _("Optional DNS server you want to use for the lookup"));
589 printf (" -a, --expected-address=IP-ADDRESS|CIDR|HOST\n");
590 printf (" %s\n", _("Optional IP-ADDRESS/CIDR you expect the DNS server to return. HOST must end"));
591 printf (" %s\n", _("with a dot (.). This option can be repeated multiple times (Returns OK if any"));
592 printf (" %s\n", _("value matches)."));
593 printf (" -n, --expect-nxdomain\n");
594 printf (" %s\n", _("Expect the DNS server to return NXDOMAIN (i.e. the domain was not found)"));
595 printf (" %s\n", _("Cannot be used together with -a"));
596 printf (" -A, --expect-authority\n");
597 printf (" %s\n", _("Optionally expect the DNS server to be authoritative for the lookup"));
598 printf (" -w, --warning=seconds\n");
599 printf (" %s\n", _("Return warning if elapsed time exceeds value. Default off"));
600 printf (" -c, --critical=seconds\n");
601 printf (" %s\n", _("Return critical if elapsed time exceeds value. Default off"));
602 printf (" -L, --all\n");
603 printf (" %s\n", _("Return critical if the list of expected addresses does not match all addresses"));
604 printf (" %s\n", _("returned. Default off"));
605
606 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
607
608 printf (UT_SUPPORT);
609} 581}
610 582
583void print_help(void) {
584 print_revision(progname, NP_VERSION);
585
586 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
587 printf(COPYRIGHT, copyright, email);
588
589 printf("%s\n", _("This plugin uses the nslookup program to obtain the IP address for the given host/domain query."));
590 printf("%s\n", _("An optional DNS server to use may be specified."));
591 printf("%s\n", _("If no DNS server is specified, the default server(s) specified in /etc/resolv.conf will be used."));
592
593 printf("\n\n");
594
595 print_usage();
596
597 printf(UT_HELP_VRSN);
598 printf(UT_EXTRA_OPTS);
599
600 printf(" -H, --hostname=HOST\n");
601 printf(" %s\n", _("The name or address you want to query"));
602 printf(" -s, --server=HOST\n");
603 printf(" %s\n", _("Optional DNS server you want to use for the lookup"));
604 printf(" -a, --expected-address=IP-ADDRESS|CIDR|HOST\n");
605 printf(" %s\n", _("Optional IP-ADDRESS/CIDR you expect the DNS server to return. HOST must end"));
606 printf(" %s\n", _("with a dot (.). This option can be repeated multiple times (Returns OK if any"));
607 printf(" %s\n", _("value matches)."));
608 printf(" -n, --expect-nxdomain\n");
609 printf(" %s\n", _("Expect the DNS server to return NXDOMAIN (i.e. the domain was not found)"));
610 printf(" %s\n", _("Cannot be used together with -a"));
611 printf(" -A, --expect-authority\n");
612 printf(" %s\n", _("Optionally expect the DNS server to be authoritative for the lookup"));
613 printf(" -w, --warning=seconds\n");
614 printf(" %s\n", _("Return warning if elapsed time exceeds value. Default off"));
615 printf(" -c, --critical=seconds\n");
616 printf(" %s\n", _("Return critical if elapsed time exceeds value. Default off"));
617 printf(" -L, --all\n");
618 printf(" %s\n", _("Return critical if the list of expected addresses does not match all addresses"));
619 printf(" %s\n", _("returned. Default off"));
620
621 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
622
623 printf(UT_SUPPORT);
624}
611 625
612void 626void print_usage(void) {
613print_usage (void) 627 printf("%s\n", _("Usage:"));
614{ 628 printf("%s -H host [-s server] [-a expected-address] [-n] [-A] [-t timeout] [-w warn] [-c crit] [-L]\n", progname);
615 printf ("%s\n", _("Usage:"));
616 printf ("%s -H host [-s server] [-a expected-address] [-n] [-A] [-t timeout] [-w warn] [-c crit] [-L]\n", progname);
617} 629}