# shellcheck shell=bash disable=SC1117 # no need for shebang - this file is loaded from charts.d.plugin # SPDX-License-Identifier: GPL-3.0-or-later # netdata # real-time performance and health monitoring, done right! # (C) 2018 Costa Tsaousis # # _update_every is a special variable - it holds the number of seconds # between the calls of the _update() function libreswan_update_every=1 # the priority is used to sort the charts on the dashboard # 1 = the first chart libreswan_priority=90000 # set to 1, to run ipsec with sudo libreswan_sudo=1 # global variables to store our collected data # [TUNNELID] = TUNNELNAME # here we track the *latest* established tunnels # as detected by: ipsec whack --status declare -A libreswan_connected_tunnels=() # [TUNNELID] = VALUE # here we track values of all established tunnels (not only the latest) # as detected by: ipsec whack --trafficstatus declare -A libreswan_traffic_in=() declare -A libreswan_traffic_out=() declare -A libreswan_established_add_time=() # [TUNNELNAME] = CHARTID # here we remember CHARTIDs of all tunnels # we need this to avoid converting tunnel names to chart IDs on every iteration declare -A libreswan_tunnel_charts=() is_able_sudo_ipsec() { if ! sudo -n -l "${IPSEC_CMD}" whack --status > /dev/null 2>&1; then return 1 fi if ! sudo -n -l "${IPSEC_CMD}" whack --trafficstatus > /dev/null 2>&1; then return 1 fi return 0 } # run the ipsec command libreswan_ipsec() { if [ ${libreswan_sudo} -ne 0 ]; then sudo -n "${IPSEC_CMD}" "${@}" return $? else "${IPSEC_CMD}" "${@}" return $? fi } # fetch latest values - fill the arrays libreswan_get() { # do all the work to collect / calculate the values # for each dimension # empty the variables libreswan_traffic_in=() libreswan_traffic_out=() libreswan_established_add_time=() libreswan_connected_tunnels=() # convert the ipsec command output to a shell script # and source it to get the values # shellcheck disable=SC1090 source <( { libreswan_ipsec whack --status libreswan_ipsec whack --trafficstatus } | sed -n \ -e "s|[0-9]\+ #\([0-9]\+\): \"\(.*\)\".*IPsec SA established.*newest IPSEC.*|libreswan_connected_tunnels[\"\1\"]=\"\2\"|p" \ -e "s|[0-9]\+ #\([0-9]\+\): \"\(.*\)\",\{0,1\}.* add_time=\([0-9]\+\),.* inBytes=\([0-9]\+\),.* outBytes=\([0-9]\+\).*|libreswan_traffic_in[\"\1\"]=\"\4\"; libreswan_traffic_out[\"\1\"]=\"\5\"; libreswan_established_add_time[\"\1\"]=\"\3\";|p" ) || return 1 # check we got some data [ ${#libreswan_connected_tunnels[@]} -eq 0 ] && return 1 return 0 } # _check is called once, to find out if this chart should be enabled or not libreswan_check() { # this should return: # - 0 to enable the chart # - 1 to disable the chart require_cmd ipsec || return 1 # make sure it is libreswan # shellcheck disable=SC2143 if [ -z "$(ipsec --version | grep -i libreswan)" ]; then error "ipsec command is not Libreswan. Disabling Libreswan plugin." return 1 fi if [ ${libreswan_sudo} -ne 0 ] && ! is_able_sudo_ipsec; then error "not enough permissions to execute ipsec with sudo. Disabling Libreswan plugin." return 1 fi # check that we can collect data libreswan_get || return 1 return 0 } # create the charts for an ipsec tunnel libreswan_create_one() { local n="${1}" name name="${libreswan_connected_tunnels[${n}]}" [ -n "${libreswan_tunnel_charts[${name}]}" ] && return 0 libreswan_tunnel_charts[${name}]="$(fixid "${name}")" cat << EOF CHART libreswan.${libreswan_tunnel_charts[${name}]}_net '${name}_net' "LibreSWAN Tunnel ${name} Traffic" "kilobits/s" "${name}" libreswan.net area $((libreswan_priority)) $libreswan_update_every '' '' 'libreswan' DIMENSION in '' incremental 8 1000 DIMENSION out '' incremental -8 1000 CHART libreswan.${libreswan_tunnel_charts[${name}]}_uptime '${name}_uptime' "LibreSWAN Tunnel ${name} Uptime" "seconds" "${name}" libreswan.uptime line $((libreswan_priority + 1)) $libreswan_update_every '' '' 'libreswan' DIMENSION uptime '' absolute 1 1 EOF return 0 } # _create is called once, to create the charts libreswan_create() { local n for n in "${!libreswan_connected_tunnels[@]}"; do libreswan_create_one "${n}" done return 0 } libreswan_now=$(date +%s) # send the values to netdata for an ipsec tunnel libreswan_update_one() { local n="${1}" microseconds="${2}" name id uptime name="${libreswan_connected_tunnels[${n}]}" id="${libreswan_tunnel_charts[${name}]}" [ -z "${id}" ] && libreswan_create_one "${name}" uptime=$((libreswan_now - libreswan_established_add_time[${n}])) [ ${uptime} -lt 0 ] && uptime=0 # write the result of the work. cat << VALUESEOF BEGIN libreswan.${id}_net ${microseconds} SET in = ${libreswan_traffic_in[${n}]} SET out = ${libreswan_traffic_out[${n}]} END BEGIN libreswan.${id}_uptime ${microseconds} SET uptime = ${uptime} END VALUESEOF } # _update is called continuously, to collect the values libreswan_update() { # the first argument to this function is the microseconds since last update # pass this parameter to the BEGIN statement (see below). libreswan_get || return 1 libreswan_now=$(date +%s) local n for n in "${!libreswan_connected_tunnels[@]}"; do libreswan_update_one "${n}" "${@}" done return 0 }