In this third and final tutorial we are going to add FritzBox specific sensors to our MRTG service.
If you have not installed and configured your MRTG already, please see my first tutorial.
If you feel unsure how to add new custom sensors based on shell scripts, or you need more help on customizing the sensor parameters, please see my second tutorial.
To begin with, the problem with Fritz!OS is that it does not support SNMP. So, there is no simple way to access performance counters using MIBs or OIDs via MRTG. The protocol implemented in the Fritz!OS is called TR-064 or TR064, and is described by DSL Forum specification as "LAN Side DSL CPE Configuration". It does not make distinction between read and write permissions, unfortunately. In this sense, you need to configure on the FritzBox a specific user account with permissions to configure all FritzBox settings. Additionally, if you need to monitor Voice and Smart Home counters, you need to grant this account permissions there as well. I won’t go into details how to setup this user; you can find more information here.
We will not reinvent the wheel from scratch. Instead, we will utilize a MIT licensed, open-sourced code called FritzBoxShell (linked in the first reference). This project offers more than simple network monitoring. It also provides ways and means to configure your FritzBox from the home network. But this tutorial concentrates solely on reading information from your FritzBox router.
From the GitHub project, there are three files you will have to download. Two of these will require slight changes.
Let’s start with fritzBoxShell.sh. At the time of this writing, the current version is 1.0.8 and has not yet merged the pull request to support a new file format ‘mrtg’. We’ll update this in our shell file. We will also add a new action in the DSLState function. This will allow us to monitor DSL status such as current and maximum rates, noise, stream attenuation, CRC errors, and severely errored seconds.
Download the raw fritzBoxShell.sh file from the GitHub repository linked in the first reference below.
Add the following between lines 114 and 115 in the original document:
mrtg)
# convert to 2-line separated values for keys containing ‘BytesReceived’ or ‘BytesSent’ string
echo “$output” | awk ‘$1 ~ /Bytes(Received|Sent)$/ { print $2 }’
exit $rc
;;
The difference looks like that afterwards:

Then, between the original lines 399 and 400 (after the first correction they changed to 404 and 405) please add the following lines:
action=’GetStatisticsTotal’
readout
The difference now should look like that:

Finally, change the original line 833 and 834 – now 843 and 844 – to include ‘|mrtg’ as outputformat option; and add ‘–‘ at the front of the full-termed parameters as depicted below:

The second file to adjust, is fritzBoxShellConfig.sh. There you enter the information for the BoxIP (may be the FQDN fritz.box which would resolve to the IP unless you had changed the default DNS settings); the BoxUSER; and the BoxPW.
No change is needed in the fritzBoxShellTest.sh file.
Now you need to copy the three files to your MRTG server.
# Create a temporary directory in your home path
cd ~
mkdir temp
# Copy the FritzBoxShell* files to temp e.g. using SCP from your computer
# Make them executable, respectively RW for your user only
cd ~/temp
sudo chmod 750 fritzBoxShell.sh
sudo chmod 750 fritzBoxShellTest.sh
sudo chmod 640 fritzBoxShellConfig.sh
At this point, test if the script is running as expected, e.g. executing the command:
./fritzBoxShell.sh WAN STATE
If there is no output, or an error, please execute the script tester:
./fritzBoxShellTest.sh
Here a screenshot of my output:

