Skip to content

Instantly share code, notes, and snippets.

@FlorianHeigl
Last active November 22, 2023 19:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FlorianHeigl/b3fb440c462240537f1d3e73f8001dd8 to your computer and use it in GitHub Desktop.
Save FlorianHeigl/b3fb440c462240537f1d3e73f8001dd8 to your computer and use it in GitHub Desktop.
pfSense IPSec VPN Status

Setup

Preinstall

Install Check_MK agent on pfSense/OPNSense

Install Dependencies

  • pip3.11 install textfsm
  • pip3.11 install tabulate
item filename install to post-install steps
FSM template ipsec_status.template /opt/check_mk/lib/check_mk_agent
local check ipsec-status.local /opt/check_mk/lib/check_mk_agent/local chmod 750 <file>

Test run

Run as root: # /opt/check_mk/lib/check_mk_agent/local/ipsec-status.local

It should output one line per VPN connection.

Re-Scan host after installing/testing

It should find services of type "local". Add those.

Example output

OK
VPN Endpoint 80.CEN.SOR.ED	Open the action menu	Connection is ESTABLISHED	231 m	47.4 s	
OK
VPN Endpoint 87.CEN.SOR.ED	Open the action menu	Connection is ESTABLISHED	231 m	47.4 s	
OK
VPN Endpoint fw1.CEN.SOR.EDtaCEN.SOR.EDrsaCEN.SOR.ED	Open the action menu	Connection is ESTABLISHED	219 m	47.4 s	

Error behaviour

  • The check is generally made to output a WARNING state if your connection has an issue
  • There are many exceptions to that
  • The StrongSWAN cli drops the connection entries if there's no negotiated connection
  • This means that the check will only turn to UNKNOWN

Getting rid of limitations

An inventory based check can work around this since it has a known good state to compare to. I'll keep this check here available in any case as an example for a leaner check that the others that were available when I checked. The processing is done client-side since you're not supposed to include python libs in server based checks. Since the authors of StrongSWAN cannot provide a stable CLI (so far) this is a situation with many tradeoffs. The choice taken here is to install TextFSM and one dependency locally on the firewall. TextFSM is the (imo) best approach to have a stable interface between the different toolstacks, for the time being. It can also return tabular output which would then be perfect for server-side processing by Check_MK.

There's also not too many practical examples for using TextFSM, so I hope this also helps a bit.

References:

#!/usr/bin/env python3.11
# v1. keine netz/tunnel infos verarbeiten
import subprocess
import textfsm
from tabulate import tabulate
def canonify(h):
# ersetzen, was nicht fuer cmk geeignet ist
# alternativ einen hash bauen
h = h.replace(" ", "_")
return h
connection_data = {}
ipsec_status_info = subprocess.run(['ipsec', 'status'], stdout=subprocess.PIPE).stdout.decode('utf-8')
with open('../ipsec_status.template') as template:
fsm = textfsm.TextFSM(template)
header = fsm.header
_parsed_output = fsm.ParseText(ipsec_status_info)
for _con in _parsed_output:
connection_label = "VPN Endpoint %s" % canonify(_con[5])
connection_state = _con[1]
#0 "My service" myvalue=73 My output text which may contain spaces
if connection_state == "ESTABLISHED":
state = 0
else:
state = 1
print("%d \"%s\" - Connection is %s" % (state, connection_label, connection_state))
Value ConnectionID (\d+)
Value ConnectionSTATE (\S+)
Value LocalIP (\S+)
Value LocalName (\S+)
Value RemoteIP (\S+)
Value RemoteName (\S+)
# con1[219638]: ESTABLISHED 20 hours ago, 88.xxxxxx[MUC_xxx]...yyyy[yyyy
Start
^\s+con${ConnectionID}\[\d+\]:\s${ConnectionSTATE}.*,\s${LocalIP}\[${LocalName}\]...${RemoteIP}\[${RemoteName}\] -> Record
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment