Issue with Windows Firewall State plugin

Plugin: https://exchange.checkmk.com/p/windows-firewall-state
my check_mk version: 1.6.0p8

I’ve installed the plugin using command line, all seemed good. I’ve extracted the vbs plugin file and placed it on the machine that’s supposed to be monitored, check_mk detected new service to me monitored but when I confirmed all changes I got an error:

As far as I know firewall is enabled on the server I tried to monitor.

This is the content of /omd/sites/swissre/local/share/check_mk/checks/windows_firewall

#!/usr/bin/python
# -*- encoding: utf-8; py-indent-offset: 4 -*-

#
# Windows Firewall State - Check the state and profile of the Windows Firewall
# Use it on your own risk!
#
# Version 1.0
# Written 2017 - Maximilian Thoma
#
# This program is free software; you can redistribute it and/or modify it under the terms of the GNU
# General Public License as published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# 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.
#
# You should have received a copy of the GNU General Public License along with this program; if not,
# write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
#

defaults_windows_firewall = {
                            "STATE": "ON",
                            "PROFILE": "Domain",
                            "CSTATE": "eingehend blockieren, ausgehend zulassen"
                            }


def inventory_windows_firewall(info):
    yield None, defaults_windows_firewall


def check_windows_firewall(item, params, info):

    for i in info:
        if "CSTATE" in i:
            cstate = " ".join(i[1:])
        elif "STATE" in i:
            state = i[1]
        elif "PROFILE" in i:
            profile = i[1]
        elif "EMSG" in i:
            emsg = " ".join(i[1:])
            
    # Check profile
    if params['PROFILE'] != profile:
        yield 1, "Profile mismatch, configured %s, on system %s" % (params['PROFILE'], profile)
    else:
        yield 0, "Profile match: %s" % profile
        
    # Check state
    if params['STATE'] != state:
        yield 2, "Firewall state mismatch, configured %s, on system %s" % (params['STATE'], state)
    else:
        yield 0, "Firewall state match: %s" % state
                

    # connstate
    if params['CSTATE'] != cstate:
        yield 1, "Connection State mismatch, configured %s, on system %s" % (params['CSTATE'], cstate)
    else:
        yield 0, "Connection State: %s" % cstate
    
    # error msg
    if 'emsg' in locals():
        yield 3, "Unexpected message: " + emsg

check_info['windows_firewall'] = {
    'inventory_function'    : inventory_windows_firewall,
    'check_function'        : check_windows_firewall,
    'service_description'   : 'Windows Firewall State',
    'group'                 : 'windows_firewall',
}

and vbs file

''
'' windows_firewall.vbs - Check for Check_MK
'' Original VBS NRPE script by Norman Bauer - Thanks! 
''
'' Modified by Maximilian Thoma for Check_MK plugin integration
'' 
''
'' This program is free software; you can redistribute it and/or modify it under the terms of the GNU
'' General Public License as published by the Free Software Foundation; either version 2 of the
'' License, or (at your option) any later version.
''
'' 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.
''
'' You should have received a copy of the GNU General Public License along with this program; if not,
'' write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
''


Dim oStdOut, oShell, oFwMgr, oProfile, NET_FW_PROFILE_TYPE, objWshScriptExec, strLine, connState
On Error Resume Next

WScript.Echo("<<<windows_firewall>>>")

Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * from Win32_OperatingSystem")
For Each objItem in colItems
  If InStr(objItem.Name, "Microsoft Windows Server 2003") > 0 Then
  	WScript.Echo("EMSG Windows Firewall will not be checked on " & objItem.Name)
  End If
Next 

Sub ExitWithUnknown()
  	WScript.Echo("EMSG Could not get Firewall State")
End Sub

Set oStdOut = WScript.StdOut
Set oShell = CreateObject("Wscript.Shell")
Set oFwMgr = CreateObject("HNetCfg.FwMgr")
Set oProfile = oFwMgr.LocalPolicy.CurrentProfile

NET_FW_PROFILE_TYPE = Array("Domain","Standard","Current","Unused","Unused")



If Err <> 0 Then
 	WScript.Echo("EMSG Windows Firewall Service not running")
	
End If

If oProfile.FirewallEnabled = False Then
	WScript.Echo("STATE OFF")
	WScript.Echo("PROFILE " & NET_FW_PROFILE_TYPE(oFwMgr.CurrentProfileType))
ElseIf oProfile.FirewallEnabled = True Then
	connState = ""
	Set objWshScriptExec = oShell.Exec("netsh advfirewall show currentprofile")
	Set oStdOut = objWshScriptExec.StdOut

	Do While Not oStdOut.AtEndOfStream
	   strLine = oStdOut.ReadLine
	   If InStr(strLine,"Firewall Policy") Then
	       connState = Replace(Lcase(Trim(Replace(strLine, "Firewall Policy", ""))), ",", ", ")
	       Exit Do
	   
	   ElseIf InStr(strLine,"Firewallrichtlinie") Then
	       connState = Replace(Lcase(Trim(Replace(strLine, "Firewallrichtlinie", ""))), ",", ", ")
	       Exit Do
	   End If
	   
	Loop
	
	if connState = "blockinbound, allowoutbound" Or connState = "eingehend blockieren, ausgehend zulassen" Then
  	WScript.Echo("STATE ON")
    WScript.Echo("PROFILE " & NET_FW_PROFILE_TYPE(oFwMgr.CurrentProfileType))
    WScript.Echo("CSTATE " & connState)
	else
  	WScript.Echo("STATE ON")
    WScript.Echo("PROFILE " & NET_FW_PROFILE_TYPE(oFwMgr.CurrentProfileType))
    WScript.Echo("CSTATE " & connState)
	End If	
Else
	ExitWithUnknown()
End If


Set oShell = Nothing
Set oFwMgr = Nothing
Set oProfile = Nothing
Set oStdOut = Nothing

The check code is a little bit strange and needs some work over.
There is no check if the agent output is complete. In your case, the incomplete or different output as expected is the cause of the error.

Hi,
you need to declare the vars in check plugin first. If no CSTATE available vor agent plugin, the error occurs.

def check_windows_firewall(item, params, info):
    cstate = ""

Cheers,
Christian

Thank you. It almost works now. When I run the vbs script on my Win10 machine it returns the correct states:
obraz
obraz
obraz
obraz

But when I run it on the Windows Server 2016 that I want to monitor I only get the information about profile being “Domain”, but state is reported OFF even when firewall is definitely turned ON and I don’t get the return info on CSTATE at all. I assume the script should be adjusted to work with WinServer 2016.

Hi,
I remember I had some similar problem with the extension as well with some machines.
I had to add the code WScript.Echo(“CSTATE OFF”) in the following block (below line 54)

If oProfile.FirewallEnabled = False Then
WScript.Echo("STATE OFF")
WScript.Echo("PROFILE " & NET_FW_PROFILE_TYPE(oFwMgr.CurrentProfileType))
WScript.Echo("CSTATE OFF")

Just to deliver some Info for CSTATE, even if the firewall is disabled.
But I never had the problem that the script didn’t recognize the correct firewall state.

I think I know what’s the problem. Since I’m using GP for governing Firewall policy the command used by script is not valid in my case.

Script currently gets the information on firewall status from “netsh advfirewall show currentprofile”

PS C:\ProgramData\checkmk\agent\plugins> netsh advfirewall show all state

Domain Profile Settings:
----------------------------------------------------------------------
State                                 OFF

Private Profile Settings:
----------------------------------------------------------------------
State                                 OFF

Public Profile Settings:
----------------------------------------------------------------------
State                                 OFF
Ok.

I found another command that returns the correct values:

PS C:\temp> Get-NetFirewallProfile -policystore activestore

Name                            : Domain
Enabled                         : True
DefaultInboundAction            : Block
DefaultOutboundAction           : Allow
AllowInboundRules               : True
AllowLocalFirewallRules         : False
AllowLocalIPsecRules            : False
AllowUserApps                   : True
AllowUserPorts                  : True
AllowUnicastResponseToMulticast : True
NotifyOnListen                  : False
EnableStealthModeForIPsec       : True
LogFileName                     : %systemroot%\system32\logfiles\firewall\pfirewall.log
LogMaxSizeKilobytes             : 32767
LogAllowed                      : True
LogBlocked                      : True
LogIgnored                      : True
DisabledInterfaceAliases        :

Name                            : Private
Enabled                         : True
DefaultInboundAction            : Block
DefaultOutboundAction           : Allow
AllowInboundRules               : True
AllowLocalFirewallRules         : True
AllowLocalIPsecRules            : True
AllowUserApps                   : True
AllowUserPorts                  : True
AllowUnicastResponseToMulticast : True
NotifyOnListen                  : False
EnableStealthModeForIPsec       : True
LogFileName                     : %systemroot%\system32\logfiles\firewall\pfirewall.log
LogMaxSizeKilobytes             : 32767
LogAllowed                      : True
LogBlocked                      : True
LogIgnored                      : True
DisabledInterfaceAliases        :

Name                            : Public
Enabled                         : True
DefaultInboundAction            : Block
DefaultOutboundAction           : Allow
AllowInboundRules               : True
AllowLocalFirewallRules         : False
AllowLocalIPsecRules            : False
AllowUserApps                   : True
AllowUserPorts                  : True
AllowUnicastResponseToMulticast : True
NotifyOnListen                  : False
EnableStealthModeForIPsec       : True
LogFileName                     : %systemroot%\system32\logfiles\firewall\pfirewall.log
LogMaxSizeKilobytes             : 32767
LogAllowed                      : True
LogBlocked                      : True
LogIgnored                      : True
DisabledInterfaceAliases        :

Now I need to find a way how to get the values from the command above. I have only a little knowledge on PowerShell and even less on VBS so it’s gonna be tricky.

If you want only the “Name”,“Enabled”,“DefaultIn/OutboundAction” you can use an syntax like this.

