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