Configure the first FritzBox Sensor – WAN Total Data
First off, we will need to copy the script files to a location where MRTG has access to:
# After testing and adjusting, copy the script files to /opt
# There they will apply the configured ACLs for root:root
sudo mkdir /opt/fritz
sudo cp ~/temp/* /opt/fritz/
Let’s create a new sensor in the mrtg.cfg file. You should already know how to do this from the previous tutorials:
#—————————–
# FritzBox WAN Total Data
#—————————–
Target[fritzbox_wan]: /opt/fritz/fritzBoxShell.sh WAN STATE -O mrtg
MaxBytes[fritzbox_wan]: 10737418240
Options[fritzbox_wan]: integer, gauge, nopercent, unknaszero
YLegend[fritzbox_wan]: Total Bytes
ShortLegend[fritzbox_wan]: B
LegendI[fritzbox_wan]: Received:
LegendO[fritzbox_wan]: Sent:
Legend1[fritzbox_wan]: Total Bytes Received
Legend2[fritzbox_wan]: Total Bytes Sent
Title[fritzbox_wan]: FritzBox WAN Total Data
PageTop[fritzbox_wan]: <H1>FritzBox WAN Total Data</H1>
Please be aware that the ‘-O mrtg’ statement will only work if you have customized the fritzBoxShell.sh file as described earlier in this document.
Pay attention to the MaxBytes value. It represents 10 Gibibytes based on my presumption that my household does not consume more than that per day. In fact, this will turn out to be higher. Also, it will turn out that this high number is not working as expected. More at the end of this tutorial.
Adding FritzBox DSL sensors
Note: the following examples only make sense if your uplink is DSL based. For IP based uplinks you might check the ‘IGDIP STATE’ output including information about the connection errors, the uptime, the external (public) IP address, and more.
If you want to monitor your DSL link performance, add the following sensor. An important thing to mention here is that this is not the utilization of your link, i.e. not how many bits per second you are really transferring. The two filtered variables NewUpstreamCurrRate and NewDownstreamCurrRate rather list the currently negotiated speed between your router and the DSLAM. Their counterparts, which we do not monitor here are the NewUpstreamMaxRate and NewUpstreamMaxRate which define the highest negotiable speed.
#—————————–
# FritzBox DSL Rate
#—————————–
Target[fritzbox_dslrate]: /opt/fritz/fritzBoxShell.sh DSL STATE | awk '$1 ~ /CurrRate$/ { print $2 }' | tac
MaxBytes1[fritzbox_dslrate]: 124977
MaxBytes2[fritzbox_dslrate]: 44211
Options[fritzbox_dslrate]: integer, gauge, unknaszero
Factor[fritzbox_dslrate]: 1000
YLegend[fritzbox_dslrate]: DSL Bandwidth
ShortLegend[fritzbox_dslrate]: bit/s
LegendI[fritzbox_dslrate]: Down:
LegendO[fritzbox_dslrate]: Up:
Legend1[fritzbox_dslrate]: Downstream Rate
Legend2[fritzbox_dslrate]: Upstream Rate
Title[fritzbox_dslrate]: FritzBox DSL Rate
PageTop[fritzbox_dslrate]: <H1>FritzBox DSL Rate</H1>
The last part of the Target line ‘| tac’ is flipping the positions of the down- and upstream values because DSL STATE returns upstream first. But logically, upstream corresponds to outgoing bytes’ rate.
Before we discuss the MaxBytes values, please note that we have added a Factor 1000 line. If you analyze the DSL STATE output, you will see that the output values of NewUpstreamCurrRate and NewDownstreamCurrRate (as well as the *MaxRate) are presented in kbit/s. Rather rare, but this is where we need to recalculate them to bit/s. Therefrom it may seem weird that I have not multiplied the values of MaxBites1 and MaxBites2 to 1000. But the reason for this was described in my second tutorial – in essence, it seems like these parameters correlate to the raw input and not the Factor-calculated one.
Another useful DSL sensor would be the quality of the DSL connection.
If you experience occasional drops of speed or reconnection attempts, you would like to know why is this happening. Even without being a DSL engineer, you could still monitor anomalies in the performance counters of the DSL line. There are many of them. Here a selection of the DSL STATE output:

I have selected the ErrorSecs (ES) and SeverelyErroredSecs (SES) values based on this online document, but you can change to whatever you find relevant.
Here again, please be aware that it only works if you have customized the fritzBoxShell.sh file as described earlier in this document. Let’s create the new sensor:
#—————————–
# FritzBox DSL State
#—————————–
Target[fritzbox_dslstat]: /opt/fritz/fritzBoxShell.sh DSL STATE | awk '$1 ~ /ErroredSecs$/ { print $2 }'
MaxBytes[fritzbox_dslstat]: 10000
Options[fritzbox_dslstat]: integer, gauge, nopercent, unknaszero
YLegend[fritzbox_dslstat]: DSL Errors
ShortLegend[fritzbox_dslstat]: err/s
LegendI[fritzbox_dslstat]: ES:
LegendO[fritzbox_dslstat]: SES:
Legend1[fritzbox_dslstat]: Error Code Seconds
Legend2[fritzbox_dslstat]: Severely Errored Seconds
Title[fritzbox_dslstat]: FritzBox DSL State
PageTop[fritzbox_dslstat]: <H1>FritzBox DSL State</H1>
The MaxBytes value was based on an observation of the current output, roughly 8000 Error Code Seconds (ES). If your output is much lower, then adjust the MaxBytes value accordingly.
What you would expect from the graphs here, is either a constant or linear, slightly increasing diagram. Any anomaly of the linearity could mean that a part of the physical line between your router and the DSLAM is derogated.
We near the end of our tutorial with the last observation, as promised by our first sensor:
WAN Total Data – the problem with UI4
When we configured the WAN total data consumption per day, we set a MaxBytes value of 10 Gibibytes. The first and foremost problem appeared after a couple of days. It showed a clear spiky pattern as illustrated below.

On the diagram it looks like the Received bytes reach nearly 4.4G and then start back from zero multiple times a day. The counters’ reset at 4am is by design and occurs simultaneously with the daily DSL link reset.
The first suspect was MRTG itself not being able to handle large values. But again, our MaxBytes are higher than 4.4GB. And if we presume that when the Target keyword includes a script instead of OIDs, it can only handle 32-bit integers instead of 64-bit, why would it increment after the first peak, instead of returning only zeros or errors? An integer overflow wraparound? This could only happen if the value returned from the script was higher than a 32-bit integer.
To verify this, I’ve then manually checked the output during some of the "0-valleys"-times and was surprised to see the FritzBoxShell command itself is returning the low values. In this example, the output from the command
sudo /opt/fritz/fritzBoxShell.sh WAN STATE
Was
NewTotalBytesReceived 8380559
NewTotalBytesSent 1292434892
NewTotalPacketsReceived 4450
NewTotalPacketsSent 1172423
This in a way correlates with the Current values represented in the above graph. And this shows much less received bytes as sent. Nonsense. By reading AVM TR064 documentation I found that the TotalBytesReceived and TotalBytesSent variables are of type UI4, which stands for 32-bit unsigned integer. Which is 2^32-1, or 4294967295. Now, that again correlates with the Max Received values from the diagram.
My presumption is that the TR064 starts the counting from zero when reaching the 32-bit limit, although internally the FritzBox shows the correct daily value. Sorry, in German only.

This means that in MRTG you will need to sum-up all the peak values of the day to get a rough estimate of the consumed bytes. Far from perfect, agree. Hope someone comes up with a better plan.
Reference:
FritzBoxShell on GitHub
https://github.com/jhubig/FritzBoxShell
MRTG online documentation
https://oss.oetiker.ch/mrtg/doc/mrtg-reference.en.html
AVM Developers Support
https://avm.de/service/schnittstellen/
FAQ-Explanations for Several Parameters About Error Code Statistics of MA5100’s ADSL Ports on NMS
https://support.huawei.com/enterprise/en/knowledge/EKB0000329288/