Merge pull request #2085 from RincewindsHat/refactor/check_curl

Refactor/check curl and introduce new output formatting
This commit is contained in:
Lorenz Kästle 2025-09-15 10:13:33 +02:00 committed by GitHub
commit a3cf9041af
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 2981 additions and 2065 deletions

View file

@ -28,7 +28,7 @@ typedef struct {
/*
* New range type with generic numerical values
*/
typedef struct mp_range_struct {
typedef struct {
mp_perfdata_value start;
bool start_infinity; /* false (default) or true */
@ -41,7 +41,7 @@ typedef struct mp_range_struct {
/*
* Old range type with floating point values
*/
typedef struct range_struct {
typedef struct {
double start;
bool start_infinity;
double end;
@ -53,7 +53,7 @@ typedef struct range_struct {
/*
* Perfdata type for storing perfdata output
*/
typedef struct perfdata_struct {
typedef struct {
char *label;
char *uom;
mp_perfdata_value value;
@ -131,15 +131,15 @@ mp_range_parsed mp_parse_range_string(const char * /*input*/);
*/
void pd_list_append(pd_list[1], mp_perfdata);
#define mp_set_pd_value(P, V) \
_Generic((V), \
float: mp_set_pd_value_float, \
double: mp_set_pd_value_double, \
int: mp_set_pd_value_int, \
unsigned int: mp_set_pd_value_u_int, \
long: mp_set_pd_value_long, \
unsigned long: mp_set_pd_value_u_long, \
long long: mp_set_pd_value_long_long, \
#define mp_set_pd_value(P, V) \
_Generic((V), \
float: mp_set_pd_value_float, \
double: mp_set_pd_value_double, \
int: mp_set_pd_value_int, \
unsigned int: mp_set_pd_value_u_int, \
long: mp_set_pd_value_long, \
unsigned long: mp_set_pd_value_u_long, \
long long: mp_set_pd_value_long_long, \
unsigned long long: mp_set_pd_value_u_long_long)(P, V)
mp_perfdata mp_set_pd_value_float(mp_perfdata, float);
@ -151,17 +151,17 @@ mp_perfdata mp_set_pd_value_u_long(mp_perfdata, unsigned long);
mp_perfdata mp_set_pd_value_long_long(mp_perfdata, long long);
mp_perfdata mp_set_pd_value_u_long_long(mp_perfdata, unsigned long long);
#define mp_create_pd_value(V) \
_Generic((V), \
float: mp_create_pd_value_float, \
double: mp_create_pd_value_double, \
char: mp_create_pd_value_char, \
unsigned char: mp_create_pd_value_u_char, \
int: mp_create_pd_value_int, \
unsigned int: mp_create_pd_value_u_int, \
long: mp_create_pd_value_long, \
unsigned long: mp_create_pd_value_u_long, \
long long: mp_create_pd_value_long_long, \
#define mp_create_pd_value(V) \
_Generic((V), \
float: mp_create_pd_value_float, \
double: mp_create_pd_value_double, \
char: mp_create_pd_value_char, \
unsigned char: mp_create_pd_value_u_char, \
int: mp_create_pd_value_int, \
unsigned int: mp_create_pd_value_u_int, \
long: mp_create_pd_value_long, \
unsigned long: mp_create_pd_value_u_long, \
long long: mp_create_pd_value_long_long, \
unsigned long long: mp_create_pd_value_u_long_long)(V)
mp_perfdata_value mp_create_pd_value_float(float);

View file

@ -6,12 +6,12 @@
/*
* Old threshold type using the old range type
*/
typedef struct thresholds_struct {
typedef struct {
range *warning;
range *critical;
} thresholds;
typedef struct mp_thresholds_struct {
typedef struct {
bool warning_is_set;
mp_range warning;
bool critical_is_set;

View file

@ -25,6 +25,7 @@
*****************************************************************************/
#include "../plugins/common.h"
#include "states.h"
#include <stdarg.h>
#include "utils_base.h"
#include <ctype.h>
@ -253,7 +254,7 @@ bool check_range(double value, range *my_range) {
yes = false;
}
if (!my_range->end_infinity && !my_range->start_infinity) {
if (!my_range->end_infinity&& !my_range->start_infinity) {
if ((my_range->start <= value) && (value <= my_range->end)) {
return no;
}
@ -267,7 +268,7 @@ bool check_range(double value, range *my_range) {
return yes;
}
if (my_range->start_infinity && !my_range->end_infinity) {
if (my_range->start_infinity && !my_range->end_infinity ) {
if (value <= my_range->end) {
return no;
}
@ -277,7 +278,7 @@ bool check_range(double value, range *my_range) {
}
/* Returns status */
int get_status(double value, thresholds *my_thresholds) {
mp_state_enum get_status(double value, thresholds *my_thresholds) {
if (my_thresholds->critical != NULL) {
if (check_range(value, my_thresholds->critical)) {
return STATE_CRITICAL;
@ -393,7 +394,7 @@ char *np_extract_value(const char *varlist, const char *name, char sep) {
return value;
}
const char *state_text(int result) {
const char *state_text(mp_state_enum result) {
switch (result) {
case STATE_OK:
return "OK";

View file

@ -7,6 +7,7 @@
#include "./perfdata.h"
#include "./thresholds.h"
#include "states.h"
#ifndef USE_OPENSSL
# include "sha256.h"
@ -37,7 +38,7 @@ void set_thresholds(thresholds **, char *, char *);
void print_thresholds(const char *, thresholds *);
bool check_range(double, range *);
bool mp_check_range(mp_perfdata_value, mp_range);
int get_status(double, thresholds *);
mp_state_enum get_status(double, thresholds *);
/* Handle timeouts */
extern int timeout_state;
@ -85,6 +86,6 @@ int mp_translate_state(char *);
void np_init(char *, int argc, char **argv);
void np_set_args(int argc, char **argv);
void np_cleanup(void);
const char *state_text(int);
const char *state_text(mp_state_enum);
#endif /* _UTILS_BASE_ */

View file

@ -66,6 +66,7 @@ EXTRA_DIST = t \
check_hpjd.d \
check_game.d \
check_radius.d \
check_curl.d \
check_disk.d \
check_time.d \
check_users.d \
@ -92,6 +93,8 @@ EXTRA_DIST = t \
check_ntp_time.d \
check_dig.d \
check_cluster.d \
check_curl.d \
check_cluster.d \
check_ups.d \
check_fping.d
@ -132,6 +135,7 @@ check_cluster_LDADD = $(BASEOBJS)
check_curl_CFLAGS = $(AM_CFLAGS) $(LIBCURLCFLAGS) $(URIPARSERCFLAGS) $(LIBCURLINCLUDE) $(URIPARSERINCLUDE) -Ipicohttpparser
check_curl_CPPFLAGS = $(AM_CPPFLAGS) $(LIBCURLCFLAGS) $(URIPARSERCFLAGS) $(LIBCURLINCLUDE) $(URIPARSERINCLUDE) -Ipicohttpparser
check_curl_LDADD = $(NETLIBS) $(LIBCURLLIBS) $(SSLOBJS) $(URIPARSERLIBS) picohttpparser/libpicohttpparser.a
check_curl_SOURCES = check_curl.c check_curl.d/check_curl_helpers.c
check_dbi_LDADD = $(NETLIBS) $(DBILIBS)
check_dig_LDADD = $(NETLIBS)
check_disk_LDADD = $(BASEOBJS)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,124 @@
#include "./config.h"
#include <curl/curl.h>
#include "../picohttpparser/picohttpparser.h"
#include "output.h"
#if defined(HAVE_SSL) && defined(USE_OPENSSL)
# include <openssl/opensslv.h>
#endif
/* for buffers for header and body */
typedef struct {
size_t buflen;
size_t bufsize;
char *buf;
} curlhelp_write_curlbuf;
/* for buffering the data sent in PUT */
typedef struct {
size_t buflen;
off_t pos;
char *buf;
} curlhelp_read_curlbuf;
/* for parsing the HTTP status line */
typedef struct {
int http_major; /* major version of the protocol, always 1 (HTTP/0.9
* never reached the big internet most likely) */
int http_minor; /* minor version of the protocol, usually 0 or 1 */
int http_code; /* HTTP return code as in RFC 2145 */
int http_subcode; /* Microsoft IIS extension, HTTP subcodes, see
* http://support.microsoft.com/kb/318380/en-us */
const char *msg; /* the human readable message */
char *first_line; /* a copy of the first line */
} curlhelp_statusline;
typedef struct {
bool curl_global_initialized;
bool curl_easy_initialized;
bool body_buf_initialized;
curlhelp_write_curlbuf *body_buf;
bool header_buf_initialized;
curlhelp_write_curlbuf *header_buf;
bool status_line_initialized;
curlhelp_statusline *status_line;
bool put_buf_initialized;
curlhelp_read_curlbuf *put_buf;
CURL *curl;
struct curl_slist *header_list;
struct curl_slist *host;
} check_curl_global_state;
/* to know the underlying SSL library used by libcurl */
typedef enum curlhelp_ssl_library {
CURLHELP_SSL_LIBRARY_UNKNOWN,
CURLHELP_SSL_LIBRARY_OPENSSL,
CURLHELP_SSL_LIBRARY_LIBRESSL,
CURLHELP_SSL_LIBRARY_GNUTLS,
CURLHELP_SSL_LIBRARY_NSS
} curlhelp_ssl_library;
#define MAKE_LIBCURL_VERSION(major, minor, patch) ((major) * 0x10000 + (minor) * 0x100 + (patch))
typedef struct {
int errorcode;
check_curl_global_state curl_state;
check_curl_working_state working_state;
} check_curl_configure_curl_wrapper;
check_curl_configure_curl_wrapper check_curl_configure_curl(check_curl_static_curl_config config,
check_curl_working_state working_state,
bool check_cert,
bool on_redirect_dependent,
int follow_method, int max_depth);
void handle_curl_option_return_code(CURLcode res, const char *option);
int curlhelp_initwritebuffer(curlhelp_write_curlbuf **buf);
size_t curlhelp_buffer_write_callback(void * /*buffer*/, size_t /*size*/, size_t /*nmemb*/,
void * /*stream*/);
void curlhelp_freewritebuffer(curlhelp_write_curlbuf * /*buf*/);
int curlhelp_initreadbuffer(curlhelp_read_curlbuf **buf, const char * /*data*/, size_t /*datalen*/);
size_t curlhelp_buffer_read_callback(void * /*buffer*/, size_t /*size*/, size_t /*nmemb*/,
void * /*stream*/);
void curlhelp_freereadbuffer(curlhelp_read_curlbuf * /*buf*/);
curlhelp_ssl_library curlhelp_get_ssl_library(void);
const char *curlhelp_get_ssl_library_string(curlhelp_ssl_library /*ssl_library*/);
typedef union {
struct curl_slist *to_info;
struct curl_certinfo *to_certinfo;
} cert_ptr_union;
int net_noopenssl_check_certificate(cert_ptr_union *, int, int);
int curlhelp_parse_statusline(const char * /*buf*/, curlhelp_statusline * /*status_line*/);
void curlhelp_free_statusline(curlhelp_statusline * /*status_line*/);
char *get_header_value(const struct phr_header *headers, size_t nof_headers, const char *header);
mp_subcheck check_document_dates(const curlhelp_write_curlbuf * /*header_buf*/,
int /*maximum_age*/);
size_t get_content_length(const curlhelp_write_curlbuf *header_buf,
const curlhelp_write_curlbuf *body_buf);
int lookup_host(const char *host, char *buf, size_t buflen, sa_family_t addr_family);
CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm);
#define INET_ADDR_MAX_SIZE INET6_ADDRSTRLEN
const char *strrstr2(const char *haystack, const char *needle);
void cleanup(check_curl_global_state global_state);
bool expected_statuscode(const char *reply, const char *statuscodes);
char *string_statuscode(int major, int minor);
void test_file(char *path);
mp_subcheck check_curl_certificate_checks(CURL *curl, X509 *cert, int warn_days_till_exp,
int crit_days_till_exp);
char *fmt_url(check_curl_working_state workingState);

View file

@ -0,0 +1,116 @@
#pragma once
#include "../../config.h"
#include "../common.h"
#include "../../lib/states.h"
#include "../../lib/thresholds.h"
#include <stddef.h>
#include <string.h>
#include <sys/socket.h>
#include "curl/curl.h"
#include "perfdata.h"
#include "regex.h"
enum {
MAX_RE_SIZE = 1024,
HTTP_PORT = 80,
HTTPS_PORT = 443,
MAX_PORT = 65535,
DEFAULT_MAX_REDIRS = 15
};
enum {
FOLLOW_HTTP_CURL = 0,
FOLLOW_LIBCURL = 1
};
enum {
STICKY_NONE = 0,
STICKY_HOST = 1,
STICKY_PORT = 2
};
#define HTTP_EXPECT "HTTP/"
#define DEFAULT_BUFFER_SIZE 2048
#define DEFAULT_SERVER_URL "/"
typedef struct {
char *server_address;
char *server_url;
char *host_name;
char *http_method;
char *http_post_data;
unsigned short virtualPort;
unsigned short serverPort;
bool use_ssl;
bool no_body;
} check_curl_working_state;
check_curl_working_state check_curl_working_state_init();
typedef struct {
bool automatic_decompression;
bool haproxy_protocol;
long socket_timeout;
sa_family_t sin_family;
int curl_http_version;
char **http_opt_headers;
size_t http_opt_headers_count;
int ssl_version;
char *client_cert;
char *client_privkey;
char *ca_cert;
bool verify_peer_and_host;
char user_agent[DEFAULT_BUFFER_SIZE];
char proxy_auth[MAX_INPUT_BUFFER];
char user_auth[MAX_INPUT_BUFFER];
char *http_content_type;
char *cookie_jar_file;
} check_curl_static_curl_config;
typedef struct {
check_curl_working_state initial_config;
check_curl_static_curl_config curl_config;
int max_depth;
int followmethod;
int followsticky;
int maximum_age;
// the original regex string from the command line
char regexp[MAX_RE_SIZE];
// the compiled regex for usage later
regex_t compiled_regex;
mp_state_enum state_regex;
bool invert_regex;
bool check_cert;
bool continue_after_check_cert;
int days_till_exp_warn;
int days_till_exp_crit;
mp_thresholds thlds;
mp_range page_length_limits;
bool page_length_limits_is_set;
struct {
char string[MAX_INPUT_BUFFER];
bool is_present;
} server_expect;
char string_expect[MAX_INPUT_BUFFER];
char header_expect[MAX_INPUT_BUFFER];
mp_state_enum on_redirect_result_state;
bool on_redirect_dependent;
bool show_extended_perfdata;
bool show_body;
bool output_format_is_set;
mp_output_format output_format;
} check_curl_config;
check_curl_config check_curl_config_init();

View file

@ -1,63 +1,65 @@
/*****************************************************************************
*
* Monitoring Plugins net utilities include file
*
* License: GPL
* Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)
* Copyright (c) 2003-2007 Monitoring Plugins Development Team
*
* Description:
*
* This file contains common include files and function definitions
* used in many of the plugins.
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*****************************************************************************/
*
* Monitoring Plugins net utilities include file
*
* License: GPL
* Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)
* Copyright (c) 2003-2007 Monitoring Plugins Development Team
*
* Description:
*
* This file contains common include files and function definitions
* used in many of the plugins.
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*****************************************************************************/
#ifndef _NETUTILS_H_
#define _NETUTILS_H_
#include "common.h"
#include "output.h"
#include "states.h"
#include "utils.h"
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#ifdef HAVE_SYS_UN_H
# include <sys/un.h>
# ifndef UNIX_PATH_MAX
/* linux uses this, on sun it's hard-coded at 108 without a define, on BSD at 104 */
# define UNIX_PATH_MAX 104
# endif /* UNIX_PATH_MAX */
#endif /* HAVE_SYS_UN_H */
# include <sys/un.h>
# ifndef UNIX_PATH_MAX
/* linux uses this, on sun it's hard-coded at 108 without a define, on BSD at 104 */
# define UNIX_PATH_MAX 104
# endif /* UNIX_PATH_MAX */
#endif /* HAVE_SYS_UN_H */
#ifndef HOST_MAX_BYTES
# define HOST_MAX_BYTES 255
# define HOST_MAX_BYTES 255
#endif
/* process_request and wrapper macros */
#define process_tcp_request(addr, port, sbuf, rbuf, rsize) \
#define process_tcp_request(addr, port, sbuf, rbuf, rsize) \
process_request(addr, port, IPPROTO_TCP, sbuf, rbuf, rsize)
#define process_udp_request(addr, port, sbuf, rbuf, rsize) \
#define process_udp_request(addr, port, sbuf, rbuf, rsize) \
process_request(addr, port, IPPROTO_UDP, sbuf, rbuf, rsize)
int process_tcp_request2 (const char *address, int port,
const char *sbuffer, char *rbuffer, int rsize);
int process_request (const char *address, int port, int proto,
const char *sbuffer, char *rbuffer, int rsize);
int process_tcp_request2(const char *address, int port, const char *sbuffer, char *rbuffer,
int rsize);
int process_request(const char *address, int port, int proto, const char *sbuffer, char *rbuffer,
int rsize);
/* my_connect and wrapper macros */
#define my_tcp_connect(addr, port, s) np_net_connect(addr, port, s, IPPROTO_TCP)
@ -65,25 +67,22 @@ int process_request (const char *address, int port, int proto,
int np_net_connect(const char *address, int port, int *sd, int proto);
/* send_request and wrapper macros */
#define send_tcp_request(s, sbuf, rbuf, rsize) \
send_request(s, IPPROTO_TCP, sbuf, rbuf, rsize)
#define send_udp_request(s, sbuf, rbuf, rsize) \
send_request(s, IPPROTO_UDP, sbuf, rbuf, rsize)
int send_request (int sd, int proto, const char *send_buffer, char *recv_buffer, int recv_size);
#define send_tcp_request(s, sbuf, rbuf, rsize) send_request(s, IPPROTO_TCP, sbuf, rbuf, rsize)
#define send_udp_request(s, sbuf, rbuf, rsize) send_request(s, IPPROTO_UDP, sbuf, rbuf, rsize)
int send_request(int sd, int proto, const char *send_buffer, char *recv_buffer, int recv_size);
/* "is_*" wrapper macros and functions */
bool is_host (const char *);
bool is_addr (const char *);
int dns_lookup (const char *, struct sockaddr_storage *, int);
bool is_host(const char *);
bool is_addr(const char *);
int dns_lookup(const char *, struct sockaddr_storage *, int);
void host_or_die(const char *str);
#define resolve_host_or_addr(addr, family) dns_lookup(addr, NULL, family)
#define is_inet_addr(addr) resolve_host_or_addr(addr, AF_INET)
#define is_inet_addr(addr) resolve_host_or_addr(addr, AF_INET)
#ifdef USE_IPV6
# define is_inet6_addr(addr) resolve_host_or_addr(addr, AF_INET6)
# define is_hostname(addr) resolve_host_or_addr(addr, address_family)
# define is_inet6_addr(addr) resolve_host_or_addr(addr, AF_INET6)
# define is_hostname(addr) resolve_host_or_addr(addr, address_family)
#else
# define is_hostname(addr) resolve_host_or_addr(addr, AF_INET)
# define is_hostname(addr) resolve_host_or_addr(addr, AF_INET)
#endif
extern unsigned int socket_timeout;
@ -92,29 +91,30 @@ extern int econn_refuse_state;
extern bool was_refused;
extern int address_family;
void socket_timeout_alarm_handler (int) __attribute__((noreturn));
void socket_timeout_alarm_handler(int) __attribute__((noreturn));
/* SSL-Related functionality */
#ifdef HAVE_SSL
# define MP_SSLv2 1
# define MP_SSLv3 2
# define MP_TLSv1 3
# define MP_TLSv1_1 4
# define MP_TLSv1_2 5
# define MP_SSLv2_OR_NEWER 6
# define MP_SSLv3_OR_NEWER 7
# define MP_TLSv1_OR_NEWER 8
# define MP_TLSv1_1_OR_NEWER 9
# define MP_TLSv1_2_OR_NEWER 10
# define MP_SSLv2 1
# define MP_SSLv3 2
# define MP_TLSv1 3
# define MP_TLSv1_1 4
# define MP_TLSv1_2 5
# define MP_SSLv2_OR_NEWER 6
# define MP_SSLv3_OR_NEWER 7
# define MP_TLSv1_OR_NEWER 8
# define MP_TLSv1_1_OR_NEWER 9
# define MP_TLSv1_2_OR_NEWER 10
/* maybe this could be merged with the above np_net_connect, via some flags */
int np_net_ssl_init(int sd);
int np_net_ssl_init_with_hostname(int sd, char *host_name);
int np_net_ssl_init_with_hostname_and_version(int sd, char *host_name, int version);
int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int version, char *cert, char *privkey);
int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int version, char *cert,
char *privkey);
void np_net_ssl_cleanup();
int np_net_ssl_write(const void *buf, int num);
int np_net_ssl_read(void *buf, int num);
int np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit);
mp_state_enum np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit);
mp_subcheck mp_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit);
#endif /* HAVE_SSL */
#endif /* _NETUTILS_H_ */

View file

@ -26,10 +26,12 @@
*
*****************************************************************************/
#include "output.h"
#define MAX_CN_LENGTH 256
#include "common.h"
#include "netutils.h"
#include "../lib/monitoringplug.h"
#include "states.h"
#ifdef HAVE_SSL
static SSL_CTX *ctx = NULL;
@ -37,13 +39,16 @@ static SSL *s = NULL;
int np_net_ssl_init(int sd) { return np_net_ssl_init_with_hostname(sd, NULL); }
int np_net_ssl_init_with_hostname(int sd, char *host_name) { return np_net_ssl_init_with_hostname_and_version(sd, host_name, 0); }
int np_net_ssl_init_with_hostname(int sd, char *host_name) {
return np_net_ssl_init_with_hostname_and_version(sd, host_name, 0);
}
int np_net_ssl_init_with_hostname_and_version(int sd, char *host_name, int version) {
return np_net_ssl_init_with_hostname_version_and_cert(sd, host_name, version, NULL, NULL);
}
int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int version, char *cert, char *privkey) {
int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int version, char *cert,
char *privkey) {
long options = 0;
if ((ctx = SSL_CTX_new(TLS_client_method())) == NULL) {
@ -75,7 +80,8 @@ int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int
# endif
case MP_TLSv1_1: /* TLSv1.1 protocol */
# if !defined(SSL_OP_NO_TLSv1_1)
printf("%s\n", _("UNKNOWN - TLS protocol version 1.1 is not supported by your SSL library."));
printf("%s\n",
_("UNKNOWN - TLS protocol version 1.1 is not supported by your SSL library."));
return STATE_UNKNOWN;
# else
SSL_CTX_set_min_proto_version(ctx, TLS1_1_VERSION);
@ -84,7 +90,8 @@ int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int
# endif
case MP_TLSv1_2: /* TLSv1.2 protocol */
# if !defined(SSL_OP_NO_TLSv1_2)
printf("%s\n", _("UNKNOWN - TLS protocol version 1.2 is not supported by your SSL library."));
printf("%s\n",
_("UNKNOWN - TLS protocol version 1.2 is not supported by your SSL library."));
return STATE_UNKNOWN;
# else
SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
@ -145,8 +152,9 @@ int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int
SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
if ((s = SSL_new(ctx)) != NULL) {
# ifdef SSL_set_tlsext_host_name
if (host_name != NULL)
if (host_name != NULL) {
SSL_set_tlsext_host_name(s, host_name);
}
# endif
SSL_set_fd(s, sd);
if (SSL_connect(s) == 1) {
@ -182,63 +190,54 @@ int np_net_ssl_write(const void *buf, int num) { return SSL_write(s, buf, num);
int np_net_ssl_read(void *buf, int num) { return SSL_read(s, buf, num); }
int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int days_till_exp_crit) {
mp_state_enum np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn,
int days_till_exp_crit) {
# ifdef USE_OPENSSL
X509_NAME *subj = NULL;
char timestamp[50] = "";
char cn[MAX_CN_LENGTH] = "";
char *tz;
int cnlen = -1;
int status = STATE_UNKNOWN;
ASN1_STRING *tm;
int offset;
struct tm stamp;
float time_left;
int days_left;
int time_remaining;
time_t tm_t;
if (!certificate) {
printf("%s\n", _("CRITICAL - No server certificate present to inspect."));
return STATE_CRITICAL;
}
/* Extract CN from certificate subject */
subj = X509_get_subject_name(certificate);
X509_NAME *subj = X509_get_subject_name(certificate);
if (!subj) {
printf("%s\n", _("CRITICAL - Cannot retrieve certificate subject."));
return STATE_CRITICAL;
}
cnlen = X509_NAME_get_text_by_NID(subj, NID_commonName, cn, sizeof(cn));
if (cnlen == -1)
char cn[MAX_CN_LENGTH] = "";
int cnlen = X509_NAME_get_text_by_NID(subj, NID_commonName, cn, sizeof(cn));
if (cnlen == -1) {
strcpy(cn, _("Unknown CN"));
}
/* Retrieve timestamp of certificate */
tm = X509_get_notAfter(certificate);
ASN1_STRING *tm = X509_get_notAfter(certificate);
int offset = 0;
struct tm stamp = {};
/* Generate tm structure to process timestamp */
if (tm->type == V_ASN1_UTCTIME) {
if (tm->length < 10) {
printf("%s\n", _("CRITICAL - Wrong time format in certificate."));
return STATE_CRITICAL;
} else {
stamp.tm_year = (tm->data[0] - '0') * 10 + (tm->data[1] - '0');
if (stamp.tm_year < 50)
stamp.tm_year += 100;
offset = 0;
}
stamp.tm_year = (tm->data[0] - '0') * 10 + (tm->data[1] - '0');
if (stamp.tm_year < 50) {
stamp.tm_year += 100;
}
offset = 0;
} else {
if (tm->length < 12) {
printf("%s\n", _("CRITICAL - Wrong time format in certificate."));
return STATE_CRITICAL;
} else {
stamp.tm_year = (tm->data[0] - '0') * 1000 + (tm->data[1] - '0') * 100 + (tm->data[2] - '0') * 10 + (tm->data[3] - '0');
stamp.tm_year -= 1900;
offset = 2;
}
stamp.tm_year = (tm->data[0] - '0') * 1000 + (tm->data[1] - '0') * 100 +
(tm->data[2] - '0') * 10 + (tm->data[3] - '0');
stamp.tm_year -= 1900;
offset = 2;
}
stamp.tm_mon = (tm->data[2 + offset] - '0') * 10 + (tm->data[3 + offset] - '0') - 1;
stamp.tm_mday = (tm->data[4 + offset] - '0') * 10 + (tm->data[5 + offset] - '0');
@ -247,48 +246,60 @@ int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int
stamp.tm_sec = (tm->data[10 + offset] - '0') * 10 + (tm->data[11 + offset] - '0');
stamp.tm_isdst = -1;
tm_t = timegm(&stamp);
time_left = difftime(tm_t, time(NULL));
days_left = time_left / 86400;
tz = getenv("TZ");
time_t tm_t = timegm(&stamp);
float time_left = difftime(tm_t, time(NULL));
int days_left = time_left / 86400;
char *tz = getenv("TZ");
setenv("TZ", "GMT", 1);
tzset();
char timestamp[50] = "";
strftime(timestamp, 50, "%c %z", localtime(&tm_t));
if (tz)
if (tz) {
setenv("TZ", tz, 1);
else
} else {
unsetenv("TZ");
}
tzset();
int time_remaining;
mp_state_enum status = STATE_UNKNOWN;
if (days_left > 0 && days_left <= days_till_exp_warn) {
printf(_("%s - Certificate '%s' expires in %d day(s) (%s).\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", cn,
days_left, timestamp);
if (days_left > days_till_exp_crit)
printf(_("%s - Certificate '%s' expires in %d day(s) (%s).\n"),
(days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", cn, days_left, timestamp);
if (days_left > days_till_exp_crit) {
status = STATE_WARNING;
else
} else {
status = STATE_CRITICAL;
}
} else if (days_left == 0 && time_left > 0) {
if (time_left >= 3600)
if (time_left >= 3600) {
time_remaining = (int)time_left / 3600;
else
} else {
time_remaining = (int)time_left / 60;
}
printf(_("%s - Certificate '%s' expires in %u %s (%s)\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", cn,
time_remaining, time_left >= 3600 ? "hours" : "minutes", timestamp);
printf(_("%s - Certificate '%s' expires in %u %s (%s)\n"),
(days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", cn, time_remaining,
time_left >= 3600 ? "hours" : "minutes", timestamp);
if (days_left > days_till_exp_crit)
if (days_left > days_till_exp_crit) {
status = STATE_WARNING;
else
} else {
status = STATE_CRITICAL;
}
} else if (time_left < 0) {
printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), cn, timestamp);
status = STATE_CRITICAL;
} else if (days_left == 0) {
printf(_("%s - Certificate '%s' just expired (%s).\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", cn, timestamp);
if (days_left > days_till_exp_crit)
printf(_("%s - Certificate '%s' just expired (%s).\n"),
(days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", cn, timestamp);
if (days_left > days_till_exp_crit) {
status = STATE_WARNING;
else
} else {
status = STATE_CRITICAL;
}
} else {
printf(_("OK - Certificate '%s' will expire on %s.\n"), cn, timestamp);
status = STATE_OK;
@ -301,7 +312,7 @@ int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int
# endif /* USE_OPENSSL */
}
int np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit) {
mp_state_enum np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit) {
# ifdef USE_OPENSSL
X509 *certificate = NULL;
certificate = SSL_get_peer_certificate(s);
@ -312,4 +323,138 @@ int np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit) {
# endif /* USE_OPENSSL */
}
mp_subcheck mp_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn,
int days_till_exp_crit) {
mp_subcheck sc_cert = mp_subcheck_init();
# ifdef USE_OPENSSL
if (!certificate) {
xasprintf(&sc_cert.output, _("No server certificate present to inspect"));
sc_cert = mp_set_subcheck_state(sc_cert, STATE_CRITICAL);
return sc_cert;
}
/* Extract CN from certificate subject */
X509_NAME *subj = X509_get_subject_name(certificate);
if (!subj) {
xasprintf(&sc_cert.output, _("Cannot retrieve certificate subject"));
sc_cert = mp_set_subcheck_state(sc_cert, STATE_CRITICAL);
return sc_cert;
}
char commonName[MAX_CN_LENGTH] = "";
int cnlen = X509_NAME_get_text_by_NID(subj, NID_commonName, commonName, sizeof(commonName));
if (cnlen == -1) {
strcpy(commonName, _("Unknown CN"));
}
/* Retrieve timestamp of certificate */
ASN1_STRING *expiry_timestamp = X509_get_notAfter(certificate);
int offset = 0;
struct tm stamp = {};
/* Generate tm structure to process timestamp */
if (expiry_timestamp->type == V_ASN1_UTCTIME) {
if (expiry_timestamp->length < 10) {
xasprintf(&sc_cert.output, _("Wrong time format in certificate"));
sc_cert = mp_set_subcheck_state(sc_cert, STATE_CRITICAL);
return sc_cert;
}
stamp.tm_year = (expiry_timestamp->data[0] - '0') * 10 + (expiry_timestamp->data[1] - '0');
if (stamp.tm_year < 50) {
stamp.tm_year += 100;
}
offset = 0;
} else {
if (expiry_timestamp->length < 12) {
xasprintf(&sc_cert.output, _("Wrong time format in certificate"));
sc_cert = mp_set_subcheck_state(sc_cert, STATE_CRITICAL);
return sc_cert;
}
stamp.tm_year = (expiry_timestamp->data[0] - '0') * 1000 +
(expiry_timestamp->data[1] - '0') * 100 +
(expiry_timestamp->data[2] - '0') * 10 + (expiry_timestamp->data[3] - '0');
stamp.tm_year -= 1900;
offset = 2;
}
stamp.tm_mon = (expiry_timestamp->data[2 + offset] - '0') * 10 +
(expiry_timestamp->data[3 + offset] - '0') - 1;
stamp.tm_mday = (expiry_timestamp->data[4 + offset] - '0') * 10 +
(expiry_timestamp->data[5 + offset] - '0');
stamp.tm_hour = (expiry_timestamp->data[6 + offset] - '0') * 10 +
(expiry_timestamp->data[7 + offset] - '0');
stamp.tm_min = (expiry_timestamp->data[8 + offset] - '0') * 10 +
(expiry_timestamp->data[9 + offset] - '0');
stamp.tm_sec = (expiry_timestamp->data[10 + offset] - '0') * 10 +
(expiry_timestamp->data[11 + offset] - '0');
stamp.tm_isdst = -1;
time_t tm_t = timegm(&stamp);
double time_left = difftime(tm_t, time(NULL));
int days_left = (int)(time_left / 86400);
char *timeZone = getenv("TZ");
setenv("TZ", "GMT", 1);
tzset();
char timestamp[50] = "";
strftime(timestamp, 50, "%c %z", localtime(&tm_t));
if (timeZone) {
setenv("TZ", timeZone, 1);
} else {
unsetenv("TZ");
}
tzset();
int time_remaining;
if (days_left > 0 && days_left <= days_till_exp_warn) {
xasprintf(&sc_cert.output, _("Certificate '%s' expires in %d day(s) (%s)"), commonName,
days_left, timestamp);
if (days_left > days_till_exp_crit) {
sc_cert = mp_set_subcheck_state(sc_cert, STATE_WARNING);
} else {
sc_cert = mp_set_subcheck_state(sc_cert, STATE_CRITICAL);
}
} else if (days_left == 0 && time_left > 0) {
if (time_left >= 3600) {
time_remaining = (int)time_left / 3600;
} else {
time_remaining = (int)time_left / 60;
}
xasprintf(&sc_cert.output, _("Certificate '%s' expires in %u %s (%s)"), commonName,
time_remaining, time_left >= 3600 ? "hours" : "minutes", timestamp);
if (days_left > days_till_exp_crit) {
sc_cert = mp_set_subcheck_state(sc_cert, STATE_WARNING);
} else {
sc_cert = mp_set_subcheck_state(sc_cert, STATE_CRITICAL);
}
} else if (time_left < 0) {
xasprintf(&sc_cert.output, _("Certificate '%s' expired on %s"), commonName, timestamp);
sc_cert = mp_set_subcheck_state(sc_cert, STATE_CRITICAL);
} else if (days_left == 0) {
xasprintf(&sc_cert.output, _("Certificate '%s' just expired (%s)"), commonName,
timestamp);
if (days_left > days_till_exp_crit) {
sc_cert = mp_set_subcheck_state(sc_cert, STATE_WARNING);
} else {
sc_cert = mp_set_subcheck_state(sc_cert, STATE_CRITICAL);
}
} else {
xasprintf(&sc_cert.output, _("Certificate '%s' will expire on %s"), commonName,
timestamp);
sc_cert = mp_set_subcheck_state(sc_cert, STATE_OK);
}
X509_free(certificate);
return sc_cert;
# else /* ifndef USE_OPENSSL */
xasprintf(&sc_cert.output, _("Plugin does not support checking certificates"));
sc_cert = mp_set_subcheck_state(sc_cert, STATE_WARNING);
return sc_cert;
# endif /* USE_OPENSSL */
}
#endif /* HAVE_SSL */

View file

@ -13,12 +13,12 @@ use vars qw($tests $has_ipv6);
BEGIN {
use NPTest;
$has_ipv6 = NPTest::has_ipv6();
$tests = $has_ipv6 ? 59 : 57;
$tests = $has_ipv6 ? 55 : 53;
plan tests => $tests;
}
my $successOutput = '/OK.*HTTP.*second/';
my $successOutput = '/.*HTTP.*second/';
my $res;
my $plugin = 'check_http';
@ -63,7 +63,7 @@ $res = NPTest->testCmd(
);
cmp_ok( $res->return_code, '==', 2, "Webserver $host_nonresponsive not responding" );
# was CRITICAL only, but both check_curl and check_http print HTTP CRITICAL (puzzle?!)
like( $res->output, "/HTTP CRITICAL - Invalid HTTP response received from host on port 80: cURL returned 28 - Connection timed out after/", "Output OK");
like( $res->output, "/cURL returned 28 - Connection timed out after/", "Output OK");
$res = NPTest->testCmd(
"./$plugin $hostname_invalid -wt 1 -ct 2"
@ -124,14 +124,14 @@ SKIP: {
$res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'mONiTORing'" );
cmp_ok( $res->return_code, "==", 2, "Not got 'mONiTORing'");
like ( $res->output, "/pattern not found/", "Error message says 'pattern not found'");
like ( $res->output, "/matched not/", "Error message says 'matched not'");
$res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -R 'mONiTORing'" );
cmp_ok( $res->return_code, "==", 0, "But case insensitive doesn't mind 'mONiTORing'");
$res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'monitoring' --invert-regex" );
cmp_ok( $res->return_code, "==", 2, "Invert results work when found");
like ( $res->output, "/pattern found/", "Error message says 'pattern found'");
like ( $res->output, "/matched/", "Error message says 'matched'");
$res = NPTest->testCmd( "./$plugin -H $host_tcp_http2 -r 'mONiTORing' --invert-regex" );
cmp_ok( $res->return_code, "==", 0, "And also when not found");
@ -151,63 +151,74 @@ SKIP: {
$res = NPTest->testCmd( "./$plugin -C 8000,1 --ssl $host_tls_http" );
cmp_ok( $res->return_code, '==', 1, "Checking certificate for $host_tls_http");
like ( $res->output, qr/WARNING - Certificate '$host_tls_cert' expires in \d+ day/, "Output Warning" );
like ( $res->output, qr/Certificate '$host_tls_cert' expires in \d+ day/, "Output Warning" );
$res = NPTest->testCmd( "./$plugin $host_tls_http -C 1" );
is( $res->return_code, 0, "Old syntax for cert checking okay" );
is( $res->output, $saved_cert_output, "Same output as new syntax" );
# deactivated since different timings will change the output
# TODO compare without perfdata
# is( $res->output, $saved_cert_output, "Same output as new syntax" );
$res = NPTest->testCmd( "./$plugin -H $host_tls_http -C 1" );
is( $res->return_code, 0, "Updated syntax for cert checking okay" );
is( $res->output, $saved_cert_output, "Same output as new syntax" );
# deactivated since different timings will change the output
# TODO compare without perfdata
# is( $res->output, $saved_cert_output, "Same output as new syntax" );
$res = NPTest->testCmd( "./$plugin -C 1 $host_tls_http" );
cmp_ok( $res->output, 'eq', $saved_cert_output, "--ssl option automatically added");
# deactivated since different timings will change the output
# TODO compare without perfdata
# cmp_ok( $res->output, 'eq', $saved_cert_output, "--ssl option automatically added");
$res = NPTest->testCmd( "./$plugin $host_tls_http -C 1" );
cmp_ok( $res->output, 'eq', $saved_cert_output, "Old syntax for cert checking still works");
# deactivated since different timings will change the output
# TODO compare without perfdata
# cmp_ok( $res->output, 'eq', $saved_cert_output, "Old syntax for cert checking still works");
# run some certificate checks with faketime
SKIP: {
skip "No faketime binary found", 12 if !$faketime;
$res = NPTest->testCmd("LC_TIME=C TZ=UTC ./$plugin -C 1 $host_tls_http");
like($res->output, qr/OK - Certificate '$host_tls_cert' will expire on/, "Catch cert output");
like($res->output, qr/Certificate '$host_tls_cert' will expire on/, "Catch cert output");
is( $res->return_code, 0, "Catch cert output exit code" );
my($mon,$day,$hour,$min,$sec,$year) = ($res->output =~ /(\w+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+(\d+)/);
if(!defined $year) {
die("parsing date failed from: ".$res->output);
}
my $months = {'Jan' => 0, 'Feb' => 1, 'Mar' => 2, 'Apr' => 3, 'May' => 4, 'Jun' => 5, 'Jul' => 6, 'Aug' => 7, 'Sep' => 8, 'Oct' => 9, 'Nov' => 10, 'Dec' => 11};
my $ts = mktime($sec, $min, $hour, $day, $months->{$mon}, $year-1900);
my $time = strftime("%Y-%m-%d %H:%M:%S", localtime($ts));
$res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts))."' ./$plugin -C 1 $host_tls_http");
like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' just expired/, "Output on expire date");
like($res->output, qr/Certificate '$host_tls_cert' just expired/, "Output on expire date");
is( $res->return_code, 2, "Output on expire date" );
$res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-1))."' ./$plugin -C 1 $host_tls_http");
like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 0 minutes/, "cert expires in 1 second output");
like($res->output, qr/Certificate '$host_tls_cert' expires in 0 minutes/, "cert expires in 1 second output");
is( $res->return_code, 2, "cert expires in 1 second exit code" );
$res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-120))."' ./$plugin -C 1 $host_tls_http");
like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 2 minutes/, "cert expires in 2 minutes output");
like($res->output, qr/Certificate '$host_tls_cert' expires in 2 minutes/, "cert expires in 2 minutes output");
is( $res->return_code, 2, "cert expires in 2 minutes exit code" );
$res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts-7200))."' ./$plugin -C 1 $host_tls_http");
like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expires in 2 hours/, "cert expires in 2 hours output");
like($res->output, qr/Certificate '$host_tls_cert' expires in 2 hours/, "cert expires in 2 hours output");
is( $res->return_code, 2, "cert expires in 2 hours exit code" );
$res = NPTest->testCmd("LC_TIME=C TZ=UTC faketime -f '".strftime("%Y-%m-%d %H:%M:%S", localtime($ts+1))."' ./$plugin -C 1 $host_tls_http");
like($res->output, qr/CRITICAL - Certificate '$host_tls_cert' expired on/, "Certificate expired output");
like($res->output, qr/Certificate '$host_tls_cert' expired on/, "Certificate expired output");
is( $res->return_code, 2, "Certificate expired exit code" );
};
$res = NPTest->testCmd( "./$plugin --ssl $host_tls_http -E" );
like ( $res->output, '/time_connect=[\d\.]+/', 'Extended Performance Data Output OK' );
like ( $res->output, '/time_ssl=[\d\.]+/', 'Extended Performance Data SSL Output OK' );
like ( $res->output, '/\'time_connect\'=[\d\.]+/', 'Extended Performance Data Output OK' );
like ( $res->output, '/\'time_tls\'=[\d\.]+/', 'Extended Performance Data SSL Output OK' );
$res = NPTest->testCmd( "./$plugin -H monitoring-plugins.org -u /download.html -f follow" );
is( $res->return_code, 0, "Redirection based on location is okay");
$res = NPTest->testCmd( "./$plugin -H monitoring-plugins.org --extended-perfdata" );
like ( $res->output, '/time_connect=[\d\.]+/', 'Extended Performance Data Output OK' );
like ( $res->output, '/\'time_connect\'=[\d\.]+/', 'Extended Performance Data Output OK' );
}

View file

@ -15,6 +15,7 @@
# Email Address []:devel@monitoring-plugins.org
use strict;
use warnings;
use Test::More;
use NPTest;
use FindBin qw($Bin);
@ -245,21 +246,21 @@ SKIP: {
$result = NPTest->testCmd( "$command -p $port_https -S -C 14" );
is( $result->return_code, 0, "$command -p $port_https -S -C 14" );
is( $result->output, "OK - Certificate 'Monitoring Plugins' will expire on $expiry.", "output ok" );
like( $result->output, '/.*Certificate \'Monitoring Plugins\' will expire on ' . quotemeta($expiry) . '.*/', "output ok" );
$result = NPTest->testCmd( "$command -p $port_https -S -C 14000" );
is( $result->return_code, 1, "$command -p $port_https -S -C 14000" );
like( $result->output, '/WARNING - Certificate \'Monitoring Plugins\' expires in \d+ day\(s\) \(' . quotemeta($expiry) . '\)./', "output ok" );
like( $result->output, '/.*Certificate \'Monitoring Plugins\' expires in \d+ day\(s\) \(' . quotemeta($expiry) . '\).*/', "output ok" );
# Expired cert tests
$result = NPTest->testCmd( "$command -p $port_https -S -C 13960,14000" );
is( $result->return_code, 2, "$command -p $port_https -S -C 13960,14000" );
like( $result->output, '/CRITICAL - Certificate \'Monitoring Plugins\' expires in \d+ day\(s\) \(' . quotemeta($expiry) . '\)./', "output ok" );
like( $result->output, '/.*Certificate \'Monitoring Plugins\' expires in \d+ day\(s\) \(' . quotemeta($expiry) . '\).*/', "output ok" );
$result = NPTest->testCmd( "$command -p $port_https_expired -S -C 7" );
is( $result->return_code, 2, "$command -p $port_https_expired -S -C 7" );
is( $result->output,
'CRITICAL - Certificate \'Monitoring Plugins\' expired on Wed Jan 2 12:00:00 2008 +0000.',
like( $result->output,
'/.*Certificate \'Monitoring Plugins\' expired on Wed Jan\s+2 12:00:00 2008 \+0000.*/',
"output ok" );
}
@ -274,19 +275,19 @@ SKIP: {
$cmd = "./$plugin -H $virtual_host -I 127.0.0.1 -p $port_http -u /virtual_port -r ^$virtual_host:$port_http\$";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
# http with virtual port (!= 80)
$cmd = "./$plugin -H $virtual_host:$virtual_port -I 127.0.0.1 -p $port_http -u /virtual_port -r ^$virtual_host:$virtual_port\$";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
# http with virtual port (80)
$cmd = "./$plugin -H $virtual_host:80 -I 127.0.0.1 -p $port_http -u /virtual_port -r ^$virtual_host\$";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
}
# and the same for SSL
@ -296,19 +297,19 @@ SKIP: {
$cmd = "./$plugin -H $virtual_host -I 127.0.0.1 -p $port_https --ssl -u /virtual_port -r ^$virtual_host:$port_https\$";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
# https with virtual port (!= 443)
$cmd = "./$plugin -H $virtual_host:$virtual_port -I 127.0.0.1 -p $port_https --ssl -u /virtual_port -r ^$virtual_host:$virtual_port\$";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
# https with virtual port (443)
$cmd = "./$plugin -H $virtual_host:443 -I 127.0.0.1 -p $port_https --ssl -u /virtual_port -r ^$virtual_host\$";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
}
@ -321,165 +322,165 @@ sub run_common_tests {
$result = NPTest->testCmd( "$command -u /file/root" );
is( $result->return_code, 0, "/file/root");
like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 274 bytes in [\d\.]+ second/', "Output correct" );
like( $result->output, '/.*HTTP/1.1 200 OK - 274 bytes in [\d\.]+ second.*/', "Output correct" );
$result = NPTest->testCmd( "$command -u /file/root -s Root" );
is( $result->return_code, 0, "/file/root search for string");
like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 274 bytes in [\d\.]+ second/', "Output correct" );
like( $result->output, '/.*HTTP/1.1 200 OK - 274 bytes in [\d\.]+ second.*/', "Output correct" );
$result = NPTest->testCmd( "$command -u /file/root -s NonRoot" );
is( $result->return_code, 2, "Missing string check");
like( $result->output, qr%^HTTP CRITICAL: HTTP/1\.1 200 OK - string 'NonRoot' not found on 'https?://127\.0\.0\.1:\d+/file/root'%, "Shows search string and location");
like( $result->output, qr%string 'NonRoot' not found on 'https?://127\.0\.0\.1:\d+/file/root'%, "Shows search string and location");
$result = NPTest->testCmd( "$command -u /file/root -s NonRootWithOver30charsAndMoreFunThanAWetFish" );
is( $result->return_code, 2, "Missing string check");
like( $result->output, qr%HTTP CRITICAL: HTTP/1\.1 200 OK - string 'NonRootWithOver30charsAndM...' not found on 'https?://127\.0\.0\.1:\d+/file/root'%, "Shows search string and location");
like( $result->output, qr%string 'NonRootWithOver30charsAndM...' not found on 'https?://127\.0\.0\.1:\d+/file/root'%, "Shows search string and location");
$result = NPTest->testCmd( "$command -u /header_check -d foo" );
is( $result->return_code, 0, "header_check search for string");
like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 96 bytes in [\d\.]+ second/', "Output correct" );
like( $result->output, '/.*HTTP/1.1 200 OK - 96 bytes in [\d\.]+ second.*/', "Output correct" );
$result = NPTest->testCmd( "$command -u /header_check -d bar" );
is( $result->return_code, 2, "Missing header string check");
like( $result->output, qr%^HTTP CRITICAL: HTTP/1\.1 200 OK - header 'bar' not found on 'https?://127\.0\.0\.1:\d+/header_check'%, "Shows search string and location");
like( $result->output, qr%header 'bar' not found on 'https?://127\.0\.0\.1:\d+/header_check'%, "Shows search string and location");
$result = NPTest->testCmd( "$command -u /header_broken_check" );
is( $result->return_code, 0, "header_check search for string");
like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - 138 bytes in [\d\.]+ second/', "Output correct" );
like( $result->output, '/.*HTTP/1.1 200 OK - 138 bytes in [\d\.]+ second.*/', "Output correct" );
my $cmd;
$cmd = "$command -u /slow";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, "$cmd");
like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
$result->output =~ /in ([\d\.]+) second/;
cmp_ok( $1, ">", 1, "Time is > 1 second" );
$cmd = "$command -u /statuscode/200";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
$cmd = "$command -u /statuscode/200 -e 200";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - Status line output matched "200" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
like( $result->output, '/.*Status line output matched "200".*/', "Output correct: ".$result->output );
$cmd = "$command -u /statuscode/201";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 201 Created - \d+ bytes in [\d\.]+ second /', "Output correct: ".$result->output );
like( $result->output, '/.*HTTP/1.1 201 Created - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
$cmd = "$command -u /statuscode/201 -e 201";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 201 Created - Status line output matched "201" - \d+ bytes in [\d\.]+ second /', "Output correct: ".$result->output );
like( $result->output, '/.*Status line output matched "201".*/', "Output correct: ".$result->output );
$cmd = "$command -u /statuscode/201 -e 200";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 2, $cmd);
like( $result->output, '/^HTTP CRITICAL - Invalid HTTP response received from host on port \d+: HTTP/1.1 201 Created/', "Output correct: ".$result->output );
like( $result->output, '/.*Invalid HTTP response received from host on port \d+: HTTP/1.1 201 Created.*/', "Output correct: ".$result->output );
$cmd = "$command -u /statuscode/200 -e 200,201,202";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - Status line output matched "200,201,202" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
like( $result->output, '/.*Status line output matched "200,201,202".*/', "Output correct: ".$result->output );
$cmd = "$command -u /statuscode/201 -e 200,201,202";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 201 Created - Status line output matched "200,201,202" - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
like( $result->output, '/.*Status line output matched "200,201,202".*/', "Output correct: ".$result->output );
$cmd = "$command -u /statuscode/203 -e 200,201,202";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 2, $cmd);
like( $result->output, '/^HTTP CRITICAL - Invalid HTTP response received from host on port (\d+): HTTP/1.1 203 Non-Authoritative Information/', "Output correct: ".$result->output );
like( $result->output, '/.*Invalid HTTP response received from host on port (\d+): HTTP/1.1 203 Non-Authoritative Information.*/', "Output correct: ".$result->output );
$cmd = "$command -j HEAD -u /method";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 200 HEAD - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
like( $result->output, '/.*HTTP/1.1 200 HEAD - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
$cmd = "$command -j POST -u /method";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 200 POST - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
like( $result->output, '/.*HTTP/1.1 200 POST - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
$cmd = "$command -j GET -u /method";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 200 GET - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
like( $result->output, '/.*HTTP/1.1 200 GET - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
$cmd = "$command -u /method";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 200 GET - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
like( $result->output, '/.*HTTP/1.1 200 GET - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
$cmd = "$command -P foo -u /method";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 200 POST - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
like( $result->output, '/.*HTTP/1.1 200 POST - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
$cmd = "$command -j DELETE -u /method";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 1, $cmd);
like( $result->output, '/^HTTP WARNING: HTTP/1.1 405 Method Not Allowed/', "Output correct: ".$result->output );
like( $result->output, '/.*HTTP/1.1 405 Method Not Allowed.*/', "Output correct: ".$result->output );
$cmd = "$command -j foo -u /method";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 2, $cmd);
like( $result->output, '/^HTTP CRITICAL: HTTP/1.1 501 Not Implemented/', "Output correct: ".$result->output );
like( $result->output, '/.*HTTP/1.1 501 Not Implemented.*/', "Output correct: ".$result->output );
$cmd = "$command -P stufftoinclude -u /postdata -s POST:stufftoinclude";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
$cmd = "$command -j PUT -P stufftoinclude -u /postdata -s PUT:stufftoinclude";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
# To confirm that the free doesn't segfault
$cmd = "$command -P stufftoinclude -j PUT -u /postdata -s PUT:stufftoinclude";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
$cmd = "$command -u /redirect";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 301 Moved Permanently - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
like( $result->output, '/.*HTTP/1.1 301 Moved Permanently - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
$cmd = "$command -f follow -u /redirect";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
$cmd = "$command -u /redirect -k 'follow: me'";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 301 Moved Permanently - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
like( $result->output, '/.*HTTP/1.1 301 Moved Permanently - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
$cmd = "$command -f follow -u /redirect -k 'follow: me'";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
$cmd = "$command -f sticky -u /redirect -k 'follow: me'";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
$cmd = "$command -f stickyport -u /redirect -k 'follow: me'";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
$cmd = "$command -f follow -u /redirect_rel -s redirected";
$result = NPTest->testCmd( $cmd );
is( $result->return_code, 0, $cmd);
like( $result->output, '/^HTTP OK: HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second/', "Output correct: ".$result->output );
like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
# These tests may block
# stickyport - on full urlS port is set back to 80 otherwise