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