From d8663132ada42d5ea5009adc999df3fe1de2ab87 Mon Sep 17 00:00:00 2001 From: Timothy Vandenbrande Date: Mon, 16 Mar 2015 11:34:07 +0100 Subject: [PATCH] windows firewall control --- lib/ansible/modules/extras/windows/win_fw.ps1 | 346 ++++++++++++++++++ lib/ansible/modules/extras/windows/win_fw.py | 110 ++++++ 2 files changed, 456 insertions(+) create mode 100644 lib/ansible/modules/extras/windows/win_fw.ps1 create mode 100644 lib/ansible/modules/extras/windows/win_fw.py diff --git a/lib/ansible/modules/extras/windows/win_fw.ps1 b/lib/ansible/modules/extras/windows/win_fw.ps1 new file mode 100644 index 00000000000..37e8935a23d --- /dev/null +++ b/lib/ansible/modules/extras/windows/win_fw.ps1 @@ -0,0 +1,346 @@ +#!powershell +# +# WANT_JSON +# POWERSHELL_COMMON + +function getFirewallRule ($fwsettings) { + try { + + #$output = Get-NetFirewallRule -name $($fwsettings.name); + $rawoutput=@(netsh advfirewall firewall show rule name=$($fwsettings.Name)) + if (!($rawoutput -eq 'No rules match the specified criteria.')){ + $rawoutput | Where {$_ -match '^([^:]+):\s*(\S.*)$'} | Foreach -Begin { + $FirstRun = $true; + $HashProps = @{}; + } -Process { + if (($Matches[1] -eq 'Rule Name') -and (!($FirstRun))) { + #$output=New-Object -TypeName PSCustomObject -Property $HashProps; + $output=$HashProps; + $HashProps = @{}; + }; + $HashProps.$($Matches[1]) = $Matches[2]; + $FirstRun = $false; + } -End { + #$output=New-Object -TypeName PSCustomObject -Property $HashProps; + $output=$HashProps; + } + } + $exists=$false; + $correct=$true; + $diff=$false; + $multi=$false; + $correct=$false; + $difference=@(); + $msg=@(); + if ($($output|measure).count -gt 0) { + $exists=$true; + $msg += @("The rule '" + $fwsettings.name + "' exists."); + if ($($output|measure).count -gt 1) { + $multi=$true + $msg += @("The rule '" + $fwsettings.name + "' has multiple entries."); + ForEach($rule in $output.GetEnumerator()) { + ForEach($fwsetting in $fwsettings.GetEnumerator()) { + if ( $rule.$fwsetting -ne $fwsettings.$fwsetting) { + $diff=$true; + #$difference+=@($fwsettings.$($fwsetting.Key)); + $difference+=@("output:$rule.$fwsetting,fwsetting:$fwsettings.$fwsetting"); + }; + }; + if ($diff -eq $false) { + $correct=$true + }; + }; + } else { + ForEach($fwsetting in $fwsettings.GetEnumerator()) { + if ( $output.$($fwsetting.Key) -ne $fwsettings.$($fwsetting.Key)) { + + if (($fwsetting.Key -eq 'RemoteIP') -and ($output.$($fwsetting.Key) -eq ($fwsettings.$($fwsetting.Key)+'-'+$fwsettings.$($fwsetting.Key)))) { + $donothing=$false + } elseif ((($fwsetting.Key -eq 'Name') -or ($fwsetting.Key -eq 'DisplayName')) -and ($output."Rule Name" -eq $fwsettings.$($fwsetting.Key))) { + $donothing=$false + } else { + $diff=$true; + $difference+=@($fwsettings.$($fwsetting.Key)); + }; + }; + }; + if ($diff -eq $false) { + $correct=$true + }; + }; + if ($correct) { + $msg += @("An identical rule exists"); + } else { + $msg += @("The rule exists but has different values"); + } + } else { + $msg += @("No rule could be found"); + }; + $result = @{ + exists = $exists + identical = $correct + multiple = $multi + difference = $difference + msg = $msg + } + } catch [Exception]{ + $result = @{ + failed = $true + error = $_.Exception.Message + msg = $msg + } + }; + return $result +}; + +function createFireWallRule ($fwsettings) { + $msg=@() + $execString="netsh advfirewall firewall add rule " + + ForEach ($fwsetting in $fwsettings.GetEnumerator()) { + if ($fwsetting.key -eq 'Direction') { + $key='dir' + } else { + $key=$($fwsetting.key).ToLower() + }; + $execString+=" "; + $execString+=$key; + $execString+="="; + $execString+=$fwsetting.value; + #$execString+="'"; + }; + try { + #$msg+=@($execString); + $output=$(Invoke-Expression $execString| ? {$_}); + $msg+=@("Created firewall rule $name"); + + $result=@{ + output=$output + changed=$true + msg=$msg + }; + + } catch [Exception]{ + $msg=@("Failed to create the rule") + $result=@{ + output=$output + failed=$true + error=$_.Exception.Message + msg=$msg + }; + }; + return $result +}; + +function removeFireWallRule ($fwsettings) { + $msg=@() + try { + $rawoutput=@(netsh advfirewall firewall delete rule name=$($fwsettings.name)) + $rawoutput | Where {$_ -match '^([^:]+):\s*(\S.*)$'} | Foreach -Begin { + $FirstRun = $true; + $HashProps = @{}; + } -Process { + if (($Matches[1] -eq 'Rule Name') -and (!($FirstRun))) { + $output=$HashProps; + $HashProps = @{}; + }; + $HashProps.$($Matches[1]) = $Matches[2]; + $FirstRun = $false; + } -End { + $output=$HashProps; + }; + $msg+=@("Removed the rule") + $result=@{ + failed=$false + changed=$true + msg=$msg + output=$output + }; + } catch [Exception]{ + $msg+=@("Failed to remove the rule") + $result=@{ + failed=$true + error=$_.Exception.Message + msg=$msg + } + }; + return $result +} + +# Mount Drives +$change=$false; +$fail=$false; +$msg=@(); +$fwsettings=@{} + +# Variabelise the arguments +$params=Parse-Args $args; + +$state=Get-Attr $params "state" "present"; +$name=Get-Attr $params "name" ""; +$direction=Get-Attr $params "direction" ""; +$force=Get-Attr $params "force" $false; +$action=Get-Attr $params "action" ""; + +# Check the arguments +if (($state -ne "present") -And ($state -ne "absent")){ + $misArg+="state"; + $msg+=@("for the state parameter only present and absent is allowed"); +}; + +if ($name -eq ""){ + $misArg+="Name"; + $msg+=@("name is a required argument"); +} else { + $fwsettings.Add("Name", $name) + #$fwsettings.Add("displayname", $name) +}; +if ((($direction.ToLower() -ne "In") -And ($direction.ToLower() -ne "Out")) -And ($state -eq "present")){ + $misArg+="Direction"; + $msg+=@("for the Direction parameter only the values 'In' and 'Out' are allowed"); +} else { + $fwsettings.Add("Direction", $direction) +}; +if ((($action.ToLower() -ne "allow") -And ($action.ToLower() -ne "block")) -And ($state -eq "present")){ + $misArg+="Direction"; + $msg+=@("for the Action parameter only the values 'allow' and 'block' are allowed"); +} else { + $fwsettings.Add("Action", $action) +}; +$args=@( + "Description", + "LocalIP", + "RemoteIP", + "LocalPort", + "RemotePort", + "Program", + "Service", + "Protocol" +) + +foreach ($arg in $args){ + New-Variable -Name $arg -Value $(Get-Attr $params $arg ""); + if ((Get-Variable -Name $arg -ValueOnly) -ne ""){ + $fwsettings.Add($arg, $(Get-Variable -Name $arg -ValueOnly)); + }; +}; + + +if ($($($misArg|measure).count) -gt 0){ + $result=New-Object psobject @{ + changed=$false + failed=$true + msg=$msg + }; + Exit-Json($result); +}; + +$output=@() +$capture=getFirewallRule ($fwsettings); +if ($capture.failed -eq $true) { + $msg+=$capture.msg; + $result=New-Object psobject @{ + changed=$false + failed=$true + error=$capture.error + msg=$msg + }; + Exit-Json $result; +} else { + $diff=$capture.difference + $msg+=$capture.msg; + $identical=$capture.identical; + $multiple=$capture.multiple; +} + + +switch ($state.ToLower()){ + "present" { + if ($capture.exists -eq $false) { + $capture=createFireWallRule($fwsettings); + $msg+=$capture.msg; + $change=$true; + if ($capture.failed -eq $true){ + $result=New-Object psobject @{ + failed=$capture.failed + error=$capture.error + output=$capture.output + changed=$change + msg=$msg + difference=$diff + fwsettings=$fwsettings + }; + Exit-Json $result; + } + } elseif ($capture.identical -eq $false) { + if ($force -eq $true) { + $capture=removeFirewallRule($fwsettings); + $msg+=$capture.msg; + $change=$true; + if ($capture.failed -eq $true){ + $result=New-Object psobject @{ + failed=$capture.failed + error=$capture.error + changed=$change + msg=$msg + output=$capture.output + fwsettings=$fwsettings + }; + Exit-Json $result; + } + $capture=createFireWallRule($fwsettings); + $msg+=$capture.msg; + $change=$true; + if ($capture.failed -eq $true){ + $result=New-Object psobject @{ + failed=$capture.failed + error=$capture.error + changed=$change + msg=$msg + difference=$diff + fwsettings=$fwsettings + }; + Exit-Json $result; + } + + } else { + $fail=$true + $msg+=@("There was already a rule $name with different values, use force=True to overwrite it"); + } + } elseif ($capture.identical -eq $true) { + $msg+=@("Firewall rule $name was already created"); + }; + } + "absent" { + if ($capture.exists -eq $true) { + $capture=removeFirewallRule($fwsettings); + $msg+=$capture.msg; + $change=$true; + if ($capture.failed -eq $true){ + $result=New-Object psobject @{ + failed=$capture.failed + error=$capture.error + changed=$change + msg=$msg + output=$capture.output + fwsettings=$fwsettings + }; + Exit-Json $result; + } + } else { + $msg+=@("Firewall rule $name did not exist"); + }; + } +}; + + +$result=New-Object psobject @{ + failed=$fail + changed=$change + msg=$msg + difference=$diff + fwsettings=$fwsettings +}; + + +Exit-Json $result; diff --git a/lib/ansible/modules/extras/windows/win_fw.py b/lib/ansible/modules/extras/windows/win_fw.py new file mode 100644 index 00000000000..0566ef0608d --- /dev/null +++ b/lib/ansible/modules/extras/windows/win_fw.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python + +# (c) 2014, Timothy Vandenbrande +# +# This file is part of Ansible +# +# Ansible 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 3 of the License, or +# (at your option) any later version. +# +# Ansible 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 Ansible. If not, see . + +DOCUMENTATION = ''' +--- +module: win_fw +author: Timothy Vandenbrande +short_description: Windows firewall automation +description: + - allows you to create/remove/update firewall rules +options: + state: + description: + - create/remove/update or powermanage your VM + default: "present" + required: true + choices: ['present', 'absent'] + name: + description: + - the rules name + default: null + required: true + direction: + description: + - is this rule for inbound or outbound trafic + default: null + required: true + choices: [ 'In', 'Out' ] + action: + description: + - what to do with the items this rule is for + default: null + required: true + choices: [ 'allow', 'block' ] + description: + description: + - description for the firewall rule + default: null + required: false + localip: + description: + - the local ip address this rule applies to + default: null + required: false + remoteip: + description: + - the remote ip address/range this rule applies to + default: null + required: false + localport: + description: + - the local port this rule applies to + default: null + required: false + remoteport: + description: + - the remote port this rule applies to + default: null + required: false + program: + description: + - the program this rule applies to + default: null + required: false + service: + description: + - the service this rule applies to + default: null + required: false + protocol: + description: + - the protocol this rule applies to + default: null + required: false + force: + description: + - Enforces the change if a rule with different values exists + default: false + required: false + + +''' + +EXAMPLES = ''' +# create smtp firewall rule + action: win_fw + args: + name: smtp + state: present + localport: 25 + action: allow + protocol: TCP + +''' \ No newline at end of file