#!/usr/bin/bash
RC_OK = 0
RC_WARN = 1
RC_CRIT = 2
RC_UNKNOWN = 3
HOSTNAME = "fritz.box"
CHECK = "bandwidthdown"
MY_SCRIPT_NAME = $( basename " $0 " )
# Duration we wait for curl response.
MY_CURL_TIMEOUT = "5"
usage( ) {
echo " usage: $MY_SCRIPT_NAME [-f <function>] [-h hostname] [-b rate] [-j] [-d] "
echo " -f: function to be executed [Default: ${ CHECK } ] "
echo " -h: hostname or IP of the FRITZ!Box [Default: ${ HOSTNAME } ] "
echo " -b: rate to display. b, k, m. all in bytes"
echo " -j: JSON output"
echo " Does not accept any functions."
echo " Will display all output in JSON format."
echo " Useful for running in cron and ingesting into another program"
echo " -d: enable debug output"
echo
echo "functions:"
echo " linkuptime connection time in seconds"
echo " connection connection status"
echo " downstream maximum downstream on current connection (Downstream Sync)"
echo " upstream maximum upstream on current connection (Upstream Sync)"
echo " bandwidthdown current bandwidth down"
echo " bandwidthup current bandwidth up"
echo " totalbwdown total downloads"
echo " totalbwup total uploads"
echo
echo " Example: $MY_SCRIPT_NAME -f downstream -h 192.168.100.1 -b m "
exit ${ RC_UNKNOWN }
}
require_number( )
{
VAR = $1
MSG = $2
if [ [ ! " ${ VAR } " = ~ ^[ 0-9] +$ ] ] ; then
echo " ERROR - ${ MSG } ( ${ VAR } ) "
exit ${ RC_UNKNOWN }
fi
}
find_xml_value( )
{
XML = $1
VAL = $2
echo " ${ XML } " | grep " ${ VAL } " | sed " s/< ${ VAL } >\([^<]*\)<\/ ${ VAL } >/\1/ "
}
check_greater( )
{
VAL = $1
WARN = $2
CRIT = $3
MSG = $4
if [ " ${ VAL } " -gt " ${ WARN } " ] || [ " ${ WARN } " -eq 0 ] ; then
echo " OK - ${ MSG } "
exit ${ RC_OK }
elif [ " ${ VAL } " -gt " ${ CRIT } " ] || [ " ${ CRIT } " -eq 0 ] ; then
echo " WARNING - ${ MSG } "
exit ${ RC_WARN }
else
echo " CRITICAL - ${ MSG } "
exit ${ RC_CRIT }
fi
}
print_json( ) {
VERB1 = GetStatusInfo
URL1 = WANIPConn1
NS1 = WANIPConnection
VERB2 = GetCommonLinkProperties
URL2 = WANCommonIFC1
NS2 = WANCommonInterfaceConfig
VERB3 = GetAddonInfos
URL3 = WANCommonIFC1
NS3 = WANCommonInterfaceConfig
STATUS1 = $( curl --max-time " ${ MY_CURL_TIMEOUT } " " http:// ${ HOSTNAME } : ${ PORT } /igdupnp/control/ ${ URL1 } " \
-H "Content-Type: text/xml; charset=\"utf-8\"" \
-H " SoapAction:urn:schemas-upnp-org:service: ${ NS1 } :1# ${ VERB1 } " \
-d " <?xml version='1.0' encoding='utf-8'?> <s:Envelope s:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'> <s:Body> <u: ${ VERB1 } xmlns:u=\"urn:schemas-upnp-org:service: ${ NS1 } :1\" /> </s:Body> </s:Envelope> " \
-s)
if [ " $? " -ne "0" ] ; then
printf '{"Connection":"ERROR - Could not retrieve status from FRITZ!Box"}'
exit ${ RC_CRIT }
fi
STATUS2 = $( curl --max-time " ${ MY_CURL_TIMEOUT } " " http:// ${ HOSTNAME } : ${ PORT } /igdupnp/control/ ${ URL2 } " \
-H "Content-Type: text/xml; charset=\"utf-8\"" \
-H " SoapAction:urn:schemas-upnp-org:service: ${ NS2 } :1# ${ VERB2 } " \
-d " <?xml version='1.0' encoding='utf-8'?> <s:Envelope s:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'> <s:Body> <u: ${ VERB2 } xmlns:u=\"urn:schemas-upnp-org:service: ${ NS2 } :1\" /> </s:Body> </s:Envelope> " \
-s)
if [ " $? " -ne "0" ] ; then
printf '{"Connection":"ERROR - Could not retrieve status from FRITZ!Box"}'
exit ${ RC_CRIT }
fi
STATUS3 = $( curl --max-time " ${ MY_CURL_TIMEOUT } " " http:// ${ HOSTNAME } : ${ PORT } /igdupnp/control/ ${ URL3 } " \
-H "Content-Type: text/xml; charset=\"utf-8\"" \
-H " SoapAction:urn:schemas-upnp-org:service: ${ NS3 } :1# ${ VERB3 } " \
-d " <?xml version='1.0' encoding='utf-8'?> <s:Envelope s:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'> <s:Body> <u: ${ VERB3 } xmlns:u=\"urn:schemas-upnp-org:service: ${ NS3 } :1\" /> </s:Body> </s:Envelope> " \
-s)
if [ " $? " -ne "0" ] ; then
printf '{"Connection":"ERROR - Could not retrieve status from FRITZ!Box"}'
exit ${ RC_CRIT }
fi
CONNECTIONSTATUS = $( find_xml_value " ${ STATUS1 } " NewConnectionStatus)
UPTIME = $( find_xml_value " ${ STATUS1 } " NewUptime)
DOWNSTREAM = $( find_xml_value " ${ STATUS2 } " NewLayer1DownstreamMaxBitRate)
UPSTREAM = $( find_xml_value " ${ STATUS2 } " NewLayer1UpstreamMaxBitRate)
BANDWIDTHDOWNBYTES = $( find_xml_value " ${ STATUS3 } " NewByteReceiveRate)
BANDWIDTHUPBYTES = $( find_xml_value " ${ STATUS3 } " NewByteSendRate)
# NewByteReceiveRate and NewByteSendRate are 32 bit registers overflowing at 4.3*1e9 bytes
# Use the 64 bit registers instead:
# TOTALBWDOWNBYTES=$(find_xml_value "${STATUS3}" NewTotalBytesReceived)
# TOTALBWUPBYTES=$(find_xml_value "${STATUS3}" NewTotalBytesSent)
TOTALBWDOWNBYTES = $( find_xml_value " ${ STATUS3 } " NewX_AVM_DE_TotalBytesReceived64)
TOTALBWUPBYTES = $( find_xml_value " ${ STATUS3 } " NewX_AVM_DE_TotalBytesSent64)
if [ " ${ DEBUG } " -eq 1 ] ; then
echo "DEBUG - Status:"
echo " $CONNECTIONSTATUS "
echo " $UPTIME "
echo " $DOWNSTREAM "
echo " $UPSTREAM "
echo " $BANDWIDTHDOWNBYTES "
echo " $BANDWIDTHUPBYTES "
echo " $TOTALBWDOWNBYTES "
echo " $TOTALBWUPBYTES "
fi
printf '{"Connection":"%s","Uptime":%d,"UpstreamSync":%d,"DownstreamSync":%d,"UploadBW":%d,"DownloadBW":%d,"TotalUploads":%d,"TotalDownloads":%d}\n' " $CONNECTIONSTATUS " " $UPTIME " " $UPSTREAM " " $DOWNSTREAM " " $BANDWIDTHUPBYTES " " $BANDWIDTHDOWNBYTES " " $TOTALBWUPBYTES " " $TOTALBWDOWNBYTES "
exit #exit so we dont get unknown service check error
}
# Check Commands
command -v curl >/dev/null 2>& 1 || { echo >& 2 "ERROR: 'curl' is needed. Please install 'curl'. More details can be found at https://curl.haxx.se/" ; exit 1; }
command -v bc >/dev/null 2>& 1 || { echo >& 2 "ERROR: 'bc' is needed. Please install 'bc'." ; exit 1; }
PORT = 49000
DEBUG = 0
WARN = 0
CRIT = 0
RATE = 1
PRE =
while getopts h:jf:db: OPTNAME; do
case " ${ OPTNAME } " in
h)
HOSTNAME = " ${ OPTARG } "
; ;
j)
CHECK = ""
print_json
; ;
f)
CHECK = " ${ OPTARG } "
; ;
d)
DEBUG = 1
; ;
b)
case " ${ OPTARG } " in
b)
RATE = 1
PRE =
; ;
k)
RATE = 1000
PRE = kilo
; ;
m)
RATE = 1000000
PRE = mega
; ;
*)
echo "Wrong prefix"
; ;
esac
; ;
*)
echo " $OPTNAME "
usage
; ;
esac
done
case ${ CHECK } in
linkuptime| connection)
VERB = GetStatusInfo
URL = WANIPConn1
NS = WANIPConnection
; ;
downstream| upstream)
VERB = GetCommonLinkProperties
URL = WANCommonIFC1
NS = WANCommonInterfaceConfig
; ;
bandwidthup| bandwidthdown| totalbwup| totalbwdown)
VERB = GetAddonInfos
URL = WANCommonIFC1
NS = WANCommonInterfaceConfig
; ;
*)
echo " ERROR - Unknown service check ${ CHECK } "
exit ${ RC_UNKNOWN }
; ;
esac
STATUS = $( curl --max-time " ${ MY_CURL_TIMEOUT } " " http:// ${ HOSTNAME } : ${ PORT } /igdupnp/control/ ${ URL } " \
-H "Content-Type: text/xml; charset=\"utf-8\"" \
-H " SoapAction:urn:schemas-upnp-org:service: ${ NS } :1# ${ VERB } " \
-d " <?xml version='1.0' encoding='utf-8'?> <s:Envelope s:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'> <s:Body> <u: ${ VERB } xmlns:u=\"urn:schemas-upnp-org:service: ${ NS } :1\" /> </s:Body> </s:Envelope> " \
-s)
if [ " $? " -ne "0" ] ; then
echo "ERROR - Could not retrieve status from FRITZ!Box"
exit ${ RC_CRIT }
fi
if [ ${ DEBUG } -eq 1 ] ; then
echo "DEBUG - Status:"
echo " ${ STATUS } "
fi
case ${ CHECK } in
linkuptime)
UPTIME = $( find_xml_value " ${ STATUS } " NewUptime)
require_number " ${ UPTIME } " "Could not parse uptime"
HOURS = $(( ${ UPTIME } / 3600 ))
MINUTES = $(( ( ${ UPTIME } - ( ${ HOURS } * 3600 )) /60) )
SECONDS = $(( ${ UPTIME } - ( ${ HOURS } * 3600 ) - ( ${ MINUTES } * 60 )) )
RESULT = " Link uptime ${ UPTIME } seconds [ ${ HOURS } h ${ MINUTES } m ${ SECONDS } s] "
echo " ${ RESULT } "
; ;
upstream)
UPSTREAMBITS = $( find_xml_value " ${ STATUS } " NewLayer1UpstreamMaxBitRate)
require_number " ${ UPSTREAMBITS } " "Could not parse upstream"
UPSTREAM = $( echo " scale=3; $UPSTREAMBITS / $RATE " | bc)
RESULT = " Upstream ${ UPSTREAM } ${ PRE } bits per second "
echo " ${ RESULT } "
; ;
downstream)
DOWNSTREAMBITS = $( find_xml_value " ${ STATUS } " NewLayer1DownstreamMaxBitRate)
require_number " ${ DOWNSTREAMBITS } " "Could not parse downstream"
DOWNSTREAM = $( echo " scale=3; $DOWNSTREAMBITS / $RATE " | bc)
RESULT = " Downstream ${ DOWNSTREAM } ${ PRE } bits per second "
echo " ${ RESULT } "
; ;
bandwidthdown)
BANDWIDTHDOWNBYTES = $( find_xml_value " ${ STATUS } " NewByteReceiveRate)
BANDWIDTHDOWN = $( echo " scale=3; $BANDWIDTHDOWNBYTES / $RATE " | bc)
RESULT = " Current download ${ BANDWIDTHDOWN } ${ PRE } bytes per second "
echo " ${ RESULT } "
; ;
bandwidthup)
BANDWIDTHUPBYTES = $( find_xml_value " ${ STATUS } " NewByteSendRate)
BANDWIDTHUP = $( echo " scale=3; $BANDWIDTHUPBYTES / $RATE " | bc)
RESULT = " Current upload ${ BANDWIDTHUP } ${ PRE } bytes per second "
echo " ${ RESULT } "
; ;
totalbwdown)
TOTALBWDOWNBYTES = $( find_xml_value " ${ STATUS } " NewTotalBytesReceived)
TOTALBWDOWN = $( echo " scale=3; $TOTALBWDOWNBYTES / $RATE " | bc)
RESULT = " total download ${ TOTALBWDOWN } ${ PRE } bytes "
echo " $RESULT "
; ;
totalbwup)
TOTALBWUPBYTES = $( find_xml_value " ${ STATUS } " NewTotalBytesSent)
TOTALBWUP = $( echo " scale=3; $TOTALBWUPBYTES / $RATE " | bc)
RESULT = " total uploads ${ TOTALBWUP } ${ PRE } bytes "
echo " $RESULT "
; ;
connection)
STATE = $( find_xml_value " ${ STATUS } " NewConnectionStatus)
case ${ STATE } in
Connected)
echo "OK - Connected"
exit ${ RC_OK }
; ;
Connecting | Disconnected)
echo "WARNING - Connection lost"
exit ${ RC_WARN }
; ;
*)
echo " ERROR - Unknown connection state ${ STATE } "
exit ${ RC_UNKNOWN }
; ;
esac
; ;
*)
echo " ERROR - Unknown service check ${ CHECK } "
exit ${ RC_UNKNOWN }
esac