[Xymon] pfSense monitoring

Brian Scott Brian.Scott at bunyatech.com.au
Sat Sep 3 06:35:27 CEST 2022


Hi List,

I've just set up Xymon monitoring of a pfSense system and I thought I'd 
share a few details for others.

pfSense is a firewall system based on FreeBSD using the 'pf' packet 
filter system. The FreeBSD system is trimmed down to a smaller operating 
system than the normal distribution and has a very small number of 
available packages available in the default repository, all related to 
it's firewall functionality. I've seen reference to pulling in packages 
from the standard FreeBSD pkg system but have chosen not to go down that 
path.

My starting point is Jeremy Laidman's xymon-rclient.sh script from 
xymonton. This is a quite well thought out shell script (in contrast to 
many of the add-ons, including mine), that connects to the target system 
using ssh (or others that don't matter) and fires off a combination of 
the standard xymon client scripts and a few extra shell commands. The 
resulting output looks like the normal client log which is then handed 
back to xymon. The idea is that no special software is required on the 
target system.

After installing the script in the server/ext directory, you add a tasks 
entry (I use a tasks.d directory file) to run the script every 5 
minutes. All pretty standard stuff so far. The recommended task entry is:

[xymon-rclient]
         ENVFILE $XYMONHOME/etc/xymonserver.cfg
         CMD /$XYMONHOME/ext/xymon-rclient.sh
         LOGFILE $XYMONSERVERLOGS/xymon-rclient.log
         INTERVAL 5m

This looks for RCLIENT tags on entries in your hosts.cfg file. My tag 
looks like this:

     "RCLIENT:cmd(ssh -T -o BatchMode=yes admin at 10.0.1.54 
/bin/sh),ostype(freebsd)"

Key points include the ostype(freebsd) part which identifies the target 
system type. This identifies the client script to send to the target 
system, in this case client/bin/xymonclient-freebsd.sh.

The /bin/sh at the end of the command solves a particular problem. It 
tells the ssh daemon to run this program rather than the normal login 
shell. This is important because if you connect to a pfSense system by 
ssh (BTW this must be enabled first in the pfSense web interface), you 
are greeted by a menu rather than a command prompt. It would be possible 
to patch the rclient.sh script to send an '8' (the option for a shell) 
as the first thing it does, but that would mess up using the script for 
any other target systems. Including the /bin/sh command bypasses the 
menu and sets up the system in a shell to begin work. Note that this is 
a more or less standard bourne shell. Bash would only be available as an 
unsupported package but is also completely unnecessary.

SSH Setup
======

To use ssh you will need to generate some key pairs and transport the 
public key parts to the target system.

On the xymon server machine I did this (as root), assuming the xymon 
server runs as user called 'xymon':

     cd ~xymon

     mkdir .ssh

     chown xymon .ssh

     cd .ssh

     ssh-keygen -t rsa -f id_rsa -P ''

     ssh-keygen -t dsa -f id_dsa -P ''

     ssh-keygen -t ecdsa -f id_ecdsa -P ''

     ssh-keygen -t ed25519 -f id_ed25519 -P ''

     chown xymon *

Your ssh may have less or additional key types than mine, check your 
manpage for ssh-keygen. Also, that's two consecutive single quotes at 
the end of the line.

