mirror of
https://gitlab.com/shorewall/code.git
synced 2024-12-03 13:03:12 +01:00
2cd098ba31
Signed-off-by: Tom Eastep <teastep@shorewall.net>
321 lines
11 KiB
Perl
321 lines
11 KiB
Perl
#
|
|
# Shorewall 5.0 -- /usr/share/shorewall/Shorewall/Tunnels.pm
|
|
#
|
|
# This program is under GPL [http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt]
|
|
# (c) 2007-2016 - Tom Eastep (teastep@shorewall.net)
|
|
#
|
|
# Complete documentation is available at http://shorewall.net
|
|
#
|
|
# This program is part of Shorewall.
|
|
#
|
|
# 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 the
|
|
# Free Software Foundation, either version 2 of the license or, at your
|
|
# option, any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
# This module handles the /etc/shorewall/tunnels file.
|
|
#
|
|
package Shorewall::Tunnels;
|
|
require Exporter;
|
|
use Shorewall::Config qw(:DEFAULT :internal);
|
|
use Shorewall::Zones;
|
|
use Shorewall::IPAddrs;
|
|
use Shorewall::Chains qw(:DEFAULT :internal);
|
|
use Shorewall::Rules;
|
|
|
|
use strict;
|
|
|
|
our @ISA = qw(Exporter);
|
|
our @EXPORT = qw( setup_tunnels );
|
|
our @EXPORT_OK = ( );
|
|
our $VERSION = 'MODULEVERSION';
|
|
|
|
#
|
|
# Here starts the tunnel stuff -- we really should get rid of this crap...
|
|
#
|
|
sub setup_tunnels() {
|
|
|
|
our $fw = firewall_zone;
|
|
|
|
sub setup_one_ipsec {
|
|
my ($inchainref, $outchainref, $kind, $source, $dest, $gatewayzones) = @_;
|
|
|
|
( $kind, my ( $qualifier , $remainder ) ) = split( /:/, $kind, 3 );
|
|
|
|
my $noah = 1;
|
|
|
|
fatal_error "Invalid IPSEC modifier ($qualifier:$remainder)" if defined $remainder;
|
|
|
|
if ( defined $qualifier ) {
|
|
if ( $qualifier eq 'ah' ) {
|
|
fatal_error ":ah not allowed with ipsecnat tunnels" if $kind eq 'ipsecnat';
|
|
$noah = 0;
|
|
} else {
|
|
fatal_error "Invalid IPSEC modifier ($qualifier)" if $qualifier ne 'noah';
|
|
}
|
|
}
|
|
|
|
my @options = have_capability( 'RAW_TABLE' ) ? state_imatch 'NEW,UNTRACKED' : state_imatch 'NEW';
|
|
|
|
add_tunnel_rule $inchainref, p => 50, @$source;
|
|
add_tunnel_rule $outchainref, p => 50, @$dest;
|
|
|
|
unless ( $noah ) {
|
|
add_tunnel_rule $inchainref, p => 51, @$source;
|
|
add_tunnel_rule $outchainref, p => 51, @$dest;
|
|
}
|
|
|
|
if ( $kind eq 'ipsec' ) {
|
|
add_tunnel_rule $inchainref, p => 'udp --dport 500', @$source, @options;
|
|
add_tunnel_rule $outchainref, p => 'udp --dport 500', @$dest, @options;
|
|
} else {
|
|
add_tunnel_rule $inchainref, p => 'udp', @$source, multiport => '--dports 500,4500', @options;
|
|
add_tunnel_rule $outchainref, p => 'udp', @$dest, multiport => '--dports 500,4500', @options;
|
|
}
|
|
|
|
unless ( $gatewayzones eq '-' ) {
|
|
for my $zone ( split_list $gatewayzones, 'zone' ) {
|
|
my $type = zone_type( $zone );
|
|
fatal_error "Invalid zone ($zone) for GATEWAY ZONE" if $type == FIREWALL || $type == BPORT;
|
|
$inchainref = ensure_rules_chain( rules_chain( ${zone}, ${fw} ) );
|
|
$outchainref = ensure_rules_chain( rules_chain( ${fw}, ${zone} ) );
|
|
|
|
unless ( have_ipsec ) {
|
|
add_tunnel_rule $inchainref, p => 50, @$source;
|
|
add_tunnel_rule $outchainref, p => 50, @$dest;
|
|
|
|
unless ( $noah ) {
|
|
add_tunnel_rule $inchainref, p => 51, @$source;
|
|
add_tunnel_rule $outchainref, p => 51, @$dest;
|
|
}
|
|
}
|
|
|
|
if ( $kind eq 'ipsec' ) {
|
|
add_tunnel_rule $inchainref, p => 'udp --dport 500', @$source, @options;
|
|
add_tunnel_rule $outchainref, p => 'udp --dport 500', @$dest, @options;
|
|
} else {
|
|
add_tunnel_rule $inchainref, p => 'udp', @$source, multiport => '--dports 500,4500', @options;
|
|
add_tunnel_rule $outchainref, p => 'udp', @$dest, multiport => '--dports 500,4500', @options;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
sub setup_one_other {
|
|
my ($inchainref, $outchainref, $source, $dest , $protocol) = @_;
|
|
|
|
add_tunnel_rule $inchainref , p => $protocol, @$source;
|
|
add_tunnel_rule $outchainref , p => $protocol, @$dest;
|
|
}
|
|
|
|
sub setup_pptp_client {
|
|
my ($inchainref, $outchainref, $kind, $source, $dest ) = @_;
|
|
|
|
add_tunnel_rule $outchainref, p => 47, @$dest;
|
|
add_tunnel_rule $inchainref, p => 47, @$source;
|
|
add_tunnel_rule $outchainref, p => 'tcp --dport 1723', @$dest;
|
|
}
|
|
|
|
sub setup_pptp_server {
|
|
my ($inchainref, $outchainref, $kind, $source, $dest ) = @_;
|
|
|
|
add_tunnel_rule $inchainref, p => 47, @$source;
|
|
add_tunnel_rule $outchainref, p => 47, @$dest;
|
|
add_tunnel_rule $inchainref, p => 'tcp --dport 1723', @$source
|
|
}
|
|
|
|
sub setup_one_tinc {
|
|
my ( $inchainref, $outchainref, $kind, $source, $dest ) = @_;
|
|
|
|
add_tunnel_rule $inchainref, p => 'udp --dport 655', @$source;
|
|
add_tunnel_rule $outchainref, p => 'udp --dport 655', @$dest;
|
|
add_tunnel_rule $inchainref, p => 'tcp --dport 655', @$source;
|
|
add_tunnel_rule $outchainref, p => 'tcp --dport 655', @$dest;
|
|
}
|
|
|
|
sub setup_one_openvpn {
|
|
my ($inchainref, $outchainref, $kind, $source, $dest) = @_;
|
|
|
|
my $protocol = 'udp';
|
|
my $port = 1194;
|
|
|
|
( $kind, my ( $proto, $p, $remainder ) ) = split( /:/, $kind, 4 );
|
|
|
|
fatal_error "Invalid port ($p:$remainder)" if defined $remainder;
|
|
|
|
if ( supplied $p ) {
|
|
$port = $p;
|
|
$protocol = $proto;
|
|
} elsif ( supplied $proto ) {
|
|
if ( "\L$proto" =~ /udp|tcp/ ) {
|
|
$protocol = $proto;
|
|
} else {
|
|
$port = $proto;
|
|
}
|
|
}
|
|
|
|
add_tunnel_rule $inchainref, p => "$protocol --dport $port", @$source;
|
|
add_tunnel_rule $outchainref, p => "$protocol --dport $port", @$dest;
|
|
}
|
|
|
|
sub setup_one_openvpn_client {
|
|
my ($inchainref, $outchainref, $kind, $source, $dest) = @_;
|
|
|
|
my $protocol = 'udp';
|
|
my $port = 1194;
|
|
|
|
( $kind, my ( $proto, $p , $remainder ) ) = split( /:/, $kind, 4 );
|
|
|
|
fatal_error "Invalid port ($p:$remainder)" if defined $remainder;
|
|
|
|
if ( supplied $p ) {
|
|
$port = $p;
|
|
$protocol = $proto;
|
|
} elsif ( supplied $proto ) {
|
|
if ( "\L$proto" =~ /udp|tcp/ ) {
|
|
$protocol = $proto;
|
|
} else {
|
|
$port = $proto;
|
|
}
|
|
}
|
|
|
|
add_tunnel_rule $inchainref, p => "$protocol --sport $port", @$source;
|
|
add_tunnel_rule $outchainref, p => "$protocol --dport $port", @$dest;
|
|
}
|
|
|
|
sub setup_one_openvpn_server {
|
|
my ($inchainref, $outchainref, $kind, $source, $dest) = @_;
|
|
|
|
my $protocol = 'udp';
|
|
my $port = 1194;
|
|
|
|
( $kind, my ( $proto, $p , $remainder ) ) = split( /:/, $kind, 4 );
|
|
|
|
fatal_error "Invalid port ($p:$remainder)" if defined $remainder;
|
|
|
|
if ( supplied $p ) {
|
|
$port = $p;
|
|
$protocol = $proto;
|
|
} elsif ( supplied $proto ) {
|
|
if ( "\L$proto" =~ /udp|tcp/ ) {
|
|
$protocol = $proto;
|
|
} else {
|
|
$port = $proto;
|
|
}
|
|
}
|
|
|
|
add_tunnel_rule $inchainref, p => "$protocol --dport $port" , @$source;
|
|
add_tunnel_rule $outchainref, p => "$protocol --sport $port", @$dest;
|
|
}
|
|
|
|
sub setup_one_l2tp {
|
|
my ($inchainref, $outchainref, $kind, $source, $dest) = @_;
|
|
|
|
fatal_error "Unknown option ($1)" if $kind =~ /^.*?:(.*)$/;
|
|
|
|
add_tunnel_rule $inchainref, p => 'udp --sport 1701 --dport 1701', @$source;
|
|
add_tunnel_rule $outchainref, p => 'udp --sport 1701 --dport 1701', @$dest;
|
|
}
|
|
|
|
sub setup_one_generic {
|
|
my ($inchainref, $outchainref, $kind, $source, $dest) = @_;
|
|
|
|
my $protocol = 'udp';
|
|
my $port = '--dport 5000';
|
|
|
|
if ( $kind =~ /.*:.*:.*/ ) {
|
|
( $kind, $protocol, $port) = split /:/, $kind;
|
|
$port = "--dport $port";
|
|
} else {
|
|
$port = '';
|
|
( $kind, $protocol ) = split /:/ , $kind if $kind =~ /.*:.*/;
|
|
}
|
|
|
|
add_tunnel_rule $inchainref, p => "$protocol $port", @$source;
|
|
add_tunnel_rule $outchainref, p => "$protocol $port", @$dest;
|
|
}
|
|
|
|
sub setup_one_tunnel($$$$) {
|
|
my ( $kind , $zone, $gateways, $gatewayzones ) = @_;
|
|
|
|
my $zonetype = zone_type( $zone );
|
|
|
|
fatal_error "Invalid tunnel ZONE ($zone)" if $zonetype & ( FIREWALL | BPORT );
|
|
|
|
my $inchainref = ensure_rules_chain( rules_chain( ${zone}, ${fw} ) );
|
|
my $outchainref = ensure_rules_chain( rules_chain( ${fw}, ${zone} ) );
|
|
|
|
$gateways = ALLIP if $gateways eq '-';
|
|
|
|
my ( $net, $excl ) = handle_network_list( $gateways , 'src' );
|
|
( $net, $excl ) = handle_network_list( $gateways , 'dst' );
|
|
|
|
fatal_error "Exclusion is not allowed in the GATEWAYS column" if $excl;
|
|
|
|
for my $gateway ( split_list $gateways, 'GATEWAYS' ) {
|
|
my @source = imatch_source_net $gateway;
|
|
my @dest = imatch_dest_net $gateway;
|
|
|
|
my %tunneltypes = ( 'ipsec' => { function => \&setup_one_ipsec , params => [ $kind, \@source, \@dest , $gatewayzones ] } ,
|
|
'ipsecnat' => { function => \&setup_one_ipsec , params => [ $kind, \@source, \@dest , $gatewayzones ] } ,
|
|
'ipip' => { function => \&setup_one_other, params => [ \@source, \@dest , 4 ] } ,
|
|
'gre' => { function => \&setup_one_other, params => [ \@source, \@dest , 47 ] } ,
|
|
'6to4' => { function => \&setup_one_other, params => [ \@source, \@dest , 41 ] } ,
|
|
'6in4' => { function => \&setup_one_other, params => [ \@source, \@dest , 41 ] } ,
|
|
'pptpclient' => { function => \&setup_pptp_client, params => [ $kind, \@source, \@dest ] } ,
|
|
'pptpserver' => { function => \&setup_pptp_server, params => [ $kind, \@source, \@dest ] } ,
|
|
'tinc' => { function => \&setup_one_tinc, params => [ $kind, \@source, \@dest ] } ,
|
|
'openvpn' => { function => \&setup_one_openvpn, params => [ $kind, \@source, \@dest ] } ,
|
|
'openvpnclient' => { function => \&setup_one_openvpn_client, params => [ $kind, \@source, \@dest ] } ,
|
|
'openvpnserver' => { function => \&setup_one_openvpn_server, params => [ $kind, \@source, \@dest ] } ,
|
|
'l2tp' => { function => \&setup_one_l2tp , params => [ $kind, \@source, \@dest ] } ,
|
|
'generic' => { function => \&setup_one_generic , params => [ $kind, \@source, \@dest ] } ,
|
|
);
|
|
|
|
$kind = "\L$kind";
|
|
|
|
(my $type) = split /:/, $kind;
|
|
|
|
my $tunnelref = $tunneltypes{ $type };
|
|
|
|
fatal_error "Tunnels of type $type are not supported" unless $tunnelref;
|
|
|
|
$tunnelref->{function}->( $inchainref, $outchainref, @{$tunnelref->{params}} );
|
|
}
|
|
|
|
progress_message " Tunnel \"$currentline\" $done";
|
|
}
|
|
|
|
#
|
|
# Setup_Tunnels() Starts Here
|
|
#
|
|
if ( my $fn = open_file( 'tunnels', 1, 1 ) ) {
|
|
|
|
first_entry "$doing $fn...";
|
|
|
|
while ( read_a_line( NORMAL_READ ) ) {
|
|
|
|
my ( $kind, $zone, $gateway, $gatewayzones ) =
|
|
split_line1( 'tunnels file',
|
|
{ type => 0, zone => 1, gateway => 2, gateways => 2, gateway_zone => 3 , gateway_zones => 3 },
|
|
{},
|
|
4 );
|
|
|
|
fatal_error 'TYPE must be specified' if $kind eq '-';
|
|
|
|
fatal_error 'ZONE must be specified' if $zone eq '-';
|
|
setup_one_tunnel $kind, $zone, $gateway, $gatewayzones;
|
|
}
|
|
}
|
|
}
|
|
|
|
1;
|