2 # Defines firewall functions for IPF
4 @actions = ( "allow", "deny", "reject" );
5 $script_file = "$module_config_directory/ipf.sh";
6 $nat_conf = "$module_config_directory/nat.conf";
9 # apply_rules(&rules, &hosts, &services)
10 # Turns the firewall configuration into an IPF script
13 &deactivate_all_interfaces(); # will add those needed later
14 local $ipfw = &has_command("ipfw");
17 open(SCRIPT, ">$script_file");
18 print SCRIPT "#!/bin/sh\n";
19 open(NATCONF, ">$nat_conf");
21 # Clear existing rules
22 print SCRIPT "$ipfw -f flush\n";
24 # Add rules for spoofing
25 local ($spoofiface, @nets) = &get_spoof();
30 print_ipfw("drop ip from $n to any recv $spoofiface");
34 # Allow established connections
36 print_ipfw("allow tcp from any to any established");
38 # Always allow localhost
40 print_ipfw("allow ip from any to any recv lo");
42 if ($config{'frags'}) {
49 local @rules = &list_rules();
50 local %services = map { $_->{'name'}, $_ } &list_services();
51 local @groups = &list_groups();
53 next if (!$r->{'enabled'});
54 next if ($r->{'sep'});
55 $num = $r->{'num'}*10;
57 # Work out all source and destination hosts?
58 local @sources = &expand_hosts($r->{'source'}, \@groups);
59 local @dests = &expand_hosts($r->{'dest'}, \@groups);
61 # Need to output a rule for every possible combination
62 local ($source, $dest);
63 local $aarg = $r->{'action'};
64 local $logarg = $r->{'log'} ? "log" : "";
65 foreach $source (@sources) {
66 $source =~ s/^!(\S.*)$/not $1/;
67 local $sarg = $source eq '*' ? "from any" :
68 $source =~ /^%(.*)$/ ? "from any" :
70 local $siarg = $source =~ /^%(.*)$/ ? "xmit $1" : "";
72 foreach $dest (@dests) {
73 $dest =~ s/^!(\S.*)$/! $1/;
74 local $darg = $dest eq '*' && !$config{'fw_any'} &&
75 $r->{'action'} eq 'allow' ? "! -d me" :
76 $dest =~ /^%(.*)$/ ? "to any" :
78 local $diarg = $dest =~ /^%(.*)$/ ? "recv $1" : "";
80 if ($r->{'service'} ne '*') {
81 # Output one rule for each service
82 local ($protos, $ports) =
83 &combine_services($r->{'service'},
85 for($i=0; $i<@$protos; $i++) {
86 local $pr = lc($protos->[$i]);
87 local $pt = $ports->[$i];
93 # handle old GRE protocols
106 elsif ($pt =~ /^(\d+)$/ || $pt eq '*') {
108 $opts = " icmptype $pt" if ($pt ne '*');
114 elsif ($pt =~ /^(\d+)\-(\d+)$/) {
118 $parg = join(",", split(/\s+/, $pt));
120 print_ipfw("$aarg $logarg $prarg $sarg $darg $parg $opts $siarg $diarg");
124 # Single service-independent rule
125 print_ipfw("$aarg $logarg ip $sarg $darg $siarg $diarg");
131 # Add syn flood and spoofing rules
132 local ($flood, $spoof, $fin) = &get_syn();
134 # Configure kernel to use syn cookies
135 print SCRIPT "sysctl net.inet.tcp.syncookies=1\n";
138 # Configure kernel to disable syn cookies
139 print SCRIPT "sysctl net.inet.tcp.syncookies=0\n";
142 # Drop TCP connection starts without SYN set
144 print_ipfw("allow tcp from any to any established");
145 print_ipfw("deny tcp from any to any tcpflags !syn");
148 # Drop TCP packets with both SYN and FIN set
150 print_ipfw("deny tcp from any to any tcpflags syn,fin");
153 local ($natiface, @nets) = &get_nat();
157 @maps = grep { ref($_) } @nets;
158 @nets = grep { !ref($_) } @nets;
161 # Add rule for static NAT (internal to external host mapping)
162 print NATCONF "map $natiface $m->[1]/32 -> $m->[0]/32\n";
163 print NATCONF "map $natiface $m->[0]/32 -> $m->[1]/32\n";
165 &activate_interface($m->[2], $m->[0]);
170 # Add rule for dynamic NAT
171 local @sources = &expand_hosts("\@$n", \@groups);
173 foreach $source (@sources) {
174 $source =~ s/^!(\S.*)$/! $1/;
175 print NATCONF "map $natiface $source -> 0/32\n";
180 # Add rules for PAT (external port to internal host mapping)
181 local @forwards = &get_pat();
183 foreach $f (@forwards) {
184 next if (!$f->{'iface'});
185 local ($protos, $ports) = &combine_services($f->{'service'},
188 for($i=0; $i<@$protos; $i++) {
189 local $pr = lc($protos->[$i]);
190 local $pt = $ports->[$i];
191 next if ($pr ne 'tcp' && $pr ne 'udp');
192 print NATCONF "rdr $f->{'iface'} 0/32 port $pt -> $f->{'host'} port $pt $pr\n";
196 # Allow all by default
198 print_ipfw("allow ip from any to any");
200 chmod(0755, $script_file);
204 #return "<pre>".`cat $script_file`."</pre>\n";
205 local $out = `cd /; $script_file 2>&1 </dev/null`;
207 return "IPF script output : <pre>$out</pre>";
211 $out = `cd /; ipnat -C >/dev/null ; ipnat -f $nat_conf 2>&1 </dev/null`;
213 return "ipnat command output : <pre>$out</pre>";
221 print SCRIPT "$ipfw add $num $_[0]\n";
228 &deactivate_all_interfaces();
229 system("cd /; ipfw -f flush; ipfw add allow ip from any to any");
230 system("cd /; ipnat -C");
234 # Enable routing under BSD
237 system("sysctl net.inet.ip.forwarding=1 >/dev/null 2>&1");
241 # Disable routing under BSD
244 system("sysctl net.inet.ip.forwarding=0 >/dev/null 2>&1");
249 return "/var/log/security";
254 return "/var/log/security";
259 return $_[0] =~ /\sipfw:\s/;
263 @time_now = localtime($time_now);
264 %mmap = ( 'jan' => 0, 'feb' => 1, 'mar' => 2, 'apr' => 3,
265 'may' => 4, 'jun' => 5, 'jul' => 6, 'aug' => 7,
266 'sep' => 8, 'oct' => 9, 'nov' =>10, 'dec' =>11 );
268 # parse_log_line(line)
269 # Parses a line into a log info structure, or returns undef
272 if (&is_log_line($_[0])) {
274 if ($_[0] =~ /^(\S+)\s+(\d+)\s+(\d+):(\d+):(\d+)/) {
275 local $tm = timelocal($5, $4, $3, $2, $mmap{lc($1)}, $time_now[5]);
276 if ($tm > $time_now + 24*60*60) {
277 # Was really last year
278 $tm = timelocal($5, $4, $3, $2, $mmap{lc($1)}, $time_now[5]-1);
280 $info->{'time'} = $tm;
282 if ($_[0] =~ /ipfw:\s+(\d+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(in|out)\s+\S+\s+(\S+)/) {
283 if ($1 >= 10 && $1 < 60000) {
284 $info->{'rule'} = int($1/10);
286 $info->{'action'} = lc($2);
287 $info->{'action'} = "allow" if ($info->{'action'} eq "accept");
288 $info->{'proto'} = uc($3);
290 $info->{'dst_iface'} = $7;
293 $info->{'src_iface'} = $7;
295 local ($src, $dst) = ($4, $5);
296 if ($src =~ /^(\S+):(\d+)$/) {
298 $info->{'src_port'} = $2;
301 $info->{'src'} = $src;
303 if ($dst =~ /^(\S+):(\d+)$/) {
305 $info->{'dst_port'} = $2;
308 $info->{'dst'} = $dst;
310 if ($info->{'proto'} =~ /^(ICMP):(\d+)/) {
311 $info->{'proto'} = $1;
312 $info->{'dst_port'} = $2;
324 return $_[0]->{'action'} eq 'allow';
329 return $_[0]->{'action'} eq 'deny';
342 sub supports_bandwidth