You then need to transfer your public keys over to the target system. To 
get your public keys, type:

     cat ~xymon/.ssh/*.pub

And copy the resulting 4 lines of output (some of which may be wrapped 
over a few lines).

We need to exchange public keys with the target server. Log on to the 
pfSense system as the local xymon user. This is important because we 
need this user to capture the remote pfSense host's public key in 
xymon's .ssh/known_hosts file.

     su - xymon -c "ssh admin at 10.0.1.54"

If you are a 'sudo' fan, adjust as necessary. Accept the remote system's 
key and then give the remote password. The pfSense menu should appear, 
select 8 to get a shell.

Create a .ssh directory:

     mkdir .ssh

And add our public keys to the system.

     cat >>.ssh/authorized_keys

Paste in our public keys from earlier and press control+D on a new line 
to end input. Type control+D again to exit the shell, then select option 
'0' to logout from the menu.

You should now be able to ssh to the pfSense system (as the xymon user) 
without accepting a new key or supplying a password. Test and verify.

     su - xymon -c "ssh admin at 10.0.1.54"

Fixes to xymon-rclient.sh
================

I've sent a diff file to Jeremy Laidman a couple of days ago. He may or 
may not change the code on xymonton. That's how these things work.

Essentially there are two essential changes to reflect the target system 
not being Linux. One is a problem with the sent command stream 
over-running a fresh shell invocation intended to set up proper 
environment variables. The other change is to some sed GNU extensions 
used. There shouldn't be any impact on other systems.

There are a couple of other minor fixes that I'd recommend but are not 
essential.

I'm including the patch in this email (not sure if the mail list server 
approves) incase you have an unpatched copy.

Fixes for Xymon
==========

The client script for a FreeBSD system includes a small C program to 
extract memory data. This is a problem since we don't want to install a 
program on the target machine. We can avoid including that section in 
the client data if the program isn't available but then we don't get 
memory tracking by xymon.

The reason for the program is that the installed memory on the system is 
available as a number of bytes. With recent systems this often excedes a 
32 bit number. The requirement is a memory size in MB and shell 
arithmetic is limited to 32 bit integers. I've implemented two 
workarounds for this:

1) A massive hack - drop the last three digits of the size and divide by 
1048 to get the size in MB. This should be surprisingly good up to 
memory sizes in TB. I've only tested to 32GB though.

2) Send the size in bytes back to xymon where it can properly process 
the numbers as unsigned longs.

Xymon already uses "memory free" from a later section (vmtotal) so we 
don't need to fake that up, although it also quite doable but commented 
out in my fix.

The other diff file includes patches for both the FreeBSD client script, 
and the xymond reader for freebsd client messages.

You have three choices depending on circumstances and how much you care:

1) Do nothing. You won't have a memory column. Remember to include a 
NOCOLUMNS:memory tag on your pfSense machine in this case.

2) Just patch the client script. This should be good to just short of 
2TB pfSense memory. pfSense doesn't need anything like that much memory.

3) Patch the script and the xymond code. Should be good up to a full 64 
bit used address space. No nasty hacks involved.

[Side note: netbsd and openbsd also have client programs for the same 
purpose. I don't have ready access to either of these systems to 
develop/test equivalent patches.]

Other systems
=========

I've also tested this on a nanobsd system (the ssh stuff is a little 
harder because of read-only file systems) and a dell server running my 
hypervisor on a recent version of FreeBSD. Also found that msdosfs file 
system on FreeBSD doesn't have inodes (I've normally handled this with 
exclusions) so added it to the inodes exclusion list.


I hope this helps someone in the future,


Brian

P.S. If this email doesn't have the diff files attached, check for 
another email following close behind with them included as the message body.
-------------- next part --------------
--- /home/brian/xymon-rclient (1).sh	2022-08-31 17:21:30.984701000 +1000
+++ xymon-rclient.sh	2022-08-31 21:42:17.063665000 +1000
@@ -140,13 +140,16 @@
 
 send_setup_commands() {
 	# sets up the environment
-	echo "/bin/sh -"
+	echo 'if [ -z "$HOME" ]; then echo "/bin/sh -"; fi'
+	sleep 1 # avoid sending any more commands until the new /bin/sh is ready for them
 	# for some reason, sunos shell sometimes corrupts the
 	# start of the command line so we need to pad it here
 	echo "################################################################"	# 64 chars
 	echo "################################################################"	# 64 chars
 	echo "XYMONTMP=$1"
 	echo "MACHINEDOTS=$2"
+	echo "XYMONHOME=/nonexistent"
+	echo "TOP=\"\`which top 2>/dev/null\`\""
 	# clean up any preamble
 	echo "echo"
 	echo "echo ---START---"
@@ -186,8 +189,8 @@
 	echo
 	echo [clock]
 	echo epoch: \${EPOCH}.000000
-	echo local: `date    "+%Y-%m-%d %H:%M:%S %Z"`
-	echo local: `date -u "+%Y-%m-%d %H:%M:%S %Z"`
+	echo local: \`date    "+%Y-%m-%d %H:%M:%S %Z"\`
+	echo local: \`date -u "+%Y-%m-%d %H:%M:%S %Z"\`
 fi
 
 -EOF-
@@ -235,7 +238,9 @@
 		echo ")"
 		send_clock_commands
 		send_finish_commands
-	) | eval $CMD $DUMPERR | sed '1,/---START---/d;$a[endmarker]\ndummy entry' &
+	) | eval $CMD $DUMPERR | sed -e '1,/---START---/d' -e '$a\
+[endmarker]\
+dummy entry' &
 	PROCPID=$!
 	[ "$PROCPID" ] || die "Failed to fork command $CMD"
 
@@ -645,9 +650,11 @@
  	[ 0$DEBUG -gt 3 ] && echo "Sending client script $XYMONSERVERROOT/client/bin/${XYMONCLIENT}-${SCRIPTOS}.sh"
 	[ 0$DEBUG -gt 4 ] && echo "Setup commands:" && send_setup_commands "$REM_XYMONTMP" "$MACHINEDOTS" | sed 's/^/  /'
  	[ 0$DEBUG -gt 4 -o "$STOPAFTERSCRIPT" ] && echo "Client script:" && (
-		send_setup_commands
+		send_setup_commands "$REM_XYMONTMP" "$MACHINEDOTS"
 		send_client_script "$EN" $XYMONSERVERROOT/client/bin/${XYMONCLIENT}-${SCRIPTOS}.sh
+		echo "("
 		send_logfetch_commands $LOGFETCHCFG
+		echo ")"
 		send_clock_commands
 		send_finish_commands
 	) | sed 's/^/  /'

-------------- next part --------------
--- client/xymonclient-freebsd.sh.orig	2015-12-17 02:13:03.000000000 +1100
+++ client/xymonclient-freebsd.sh	2022-09-02 16:50:49.868068000 +1000
@@ -28,7 +28,7 @@
 }'
 echo "[inode]"
 # The sed stuff is to make sure lines are not split into two.
-df -i -tnonfs,nullfs,cd9660,procfs,devfs,linprocfs,fdescfs | sed -e '/^[^ 	][^ 	]*$/{
+df -i -tnonfs,nullfs,cd9660,procfs,devfs,linprocfs,fdescfs,msdosfs | sed -e '/^[^ 	][^ 	]*$/{
 N
 s/[ 	]*\n[ 	]*/ /
 }' | awk '
