From 7fe76f778ca9445828c0122ba4bd5e82c59e2c9f Mon Sep 17 00:00:00 2001 From: teastep Date: Tue, 24 Apr 2007 19:53:13 +0000 Subject: [PATCH] Fix MACLIST bug git-svn-id: https://shorewall.svn.sourceforge.net/svnroot/shorewall/trunk@6104 fbd18981-670d-0410-9b5c-8dc0c1a9a2bb --- Shorewall-perl/Shorewall/Chains.pm | 115 ++++++++++++++++++++++++++++- Shorewall-perl/Shorewall/Config.pm | 33 ++++++++- Shorewall-perl/Shorewall/Rules.pm | 2 +- 3 files changed, 145 insertions(+), 5 deletions(-) diff --git a/Shorewall-perl/Shorewall/Chains.pm b/Shorewall-perl/Shorewall/Chains.pm index 6205f7fca..79aea823c 100644 --- a/Shorewall-perl/Shorewall/Chains.pm +++ b/Shorewall-perl/Shorewall/Chains.pm @@ -630,6 +630,104 @@ sub clearrule() { $iprangematch = 0; } +sub validate_proto( $ ) { + my $proto = $_[0]; + my $value = $protocols{$proto}; + return $value if defined $value; + return $proto if $proto =~ /^(\d+)$/ && $proto <= 65535; + return $proto if $proto eq 'all'; + fatal_error "Invalid/Unknown protocol ($proto)"; +} + +sub validate_portpair( $ ) { + my $portpair = $_[0]; + + fatal_error "Invalid port range ($portpair)" if $portpair =~ tr/:/:/ > 1; + + $portpair = "0$portpair" if substr( $portpair, 0, 1 ) eq ':'; + $portpair = "${portpair}65535" if substr( $portpair, -1, 1 ) eq ':'; + + my @ports = split/:/, $portpair; + + for my $port ( @ports ) { + my $value = $services{$port}; + + unless ( defined $value ) { + $value = $port if $port =~ /^(\d+)$/ && $port <= 65535; + } + + fatal_error "Invalid/Unknown port/service ($port)" unless defined $value; + + $port = $value; + } + + if ( @ports == 2 ) { + fatal_error "Invalid port range ($portpair)" unless $ports[0] < $ports[1]; + } + + join ':', @ports; + +} + +sub validate_port_list( $ ) { + my $result = ''; + + for my $port ( split/,/, $_[0] ) { + my $value = validate_portpair( $port ); + $result = $result ? join ',', $result, $value : $value; + } + + $result; +} + +my %icmp_types = ( any => 'any', + 'echo-reply' => 0, + 'destination-unreachable' => 3, + 'network-unreachable' => '3/0', + 'host-unreachable' => '3/1', + 'protocol-unreachable' => '3/2', + 'port-unreachable' => '3/3', + 'fragmentation-needed' => '3/4', + 'source-route-failed' => '3/5', + 'network-unknown' => '3/6', + 'host-unknown' => '3/7', + 'network-prohibited' => '3/9', + 'host-prohibited' => '3/10', + 'TOS-network-unreachable' => '3/11', + 'TOS-host-unreachable' => '3/12', + 'communication-prohibited' => '3/13', + 'host-precedence-violation' => '3/14', + 'precedence-cutoff' => '3/15', + 'source-quench' => 4, + 'redirect' => 5, + 'network-redirect' => '5/0', + 'host-redirect' => '5/1', + 'TOS-network-redirect' => '5/2', + 'TOS-host-redirect' => '5/3', + 'echo-request' => '8', + 'router-advertisement' => 9, + 'router-solicitation' => 10, + 'time-exceeded' => 11, + 'ttl-zero-during-transit' => '11/0', + 'ttl-zero-during-reassembly' => '11/1', + 'parameter-problem' => 12, + 'ip-header-bad' => '12/0', + 'required-option-missing' => '12/1', + 'timestamp-request' => 13, + 'timestamp-reply' => 14, + 'address-mask-request' => 17, + 'address-mask-reply' => 18 ); + +sub validate_icmp( $ ) { + my $type = $_[0]; + + my $value = $icmp_types{$type}; + + return $value if defined $value; + return $type if $type =~ /^(\d+)(\/\d+)?$/; + fatal_error "Invalid ICMP Type ($type)" +} + # # Handle parsing of PROTO, DEST PORT(S) , SOURCE PORTS(S). Returns the appropriate match string. # @@ -653,8 +751,9 @@ sub do_proto( $$$ ) if ( $proto =~ /^((tcp|6)((:syn)?))|(udp|17)$/ ) { if ( $3 ) { - $output = '-p tcp --syn '; + $output = '-p 6 --syn '; } else { + $proto = $protocols{$proto} if defined $protocols{$proto}; $output = "-p $proto "; } @@ -662,8 +761,10 @@ sub do_proto( $$$ ) if ( $ports =~ tr/,/,/ > 0 ) { fatal_error "Port list requires Multiport support in your kernel/iptables: $ports" unless $capabilities{MULTIPORT}; fatal_error "Too many entries in port list: $ports" if port_count( $ports ) > 15; + $ports = validate_port_list $ports; $output .= "-m multiport --dports $ports "; } else { + $ports = validate_portpair $ports; $output .= "--dport $ports "; } } @@ -672,15 +773,22 @@ sub do_proto( $$$ ) if ( $sports =~ tr/,/,/ > 0 ) { fatal_error "Port list requires Multiport support in your kernel/iptables: $sports" unless $capabilities{MULTIPORT}; fatal_error "Too many entries in port list: $sports" if port_count( $sports ) > 15; + $sports = validate_port_list $sports; $output .= "-m multiport --sports $sports "; } else { + $sports = validate_portpair $sports; $output .= "--sport $sports "; } } } elsif ( $proto =~ /^(icmp|1)$/i ) { fatal_error 'Multiple ICMP types are not permitted' if $ports =~ /,/; $output .= "-p icmp "; - $output .= "--icmp-type $ports " if $ports; + + if ( $ports ne '' ) { + $ports = validate_icmp $ports; + $output .= "--icmp-type $ports "; + } + fatal_error 'SOURCE PORT(S) not permitted with ICMP' if $sports ne ''; } elsif ( $proto =~ /^(ipp2p(:(tcp|udp|all)))?$/i ) { require_capability( 'IPP2P' , 'PROTO = ipp2p' ); @@ -689,6 +797,7 @@ sub do_proto( $$$ ) $output .= "-p $proto -m ipp2p --$ports "; } else { fatal_error "SOURCE/DEST PORT(S) not allowed with PROTO $proto, rule \"$line\"" if $ports ne '' || $sports ne ''; + $proto = validate_proto $proto; $output .= "-p $proto "; } } elsif ( $ports ne '' || $sports ne '' ) { @@ -1013,7 +1122,7 @@ sub mysplit( $ ) { my $element = shift @input; if ( $element =~ /\[/ ) { - while ( ! ( $element =~ /\]/ ) ) { + while ( substr( $element, -1, 1 ) ne ']' ) { last unless @input; $element .= ( ',' . shift @input ); } diff --git a/Shorewall-perl/Shorewall/Config.pm b/Shorewall-perl/Shorewall/Config.pm index bb288cf80..3fd588dc0 100644 --- a/Shorewall-perl/Shorewall/Config.pm +++ b/Shorewall-perl/Shorewall/Config.pm @@ -54,7 +54,9 @@ our @EXPORT = qw( %config %globals - %capabilities ); + %capabilities + %protocols + %services ); our @EXPORT_OK = (); our @VERSION = 1.00; @@ -196,6 +198,11 @@ our %capabilities = COMMENTS => undef, ADDRTYPE => undef, ); +# +# /etc/protocols and /etc/services +# +our %protocols; +our %services; my %capdesc = ( NAT_ENABLED => 'NAT', MANGLE_ENABLED => 'Packet Mangling', @@ -1036,6 +1043,30 @@ sub get_configuration( $ ) { } else { $config{LOCKFILE} = ''; } + + open_file '/etc/protocols' or fatal_error "Cannot open /etc/protocols: $!"; + + while ( read_a_line ) { + my ( $proto1, $number, $proto2, $proto3 ) = split_line( 2, 4, '/etc/protocols entry'); + + $protocols{ $proto1 } = $number; + $protocols{ $proto2 } = $number unless $proto2 eq '-' || $proto3 ne '-'; + } + + + open_file '/etc/services' or fatal_error "Cannot open /etc/services: $!"; + + while ( read_a_line ) { + my ( $name1, $proto_number, @names ) = split_line( 2, 10, '/etc/services entry'); + + my ( $number, $proto ) = split '/', $proto_number; + + $services{ $name1 } = $number; + + while ( defined ( $name1 = shift @names ) && $name1 ne '-' ) { + $services{ $name1 } = $number; + } + } } # diff --git a/Shorewall-perl/Shorewall/Rules.pm b/Shorewall-perl/Shorewall/Rules.pm index 0ae97b9f9..e37ba8ade 100644 --- a/Shorewall-perl/Shorewall/Rules.pm +++ b/Shorewall-perl/Shorewall/Rules.pm @@ -746,7 +746,7 @@ sub setup_mac_lists( $ ) { my $chainref = $chain_table{$table}{( $config{MACLIST_TTL} ? macrecent_target $interface : mac_chain $interface )}; my $chain = $chainref->{name}; - if ( $config{MACLIST_LOG_LEVEL} || $config{MACLIST_DISPOSITION} != 'ACCEPT' ) { + if ( $config{MACLIST_LOG_LEVEL} || $config{MACLIST_DISPOSITION} ne 'ACCEPT' ) { my $variable = get_interface_addresses $interface; add_command $chainref, "for address in $variable; do"; add_command $chainref, " echo \"-A $chainref->{name} -s \$address -m addrtype --dst-type BROADCAST -j RETURN\" >&3";