From mboxrd@z Thu Jan 1 00:00:00 1970 From: Adolf Belka To: development@lists.ipfire.org Subject: Re: [PATCH] graphs.pl: Fixes graph failure when the DROP_HOSTILE directory is missing Date: Wed, 14 Feb 2024 14:24:40 +0100 Message-ID: In-Reply-To: <14259E27-24DA-4C69-AF6D-C211FFD943CD@ipfire.org> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============6986187317172934363==" List-Id: --===============6986187317172934363== Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Hi Michael, On 14/02/2024 13:59, Michael Tremer wrote: > Hello Adolf, >=20 > The fix technically looks fine. It would have been more elegant to put the = strings into a big array and then add only the ones that we need to avoid cop= ying the large block. I also thought there must be a more elegant way but I had no idea how to=20 create it. >=20 > However, this is fine for me to be merged. I can always look at doing a later code tidy up. I will have a look at=20 how to use the array approach when its a bit quieter. Regards, Adolf. >=20 > -Michael >=20 >> On 14 Feb 2024, at 10:34, Adolf Belka wrote: >> >> - If a fresh install is done then only the DROP_HOSTILE_IN & DROP_HOSTILE_= OUT >> rrd directories are created. >> - With the DROP_HOSTILE directory missing then when the fwhits graph is up= dated an error >> message is caused by the inability to open the required files. >> - This patch adds an if/else loop into the fwhits graph code to deal with = the two cases >> of the DROP_HOSTILE being present or not depending on the history and i= f a backup with >> logs has been restored from when DROP_HOSTILE was in use. >> - Tested on vm testbed and created a historical line for the hostile data = when it was not >> split >> - There might be a simpler or better approach than this but it was the onl= y option I >> could identify. I couldn't find anything about being able to use if loo= ps within the >> RRD::Graph loop >> >> Tested-by: Adolf Belka >> Signed-off-by: Adolf Belka >> --- >> config/cfgroot/graphs.pl | 237 ++++++++++++++++++++++++++------------- >> 1 file changed, 158 insertions(+), 79 deletions(-) >> >> diff --git a/config/cfgroot/graphs.pl b/config/cfgroot/graphs.pl >> index a23e49c98..96c6c26ea 100644 >> --- a/config/cfgroot/graphs.pl >> +++ b/config/cfgroot/graphs.pl >> @@ -13,7 +13,7 @@ >> # This program is distributed in the hope that it will be useful, = # >> # but WITHOUT ANY WARRANTY; without even the implied warranty of = # >> # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the = # >> -# GNU General Public License for more details. = # >> +# GNU General Public License for more details. = #update.sh >> # = # >> # You should have received a copy of the GNU General Public License = # >> # along with this program. If not, see . = # >> @@ -676,84 +676,163 @@ sub updatevpnn2ngraph { >> >> sub updatefwhitsgraph { >> my $period =3D $_[0]; >> - RRDs::graph( >> - @GRAPH_ARGS, >> - "-", >> - "--start", >> - "-1".$period, >> - "-r", >> - "-t ".$Lang::tr{'firewall hits per'}." ".$Lang::tr{$period."-graph"}, >> - "-v ".$Lang::tr{'bytes per second'}, >> - "--color=3DSHADEA".$color{"color19"}, >> - "--color=3DSHADEB".$color{"color19"}, >> - "--color=3DBACK".$color{"color21"}, >> - "DEF:output=3D".$mainsettings{'RRDLOG'}."/collectd/localhost/iptables-fi= lter-POLICYOUT/ipt_bytes-DROP_OUTPUT.rrd:value:AVERAGE", >> - "DEF:input=3D".$mainsettings{'RRDLOG'}."/collectd/localhost/iptables-fil= ter-POLICYIN/ipt_bytes-DROP_INPUT.rrd:value:AVERAGE", >> - "DEF:forward=3D".$mainsettings{'RRDLOG'}."/collectd/localhost/iptables-f= ilter-POLICYFWD/ipt_bytes-DROP_FORWARD.rrd:value:AVERAGE", >> - "DEF:newnotsyn=3D".$mainsettings{'RRDLOG'}."/collectd/localhost/iptables= -filter-NEWNOTSYN/ipt_bytes-DROP_NEWNOTSYN.rrd:value:AVERAGE", >> - "DEF:portscan=3D".$mainsettings{'RRDLOG'}."/collectd/localhost/iptables-= filter-PSCAN/ipt_bytes-DROP_PScan.rrd:value:AVERAGE", >> - "DEF:spoofedmartian=3D".$mainsettings{'RRDLOG'}."/collectd/localhost/ipt= ables-filter-SPOOFED_MARTIAN/ipt_bytes-DROP_SPOOFED_MARTIAN.rrd:value:AVERAGE= ", >> - "DEF:hostilein=3D".$mainsettings{'RRDLOG'}."/collectd/localhost/iptables= -filter-HOSTILE_DROP_IN/ipt_bytes-DROP_HOSTILE.rrd:value:AVERAGE", >> - "DEF:hostileout=3D".$mainsettings{'RRDLOG'}."/collectd/localhost/iptable= s-filter-HOSTILE_DROP_OUT/ipt_bytes-DROP_HOSTILE.rrd:value:AVERAGE", >> - "DEF:hostilelegacy=3D".$mainsettings{'RRDLOG'}."/collectd/localhost/ipta= bles-filter-HOSTILE_DROP/ipt_bytes-DROP_HOSTILE.rrd:value:AVERAGE", >> - >> - # This creates a new combined hostile segment. >> - # Previously we did not split into incoming/outgoing, but we cannot go b= ack in time. This CDEF will take the values >> - # from the old RRD database unless those are UNKNOWN (i.e. we started co= llected IN/OUT). If the values are unknown, >> - # we replace them with them sum of IN + OUT. >> - "CDEF:hostile=3Dhostilelegacy,UN,hostilein,hostileout,+,hostilelegacy,IF= ", >> - >> - "COMMENT:".sprintf("%-26s",$Lang::tr{'caption'}), >> - "COMMENT:".sprintf("%15s",$Lang::tr{'maximal'}), >> - "COMMENT:".sprintf("%15s",$Lang::tr{'average'}), >> - "COMMENT:".sprintf("%14s",$Lang::tr{'minimal'}), >> - "COMMENT:".sprintf("%15s",$Lang::tr{'current'})."\\j", >> - "AREA:output".$color{"color25"}."A0:".sprintf("%-25s",$Lang::tr{'firewal= lhits'}." (OUTPUT)"), >> - "GPRINT:output:MAX:%8.1lf %sBps", >> - "GPRINT:output:AVERAGE:%8.1lf %sBps", >> - "GPRINT:output:MIN:%8.1lf %sBps", >> - "GPRINT:output:LAST:%8.1lf %sBps\\j", >> - "STACK:forward".$color{"color23"}."A0:".sprintf("%-25s",$Lang::tr{'firew= allhits'}." (FORWARD)"), >> - "GPRINT:forward:MAX:%8.1lf %sBps", >> - "GPRINT:forward:AVERAGE:%8.1lf %sBps", >> - "GPRINT:forward:MIN:%8.1lf %sBps", >> - "GPRINT:forward:LAST:%8.1lf %sBps\\j", >> - "STACK:input".$color{"color24"}."A0:".sprintf("%-25s",$Lang::tr{'firewal= lhits'}." (INPUT)"), >> - "GPRINT:input:MAX:%8.1lf %sBps", >> - "GPRINT:input:AVERAGE:%8.1lf %sBps", >> - "GPRINT:input:MIN:%8.1lf %sBps", >> - "GPRINT:input:LAST:%8.1lf %sBps\\j", >> - "STACK:newnotsyn".$color{"color14"}."A0:".sprintf("%-25s","NewNotSYN"), >> - "GPRINT:newnotsyn:MAX:%8.1lf %sBps", >> - "GPRINT:newnotsyn:AVERAGE:%8.1lf %sBps", >> - "GPRINT:newnotsyn:MIN:%8.1lf %sBps", >> - "GPRINT:newnotsyn:LAST:%8.1lf %sBps\\j", >> - "STACK:portscan".$color{"color16"}."A0:".sprintf("%-25s",$Lang::tr{'port= scans'}), >> - "GPRINT:portscan:MAX:%8.1lf %sBps", >> - "GPRINT:portscan:AVERAGE:%8.1lf %sBps", >> - "GPRINT:portscan:MIN:%8.1lf %sBps", >> - "GPRINT:portscan:LAST:%8.1lf %sBps\\j", >> - "STACK:spoofedmartian".$color{"color12"}."A0:".sprintf("%-25s",$Lang::tr= {'spoofed or martians'}), >> - "GPRINT:spoofedmartian:MAX:%8.1lf %sBps", >> - "GPRINT:spoofedmartian:AVERAGE:%8.1lf %sBps", >> - "GPRINT:spoofedmartian:MIN:%8.1lf %sBps", >> - "GPRINT:spoofedmartian:LAST:%8.1lf %sBps\\j", >> - "STACK:hostilein".$color{"color13"}."A0:".sprintf("%-25s",$Lang::tr{'hos= tile networks in'}), >> - "GPRINT:hostilein:MAX:%8.1lf %sBps", >> - "GPRINT:hostilein:AVERAGE:%8.1lf %sBps", >> - "GPRINT:hostilein:MIN:%8.1lf %sBps", >> - "GPRINT:hostilein:LAST:%8.1lf %sBps\\j", >> - "STACK:hostileout".$color{"color25"}."A0:".sprintf("%-25s",$Lang::tr{'ho= stile networks out'}), >> - "GPRINT:hostileout:MAX:%8.1lf %sBps", >> - "GPRINT:hostileout:AVERAGE:%8.1lf %sBps", >> - "GPRINT:hostileout:MIN:%8.1lf %sBps", >> - "GPRINT:hostileout:LAST:%8.1lf %sBps\\j", >> - "LINE:hostile#000000A0:".sprintf("%-25s",$Lang::tr{'hostile networks tot= al'}), >> - "GPRINT:hostile:MAX:%8.1lf %sBps", >> - "GPRINT:hostile:AVERAGE:%8.1lf %sBps", >> - "GPRINT:hostile:MIN:%8.1lf %sBps", >> - "GPRINT:hostile:LAST:%8.1lf %sBps\\j", >> - ); >> + if ( -e "$mainsettings{'RRDLOG'}/collectd/localhost/iptables-filter-HOST= ILE_DROP/ipt_bytes-DROP_HOSTILE.rrd" ) { >> + RRDs::graph( >> + @GRAPH_ARGS, >> + "-", >> + "--start", >> + "-1".$period, >> + "-r", >> + "-t ".$Lang::tr{'firewall hits per'}." ".$Lang::tr{$period."-graph"}, >> + "-v ".$Lang::tr{'bytes per second'}, >> + "--color=3DSHADEA".$color{"color19"}, >> + "--color=3DSHADEB".$color{"color19"}, >> + "--color=3DBACK".$color{"color21"}, >> + "DEF:output=3D".$mainsettings{'RRDLOG'}."/collectd/localhost/iptables-fi= lter-POLICYOUT/ipt_bytes-DROP_OUTPUT.rrd:value:AVERAGE", >> + "DEF:input=3D".$mainsettings{'RRDLOG'}."/collectd/localhost/iptables-fil= ter-POLICYIN/ipt_bytes-DROP_INPUT.rrd:value:AVERAGE", >> + "DEF:forward=3D".$mainsettings{'RRDLOG'}."/collectd/localhost/iptables-f= ilter-POLICYFWD/ipt_bytes-DROP_FORWARD.rrd:value:AVERAGE", >> + "DEF:newnotsyn=3D".$mainsettings{'RRDLOG'}."/collectd/localhost/iptables= -filter-NEWNOTSYN/ipt_bytes-DROP_NEWNOTSYN.rrd:value:AVERAGE", >> + "DEF:portscan=3D".$mainsettings{'RRDLOG'}."/collectd/localhost/iptables-= filter-PSCAN/ipt_bytes-DROP_PScan.rrd:value:AVERAGE", >> + "DEF:spoofedmartian=3D".$mainsettings{'RRDLOG'}."/collectd/localhost/ipt= ables-filter-SPOOFED_MARTIAN/ipt_bytes-DROP_SPOOFED_MARTIAN.rrd:value:AVERAGE= ", >> + "DEF:hostilein=3D".$mainsettings{'RRDLOG'}."/collectd/localhost/iptables= -filter-HOSTILE_DROP_IN/ipt_bytes-DROP_HOSTILE.rrd:value:AVERAGE", >> + "DEF:hostileout=3D".$mainsettings{'RRDLOG'}."/collectd/localhost/iptable= s-filter-HOSTILE_DROP_OUT/ipt_bytes-DROP_HOSTILE.rrd:value:AVERAGE", >> + "DEF:hostilelegacy=3D".$mainsettings{'RRDLOG'}."/collectd/localhost/ipta= bles-filter-HOSTILE_DROP/ipt_bytes-DROP_HOSTILE.rrd:value:AVERAGE", >> + >> + # This creates a new combined hostile segment. >> + # Previously we did not split into incoming/outgoing, but we cannot go b= ack in time. This CDEF will take the values >> + # from the old RRD database if it exists and if those values are UNKNOWN= (time period after Hostile was split into In and Out), >> + # we replace them with the sum of IN + OUT. >> + "CDEF:hostile=3Dhostilelegacy,UN,hostilein,hostileout,+,hostilelegacy,IF= ", >> + >> + "COMMENT:".sprintf("%-26s",$Lang::tr{'caption'}), >> + "COMMENT:".sprintf("%15s",$Lang::tr{'maximal'}), >> + "COMMENT:".sprintf("%15s",$Lang::tr{'average'}), >> + "COMMENT:".sprintf("%14s",$Lang::tr{'minimal'}), >> + "COMMENT:".sprintf("%15s",$Lang::tr{'current'})."\\j", >> + "AREA:output".$color{"color25"}."A0:".sprintf("%-25s",$Lang::tr{'firewal= lhits'}." (OUTPUT)"), >> + "GPRINT:output:MAX:%8.1lf %sBps", >> + "GPRINT:output:AVERAGE:%8.1lf %sBps", >> + "GPRINT:output:MIN:%8.1lf %sBps", >> + "GPRINT:output:LAST:%8.1lf %sBps\\j", >> + "STACK:forward".$color{"color23"}."A0:".sprintf("%-25s",$Lang::tr{'firew= allhits'}." (FORWARD)"), >> + "GPRINT:forward:MAX:%8.1lf %sBps", >> + "GPRINT:forward:AVERAGE:%8.1lf %sBps", >> + "GPRINT:forward:MIN:%8.1lf %sBps", >> + "GPRINT:forward:LAST:%8.1lf %sBps\\j", >> + "STACK:input".$color{"color24"}."A0:".sprintf("%-25s",$Lang::tr{'firewal= lhits'}." (INPUT)"), >> + "GPRINT:input:MAX:%8.1lf %sBps", >> + "GPRINT:input:AVERAGE:%8.1lf %sBps", >> + "GPRINT:input:MIN:%8.1lf %sBps", >> + "GPRINT:input:LAST:%8.1lf %sBps\\j", >> + "STACK:newnotsyn".$color{"color14"}."A0:".sprintf("%-25s","NewNotSYN"), >> + "GPRINT:newnotsyn:MAX:%8.1lf %sBps", >> + "GPRINT:newnotsyn:AVERAGE:%8.1lf %sBps", >> + "GPRINT:newnotsyn:MIN:%8.1lf %sBps", >> + "GPRINT:newnotsyn:LAST:%8.1lf %sBps\\j", >> + "STACK:portscan".$color{"color16"}."A0:".sprintf("%-25s",$Lang::tr{'port= scans'}), >> + "GPRINT:portscan:MAX:%8.1lf %sBps", >> + "GPRINT:portscan:AVERAGE:%8.1lf %sBps", >> + "GPRINT:portscan:MIN:%8.1lf %sBps", >> + "GPRINT:portscan:LAST:%8.1lf %sBps\\j", >> + "STACK:spoofedmartian".$color{"color12"}."A0:".sprintf("%-25s",$Lang::tr= {'spoofed or martians'}), >> + "GPRINT:spoofedmartian:MAX:%8.1lf %sBps", >> + "GPRINT:spoofedmartian:AVERAGE:%8.1lf %sBps", >> + "GPRINT:spoofedmartian:MIN:%8.1lf %sBps", >> + "GPRINT:spoofedmartian:LAST:%8.1lf %sBps\\j", >> + "STACK:hostilein".$color{"color13"}."A0:".sprintf("%-25s",$Lang::tr{'hos= tile networks in'}), >> + "GPRINT:hostilein:MAX:%8.1lf %sBps", >> + "GPRINT:hostilein:AVERAGE:%8.1lf %sBps", >> + "GPRINT:hostilein:MIN:%8.1lf %sBps", >> + "GPRINT:hostilein:LAST:%8.1lf %sBps\\j", >> + "STACK:hostileout".$color{"color25"}."A0:".sprintf("%-25s",$Lang::tr{'ho= stile networks out'}), >> + "GPRINT:hostileout:MAX:%8.1lf %sBps", >> + "GPRINT:hostileout:AVERAGE:%8.1lf %sBps", >> + "GPRINT:hostileout:MIN:%8.1lf %sBps", >> + "GPRINT:hostileout:LAST:%8.1lf %sBps\\j", >> + "LINE:hostile#000000A0:".sprintf("%-25s",$Lang::tr{'hostile networks tot= al'}), >> + "GPRINT:hostile:MAX:%8.1lf %sBps", >> + "GPRINT:hostile:AVERAGE:%8.1lf %sBps", >> + "GPRINT:hostile:MIN:%8.1lf %sBps", >> + "GPRINT:hostile:LAST:%8.1lf %sBps\\j", >> + ); >> + }else{ >> + RRDs::graph( >> + @GRAPH_ARGS, >> + "-", >> + "--start", >> + "-1".$period, >> + "-r", >> + "-t ".$Lang::tr{'firewall hits per'}." ".$Lang::tr{$period."-graph"}, >> + "-v ".$Lang::tr{'bytes per second'}, >> + "--color=3DSHADEA".$color{"color19"}, >> + "--color=3DSHADEB".$color{"color19"}, >> + "--color=3DBACK".$color{"color21"}, >> + "DEF:output=3D".$mainsettings{'RRDLOG'}."/collectd/localhost/iptables-fi= lter-POLICYOUT/ipt_bytes-DROP_OUTPUT.rrd:value:AVERAGE", >> + "DEF:input=3D".$mainsettings{'RRDLOG'}."/collectd/localhost/iptables-fil= ter-POLICYIN/ipt_bytes-DROP_INPUT.rrd:value:AVERAGE", >> + "DEF:forward=3D".$mainsettings{'RRDLOG'}."/collectd/localhost/iptables-f= ilter-POLICYFWD/ipt_bytes-DROP_FORWARD.rrd:value:AVERAGE", >> + "DEF:newnotsyn=3D".$mainsettings{'RRDLOG'}."/collectd/localhost/iptables= -filter-NEWNOTSYN/ipt_bytes-DROP_NEWNOTSYN.rrd:value:AVERAGE", >> + "DEF:portscan=3D".$mainsettings{'RRDLOG'}."/collectd/localhost/iptables-= filter-PSCAN/ipt_bytes-DROP_PScan.rrd:value:AVERAGE", >> + "DEF:spoofedmartian=3D".$mainsettings{'RRDLOG'}."/collectd/localhost/ipt= ables-filter-SPOOFED_MARTIAN/ipt_bytes-DROP_SPOOFED_MARTIAN.rrd:value:AVERAGE= ", >> + "DEF:hostilein=3D".$mainsettings{'RRDLOG'}."/collectd/localhost/iptables= -filter-HOSTILE_DROP_IN/ipt_bytes-DROP_HOSTILE.rrd:value:AVERAGE", >> + "DEF:hostileout=3D".$mainsettings{'RRDLOG'}."/collectd/localhost/iptable= s-filter-HOSTILE_DROP_OUT/ipt_bytes-DROP_HOSTILE.rrd:value:AVERAGE", >> + >> + # This creates a new combined hostile segment. >> + # If we started collecting IN/OUT, ie the old single Hostile RRD databas= e is not available then this CDEF will take the values >> + # from the sum of IN + OUT. >> + "CDEF:hostile=3Dhostilein,hostileout,+", >> + >> + "COMMENT:".sprintf("%-26s",$Lang::tr{'caption'}), >> + "COMMENT:".sprintf("%15s",$Lang::tr{'maximal'}), >> + "COMMENT:".sprintf("%15s",$Lang::tr{'average'}), >> + "COMMENT:".sprintf("%14s",$Lang::tr{'minimal'}), >> + "COMMENT:".sprintf("%15s",$Lang::tr{'current'})."\\j", >> + "AREA:output".$color{"color25"}."A0:".sprintf("%-25s",$Lang::tr{'firewal= lhits'}." (OUTPUT)"), >> + "GPRINT:output:MAX:%8.1lf %sBps", >> + "GPRINT:output:AVERAGE:%8.1lf %sBps", >> + "GPRINT:output:MIN:%8.1lf %sBps", >> + "GPRINT:output:LAST:%8.1lf %sBps\\j", >> + "STACK:forward".$color{"color23"}."A0:".sprintf("%-25s",$Lang::tr{'firew= allhits'}." (FORWARD)"), >> + "GPRINT:forward:MAX:%8.1lf %sBps", >> + "GPRINT:forward:AVERAGE:%8.1lf %sBps", >> + "GPRINT:forward:MIN:%8.1lf %sBps", >> + "GPRINT:forward:LAST:%8.1lf %sBps\\j", >> + "STACK:input".$color{"color24"}."A0:".sprintf("%-25s",$Lang::tr{'firewal= lhits'}." (INPUT)"), >> + "GPRINT:input:MAX:%8.1lf %sBps", >> + "GPRINT:input:AVERAGE:%8.1lf %sBps", >> + "GPRINT:input:MIN:%8.1lf %sBps", >> + "GPRINT:input:LAST:%8.1lf %sBps\\j", >> + "STACK:newnotsyn".$color{"color14"}."A0:".sprintf("%-25s","NewNotSYN"), >> + "GPRINT:newnotsyn:MAX:%8.1lf %sBps", >> + "GPRINT:newnotsyn:AVERAGE:%8.1lf %sBps", >> + "GPRINT:newnotsyn:MIN:%8.1lf %sBps", >> + "GPRINT:newnotsyn:LAST:%8.1lf %sBps\\j", >> + "STACK:portscan".$color{"color16"}."A0:".sprintf("%-25s",$Lang::tr{'port= scans'}), >> + "GPRINT:portscan:MAX:%8.1lf %sBps", >> + "GPRINT:portscan:AVERAGE:%8.1lf %sBps", >> + "GPRINT:portscan:MIN:%8.1lf %sBps", >> + "GPRINT:portscan:LAST:%8.1lf %sBps\\j", >> + "STACK:spoofedmartian".$color{"color12"}."A0:".sprintf("%-25s",$Lang::tr= {'spoofed or martians'}), >> + "GPRINT:spoofedmartian:MAX:%8.1lf %sBps", >> + "GPRINT:spoofedmartian:AVERAGE:%8.1lf %sBps", >> + "GPRINT:spoofedmartian:MIN:%8.1lf %sBps", >> + "GPRINT:spoofedmartian:LAST:%8.1lf %sBps\\j", >> + "STACK:hostilein".$color{"color13"}."A0:".sprintf("%-25s",$Lang::tr{'hos= tile networks in'}), >> + "GPRINT:hostilein:MAX:%8.1lf %sBps", >> + "GPRINT:hostilein:AVERAGE:%8.1lf %sBps", >> + "GPRINT:hostilein:MIN:%8.1lf %sBps", >> + "GPRINT:hostilein:LAST:%8.1lf %sBps\\j", >> + "STACK:hostileout".$color{"color25"}."A0:".sprintf("%-25s",$Lang::tr{'ho= stile networks out'}), >> + "GPRINT:hostileout:MAX:%8.1lf %sBps", >> + "GPRINT:hostileout:AVERAGE:%8.1lf %sBps", >> + "GPRINT:hostileout:MIN:%8.1lf %sBps", >> + "GPRINT:hostileout:LAST:%8.1lf %sBps\\j", >> + "LINE:hostile#000000A0:".sprintf("%-25s",$Lang::tr{'hostile networks tot= al'}), >> + "GPRINT:hostile:MAX:%8.1lf %sBps", >> + "GPRINT:hostile:AVERAGE:%8.1lf %sBps", >> + "GPRINT:hostile:MIN:%8.1lf %sBps", >> + "GPRINT:hostile:LAST:%8.1lf %sBps\\j", >> + ); >> + } >> $ERROR =3D RRDs::error; >> return "Error in RRD::graph for firewallhits: ".$ERROR."\n" if $ERROR; >> } >> --=20 >> 2.43.0 >> >=20 --=20 Sent from my laptop --===============6986187317172934363==--