Write-Host("<<<windows_firewall:sep(129)>>>")
Get-NetFirewallProfile -policystore activestore | foreach-object { '{0}|{1}|{2}|{3}' -f $_.name, $_.enabled, $_.DefaultInboundAction, $_.DefaultOutboundAction }

Result looks like

<<<windows_firewall:sep(129)>>>
Domain|True|Block|Allow
Private|True|Block|Allow
Public|True|Block|Allow

But with this output you need to rewrite the Python check itself.

I’m using cmk 1.6, the guide for developing plugins says I should put my plugin *.py file in

local/lib/check_mk/base/plugins/agent_based

but there’s no such path in my installation. What’s the place for the plugin files for 1.6?

Yes this is only for 2.0
For 1.6 your own plugin needs to be inside “~/local/share/check_mk/checks/” without the file name ending “.py”

I just found out I was following a guide for v2.0. I’ve created file in the folder you mentioned but it seems I still have to do something more or the plugin itself is missing info because I don’t see it listed under “Check Plugins”.

Plugin itself looks like this:

from .agent_based_api.v1 import *
def discover_firewall_status(section):
    for profile, enabled, inbound, outbound in section:
        yield Service(item=profile)
def check_firewall_status(item, section):
    for profile, enabled, inbound, outbound in section:
        if profile == item:
            if profile == "Domain" and enabled == "True" and inbound == "Block" and outbound == "Allow":
                s = State.OK
            else:
                s = State.CRIT
            yield Result(
                state = s
            return

register.check_plugin(
    name="windows_firewall.ps1",
    service_name="Windows Firewall",
    discovery_function=discover_firewall_status,
    check_function=check_firewall_status,
)

Your plugin is completely for CMK 2 it will not work with 1.6.
There you need to write a complete different code.
Only the check function can be used nearly the same way but only nearly :wink:

Nooooooo :frowning: There’s no guide for 1.6.

Putting that aside, if I were on v2.0 it would work?

#checkmk-v2

I’ve deployed 2.0 instance of Check-MK to test the firewall plugin but I’m confused. I copied the py file into the “local/lib/check_mk/base/plugins/agent_based” and have windows_firewall.ps1 in C:\ProgramData\checkmk\agent\plugins on the server I want to monitor.

I ran command “OMD[cmk]:~$ cmk -d servername.domain.com” and in the first line I got:

Error in agent based plugin firewall: check_function: unexpected ‘item’ argument

Script itself was executed correctly as I’ve found on the bottom of the command output:

<<<Windows_Firewall>>>
Domain True Block Allow
Private True Block Allow
Public True Block Allow

I’m new to checkmk2.0 and can’t find anywhere how should I enable this check for the server. I don’t see it in the services during the discovery and can’t find it in Setup → Agents or Setup → Services.

I’ve also tried to follow up the Guide on writing plugins, section 3.2. A simple example and don’t see it listed either.

Hi,

just copying a version 1.6 check Plugin into the agent_based folder of a version 2 checkmk will not work all.
Checks in the agent_based folder need to be python 3 modules ending with .py
So someone needs to rewrite the check to be compatible with version 2.

There might be a small chance that the plugins works if you install the 1.6 mkp file, if it is correctly written for 1.6 and the auto migration works, but I assume that this is not the case.

1 Like

I have rewritten the plugin per guide in the documentation, but I can’t find it anywhere in the configuration after I put it in “agent_based” folder.

I can’t even make the “Simple example” from the guide to work and I have no idea why.

I have rewritten the sample “foobar” plugin and it’s working as expected now :slight_smile: I need to correct some names and share the final result here.

Here’s the final plugin script:


from .agent_based_api.v1 import *
import pprint


def discover_firewall(section):
    for type, status, inbound, outbound in section:
        yield Service(item=type)


def check_firewall(item, section):
    for type, status, inbound, outbound in section:
        if type == item:
            if status == "False":
                temp = "Disabled"
                s = State.CRIT
            else:
                temp = "Enabled"
                s = State.OK
            yield Result(
                state = s,
                summary = f"Firewall is {temp}. Inbound is {inbound}ed. Outbound is {outbound}ed")
            return


register.check_plugin(
    name = "Windows_Firewall",
    service_name = "%s Firewall",
    discovery_function = discover_firewall,
    check_function = check_firewall,
)

and on the client side:

"<<<Windows_Firewall>>>"
Get-NetFirewallProfile -policystore activestore | foreach-object { '{0} {1} {2} {3}' -f $_.name, $_.enabled, $_.DefaultInboundAction, $_.DefaultOutboundAction }
1 Like

I’d like to confirm what @hyperqbe is seeing with the original “Window Firewall State” plugin. When you are managing Windows Firewall with a GPO to ensure the firewall is enabled across all profiles (Domain, Private, Public), the plugin reports that the firewall state is off, when it is enabled.

@hyperqbe, are their any plans to release the “final” script via the exchange and depreciate the old version?

After my post in March i wrote already a complete check with deployment and so on :slight_smile:
You can find the mkp here.

1 Like