diff options
-rw-r--r-- | doc/ping903.cred.5 | 4 | ||||
-rw-r--r-- | maint/README.org | 549 | ||||
-rw-r--r-- | maint/style.css | 85 | ||||
-rw-r--r-- | src/remoteip.c | 4 |
4 files changed, 638 insertions, 4 deletions
diff --git a/doc/ping903.cred.5 b/doc/ping903.cred.5 index b2e187a..ede1b2b 100644 --- a/doc/ping903.cred.5 +++ b/doc/ping903.cred.5 @@ -13,9 +13,9 @@ .\" .\" You should have received a copy of the GNU General Public License .\" along with Ping903. If not, see <http://www.gnu.org/licenses/>. -.TH PING903.CRED 5 "February 27, 2020" "PING903.CONF" "File Formats Manual" +.TH PING903.CRED 5 "March 22, 2020" "PING903.CRED" "File Formats Manual" .SH NAME -ping903.conf \- Credentials storage for ping903 +ping903.cred \- Credentials storage for ping903 .SH DESCRIPTION The file .B .ping903.conf diff --git a/maint/README.org b/maint/README.org new file mode 100644 index 0000000..4374649 --- /dev/null +++ b/maint/README.org @@ -0,0 +1,549 @@ +* Overview + +Ping903 is designed to periodically monitor a very large number of +remote hosts using ICMP ECHO packets. The system is built using the +client-server architecture. The main component (*ping903*) is a daemon +that sits in memory and wakes up periodically to send certain number +of ICMP echo packets to a preconfigured number of hosts and to collect +replies. The resulting round-trip statistics is made available via +REST API. + +The daemon reads its settings from a plain text configuration file. +Most settings have sensible defaults, so that the only thing that the +user needs to supply to get started is a list of IP addresses to +monitor. This list is referred to in this document as /ip-list/. + +A simple command line client utility (*ping903q*) allows the user to +communicate with the daemon, obtaining the needed information about +each host in particular, or all monitored hosts at once. This utility +can operate in several modes. In particular, it can be used as +Nagios external check tool, instead of the standard *check_ping* utility. + +The package and its companion packages are available for download from +https://download.gnu.org.ua/release/ping903. + +For the recent news, visit the package development site at +https://puszcza.gnu.org.ua/projects/ping903. + +The git repository is available at +http://git.gnu.org.ua/cgit/ping903.git. + + +* Installation + +To build *ping903* you will need *GNU Libmicrohttpd library*. It is +available for download from http://ftp.gnu.org/gnu/libmicrohttpd. + +When building from source package, usual incantations apply: + +#+BEGIN_SRC shell-script + ./configure + make + make install +#+END_SRC + +This will install the package under */usr/local*. That is, the server +will be installed as */usr/local/sbin/ping903*, the client program as +*/usr/local/bin/ping903q*, etc. You can give a number of options to +*./configure* in order to customize your installation, in particular to +alter the default installation paths. For example, to install to the +*/usr* file hierarchy, use + +#+BEGIN_SRC shell-script + ./configure --prefix=/usr +#+END_SRC + +Please refer to the =INSTALL= document in the source directory for a +discussion of available options to configure and their effect. + +After installing the package, copy the file *src/ping903.conf* to +*/etc/ping903.conf* and edit it to your liking. This file contains +configuration settings that control the behavior of the server daemon +and, to a certain extent, that of a query tool. Short annotations +before each statement will help you navigate through it. You will +find a detailed discussion of the configuration file in the manpage +[[http://man.gnu.org.ua/manpage/?5+ping903.conf][ping903.conf]](5). What follows is a short outline, intended for quick +start. + +At the very beginning you can leave most settings at their default +values. You might wish to supply a list of IP addresses to monitor, +although even that is not mandatory, since you can add them later, +when the program is already running. To specify them in configuration +file, use the =ip-list= statement. Its argument is either the name +of a file with the IP addresses, or a list of IP addresses as a +/here-document/: + +#+BEGIN_SRC shell-script + ip-list FILENAME +#+END_SRC + +or + +#+BEGIN_SRC shell-script + ip-list <<EOF + ... + EOF +#+END_SRC + +(you can use arbitrary word in place of =EOF= in the latter example, +the only requirement being that the list end with exactly the same +word as the one that followed =<<= at its beginning). + +In either case, IP addresses must be listed one per line of input. +Leading and trailing whitespace is ignored, as well as empty lines. +Comments are introduced by a hash sign (#) appearing as the first +non-whitespace character on a line. + +You are not required to keep all your IP addresses in a single file. +If necessary, you can scatter them among several files and name each +of them in a separate =ip-list= statement. + +IP addresses listed in ip-list files form the /immutable/ IP list, +called so because it cannot be altered while the program is running. +The REST API allows the user to add any number of IP addresses at +runtime as well as remove any of IP addresses added this way. These +addresses form the /mutable/ IP list. Mutable IP list is preserved +across program restarts. + +This means that actually the immutable IP list is optional. You may +choose to keep all monitored addresses in an external storage (an SQL +database, for example) and load them dynamically after the daemon +has started. A working example program for adding IP addresses from +a MySQL database is shipped in the [[http://git.gnu.org.ua/cgit/ping903.git/tree/examples][examples]] directory. A full-fledged +client package able to add or delete keywords at runtime, both +individually or in batches and providing another features is available +from <http://git.gnu.org.ua/cgit/ping903/mangemanche.git>. + +Normally, the ip-list file should contain IP addresses of the hosts to +monitor. It is OK, however, to use symbolic DNS names, too. If a +hostname resolves to a single A record, such usage is equivalent to +placing that IP in the ip-list. However, if the hostname resolves to +multiple IPs, only first one will be used. + +By default, the server will wake up each minute and send 10 echo +requests within 1 second intervals to each registered IP. If the +number of collected replies is less than 7, the IP will be declared as +dead ("alive": false, in the returned JSON). Otherwise it is +considered alive ("alive": true). + +The following settings control these parameters: + +- probe-interval N :: + Interval between wake-ups in seconds. + Default *N=60*. +- ping-count N :: + Number of ICMP packets to send within each probe. + Default *N=10*. +- ping-interval N :: + Interval in seconds between two sequential echo requests. + Default *N=1*. +- tolerance N :: + Maximum number of lost requests after which the host is considered + dead. + Default *N=3*. + +Another statement worth your attention is =listen=. It configures the +IP address and port on which the server will listen for incoming HTTP +requests. The default is *localhost:8080*. Change this setting if +this port is already occupied on your system or if you wish to make +ping903 accessible from outside. + +The access to the HTTP interface is protected by the default access +control library (the files */etc/hosts.allow* and */etc/hosts.deny*). +Refer to [[http://man.gnu.org.ua/manpage/?3+hosts_access][hosts_access]](3) for details. + +When you have finished with the configuration file, run *ping903* to +start the daemon. Check if there are no errors (on the standard +error and in the syslog channel *daemon*). To verify if the daemon is +operational, run + +#+BEGIN_SRC shell-script + curl http://localhost:8080/config +#+END_SRC + +This should return the running configuration. + +Within the next =probe-interval= seconds the server will collect +enough statistics to answer your queries. You can request information +about any particular IP from your ip-list by running + +#+BEGIN_SRC shell-script + ping903q IP +#+END_SRC + +This will return the current status of the IP, e.g. + +#+BEGIN_SRC shell-script + $ ping903q 203.0.113.1 + 203.0.113.1 is alive +#+END_SRC + +To get the detailed statistics use the *-v* option. The result will be +formatted in a [[http://man.gnu.org.ua/manpage/?8+ping][ping]](8)-like manner: + +#+BEGIN_SRC shell-script + $ ping903q -v 203.0.113.1 + 203.0.113.1 is alive + --- 203.0.113.1 ping statistics --- + 10 packets transmitted, 10 received, 0% packet loss, time 9414ms + rtt min/avg/max/mdev = 41.212/41.265/41.374/0.046 ms +#+END_SRC + +In both cases, any number of IP addresses can be given. E.g. the +following command will returns statistics for two IPs: + +#+BEGIN_SRC shell-script + $ ping903q -v 203.0.113.1 203.0.113.5 +#+END_SRC + +To check the current status of all hosts, run + +#+BEGIN_SRC shell-script + $ ping903q -a +#+END_SRC + +Note, that depending on your settings the output can be huge. + +Please refer to [[http://man.gnu.org.ua/manpage/?1+ping903q][ping903q]](1), for a detailed discussion of the tool. + +* System start-up sequence + +To configure *ping903* to start automatically at the system start-up, +see the [[http://git.gnu.org.ua/cgit/ping903.git/tree/rc][rc]] subdirectory. It contains start up scripts for various +flavors of GNU/Linux distributions. Please refer to the *README* file +in this directory for detailed instructions. + +* Nagios external check + +The *ping903q* tool can be used as a Nagios external check program. The +following snippet illustrates the simple Nagios configuration that +makes use of it: + +#+BEGIN_SRC nagios-script + # Define the check_ping903 command + define command { + command_name check_ping903 + command_line /usr/bin/ping903q -r -H $HOSTADDRESS$ -w $ARG1$ -c $ARG2$ + } + + # Define the service using the new command + define service { + host_name server.example.net + address 203.0.113.1 + service_description Server status + check_command check_ping903!200.0,20%!600.0,60% + check_interval 5 + retry_interval 1 + } +#+END_SRC + +* Installation from a git clone + +If you are building from a clone of the Git repository, you will need +GNU autotools to bootstrap the package first. Run + +#+BEGIN_SRC nagios-script + ./bootstrap +#+END_SRC + +in the top level source directory. This will create the configure +script and populate the directory with the missing files. Then proceed +as described above. + +* REST API + +The default channel for communication with the *ping903* daemon is the +HTTP socket open on localhost port 8080. Only GET requests are +allowed. The following endpoints are provided: + +** /id + +Identifies the running instance. On success, a JSON object with the +following attributes is returned: + +- "package": string :: + The package name. +- "version": string :: + Package version string. +- "pid": number :: + PID of the running instance. + +** /id/ATTR + +*ATTR* is one of the attributes discussed above. Returned is the value +of that attribute. + +** /host/[NAME]?[select=HOSTLIST][attr=ATTRLIST] + +*NAME* is the IP address or hostname and *HOSTLIST* is a comma-separated +list of such names. If *NAME* is supplied, it is added at the beginning +of *HOSTLIST* and the hosts in *HOSTLIST* are looked up in the list of +hosts being monitored. Note that *NAME* is treated as a character +string and must coincide exactly with the IP or hostname as it was +supplied in configuration. In particular, if a host was specified by +its symbolic DNS name in the configuration, exactly that name must be +used in URL to obtain statistics for that host. If you wish to use +IP, see the */match* endpoint, discussed below. + +The return value is a JSON array whose elements correspond to the +entries in *HOSTLIST* (after addition of *NAME*, if given). Each element +is an object with the following attributes: + +- "name": string :: + The IP or hostname of the host under which it was supplied in the + ip-list. + +- "validity": boolean :: + Status of this record. If false, the data has not been collected yet + or the host is unreachable. A more detailed information is available in + the "status" member (see below). If "validity" is false, only the + following keys are warranted to be present in the object: "name", + "validity", "status", and "xmit-timestamp". If it is true, the full + statistics is available as described below. + +- "status": string :: + Detailed status of the object. Following values are defined: + + - "init" :: + Initial state: data are being collected ("validity":false). + - "valid" :: + The object is valid and its statistics is reliable ("validity": true). + - "pending" :: + The object is valid, it contains reliable statistics. The host + is being probed at the moment and the object will be updated + soon ("validity": true). + - "invalid" :: + Host is unreachable. No statistics available ("validity": false). + +- "xmit-timestamp": number :: + + Time (the number of seconds since the Epoch) when the last ICMP + ECHO request was transmitted. + +- "start-timestamp": number :: + Time when the recent probe sequence was initiated. + +- "stop-timestamp": number :: + Time when the recent probe sequence was finished. + +- "xmit": number :: + Number of ICMP ECHO requests transmitted during the probe. + +- "recv": number :: + Number of ICMP ECHO responses received during the probe. + +- "loss": number :: + Percentage of lost packets. + +- "tmin": number :: + Minimal round-trip time observed during the probe. + +- "tmax": number :: + Maximal round-trip time observed during the probe. + +- "avg": number :: + Average round-trip time. + +- "stddev": number :: + Standard deviation of round-trip times. + +- "alive": boolean :: + Host status computed as a result of the probe. It is true, if the + difference between "xmit" and "recv" parameters is less than the + "tolerance" configuration setting, and false otherwise. + +Example of the returned JSON for a reachable host: + +#+BEGIN_SRC json + { + "alive":true, + "avg":25.85150, + "dup":0.00000, + "loss":0.00000, + "name":"203.0.113.1", + "recv":10.00000, + "start-timestamp":1581666176.01285, + "status":true, + "stddev":0.03201, + "stop-timestamp":1581666185.27210, + "tmax":25.91400, + "tmin":25.81200, + "xmit":10.00000, + "xmit-timestamp":1581666185.24628 + } +#+END_SRC + +Example of the returned JSON for an unreachable host: + +#+BEGIN_SRC json + { + "name":"203.0.113.2", + "status":false, + "xmit-timestamp":1581666176.01373 + } +#+END_SRC + +The "attr" request argument allows you to specify attributes in the +"stat" object that you are interested in. It is a comma-separated +list of attribute names. If given, each returned "stat" object will +contain only elements from that list. + +** /host + +Return statistics for all monitored hosts. The result is returned as +an array of JSON "stat" objects (described above). + +This is an experimental endpoint. Be careful with it, as it may cause +considerable strain on the server. + +** /match/[HOST]?[select=HOSTLIST] + +Return monitored names that correspond to *HOST* or *HOSTLIST*. *HOSTLIST* +is a comma-separated list of host names or IPv4 addresses, *HOST* is a +single such address. Both *HOST* and *HOSTLIST* can be supplied: +=/match/HOST?select=HOSTLIST= is equivalent to +=/match?select=HOST,HOSTLIST=. + +Each name in the resulting list is resolved and monitored hosts +with IPs matching any of its IPv4 addresses are returned as an +array of JSON objects. Each element in the array describes a single +host from the list and has the following attributes: + +- "name": string :: + Name under which this host appears in the *HOSTLIST*. + +- "hosts": array of strings :: + Array of monitored names corresponding to this "name". Each name + from the array can be used as argument in a GET request to the + */host* endpoint. + + This array is empty if none of the IP addresses of this "name" are + monitored by the server. + +If any error occurred during processing, the following attribute is +added as well: + +- "error": string :: + Textual description of the error. + +** /config + +Return current server configuration as a JSON object. + +** /config/KEYWORD + +Return the value of a particular configuration setting. + +* Updating configuration on the fly. + +The following requests allow administrator to update the IP list +without reloading the server. For the purpose of updating the +IP list is sectioned in two parts: + +- 1. Immutable IP addresses :: + These are IP addresses specified in the configuration file via + the =ip-list= statement. These addresses cannot be modified using + the API described in this section. An attempt to do so will return + an error status. + +- 2. Mutable IP addresses :: + These are additional IP addresses configured via this API. + The mutable IP addresses are saved in the file + */var/lib/ping903/ip-list* before starting next ping probe. + This file is read upon start-up, after all files supplied + in the configuration have been read and processed. This ensures + that the mutable IP address list persists between restarts. + +** POST /config/ip-list + +Adds one or more IP addresses to the list. The request must have +the content type "application/json". The content can be either an +array of IP addresses in dotted-quad representation (or hostnames +that can be resolved to IPv4 addresses) or an object. The latter +must contain the attribute "ip-list" whose value is an array of +IP addresses formatted as described above, and the "mode" attribute. +If "mode" has the value "replace", the new addresses will replace +the current content of the ip-list. If its value is "append", the +new addresses will be appended to the ip-list. + +On success, returns 200 (OK). On error, returns a meaningful error +status. If the error response has the content type +"application/json", the returned JSON object describes the error in +detail. It contains at least the "message" attribute with a +descriptive explanation of the error. If the error refers to an +element of the "ip-list" array, the "index" attribute contains the +1-based index of that element in the array. + +** PUT /config/ip-list/IP + +Adds IP to the current IP list. Returns HTTP status 201 (Created) on +success. On error, the following codes can be returned: + +- 403 (Forbidden) :: + The entry for this IP address already exists or (if a hostname is + given) the argument cannot be resolved to a IPv4 address. If the + Content-Type of the response is "application/json", the "message" + attribute of the returned JSON object supplies an explanation of + the error. +- 500 (Internal server error) :: + Ping903 was unable to fulfill the request. See log files for a + detailed diagnostics. + +** DELETE /config/ip-list/IP-OR-HOSTNAME + +Deletes *IP-OR-HOSTNAME* from the IP list. Returns 200 (OK) on success. +If *IP-OR-HOSTNAME* was not found in the IP list or is immutable, +returns 404 (Not found). + +All update requests are queued and take effect at the beginning of the +next ping probe. + +* References + +Ping903 is documented in the following manual pages: + +- [[http://man.gnu.org.ua/manpage/?8+ping903][ping903]](8) :: Documentation for the ping903 server program. +- [[http://man.gnu.org.ua/manpage/?5+ping903.conf][ping903.conf]](5) :: Documents the ping903 configuration. +- [[http://man.gnu.org.ua/manpage/?1+ping903q][ping903q]](1) :: Documents the ping903 query program. +- [[http://man.gnu.org.ua/manpage/?5+ping903.cred][ping903.cred]](5) :: Documents format of the user's credential storage file. + +* Bug reports + +If you think you found a bug in *ping903* or its documentation, please +send a mail to [[mailto:gray@gnu.org][Sergey Poznyakoff]] or use the bug tracker at +https://puszcza.gnu.org.ua/bugs/?group=ping903 (requires authorization). + +* Copyright + +Copyright (C) 2020 Sergey Poznyakoff + +Permission is granted to anyone to make or distribute verbatim copies +of this document as received, in any medium, provided that the +copyright notice and this permission notice are preserved, +thus giving the recipient permission to redistribute in turn. + +Permission is granted to distribute modified versions +of this document, or of portions of it, +under the above conditions, provided also that they +carry prominent notices stating who last changed them. + +* Document settings :noexport: + +Please ignore this section. It supplies the variables necessary for +proper rendering of this document. + +:PROPERTIES: +:VISIBILITY: folded +:END: + +#+TITLE: ping903 +#+STARTUP: showall +#+EXCLUDE_TAGS: noexport +#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="style.css" /> +#+OPTIONS: ^:nil + +# Local Variables: +# mode: org +# paragraph-separate: "[ ^L]*$" +# version-control: never +# End: diff --git a/maint/style.css b/maint/style.css new file mode 100644 index 0000000..2304fb5 --- /dev/null +++ b/maint/style.css @@ -0,0 +1,85 @@ +/* Basic settings */ +body { + margin-left: auto; + margin-right: auto; + max-width: 80em; + background-color: silver; + padding: 4px; +} +html {} +div { + background-color: white; +} + +div#content { + margin-top: 2em; + margin-left: 5%; + margin-right: 5%; + padding: 1em; + border: 1px solid black; +} + +div#postamble { + margin-bottom: 2em; + margin-left: 5%; + margin-right: 5%; + border: 1px solid black; + font-size: 80%; + padding: 4px; +} + +.title { text-align: center; } +.todo { color: red; } +.done { color: green; } +.tag { background-color: #add8e6; font-weight:normal } +.target { } +.timestamp { color: #bebebe; } +.timestamp-kwd { color: #5f9ea0; } +.right {margin-left:auto; margin-right:0px; text-align:right;} +.left {margin-left:0px; margin-right:auto; text-align:left;} +.center {margin-left:auto; margin-right:auto; text-align:center;} +p.verse { margin-left: 3% } +pre { + border: 1pt solid #AEBDCC; + background-color: #F3F5F7; + padding: 5pt; + font-family: courier, monospace; + font-size: 90%; + overflow:auto; +} +table { border-collapse: collapse; } +td, th { vertical-align: top; } +th.right { text-align:center; } +th.left { text-align:center; } +th.center { text-align:center; } +td.right { text-align:right; } +td.left { text-align:left; } +td.center { text-align:center; } +dt { font-weight: bold; } +div.figure { padding: 0.5em; } +div.figure p { text-align: center; } +div.inlinetask { + padding:10px; + border:2px solid gray; + margin:10px; + background: #ffffcc; +} +textarea { overflow-x: auto; } +.linenr { font-size:smaller } +.code-highlighted { + background-color:#ffff00; +} +.org-info-js_info-navigation { + border-style:none; +} +#org-info-js_console-label { + font-size:10px; + font-weight:bold; + white-space:nowrap; +} +.org-info-js_search-highlight { + background-color:#ffff00; + color:#000000; + font-weight:bold; +} + diff --git a/src/remoteip.c b/src/remoteip.c index 573b69d..2966eca 100644 --- a/src/remoteip.c +++ b/src/remoteip.c @@ -48,7 +48,7 @@ str_is_ipv4(const char *addr) return (dot_count == 3); } -#define PFXSTR_IPV4_MAPPED "::ffff:" +#define PFXSTR_IPV4_MAPPED "::ffff" #define PFXLEN_IPV4_MAPPED (sizeof PFXSTR_IPV4_MAPPED - 1) static int @@ -217,7 +217,7 @@ str_to_cidr(char const *str, struct cidr *cidr, if (*end == 0) masklen_to_netmask(cidr->netmask, cidr->len, masklen); else if ((cidr->family == AF_INET && str_is_ipv4(p)) - || (cidr->family == AF_INET6 && str_is_ipv6(ipbuf))) { + || (cidr->family == AF_INET6 && str_is_ipv6(p))) { rc = inet_pton(cidr->family, p, &inaddr); if (rc != 1) { error(file, line, "bad netmask: %s", |