@@ -37,7 +37,16 @@
 echo "[mount]"
 mount
 echo "[meminfo]"
-$XYMONHOME/bin/freebsd-meminfo
+if [ -x $XYMONHOME/bin/freebsd-meminfo ]; then
+	$XYMONHOME/bin/freebsd-meminfo
+else
+	physmem=`sysctl -n hw.physmem`
+	#vmfree=`sysctl vm.vmtotal | grep 'Free Memory:' | cut -w -f3 | cut -dK -f1`
+	total=`echo $physmem|sed -e 's/...$//'`
+	echo Total:$(($total/1048))
+	#echo Free:$(($vmfree/1024)) # the file reader gets this from the [vmtotal] section so we don't need to.
+	echo Physmem:$physmem # reader can avoid our dodgy maths completely
+fi
 echo "[swapinfo]"
 swapinfo -k
 echo "[vmtotal]"
--- xymond/client/freebsd.c.orig	2016-02-03 07:16:19.000000000 +1100
+++ xymond/client/freebsd.c	2022-09-02 09:59:12.485795000 +1000
@@ -82,6 +82,7 @@
 	if (meminfostr) {
 		p = strstr(meminfostr, "Total:"); if (p) { memphystotal = atol(p+6); found++; }
 		p = strstr(meminfostr, "Actual:"); if (p) memphysactual = atol(p+7);
+		p = strstr(meminfostr, "Physmem:"); if (p) { memphystotal = strtoul(p+8,NULL,10)/(1024 * 1024); found++; }
 	}
 
 	if (vmtotalstr) {


More information about the Xymon mailing list