]> git.ipfire.org Git - ipfire-2.x.git/blame - config/firewall/firewall-lib.pl
bash: Update to version 4.3.30
[ipfire-2.x.git] / config / firewall / firewall-lib.pl
CommitLineData
2a81ab0d
AM
1#!/usr/bin/perl
2###############################################################################
3# #
4# IPFire.org - A linux based firewall #
5bee9a9d 5# Copyright (C) 2013 Alexander Marx <amarx@ipfire.org> #
2a81ab0d
AM
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###############################################################################
2a81ab0d
AM
21
22use strict;
23no warnings 'uninitialized';
24
25package fwlib;
26
27my %customnetwork=();
28my %customhost=();
29my %customgrp=();
30my %customservice=();
31my %customservicegrp=();
32my %ccdnet=();
33my %ccdhost=();
34my %ipsecconf=();
35my %ipsecsettings=();
36my %netsettings=();
37my %ovpnsettings=();
4e54e3c6 38my %aliases=();
2a81ab0d
AM
39
40require '/var/ipfire/general-functions.pl';
41
42my $confignet = "${General::swroot}/fwhosts/customnetworks";
43my $confighost = "${General::swroot}/fwhosts/customhosts";
44my $configgrp = "${General::swroot}/fwhosts/customgroups";
45my $configsrv = "${General::swroot}/fwhosts/customservices";
46my $configsrvgrp = "${General::swroot}/fwhosts/customservicegrp";
47my $configccdnet = "${General::swroot}/ovpn/ccd.conf";
48my $configccdhost = "${General::swroot}/ovpn/ovpnconfig";
49my $configipsec = "${General::swroot}/vpn/config";
50my $configovpn = "${General::swroot}/ovpn/settings";
51my $val;
52my $field;
fd169d0a 53my $netsettings = "${General::swroot}/ethernet/settings";
2a81ab0d
AM
54
55&General::readhash("/var/ipfire/ethernet/settings", \%netsettings);
56&General::readhash("${General::swroot}/ovpn/settings", \%ovpnsettings);
57&General::readhash("${General::swroot}/vpn/settings", \%ipsecsettings);
2a81ab0d
AM
58
59&General::readhasharray("$confignet", \%customnetwork);
60&General::readhasharray("$confighost", \%customhost);
61&General::readhasharray("$configgrp", \%customgrp);
62&General::readhasharray("$configccdnet", \%ccdnet);
63&General::readhasharray("$configccdhost", \%ccdhost);
64&General::readhasharray("$configipsec", \%ipsecconf);
65&General::readhasharray("$configsrv", \%customservice);
66&General::readhasharray("$configsrvgrp", \%customservicegrp);
085a20ec 67&General::get_aliases(\%aliases);
2a81ab0d
AM
68
69sub get_srv_prot
70{
71 my $val=shift;
992394d5 72 foreach my $key (sort {$a <=> $b} keys %customservice){
2a81ab0d
AM
73 if($customservice{$key}[0] eq $val){
74 if ($customservice{$key}[0] eq $val){
75 return $customservice{$key}[2];
76 }
77 }
78 }
79}
80sub get_srvgrp_prot
81{
82 my $val=shift;
83 my @ips=();
84 my $tcp;
85 my $udp;
86 my $icmp;
992394d5 87 foreach my $key (sort {$a <=> $b} keys %customservicegrp){
2a81ab0d
AM
88 if($customservicegrp{$key}[0] eq $val){
89 if (&get_srv_prot($customservicegrp{$key}[2]) eq 'TCP'){
90 $tcp=1;
91 }elsif(&get_srv_prot($customservicegrp{$key}[2]) eq 'UDP'){
92 $udp=1;
93 }elsif(&get_srv_prot($customservicegrp{$key}[2]) eq 'ICMP'){
94 $icmp=1;
82b837cf
AM
95 }else{
96 #Protocols used in servicegroups
97 push (@ips,$customservicegrp{$key}[2]);
98 }
2a81ab0d
AM
99 }
100 }
101 if ($tcp eq '1'){push (@ips,'TCP');}
102 if ($udp eq '1'){push (@ips,'UDP');}
103 if ($icmp eq '1'){push (@ips,'ICMP');}
104 my $back=join(",",@ips);
105 return $back;
106
107}
2a81ab0d
AM
108sub get_srv_port
109{
110 my $val=shift;
111 my $field=shift;
112 my $prot=shift;
992394d5 113 foreach my $key (sort {$a <=> $b} keys %customservice){
14bcb9a2
AM
114 if($customservice{$key}[0] eq $val && $customservice{$key}[2] eq $prot){
115 return $customservice{$key}[$field];
2a81ab0d
AM
116 }
117 }
118}
119sub get_srvgrp_port
120{
121 my $val=shift;
122 my $prot=shift;
123 my $back;
124 my $value;
125 my @ips=();
992394d5 126 foreach my $key (sort {$a <=> $b} keys %customservicegrp){
2a81ab0d
AM
127 if($customservicegrp{$key}[0] eq $val){
128 if ($prot ne 'ICMP'){
129 $value=&get_srv_port($customservicegrp{$key}[2],1,$prot);
130 }elsif ($prot eq 'ICMP'){
131 $value=&get_srv_port($customservicegrp{$key}[2],3,$prot);
132 }
133 push (@ips,$value) if ($value ne '') ;
134 }
135 }
136 if($prot ne 'ICMP'){
137 if ($#ips gt 0){$back="-m multiport --dports ";}else{$back="--dport ";}
138 }elsif ($prot eq 'ICMP'){
139 $back="--icmp-type ";
140 }
141
142 $back.=join(",",@ips);
143 return $back;
144}
145sub get_ipsec_net_ip
146{
147 my $val=shift;
148 my $field=shift;
992394d5 149 foreach my $key (sort {$a <=> $b} keys %ipsecconf){
2a81ab0d
AM
150 if($ipsecconf{$key}[1] eq $val){
151 return $ipsecconf{$key}[$field];
152 }
153 }
154}
155sub get_ipsec_host_ip
156{
157 my $val=shift;
158 my $field=shift;
992394d5 159 foreach my $key (sort {$a <=> $b} keys %ipsecconf){
2a81ab0d
AM
160 if($ipsecconf{$key}[1] eq $val){
161 return $ipsecconf{$key}[$field];
162 }
163 }
164}
165sub get_ovpn_n2n_ip
166{
167 my $val=shift;
168 my $field=shift;
992394d5 169 foreach my $key (sort {$a <=> $b} keys %ccdhost){
2a81ab0d
AM
170 if($ccdhost{$key}[1] eq $val){
171 return $ccdhost{$key}[$field];
172 }
173 }
174}
175sub get_ovpn_host_ip
176{
177 my $val=shift;
178 my $field=shift;
992394d5 179 foreach my $key (sort {$a <=> $b} keys %ccdhost){
2a81ab0d
AM
180 if($ccdhost{$key}[1] eq $val){
181 return $ccdhost{$key}[$field];
182 }
183 }
184}
185sub get_ovpn_net_ip
186{
187
188 my $val=shift;
189 my $field=shift;
992394d5 190 foreach my $key (sort {$a <=> $b} keys %ccdnet){
2a81ab0d
AM
191 if($ccdnet{$key}[0] eq $val){
192 return $ccdnet{$key}[$field];
193 }
194 }
195}
196sub get_grp_ip
197{
198 my $val=shift;
199 my $src=shift;
992394d5 200 foreach my $key (sort {$a <=> $b} keys %customgrp){
2a81ab0d
AM
201 if ($customgrp{$key}[0] eq $val){
202 &get_address($customgrp{$key}[3],$src);
203 }
204 }
205
206}
207sub get_std_net_ip
208{
209 my $val=shift;
ddcec9d3 210 my $con=shift;
2a81ab0d
AM
211 if ($val eq 'ALL'){
212 return "0.0.0.0/0.0.0.0";
213 }elsif($val eq 'GREEN'){
214 return "$netsettings{'GREEN_NETADDRESS'}/$netsettings{'GREEN_NETMASK'}";
215 }elsif($val eq 'ORANGE'){
216 return "$netsettings{'ORANGE_NETADDRESS'}/$netsettings{'ORANGE_NETMASK'}";
217 }elsif($val eq 'BLUE'){
218 return "$netsettings{'BLUE_NETADDRESS'}/$netsettings{'BLUE_NETMASK'}";
62fc8511 219 }elsif($val eq 'RED'){
48f07c19 220 return "0.0.0.0/0";
2a81ab0d
AM
221 }elsif($val =~ /OpenVPN/i){
222 return "$ovpnsettings{'DOVPN_SUBNET'}";
223 }elsif($val =~ /IPsec/i){
224 return "$ipsecsettings{'RW_NET'}";
5d7faa45
AM
225 }elsif($val eq 'IPFire'){
226 return ;
2a81ab0d
AM
227 }
228}
48f07c19
AM
229sub get_interface
230{
231 my $net=shift;
232 if($net eq "$netsettings{'GREEN_NETADDRESS'}/$netsettings{'GREEN_NETMASK'}"){
233 return "$netsettings{'GREEN_DEV'}";
234 }
235 if($net eq "$netsettings{'ORANGE_NETADDRESS'}/$netsettings{'ORANGE_NETMASK'}"){
236 return "$netsettings{'ORANGE_DEV'}";
237 }
238 if($net eq "$netsettings{'BLUE_NETADDRESS'}/$netsettings{'BLUE_NETMASK'}"){
239 return "$netsettings{'BLUE_DEV'}";
240 }
241 if($net eq "0.0.0.0/0"){
242 return "$netsettings{'RED_DEV'}";
243 }
244 return "";
245}
2a81ab0d
AM
246sub get_net_ip
247{
248 my $val=shift;
992394d5 249 foreach my $key (sort {$a <=> $b} keys %customnetwork){
2a81ab0d
AM
250 if($customnetwork{$key}[0] eq $val){
251 return "$customnetwork{$key}[1]/$customnetwork{$key}[2]";
252 }
253 }
254}
255sub get_host_ip
256{
257 my $val=shift;
258 my $src=shift;
992394d5 259 foreach my $key (sort {$a <=> $b} keys %customhost){
2a81ab0d
AM
260 if($customhost{$key}[0] eq $val){
261 if ($customhost{$key}[1] eq 'mac' && $src eq 'src'){
262 return "-m mac --mac-source $customhost{$key}[2]";
263 }elsif($customhost{$key}[1] eq 'ip' && $src eq 'src'){
264 return "$customhost{$key}[2]";
265 }elsif($customhost{$key}[1] eq 'ip' && $src eq 'tgt'){
266 return "$customhost{$key}[2]";
267 }elsif($customhost{$key}[1] eq 'mac' && $src eq 'tgt'){
268 return "none";
269 }
270 }
271 }
272}
fd169d0a
AM
273sub get_addresses
274{
4e54e3c6
AM
275 my $hash = shift;
276 my $key = shift;
277 my $type = shift;
278
279 my @addresses = ();
280 my $addr_type;
281 my $value;
282 my $group_name;
283
284 if ($type eq "src") {
285 $addr_type = $$hash{$key}[3];
286 $value = $$hash{$key}[4];
287
288 } elsif ($type eq "tgt") {
289 $addr_type = $$hash{$key}[5];
290 $value = $$hash{$key}[6];
291 }
292
293 if ($addr_type ~~ ["cust_grp_src", "cust_grp_tgt"]) {
294 foreach my $grp (sort {$a <=> $b} keys %customgrp) {
295 if ($customgrp{$grp}[0] eq $value) {
296 my @address = &get_address($customgrp{$grp}[3], $customgrp{$grp}[2], $type);
297
298 if (@address) {
299 push(@addresses, @address);
300 }
301 }
302 }
303 } else {
304 my @address = &get_address($addr_type, $value, $type);
305
306 if (@address) {
307 push(@addresses, @address);
308 }
309 }
310
311 return @addresses;
312}
fd169d0a
AM
313sub get_address
314{
4e54e3c6
AM
315 my $key = shift;
316 my $value = shift;
317 my $type = shift;
318
319 my @ret = ();
320
321 # If the user manually typed an address, we just check if it is a MAC
322 # address. Otherwise, we assume that it is an IP address.
323 if ($key ~~ ["src_addr", "tgt_addr"]) {
324 if (&General::validmac($value)) {
48f07c19 325 push(@ret, ["-m mac --mac-source $value", ""]);
4e54e3c6 326 } else {
48f07c19 327 push(@ret, [$value, ""]);
4e54e3c6
AM
328 }
329
330 # If a default network interface (GREEN, BLUE, etc.) is selected, we
331 # try to get the corresponding address of the network.
332 } elsif ($key ~~ ["std_net_src", "std_net_tgt", "Standard Network"]) {
333 my $external_interface = &get_external_interface();
334
335 my $network_address = &get_std_net_ip($value, $external_interface);
48f07c19 336
4e54e3c6 337 if ($network_address) {
48f07c19
AM
338 my $interface = &get_interface($network_address);
339 push(@ret, [$network_address, $interface]);
4e54e3c6
AM
340 }
341
342 # Custom networks.
343 } elsif ($key ~~ ["cust_net_src", "cust_net_tgt", "Custom Network"]) {
344 my $network_address = &get_net_ip($value);
345 if ($network_address) {
48f07c19 346 push(@ret, [$network_address, ""]);
4e54e3c6
AM
347 }
348
349 # Custom hosts.
350 } elsif ($key ~~ ["cust_host_src", "cust_host_tgt", "Custom Host"]) {
351 my $host_address = &get_host_ip($value, $type);
352 if ($host_address) {
48f07c19 353 push(@ret, [$host_address, ""]);
4e54e3c6
AM
354 }
355
356 # OpenVPN networks.
357 } elsif ($key ~~ ["ovpn_net_src", "ovpn_net_tgt", "OpenVPN static network"]) {
358 my $network_address = &get_ovpn_net_ip($value, 1);
359 if ($network_address) {
48f07c19 360 push(@ret, [$network_address, ""]);
4e54e3c6
AM
361 }
362
363 # OpenVPN hosts.
364 } elsif ($key ~~ ["ovpn_host_src", "ovpn_host_tgt", "OpenVPN static host"]) {
365 my $host_address = &get_ovpn_host_ip($value, 33);
366 if ($host_address) {
48f07c19 367 push(@ret, [$host_address, ""]);
4e54e3c6
AM
368 }
369
370 # OpenVPN N2N.
371 } elsif ($key ~~ ["ovpn_n2n_src", "ovpn_n2n_tgt", "OpenVPN N-2-N"]) {
372 my $network_address = &get_ovpn_n2n_ip($value, 11);
373 if ($network_address) {
48f07c19 374 push(@ret, [$network_address, ""]);
4e54e3c6
AM
375 }
376
377 # IPsec networks.
378 } elsif ($key ~~ ["ipsec_net_src", "ipsec_net_tgt", "IpSec Network"]) {
379 my $network_address = &get_ipsec_net_ip($value, 11);
380 if ($network_address) {
48f07c19 381 push(@ret, [$network_address, ""]);
4e54e3c6
AM
382 }
383
384 # The firewall's own IP addresses.
385 } elsif ($key ~~ ["ipfire", "ipfire_src"]) {
386 # ALL
387 if ($value eq "ALL") {
48f07c19 388 push(@ret, ["0/0", ""]);
4e54e3c6
AM
389
390 # GREEN
391 } elsif ($value eq "GREEN") {
48f07c19 392 push(@ret, [$netsettings{"GREEN_ADDRESS"}, ""]);
4e54e3c6
AM
393
394 # BLUE
395 } elsif ($value eq "BLUE") {
48f07c19 396 push(@ret, [$netsettings{"BLUE_ADDRESS"}, ""]);
4e54e3c6
AM
397
398 # ORANGE
399 } elsif ($value eq "ORANGE") {
48f07c19 400 push(@ret, [$netsettings{"ORANGE_ADDRESS"}, ""]);
4e54e3c6
AM
401
402 # RED
403 } elsif ($value ~~ ["RED", "RED1"]) {
404 my $address = &get_external_address();
405 if ($address) {
48f07c19 406 push(@ret, [$address, ""]);
4e54e3c6
AM
407 }
408
409 # Aliases
410 } else {
085a20ec
MT
411 my $alias = &get_alias($value);
412 if ($alias) {
48f07c19 413 push(@ret, [$alias, ""]);
4e54e3c6
AM
414 }
415 }
416
417 # If nothing was selected, we assume "any".
418 } else {
48f07c19 419 push(@ret, ["0/0", ""]);
4e54e3c6
AM
420 }
421
422 return @ret;
423}
fd169d0a
AM
424sub get_external_interface()
425{
4e54e3c6
AM
426 open(IFACE, "/var/ipfire/red/iface") or return "";
427 my $iface = <IFACE>;
428 close(IFACE);
429
430 return $iface;
431}
fd169d0a
AM
432sub get_external_address()
433{
4e54e3c6
AM
434 open(ADDR, "/var/ipfire/red/local-ipaddress") or return "";
435 my $address = <ADDR>;
436 close(ADDR);
437
438 return $address;
439}
fd169d0a
AM
440sub get_alias
441{
4e54e3c6
AM
442 my $id = shift;
443
444 foreach my $alias (sort keys %aliases) {
445 if ($id eq $alias) {
085a20ec 446 return $aliases{$alias}{"IPT"};
4e54e3c6
AM
447 }
448 }
449}
085a20ec
MT
450
451sub get_nat_address {
4e54e3c6
AM
452 my $zone = shift;
453 my $source = shift;
454
455 # Any static address of any zone.
456 if ($zone eq "AUTO") {
fd169d0a 457 if ($source && ($source !~ m/mac/i )) {
4e54e3c6
AM
458 my $firewall_ip = &get_internal_firewall_ip_address($source, 1);
459 if ($firewall_ip) {
460 return $firewall_ip;
461 }
462
463 $firewall_ip = &get_matching_firewall_address($source, 1);
464 if ($firewall_ip) {
465 return $firewall_ip;
466 }
467 }
468
469 return &get_external_address();
470
471 } elsif ($zone eq "RED" || $zone eq "GREEN" || $zone eq "ORANGE" || $zone eq "BLUE") {
c71499d8 472 return $netsettings{$zone . "_ADDRESS"};
4e54e3c6 473
085a20ec 474 } elsif ($zone ~~ ["Default IP", "ALL"]) {
4e54e3c6
AM
475 return &get_external_address();
476
477 } else {
085a20ec
MT
478 my $alias = &get_alias($zone);
479 unless ($alias) {
480 $alias = &get_external_address();
481 }
482 return $alias;
4e54e3c6
AM
483 }
484
485 print_error("Could not find NAT address");
486}
085a20ec 487
fd169d0a
AM
488sub get_internal_firewall_ip_addresses
489{
4e54e3c6
AM
490 my $use_orange = shift;
491
492 my @zones = ("GREEN", "BLUE");
493 if ($use_orange) {
494 push(@zones, "ORANGE");
495 }
496
497 my @addresses = ();
498 for my $zone (@zones) {
c71499d8 499 next unless (exists $netsettings{$zone . "_ADDRESS"});
4e54e3c6 500
c71499d8 501 my $zone_address = $netsettings{$zone . "_ADDRESS"};
4e54e3c6
AM
502 push(@addresses, $zone_address);
503 }
504
505 return @addresses;
506}
fd169d0a
AM
507sub get_matching_firewall_address
508{
4e54e3c6
AM
509 my $addr = shift;
510 my $use_orange = shift;
511
512 my ($address, $netmask) = split("/", $addr);
513
514 my @zones = ("GREEN", "BLUE");
515 if ($use_orange) {
516 push(@zones, "ORANGE");
517 }
518
519 foreach my $zone (@zones) {
c71499d8 520 next unless (exists $netsettings{$zone . "_ADDRESS"});
4e54e3c6 521
c71499d8
AM
522 my $zone_subnet = $netsettings{$zone . "_NETADDRESS"};
523 my $zone_mask = $netsettings{$zone . "_NETMASK"};
4e54e3c6
AM
524
525 if (&General::IpInSubnet($address, $zone_subnet, $zone_mask)) {
c71499d8 526 return $netsettings{$zone . "_ADDRESS"};
4e54e3c6
AM
527 }
528 }
529
530 return 0;
531}
fd169d0a
AM
532sub get_internal_firewall_ip_address
533{
4e54e3c6
AM
534 my $subnet = shift;
535 my $use_orange = shift;
536
537 my ($net_address, $net_mask) = split("/", $subnet);
538 if ((!$net_mask) || ($net_mask ~~ ["32", "255.255.255.255"])) {
539 return 0;
540 }
541
aa5f4b65
MT
542 # Convert net mask into correct format for &General::IpInSubnet().
543 $net_mask = &General::iporsubtodec($net_mask);
544
4e54e3c6
AM
545 my @addresses = &get_internal_firewall_ip_addresses($use_orange);
546 foreach my $zone_address (@addresses) {
547 if (&General::IpInSubnet($zone_address, $net_address, $net_mask)) {
548 return $zone_address;
549 }
550 }
551
552 return 0;
553}
554
2a81ab0d 555return 1;