summaryrefslogtreecommitdiffstats
path: root/plugins/check_tcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/check_tcp.c')
-rw-r--r--plugins/check_tcp.c1151
1 files changed, 617 insertions, 534 deletions
diff --git a/plugins/check_tcp.c b/plugins/check_tcp.c
index 01dd35eb..22dcc74e 100644
--- a/plugins/check_tcp.c
+++ b/plugins/check_tcp.c
@@ -1,714 +1,797 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_tcp plugin 3 * Monitoring check_tcp plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2013 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2025 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_tcp plugin 10 * This file contains the check_tcp plugin
11* 11 *
12* 12 *
13* This program is free software: you can redistribute it and/or modify 13 * This program is free software: you can redistribute it and/or modify
14* it under the terms of the GNU General Public License as published by 14 * it under the terms of the GNU General Public License as published by
15* the Free Software Foundation, either version 3 of the License, or 15 * the Free Software Foundation, either version 3 of the License, or
16* (at your option) any later version. 16 * (at your option) any later version.
17* 17 *
18* This program is distributed in the hope that it will be useful, 18 * This program is distributed in the hope that it will be useful,
19* but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21* GNU General Public License for more details. 21 * GNU General Public License for more details.
22* 22 *
23* You should have received a copy of the GNU General Public License 23 * You should have received a copy of the GNU General Public License
24* along with this program. If not, see <http://www.gnu.org/licenses/>. 24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25* 25 *
26* $Id$ 26 * $Id$
27* 27 *
28*****************************************************************************/ 28 *****************************************************************************/
29 29
30/* progname "check_tcp" changes depending on symlink called */ 30/* progname "check_tcp" changes depending on symlink called */
31char *progname; 31char *progname;
32const char *copyright = "1999-2008"; 32const char *copyright = "1999-2025";
33const char *email = "devel@monitoring-plugins.org"; 33const char *email = "devel@monitoring-plugins.org";
34 34
35#include "common.h" 35#include "./common.h"
36#include "netutils.h" 36#include "./netutils.h"
37#include "utils.h" 37#include "./utils.h"
38#include "utils_tcp.h" 38#include "./check_tcp.d/config.h"
39#include "output.h"
40#include "states.h"
39 41
42#include <sys/types.h>
40#include <ctype.h> 43#include <ctype.h>
41#include <sys/select.h> 44#include <sys/select.h>
42 45
46ssize_t my_recv(int socket_descriptor, char *buf, size_t len, bool use_tls) {
43#ifdef HAVE_SSL 47#ifdef HAVE_SSL
44static bool check_cert = false; 48 if (use_tls) {
45static int days_till_exp_warn, days_till_exp_crit; 49 return np_net_ssl_read(buf, (int)len);
46# define my_recv(buf, len) ((flags & FLAG_SSL) ? np_net_ssl_read(buf, len) : read(sd, buf, len)) 50 }
47# define my_send(buf, len) ((flags & FLAG_SSL) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
48#else
49# define my_recv(buf, len) read(sd, buf, len)
50# define my_send(buf, len) send(sd, buf, len, 0)
51#endif 51#endif
52 return read(socket_descriptor, buf, len);
53}
52 54
53/* int my_recv(char *, size_t); */ 55ssize_t my_send(int socket_descriptor, char *buf, size_t len, bool use_tls) {
54static int process_arguments (int, char **);
55void print_help (void);
56void print_usage (void);
57
58#define EXPECT server_expect[0]
59static char *SERVICE = "TCP";
60static char *SEND = NULL;
61static char *QUIT = NULL;
62static int PROTOCOL = IPPROTO_TCP; /* most common is default */
63static int PORT = 0;
64static int READ_TIMEOUT = 2;
65
66static int server_port = 0;
67static char *server_address = NULL;
68static bool host_specified = false;
69static char *server_send = NULL;
70static char *server_quit = NULL;
71static char **server_expect;
72static size_t server_expect_count = 0;
73static ssize_t maxbytes = 0;
74static char **warn_codes = NULL;
75static size_t warn_codes_count = 0;
76static char **crit_codes = NULL;
77static size_t crit_codes_count = 0;
78static unsigned int delay = 0;
79static double warning_time = 0;
80static double critical_time = 0;
81static double elapsed_time = 0;
82static long microsec;
83static int sd = 0;
84#define MAXBUF 1024
85static char buffer[MAXBUF];
86static int expect_mismatch_state = STATE_WARNING;
87static int match_flags = NP_MATCH_EXACT;
88
89#ifdef HAVE_SSL 56#ifdef HAVE_SSL
90static char *sni = NULL; 57 if (use_tls) {
91static bool sni_specified = false; 58 return np_net_ssl_write(buf, (int)len);
59 }
92#endif 60#endif
61 return write(socket_descriptor, buf, len);
62}
93 63
94#define FLAG_SSL 0x01 64typedef struct {
95#define FLAG_VERBOSE 0x02 65 int errorcode;
96#define FLAG_TIME_WARN 0x04 66 check_tcp_config config;
97#define FLAG_TIME_CRIT 0x08 67} check_tcp_config_wrapper;
98#define FLAG_HIDE_OUTPUT 0x10 68static check_tcp_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/, check_tcp_config /*config*/);
99static size_t flags; 69void print_help(const char *service);
100 70void print_usage(void);
101int 71
102main (int argc, char **argv) 72int verbosity = 0;
103{ 73
104 int result = STATE_UNKNOWN; 74static const int READ_TIMEOUT = 2;
105 char *status = NULL; 75
106 struct timeval tv; 76const int MAXBUF = 1024;
107 struct timeval timeout; 77
108 int match = -1; 78const int DEFAULT_FTP_PORT = 21;
109 fd_set rfds; 79const int DEFAULT_POP_PORT = 110;
110 80const int DEFAULT_SPOP_PORT = 995;
111 FD_ZERO(&rfds); 81const int DEFAULT_SMTP_PORT = 25;
112 82const int DEFAULT_SSMTP_PORT = 465;
113 setlocale (LC_ALL, ""); 83const int DEFAULT_IMAP_PORT = 143;
114 bindtextdomain (PACKAGE, LOCALEDIR); 84const int DEFAULT_SIMAP_PORT = 993;
115 textdomain (PACKAGE); 85const int DEFAULT_XMPP_C2S_PORT = 5222;
86const int DEFAULT_NNTP_PORT = 119;
87const int DEFAULT_NNTPS_PORT = 563;
88const int DEFAULT_CLAMD_PORT = 3310;
89
90int main(int argc, char **argv) {
91 setlocale(LC_ALL, "");
92 bindtextdomain(PACKAGE, LOCALEDIR);
93 textdomain(PACKAGE);
116 94
117 /* determine program- and service-name quickly */ 95 /* determine program- and service-name quickly */
118 progname = strrchr(argv[0], '/'); 96 progname = strrchr(argv[0], '/');
119 if(progname != NULL) progname++; 97 if (progname != NULL) {
120 else progname = argv[0]; 98 progname++;
99 } else {
100 progname = argv[0];
101 }
102
103 // Initialize config here with values from above,
104 // might be changed by on disk config or cli commands
105 check_tcp_config config = check_tcp_config_init();
121 106
122 size_t prog_name_len = strlen(progname); 107 size_t prog_name_len = strlen(progname);
123 if(prog_name_len > 6 && !memcmp(progname, "check_", 6)) { 108 const size_t prefix_length = strlen("check_");
124 SERVICE = strdup(progname + 6); 109
125 for(size_t i = 0; i < prog_name_len - 6; i++) 110 if (prog_name_len <= prefix_length) {
126 SERVICE[i] = toupper(SERVICE[i]); 111 die(STATE_UNKNOWN, _("Weird progname"));
112 }
113
114 if (!memcmp(progname, "check_", prefix_length)) {
115 config.service = strdup(progname + prefix_length);
116 if (config.service == NULL) {
117 die(STATE_UNKNOWN, _("Allocation failed"));
118 }
119
120 for (size_t i = 0; i < prog_name_len - prefix_length; i++) {
121 config.service[i] = toupper(config.service[i]);
122 }
127 } 123 }
128 124
129 /* set up a reasonable buffer at first (will be realloc()'ed if 125 /* set up a reasonable buffer at first (will be realloc()'ed if
130 * user specifies other options) */ 126 * user specifies other options) */
131 server_expect = calloc(sizeof(char *), 2); 127 config.server_expect = calloc(2, sizeof(char *));
132 128
133 /* determine defaults for this service's protocol */ 129 if (config.server_expect == NULL) {
134 if (!strncmp(SERVICE, "UDP", 3)) { 130 die(STATE_UNKNOWN, _("Allocation failed"));
135 PROTOCOL = IPPROTO_UDP;
136 }
137 else if (!strncmp(SERVICE, "FTP", 3)) {
138 EXPECT = "220";
139 QUIT = "QUIT\r\n";
140 PORT = 21;
141 }
142 else if (!strncmp(SERVICE, "POP", 3) || !strncmp(SERVICE, "POP3", 4)) {
143 EXPECT = "+OK";
144 QUIT = "QUIT\r\n";
145 PORT = 110;
146 }
147 else if (!strncmp(SERVICE, "SMTP", 4)) {
148 EXPECT = "220";
149 QUIT = "QUIT\r\n";
150 PORT = 25;
151 } 131 }
152 else if (!strncmp(SERVICE, "IMAP", 4)) { 132
153 EXPECT = "* OK"; 133 /* determine defaults for this service's protocol */
154 QUIT = "a1 LOGOUT\r\n"; 134 if (!strncmp(config.service, "UDP", strlen("UDP"))) {
155 PORT = 143; 135 config.protocol = IPPROTO_UDP;
136 } else if (!strncmp(config.service, "FTP", strlen("FTP"))) {
137 config.server_expect[0] = "220";
138 config.quit = "QUIT\r\n";
139 config.server_port = DEFAULT_FTP_PORT;
140 } else if (!strncmp(config.service, "POP", strlen("POP")) || !strncmp(config.service, "POP3", strlen("POP3"))) {
141 config.server_expect[0] = "+OK";
142 config.quit = "QUIT\r\n";
143 config.server_port = DEFAULT_POP_PORT;
144 } else if (!strncmp(config.service, "SMTP", strlen("SMTP"))) {
145 config.server_expect[0] = "220";
146 config.quit = "QUIT\r\n";
147 config.server_port = DEFAULT_SMTP_PORT;
148 } else if (!strncmp(config.service, "IMAP", strlen("IMAP"))) {
149 config.server_expect[0] = "* OK";
150 config.quit = "a1 LOGOUT\r\n";
151 config.server_port = DEFAULT_IMAP_PORT;
156 } 152 }
157#ifdef HAVE_SSL 153#ifdef HAVE_SSL
158 else if (!strncmp(SERVICE, "SIMAP", 5)) { 154 else if (!strncmp(config.service, "SIMAP", strlen("SIMAP"))) {
159 EXPECT = "* OK"; 155 config.server_expect[0] = "* OK";
160 QUIT = "a1 LOGOUT\r\n"; 156 config.quit = "a1 LOGOUT\r\n";
161 flags |= FLAG_SSL; 157 config.use_tls = true;
162 PORT = 993; 158 config.server_port = DEFAULT_SIMAP_PORT;
163 } 159 } else if (!strncmp(config.service, "SPOP", strlen("SPOP"))) {
164 else if (!strncmp(SERVICE, "SPOP", 4)) { 160 config.server_expect[0] = "+OK";
165 EXPECT = "+OK"; 161 config.quit = "QUIT\r\n";
166 QUIT = "QUIT\r\n"; 162 config.use_tls = true;
167 flags |= FLAG_SSL; 163 config.server_port = DEFAULT_SPOP_PORT;
168 PORT = 995; 164 } else if (!strncmp(config.service, "SSMTP", strlen("SSMTP"))) {
169 } 165 config.server_expect[0] = "220";
170 else if (!strncmp(SERVICE, "SSMTP", 5)) { 166 config.quit = "QUIT\r\n";
171 EXPECT = "220"; 167 config.use_tls = true;
172 QUIT = "QUIT\r\n"; 168 config.server_port = DEFAULT_SSMTP_PORT;
173 flags |= FLAG_SSL; 169 } else if (!strncmp(config.service, "JABBER", strlen("JABBER"))) {
174 PORT = 465; 170 config.send = "<stream:stream to=\'host\' xmlns=\'jabber:client\' xmlns:stream=\'http://etherx.jabber.org/streams\'>\n";
175 } 171 config.server_expect[0] = "<?xml version=\'1.0\'";
176 else if (!strncmp(SERVICE, "JABBER", 6)) { 172 config.quit = "</stream:stream>\n";
177 SEND = "<stream:stream to=\'host\' xmlns=\'jabber:client\' xmlns:stream=\'http://etherx.jabber.org/streams\'>\n"; 173 config.hide_output = true;
178 EXPECT = "<?xml version=\'1.0\'"; 174 config.server_port = DEFAULT_XMPP_C2S_PORT;
179 QUIT = "</stream:stream>\n"; 175 } else if (!strncmp(config.service, "NNTPS", strlen("NNTPS"))) {
180 flags |= FLAG_HIDE_OUTPUT; 176 config.server_expect_count = 2;
181 PORT = 5222; 177 config.server_expect[0] = "200";
182 } 178 config.server_expect[1] = "201";
183 else if (!strncmp (SERVICE, "NNTPS", 5)) { 179 config.quit = "QUIT\r\n";
184 server_expect_count = 2; 180 config.use_tls = true;
185 server_expect[0] = "200"; 181 config.server_port = DEFAULT_NNTPS_PORT;
186 server_expect[1] = "201";
187 QUIT = "QUIT\r\n";
188 flags |= FLAG_SSL;
189 PORT = 563;
190 } 182 }
191#endif 183#endif
192 else if (!strncmp (SERVICE, "NNTP", 4)) { 184 else if (!strncmp(config.service, "NNTP", strlen("NNTP"))) {
193 server_expect_count = 2; 185 config.server_expect_count = 2;
194 server_expect = malloc(sizeof(char *) * server_expect_count); 186 char **tmp = realloc(config.server_expect, config.server_expect_count * sizeof(char *));
195 server_expect[0] = strdup("200"); 187 if (tmp == NULL) {
196 server_expect[1] = strdup("201"); 188 free(config.server_expect);
197 QUIT = "QUIT\r\n"; 189 die(STATE_UNKNOWN, _("Allocation failed"));
198 PORT = 119; 190 }
199 } 191 config.server_expect = tmp;
200 else if (!strncmp(SERVICE, "CLAMD", 5)) { 192
201 SEND = "PING"; 193 config.server_expect[0] = strdup("200");
202 EXPECT = "PONG"; 194 config.server_expect[1] = strdup("201");
203 QUIT = NULL; 195 config.quit = "QUIT\r\n";
204 PORT = 3310; 196 config.server_port = DEFAULT_NNTP_PORT;
197 } else if (!strncmp(config.service, "CLAMD", strlen("CLAMD"))) {
198 config.send = "PING";
199 config.server_expect[0] = "PONG";
200 config.quit = NULL;
201 config.server_port = DEFAULT_CLAMD_PORT;
205 } 202 }
206 /* fallthrough check, so it's supposed to use reverse matching */ 203 /* fallthrough check, so it's supposed to use reverse matching */
207 else if (strcmp (SERVICE, "TCP")) 204 else if (strcmp(config.service, "TCP")) {
208 usage (_("CRITICAL - Generic check_tcp called with unknown service\n")); 205 usage(_("CRITICAL - Generic check_tcp called with unknown service\n"));
209 206 }
210 server_address = "127.0.0.1";
211 server_port = PORT;
212 server_send = SEND;
213 server_quit = QUIT;
214 status = NULL;
215 207
216 /* Parse extra opts if any */ 208 /* Parse extra opts if any */
217 argv=np_extra_opts (&argc, argv, progname); 209 argv = np_extra_opts(&argc, argv, progname);
210
211 check_tcp_config_wrapper paw = process_arguments(argc, argv, config);
212 if (paw.errorcode == ERROR) {
213 usage4(_("Could not parse arguments"));
214 }
218 215
219 if (process_arguments (argc, argv) == ERROR) 216 config = paw.config;
220 usage4 (_("Could not parse arguments"));
221 217
222 if(flags & FLAG_VERBOSE) { 218 if (verbosity > 0) {
223 printf("Using service %s\n", SERVICE); 219 printf("Using service %s\n", config.service);
224 printf("Port: %d\n", server_port); 220 printf("Port: %d\n", config.server_port);
225 printf("flags: 0x%x\n", (int)flags);
226 } 221 }
227 222
228 if(EXPECT && !server_expect_count) 223 if ((config.server_expect_count == 0) && config.server_expect[0]) {
229 server_expect_count++; 224 config.server_expect_count++;
225 }
230 226
231 if(PROTOCOL==IPPROTO_UDP && !(server_expect_count && server_send)){ 227 if (config.protocol == IPPROTO_UDP && !(config.server_expect_count && config.send)) {
232 usage(_("With UDP checks, a send/expect string must be specified.")); 228 usage(_("With UDP checks, a send/expect string must be specified."));
233 } 229 }
234 230
231 // Initialize check stuff before setting timers
232 mp_check overall = mp_check_init();
233 if (config.output_format_set) {
234 mp_set_format(config.output_format);
235 }
236
235 /* set up the timer */ 237 /* set up the timer */
236 signal (SIGALRM, socket_timeout_alarm_handler); 238 signal(SIGALRM, socket_timeout_alarm_handler);
237 alarm (socket_timeout); 239 alarm(socket_timeout);
238 240
239 /* try to connect to the host at the given port number */ 241 /* try to connect to the host at the given port number */
240 gettimeofday (&tv, NULL); 242 struct timeval start_time;
241 243 gettimeofday(&start_time, NULL);
242 result = np_net_connect (server_address, server_port, &sd, PROTOCOL); 244
243 if (result == STATE_CRITICAL) return econn_refuse_state; 245 int socket_descriptor = 0;
246 mp_subcheck inital_connect_result = mp_subcheck_init();
247
248 // Try initial connection
249 if (np_net_connect(config.server_address, config.server_port, &socket_descriptor, config.protocol) == STATE_CRITICAL) {
250 // Early exit here, we got connection refused
251 inital_connect_result = mp_set_subcheck_state(inital_connect_result, config.econn_refuse_state);
252 xasprintf(&inital_connect_result.output, "Connection to %s on port %i was REFUSED", config.server_address, config.server_port);
253 mp_add_subcheck_to_check(&overall, inital_connect_result);
254 mp_exit(overall);
255 } else {
256 inital_connect_result = mp_set_subcheck_state(inital_connect_result, STATE_OK);
257 xasprintf(&inital_connect_result.output, "Connection to %s on port %i was a SUCCESS", config.server_address, config.server_port);
258 mp_add_subcheck_to_check(&overall, inital_connect_result);
259 }
244 260
245#ifdef HAVE_SSL 261#ifdef HAVE_SSL
246 if (flags & FLAG_SSL){ 262 if (config.use_tls) {
247 result = np_net_ssl_init_with_hostname(sd, (sni_specified ? sni : NULL)); 263 mp_subcheck tls_connection_result = mp_subcheck_init();
248 if (result == STATE_OK && check_cert) { 264 mp_state_enum result = np_net_ssl_init_with_hostname(socket_descriptor, (config.sni_specified ? config.sni : NULL));
249 result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit); 265 tls_connection_result = mp_set_subcheck_default_state(tls_connection_result, result);
266
267 if (result == STATE_OK) {
268 xasprintf(&tls_connection_result.output, "TLS connection succeeded");
269
270 if (config.check_cert) {
271 result = np_net_ssl_check_cert(config.days_till_exp_warn, config.days_till_exp_crit);
272
273 mp_subcheck tls_certificate_lifetime_result = mp_subcheck_init();
274 tls_certificate_lifetime_result = mp_set_subcheck_state(tls_certificate_lifetime_result, result);
275
276 if (result == STATE_OK) {
277 xasprintf(&tls_certificate_lifetime_result.output, "Certificate lifetime is within thresholds");
278 } else if (result == STATE_WARNING) {
279 xasprintf(&tls_certificate_lifetime_result.output, "Certificate lifetime is violating warning threshold (%i)",
280 config.days_till_exp_warn);
281 } else if (result == STATE_CRITICAL) {
282 xasprintf(&tls_certificate_lifetime_result.output, "Certificate lifetime is violating critical threshold (%i)",
283 config.days_till_exp_crit);
284 } else {
285 xasprintf(&tls_certificate_lifetime_result.output, "Certificate lifetime is somehow unknown");
286 }
287
288 mp_add_subcheck_to_subcheck(&tls_connection_result, tls_certificate_lifetime_result);
289 }
290
291 mp_add_subcheck_to_check(&overall, tls_connection_result);
292 } else {
293 xasprintf(&tls_connection_result.output, "TLS connection failed");
294 mp_add_subcheck_to_check(&overall, tls_connection_result);
295
296 if (socket_descriptor) {
297 close(socket_descriptor);
298 }
299 np_net_ssl_cleanup();
300
301 mp_exit(overall);
250 } 302 }
251 } 303 }
252 if(result != STATE_OK){
253 if(sd) close(sd);
254 np_net_ssl_cleanup();
255 return result;
256 }
257#endif /* HAVE_SSL */ 304#endif /* HAVE_SSL */
258 305
259 if (server_send != NULL) { /* Something to send? */ 306 if (config.send != NULL) { /* Something to send? */
260 my_send(server_send, strlen(server_send)); 307 my_send(socket_descriptor, config.send, strlen(config.send), config.use_tls);
261 } 308 }
262 309
263 if (delay > 0) { 310 if (config.delay > 0) {
264 tv.tv_sec += delay; 311 start_time.tv_sec += config.delay;
265 sleep (delay); 312 sleep(config.delay);
266 } 313 }
267 314
268 if(flags & FLAG_VERBOSE) { 315 if (verbosity > 0) {
269 if (server_send) { 316 if (config.send) {
270 printf("Send string: %s\n", server_send); 317 printf("Send string: %s\n", config.send);
318 }
319 if (config.quit) {
320 printf("Quit string: %s\n", config.quit);
271 } 321 }
272 if (server_quit) { 322 printf("server_expect_count: %d\n", (int)config.server_expect_count);
273 printf("Quit string: %s\n", server_quit); 323 for (size_t i = 0; i < config.server_expect_count; i++) {
324 printf("\t%zd: %s\n", i, config.server_expect[i]);
274 } 325 }
275 printf("server_expect_count: %d\n", (int)server_expect_count);
276 for(size_t i = 0; i < server_expect_count; i++)
277 printf("\t%zd: %s\n", i, server_expect[i]);
278 } 326 }
279 327
280 /* if(len) later on, we know we have a non-NULL response */ 328 /* if(len) later on, we know we have a non-NULL response */
281 ssize_t len = 0; 329 ssize_t len = 0;
330 char *received_buffer = NULL;
331 enum np_match_result match = NP_MATCH_NONE;
332 mp_subcheck expected_data_result = mp_subcheck_init();
282 333
283 if (server_expect_count) { 334 if (config.server_expect_count) {
284 ssize_t received = 0; 335 ssize_t received = 0;
336 char buffer[MAXBUF];
285 337
286 /* watch for the expect string */ 338 /* watch for the expect string */
287 while ((received = my_recv(buffer, sizeof(buffer))) > 0) { 339 while ((received = my_recv(socket_descriptor, buffer, sizeof(buffer), config.use_tls)) > 0) {
288 status = realloc(status, len + received + 1); 340 received_buffer = realloc(received_buffer, len + received + 1);
289 memcpy(&status[len], buffer, received); 341
342 if (received_buffer == NULL) {
343 die(STATE_UNKNOWN, _("Allocation failed"));
344 }
345
346 memcpy(&received_buffer[len], buffer, received);
290 len += received; 347 len += received;
291 status[len] = '\0'; 348 received_buffer[len] = '\0';
292 349
293 /* stop reading if user-forced */ 350 /* stop reading if user-forced */
294 if (maxbytes && len >= maxbytes) 351 if (config.maxbytes && len >= config.maxbytes) {
295 break; 352 break;
353 }
296 354
297 if ((match = np_expect_match(status, 355 if ((match = np_expect_match(received_buffer, config.server_expect, config.server_expect_count, config.match_flags)) !=
298 server_expect, 356 NP_MATCH_RETRY) {
299 server_expect_count,
300 match_flags)) != NP_MATCH_RETRY)
301 break; 357 break;
358 }
359
360 fd_set rfds;
361 FD_ZERO(&rfds);
362 FD_SET(socket_descriptor, &rfds);
302 363
303 /* some protocols wait for further input, so make sure we don't wait forever */ 364 /* some protocols wait for further input, so make sure we don't wait forever */
304 FD_SET(sd, &rfds); 365 struct timeval timeout;
305 timeout.tv_sec = READ_TIMEOUT; 366 timeout.tv_sec = READ_TIMEOUT;
306 timeout.tv_usec = 0; 367 timeout.tv_usec = 0;
307 if(select(sd + 1, &rfds, NULL, NULL, &timeout) <= 0) 368
369 if (select(socket_descriptor + 1, &rfds, NULL, NULL, &timeout) <= 0) {
308 break; 370 break;
371 }
309 } 372 }
310 373
311 if (match == NP_MATCH_RETRY) 374 if (match == NP_MATCH_RETRY) {
312 match = NP_MATCH_FAILURE; 375 match = NP_MATCH_FAILURE;
376 }
313 377
314 /* no data when expected, so return critical */ 378 /* no data when expected, so return critical */
315 if (len == 0) 379 if (len == 0) {
316 die (STATE_CRITICAL, _("No data received from host\n")); 380 xasprintf(&expected_data_result.output, "Received no data when some was expected");
381 expected_data_result = mp_set_subcheck_state(expected_data_result, STATE_CRITICAL);
382 mp_add_subcheck_to_check(&overall, expected_data_result);
383 mp_exit(overall);
384 }
317 385
318 /* print raw output if we're debugging */ 386 /* print raw output if we're debugging */
319 if(flags & FLAG_VERBOSE) 387 if (verbosity > 0) {
320 printf("received %d bytes from host\n#-raw-recv-------#\n%s\n#-raw-recv-------#\n", 388 printf("received %d bytes from host\n#-raw-recv-------#\n%s\n#-raw-recv-------#\n", (int)len + 1, received_buffer);
321 (int)len + 1, status); 389 }
322 /* strip whitespace from end of output */ 390 /* strip whitespace from end of output */
323 while(--len > 0 && isspace(status[len])) 391 while (--len > 0 && isspace(received_buffer[len])) {
324 status[len] = '\0'; 392 received_buffer[len] = '\0';
393 }
394 }
395
396 if (config.quit != NULL) {
397 my_send(socket_descriptor, config.quit, strlen(config.quit), config.use_tls);
325 } 398 }
326 399
327 if (server_quit != NULL) { 400 if (socket_descriptor) {
328 my_send(server_quit, strlen(server_quit)); 401 close(socket_descriptor);
329 } 402 }
330 if (sd) close (sd);
331#ifdef HAVE_SSL 403#ifdef HAVE_SSL
332 np_net_ssl_cleanup(); 404 np_net_ssl_cleanup();
333#endif 405#endif
334 406
335 microsec = deltime (tv); 407 long microsec = deltime(start_time);
336 elapsed_time = (double)microsec / 1.0e6; 408 double elapsed_time = (double)microsec / 1.0e6;
337 409
338 if (flags & FLAG_TIME_CRIT && elapsed_time > critical_time) 410 mp_subcheck elapsed_time_result = mp_subcheck_init();
339 result = STATE_CRITICAL;
340 else if (flags & FLAG_TIME_WARN && elapsed_time > warning_time)
341 result = STATE_WARNING;
342 411
343 /* did we get the response we hoped? */ 412 mp_perfdata time_pd = perfdata_init();
344 if(match == NP_MATCH_FAILURE && result != STATE_CRITICAL) 413 time_pd = mp_set_pd_value(time_pd, elapsed_time);
345 result = expect_mismatch_state; 414 time_pd.label = "time";
415 time_pd.uom = "s";
346 416
347 /* reset the alarm */ 417 if (config.critical_time_set && elapsed_time > config.critical_time) {
348 alarm (0); 418 xasprintf(&elapsed_time_result.output, "Connection time %fs exceeded critical threshold (%f)", elapsed_time, config.critical_time);
349 419
350 /* this is a bit stupid, because we don't want to print the 420 elapsed_time_result = mp_set_subcheck_state(elapsed_time_result, STATE_CRITICAL);
351 * response time (which can look ok to the user) if we didn't get 421 time_pd.crit_present = true;
352 * the response we were looking for. if-else */ 422 mp_range crit_val = mp_range_init();
353 printf("%s %s - ", SERVICE, state_text(result)); 423
354 424 crit_val.end = mp_create_pd_value(config.critical_time);
355 if(match == NP_MATCH_FAILURE && len && !(flags & FLAG_HIDE_OUTPUT)) 425 crit_val.end_infinity = false;
356 printf("Unexpected response from host/socket: %s", status); 426
357 else { 427 time_pd.crit = crit_val;
358 if(match == NP_MATCH_FAILURE) 428 } else if (config.warning_time_set && elapsed_time > config.warning_time) {
359 printf("Unexpected response from host/socket on "); 429 xasprintf(&elapsed_time_result.output, "Connection time %fs exceeded warning threshold (%f)", elapsed_time, config.critical_time);
360 else 430
361 printf("%.3f second response time on ", elapsed_time); 431 elapsed_time_result = mp_set_subcheck_state(elapsed_time_result, STATE_WARNING);
362 if(server_address[0] != '/') { 432 time_pd.warn_present = true;
363 if (host_specified) 433 mp_range warn_val = mp_range_init();
364 printf("%s port %d", 434 warn_val.end = mp_create_pd_value(config.critical_time);
365 server_address, server_port); 435 warn_val.end_infinity = false;
366 else 436
367 printf("port %d", server_port); 437 time_pd.warn = warn_val;
368 } 438 } else {
369 else 439 elapsed_time_result = mp_set_subcheck_state(elapsed_time_result, STATE_OK);
370 printf("socket %s", server_address); 440 xasprintf(&elapsed_time_result.output, "Connection time %fs is within thresholds", elapsed_time);
371 } 441 }
372 442
373 if (match != NP_MATCH_FAILURE && !(flags & FLAG_HIDE_OUTPUT) && len) 443 mp_add_perfdata_to_subcheck(&elapsed_time_result, time_pd);
374 printf (" [%s]", status); 444 mp_add_subcheck_to_check(&overall, elapsed_time_result);
375
376 /* perf-data doesn't apply when server doesn't talk properly,
377 * so print all zeroes on warn and crit. Use fperfdata since
378 * localisation settings can make different outputs */
379 if(match == NP_MATCH_FAILURE)
380 printf ("|%s",
381 fperfdata ("time", elapsed_time, "s",
382 (flags & FLAG_TIME_WARN ? true : false), 0,
383 (flags & FLAG_TIME_CRIT ? true : false), 0,
384 true, 0,
385 true, socket_timeout)
386 );
387 else
388 printf("|%s",
389 fperfdata ("time", elapsed_time, "s",
390 (flags & FLAG_TIME_WARN ? true : false), warning_time,
391 (flags & FLAG_TIME_CRIT ? true : false), critical_time,
392 true, 0,
393 true, socket_timeout)
394 );
395
396 putchar('\n');
397 return result;
398}
399 445
446 /* did we get the response we hoped? */
447 if (match == NP_MATCH_FAILURE) {
448 expected_data_result = mp_set_subcheck_state(expected_data_result, config.expect_mismatch_state);
449 xasprintf(&expected_data_result.output, "Answer failed to match expectation");
450 mp_add_subcheck_to_check(&overall, expected_data_result);
451 } else if (match == NP_MATCH_SUCCESS) {
452 expected_data_result = mp_set_subcheck_state(expected_data_result, STATE_OK);
453 xasprintf(&expected_data_result.output, "The answer of the server matched the expectation");
454 mp_add_subcheck_to_check(&overall, expected_data_result);
455 }
400 456
457 /* reset the alarm */
458 alarm(0);
401 459
402/* process command-line arguments */ 460 mp_exit(overall);
403static int process_arguments (int argc, char **argv) { 461}
404 int c;
405 bool escape = false;
406 char *temp;
407 462
463/* process command-line arguments */
464static check_tcp_config_wrapper process_arguments(int argc, char **argv, check_tcp_config config) {
408 enum { 465 enum {
409 SNI_OPTION = CHAR_MAX + 1 466 SNI_OPTION = CHAR_MAX + 1,
467 output_format_index,
410 }; 468 };
411 469
412 int option = 0; 470 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
413 static struct option longopts[] = { 471 {"critical", required_argument, 0, 'c'},
414 {"hostname", required_argument, 0, 'H'}, 472 {"warning", required_argument, 0, 'w'},
415 {"critical", required_argument, 0, 'c'}, 473 {"critical-codes", required_argument, 0, 'C'},
416 {"warning", required_argument, 0, 'w'}, 474 {"warning-codes", required_argument, 0, 'W'},
417 {"critical-codes", required_argument, 0, 'C'}, 475 {"timeout", required_argument, 0, 't'},
418 {"warning-codes", required_argument, 0, 'W'}, 476 {"protocol", required_argument, 0, 'P'}, /* FIXME: Unhandled */
419 {"timeout", required_argument, 0, 't'}, 477 {"port", required_argument, 0, 'p'},
420 {"protocol", required_argument, 0, 'P'}, /* FIXME: Unhandled */ 478 {"escape", no_argument, 0, 'E'},
421 {"port", required_argument, 0, 'p'}, 479 {"all", no_argument, 0, 'A'},
422 {"escape", no_argument, 0, 'E'}, 480 {"send", required_argument, 0, 's'},
423 {"all", no_argument, 0, 'A'}, 481 {"expect", required_argument, 0, 'e'},
424 {"send", required_argument, 0, 's'}, 482 {"maxbytes", required_argument, 0, 'm'},
425 {"expect", required_argument, 0, 'e'}, 483 {"quit", required_argument, 0, 'q'},
426 {"maxbytes", required_argument, 0, 'm'}, 484 {"jail", no_argument, 0, 'j'},
427 {"quit", required_argument, 0, 'q'}, 485 {"delay", required_argument, 0, 'd'},
428 {"jail", no_argument, 0, 'j'}, 486 {"refuse", required_argument, 0, 'r'},
429 {"delay", required_argument, 0, 'd'}, 487 {"mismatch", required_argument, 0, 'M'},
430 {"refuse", required_argument, 0, 'r'}, 488 {"use-ipv4", no_argument, 0, '4'},
431 {"mismatch", required_argument, 0, 'M'}, 489 {"use-ipv6", no_argument, 0, '6'},
432 {"use-ipv4", no_argument, 0, '4'}, 490 {"verbose", no_argument, 0, 'v'},
433 {"use-ipv6", no_argument, 0, '6'}, 491 {"version", no_argument, 0, 'V'},
434 {"verbose", no_argument, 0, 'v'}, 492 {"help", no_argument, 0, 'h'},
435 {"version", no_argument, 0, 'V'}, 493 {"ssl", no_argument, 0, 'S'},
436 {"help", no_argument, 0, 'h'}, 494 {"sni", required_argument, 0, SNI_OPTION},
437 {"ssl", no_argument, 0, 'S'}, 495 {"certificate", required_argument, 0, 'D'},
438 {"sni", required_argument, 0, SNI_OPTION}, 496 {"output-format", required_argument, 0, output_format_index},
439 {"certificate", required_argument, 0, 'D'}, 497 {0, 0, 0, 0}};
440 {0, 0, 0, 0} 498
441 }; 499 if (argc < 2) {
442 500 usage4(_("No arguments found"));
443 if (argc < 2) 501 }
444 usage4 (_("No arguments found"));
445 502
446 /* backwards compatibility */ 503 /* backwards compatibility */
447 for (c = 1; c < argc; c++) { 504 for (int i = 1; i < argc; i++) {
448 if (strcmp ("-to", argv[c]) == 0) 505 if (strcmp("-to", argv[i]) == 0) {
449 strcpy (argv[c], "-t"); 506 strcpy(argv[i], "-t");
450 else if (strcmp ("-wt", argv[c]) == 0) 507 } else if (strcmp("-wt", argv[i]) == 0) {
451 strcpy (argv[c], "-w"); 508 strcpy(argv[i], "-w");
452 else if (strcmp ("-ct", argv[c]) == 0) 509 } else if (strcmp("-ct", argv[i]) == 0) {
453 strcpy (argv[c], "-c"); 510 strcpy(argv[i], "-c");
511 }
454 } 512 }
455 513
456 if (!is_option (argv[1])) { 514 if (!is_option(argv[1])) {
457 server_address = argv[1]; 515 config.server_address = argv[1];
458 argv[1] = argv[0]; 516 argv[1] = argv[0];
459 argv = &argv[1]; 517 argv = &argv[1];
460 argc--; 518 argc--;
461 } 519 }
462 520
463 while (1) { 521 bool escape = false;
464 c = getopt_long (argc, argv, "+hVv46EAH:s:e:q:m:c:w:t:p:C:W:d:Sr:jD:M:", 522
465 longopts, &option); 523 while (true) {
524 int option = 0;
525 int option_index = getopt_long(argc, argv, "+hVv46EAH:s:e:q:m:c:w:t:p:C:W:d:Sr:jD:M:", longopts, &option);
466 526
467 if (c == -1 || c == EOF || c == 1) 527 if (option_index == -1 || option_index == EOF || option_index == 1) {
468 break; 528 break;
529 }
469 530
470 switch (c) { 531 switch (option_index) {
471 case '?': /* print short usage statement if args not parsable */ 532 case '?': /* print short usage statement if args not parsable */
472 usage5 (); 533 usage5();
473 case 'h': /* help */ 534 case 'h': /* help */
474 print_help (); 535 print_help(config.service);
475 exit (STATE_UNKNOWN); 536 exit(STATE_UNKNOWN);
476 case 'V': /* version */ 537 case 'V': /* version */
477 print_revision (progname, NP_VERSION); 538 print_revision(progname, NP_VERSION);
478 exit (STATE_UNKNOWN); 539 exit(STATE_UNKNOWN);
479 case 'v': /* verbose mode */ 540 case 'v': /* verbose mode */
480 flags |= FLAG_VERBOSE; 541 verbosity++;
481 match_flags |= NP_MATCH_VERBOSE; 542 config.match_flags |= NP_MATCH_VERBOSE;
482 break; 543 break;
483 case '4': 544 case '4': // Apparently unused TODO
484 address_family = AF_INET; 545 address_family = AF_INET;
485 break; 546 break;
486 case '6': 547 case '6': // Apparently unused TODO
487#ifdef USE_IPV6 548#ifdef USE_IPV6
488 address_family = AF_INET6; 549 address_family = AF_INET6;
489#else 550#else
490 usage4 (_("IPv6 support not available")); 551 usage4(_("IPv6 support not available"));
491#endif 552#endif
492 break; 553 break;
493 case 'H': /* hostname */ 554 case 'H': /* hostname */
494 host_specified = true; 555 config.host_specified = true;
495 server_address = optarg; 556 config.server_address = optarg;
496 break;
497 case 'c': /* critical */
498 critical_time = strtod (optarg, NULL);
499 flags |= FLAG_TIME_CRIT;
500 break; 557 break;
501 case 'j': /* hide output */ 558 case 'c': /* critical */
502 flags |= FLAG_HIDE_OUTPUT; 559 config.critical_time = strtod(optarg, NULL);
560 config.critical_time_set = true;
503 break; 561 break;
504 case 'w': /* warning */ 562 case 'j': /* hide output */
505 warning_time = strtod (optarg, NULL); 563 config.hide_output = true;
506 flags |= FLAG_TIME_WARN;
507 break; 564 break;
508 case 'C': 565 case 'w': /* warning */
509 crit_codes = realloc (crit_codes, ++crit_codes_count); 566 config.warning_time = strtod(optarg, NULL);
510 crit_codes[crit_codes_count - 1] = optarg; 567 config.warning_time_set = true;
511 break; 568 break;
512 case 'W': 569 case 't': /* timeout */
513 warn_codes = realloc (warn_codes, ++warn_codes_count); 570 if (!is_intpos(optarg)) {
514 warn_codes[warn_codes_count - 1] = optarg; 571 usage4(_("Timeout interval must be a positive integer"));
515 break; 572 } else {
516 case 't': /* timeout */ 573 socket_timeout = atoi(optarg);
517 if (!is_intpos (optarg)) 574 }
518 usage4 (_("Timeout interval must be a positive integer"));
519 else
520 socket_timeout = atoi (optarg);
521 break; 575 break;
522 case 'p': /* port */ 576 case 'p': /* port */
523 if (!is_intpos (optarg)) 577 if (!is_intpos(optarg)) {
524 usage4 (_("Port must be a positive integer")); 578 usage4(_("Port must be a positive integer"));
525 else 579 } else {
526 server_port = atoi (optarg); 580 config.server_port = atoi(optarg);
581 }
527 break; 582 break;
528 case 'E': 583 case 'E':
529 escape = true; 584 escape = true;
530 break; 585 break;
531 case 's': 586 case 's':
532 if (escape) 587 if (escape) {
533 server_send = np_escaped_string(optarg); 588 config.send = np_escaped_string(optarg);
534 else 589 } else {
535 xasprintf(&server_send, "%s", optarg); 590 xasprintf(&config.send, "%s", optarg);
591 }
536 break; 592 break;
537 case 'e': /* expect string (may be repeated) */ 593 case 'e': /* expect string (may be repeated) */
538 match_flags &= ~NP_MATCH_EXACT; 594 config.match_flags &= ~NP_MATCH_EXACT;
539 if (server_expect_count == 0) 595 if (config.server_expect_count == 0) {
540 server_expect = malloc (sizeof (char *) * (++server_expect_count)); 596 config.server_expect = malloc(sizeof(char *) * (++config.server_expect_count));
541 else 597 } else {
542 server_expect = realloc (server_expect, sizeof (char *) * (++server_expect_count)); 598 config.server_expect = realloc(config.server_expect, sizeof(char *) * (++config.server_expect_count));
543 server_expect[server_expect_count - 1] = optarg; 599 }
600
601 if (config.server_expect == NULL) {
602 die(STATE_UNKNOWN, _("Allocation failed"));
603 }
604 config.server_expect[config.server_expect_count - 1] = optarg;
544 break; 605 break;
545 case 'm': 606 case 'm':
546 if (!is_intpos (optarg)) 607 if (!is_intpos(optarg)) {
547 usage4 (_("Maxbytes must be a positive integer")); 608 usage4(_("Maxbytes must be a positive integer"));
548 else 609 } else {
549 maxbytes = strtol (optarg, NULL, 0); 610 config.maxbytes = strtol(optarg, NULL, 0);
611 }
550 break; 612 break;
551 case 'q': 613 case 'q':
552 if (escape) 614 if (escape) {
553 server_quit = np_escaped_string(optarg); 615 config.quit = np_escaped_string(optarg);
554 else 616 } else {
555 xasprintf(&server_quit, "%s\r\n", optarg); 617 xasprintf(&config.quit, "%s\r\n", optarg);
618 }
556 break; 619 break;
557 case 'r': 620 case 'r':
558 if (!strncmp(optarg,"ok",2)) 621 if (!strncmp(optarg, "ok", 2)) {
559 econn_refuse_state = STATE_OK; 622 config.econn_refuse_state = STATE_OK;
560 else if (!strncmp(optarg,"warn",4)) 623 } else if (!strncmp(optarg, "warn", 4)) {
561 econn_refuse_state = STATE_WARNING; 624 config.econn_refuse_state = STATE_WARNING;
562 else if (!strncmp(optarg,"crit",4)) 625 } else if (!strncmp(optarg, "crit", 4)) {
563 econn_refuse_state = STATE_CRITICAL; 626 config.econn_refuse_state = STATE_CRITICAL;
564 else 627 } else {
565 usage4 (_("Refuse must be one of ok, warn, crit")); 628 usage4(_("Refuse must be one of ok, warn, crit"));
629 }
566 break; 630 break;
567 case 'M': 631 case 'M':
568 if (!strncmp(optarg,"ok",2)) 632 if (!strncmp(optarg, "ok", 2)) {
569 expect_mismatch_state = STATE_OK; 633 config.expect_mismatch_state = STATE_OK;
570 else if (!strncmp(optarg,"warn",4)) 634 } else if (!strncmp(optarg, "warn", 4)) {
571 expect_mismatch_state = STATE_WARNING; 635 config.expect_mismatch_state = STATE_WARNING;
572 else if (!strncmp(optarg,"crit",4)) 636 } else if (!strncmp(optarg, "crit", 4)) {
573 expect_mismatch_state = STATE_CRITICAL; 637 config.expect_mismatch_state = STATE_CRITICAL;
574 else 638 } else {
575 usage4 (_("Mismatch must be one of ok, warn, crit")); 639 usage4(_("Mismatch must be one of ok, warn, crit"));
640 }
576 break; 641 break;
577 case 'd': 642 case 'd':
578 if (is_intpos (optarg)) 643 if (is_intpos(optarg)) {
579 delay = atoi (optarg); 644 config.delay = atoi(optarg);
580 else 645 } else {
581 usage4 (_("Delay must be a positive integer")); 646 usage4(_("Delay must be a positive integer"));
647 }
582 break; 648 break;
583 case 'D': /* Check SSL cert validity - days 'til certificate expiration */ 649 case 'D': /* Check SSL cert validity - days 'til certificate expiration */
584#ifdef HAVE_SSL 650#ifdef HAVE_SSL
585# ifdef USE_OPENSSL /* XXX */ 651# ifdef USE_OPENSSL /* XXX */
586 if ((temp=strchr(optarg,','))!=NULL) { 652 {
587 *temp='\0'; 653 char *temp;
588 if (!is_intnonneg (optarg)) 654 if ((temp = strchr(optarg, ',')) != NULL) {
589 usage2 (_("Invalid certificate expiration period"), optarg); 655 *temp = '\0';
590 days_till_exp_warn = atoi (optarg); 656 if (!is_intnonneg(optarg)) {
591 *temp=','; 657 usage2(_("Invalid certificate expiration period"), optarg);
592 temp++; 658 }
593 if (!is_intnonneg (temp)) 659 config.days_till_exp_warn = atoi(optarg);
594 usage2 (_("Invalid certificate expiration period"), temp); 660 *temp = ',';
595 days_till_exp_crit = atoi (temp); 661 temp++;
596 } 662 if (!is_intnonneg(temp)) {
597 else { 663 usage2(_("Invalid certificate expiration period"), temp);
598 days_till_exp_crit=0; 664 }
599 if (!is_intnonneg (optarg)) 665 config.days_till_exp_crit = atoi(temp);
600 usage2 (_("Invalid certificate expiration period"), optarg); 666 } else {
601 days_till_exp_warn = atoi (optarg); 667 config.days_till_exp_crit = 0;
668 if (!is_intnonneg(optarg)) {
669 usage2(_("Invalid certificate expiration period"), optarg);
670 }
671 config.days_till_exp_warn = atoi(optarg);
602 } 672 }
603 check_cert = true; 673 config.check_cert = true;
604 flags |= FLAG_SSL; 674 config.use_tls = true;
605 break; 675 } break;
606# endif /* USE_OPENSSL */ 676# endif /* USE_OPENSSL */
607#endif 677#endif
608 /* fallthrough if we don't have ssl */ 678 /* fallthrough if we don't have ssl */
609 case 'S': 679 case 'S':
610#ifdef HAVE_SSL 680#ifdef HAVE_SSL
611 flags |= FLAG_SSL; 681 config.use_tls = true;
612#else 682#else
613 die (STATE_UNKNOWN, _("Invalid option - SSL is not available")); 683 die(STATE_UNKNOWN, _("Invalid option - SSL is not available"));
614#endif 684#endif
615 break; 685 break;
616 case SNI_OPTION: 686 case SNI_OPTION:
617#ifdef HAVE_SSL 687#ifdef HAVE_SSL
618 flags |= FLAG_SSL; 688 config.use_tls = true;
619 sni_specified = true; 689 config.sni_specified = true;
620 sni = optarg; 690 config.sni = optarg;
621#else 691#else
622 die (STATE_UNKNOWN, _("Invalid option - SSL is not available")); 692 die(STATE_UNKNOWN, _("Invalid option - SSL is not available"));
623#endif 693#endif
624 break; 694 break;
625 case 'A': 695 case 'A':
626 match_flags |= NP_MATCH_ALL; 696 config.match_flags |= NP_MATCH_ALL;
627 break; 697 break;
698 case output_format_index: {
699 parsed_output_format parser = mp_parse_output_format(optarg);
700 if (!parser.parsing_success) {
701 // TODO List all available formats here, maybe add anothoer usage function
702 printf("Invalid output format: %s\n", optarg);
703 exit(STATE_UNKNOWN);
704 }
705
706 config.output_format_set = true;
707 config.output_format = parser.output_format;
708 break;
709 }
628 } 710 }
629 } 711 }
630 712
631 c = optind; 713 int index = optind;
632 if(!host_specified && c < argc) 714 if (!config.host_specified && index < argc) {
633 server_address = strdup (argv[c++]); 715 config.server_address = strdup(argv[index++]);
716 }
634 717
635 if (server_address == NULL) 718 if (config.server_address == NULL) {
636 usage4 (_("You must provide a server address")); 719 usage4(_("You must provide a server address"));
637 else if (server_address[0] != '/' && !is_host(server_address)) 720 } else if (config.server_address[0] != '/' && !is_host(config.server_address)) {
638 die (STATE_CRITICAL, "%s %s - %s: %s\n", SERVICE, state_text(STATE_CRITICAL), _("Invalid hostname, address or socket"), server_address); 721 die(STATE_CRITICAL, "%s %s - %s: %s\n", config.service, state_text(STATE_CRITICAL), _("Invalid hostname, address or socket"),
722 config.server_address);
723 }
639 724
640 return OK; 725 check_tcp_config_wrapper result = {
726 .config = config,
727 .errorcode = OK,
728 };
729 return result;
641} 730}
642 731
643 732void print_help(const char *service) {
644void 733 print_revision(progname, NP_VERSION);
645print_help (void) 734
646{ 735 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
647 print_revision (progname, NP_VERSION); 736 printf(COPYRIGHT, copyright, email);
648 737
649 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 738 printf(_("This plugin tests %s connections with the specified host (or unix socket).\n\n"), service);
650 printf (COPYRIGHT, copyright, email); 739
651 740 print_usage();
652 printf (_("This plugin tests %s connections with the specified host (or unix socket).\n\n"), 741
653 SERVICE); 742 printf(UT_HELP_VRSN);
654 743 printf(UT_EXTRA_OPTS);
655 print_usage (); 744
656 745 printf(UT_HOST_PORT, 'p', "none");
657 printf (UT_HELP_VRSN); 746
658 printf (UT_EXTRA_OPTS); 747 printf(UT_IPv46);
659 748
660 printf (UT_HOST_PORT, 'p', "none"); 749 printf(" %s\n", "-E, --escape");
661 750 printf(" %s\n", _("Can use \\n, \\r, \\t or \\\\ in send or quit string. Must come before send or quit option"));
662 printf (UT_IPv46); 751 printf(" %s\n", _("Default: nothing added to send, \\r\\n added to end of quit"));
663 752 printf(" %s\n", "-s, --send=STRING");
664 printf (" %s\n", "-E, --escape"); 753 printf(" %s\n", _("String to send to the server"));
665 printf (" %s\n", _("Can use \\n, \\r, \\t or \\\\ in send or quit string. Must come before send or quit option")); 754 printf(" %s\n", "-e, --expect=STRING");
666 printf (" %s\n", _("Default: nothing added to send, \\r\\n added to end of quit")); 755 printf(" %s %s\n", _("String to expect in server response"), _("(may be repeated)"));
667 printf (" %s\n", "-s, --send=STRING"); 756 printf(" %s\n", "-A, --all");
668 printf (" %s\n", _("String to send to the server")); 757 printf(" %s\n", _("All expect strings need to occur in server response. Default is any"));
669 printf (" %s\n", "-e, --expect=STRING"); 758 printf(" %s\n", "-q, --quit=STRING");
670 printf (" %s %s\n", _("String to expect in server response"), _("(may be repeated)")); 759 printf(" %s\n", _("String to send server to initiate a clean close of the connection"));
671 printf (" %s\n", "-A, --all"); 760 printf(" %s\n", "-r, --refuse=ok|warn|crit");
672 printf (" %s\n", _("All expect strings need to occur in server response. Default is any")); 761 printf(" %s\n", _("Accept TCP refusals with states ok, warn, crit (default: crit)"));
673 printf (" %s\n", "-q, --quit=STRING"); 762 printf(" %s\n", "-M, --mismatch=ok|warn|crit");
674 printf (" %s\n", _("String to send server to initiate a clean close of the connection")); 763 printf(" %s\n", _("Accept expected string mismatches with states ok, warn, crit (default: warn)"));
675 printf (" %s\n", "-r, --refuse=ok|warn|crit"); 764 printf(" %s\n", "-j, --jail");
676 printf (" %s\n", _("Accept TCP refusals with states ok, warn, crit (default: crit)")); 765 printf(" %s\n", _("Hide output from TCP socket"));
677 printf (" %s\n", "-M, --mismatch=ok|warn|crit"); 766 printf(" %s\n", "-m, --maxbytes=INTEGER");
678 printf (" %s\n", _("Accept expected string mismatches with states ok, warn, crit (default: warn)")); 767 printf(" %s\n", _("Close connection once more than this number of bytes are received"));
679 printf (" %s\n", "-j, --jail"); 768 printf(" %s\n", "-d, --delay=INTEGER");
680 printf (" %s\n", _("Hide output from TCP socket")); 769 printf(" %s\n", _("Seconds to wait between sending string and polling for response"));
681 printf (" %s\n", "-m, --maxbytes=INTEGER");
682 printf (" %s\n", _("Close connection once more than this number of bytes are received"));
683 printf (" %s\n", "-d, --delay=INTEGER");
684 printf (" %s\n", _("Seconds to wait between sending string and polling for response"));
685 770
686#ifdef HAVE_SSL 771#ifdef HAVE_SSL
687 printf (" %s\n", "-D, --certificate=INTEGER[,INTEGER]"); 772 printf(" %s\n", "-D, --certificate=INTEGER[,INTEGER]");
688 printf (" %s\n", _("Minimum number of days a certificate has to be valid.")); 773 printf(" %s\n", _("Minimum number of days a certificate has to be valid."));
689 printf (" %s\n", _("1st is #days for warning, 2nd is critical (if not specified - 0).")); 774 printf(" %s\n", _("1st is #days for warning, 2nd is critical (if not specified - 0)."));
690 printf (" %s\n", "-S, --ssl"); 775 printf(" %s\n", "-S, --ssl");
691 printf (" %s\n", _("Use SSL for the connection.")); 776 printf(" %s\n", _("Use SSL for the connection."));
692 printf (" %s\n", "--sni=STRING"); 777 printf(" %s\n", "--sni=STRING");
693 printf (" %s\n", _("SSL server_name")); 778 printf(" %s\n", _("SSL server_name"));
694#endif 779#endif
695 780
696 printf (UT_WARN_CRIT); 781 printf(UT_WARN_CRIT);
697 782
698 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 783 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
699 784
700 printf (UT_VERBOSE); 785 printf(UT_OUTPUT_FORMAT);
786 printf(UT_VERBOSE);
701 787
702 printf (UT_SUPPORT); 788 printf(UT_SUPPORT);
703} 789}
704 790
705 791void print_usage(void) {
706void 792 printf("%s\n", _("Usage:"));
707print_usage (void) 793 printf("%s -H host -p port [-w <warning time>] [-c <critical time>] [-s <send string>]\n", progname);
708{ 794 printf("[-e <expect string>] [-q <quit string>][-m <maximum bytes>] [-d <delay>]\n");
709 printf ("%s\n", _("Usage:")); 795 printf("[-t <timeout seconds>] [-r <refuse state>] [-M <mismatch state>] [-v] [-4|-6] [-j]\n");
710 printf ("%s -H host -p port [-w <warning time>] [-c <critical time>] [-s <send string>]\n",progname); 796 printf("[-D <warn days cert expire>[,<crit days cert expire>]] [-S <use SSL>] [-E]\n");
711 printf ("[-e <expect string>] [-q <quit string>][-m <maximum bytes>] [-d <delay>]\n");
712 printf ("[-t <timeout seconds>] [-r <refuse state>] [-M <mismatch state>] [-v] [-4|-6] [-j]\n");
713 printf ("[-D <warn days cert expire>[,<crit days cert expire>]] [-S <use SSL>] [-E]\n");
714} 797}