From d997ef1653de6a90a64eed61e724ea4a271ba35a Mon Sep 17 00:00:00 2001 From: Tom Eastep Date: Thu, 19 Aug 2010 11:46:26 -0700 Subject: [PATCH] First cut at IPSEC support in the accounting file. Signed-off-by: Tom Eastep --- Shorewall/Perl/Shorewall/Accounting.pm | 4 +- Shorewall/Perl/Shorewall/Chains.pm | 88 ++++++++++++++++++++++++++ Shorewall/Perl/Shorewall/Nat.pm | 58 ++--------------- 3 files changed, 94 insertions(+), 56 deletions(-) diff --git a/Shorewall/Perl/Shorewall/Accounting.pm b/Shorewall/Perl/Shorewall/Accounting.pm index d2868e3ff..749d22e24 100644 --- a/Shorewall/Perl/Shorewall/Accounting.pm +++ b/Shorewall/Perl/Shorewall/Accounting.pm @@ -52,7 +52,7 @@ sub process_accounting_rule( ) { our $jumpchainref; - my ($action, $chain, $source, $dest, $proto, $ports, $sports, $user, $mark ) = split_line1 1, 9, 'Accounting File'; + my ($action, $chain, $source, $dest, $proto, $ports, $sports, $user, $mark, $ipsec ) = split_line1 1, 10, 'Accounting File'; if ( $action eq 'COMMENT' ) { process_comment; @@ -84,7 +84,7 @@ sub process_accounting_rule( ) { $ports = '' if $ports eq 'any' || $ports eq 'all'; $sports = '' if $sports eq 'any' || $sports eq 'all'; - my $rule = do_proto( $proto, $ports, $sports ) . do_user ( $user ) . do_test ( $mark, $globals{TC_MASK} ); + my $rule = do_proto( $proto, $ports, $sports ) . do_user ( $user ) . do_test ( $mark, $globals{TC_MASK} ) . do_ipsec( $ipsec ); my $rule2 = 0; unless ( $action eq 'COUNT' ) { diff --git a/Shorewall/Perl/Shorewall/Chains.pm b/Shorewall/Perl/Shorewall/Chains.pm index 319e24d06..d95397a6a 100644 --- a/Shorewall/Perl/Shorewall/Chains.pm +++ b/Shorewall/Perl/Shorewall/Chains.pm @@ -149,6 +149,8 @@ our %EXPORT_TAGS = ( match_orig_dest match_ipsec_in match_ipsec_out + do_ipsec_options + do_ipsec log_rule expand_rule addnatjump @@ -2615,6 +2617,92 @@ sub match_ipsec_out( $$ ) { $match; } +# +# Handle a unidirectional IPSEC Options +# +sub do_ipsec_options($$$) +{ + my %validoptions = ( strict => NOTHING, + next => NOTHING, + reqid => NUMERIC, + spi => NUMERIC, + proto => IPSECPROTO, + mode => IPSECMODE, + "tunnel-src" => NETWORK, + "tunnel-dst" => NETWORK, + ); + my ( $dir, $policy, $list ) = @_; + my $options = "-m policy --pol $policy --dir $dir "; + my $fmt; + + for my $e ( split_list $list, 'IPSEC option' ) { + my $val = undef; + my $invert = ''; + + if ( $e =~ /([\w-]+)!=(.+)/ ) { + $val = $2; + $e = $1; + $invert = '! '; + } elsif ( $e =~ /([\w-]+)=(.+)/ ) { + $val = $2; + $e = $1; + } + + $fmt = $validoptions{$e}; + + fatal_error "Invalid IPSEC Option ($e)" unless $fmt; + + if ( $fmt eq NOTHING ) { + fatal_error "Option \"$e\" does not take a value" if defined $val; + } else { + fatal_error "Missing value for option \"$e\"" unless defined $val; + fatal_error "Invalid value ($val) for option \"$e\"" unless $val =~ /^($fmt)$/; + } + + $options .= $invert; + $options .= "--$e "; + $options .= "$val " if defined $val; + } + + $options; +} + +# +# Handle a bi-directional IPSEC column +# +sub do_ipsec($) { + my $ipsec = $_[0]; + + if ( $ipsec eq '-' ) { + return ''; + } + + fatal_error "Non-empty IPSEC column requires policy match support in your kernel and iptables" unless have_capability( 'POLICY_MATCH' ); + + if ( $ipsec eq 'in' ) { + do_ipsec_options 'in', 'ipsec', ''; + } elsif ( $ipsec eq 'out' ) { + do_ipsec_options 'out', 'ipsec', ''; + } else { + my @options = split_list $ipsec, 'IPSEC options'; + my $dir = shift @options; + + fatal_error q(First IPSEC option must be 'in' or 'out') unless $dir =~ /^(?:in|out)$/; + + if ( @options == 1 ) { + if ( lc( $options[0] ) =~ /^(yes|ipsec)$/ ) { + return do_ipsec_option $dir, 'ipsec', ''; + } + + if ( lc( $options[0] ) =~ /^(no|none)$/ ) { + return do_ipsec_option $dir, 'ipsec', ''; + } + } + + do_ipsec_options $dir, 'ipsec', join( ',', @options ); + } +} + # # Generate a log message # diff --git a/Shorewall/Perl/Shorewall/Nat.pm b/Shorewall/Perl/Shorewall/Nat.pm index 4c6f4c6d4..801a72b97 100644 --- a/Shorewall/Perl/Shorewall/Nat.pm +++ b/Shorewall/Perl/Shorewall/Nat.pm @@ -36,7 +36,7 @@ use strict; our @ISA = qw(Exporter); our @EXPORT = qw( setup_masq setup_nat setup_netmap add_addresses ); our @EXPORT_OK = (); -our $VERSION = '4.4_11'; +our $VERSION = '4.4_13'; our @addresses_to_add; our %addresses_to_add; @@ -49,56 +49,6 @@ sub initialize() { %addresses_to_add = (); } -# -# Handle IPSEC Options in a masq record -# -sub do_ipsec_options($) -{ - my %validoptions = ( strict => NOTHING, - next => NOTHING, - reqid => NUMERIC, - spi => NUMERIC, - proto => IPSECPROTO, - mode => IPSECMODE, - "tunnel-src" => NETWORK, - "tunnel-dst" => NETWORK, - ); - my $list=$_[0]; - my $options = '-m policy --pol ipsec --dir out '; - my $fmt; - - for my $e ( split_list $list, 'option' ) { - my $val = undef; - my $invert = ''; - - if ( $e =~ /([\w-]+)!=(.+)/ ) { - $val = $2; - $e = $1; - $invert = '! '; - } elsif ( $e =~ /([\w-]+)=(.+)/ ) { - $val = $2; - $e = $1; - } - - $fmt = $validoptions{$e}; - - fatal_error "Invalid Option ($e)" unless $fmt; - - if ( $fmt eq NOTHING ) { - fatal_error "Option \"$e\" does not take a value" if defined $val; - } else { - fatal_error "Missing value for option \"$e\"" unless defined $val; - fatal_error "Invalid value ($val) for option \"$e\"" unless $val =~ /^($fmt)$/; - } - - $options .= $invert; - $options .= "--$e "; - $options .= "$val " if defined $val; - } - - $options; -} - # # Process a single rule from the the masq file # @@ -153,11 +103,11 @@ sub process_one_masq( ) fatal_error "Non-empty IPSEC column requires policy match support in your kernel and iptables" unless have_capability( 'POLICY_MATCH' ); if ( $ipsec =~ /^yes$/i ) { - $baserule .= '-m policy --pol ipsec --dir out '; + $baserule .= do_ipsec_options 'out', 'ipsec', ''; } elsif ( $ipsec =~ /^no$/i ) { - $baserule .= '-m policy --pol none --dir out '; + $baserule .= do_ipsec_options 'out', 'none', ''; } else { - $baserule .= do_ipsec_options $ipsec; + $baserule .= do_ipsec_options 'out', 'ipsec', $ipsec; } } elsif ( have_ipsec ) { $baserule .= '-m policy --pol none --dir out ';