From c5bb60907c8c36b2aa2b5348adad87573109402d Mon Sep 17 00:00:00 2001 From: VVelox Date: Thu, 22 Nov 2018 09:05:38 -0600 Subject: [PATCH] add app for getting status of TCP connections for specified services (#8090) * add the poller for portactivity * add the ability to get monitor ports for portactivity * add the graphs for displaying stuff for the portactivity app * add the portactivity app page * update the docs for Portactivity * remove extra line * minor doc update for Portactivity * add update_application line * convert to use json_app_get * convert curly brackets to square * style fix * remote error, errorString, and version after they stop being important so they are not processed * add alert rule examples * add the poller for portactivity * add the ability to get monitor ports for portactivity * add the graphs for displaying stuff for the portactivity app * add the portactivity app page * update the docs for Portactivity * remove extra line * minor doc update for Portactivity * add update_application line * convert to use json_app_get * convert curly brackets to square * style fix * remote error, errorString, and version after they stop being important so they are not processed * add alert rule examples * remove dump of get_portactivity_ports function added during rebase * update to the current json_app_get * add portactivity snmprec * add the portactivity test data * whoops bad merge when rebasing... fix * minor formatting cleanup and add a missing comma * fix some odditities with what one of the tests is doing * whoops... include the use for the exception * set the response to okay * attempt to make snmpsim array check happy again * the json now lints * more making metric testing happy * one more update to make travis-ci happy * now flattens arrays also add array_flatten * rename array_flatten to data_flatten as pre-commit chokes on it as laravel has something similarly named * go through and properly add all the metrics * tested with the newest one and it works * whoops, clean up json and remove prototype that was used when putting it together * doh! make it happy with laravel now * see if a minor changing in formatting for the numbers makes the polling unit test happy * order them properly * remove a comma * a few more minor fixes --- doc/Extensions/Applications.md | 27 ++ html/includes/functions.inc.php | 25 ++ .../application/portactivity_from.inc.php | 80 +++++ .../application/portactivity_to.inc.php | 80 +++++ .../portactivity_total_details.inc.php | 80 +++++ .../application/portactivity_totals.inc.php | 35 +++ html/pages/device/apps/portactivity.inc.php | 78 +++++ .../polling/applications/portactivity.inc.php | 159 ++++++++++ includes/polling/functions.inc.php | 43 ++- misc/alert_rules.json | 37 ++- tests/data/linux_portactivity-v1.json | 283 ++++++++++++++++++ tests/snmpsim/linux_portactivity-v1.snmprec | 11 + 12 files changed, 933 insertions(+), 5 deletions(-) create mode 100644 html/includes/graphs/application/portactivity_from.inc.php create mode 100644 html/includes/graphs/application/portactivity_to.inc.php create mode 100644 html/includes/graphs/application/portactivity_total_details.inc.php create mode 100644 html/includes/graphs/application/portactivity_totals.inc.php create mode 100644 html/pages/device/apps/portactivity.inc.php create mode 100644 includes/polling/applications/portactivity.inc.php create mode 100644 tests/data/linux_portactivity-v1.json create mode 100644 tests/snmpsim/linux_portactivity-v1.snmprec diff --git a/doc/Extensions/Applications.md b/doc/Extensions/Applications.md index ac338453f0..0f266eadc8 100644 --- a/doc/Extensions/Applications.md +++ b/doc/Extensions/Applications.md @@ -62,6 +62,7 @@ The unix-agent does not have a discovery module, only a poller module. That poll 1. [OS Updates](#os-updates) - SNMP extend 1. [PHP-FPM](#php-fpm) - SNMP extend 1. [Pi-hole](#pi-hole) - SNMP extend +1. [Portactivity](#portactivity) - SNMP extend 1. [Postfix](#postfix) - SNMP extend 1. [Postgres](#postgres) - SNMP extend 1. [PowerDNS](#powerdns) - Agent @@ -772,6 +773,32 @@ extend pi-hole /etc/snmp/pi-hole The application should be auto-discovered as described at the top of the page. If it is not, please follow the steps set out under `SNMP Extend` heading top of page. +### Portactivity +#### SNMP Extend + +1. Install the Perl module Parse::Netstat. + +2. Copy the Perl script to the desired host (the host must be added to LibreNMS devices) +``` +wget https://github.com/librenms/librenms-agent/raw/master/snmp/portactivity -O /etc/snmp/portactivity +``` + +3. Make the script executable. (chmod +x /etc/snmp/portactivity) + +4. Edit your snmpd.conf file (usually /etc/snmp/snmpd.conf) and add: +``` +extend portactivity /etc/snmp/portactivity -p http,ldap,imap +``` + +Will monitor HTTP, LDAP, and IMAP. The -p switch specifies what ports to use. This is a comma seperated list. + +These must be found in '/etc/services' or where ever NSS is set to fetch it from. If not, it will throw an error. + +If you want to JSON returned by it to be printed in a pretty format use the -P flag. + +5. Restart snmpd on your host. + +Please note that for only TCP[46] services are supported. ### Postfix #### SNMP Extend diff --git a/html/includes/functions.inc.php b/html/includes/functions.inc.php index 2d8ad19e60..a0ab4cb74d 100644 --- a/html/includes/functions.inc.php +++ b/html/includes/functions.inc.php @@ -1710,6 +1710,31 @@ function get_zfs_pools($device_id) return array(); } +/** + * Get the ports for a device... just requires the device ID + * an empty return means portsactivity is not in use or there are currently no ports + * @param $device_id + * @return array + */ +function get_portactivity_ports($device_id) +{ + $options=array( + 'filter' => array( + 'type' => array('=', 'portsactivity'), + ), + ); + + $component=new LibreNMS\Component(); + $portsc=$component->getComponents($device_id, $options); + + if (isset($portsc[$device_id])) { + $id = $component->getFirstComponentID($portsc, $device_id); + return json_decode($portsc[$device_id][$id]['ports']); + } + + return array(); +} + /** * Returns the sysname of a device with a html line break prepended. * if the device has an empty sysname it will return device's hostname instead diff --git a/html/includes/graphs/application/portactivity_from.inc.php b/html/includes/graphs/application/portactivity_from.inc.php new file mode 100644 index 0000000000..e56c1c4be8 --- /dev/null +++ b/html/includes/graphs/application/portactivity_from.inc.php @@ -0,0 +1,80 @@ + $rrd_filename, + 'descr' => 'CLOSED', + 'ds' => 'fromCLOSED', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'SYN_SENT', + 'ds' => 'fromSYN_SENT', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'SYN_RECEIVED', + 'ds' => 'fromSYN_RECEIVED', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'ESTABLISHED', + 'ds' => 'fromESTABLISHED', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'CLOSE_WAIT', + 'ds' => 'fromCLOSE_WAIT', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'FIN_WAIT_1', + 'ds' => 'fromFIN_WAIT_1', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'CLOSING', + 'ds' => 'fromCLOSING', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'LAST_ACK', + 'ds' => 'fromLAST_ACK', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'FIN_WAIT_2', + 'ds' => 'fromFIN_WAIT_2', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'TIME_WAIT', + 'ds' => 'fromTIME_WAIT', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'UNKNOWN', + 'ds' => 'fromUNKNOWN', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'other', + 'ds' => 'fromother', + ); +} else { + d_echo('RRD "'.$rrd_filename.'" not found'); +} + +require 'includes/graphs/generic_multi_line.inc.php'; diff --git a/html/includes/graphs/application/portactivity_to.inc.php b/html/includes/graphs/application/portactivity_to.inc.php new file mode 100644 index 0000000000..a5f05bf16f --- /dev/null +++ b/html/includes/graphs/application/portactivity_to.inc.php @@ -0,0 +1,80 @@ + $rrd_filename, + 'descr' => 'CLOSED', + 'ds' => 'toCLOSED', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'SYN_SENT', + 'ds' => 'toSYN_SENT', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'SYN_RECEIVED', + 'ds' => 'toSYN_RECEIVED', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'ESTABLISHED', + 'ds' => 'toESTABLISHED', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'CLOSE_WAIT', + 'ds' => 'toCLOSE_WAIT', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'FIN_WAIT_1', + 'ds' => 'toFIN_WAIT_1', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'CLOSING', + 'ds' => 'toCLOSING', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'LAST_ACK', + 'ds' => 'toLAST_ACK', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'FIN_WAIT_2', + 'ds' => 'toFIN_WAIT_2', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'TIME_WAIT', + 'ds' => 'toTIME_WAIT', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'UNKNOWN', + 'ds' => 'toUNKNOWN', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'other', + 'ds' => 'toother', + ); +} else { + d_echo('RRD "'.$rrd_filename.'" not found'); +} + +require 'includes/graphs/generic_multi_line.inc.php'; diff --git a/html/includes/graphs/application/portactivity_total_details.inc.php b/html/includes/graphs/application/portactivity_total_details.inc.php new file mode 100644 index 0000000000..5b3f79ead6 --- /dev/null +++ b/html/includes/graphs/application/portactivity_total_details.inc.php @@ -0,0 +1,80 @@ + $rrd_filename, + 'descr' => 'CLOSED', + 'ds' => 'totalCLOSED', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'SYN_SENT', + 'ds' => 'totalSYN_SENT', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'SYN_RECEIVED', + 'ds' => 'totalSYN_RECEIVED', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'ESTABLISHED', + 'ds' => 'totalESTABLISHED', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'CLOSE_WAIT', + 'ds' => 'totalCLOSE_WAIT', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'FIN_WAIT_1', + 'ds' => 'totalFIN_WAIT_1', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'CLOSING', + 'ds' => 'totalCLOSING', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'LAST_ACK', + 'ds' => 'totalLAST_ACK', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'FIN_WAIT_2', + 'ds' => 'totalFIN_WAIT_2', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'TIME_WAIT', + 'ds' => 'totalTIME_WAIT', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'UNKNOWN', + 'ds' => 'totalUNKNOWN', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'other', + 'ds' => 'totalother', + ); +} else { + d_echo('RRD "'.$rrd_filename.'" not found'); +} + +require 'includes/graphs/generic_multi_line.inc.php'; diff --git a/html/includes/graphs/application/portactivity_totals.inc.php b/html/includes/graphs/application/portactivity_totals.inc.php new file mode 100644 index 0000000000..9bc004f422 --- /dev/null +++ b/html/includes/graphs/application/portactivity_totals.inc.php @@ -0,0 +1,35 @@ + $rrd_filename, + 'descr' => 'Total', + 'ds' => 'total_conns', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'From', + 'ds' => 'total_from', + ); + $rrd_list[]=array( + 'filename' => $rrd_filename, + 'descr' => 'To', + 'ds' => 'total_to', + ); +} else { + d_echo('RRD "'.$rrd_filename.'" not found'); +} + +require 'includes/graphs/generic_multi_line.inc.php'; diff --git a/html/pages/device/apps/portactivity.inc.php b/html/pages/device/apps/portactivity.inc.php new file mode 100644 index 0000000000..9acbd8fe92 --- /dev/null +++ b/html/pages/device/apps/portactivity.inc.php @@ -0,0 +1,78 @@ + 'device', + 'device' => $device['device_id'], + 'tab' => 'apps', + 'app' => 'portactivity', +); + +print_optionbar_start(); + +echo 'Ports:'; +$ports_int=0; +while (isset($ports[$ports_int])) { + $port=$ports[$ports_int]; + $label=$ports[$ports_int]; + + if ($vars['port'] == $port) { + $label='>>'.$port.'<<'; + } + + $ports_int++; + + $append=''; + if (isset($ports[$ports_int])) { + $append=', '; + } + + echo generate_link($label, $link_array, array('port'=>$port)).$append; +} + +print_optionbar_end(); + +if (!isset($vars['port'])) { + echo "Please select a port.\n"; + + $graphs = array( +# No useful bits to display with out selecting anything. + ); +} else { + $graphs = array( + 'portactivity_totals'=>'Total Connections', + 'portactivity_total_details'=>'Total Connections Details', + 'portactivity_to'=>'Connections To Server', + 'portactivity_from'=>'Connections From Server', + ); +} + +foreach ($graphs as $key => $text) { + $graph_type = $key; + $graph_array['height'] = '100'; + $graph_array['width'] = '215'; + $graph_array['to'] = $config['time']['now']; + $graph_array['id'] = $app['app_id']; + $graph_array['type'] = 'application_'.$key; + + if (isset($vars['port'])) { + $graph_array['port']=$vars['port']; + } + + + echo '
+
+

'.$text.'

+
+
+
'; + include 'includes/print-graphrow.inc.php'; + echo '
'; + echo '
'; + echo '
'; +} diff --git a/includes/polling/applications/portactivity.inc.php b/includes/polling/applications/portactivity.inc.php new file mode 100644 index 0000000000..264b416c5f --- /dev/null +++ b/includes/polling/applications/portactivity.inc.php @@ -0,0 +1,159 @@ +getCode().':'. $e->getMessage() . PHP_EOL; + update_application($app, $e->getCode().':'.$e->getMessage(), []); // Set empty metrics and error message + return; +} + +$ports=$returned['data']; + +$ports_rrd_def = RrdDefinition::make() + ->addDataset('total_conns', 'GAUGE', 0) + ->addDataset('total_to', 'GAUGE', 0) + ->addDataset('total_from', 'GAUGE', 0) + ->addDataset('totalLISTEN', 'GAUGE', 0) + ->addDataset('totalCLOSED', 'GAUGE', 0) + ->addDataset('totalSYN_SENT', 'GAUGE', 0) + ->addDataset('totalSYN_RECEIVED', 'GAUGE', 0) + ->addDataset('totalESTABLISHED', 'GAUGE', 0) + ->addDataset('totalCLOSE_WAIT', 'GAUGE', 0) + ->addDataset('totalFIN_WAIT_1', 'GAUGE', 0) + ->addDataset('totalCLOSING', 'GAUGE', 0) + ->addDataset('totalLAST_ACK', 'GAUGE', 0) + ->addDataset('totalFIN_WAIT_2', 'GAUGE', 0) + ->addDataset('totalTIME_WAIT', 'GAUGE', 0) + ->addDataset('totalUNKNOWN', 'GAUGE', 0) + ->addDataset('totalother', 'GAUGE', 0) + ->addDataset('toLISTEN', 'GAUGE', 0) + ->addDataset('toCLOSED', 'GAUGE', 0) + ->addDataset('toSYN_SENT', 'GAUGE', 0) + ->addDataset('toSYN_RECEIVED', 'GAUGE', 0) + ->addDataset('toESTABLISHED', 'GAUGE', 0) + ->addDataset('toCLOSE_WAIT', 'GAUGE', 0) + ->addDataset('toFIN_WAIT_1', 'GAUGE', 0) + ->addDataset('toCLOSING', 'GAUGE', 0) + ->addDataset('toLAST_ACK', 'GAUGE', 0) + ->addDataset('toFIN_WAIT_2', 'GAUGE', 0) + ->addDataset('toTIME_WAIT', 'GAUGE', 0) + ->addDataset('toUNKNOWN', 'GAUGE', 0) + ->addDataset('toother', 'GAUGE', 0) + ->addDataset('fromLISTEN', 'GAUGE', 0) + ->addDataset('fromCLOSED', 'GAUGE', 0) + ->addDataset('fromSYN_SENT', 'GAUGE', 0) + ->addDataset('fromSYN_RECEIVED', 'GAUGE', 0) + ->addDataset('fromESTABLISHED', 'GAUGE', 0) + ->addDataset('fromCLOSE_WAIT', 'GAUGE', 0) + ->addDataset('fromFIN_WAIT_1', 'GAUGE', 0) + ->addDataset('fromCLOSING', 'GAUGE', 0) + ->addDataset('fromLAST_ACK', 'GAUGE', 0) + ->addDataset('fromFIN_WAIT_2', 'GAUGE', 0) + ->addDataset('fromTIME_WAIT', 'GAUGE', 0) + ->addDataset('fromUNKNOWN', 'GAUGE', 0) + ->addDataset('fromother', 'GAUGE', 0); + +// +// update the RRD files for each port +// + +$ports_keys=array_keys($ports); +$ports_keys_int=0; +while (isset($ports[$ports_keys[$ports_keys_int]])) { + $rrd_name = array('app', $name, $app_id, $ports_keys[$ports_keys_int]); + $fields = array( + 'total_conns' => $ports[$ports_keys[$ports_keys_int]]['total_conns'], + 'total_to' => $ports[$ports_keys[$ports_keys_int]]['total_to'], + 'total_from' => $ports[$ports_keys[$ports_keys_int]]['total_from'], + 'totalLISTEN' => $ports[$ports_keys[$ports_keys_int]]['total']['LISTEN'], + 'totalCLOSED' => $ports[$ports_keys[$ports_keys_int]]['total']['CLOSED'], + 'totalSYN_SENT' => $ports[$ports_keys[$ports_keys_int]]['total']['SYN_SENT'], + 'totalSYN_RECEIVED' => $ports[$ports_keys[$ports_keys_int]]['total']['SYN_RECEIVED'], + 'totalESTABLISHED' => $ports[$ports_keys[$ports_keys_int]]['total']['ESTABLISHED'], + 'totalCLOSE_WAIT' => $ports[$ports_keys[$ports_keys_int]]['total']['CLOSE_WAIT'], + 'totalFIN_WAIT_1' => $ports[$ports_keys[$ports_keys_int]]['total']['FIN_WAIT_1'], + 'totalCLOSING' => $ports[$ports_keys[$ports_keys_int]]['total']['CLOSING'], + 'totalLAST_ACK' => $ports[$ports_keys[$ports_keys_int]]['total']['LAST_ACK'], + 'totalFIN_WAIT_2' => $ports[$ports_keys[$ports_keys_int]]['total']['FIN_WAIT_2'], + 'totalTIME_WAIT' => $ports[$ports_keys[$ports_keys_int]]['total']['TIME_WAIT'], + 'totalUNKNOWN' => $ports[$ports_keys[$ports_keys_int]]['total']['UNKNOWN'], + 'totalother' => $ports[$ports_keys[$ports_keys_int]]['total']['other'], + 'toLISTEN' => $ports[$ports_keys[$ports_keys_int]]['to']['LISTEN'], + 'toCLOSED' => $ports[$ports_keys[$ports_keys_int]]['to']['CLOSED'], + 'toSYN_SENT' => $ports[$ports_keys[$ports_keys_int]]['to']['SYN_SENT'], + 'toSYN_RECEIVED' => $ports[$ports_keys[$ports_keys_int]]['to']['SYN_RECEIVED'], + 'toESTABLISHED' => $ports[$ports_keys[$ports_keys_int]]['to']['ESTABLISHED'], + 'toCLOSE_WAIT' => $ports[$ports_keys[$ports_keys_int]]['to']['CLOSE_WAIT'], + 'toFIN_WAIT_1' => $ports[$ports_keys[$ports_keys_int]]['to']['FIN_WAIT_1'], + 'toCLOSING' => $ports[$ports_keys[$ports_keys_int]]['to']['CLOSING'], + 'toLAST_ACK' => $ports[$ports_keys[$ports_keys_int]]['to']['LAST_ACK'], + 'toFIN_WAIT_2' => $ports[$ports_keys[$ports_keys_int]]['to']['FIN_WAIT_2'], + 'toTIME_WAIT' => $ports[$ports_keys[$ports_keys_int]]['to']['TIME_WAIT'], + 'toUNKNOWN' => $ports[$ports_keys[$ports_keys_int]]['to']['UNKNOWN'], + 'toother' => $ports[$ports_keys[$ports_keys_int]]['to']['other'], + 'fromLISTEN' => $ports[$ports_keys[$ports_keys_int]]['from']['LISTEN'], + 'fromCLOSED' => $ports[$ports_keys[$ports_keys_int]]['from']['CLOSED'], + 'fromSYN_SENT' => $ports[$ports_keys[$ports_keys_int]]['from']['SYN_SENT'], + 'fromSYN_RECEIVED' => $ports[$ports_keys[$ports_keys_int]]['from']['SYN_RECEIVED'], + 'fromESTABLISHED' => $ports[$ports_keys[$ports_keys_int]]['from']['ESTABLISHED'], + 'fromCLOSE_WAIT' => $ports[$ports_keys[$ports_keys_int]]['from']['CLOSE_WAIT'], + 'fromFIN_WAIT_1' => $ports[$ports_keys[$ports_keys_int]]['from']['FIN_WAIT_1'], + 'fromCLOSING' => $ports[$ports_keys[$ports_keys_int]]['from']['CLOSING'], + 'fromLAST_ACK' => $ports[$ports_keys[$ports_keys_int]]['from']['LAST_ACK'], + 'fromFIN_WAIT_2' => $ports[$ports_keys[$ports_keys_int]]['from']['FIN_WAIT_2'], + 'fromTIME_WAIT' => $ports[$ports_keys[$ports_keys_int]]['from']['TIME_WAIT'], + 'fromUNKNOWN' => $ports[$ports_keys[$ports_keys_int]]['from']['UNKNOWN'], + 'fromother' => $ports[$ports_keys[$ports_keys_int]]['from']['other'], + ); + $tags = array('name' => $name, 'app_id' => $app_id, 'rrd_def' => $ports_rrd_def, 'rrd_name' => $rrd_name); + data_update($device, 'app', $tags, $fields); + + $ports_keys_int++; +} + +// +// component processing for portsactivity +// +$device_id=$device['device_id']; +$options=array( + 'filter' => array( + 'device_id' => array('=', $device_id), + 'type' => array('=', 'portsactivity'), + ), +); + +$component=new LibreNMS\Component(); +$components=$component->getComponents($device_id, $options); + +//delete portsactivity component if nothing is found +if (empty($ports_keys)) { + if (isset($components[$device_id])) { + foreach ($components[$device_id] as $component_id => $_unused) { + $component->deleteComponent($component_id); + } + } +//add portsactivity component if found +} else { + if (isset($components[$device_id])) { + $portsc = $components[$device_id]; + } else { + $portsc = $component->createComponent($device_id, 'portsactivity'); + } + + $id = $component->getFirstComponentID($portsc); + $portsc[$id]['label'] = 'Portsactivity'; + $portsc[$id]['ports'] = json_encode($ports_keys); + + $component->setComponentPrefs($device_id, $portsc); +} + +update_application($app, 'OK', data_flatten($ports)); diff --git a/includes/polling/functions.inc.php b/includes/polling/functions.inc.php index 1d1795f9b6..0ec9bfa1bd 100644 --- a/includes/polling/functions.inc.php +++ b/includes/polling/functions.inc.php @@ -81,10 +81,10 @@ function poll_sensor($device, $class) } elseif ($class == 'state') { if (!is_numeric($sensor_value)) { $state_value = dbFetchCell( - 'SELECT `state_value` - FROM `state_translations` LEFT JOIN `sensors_to_state_indexes` - ON `state_translations`.`state_index_id` = `sensors_to_state_indexes`.`state_index_id` - WHERE `sensors_to_state_indexes`.`sensor_id` = ? + 'SELECT `state_value` + FROM `state_translations` LEFT JOIN `sensors_to_state_indexes` + ON `state_translations`.`state_index_id` = `sensors_to_state_indexes`.`state_index_id` + WHERE `sensors_to_state_indexes`.`sensor_id` = ? AND `state_translations`.`state_descr` LIKE ?', array($sensor['sensor_id'], $sensor_value) ); @@ -829,3 +829,38 @@ function json_app_get($device, $extend, $min_version = 1) return $parsed_json; } + +/** + * Some data arrays returned with json_app_get are deeper than + * update_application likes. This recurses through the array + * and flattens it out so it can nicely be inserted into the + * database. + * + * One argument is taken and that is the array to flatten. + * + * @param array $array + * @param string $prefix What to prefix to the name. Defaults to '', nothing. + * @param string $joiner The string to join the prefix, if set to something other + * than '', and array keys with. + * + * @return array The flattened array. + */ +function data_flatten($array, $prefix = '', $joiner = '_') +{ + $return = array(); + foreach ($array as $key => $value) { + if (is_array($value)) { + if (strcmp($prefix, '')) { + $key=$prefix.$joiner.$key; + } + $return = array_merge($return, data_flatten($value, $key, $joiner)); + } else { + if (strcmp($prefix, '')) { + $key=$prefix.$joiner.$key; + } + $return[$key] = $value; + } + } + + return $return; +} diff --git a/misc/alert_rules.json b/misc/alert_rules.json index 66bcac442f..41c16e1328 100644 --- a/misc/alert_rules.json +++ b/misc/alert_rules.json @@ -363,6 +363,41 @@ { "rule": "devices.os = \"Netscaler\" && sensors.sensor_type = \"haCurState\" && sensors.sensor_current ~ \"[2|4|5|7|10|11]\" && macros.device_up = \"1\"", "name": "Netscaler HA node state Critical" + }, + { + "rule": "%applications.app_type='portactivity' && %applications_metrics.ssh_total_to>'5'", + "name": "SSH Connections To" + }, + { + "rule": "%applications.app_type='portactivity' && %applications_metrics.http_total_to>'100'", + "name": "HTTP Connections To" + }, + { + "rule": "%applications.app_type='portactivity' && %applications_metrics.https_total_to>'100'", + "name": "HTTPS Connections To" + }, + { + "rule": "%applications.app_type='portactivity' && %applications_metrics.smtp_total_from>'10'", + "name": "SMTP Connections From" + }, + { + "rule": "%applications.app_type='portactivity' && %applications_metrics.smtp_total_to>'30'", + "name": "SMTP Connections To" + }, + { + "rule": "%applications.app_type='portactivity' && %applications_metrics.ftp_total_to>'5'", + "name": "FTP Connections To" + }, + { + "rule": "%applications.app_type='portactivity' && %applications_metrics.imap_total_to>'20'", + "name": "IMAP Connections To" + }, + { + "rule": "%applications.app_type='portactivity' && %applications_metrics.imaps_total_to>'20'", + "name": "IMAPS Connections To" + }, + { + "rule": "%applications.app_type='portactivity' && %applications_metrics.imaps_total_from>'0'", + "name": "IRCD Connections From" } - ] diff --git a/tests/data/linux_portactivity-v1.json b/tests/data/linux_portactivity-v1.json new file mode 100644 index 0000000000..7a91de74d6 --- /dev/null +++ b/tests/data/linux_portactivity-v1.json @@ -0,0 +1,283 @@ +{ + "applications": { + "discovery": { + "applications": [ + { + "app_type": "portactivity", + "app_state": "UNKNOWN", + "discovered": "1", + "app_state_prev": null, + "app_status": "", + "app_instance": "" + } + ], + "application_metrics": [] + }, + "poller": { + "applications": [ + { + "app_type": "portactivity", + "app_state": "OK", + "discovered": "1", + "app_state_prev": "UNKNOWN", + "app_status": "", + "app_instance": "" + } + ], + "application_metrics": [ + { + "metric": "ssh_from_CLOSE_WAIT", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_from_CLOSED", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_from_CLOSING", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_from_ESTABLISHED", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_from_FIN_WAIT_1", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_from_FIN_WAIT_2", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_from_LAST_ACK", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_from_LISTEN", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_from_other", + "value": 0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_from_SYN_RECEIVED", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_from_SYN_SENT", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_from_TIME_WAIT", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_from_UNKNOWN", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_to_CLOSE_WAIT", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_to_CLOSED", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_to_CLOSING", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_to_ESTABLISHED", + "value": 1.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_to_FIN_WAIT_1", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_to_FIN_WAIT_2", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_to_LAST_ACK", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_to_LISTEN", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_to_other", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_to_SYN_RECEIVED", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_to_SYN_SENT", + "value": "0.0", + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_to_TIME_WAIT", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_to_UNKNOWN", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_total_CLOSE_WAIT", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_total_CLOSED", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_total_CLOSING", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_total_conns", + "value": 1.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_total_ESTABLISHED", + "value": 1.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_total_FIN_WAIT_1", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_total_FIN_WAIT_2", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_total_from", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_total_LAST_ACK", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_total_LISTEN", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_total_other", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_total_SYN_RECEIVED", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_total_SYN_SENT", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_total_TIME_WAIT", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_total_to", + "value": 1.0, + "value_prev": null, + "app_type": "portactivity" + }, + { + "metric": "ssh_total_UNKNOWN", + "value": 0.0, + "value_prev": null, + "app_type": "portactivity" + } + ] + } + } +} diff --git a/tests/snmpsim/linux_portactivity-v1.snmprec b/tests/snmpsim/linux_portactivity-v1.snmprec new file mode 100644 index 0000000000..a4fc65d017 --- /dev/null +++ b/tests/snmpsim/linux_portactivity-v1.snmprec @@ -0,0 +1,11 @@ +1.3.6.1.2.1.1.1.0|4|Linux server 3.10.0-693.5.2.el7.x86_64 #1 SMP Fri Oct 20 20:32:50 UTC 2017 x86_64 +1.3.6.1.2.1.1.2.0|6|1.3.6.1.4.1.8072.3.2.10 +1.3.6.1.2.1.1.3.0|67|77550514 +1.3.6.1.2.1.1.4.0|4| +1.3.6.1.2.1.1.5.0|4| +1.3.6.1.2.1.1.6.0|4| +1.3.6.1.2.1.25.1.1.0|67|77552962 +1.3.6.1.4.1.8072.1.3.2.2.1.21.6.100.105.115.116.114.111|2|1 +1.3.6.1.4.1.8072.1.3.2.2.1.21.12.112.111.114.116.97.99.116.105.118.105.116.121|2|1 +1.3.6.1.4.1.8072.1.3.2.3.1.2.12.112.111.114.116.97.99.116.105.118.105.116.121|4x|7b0a2020202276657273696f6e22203a20312c0a202020226461746122203a207b0a2020202020202273736822203a207b0a20202020202020202022746f74616c5f746f22203a20312c0a20202020202020202022746f74616c5f636f6e6e7322203a20312c0a2020202020202020202266726f6d22203a207b0a2020202020202020202020202253594e5f524543454956454422203a20302c0a202020202020202020202020224c4153545f41434b22203a20302c0a2020202020202020202020202245535441424c495348454422203a20302c0a20202020202020202020202022554e4b4e4f574e22203a20302c0a2020202020202020202020202254494d455f5741495422203a20302c0a2020202020202020202020202246494e5f574149545f3122203a20302c0a2020202020202020202020202253594e5f53454e5422203a20302c0a20202020202020202020202022434c4f53455f5741495422203a20302c0a202020202020202020202020224c495354454e22203a20302c0a2020202020202020202020202246494e5f574149545f3222203a20302c0a20202020202020202020202022434c4f53454422203a20302c0a20202020202020202020202022434c4f53494e4722203a20302c0a202020202020202020202020226f7468657222203a20300a2020202020202020207d2c0a20202020202020202022746f74616c22203a207b0a2020202020202020202020202245535441424c495348454422203a20312c0a20202020202020202020202022554e4b4e4f574e22203a20302c0a2020202020202020202020202254494d455f5741495422203a20302c0a2020202020202020202020202246494e5f574149545f3122203a20302c0a2020202020202020202020202253594e5f53454e5422203a20302c0a2020202020202020202020202253594e5f524543454956454422203a20302c0a202020202020202020202020224c4153545f41434b22203a20302c0a2020202020202020202020202246494e5f574149545f3222203a20302c0a202020202020202020202020224c495354454e22203a20302c0a20202020202020202020202022434c4f53454422203a20302c0a20202020202020202020202022434c4f53494e4722203a20302c0a202020202020202020202020226f7468657222203a20302c0a20202020202020202020202022434c4f53455f5741495422203a20300a2020202020202020207d2c0a20202020202020202022746f74616c5f66726f6d22203a20302c0a20202020202020202022746f22203a207b0a20202020202020202020202022434c4f53455f5741495422203a20302c0a202020202020202020202020226f7468657222203a20302c0a2020202020202020202020202246494e5f574149545f3222203a20302c0a202020202020202020202020224c495354454e22203a20302c0a20202020202020202020202022434c4f53454422203a20302c0a20202020202020202020202022434c4f53494e4722203a20302c0a2020202020202020202020202253594e5f524543454956454422203a20302c0a202020202020202020202020224c4153545f41434b22203a20302c0a2020202020202020202020202254494d455f5741495422203a20302c0a2020202020202020202020202253594e5f53454e5422203a20302c0a2020202020202020202020202246494e5f574149545f3122203a20302c0a20202020202020202020202022554e4b4e4f574e22203a20302c0a2020202020202020202020202245535441424c495348454422203a20310a2020202020202020207d0a2020202020207d0a2020207d2c0a202020226572726f72537472696e6722203a2022222c0a202020226572726f7222203a202230220a7d0a +1.3.6.1.6.3.10.2.1.3.0|2|775505