]>
Commit | Line | Data |
---|---|---|
b08d4dde SS |
1 | package Guardian::IPtables; |
2 | use strict; | |
3 | use warnings; | |
4 | ||
5 | use Exporter qw(import); | |
6 | ||
7 | our @EXPORT = qw(DoBlock DoUnblock DoFlush); | |
8 | ||
e9c558fe SS |
9 | # Array of supported block actions. |
10 | my @supported_actions = ("DROP", "REJECT"); | |
11 | ||
b08d4dde SS |
12 | # The path to the iptables executeable. |
13 | my $iptables = "/usr/sbin/iptables"; | |
14 | ||
15 | # The used firewall chain. | |
16 | my $chain = "INPUT"; | |
17 | ||
18 | # | |
19 | ## The DoBlock subroutine. | |
20 | # | |
21 | ## This subroutine is called, when a given address should be locked by | |
22 | ## using IPtables. | |
23 | # | |
24 | ## Guardian is using the "append" option from IPtables, which will add the new rule | |
25 | ## to the end of the chain to prevent from possible race-conditions when adding/deleting | |
26 | ## rules at the same time. | |
27 | # | |
28 | sub DoBlock (@) { | |
29 | my ($address, $action) = @_; | |
30 | ||
31 | # If no action has been given, default to "DROP". | |
32 | unless($action) { | |
33 | $action = "DROP"; | |
34 | } | |
35 | ||
e9c558fe SS |
36 | # Check if the given action is supported. |
37 | my $error = &_check_action($action); | |
38 | ||
39 | # Abort and return the recieved error. | |
40 | if ($error) { | |
41 | return $error; | |
42 | } | |
43 | ||
b08d4dde SS |
44 | # Call iptables to block the given address. |
45 | system("$iptables --wait -A $chain -s $address -j $action"); | |
46 | } | |
47 | ||
48 | # | |
49 | ## The DoUnblock subroutine. | |
50 | # | |
51 | ## This subroutine can be used to delete all firewall rules (unblock) | |
52 | ## of a previously blocked address. | |
53 | # | |
54 | ## To do this a subroutine will be called, which is collecting all rule | |
55 | ## positions in the firewall chain for the given address, which returns | |
56 | ## them in reversed order. This list of rules will be deleted one-by-one | |
57 | ## so multiple entries (if present) for the address will be deleted. | |
58 | # | |
59 | ## This approach also eliminates the exact rule argument processing again | |
60 | ## for dropping it. So it is not neccessary to know the additional arguments | |
61 | ## like firewall action (DROP, REJECT) etc. | |
62 | # | |
63 | sub DoUnblock ($) { | |
64 | my ($address) = @_; | |
65 | ||
66 | # Get rulepositions for the specified address. | |
67 | my @rules = &_get_rules_positions_by_address($address); | |
68 | ||
69 | # Loop through the rules array and drop the firewall rules. | |
70 | foreach my $rule (@rules) { | |
71 | # Call iptables to delete the rule. | |
72 | system("$iptables --wait -D $chain $rule"); | |
73 | } | |
74 | } | |
75 | ||
76 | # | |
77 | ## The DoFlush subroutine. | |
78 | # | |
79 | ## Call this subroutine to entirely flush the IPtables chain. | |
80 | # | |
81 | sub DoFlush () { | |
82 | # Call iptalbes and flush the chain. | |
83 | system("$iptables --wait -F $chain"); | |
84 | } | |
85 | ||
86 | # | |
87 | ## Get rules subroutine. | |
88 | # | |
89 | ## This subroutine is used to get the rule position of the active | |
90 | ## firewall rules for a given address. Those position will be collected | |
91 | ## and returned in reversed order. | |
92 | # | |
93 | sub _get_rules_positions_by_address ($) { | |
94 | my ($address) = @_; | |
95 | ||
96 | # Array to store the rule positions. | |
97 | my @rules; | |
98 | ||
99 | # Call iptables and list all firewall rules. | |
100 | open(RULES, "$iptables --wait -L $chain -n -v --line-numbers |"); | |
101 | ||
102 | # Read input line by line. | |
103 | foreach my $line (<RULES>) { | |
104 | # Skip descriptive line. | |
105 | next if ($line =~ /^Chain/); | |
106 | next if ($line =~ /^ pkts/); | |
107 | ||
108 | # Generate array, based on the line content | |
109 | # (seperator is a single or multiple space's) | |
110 | my @comps = split(/\s{1,}/, $line); | |
111 | my ($pos, $pkts, $bytes, $target, $prot, $opt, $in, $out, $source, $destination) = @comps; | |
112 | ||
113 | # Compare the current source address with the given one. | |
114 | # If they are equal, the rule position will be added to the | |
115 | # rules array. | |
116 | if ($address eq $source) { | |
117 | push(@rules, $pos); | |
118 | } | |
119 | } | |
120 | ||
121 | # Reverse the array. | |
122 | my @reversed_rules = reverse @rules; | |
123 | ||
124 | # Return the reversed array. | |
125 | return @reversed_rules; | |
126 | } | |
127 | ||
e9c558fe SS |
128 | # |
129 | ## The _check_action function. | |
130 | # | |
131 | ## This private function is used to check if the given action is supported by | |
132 | ## the firewall engine. | |
133 | # | |
134 | sub _check_action ($) { | |
135 | my $action = $_[0]; | |
136 | ||
137 | # Check if the recieved action is part of the supported_actions array. | |
138 | foreach my $item (@supported_actions) { | |
139 | # Exit the loop and return "nothing" if we found a match. | |
140 | if($item eq $action) { | |
141 | return; | |
142 | } | |
143 | } | |
144 | ||
145 | # If we got here, the given action is not part of the array of supported | |
146 | # actions. Return an error message. | |
147 | return "Unsupported action: $action"; | |
148 | } | |
149 | ||
b08d4dde | 150 | 1; |