###############################################################################
# #
# IPFire.org - A linux based firewall #
-# Copyright (C) 2013 Alexander Marx <amarx@ipfire.org> #
+# Copyright (C) 2021 Alexander Marx <amarx@ipfire.org> #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
###############################################################################
use strict;
+use experimental 'smartmatch';
+
no warnings 'uninitialized';
package fwlib;
my %customnetwork=();
my %customhost=();
my %customgrp=();
+my %customlocationgrp=();
my %customservice=();
my %customservicegrp=();
my %ccdnet=();
my %aliases=();
require '/var/ipfire/general-functions.pl';
+require '/var/ipfire/location-functions.pl';
my $confignet = "${General::swroot}/fwhosts/customnetworks";
my $confighost = "${General::swroot}/fwhosts/customhosts";
my $configgrp = "${General::swroot}/fwhosts/customgroups";
+my $configlocationgrp = "${General::swroot}/fwhosts/customlocationgrp";
my $configsrv = "${General::swroot}/fwhosts/customservices";
my $configsrvgrp = "${General::swroot}/fwhosts/customservicegrp";
my $configccdnet = "${General::swroot}/ovpn/ccd.conf";
&General::readhasharray("$confignet", \%customnetwork);
&General::readhasharray("$confighost", \%customhost);
&General::readhasharray("$configgrp", \%customgrp);
+&General::readhasharray("$configlocationgrp", \%customlocationgrp);
&General::readhasharray("$configccdnet", \%ccdnet);
&General::readhasharray("$configccdhost", \%ccdhost);
&General::readhasharray("$configipsec", \%ipsecconf);
&General::readhasharray("$configsrvgrp", \%customservicegrp);
&General::get_aliases(\%aliases);
+# Get all available locations.
+my @available_locations = &get_locations();
+
sub get_srv_prot
{
my $val=shift;
my $val=shift;
my $field=shift;
foreach my $key (sort {$a <=> $b} keys %ipsecconf){
+ #adapt $val to reflect real name without subnet (if rule with only one ipsec subnet is created)
+ my @tmpval = split (/\|/, $val);
+ $val = $tmpval[0];
if($ipsecconf{$key}[1] eq $val){
return $ipsecconf{$key}[$field];
}
}
}
}
+sub get_ipsec_id {
+ my $val = shift;
+
+ foreach my $key (keys %ipsecconf) {
+ if ($ipsecconf{$key}[1] eq $val) {
+ return $key;
+ }
+ }
+}
sub get_ovpn_n2n_ip
{
my $val=shift;
}elsif($val eq 'BLUE'){
return "$netsettings{'BLUE_NETADDRESS'}/$netsettings{'BLUE_NETMASK'}";
}elsif($val eq 'RED'){
- return "0.0.0.0/0 -o $con";
+ return "0.0.0.0/0";
}elsif($val =~ /OpenVPN/i){
return "$ovpnsettings{'DOVPN_SUBNET'}";
}elsif($val =~ /IPsec/i){
return ;
}
}
+sub get_interface
+{
+ my $net=shift;
+ if($net eq "$netsettings{'GREEN_NETADDRESS'}/$netsettings{'GREEN_NETMASK'}"){
+ return "$netsettings{'GREEN_DEV'}";
+ }
+ if($net eq "$netsettings{'ORANGE_NETADDRESS'}/$netsettings{'ORANGE_NETMASK'}"){
+ return "$netsettings{'ORANGE_DEV'}";
+ }
+ if($net eq "$netsettings{'BLUE_NETADDRESS'}/$netsettings{'BLUE_NETMASK'}"){
+ return "$netsettings{'BLUE_DEV'}";
+ }
+ if($net eq "0.0.0.0/0") {
+ return &get_external_interface();
+ }
+ return "";
+}
sub get_net_ip
{
my $val=shift;
foreach my $grp (sort {$a <=> $b} keys %customgrp) {
if ($customgrp{$grp}[0] eq $value) {
my @address = &get_address($customgrp{$grp}[3], $customgrp{$grp}[2], $type);
+ next if ($address[0][0] eq 'none');
+ if (@address) {
+ push(@addresses, @address);
+ }
+ }
+ }
+ }elsif ($addr_type ~~ ["cust_location_src", "cust_location_tgt"] && $value =~ "group:") {
+ $value=substr($value,6);
+ foreach my $grp (sort {$a <=> $b} keys %customlocationgrp) {
+ if ($customlocationgrp{$grp}[0] eq $value) {
+ my @address = &get_address($addr_type, $customlocationgrp{$grp}[2], $type);
if (@address) {
push(@addresses, @address);
# address. Otherwise, we assume that it is an IP address.
if ($key ~~ ["src_addr", "tgt_addr"]) {
if (&General::validmac($value)) {
- push(@ret, "-m mac --mac-source $value");
+ push(@ret, ["-m mac --mac-source $value", ""]);
} else {
- push(@ret, $value);
+ push(@ret, [$value, ""]);
}
# If a default network interface (GREEN, BLUE, etc.) is selected, we
my $external_interface = &get_external_interface();
my $network_address = &get_std_net_ip($value, $external_interface);
+
if ($network_address) {
- push(@ret, $network_address);
+ my $interface = &get_interface($network_address);
+ push(@ret, [$network_address, $interface]);
}
# Custom networks.
} elsif ($key ~~ ["cust_net_src", "cust_net_tgt", "Custom Network"]) {
my $network_address = &get_net_ip($value);
if ($network_address) {
- push(@ret, $network_address);
+ push(@ret, [$network_address, ""]);
}
# Custom hosts.
} elsif ($key ~~ ["cust_host_src", "cust_host_tgt", "Custom Host"]) {
my $host_address = &get_host_ip($value, $type);
if ($host_address) {
- push(@ret, $host_address);
+ push(@ret, [$host_address, ""]);
}
# OpenVPN networks.
} elsif ($key ~~ ["ovpn_net_src", "ovpn_net_tgt", "OpenVPN static network"]) {
my $network_address = &get_ovpn_net_ip($value, 1);
if ($network_address) {
- push(@ret, $network_address);
+ push(@ret, [$network_address, ""]);
}
# OpenVPN hosts.
} elsif ($key ~~ ["ovpn_host_src", "ovpn_host_tgt", "OpenVPN static host"]) {
my $host_address = &get_ovpn_host_ip($value, 33);
if ($host_address) {
- push(@ret, $host_address);
+ push(@ret, [$host_address, ""]);
}
# OpenVPN N2N.
} elsif ($key ~~ ["ovpn_n2n_src", "ovpn_n2n_tgt", "OpenVPN N-2-N"]) {
my $network_address = &get_ovpn_n2n_ip($value, 11);
if ($network_address) {
- push(@ret, $network_address);
+ push(@ret, [$network_address, ""]);
}
# IPsec networks.
} elsif ($key ~~ ["ipsec_net_src", "ipsec_net_tgt", "IpSec Network"]) {
- my $network_address = &get_ipsec_net_ip($value, 11);
- if ($network_address) {
- push(@ret, $network_address);
+ #Check if we have multiple subnets and only want one of them
+ if ( $value =~ /\|/ ){
+ my @parts = split(/\|/, $value);
+ push(@ret, [$parts[1], ""]);
+ }else{
+ my $interface_mode = &get_ipsec_net_ip($value, 36);
+ if ($interface_mode ~~ ["gre", "vti"]) {
+ my $id = &get_ipsec_id($value);
+ push(@ret, ["0.0.0.0/0", "${interface_mode}${id}"]);
+ } else {
+ my $network_address = &get_ipsec_net_ip($value, 11);
+ my @nets = split(/\|/, $network_address);
+ foreach my $net (@nets) {
+ push(@ret, [$net, ""]);
+ }
+ }
}
# The firewall's own IP addresses.
} elsif ($key ~~ ["ipfire", "ipfire_src"]) {
# ALL
if ($value eq "ALL") {
- push(@ret, "0/0");
+ push(@ret, ["0/0", ""]);
# GREEN
} elsif ($value eq "GREEN") {
- push(@ret, $netsettings{"GREEN_ADDRESS"});
+ push(@ret, [$netsettings{"GREEN_ADDRESS"}, ""]);
# BLUE
} elsif ($value eq "BLUE") {
- push(@ret, $netsettings{"BLUE_ADDRESS"});
+ push(@ret, [$netsettings{"BLUE_ADDRESS"}, ""]);
# ORANGE
} elsif ($value eq "ORANGE") {
- push(@ret, $netsettings{"ORANGE_ADDRESS"});
+ push(@ret, [$netsettings{"ORANGE_ADDRESS"}, ""]);
# RED
} elsif ($value ~~ ["RED", "RED1"]) {
my $address = &get_external_address();
if ($address) {
- push(@ret, $address);
+ push(@ret, [$address, ""]);
}
# Aliases
} else {
my $alias = &get_alias($value);
if ($alias) {
- push(@ret, $alias);
+ push(@ret, [$alias, ""]);
}
}
+ # Handle rule options with a location as source.
+ } elsif ($key eq "cust_location_src") {
+ # Check if the given location is available.
+ if(&location_is_available($value)) {
+ # Get external interface.
+ my $external_interface = &get_external_interface();
+
+ push(@ret, ["-m set --match-set CC_$value src", "$external_interface"]);
+ }
+
+ # Handle rule options with a location as target.
+ } elsif ($key eq "cust_location_tgt") {
+ # Check if the given location is available.
+ if(&location_is_available($value)) {
+ # Get external interface.
+ my $external_interface = &get_external_interface();
+
+ push(@ret, ["-m set --match-set CC_$value dst", "$external_interface"]);
+ }
+
# If nothing was selected, we assume "any".
} else {
- push(@ret, "0/0");
+ push(@ret, ["0/0", ""]);
}
return @ret;
return 0;
}
+ # Convert net mask into correct format for &General::IpInSubnet().
+ $net_mask = &General::iporsubtodec($net_mask);
+
my @addresses = &get_internal_firewall_ip_addresses($use_orange);
foreach my $zone_address (@addresses) {
if (&General::IpInSubnet($zone_address, $net_address, $net_mask)) {
return 0;
}
+sub get_locations() {
+ return &Location::Functions::get_locations();
+}
+
+# Function to check if a database of a given location is
+# available.
+sub location_is_available($) {
+ my ($requested_location) = @_;
+
+ # Loop through the global array of available locations.
+ foreach my $location (@available_locations) {
+ # Check if the current processed location is the searched one.
+ if($location eq $requested_location) {
+ # If it is part of the array, return "1" - True.
+ return 1;
+ }
+ }
+
+ # If we got here, the given location is not part of the array of available
+ # zones. Return nothing.
+ return;
+}
+
return 1;