in managementnode/lib/VCL/Module/OS/Windows/Version_6.pm [1380:1532]
sub get_firewall_configuration {
my $self = shift;
if (ref($self) !~ /windows/i) {
notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method");
return;
}
return $self->{firewall_configuration} if $self->{firewall_configuration};
my $computer_node_name = $self->data->get_computer_node_name();
my $system32_path = $self->get_system32_path() || return;
my $firewall_configuration;
my $command = "$system32_path/netsh.exe advfirewall firewall show rule name=all verbose";
my ($exit_status, $output) = $self->execute($command, 0);
if (!defined($output)) {
notify($ERRORS{'WARNING'}, 0, "failed to run command to show firewall rules on $computer_node_name");
return;
}
elsif (!grep(/Rule Name:/i, @$output)) {
notify($ERRORS{'WARNING'}, 0, "unexpected output returned from command to show firewall rules on $computer_node_name, command: '$command', exit status: $exit_status, output:\n" . join("\n", @$output));
return;
}
# Execute the netsh.exe command to retrieve firewall rules
# Rule Name: VCL: allow RDP port 3389
# ----------------------------------------------------------------------
# Enabled: Yes
# Direction: In
# Profiles: Domain,Private,Public
# Grouping:
# LocalIP: Any
# RemoteIP: 152.14.53.0/26,10.10.1.2-10.10.2.22
# Protocol: TCP
# LocalPort: 3389
# RemotePort: Any
# Edge traversal: No
# Action: Allow
# Rule Name: VCL: allow ping to/from any address
# ----------------------------------------------------------------------
# Enabled: Yes
# Direction: In
# Profiles: Domain,Private,Public
# Grouping:
# LocalIP: Any
# RemoteIP: Any
# Protocol: ICMPv4
# Type Code
# 8 Any
# Edge traversal: No
# Action: Allow
# Split the output into rule sections
my @rule_sections = split(/Rule Name:\s*/, join("\n", @$output));
RULE: for my $rule_section (@rule_sections) {
my @lines = split(/\n+/, $rule_section);
my $rule_name = shift(@lines);
# The first rule section will probably be blank because of the way split works
next RULE if (!$rule_name);
my $rule_info;
for my $line (@lines) {
if (my ($parameter, $value) = $line =~ /^(\w+):\s*(.*)/g) {
$rule_info->{$parameter} = $value;
}
elsif ($rule_info->{Protocol} && $rule_info->{Protocol} =~ /icmp/i) {
if (my ($icmp_type, $icmp_code) = $line =~ /^\s*(\d+)\s+(.*)/g) {
push @{$rule_info->{ICMPTypes}{$icmp_type}}, $icmp_code;
}
}
}
if (!defined($rule_info->{Enabled}) || $rule_info->{Enabled} !~ /yes/i) {
#notify($ERRORS{'DEBUG'}, 0, "ignoring disabled rule: '$rule_name'");
next RULE;
}
if (!defined($rule_info->{Direction}) || $rule_info->{Direction} !~ /in/i) {
#notify($ERRORS{'DEBUG'}, 0, "ignoring outgoing rule: '$rule_name'");
next RULE;
}
elsif (!defined($rule_info->{Action}) || $rule_info->{Action} !~ /allow/i) {
#notify($ERRORS{'DEBUG'}, 0, "ignoring rule: '$rule_name', Action is NOT allow");
next RULE;
}
elsif (!defined($rule_info->{Protocol})) {
#notify($ERRORS{'DEBUG'}, 0, "ignoring rule: '$rule_name', Protocol is not defined:\n$rule_section");
next RULE;
}
elsif ($rule_info->{Protocol} =~ /v6/i) {
# Skip IPv6 rules for now
next RULE;
}
my @ports;
if ($rule_info->{Protocol} =~ /icmp/i) {
if (!defined($rule_info->{ICMPTypes})) {
notify($ERRORS{'DEBUG'}, 0, "ignoring rule: '$rule_name', ICMP type could not be determined:\n$rule_section");
next RULE;
}
@ports = sort keys(%{$rule_info->{ICMPTypes}})
}
else {
if (!defined($rule_info->{LocalPort})) {
#notify($ERRORS{'DEBUG'}, 0, "ignoring rule: '$rule_name', LocalPort is not defined");
next RULE;
}
elsif ($rule_info->{LocalPort} !~ /^\d+$/) {
#notify($ERRORS{'DEBUG'}, 0, "ignoring rule: '$rule_name', LocalPort is not an integer");
next RULE;
}
@ports = split(",", $rule_info->{LocalPort});
}
if (!@ports) {
notify($ERRORS{'WARNING'}, 0, "ignoring rule: '$rule_name', no ports defined:\n" . format_data($rule_info) . "\n$rule_section");
next RULE;
}
for my $port (@ports) {
$firewall_configuration->{$rule_info->{Protocol}}{$port}{name} = $rule_name;
$firewall_configuration->{$rule_info->{Protocol}}{$port}{description} = $rule_info->{Description};
$firewall_configuration->{$rule_info->{Protocol}}{$port}{scope} = $rule_info->{RemoteIP};
$firewall_configuration->{$rule_info->{Protocol}}{$port}{local_ip} = $rule_info->{LocalIP};
}
}
# Assemble a string containing all the rule info (don't print_data because it outputs too much to vcld.log)
my $rules_string;
for my $protocol (keys %$firewall_configuration) {
for my $port (sort keys %{$firewall_configuration->{$protocol}}) {
my $name = $firewall_configuration->{$protocol}{$port}{name};
my $scope = $firewall_configuration->{$protocol}{$port}{scope};
my $local_ip = $firewall_configuration->{$protocol}{$port}{local_ip};
$rules_string .= "$protocol:$port '$name' - local IP: $local_ip, scope: $scope\n";
}
}
# Copy the ICMPv4 key to one named ICMP for compatibility
if (defined($firewall_configuration->{ICMPv4})) {
$firewall_configuration->{ICMP} = $firewall_configuration->{ICMPv4};
}
$self->{firewall_configuration} = $firewall_configuration;
notify($ERRORS{'DEBUG'}, 0, "retrieved firewall info from $computer_node_name:\n$rules_string");
return $firewall_configuration;
}