More IPv6 Changes

git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@8939 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb
This commit is contained in:
teastep 2008-12-07 20:54:15 +00:00
parent cfa3212b30
commit 692e83c1c8
5 changed files with 269 additions and 49 deletions

View File

@ -70,6 +70,9 @@ our %EXPORT_TAGS = (
OUTPUT_RESTRICT
POSTROUTE_RESTRICT
ALL_RESTRICT
use_ipv4_chains
use_ipv6_chains
add_command
add_commands
@ -261,13 +264,13 @@ use constant { NULL_MODE => 0 , # Generating neither shell commands nor iptabl
our $mode;
sub use_ipv4() {
sub use_ipv4_chains() {
$nat_table = $chain_table{nat};
$mangle_table = $chain_table{mangle};
$filter_table = $chain_table{filter};
}
sub use_ipv6() {
sub use_ipv6_chains() {
$nat_table = undef;
$mangle_table = $chain_table{mangle6};
$filter_table = $chain_table{filter6};
@ -294,11 +297,11 @@ sub initialize() {
$chain_table{mangle}{__NAME__} = 'mangle';
$chain_table{nat}{__NAME__} = 'nat';
$chain_table{filter}{__NAME__} = 'filter';
$chain_table{raw6}{__NAME__} = 'raw';
$chain_table{mangle6}{__NAME__} = 'mangle';
$chain_table{filter6}{__NAME__} = 'filter';
$chain_table{raw6}{__NAME__} = 'raw6';
$chain_table{mangle6}{__NAME__} = 'mangle6';
$chain_table{filter6}{__NAME__} = 'filter6';
use_ipv4;
use_ipv4_chains;
#
# These get set to 1 as sections are encountered.
#

View File

@ -26,17 +26,25 @@
#
package Shorewall::IPAddrs;
require Exporter;
use Socket6;
use Shorewall::Config qw( :DEFAULT split_list require_capability in_hex8);
use strict;
our @ISA = qw(Exporter);
our @EXPORT = qw( ALLIPv4
ALLIPv6
ALLIP
ALL
TCP
UDP
ICMP
IPv6_ICMP
SCTP
F_INET
F_INET6
validate_address
validate_net
decompose_net
@ -45,33 +53,82 @@ our @EXPORT = qw( ALLIPv4
ip_range_explicit
expand_port_range
allipv4
allipv6
allip
rfc1918_networks
resolve_proto
proto_name
use_ipv4_addrs
use_ipv6_addrs
using_ipv4_addrs
using_ipv6_addrs
validate_port
validate_portpair
validate_port_list
validate_icmp
);
our @EXPORT_OK = qw( );
our $VERSION = 4.1.5;
our $VERSION = 4.3.0;
#
# Some IPv4 useful stuff
# Some IPv4/6 useful stuff
#
our @allipv4 = ( '0.0.0.0/0' );
our @allipv6 = ( '::/0' );
our $family;
use constant { ALLIPv4 => '0.0.0.0/0' , ICMP => 1, TCP => 6, UDP => 17 , SCTP => 132 };
use constant { ALLIPv4 => '0.0.0.0/0' ,
ALLIPv6 => '::/0' ,
F_INET => 1,
F_INET6 => 2,
ICMP => 1,
TCP => 6,
UDP => 17,
ICMPv6_ICMP => 58,
SCTP => 132 };
our @rfc1918_networks = ( "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16" );
sub use_ipv4() {
$family = F_INET;
}
sub using_ipv4() {
$family == F_INET;
}
sub use_ipv6() {
$family = F_INET6;
}
sub using_ipv6() {
$family == F_INET6;
}
#
# Initialize globals -- we take this novel approach to globals initialization to allow
# the compiler to run multiple times in the same process. The
# initialize() function does globals initialization for this
# module and is called from an INIT block below. The function is
# also called by Shorewall::Compiler::compiler at the beginning of
# the second and subsequent calls to that function.
#
sub initialize() {
use_ipv4;
}
INIT {
initialize;
}
sub vlsm_to_mask( $ ) {
my $vlsm = $_[0];
in_hex8 ( ( 0xFFFFFFFF << ( 32 - $vlsm ) ) && 0xFFFFFFFF );
}
sub valid_address( $ ) {
sub valid_4address( $ ) {
my $address = $_[0];
my @address = split /\./, $address;
@ -83,20 +140,19 @@ sub valid_address( $ ) {
1;
}
sub validate_address( $$ ) {
sub validate_4address( $$ ) {
my ( $addr, $allow_name ) = @_;
my @addrs = ( $addr );
unless ( valid_address $addr ) {
unless ( valid_4address $addr ) {
fatal_error "Invalid IP Address ($addr)" unless $allow_name;
fatal_error "Unknown Host ($addr)" unless (@addrs = gethostbyname $addr);
if ( defined wantarray ) {
shift @addrs for (1..4);
for ( @addrs ) {
my (@a) = unpack('C4',$_);
$_ = join('.', @a );
$_ = inet_htoa $_;
}
}
}
@ -130,7 +186,7 @@ sub encodeaddr( $ ) {
$result;
}
sub validate_net( $$ ) {
sub validate_4net( $$ ) {
my ($net, $vlsm, $rest) = split( '/', $_[0], 3 );
my $allow_name = $_[1];
@ -142,10 +198,10 @@ sub validate_net( $$ ) {
if ( defined $vlsm ) {
fatal_error "Invalid VLSM ($vlsm)" unless $vlsm =~ /^\d+$/ && $vlsm <= 32;
fatal_error "Invalid Network address ($_[0])" if defined $rest;
fatal_error "Invalid IP address ($net)" unless valid_address $net;
fatal_error "Invalid IP address ($net)" unless valid_4address $net;
} else {
fatal_error "Invalid Network address ($_[0])" if $_[0] =~ '/' || ! defined $net;
validate_address $net, $_[1];
validate_4address $net, $_[1];
$vlsm = 32;
}
@ -159,11 +215,11 @@ sub validate_net( $$ ) {
}
}
sub validate_range( $$ ) {
sub validate_4range( $$ ) {
my ( $low, $high ) = @_;
validate_address $low, 0;
validate_address $high, 0;
validate_4address $low, 0;
validate_4address $high, 0;
my $first = decodeaddr $low;
my $last = decodeaddr $high;
@ -171,6 +227,16 @@ sub validate_range( $$ ) {
fatal_error "Invalid IP Range ($low-$high)" unless $first <= $last;
}
sub validate_4host( $$ ) {
my ( $host, $allow_name ) = $_[0];
if ( $host =~ /^(\d+\.\d+\.\d+\.\d+)-(\d+\.\d+\.\d+\.\d+)$/ ) {
validate_4ange $1, $2;
} else {
validate_4net( $host, $allow_name );
}
}
sub ip_range_explicit( $ ) {
my $range = $_[0];
my @result;
@ -182,7 +248,7 @@ sub ip_range_explicit( $ ) {
push @result, $low;
if ( defined $high ) {
validate_address $high, 0;
validate_faddress $high, 0;
my $first = decodeaddr $low;
my $last = decodeaddr $high;
@ -209,20 +275,14 @@ sub decompose_net( $ ) {
}
sub validate_host( $$ ) {
my ( $host, $allow_name ) = $_[0];
if ( $host =~ /^(\d+\.\d+\.\d+\.\d+)-(\d+\.\d+\.\d+\.\d+)$/ ) {
validate_range $1, $2;
} else {
validate_net( $host, $allow_name );
}
}
sub allipv4() {
@allipv4;
}
sub allipv6() {
@allipv6;
}
sub rfc1918_networks() {
@rfc1918_networks
}
@ -231,7 +291,7 @@ sub rfc1918_networks() {
# Protocol/port validation
#
our %nametoproto = ( all => 0, ALL => 0, icmp => 1, ICMP => 1, tcp => 6, TCP => 6, udp => 17, UDP => 17 );
our %nametoproto = ( all => 0, ALL => 0, icmp => 1, ICMP => 1, tcp => 6, TCP => 6, udp => 17, UDP => 17 );
our @prototoname = ( 'all', 'icmp', '', '', '', '', 'tcp', '', '', '', '', '', '', '', '', '', '', 'udp' );
#
@ -345,6 +405,8 @@ my %icmp_types = ( any => 'any',
'address-mask-reply' => 18 );
sub validate_icmp( $ ) {
fatal_error "IPv4 ICMP not allowed in an IPv6 Rule" unless $family == F_INET;
my $type = $_[0];
my $value = $icmp_types{$type};
@ -419,4 +481,159 @@ sub expand_port_range( $$ ) {
}
}
sub valid_6address( $ ) {
my $address = $_[0];
my @address = split /:/, $address;
return 0 if @address > 8;
return 0 if @address < 8 && ! $address =~ /::/;
return 0 if $address =~ /:::/ || $address =~ /::.*::/;
if ( $address =~ /^:/ ) {
unless ( $address eq '::' ) {
return 0 if $address =~ /:$/ || $address =~ /^:.*::/;
}
} elsif ( $address =~ /:$/ ) {
return 0 if $address =~ /::.*:$/;
}
for my $a ( @address ) {
return 0 unless $a eq '' || ( $a =~ /^[a-fA-f\d]+$/ && oct "0x$a" < 65536 );
}
1;
}
sub validate_6address( $$ ) {
my ( $addr, $allow_name ) = @_;
my @addrs = ( $addr );
unless ( valid_6address $addr ) {
fatal_error "Invalid IPv6 Address ($addr)" unless $allow_name;
fatal_error "Unknown Host ($addr)" unless (@addrs = gethostbyname2 $addr, AF_INET6);
if ( defined wantarray ) {
shift @addrs for (1..4);
for ( @addrs ) {
$_ = inet_ntop AF_INET6, $_;
}
}
}
defined wantarray ? wantarray ? @addrs : $addrs[0] : undef;
}
sub validate_6net( $$ ) {
my ($net, $vlsm, $rest) = split( '/', $_[0], 3 );
my $allow_name = $_[1];
fatal_error "An ipset name ($net) is not allowed in this context" if substr( $net, 0, 1 ) eq '+';
if ( defined $vlsm ) {
fatal_error "Invalid VLSM ($vlsm)" unless $vlsm =~ /^\d+$/ && $vlsm <= 64;
fatal_error "Invalid Network address ($_[0])" if defined $rest;
fatal_error "Invalid IPv6 address ($net)" unless valid_6address $net;
} else {
fatal_error "Invalid Network address ($_[0])" if $_[0] =~ '/' || ! defined $net;
validate_6address $net, $allow_name;
}
}
sub validate_6range( $$ ) {
my ( $low, $high ) = @_;
validate_6address $low, 0;
validate_6address $high, 0;
my @low = split ":", $low;
my @high = split ":", $high;
if ( @low == @high ) {
my ( $l, $h) = ( pop @low, pop @high );
return 1 if hex "0x$l" <= hex "0x$h" && join( ":", @low ) eq join( ":", @high );
}
fatal_error "Invalid IPv6 Range ($low-$high)";
}
sub validate_6host( $$ ) {
my ( $host, $allow_name ) = $_[0];
if ( $host =~ /^(.*:.*)-(.*:.*)$/ ) {
validate_6range $1, $2;
} else {
validate_6net( $host, $allow_name );
}
}
my %ipv6_icmp_types = ( any => 'any',
'destination-unreachable' => 1,
'no-route' => '1/0',
'communication-prohibited' => '1/1',
'address-unreachable' => '1/2',
'port-unreachable' => '1/3',
'packet-too-big' => 2,
'time-exceeded' => 3,
'ttl-exceeded' => 3,
'ttl-zero-during-transit' => '3/0',
'ttl-zero-during-reassembly' => '3/1',
'parameter-problem' => 4,
'bad-header' => '4/0',
'unknown-header-type' => '4/1',
'unknown-option' => '4/2',
'echo-request' => 128,
'echo-reply' => 129,
'router-solicitation' => 133,
'router-advertisement' => 134,
'neighbour-solicitation' => 135,
'neighbour-advertisement' => 136,
redirect => 137 );
sub validate_icmp6( $ ) {
fatal_error "IPv6 ICMP not allowed in an IPv4 Rule" unless $family == F_INET6;
my $type = $_[0];
my $value = $ipv6_icmp_types{$type};
return $value if defined $value;
if ( $type =~ /^(\d+)(\/(\d+))?$/ ) {
return $type if $1 < 256 && ( ! $2 || $3 < 256 );
}
fatal_error "Invalid IPv6 ICMP Type ($type)"
}
sub ALLIP() {
$family == F_INET ? ALLIPv4 : ALLIPv6;
}
sub allip() {
$family == F_INET ? ALLIPv4 : ALLIPv6;
}
sub valid_address ( $ ) {
$family == F_INET ? valid_4address( $_[0] ) : valid_6address( $_[0] );
}
sub validate_address ( $$ ) {
$family == F_INET ? validate_4address( $_[0], $_[1] ) : validate_6address( $_[0], $_[1] );
}
sub validate_net ( $$ ) {
$family == F_INET ? validate_4net( $_[0], $_[1] ) : validate_6net( $_[0], $_[1] );
}
sub validate_range ($$ ) {
$family == F_INET ? validate_4range( $_[0], $_[1] ) : validate_6range( $_[0], $_[1] );
}
sub validate_host ($$ ) {
$family == F_INET ? validate_4host( $_[0], $_[1] ) : validate_6host( $_[0], $_[1] );
}
1;

View File

@ -419,14 +419,14 @@ sub add_an_rtrule( $$$$ ) {
fatal_error "You must specify either the source or destination in a route_rules entry" if $source eq '-' && $dest eq '-';
if ( $dest eq '-' ) {
$dest = 'to ' . ALLIPv4;
$dest = 'to ' . ALLIP;
} else {
validate_net( $dest, 0 );
$dest = "to $dest";
}
if ( $source eq '-' ) {
$source = 'from ' . ALLIPv4;
$source = 'from ' . ALLIP;
} elsif ( $source =~ /:/ ) {
( my $interface, $source , my $remainder ) = split( /:/, $source, 3 );
fatal_error "Invalid SOURCE" if defined $remainder;

View File

@ -177,7 +177,7 @@ sub setup_ecn()
$interfaces{$interface} = 1;
$hosts = ALLIPv4 if $hosts eq '-';
$hosts = ALLIP if $hosts eq '-';
for my $host( split_list $hosts, 'address' ) {
validate_host( $host , 1 );
@ -361,7 +361,7 @@ sub process_criticalhosts() {
fatal_error "Unknown interface ($interface)" unless known_interface $interface;
$hosts = ALLIPv4 unless $hosts ne '-';
$hosts = ALLIP unless $hosts ne '-';
my @hosts;
@ -402,7 +402,7 @@ sub process_routestopped() {
fatal_error "Unknown interface ($interface)" unless known_interface $interface;
$hosts = ALLIPv4 unless $hosts && $hosts ne '-';
$hosts = ALLIP unless $hosts && $hosts ne '-';
my @hosts;
@ -1034,7 +1034,7 @@ sub process_rule1 ( $$$$$$$$$$$$$ ) {
$source = $2;
} else {
$sourcezone = $source;
$source = ALLIPv4;
$source = ALLIP;
}
if ( $dest =~ /^(.*?):(.*)/ ) {
@ -1048,7 +1048,7 @@ sub process_rule1 ( $$$$$$$$$$$$$ ) {
$destzone = '-';
} else {
$destzone = $dest;
$dest = ALLIPv4;
$dest = ALLIP;
}
fatal_error "Missing source zone" if $sourcezone eq '-' || $sourcezone =~ /^:/;
@ -1073,7 +1073,7 @@ sub process_rule1 ( $$$$$$$$$$$$$ ) {
#
# For compatibility with older Shorewall versions
#
$origdest = ALLIPv4 if $origdest eq 'all';
$origdest = ALLIP if $origdest eq 'all';
#
# Take care of chain
@ -1178,14 +1178,14 @@ sub process_rule1 ( $$$$$$$$$$$$$ ) {
$target = '-j REDIRECT ';
$target .= "--to-port $serverport " if $serverport;
if ( $origdest eq '' || $origdest eq '-' ) {
$origdest = ALLIPv4;
$origdest = ALLIP;
} elsif ( $origdest eq 'detect' ) {
if ( $config{DETECT_DNAT_IPADDRS} && $sourcezone ne firewall_zone ) {
my $interfacesref = $sourceref->{interfaces};
my @interfaces = keys %$interfacesref;
$origdest = @interfaces ? "detect:@interfaces" : ALLIPv4;
} else {
$origdest = ALLIPv4;
$origdest = ALLIP;
}
}
} else {
@ -1218,9 +1218,9 @@ sub process_rule1 ( $$$$$$$$$$$$$ ) {
if ( $config{DETECT_DNAT_IPADDRS} && $sourcezone ne firewall_zone ) {
my $interfacesref = $sourceref->{interfaces};
my @interfaces = keys %$interfacesref;
$origdest = @interfaces ? "detect:@interfaces" : ALLIPv4;
$origdest = @interfaces ? "detect:@interfaces" : ALLIP;
} else {
$origdest = ALLIPv4;
$origdest = ALLIP;
}
}
}
@ -1265,7 +1265,7 @@ sub process_rule1 ( $$$$$$$$$$$$$ ) {
if ( $origdest eq 'detect' ) {
my $interfacesref = $sourceref->{interfaces};
my $interfaces = "@$interfacesref";
$origdest = $interfaces ? "detect:$interfaces" : ALLIPv4;
$origdest = $interfaces ? "detect:$interfaces" : ALLIP;
}
expand_rule( ensure_chain ('nat' , $sourceref->{type} eq 'firewall' ? 'OUTPUT' : dnat_chain $sourcezone) ,

View File

@ -481,7 +481,7 @@ sub add_group_to_zone($$$$$)
unless ( $switched ) {
if ( $type eq $zonetype ) {
fatal_error "Duplicate Host Group ($interface:$host) in zone $zone" if $ifacezone eq $zone;
$ifacezone = $zone if $host eq ALLIPv4;
$ifacezone = $zone if $host eq ALLIP;
}
}
@ -746,7 +746,7 @@ sub validate_interfaces_file( $ )
push @ifaces, $interface;
my @networks = allipv4;
my @networks = allip;
add_group_to_zone( $zone, $zoneref->{type}, $interface, \@networks, $optionsref ) if $zone;
@ -993,7 +993,7 @@ sub validate_hosts_file()
#
# Take care of case where the hosts list begins with '!'
#
$hosts = join( '', ALLIPv4 , $hosts ) if substr($hosts, 0, 2 ) eq ',!';
$hosts = join( '', ALLIP , $hosts ) if substr($hosts, 0, 2 ) eq ',!';
add_group_to_zone( $zone, $type , $interface, [ split_list( $hosts, 'host' ) ] , $optionsref);
@ -1027,7 +1027,7 @@ sub find_hosts_by_option( $ ) {
for my $interface ( @interfaces ) {
if ( ! $interfaces{$interface}{zone4} && $interfaces{$interface}{options}{$option} ) {
push @hosts, [ $interface, 'none', ALLIPv4 ];
push @hosts, [ $interface, 'none', ALLIP ];
}
}