Browse Source

Added IPsec Template, Detecting Package Update

master
Riccardo Bicelli 5 months ago
parent
commit
af39fd39ed
  1. 7
      README.md
  2. 342
      pfsense_zbx.php
  3. 241
      template_pfsense_active.xml
  4. 1080
      template_pfsense_active_ipsec.xml
  5. 6
      template_pfsense_active_ovpn_user.xml

7
README.md

@ -18,12 +18,19 @@ Tested with pfSense 2.4.x, Zabbix 4.0, Zabbix 5.0
- CARP Monitoring (Global CARP State)
- Basic Service Discovery and Monitoring (Service Status)
- pfSense Version/Update Available
- Packages Update Available
**Template pfSense Active: OpenVPN Server User Auth**
- Discovery of OpenVPN Clients connected to OpenVPN Servers in user auth mode
- Monitoring of Client Parameters (Bytes sent/received, Connection Time...)
**Template pfSense Active: IPsec**
- Discovery of IPsec Site-to-Site tunnels
- Monitoring tunnel status (Phase 1 and Phase 2)
## Configuration
First copy the file pfsense_zbx.php to your pfsense box (e.g. to /root/scripts).

342
pfsense_zbx.php

@ -1,7 +1,7 @@
<?php
/***
pfsense_zbx.php - pfSense Zabbix Interface
Version 0.9.3 - 2020-04-26
Version 1.0.2 - 2021-01-18
Written by Riccardo Bicelli <r.bicelli@gmail.com>
This program is licensed under Apache 2.0 License
@ -24,6 +24,8 @@ require_once("service-utils.inc");
//For System
require_once('pkg-utils.inc');
//For DHCP
//Testing function, for template creating purpose
function pfz_test(){
@ -55,7 +57,34 @@ function pfz_test(){
echo "Services: \n";
print_r($services);
echo $line;
echo "IPsec: \n";
require_once("ipsec.inc");
global $config;
init_config_arr(array('ipsec', 'phase1'));
init_config_arr(array('ipsec', 'phase2'));
$a_phase2 = &$config['ipsec']['phase2'];
$status = ipsec_list_sa();
echo "IPsec Status: \n";
print_r($status);
$a_phase1 = &$config['ipsec']['phase1'];
$a_phase2 = &$config['ipsec']['phase2'];
echo "IPsec Config Phase 1: \n";
print_r($a_phase1);
echo "IPsec Config Phase 2: \n";
print_r($a_phase2);
echo $line;
//Packages
echo "Packages: \n";
require_once("pkg-utils.inc");
$installed_packages = get_pkg_info('all', false, true);
print_r($installed_packages);
}
@ -334,6 +363,7 @@ function pfz_service_value($name,$value){
echo 0;
else
echo 1;
break;
default:
echo $service[$value];
break;
@ -381,18 +411,207 @@ function pfz_gw_value($gw, $valuekey) {
}
function pfz_carp_status(){
// IPSEC Discovery
function pfz_ipsec_discovery_ph1(){
require_once("ipsec.inc");
global $config;
init_config_arr(array('ipsec', 'phase1'));
$a_phase1 = &$config['ipsec']['phase1'];
$json_string = '{"data":[';
foreach ($a_phase1 as $data) {
$json_string .= '{"{#IKEID}":"' . $data['ikeid'] . '"';
$json_string .= ',"{#NAME}":"' . $data['descr'] . '"';
$json_string .= '},';
}
$json_string = rtrim($json_string,",");
$json_string .= "]}";
echo $json_string;
}
function pfz_ipsec_ph1($ikeid,$valuekey){
// Get Value from IPsec Phase 1 Configuration
// If Getting "disabled" value only check item presence in config array
require_once("ipsec.inc");
global $config;
init_config_arr(array('ipsec', 'phase1'));
$a_phase1 = &$config['ipsec']['phase1'];
$value = "";
switch ($valuekey) {
case 'status':
$value = pfz_ipsec_status($ikeid);
break;
case 'disabled':
$value = "0";
default:
foreach ($a_phase1 as $data) {
if ($data['ikeid'] == $ikeid) {
if(array_key_exists($valuekey,$data)) {
if ($valuekey=='disabled')
$value = "1";
else
$value = pfz_valuemap("ipsec." . $valuekey, $data[$valuekey], $data[$valuekey]);
break;
}
}
}
}
echo $value;
}
function pfz_ipsec_discovery_ph2(){
require_once("ipsec.inc");
global $config;
init_config_arr(array('ipsec', 'phase2'));
$a_phase2 = &$config['ipsec']['phase2'];
$json_string = '{"data":[';
foreach ($a_phase2 as $data) {
$json_string .= '{"{#IKEID}":"' . $data['ikeid'] . '"';
$json_string .= ',"{#NAME}":"' . $data['descr'] . '"';
$json_string .= ',"{#UNIQID}":"' . $data['uniqid'] . '"';
$json_string .= ',"{#REQID}":"' . $data['reqid'] . '"';
$json_string .= ',"{#EXTID}":"' . $data['ikeid'] . '.' . $data['reqid'] . '"';
$json_string .= '},';
}
$json_string = rtrim($json_string,",");
$json_string .= "]}";
echo $json_string;
}
function pfz_ipsec_ph2($uniqid, $valuekey){
require_once("ipsec.inc");
global $config;
init_config_arr(array('ipsec', 'phase2'));
$a_phase2 = &$config['ipsec']['phase2'];
$valuecfr = explode(".",$valuekey);
switch ($valuecfr[0]) {
case 'status':
$idarr = explode(".", $uniqid);
$statuskey = "state";
if (isset($valuecfr[1])) $statuskey = $valuecfr[1];
$value = pfz_ipsec_status($idarr[0],$idarr[1],$statuskey);
break;
case 'disabled':
$value = "0";
}
foreach ($a_phase2 as $data) {
if ($data['uniqid'] == $uniqid) {
if(array_key_exists($valuekey,$data)) {
if ($valuekey=='disabled')
$value = "1";
else
$value = pfz_valuemap("ipsec_ph2." . $valuekey, $data[$valuekey], $data[$valuekey]);
break;
}
}
}
echo $value;
}
function pfz_ipsec_status($ikeid,$reqid=-1,$valuekey='state'){
require_once("ipsec.inc");
global $config;
init_config_arr(array('ipsec', 'phase1'));
$a_phase1 = &$config['ipsec']['phase1'];
$status = ipsec_list_sa();
$ipsecconnected = array();
$carp_status = pfz_carp_status(false);
//Phase-Status match borrowed from status_ipsec.php
if (is_array($status)) {
foreach ($status as $l_ikeid=>$ikesa) {
if(isset($ikesa['con-id'])){
$con_id = substr($ikesa['con-id'], 3);
}else{
$con_id = filter_var($l_ikeid, FILTER_SANITIZE_NUMBER_INT);
}
if ($ikesa['version'] == 1) {
$ph1idx = substr($con_id, 0, strrpos(substr($con_id, 0, -1), '00'));
$ipsecconnected[$ph1idx] = $ph1idx;
} else {
if (!ipsec_ikeid_used($con_id)) {
// probably a v2 with split connection then
$ph1idx = substr($con_id, 0, strrpos(substr($con_id, 0, -1), '00'));
$ipsecconnected[$ph1idx] = $ph1idx;
} else {
$ipsecconnected[$con_id] = $ph1idx = $con_id;
}
}
if ($ph1idx == $ikeid){
if ($reqid!=-1) {
// Asking for Phase2 Status Value
foreach ($ikesa['child-sas'] as $childsas) {
if ($childsas['reqid']==$reqid) {
if ($childsas['state'] == 'REKEYED') {
//if state is rekeyed go on
$tmp_value = $childsas[$valuekey];
} else {
$tmp_value = $childsas[$valuekey];
break;
}
}
}
} else {
$tmp_value = $ikesa[$valuekey];
}
break;
}
}
}
switch($valuekey) {
case 'state':
$value = pfz_valuemap('ipsec.state', strtolower($tmp_value));
$value = $value + (10 * ($carp_status-1));
break;
default:
$value = $tmp_value;
break;
}
// print_r($ikesa);
return $value;
}
function pfz_carp_status($echo = true){
//Detect CARP Status
global $config;
$status_return = 0;
$status = get_carp_status();
$carp_detected_problems = get_single_sysctl("net.inet.carp.demotion");
//CARP is disabled
$ret = 0;
if ($status != 0) { //CARP is enabled
if ($carp_detected_problems != 0) {
echo 4; //There's some Major Problems with CARP
return true;
//There's some Major Problems with CARP
$ret = 4;
if ($echo == true) echo $ret;
return $ret;
}
$status_changed = false;
@ -410,19 +629,55 @@ function pfz_carp_status(){
}
if ($status_changed) {
//CARP Status is inconsistent across interfaces
$ret=3;
echo 3;
} else {
if ($prev_status=="MASTER")
echo 1;
$ret = 1;
else
echo 2;
$ret = 2;
}
} else {
//CARP is Disabled
echo 0;
}
if ($echo == true) echo $ret;
return $ret;
}
function pfz_dhcpfailover_discovery(){
//System functions regarding DHCP Leases will be available in the upcoming release of pfSense, so let's wait
require_once("system.inc");
$leases = system_get_dhcpleases();
$json_string = '{"data":[';
if (count($leases['failover']) > 0){
foreach ($leases['failover'] as $data){
$json_string .= '{"{#FAILOVER_GROUP}":"' . str_replace(" ", "__", $data['name']) . '"';
}
}
$json_string = rtrim($json_string,",");
$json_string .= "]}";
echo $json_string;
}
//Packages
function pfz_packages_uptodate(){
require_once("pkg-utils.inc");
$installed_packages = get_pkg_info('all', false, true);
$ret = 0;
foreach ($installed_packages as $package){
if ($package['version']!=$package['installed_version']){
$ret ++;
}
}
return $ret;
}
//System Information
function pfz_get_system_value($section){
@ -440,13 +695,17 @@ function pfz_get_system_value($section){
else
echo "1";
break;
case "packages_update":
echo pfz_packages_uptodate();
break;
}
}
// Value mappings
// Each value map is represented by an associative array
function pfz_valuemap($valuename, $value){
function pfz_valuemap($valuename, $value, $default="0"){
switch ($valuename){
@ -485,13 +744,55 @@ function pfz_valuemap($valuename, $value){
"highloss" => "3",
"force_down" => "4",
"down" => "5");
break;
break;
case "ipsec.iketype":
$valuemap = array (
"auto" => 0,
"ikev1" => 1,
"ikev2" => 2);
break;
case "ipsec.mode":
$valuemap = array (
"main" => 0,
"aggressive" => 1);
break;
case "ipsec.protocol":
$valuemap = array (
"both" => 0,
"inet" => 1,
"inet6" => 2);
break;
case "ipsec_ph2.mode":
$valuemap = array (
"transport" => 0,
"tunnel" => 1,
"tunnel6" => 2);
break;
case "ipsec_ph2.protocol":
$valuemap = array (
"esp" => 1,
"ah" => 2);
break;
case "ipsec.state":
$valuemap = array (
"established" => 1,
"connecting" => 2,
"installed" => 1,
"rekeyed" => 2);
break;
}
if (array_key_exists($value, $valuemap))
return $valuemap[$value];
return "0";
return $default;
}
//Argument parsers for Discovery
@ -515,6 +816,15 @@ function pfz_discovery($section){
case "interfaces":
pfz_interface_discovery();
break;
case "ipsec_ph1":
pfz_ipsec_discovery_ph1();
break;
case "ipsec_ph2":
pfz_ipsec_discovery_ph2();
break;
case "dhcpfailover":
pfz_dhcpfailover_discovery();
break;
}
}
@ -553,6 +863,12 @@ switch (strtolower($argv[1])){
case "system":
pfz_get_system_value($argv[2]);
break;
case "ipsec_ph1":
pfz_ipsec_ph1($argv[2],$argv[3]);
break;
case "ipsec_ph2":
pfz_ipsec_ph2($argv[2],$argv[3]);
break;
default:
pfz_test();
}

241
template_pfsense_active.xml

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<zabbix_export>
<version>4.0</version>
<date>2020-07-12T20:15:44Z</date>
<date>2021-01-18T15:00:52Z</date>
<groups>
<group>
<name>Templates/Network Devices</name>
@ -12,7 +12,7 @@
<template>Template pfSense Active</template>
<name>pfsense Active</name>
<description>Active template for pfsense, requires pfsense_zbx.php installed to pfSense Box.&#13;
Version 1.0.1&#13;
Version 1.0.2&#13;
&#13;
https://github.com/rbicelli/pfsense-zabbix-template</description>
<groups>
@ -954,6 +954,65 @@ https://github.com/rbicelli/pfsense-zabbix-template</description>
<master_item/>
</item>
<item>
<name>Packages Needing Update</name>
<type>7</type>
<snmp_community/>
<snmp_oid/>
<key>pfsense.value[system,packages_update]</key>
<delay>1d</delay>
<history>90d</history>
<trends>365d</trends>
<status>0</status>
<value_type>3</value_type>
<allowed_hosts/>
<units/>
<snmpv3_contextname/>
<snmpv3_securityname/>
<snmpv3_securitylevel>0</snmpv3_securitylevel>
<snmpv3_authprotocol>0</snmpv3_authprotocol>
<snmpv3_authpassphrase/>
<snmpv3_privprotocol>0</snmpv3_privprotocol>
<snmpv3_privpassphrase/>
<params/>
<ipmi_sensor/>
<authtype>0</authtype>
<username/>
<password/>
<publickey/>
<privatekey/>
<port/>
<description>Number of packages needing update.</description>
<inventory_link>0</inventory_link>
<applications>
<application>
<name>System</name>
</application>
</applications>
<valuemap/>
<logtimefmt/>
<preprocessing/>
<jmx_endpoint/>
<timeout>3s</timeout>
<url/>
<query_fields/>
<posts/>
<status_codes>200</status_codes>
<follow_redirects>1</follow_redirects>
<post_type>0</post_type>
<http_proxy/>
<headers/>
<retrieve_mode>0</retrieve_mode>
<request_method>0</request_method>
<output_format>0</output_format>
<allow_traps>0</allow_traps>
<ssl_cert_file/>
<ssl_key_file/>
<ssl_key_password/>
<verify_peer>0</verify_peer>
<verify_host>0</verify_host>
<master_item/>
</item>
<item>
<name>pfSense Available Version</name>
<type>7</type>
<snmp_community/>
@ -3045,7 +3104,7 @@ https://github.com/rbicelli/pfsense-zabbix-template</description>
<snmp_community/>
<snmp_oid/>
<key>pfsense.discovery[gw]</key>
<delay>30s</delay>
<delay>300s</delay>
<status>0</status>
<allowed_hosts/>
<snmpv3_contextname/>
@ -3077,7 +3136,7 @@ https://github.com/rbicelli/pfsense-zabbix-template</description>
<snmp_community/>
<snmp_oid/>
<key>pfsense.value[gw_value,{#GATEWAY},delay]</key>
<delay>30s</delay>
<delay>60s</delay>
<history>90d</history>
<trends>365d</trends>
<status>0</status>
@ -3142,7 +3201,7 @@ https://github.com/rbicelli/pfsense-zabbix-template</description>
<snmp_community/>
<snmp_oid/>
<key>pfsense.value[gw_value,{#GATEWAY},loss]</key>
<delay>30s</delay>
<delay>60s</delay>
<history>90d</history>
<trends>365d</trends>
<status>0</status>
@ -3207,7 +3266,7 @@ https://github.com/rbicelli/pfsense-zabbix-template</description>
<snmp_community/>
<snmp_oid/>
<key>pfsense.value[gw_value,{#GATEWAY},status]</key>
<delay>30s</delay>
<delay>60s</delay>
<history>90d</history>
<trends>365d</trends>
<status>0</status>
@ -3269,7 +3328,7 @@ https://github.com/rbicelli/pfsense-zabbix-template</description>
<snmp_community/>
<snmp_oid/>
<key>pfsense.value[gw_value,{#GATEWAY},stddev]</key>
<delay>30s</delay>
<delay>60s</delay>
<history>90d</history>
<trends>365d</trends>
<status>0</status>
@ -3549,6 +3608,71 @@ https://github.com/rbicelli/pfsense-zabbix-template</description>
<description>Discovery of network interfaces as defined in global regular expression &quot;Network interfaces for discovery&quot;.</description>
<item_prototypes>
<item_prototype>
<name>Incoming Errors on {#IFDESCR}</name>
<type>7</type>
<snmp_community/>
<snmp_oid/>
<key>net.if.in[{#IFNAME},errors]</key>
<delay>60</delay>
<history>7d</history>
<trends>365d</trends>
<status>0</status>
<value_type>3</value_type>
<allowed_hosts/>
<units/>
<snmpv3_contextname/>
<snmpv3_securityname/>
<snmpv3_securitylevel>0</snmpv3_securitylevel>
<snmpv3_authprotocol>0</snmpv3_authprotocol>
<snmpv3_authpassphrase/>
<snmpv3_privprotocol>0</snmpv3_privprotocol>
<snmpv3_privpassphrase/>
<params/>
<ipmi_sensor/>
<authtype>0</authtype>
<username/>
<password/>
<publickey/>
<privatekey/>
<port/>
<description/>
<inventory_link>0</inventory_link>
<applications>
<application>
<name>Network interfaces</name>
</application>
</applications>
<valuemap/>
<logtimefmt/>
<preprocessing>
<step>
<type>10</type>
<params/>
</step>
</preprocessing>
<jmx_endpoint/>
<timeout>3s</timeout>
<url/>
<query_fields/>
<posts/>
<status_codes>200</status_codes>
<follow_redirects>1</follow_redirects>
<post_type>0</post_type>
<http_proxy/>
<headers/>
<retrieve_mode>0</retrieve_mode>
<request_method>0</request_method>
<output_format>0</output_format>
<allow_traps>0</allow_traps>
<ssl_cert_file/>
<ssl_key_file/>
<ssl_key_password/>
<verify_peer>0</verify_peer>
<verify_host>0</verify_host>
<application_prototypes/>
<master_item/>
</item_prototype>
<item_prototype>
<name>Incoming network traffic on {#IFDESCR}</name>
<type>7</type>
<snmp_community/>
@ -3618,6 +3742,71 @@ https://github.com/rbicelli/pfsense-zabbix-template</description>
<master_item/>
</item_prototype>
<item_prototype>
<name>Outgoing errors on {#IFDESCR}</name>
<type>7</type>
<snmp_community/>
<snmp_oid/>
<key>net.if.out[{#IFNAME},errors]</key>
<delay>60</delay>
<history>7d</history>
<trends>365d</trends>
<status>0</status>
<value_type>3</value_type>
<allowed_hosts/>
<units/>
<snmpv3_contextname/>
<snmpv3_securityname/>
<snmpv3_securitylevel>0</snmpv3_securitylevel>
<snmpv3_authprotocol>0</snmpv3_authprotocol>
<snmpv3_authpassphrase/>
<snmpv3_privprotocol>0</snmpv3_privprotocol>
<snmpv3_privpassphrase/>
<params/>
<ipmi_sensor/>
<authtype>0</authtype>
<username/>
<password/>
<publickey/>
<privatekey/>
<port/>
<description/>
<inventory_link>0</inventory_link>
<applications>
<application>
<name>Network interfaces</name>
</application>
</applications>
<valuemap/>
<logtimefmt/>
<preprocessing>
<step>
<type>10</type>
<params/>
</step>
</preprocessing>
<jmx_endpoint/>
<timeout>3s</timeout>
<url/>
<query_fields/>
<posts/>
<status_codes>200</status_codes>
<follow_redirects>1</follow_redirects>
<post_type>0</post_type>
<http_proxy/>
<headers/>
<retrieve_mode>0</retrieve_mode>
<request_method>0</request_method>
<output_format>0</output_format>
<allow_traps>0</allow_traps>
<ssl_cert_file/>
<ssl_key_file/>
<ssl_key_password/>
<verify_peer>0</verify_peer>
<verify_host>0</verify_host>
<application_prototypes/>
<master_item/>
</item_prototype>
<item_prototype>
<name>Outgoing network traffic on {#IFDESCR}</name>
<type>7</type>
<snmp_community/>
@ -3760,7 +3949,7 @@ https://github.com/rbicelli/pfsense-zabbix-template</description>
<snmp_community/>
<snmp_oid/>
<key>pfsense.discovery[openvpn_client]</key>
<delay>30s</delay>
<delay>300s</delay>
<status>0</status>
<allowed_hosts/>
<snmpv3_contextname/>
@ -3792,7 +3981,7 @@ https://github.com/rbicelli/pfsense-zabbix-template</description>
<snmp_community/>
<snmp_oid/>
<key>pfsense.value[openvpn_clientvalue,{#CLIENT},status]</key>
<delay>30s</delay>
<delay>60s</delay>
<history>90d</history>
<trends>365d</trends>
<status>0</status>
@ -3894,7 +4083,7 @@ https://github.com/rbicelli/pfsense-zabbix-template</description>
<snmp_community/>
<snmp_oid/>
<key>pfsense.discovery[openvpn_server]</key>
<delay>30s</delay>
<delay>300s</delay>
<status>0</status>
<allowed_hosts/>
<snmpv3_contextname/>
@ -4210,7 +4399,7 @@ https://github.com/rbicelli/pfsense-zabbix-template</description>
<snmp_community/>
<snmp_oid/>
<key>pfsense.discovery[services]</key>
<delay>30s</delay>
<delay>300s</delay>
<status>0</status>
<allowed_hosts/>
<snmpv3_contextname/>
@ -4304,7 +4493,7 @@ https://github.com/rbicelli/pfsense-zabbix-template</description>
<snmp_community/>
<snmp_oid/>
<key>pfsense.value[service_value,{#SERVICE},status]</key>
<delay>30s</delay>
<delay>60s</delay>
<history>90d</history>
<trends>365d</trends>
<status>0</status>
@ -4868,6 +5057,18 @@ or&#13;
<httptests/>
<macros>
<macro>
<macro>{$CARP_SERVICES_STOPPED}</macro>
<value>^(haproxy|openvpn)$</value>
</macro>
<macro>
<macro>{$CARP_SLAVE_SERVICES:&quot;haproxy&quot;}</macro>
<value>0</value>
</macro>
<macro>
<macro>{$CARP_SLAVE_SERVICES:&quot;openvpn&quot;}</macro>
<value>0</value>
</macro>
<macro>
<macro>{$EXPECTED_CARP_STATUS}</macro>
<value>0</value>
</macro>
@ -5182,6 +5383,22 @@ or&#13;
<tags/>
</trigger>
<trigger>
<expression>{Template pfSense Active:pfsense.value[system,packages_update].last()}&gt;0</expression>
<recovery_mode>0</recovery_mode>
<recovery_expression/>
<name>Packages Update Available on {HOST.NAME}</name>
<correlation_mode>0</correlation_mode>
<correlation_tag/>
<url/>
<status>0</status>
<priority>1</priority>
<description>Notify of new version of packages are available</description>
<type>0</type>
<manual_close>0</manual_close>
<dependencies/>
<tags/>
</trigger>
<trigger>
<expression>{Template pfSense Active:pfsense.value[gw_status].diff()}&gt;0</expression>
<recovery_mode>1</recovery_mode>
<recovery_expression>{Template pfSense Active:pfsense.value[gw_status].diff()}=0</recovery_expression>

1080
template_pfsense_active_ipsec.xml
File diff suppressed because it is too large
View File

6
template_pfsense_active_ovpn_user.xml

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<zabbix_export>
<version>4.0</version>
<date>2020-07-12T06:37:29Z</date>
<date>2021-01-18T15:02:06Z</date>
<groups>
<group>
<name>Templates/Network Devices</name>
@ -15,7 +15,7 @@
Monitor client Connections of OpenVPN Server.&#13;
&#13;
Requires pfsense_zbx.php installed to pfSense Box.&#13;
Version 1.0.1&#13;
Version 1.0.2&#13;
&#13;
https://github.com/rbicelli/pfsense-zabbix-template</description>
<groups>
@ -36,7 +36,7 @@ https://github.com/rbicelli/pfsense-zabbix-template</description>
<snmp_community/>
<snmp_oid/>
<key>pfsense.discovery[openvpn_server_user]</key>
<delay>30s</delay>
<delay>60s</delay>
<status>0</status>
<allowed_hosts/>
<snmpv3_contextname/>

Loading…
Cancel
Save