]>
Commit | Line | Data |
---|---|---|
5b0b4182 SS |
1 | #!/usr/bin/perl |
2 | ############################################################################### | |
3 | # # | |
4 | # IPFire.org - A linux based firewall # | |
e698090e | 5 | # Copyright (C) 2020 IPFire Development Team <info@ipfire.org> # |
5b0b4182 SS |
6 | # # |
7 | # This program is free software: you can redistribute it and/or modify # | |
8 | # it under the terms of the GNU General Public License as published by # | |
9 | # the Free Software Foundation, either version 3 of the License, or # | |
10 | # (at your option) any later version. # | |
11 | # # | |
12 | # This program is distributed in the hope that it will be useful, # | |
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # | |
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # | |
15 | # GNU General Public License for more details. # | |
16 | # # | |
17 | # You should have received a copy of the GNU General Public License # | |
18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. # | |
19 | # # | |
20 | ############################################################################### | |
21 | ||
22 | use strict; | |
23 | ||
24 | require '/var/ipfire/general-functions.pl'; | |
25 | require "${General::swroot}/ids-functions.pl"; | |
26 | ||
27 | # Snort settings file, which contains the settings from the WUI. | |
28 | my $snort_settings_file = "${General::swroot}/snort/settings"; | |
29 | ||
30 | # Main snort config file. | |
31 | my $snort_config_file = "/etc/snort/snort.conf"; | |
32 | ||
33 | # Snort rules tarball. | |
34 | my $snort_rules_tarball = "/var/tmp/snortrules.tar.gz"; | |
35 | ||
5b0b4182 | 36 | # |
cde7cab2 SS |
37 | ## Step 1: Convert snort user and group to suricata if exist. |
38 | # | |
39 | ||
40 | # Check if the snort user exists. | |
41 | if (getpwnam("snort")) { | |
42 | # Change username. | |
43 | my @command = ( | |
44 | '/usr/sbin/usermod', | |
45 | '-l', 'suricata', 'snort' | |
46 | ); | |
47 | ||
48 | system(@command) == 0 or die "Could not change username: @command failed: $?\n"; | |
49 | ||
50 | # Adjust home directory. | |
51 | @command = ( | |
52 | '/usr/sbin/usermod', | |
53 | '-d', "/var/log/suricata", | |
54 | 'suricata' | |
55 | ); | |
56 | ||
57 | system(@command) == 0 or die "Failed to adjust home directory: @command failed: $?\n"; | |
58 | } | |
59 | ||
60 | # Check if the snort group exists. | |
61 | if (getgrnam("snort")) { | |
62 | # Change groupname | |
63 | my @command = ( | |
64 | '/usr/sbin/groupmod', | |
65 | '-n', 'suricata', 'snort' | |
66 | ); | |
67 | ||
68 | system(@command) == 0 or die "Could not rename groupname: @command failed: $?\n"; | |
69 | } | |
70 | ||
71 | # | |
72 | ## Step 2: Setup directory and file layout, if not present and set correct | |
5b0b4182 SS |
73 | ## ownership. The converter runs as a privileged user, but the files |
74 | ## needs to be full access-able by the WUI user and group (nobody:nobody). | |
75 | # | |
76 | ||
5b0b4182 SS |
77 | # Check if the settings directory exists. |
78 | unless (-d $IDS::settingsdir) { | |
79 | # Create the directory. | |
80 | mkdir($IDS::settingsdir); | |
81 | } | |
82 | ||
83 | # Check if the rules directory exists. | |
84 | unless (-d $IDS::rulespath) { | |
85 | # Create the directory. | |
86 | mkdir($IDS::rulespath); | |
87 | } | |
88 | ||
5b0b4182 SS |
89 | # Create file layout, if not exists yet. |
90 | &IDS::check_and_create_filelayout(); | |
91 | ||
36e69d34 SS |
92 | # Set correct ownership for settingsdir and rulespath. |
93 | &IDS::set_ownership("$IDS::settingsdir"); | |
94 | &IDS::set_ownership("$IDS::rulespath"); | |
5b0b4182 | 95 | |
78690361 SS |
96 | # Check if a snort settings file exists. |
97 | unless( -f "$snort_settings_file") { | |
98 | print "$snort_settings_file not found - Nothing to do. Exiting!\n"; | |
99 | exit(0); | |
100 | } | |
101 | ||
102 | # Check if the snort settings file is empty. | |
103 | if (-z "$snort_settings_file") { | |
104 | print "$snort_settings_file is empty - Nothing to do. Exiting!\n"; | |
105 | exit(0); | |
106 | } | |
107 | ||
5b0b4182 | 108 | # |
cde7cab2 | 109 | ## Step 3: Import snort settings and convert to the required format for the new IDS |
5b0b4182 SS |
110 | ## (suricata). |
111 | # | |
112 | ||
113 | # Hash which contains the "old" snort settings. | |
114 | my %snortsettings; | |
115 | ||
116 | # Hash which contains the IDS (suricata) settings. | |
117 | # | |
118 | # Add default value for MONITOR_TRAFFIC_ONLY which will be "on" | |
119 | # when migrating from snort to the new IDS. | |
120 | my %idssettings = ( | |
121 | "MONITOR_TRAFFIC_ONLY" => "on", | |
122 | ); | |
123 | ||
124 | # Hash which contains the RULES settings. | |
125 | # | |
126 | # Set default value for UPDATE_INTERVAL to weekly. | |
127 | my %rulessettings = ( | |
128 | "AUTOUPDATE_INTERVAL" => "weekly", | |
129 | ); | |
130 | ||
131 | # Get all available network zones. | |
132 | my @network_zones = &IDS::get_available_network_zones(); | |
133 | ||
134 | # Read-in snort settings file. | |
135 | &General::readhash("$snort_settings_file", \%snortsettings); | |
136 | ||
137 | # Loop through the array of network zones. | |
138 | foreach my $zone (@network_zones) { | |
139 | # Convert current zone into upper case. | |
140 | my $zone_upper = uc($zone); | |
141 | ||
142 | # Check if the current network zone is "red". | |
143 | if($zone eq "red") { | |
144 | # Check if snort was enabled and enabled on red. | |
145 | if ($snortsettings{"ENABLE_SNORT"} eq "on") { | |
146 | # Enable the IDS. | |
147 | $idssettings{"ENABLE_IDS"} = "on"; | |
148 | ||
149 | # Enable the IDS on RED. | |
150 | $idssettings{"ENABLE_IDS_$zone_upper"} = "on"; | |
151 | } | |
152 | } else { | |
153 | # Check if snort was enabled on the current zone. | |
154 | if ($snortsettings{"ENABLE_SNORT_$zone_upper"} eq "on") { | |
155 | # Enable the IDS on this zone too. | |
156 | $idssettings{"ENABLE_IDS_$zone_upper"} = "on"; | |
157 | } | |
158 | } | |
159 | } | |
160 | ||
161 | # Grab the choosen ruleset from snort settings hash and store it in the rules | |
162 | # settings hash. | |
163 | $rulessettings{"RULES"} = $snortsettings{"RULES"}; | |
164 | ||
165 | # Check if an oinkcode has been provided. | |
166 | if($snortsettings{"OINKCODE"}) { | |
167 | # Take the oinkcode from snort settings hash and store it in the rules | |
168 | # settings hash. | |
169 | $rulessettings{"OINKCODE"} = $snortsettings{"OINKCODE"}; | |
170 | } | |
171 | ||
172 | # | |
cde7cab2 | 173 | ## Step 4: Import guardian settings and whitelist if the addon is installed. |
5b0b4182 SS |
174 | # |
175 | ||
176 | # Pakfire meta file for owncloud. | |
177 | # (File exists when the addon is installed.) | |
178 | my $guardian_meta = "/opt/pakfire/db/installed/meta-guardian"; | |
179 | ||
180 | # Check if the guardian addon is installed. | |
181 | if (-f $guardian_meta) { | |
182 | # File which contains the taken setting for guardian. | |
183 | my $guardian_settings_file = "${General::swroot}/guardian/settings"; | |
184 | ||
185 | # File which contains the white-listed hosts. | |
186 | my $guardian_ignored_file = "${General::swroot}/guardian/ignored"; | |
187 | ||
188 | # Hash which will contain the settings of guardian. | |
189 | my %guardiansettings; | |
190 | ||
191 | # Check if the settings file of guardian is empty. | |
192 | unless (-z $guardian_settings_file) { | |
193 | # Read-in settings. | |
194 | &General::readhash("$guardian_settings_file", \%guardiansettings); | |
195 | } | |
196 | ||
197 | # Check if guardian is not configured to take actions on snort events. | |
198 | if ($guardiansettings{"GUARDIAN_MONITOR_SNORT"} eq "on") { | |
199 | # Change the IDS into MONITOR_TRAFFIC_ONLY mode. | |
200 | $idssettings{"MONITOR_TRAFFIC_ONLY"} = "off"; | |
201 | } | |
202 | ||
203 | # Check if guardian has any white-listed hosts configured. | |
204 | unless (-z $guardian_ignored_file) { | |
205 | # Temporary hash to store the ignored hosts. | |
206 | my %ignored_hosts; | |
207 | ||
208 | # Read-in white-listed hosts and store them in the hash. | |
209 | &General::readhasharray($guardian_ignored_file, \%ignored_hosts); | |
210 | ||
211 | # Write-out the white-listed hosts for the IDS system. | |
212 | &General::writehasharray($IDS::ignored_file, \%ignored_hosts); | |
213 | ||
214 | # Call subfunction to generate the file for white-listing the hosts. | |
215 | &IDS::generate_ignored_file(); | |
216 | } | |
217 | ||
218 | } | |
219 | ||
220 | # | |
cde7cab2 | 221 | ## Step 5: Save IDS and rules settings. |
5b0b4182 SS |
222 | # |
223 | ||
224 | # Write IDS settings. | |
225 | &General::writehash("$IDS::ids_settings_file", \%idssettings); | |
226 | ||
227 | # Write rules settings. | |
228 | &General::writehash("$IDS::rules_settings_file", \%rulessettings); | |
229 | ||
230 | # | |
cde7cab2 | 231 | ## Step 6: Generate and write the file to modify the ruleset. |
5b0b4182 SS |
232 | # |
233 | ||
5b0b4182 | 234 | # Call subfunction and pass the desired IDS action. |
f1add9a8 | 235 | &IDS::write_modify_sids_file(); |
5b0b4182 | 236 | |
5d7d8749 SS |
237 | # Set correct ownership. |
238 | &IDS::set_ownership("$IDS::modify_sids_file"); | |
239 | ||
5b0b4182 | 240 | # |
cde7cab2 | 241 | ## Step 7: Move rulestarball to its new location. |
5b0b4182 SS |
242 | # |
243 | ||
244 | # Check if a rulestarball has been downloaded yet. | |
245 | if (-f $snort_rules_tarball) { | |
246 | # Load perl module which contains the move command. | |
247 | use File::Copy; | |
248 | ||
249 | # Move the rulestarball to the new location. | |
250 | move($snort_rules_tarball, $IDS::rulestarball); | |
251 | ||
252 | # Set correct ownership. | |
b09c13f1 | 253 | &IDS::set_ownership("$IDS::rulestarball"); |
cc636c47 SS |
254 | |
255 | # In case no tarball is present, try to download the ruleset. | |
256 | } else { | |
257 | # Check if enought disk space is available. | |
258 | if(&IDS::checkdiskspace()) { | |
e4bc9b8b SS |
259 | # Print error message. |
260 | print "Could not download ruleset - Not enough free diskspace available.\n"; | |
261 | } else { | |
cc636c47 SS |
262 | # Call the download function and grab the new ruleset. |
263 | &IDS::downloadruleset(); | |
264 | } | |
5b0b4182 SS |
265 | } |
266 | ||
267 | # | |
cde7cab2 | 268 | ## Step 8: Call oinkmaster to extract and setup the rules structures. |
5b0b4182 SS |
269 | # |
270 | ||
271 | # Check if a rulestarball is present. | |
272 | if (-f $IDS::rulestarball) { | |
273 | # Launch oinkmaster by calling the subfunction. | |
274 | &IDS::oinkmaster(); | |
cc636c47 SS |
275 | |
276 | # Set correct ownership for the rulesdir and files. | |
277 | &IDS::set_ownership("$IDS::rulespath"); | |
5b0b4182 SS |
278 | } |
279 | ||
280 | # | |
cde7cab2 | 281 | ## Step 9: Generate file for the HOME Net. |
ee82349a SS |
282 | # |
283 | ||
284 | # Call subfunction to generate the file. | |
285 | &IDS::generate_home_net_file(); | |
286 | ||
25d42438 SS |
287 | # Set correct ownership for the homenet file. |
288 | &IDS::set_ownership("$IDS::homenet_file"); | |
289 | ||
ee82349a | 290 | # |
cde7cab2 | 291 | ## Step 10: Generate file for the DNS servers. |
bb2696da SS |
292 | # |
293 | ||
294 | # Call subfunction to generate the file. | |
295 | &IDS::generate_dns_servers_file(); | |
296 | ||
297 | # Set correct ownership for the dns_servers_file. | |
298 | &IDS::set_ownership("$IDS::dns_servers_file"); | |
299 | ||
300 | # | |
e698090e SS |
301 | ## Step 11: Generate file which contains the HTTP ports. |
302 | # | |
303 | ||
304 | # Call subfunction to generate the file. | |
305 | &IDS::generate_http_ports_file(); | |
306 | ||
307 | # Set correct ownership for the http_ports_file. | |
308 | &IDS::set_ownership("$IDS::http_ports_file"); | |
309 | ||
310 | # | |
311 | ## Step 12: Setup automatic ruleset updates. | |
ee82349a SS |
312 | # |
313 | ||
314 | # Check if a ruleset is configured. | |
315 | if($rulessettings{"RULES"}) { | |
316 | # Call suricatactrl and setup the periodic update mechanism. | |
317 | &IDS::call_suricatactrl("cron", $rulessettings{'AUTOUPDATE_INTERVAL'}); | |
318 | } | |
319 | ||
320 | # | |
e698090e | 321 | ## Step 13: Grab used ruleset files from snort config file and convert |
5b0b4182 SS |
322 | ## them into the new format. |
323 | # | |
324 | ||
325 | # Check if the snort config file exists. | |
326 | unless (-f $snort_config_file) { | |
327 | print "$snort_config_file does not exist - Nothing to do. Exiting!\n"; | |
328 | exit(0); | |
329 | } | |
330 | ||
331 | # Array to store the enabled rules files. | |
332 | my @enabled_rule_files; | |
333 | ||
334 | # Open snort config file. | |
335 | open(SNORTCONF, $snort_config_file) or die "Could not open $snort_config_file. $!\n"; | |
336 | ||
337 | # Loop through the file content. | |
338 | while (my $line = <SNORTCONF>) { | |
339 | # Skip comments. | |
340 | next if ($line =~ /\#/); | |
341 | ||
342 | # Skip blank lines. | |
343 | next if ($line =~ /^\s*$/); | |
344 | ||
345 | # Remove newlines. | |
346 | chomp($line); | |
347 | ||
348 | # Check for a line with .rules | |
349 | if ($line =~ /\.rules$/) { | |
350 | # Parse out rule file name | |
351 | my $rulefile = $line; | |
352 | $rulefile =~ s/\$RULE_PATH\///i; | |
353 | $rulefile =~ s/ ?include ?//i; | |
354 | ||
355 | # Add the enabled rulefile to the array of enabled rule files. | |
356 | push(@enabled_rule_files, $rulefile); | |
357 | } | |
358 | } | |
359 | ||
360 | # Close filehandle. | |
361 | close(SNORTCONF); | |
362 | ||
363 | # Pass the array of enabled rule files to the subfunction and write the file. | |
364 | &IDS::write_used_rulefiles_file(@enabled_rule_files); | |
365 | ||
5b0b4182 | 366 | # |
e698090e | 367 | ## Step 14: Start the IDS if enabled. |
5b0b4182 SS |
368 | # |
369 | ||
370 | # Check if the IDS should be started. | |
371 | if($idssettings{"ENABLE_IDS"} eq "on") { | |
372 | # Call suricatactrl and launch the IDS. | |
373 | &IDS::call_suricatactrl("start"); | |
374 | } |