]> git.ipfire.org Git - people/stevee/guardian.git/blob - modules/Events.pm
Allow to configure the used parser for a monitored file.
[people/stevee/guardian.git] / modules / Events.pm
1 package Guardian::Events;
2 use strict;
3 use warnings;
4
5 use Exporter qw(import);
6
7 our @EXPORT_OK = qw(Init CheckAction Update);
8
9 # Hash which stores all supported commands from the queue.
10 my %commands = (
11 'count' => \&Counter,
12 'block' => \&CallBlock,
13 'unblock' => \&CallUnblock,
14 'flush' => \&CallFlush,
15 );
16
17 # Hash to store addresses and their current count.
18 my %counthash = ();
19
20 # Hash to store all currentyl blocked addresses and a timestamp
21 # when the block for this address can be released.
22 my %blockhash = ();
23
24 # This object will contain the reference to the logger object after calling Init.
25 my $logger;
26
27 #
28 ## The "Init" (Block) function.
29 #
30 ## This function is responsible to initialize Block as a class based object.
31 ## It has to be called once before any blocking event can be processed.
32 #
33 ## The following arguments must be passed, during initialization:
34 ## "BlockCount" and "BlockTime" which both have to be natural numbers.
35 #
36 sub Init (%) {
37 my ( $class, %args ) = @_;
38 my $self = \%args;
39
40 # Fail, if some critical arguments are missing.
41 unless ((exists($self->{BlockCount})) && (exists($self->{BlockTime}))) {
42 die "Could not initialize Block: Too less arguments are given.\n";
43 }
44
45 # Use bless to make "$self" to an object of class "$class".
46 bless($self, $class);
47
48 # Assign logger object.
49 $logger = $self->{Logger};
50
51 # Log used firewall engine.
52 $logger->Log("debug", "Using firewall engine: $self->{FirewallEngine}");
53
54 # Try to load the specified firewall engine or die.
55 my $module_name = "Guardian::" . $self->{FirewallEngine};
56 eval "use $module_name; 1" or die "Could not load a module for firewall engine: $self->{FirewallEngine}!";
57
58 # Return the class object.
59 return $self;
60 }
61
62 #
63 ## The main "CheckAction" function.
64 #
65 ## This function is used to handle each recived event from the main event queue of guardian.
66 #
67 ## It will check if the given command is valid and will pass it to the responsible function.
68 #
69 sub CheckAction ($$) {
70 my $self = shift;
71 my @event = split(/ /, $_[0], 4);
72 my ($command, $address, $module, $message) = @event;
73
74 # Check if we got an invalid command.
75 unless(exists($commands{$command})) {
76 $logger->Log("err", "The CheckAction function has been called with an unsupported command ($command)!");
77 return;
78 }
79
80 # XXX
81 # Check if the given address is valid.
82
83 # Call required handler.
84 my $error = $commands{$command}->($self, $address, $module, $message);
85
86 # If we got any return code, something went wrong and should be logged.
87 if ($error) {
88 $logger->Log("err", "Got error: $error");
89 return;
90 }
91 }
92
93 #
94 ## The main "Counter" function.
95 #
96 ## This function is used to handle each count message + address, which has been sent by the main event
97 ## loop of guardian.
98 #
99 ## It stores the address and the current count into the counthash and increase the count each time when
100 ## the same address should be counted again. When the current count reaches the configured BlockCount,
101 ## the responsible function will be called to block the address.
102 #
103 sub Counter ($@) {
104 my $self = shift;
105 my ($address, $module, $message) = @_;
106
107 # Log event.
108 $logger->Log("debug", "$module reported $message for address: $address");
109
110 # Increase existing count or start counting for new source addresses.
111 if (exists($counthash{$address})) {
112 # Skip already blocked addresses.
113 if (exists($blockhash{$address})) {
114 return undef;
115 }
116
117 # Increase count of the existing entry.
118 $counthash{$address} = $counthash{$address} + 1;
119
120 # Log altered count of the address.
121 $logger->Log("debug", "Source $address now has count $counthash{$address}/$self->{BlockCount}...");
122 } else {
123 # Log that counting for the address has been started.
124 $logger->Log("debug", "Start counting for $address...");
125
126 # Set count to "1".
127 $counthash{$address} = 1;
128 }
129
130 # Check if the address has reached the configured count limit.
131 if ($counthash{$address} >= $self->{BlockCount}) {
132 # Write out log message.
133 $logger->Log("info", "Blocking $address for $self->{BlockTime} seconds...");
134
135 # Call block subroutine to block the address.
136 my $error = &CallBlock($self, $address, $module, $message);
137
138 # Return the message if an error occurs.
139 return $error;
140 }
141
142 # Everything worked well, return nothing.
143 return undef;
144 }
145
146 #
147 ## The RemoveBlocks function.
148 #
149 ## This function periodly will be called and is responsible for releasing the block if the Blocktime
150 ## on an address has expired.
151 #
152 ## To do this, the code will loop through all entries of the blockhash and check
153 ## if the estimiated BlockTime of each address has reached and so the block can be released.
154 #
155 sub RemoveBlocks () {
156 my $self = shift;
157
158 # Get the current time.
159 my $time = time();
160
161 # Loop through the blockhash.
162 foreach my $address (keys %blockhash) {
163 # Check if the blocktime for the address has expired.
164 if ($blockhash{$address} <= $time) {
165 # Call unblock subroutine.
166 my $error = &CallUnblock($self, $address, "BlockTime", "has expired for $address");
167
168 # Log error messages if returned.
169 if ($error) {
170 $logger->Log("err", "$error");
171 }
172 }
173 }
174
175 # Everything okay, return nothing.
176 return undef;
177 }
178
179 #
180 ## The CallBlock function.
181 #
182 ## This function is called, if the BlockCount for an address is reached or a direct
183 ## request for blocking an address has been recieved.
184 #
185 sub CallBlock ($@) {
186 my $self = shift;
187 my ($address, $module, $message) = @_;
188
189 # Log the call for blocking an address.
190 $logger->Log("info", "$module - $message");
191
192 # Check if an entry for this address exists
193 # in the blockhash. If not, the address has
194 # not been blocked yet, call the responisible
195 # function to do this now.
196 unless (exists($blockhash{$address})) {
197 # Obtain the configured FirewallAction.
198 my $action = $self->{FirewallAction};
199
200 # Block the given address.
201 my $error = &DoBlock($address, $action);
202
203 # If we got back an error message something went wrong.
204 if ($error) {
205 # Exit function and return the used FirewallEngine and the error message.
206 return "$self->{FirewallEngine} - $error";
207 } else {
208 # Address has been successfully blocked, print a log message.
209 $logger->Log("debug", "Address $address successfully has been blocked...");
210 }
211 }
212
213 # Generate time when the block will expire.
214 my $expire = time() + $self->{BlockTime};
215
216 # Store the blocked address and the expire time
217 # in the blockhash.
218 $blockhash{$address} = $expire;
219
220 # Return nothing "undef" if everything is okay.
221 return undef;
222 }
223
224 #
225 ## CallUnblock function.
226 #
227 ## This function is responsible for unblocking and deleting a given
228 ## address from the blockhash.
229 #
230 sub CallUnblock ($) {
231 my $self = shift;
232 my ($address, $module, $message) = @_;
233
234 # Log the call for unblocking an address.
235 $logger->Log("info", "$module - $message");
236
237 # Return an error if no entry for the given address
238 # is present in the blockhash.
239 unless (exists($blockhash{$address})) {
240 return "Address $address was not blocked!";
241 }
242
243 # Unblock the address.
244 my $error = &DoUnblock($address);
245
246 # If an error message is returned, something went wrong.
247 if ($error) {
248 # Exit function and return the error message.
249 return $error;
250 } else {
251 # Address successfully has been unblocked.
252 $logger->Log("debug", "Address $address successfully has been unblocked...");
253 }
254
255 # Drop address from blockhash.
256 delete ($blockhash{$address});
257
258 # Everything worked well, return nothing.
259 return undef;
260 }
261
262 1;