aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2020-02-13 15:28:56 +0200
committerSergey Poznyakoff <gray@gnu.org>2020-02-13 15:28:56 +0200
commit4263bf8b57b7d8a0b5f73a586c55e9ee2a07b6ca (patch)
tree8489b1f0ec53564fc780f480a3a75804e9d4e6e2
parent47bed8e5bc0e1a58e10c6237d27ce578bb50d7d6 (diff)
downloadping903-4263bf8b57b7d8a0b5f73a586c55e9ee2a07b6ca.tar.gz
ping903-4263bf8b57b7d8a0b5f73a586c55e9ee2a07b6ca.tar.bz2
Implement IP lookup and match mode.
* src/ping903.c: Implement two new endpoints: /ip and /match, for IP lookup and match mode. * src/ping903.h (get_ipaddr_stat) (get_host_matches): New protos. * src/pinger.c (get_ipaddr_stat) (get_host_matches): New functions. * src/ping903q.c (resolve_ip): New global. (query_host): Use /host or /ip depending on the value of resolve_ip. (match_host): New function. * doc/ping903q.1: Update.
-rw-r--r--doc/ping903q.130
-rw-r--r--src/ping903.c72
-rw-r--r--src/ping903.h3
-rw-r--r--src/ping903q.c120
-rw-r--r--src/pinger.c77
5 files changed, 284 insertions, 18 deletions
diff --git a/doc/ping903q.1 b/doc/ping903q.1
index 2d351a3..326ca81 100644
--- a/doc/ping903q.1
+++ b/doc/ping903q.1
@@ -21,14 +21,16 @@ ping903q \- ping903 query tool
[\fB\-hVv\fR]\
[\fB\-f \fIFILE\fR]\
[\fIIP\fR]
-
-or
-
+.PP
\fBping903q\fR\
[\fB\-f \fIFILE\fR]\
\fB\-H \fIHOST\fR\
\fB\-c \fIRTA\fB,\fIPCT\fB%\fR\
- \fB\-w \fIRTA\fB,\fIPCT\fB%\fR
+ \fB\-w \fIRTA\fB,\fIPCT\fB%\fR
+.PP
+\fBping903q\fR\
+ [\fB\-f \fIFILE\fR]\
+ \fB\-m\fR
.SH DESCRIPTION
Queries monitoring statistics from the \fBping903\fR daemon. When
used with a single argument (\fIIP\fR), displays information about
@@ -54,6 +56,10 @@ When the \fB\-H\fR, \fB\-c\fR, and \fB\-w\fR options are used, the
program enters \fINagios check mode\fR. In this mode its output
complies with the requirements for external \fBNagios\fR check
programs.
+.SS Match mode
+When invoked with the \fB\-m\fR option, \fBping903q\fR checks if
+\fIHOST\fR is monitored by the server. If so, it prints the matching
+host names and exits with code 0.
.SH EXIT CODE
When called with one argument, the program exits with code 0 (success)
if the IP is alive and 2 otherwise.
@@ -73,6 +79,9 @@ Warning condition.
.B 2
Critical condition.
.PP
+In match mode, the program exits with code 0 if the requested host is
+monitored by the server, and with code 2 if it is not.
+.PP
If any error is encountered, \fBping903q\fR exits with status \fB3\fR.
.SH OPTIONS
.TP
@@ -83,12 +92,19 @@ Read configuration from \fIFILE\fR instead of from the default
.B \-h
Print a short usage summary.
.TP
+.B \-r
+Resolve host argument to IP address and use the IP address to query
+the server. Using this option you can supply a symbolic host name
+as argument even if the server uses the corresponding IP and still get
+a meaningful result. Otherwise, you can use the matching mode (see
+below).
+.TP
.B \-V
Print program version, copyright information, and exit.
.TP
.B \-v
Turn on verbose output.
-.SS Options valid in Nagios check mode
+.SS Options specific for Nagios check mode
The presense of any of these options switches \fBping903q\fR to Nagios
check mode. For this mode to succeed, all three options must be specified.
.TP
@@ -107,6 +123,10 @@ also that the use of the percent sign is mandatory.
\fB\-w \fIRTA\fB,\fIPCT\fB%\fR
Sets the warning threshold value. See above for the discussion of the
arguments.
+.SS Options specific for match mode
+.TP
+.B \-m
+Switch to the host match mode.
.SH SEE ALSO
.BR ping903 (8),
.BR Nagios <https://www.nagios.org/>.
diff --git a/src/ping903.c b/src/ping903.c
index 02b4228..99e3a80 100644
--- a/src/ping903.c
+++ b/src/ping903.c
@@ -257,7 +257,7 @@ httpd_json_response(struct MHD_Connection *conn,
return ret;
}
-int
+static int
ept_config(struct MHD_Connection *conn,
const char *url, const char *method, const char *suffix)
{
@@ -270,7 +270,7 @@ ept_config(struct MHD_Connection *conn,
return httpd_json_response(conn, url, method, val);
}
-int
+static int
ept_host_stat(struct MHD_Connection *conn,
const char *url, const char *method, const char *suffix)
{
@@ -292,6 +292,72 @@ ept_host_stat(struct MHD_Connection *conn,
return httpd_json_response(conn, url, method, val);
}
+static int
+ept_ip_stat(struct MHD_Connection *conn,
+ const char *url, const char *method, const char *suffix)
+{
+ struct json_value *val;
+ int rc;
+
+ while (*suffix == '/')
+ suffix++;
+
+ if (suffix[0] == 0) {
+ return http_error(conn, method, url, MHD_HTTP_FORBIDDEN);
+ } else {
+ int ret;
+ struct addrinfo hints, *res;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_protocol = IPPROTO_TCP;
+ rc = getaddrinfo(suffix, NULL, &hints, &res);
+ if (rc)
+ return http_error(conn, method, url,
+ MHD_HTTP_NOT_FOUND);
+ rc = get_ipaddr_stat(res->ai_addr, res->ai_addrlen, &val);
+ if (rc)
+ ret = http_error(conn, method, url,
+ MHD_HTTP_INTERNAL_SERVER_ERROR);
+ else if (val)
+ ret = httpd_json_response(conn, url, method, val);
+ else
+ ret = http_error(conn, method, url, MHD_HTTP_FORBIDDEN);
+ freeaddrinfo(res);
+ return ret;
+ }
+}
+
+static int
+ept_ip_match(struct MHD_Connection *conn,
+ const char *url, const char *method, const char *suffix)
+{
+ struct json_value *val;
+ int rc;
+ int ret;
+ struct addrinfo hints, *res;
+
+ while (*suffix == '/')
+ suffix++;
+
+ if (suffix[0] == 0)
+ return http_error(conn, method, url, MHD_HTTP_FORBIDDEN);
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_protocol = IPPROTO_TCP;
+ rc = getaddrinfo(suffix, NULL, &hints, &res);
+ if (rc)
+ return http_error(conn, method, url, MHD_HTTP_NOT_FOUND);
+ rc = get_host_matches(&res, &val);
+ if (rc)
+ ret = http_error(conn, method, url,
+ MHD_HTTP_INTERNAL_SERVER_ERROR);
+ else
+ ret = httpd_json_response(conn, url, method, val);
+ freeaddrinfo(res);
+ return ret;
+}
+
typedef int (*ENDPOINT_HANDLER)(struct MHD_Connection *,
const char *, const char *, const char *);
@@ -311,6 +377,8 @@ struct endpoint {
static struct endpoint endpoint[] = {
{ "/config", EPT_EXACT, MHD_HTTP_METHOD_GET, ept_config },
{ "/host", EPT_PREFIX, MHD_HTTP_METHOD_GET, ept_host_stat },
+ { "/ip", EPT_PREFIX, MHD_HTTP_METHOD_GET, ept_ip_stat },
+ { "/match", EPT_PREFIX, MHD_HTTP_METHOD_GET, ept_ip_match },
{ NULL }
};
diff --git a/src/ping903.h b/src/ping903.h
index f7ad6b1..57123a1 100644
--- a/src/ping903.h
+++ b/src/ping903.h
@@ -116,7 +116,10 @@ extern size_t hostaddr_max;
struct json_value *config_to_json(void);
int get_host_stat(HOSTADDR *host, struct json_value **);
int get_hostname_stat(char const *name, struct json_value **retval);
+int get_ipaddr_stat(struct sockaddr *sa, int salen, struct json_value **retval);
int get_all_host_stat(struct json_value **);
+struct addrinfo;
+int get_host_matches(struct addrinfo **aip, struct json_value **retval);
void p903_init(void);
void *p903_sender(void *p);
diff --git a/src/ping903q.c b/src/ping903q.c
index fdef668..7007745 100644
--- a/src/ping903q.c
+++ b/src/ping903q.c
@@ -17,6 +17,7 @@
static char *config_file = DEFAULT_CONFIG_FILE;
FILE *http;
int verbose;
+int resolve_ip;
char const http_version[] = "HTTP/1.1";
enum {
@@ -487,7 +488,12 @@ query_host(char const *name, int (*report)(struct json_value *, void *),
char *ipstr = resolve_host(name);
ssize_t n;
- n = snprintf(url, sizeof(url), "/host/%s", ipstr);
+ if (resolve_ip) {
+ n = snprintf(url, sizeof(url), "/ip/%s", ipstr);
+ } else {
+ n = snprintf(url, sizeof(url), "/host/%s", name);
+ }
+
if (n < 0 || n == sizeof(url)) {
abend("bad host name or IP");
}
@@ -514,6 +520,56 @@ query_host(char const *name, int (*report)(struct json_value *, void *),
}
static void
+match_host(char const *name)
+{
+ int rc;
+ struct http_resp resp;
+ struct json_value *obj;
+ char url[1024];
+ char const *hval;
+ char *p;
+ ssize_t n;
+ size_t i, len;
+
+ n = snprintf(url, sizeof(url), "/match/%s", name);
+ http_query("GET", url, std_headers);
+ http_resp_init(&resp);
+ http_recv(&resp);
+ if (resp.code != 200) {
+ abend("%s", resp.reason);
+ }
+
+ hval = http_resp_get_header(&resp, "content-type");
+ if (!hval || strcmp(hval, "application/json")) {
+ abend("missing or unsupported content type");
+ }
+
+ rc = json_parse_string(resp.content, &obj, &p);
+ if (rc != JSON_E_NOERR)
+ abend("%s near %s", json_strerror(rc), p);
+ if (obj->type != json_array)
+ abend("returned entity has wrong type");
+
+ len = json_array_length(obj);
+ if (json_array_length(obj) == 0) {
+ if (verbose)
+ error("no matching hosts found");
+ exit(EX_NAGIOS_CRITICAL);
+ }
+
+ for (i = 0; i < len; i++) {
+ struct json_value *jv;
+ if (json_array_get(obj, i, &jv)) {
+ abend("can't get element %lu", (unsigned long) i);
+ }
+ if (jv->type != json_string)
+ abend("bad type of element %lu", (unsigned long) i);
+ printf("%s\n", jv->v.s);
+ }
+ exit(EX_NAGIOS_OK);
+}
+
+static void
query_all(void)
{
int rc;
@@ -643,13 +699,15 @@ nagios_check(struct json_value *obj, void *data)
void
usage(void)
{
- printf("Usage: %s [-hVv] [-f FILE] [HOST]\n", progname);
+ printf("Usage: %s [-hrVv] [-f FILE] [HOST]\n", progname);
printf(" or: %s -H HOST -c RTA,PCT%% -w RTA,PCT%%\n", progname);
+ printf(" or: %s -m HOST\n", progname);
printf("Query ping903 daemon.\n");
printf("\n");
printf("Options:\n\n");
printf(" -f FILE read configuration from FILE\n");
printf(" -h print this help test\n");
+ printf(" -r resolve HOST to IP address\n");
printf(" -V print program version and exit\n");
printf(" -v additional verbosity\n");
printf("\nNagios check mode:\n\n");
@@ -657,6 +715,8 @@ usage(void)
printf(" -c RTA,PCT%% set critical threshold\n");
printf(" -w RTA,PCT%% set warning threshold\n");
printf("\n(all three must be given in this mode)\n");
+ printf("\nMatch mode:\n\n");
+ printf(" -m check whether HOST is monitored\n");
printf("\n");
printf("Report bugs to <%s>.\n", PACKAGE_BUGREPORT);
printf("%s home page: <%s>\n", PACKAGE_NAME, PACKAGE_URL);
@@ -669,12 +729,29 @@ version(void)
printf("%s", COPYLEFT);
}
+enum {
+ MODE_DEFAULT,
+ MODE_NAGIOS_CHECK,
+ MODE_MATCH
+};
+
+static int mode = MODE_DEFAULT;
+static int mode_opt = 0;
+static inline void
+setmode(int newmode, int opt)
+{
+ if (mode != MODE_DEFAULT && mode != newmode)
+ abend("option -%d conflicts with -%d", opt, mode_opt);
+ mode = newmode;
+ mode_opt = opt;
+}
+
+
int
main(int argc, char **argv)
{
int c;
char *p, *node, *service;
- int nagios_check_mode = 0;
char const *host = NULL;
char *c_opt = NULL;
char *w_opt = NULL;
@@ -692,22 +769,28 @@ main(int argc, char **argv)
exit(0);
}
}
- while ((c = getopt(argc, argv, "c:f:H:hVvw:")) != EOF) {
+ while ((c = getopt(argc, argv, "c:f:H:hmrVvw:")) != EOF) {
switch (c) {
case 'c':
c_opt = optarg;
- nagios_check_mode = 1;
+ setmode(MODE_NAGIOS_CHECK, c);
break;
case 'f':
config_file = optarg;
break;
case 'H':
host = optarg;
- nagios_check_mode = 1;
+ setmode(MODE_NAGIOS_CHECK, c);
break;
case 'h':
usage();
exit(0);
+ case 'm':
+ setmode(MODE_MATCH, c);
+ break;
+ case 'r':
+ resolve_ip = 1;
+ break;
case 'V':
version();
exit(0);
@@ -716,7 +799,7 @@ main(int argc, char **argv)
break;
case 'w':
w_opt = optarg;
- nagios_check_mode = 1;
+ setmode(MODE_NAGIOS_CHECK, c);
break;
default:
exit(EX_NAGIOS_UNKNOWN);
@@ -725,7 +808,10 @@ main(int argc, char **argv)
argc -= optind;
argv += optind;
- if (nagios_check_mode) {
+ switch (mode) {
+ case MODE_DEFAULT:
+ break;
+ case MODE_NAGIOS_CHECK:
if (argc != 0) {
abend("bad number of arguments");
}
@@ -738,6 +824,11 @@ main(int argc, char **argv)
if (!w_opt)
abend("warning threshold missing; use -w option");
parse_nagios_threshold(w_opt, &chkdata.wth);
+ break;
+ case MODE_MATCH:
+ if (argc != 1)
+ abend("-m requires exactly one command line argument");
+ break;
}
p = node = read_listen(&service);
@@ -748,9 +839,8 @@ main(int argc, char **argv)
http_connect(node, service);
free(p);
- if (nagios_check_mode)
- query_host(host, nagios_check, &chkdata);
- else {
+ switch (mode) {
+ case MODE_DEFAULT:
switch (argc) {
case 0:
query_all();
@@ -759,6 +849,14 @@ main(int argc, char **argv)
default:
abend("bad number of arguments");
}
+ break;
+
+ case MODE_NAGIOS_CHECK:
+ query_host(host, nagios_check, &chkdata);
+ break;
+
+ case MODE_MATCH:
+ match_host(argv[0]);
}
exit(EX_NAGIOS_UNKNOWN);
}
diff --git a/src/pinger.c b/src/pinger.c
index 7c39bca..8ce22d1 100644
--- a/src/pinger.c
+++ b/src/pinger.c
@@ -452,6 +452,20 @@ get_hostname_stat(char const *name, struct json_value **retval)
}
int
+get_ipaddr_stat(struct sockaddr *sa, int salen, struct json_value **retval)
+{
+ size_t i;
+
+ for (i = 0; i < hostaddr_count; i++) {
+ if (hostaddr[i].addrlen == salen
+ && memcmp(hostaddr[i].addr, sa, salen) == 0)
+ return get_host_stat(&hostaddr[i], retval);
+ }
+ *retval = NULL;
+ return 0;
+}
+
+int
get_all_host_stat(struct json_value **retval)
{
struct json_value *ar;
@@ -475,6 +489,69 @@ get_all_host_stat(struct json_value **retval)
return -1;
}
+int
+get_host_matches(struct addrinfo **aip, struct json_value **retval)
+{
+ struct json_value *ar;
+ size_t i;
+ struct addrinfo *ai_head = NULL, *ai_tail = NULL;
+ struct addrinfo *ai = *aip;
+ int ret = -1;
+
+ if (!(ar = json_new_array()))
+ goto err;
+ for (i = 0; i < hostaddr_count; i++) {
+ struct addrinfo *prev = NULL, *p;
+ if (!ai)
+ break;
+ p = ai;
+ while (p) {
+ struct addrinfo *next = p->ai_next;
+ if (p->ai_addrlen == hostaddr[i].addrlen
+ && memcmp(hostaddr[i].addr, p->ai_addr,
+ hostaddr[i].addrlen) == 0) {
+ struct json_value *jv;
+
+ jv = json_new_string(hostaddr[i].name);
+ if (!jv)
+ goto err;
+ if (json_array_append(ar, jv)) {
+ json_value_free(jv);
+ goto err;
+ }
+
+ if (prev)
+ prev->ai_next = next;
+ else
+ ai = next;
+
+ p->ai_next = NULL;
+ if (ai_tail)
+ ai_tail->ai_next = p;
+ else
+ ai_head = p;
+ ai_tail = p;
+
+ break;
+ } else {
+ prev = p;
+ p = next;
+ }
+ }
+ }
+
+ ret = 0;
+ *retval = ar;
+ ar = NULL;
+err:
+ if (ai_tail) {
+ ai_tail->ai_next = ai;
+ *aip = ai_head;
+ }
+ json_value_free(ar);
+ return ret;
+}
+
static void
log_echo(struct sockaddr *addr, socklen_t addrlen,
struct icmp *icmp, struct ip *ip,

Return to:

Send suggestions and report system problems to the System administrator.