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