diff --git a/Shorewall/Perl/Shorewall/Config.pm b/Shorewall/Perl/Shorewall/Config.pm index d41ae9613..c3460773d 100644 --- a/Shorewall/Perl/Shorewall/Config.pm +++ b/Shorewall/Perl/Shorewall/Config.pm @@ -4097,7 +4097,7 @@ sub get_configuration( $$$ ) { fatal_error 'Invalid Packet Mark layout' if $config{ZONE_BITS} + $globals{ZONE_OFFSET} > 30; $globals{EXCLUSION_MASK} = 1 << ( $globals{ZONE_OFFSET} + $config{ZONE_BITS} ); - $globals{TPROXY_MASK} = $globals{EXCLUSION_MASK} << 1; + $globals{TPROXY_MARK} = $globals{EXCLUSION_MASK} << 1; $globals{PROVIDER_MIN} = 1 << $config{PROVIDER_OFFSET}; $globals{TC_MAX} = make_mask( $config{TC_BITS} ); diff --git a/Shorewall/Perl/Shorewall/Providers.pm b/Shorewall/Perl/Shorewall/Providers.pm index 187a63638..2e1b057aa 100644 --- a/Shorewall/Perl/Shorewall/Providers.pm +++ b/Shorewall/Perl/Shorewall/Providers.pm @@ -396,8 +396,8 @@ sub process_a_provider() { $gateway = ''; } - my ( $loose, $track, $balance , $default, $default_balance, $optional, $mtu, $local , $load ) = - (0, $config{TRACK_PROVIDERS}, 0 , 0, $config{USE_DEFAULT_RT} ? 1 : 0, interface_is_optional( $interface ), '' , 0 , 0 ); + my ( $loose, $track, $balance , $default, $default_balance, $optional, $mtu, $tproxy , $load ) = + (0, $config{TRACK_PROVIDERS}, 0 , 0, $config{USE_DEFAULT_RT} ? 1 : 0, interface_is_optional( $interface ), '' , 0 , 0 ); unless ( $options eq '-' ) { for my $option ( split_list $options, 'option' ) { @@ -434,10 +434,10 @@ sub process_a_provider() { } elsif ( $option eq 'fallback' ) { $default = -1; $default_balance = 0; - } elsif ( $option eq 'local' ) { - $local = 1; - $track = 0 if $config{TRACK_PROVIDERS}; - $default_balance = 0 if $config{USE_DEFAULT_RT}; + } elsif ( $option eq 'tproxy' ) { + $tproxy = 1; + $track = 0 if $config{TRACK_PROVIDERS}; + $default_balance = 0 if $config{USE_DEFAULT_RT}; } elsif ( $option =~ /^load=(0?\.\d{1,8})/ ) { $load = $1; require_capability 'STATISTIC_MATCH', "load=$load", 's'; @@ -455,11 +455,12 @@ sub process_a_provider() { $maxload += $load; } - if ( $local ) { - fatal_error "GATEWAY not valid with 'local' provider" unless $gatewaycase eq 'none'; - fatal_error "'track' not valid with 'local'" if $track; - fatal_error "DUPLICATE not valid with 'local'" if $duplicate ne '-'; - fatal_error "MARK required with 'local'" unless $mark; + if ( $tproxy ) { + fatal_error "GATEWAY not valid with 'tproxy' provider" unless $gatewaycase eq 'none'; + fatal_error "'track' not valid with 'tproxy'" if $track; + fatal_error "DUPLICATE not valid with 'tproxy'" if $duplicate ne '-'; + fatal_error "MARK not allowed with 'tproxy'" if $mark ne '-'; + $mark = $globals{TPROXY_MARK}; } my $val = 0; @@ -471,24 +472,29 @@ sub process_a_provider() { require_capability( 'MANGLE_ENABLED' , 'Provider marks' , '' ); - $val = numeric_value $mark; + if ( $tproxy ) { + $val = $globals{TPROXY_MARK}; + $pref = 1; + } else { + $val = numeric_value $mark; - fatal_error "Invalid Mark Value ($mark)" unless defined $val && $val; + fatal_error "Invalid Mark Value ($mark)" unless defined $val && $val; - verify_mark $mark; + verify_mark $mark; - fatal_error "Invalid Mark Value ($mark)" unless ( $val & $globals{PROVIDER_MASK} ) == $val; + fatal_error "Invalid Mark Value ($mark)" unless ( $val & $globals{PROVIDER_MASK} ) == $val; - fatal_error "Provider MARK may not be specified when PROVIDER_BITS=0" unless $config{PROVIDER_BITS}; + fatal_error "Provider MARK may not be specified when PROVIDER_BITS=0" unless $config{PROVIDER_BITS}; - for my $providerref ( values %providers ) { - fatal_error "Duplicate mark value ($mark)" if numeric_value( $providerref->{mark} ) == $val; + for my $providerref ( values %providers ) { + fatal_error "Duplicate mark value ($mark)" if numeric_value( $providerref->{mark} ) == $val; + } + + $lastmark = $val; + + $pref = 10000 + $number - 1; } - $pref = 10000 + $number - 1; - - $lastmark = $val; - } unless ( $loose ) { @@ -526,7 +532,7 @@ sub process_a_provider() { loose => $loose , duplicate => $duplicate , address => $address , - local => $local , + tproxy => $tproxy , load => $load , rules => [] , routes => [] , @@ -578,7 +584,7 @@ sub add_a_provider( $$ ) { my $loose = $providerref->{loose}; my $duplicate = $providerref->{duplicate}; my $address = $providerref->{address}; - my $local = $providerref->{local}; + my $tproxy = $providerref->{tproxy}; my $load = $providerref->{load}; my $dev = chain_base $physical; @@ -600,7 +606,7 @@ sub add_a_provider( $$ ) { $provider_interfaces{$interface} = $table; if ( $gatewaycase eq 'none' ) { - if ( $local ) { + if ( $tproxy ) { emit 'run_ip route add local ' . ALLIP . " dev $physical table $number"; } else { emit "run_ip route add default dev $physical table $number"; @@ -632,12 +638,13 @@ CEOF setup_interface_proc( $interface ); if ( $mark ne '-' ) { - my $mask = have_capability 'FWMARK_RT_MASK' ? '/' . in_hex $globals{PROVIDER_MASK} : ''; + my $hexmark = in_hex( $mark ); + my $mask = have_capability 'FWMARK_RT_MASK' ? '/' . in_hex( $globals{ $tproxy ? 'TPROXY_MARK' : 'PROVIDER_MASK' } ) : ''; - emit ( "qt \$IP -$family rule del fwmark ${mark}${mask}" ) if $config{DELETE_THEN_ADD}; + emit ( "qt \$IP -$family rule del fwmark ${hexmark}${mask}" ) if $config{DELETE_THEN_ADD}; - emit ( "run_ip rule add fwmark ${mark}${mask} pref $pref table $number", - "echo \"qt \$IP -$family rule del fwmark ${mark}${mask}\" >> \${VARDIR}/undo_${table}_routing" + emit ( "run_ip rule add fwmark ${hexmark}${mask} pref $pref table $number", + "echo \"qt \$IP -$family rule del fwmark ${hexmark}${mask}\" >> \${VARDIR}/undo_${table}_routing" ); } @@ -697,7 +704,7 @@ CEOF qq( qt \$IP -6 rule add from all table ) . DEFAULT_TABLE . qq( prio 32767\n) , qq(fi) ) if $family == F_IPV6; - unless ( $local ) { + unless ( $tproxy ) { emit ''; if ( $loose ) { diff --git a/Shorewall/Perl/Shorewall/Tc.pm b/Shorewall/Perl/Shorewall/Tc.pm index 6da363341..ed880fa75 100644 --- a/Shorewall/Perl/Shorewall/Tc.pm +++ b/Shorewall/Perl/Shorewall/Tc.pm @@ -163,18 +163,16 @@ my @tcclasses; my %tcclasses; my %restrictions = ( tcpre => PREROUTE_RESTRICT , + tproxy => PREROUTE_RESTRICT , tcpost => POSTROUTE_RESTRICT , tcfor => NO_RESTRICT , tcin => INPUT_RESTRICT , - tcout => OUTPUT_RESTRICT ); + tcout => OUTPUT_RESTRICT , + ); my $family; -# -# Variables supporting DIVERT -# -my $divert; #Next chain sequence number -my %diversions; #Map of marks -> chains. We use a hash rather than an array because mark values can be huge +my $divertref; # DIVERT chain # # Rather than initializing globals in an INIT block or during declaration, @@ -187,18 +185,17 @@ my %diversions; #Map of marks -> chains. We use a hash rather than an array # able to re-initialize its dependent modules' state. # sub initialize( $ ) { - $family = shift; - %classids = (); - @tcdevices = (); - %tcdevices = (); - @tcclasses = (); - %tcclasses = (); - %diversions = (); - @devnums = (); - $devnum = 0; - $sticky = 0; - $ipp2p = 0; - $divert = 0; + $family = shift; + %classids = (); + @tcdevices = (); + %tcdevices = (); + @tcclasses = (); + %tcclasses = (); + @devnums = (); + $devnum = 0; + $sticky = 0; + $ipp2p = 0; + $divertref = 0; } sub process_tc_rule( ) { @@ -305,30 +302,18 @@ sub process_tc_rule( ) { }, DIVERT => sub() { fatal_error "Invalid DIVERT specification( $cmd/$rest )" if $rest; - fatal_error "DIVERT requires TC_EXPERT=Yes" unless $config{TC_EXPERT}; - $chain = 'tcpre'; + $chain = 'tproxy'; - $cmd =~ /DIVERT\((.+?)\)$/; + $mark = in_hex( $globals{TPROXY_MARK} ) . '/' . in_hex( $globals{TPROXY_MARK} ); - $mark = $1; - - fatal_error "Invalid DIVERT specification( $cmd )" unless defined $mark; - - my $val = numeric_value( $mark ); - - validate_mark $val . '/' . in_hex( $globals{PROVIDER_MASK} ); - - my $divertref = $diversions{$val}; - unless ( $divertref ) { - $divertref = $diversions{$val} = new_chain( 'mangle', 'DIVERT' . ( $divert ? $divert : '' ) ); - $divert++; - add_ijump( $divertref , j => 'MARK', targetopts => '--set-mark ' . in_hex( $val ) . '/' . in_hex( $globals{PROVIDER_MASK} ) ); + $divertref = new_chain( 'mangle', 'divert' ); + add_ijump( $divertref , j => 'MARK', targetopts => "--set-mark $mark" ); add_ijump( $divertref , j => 'ACCEPT' ); } - $target = $divertref->{name}; + $target = 'divert'; $matches = '! --tcp-flags FIN,SYN,RST,ACK SYN -m socket --transparent '; }, @@ -337,7 +322,7 @@ sub process_tc_rule( ) { fatal_error "Invalid TPROXY specification( $cmd/$rest )" if $rest; - $chain = 'tcpre'; + $chain = 'tproxy'; $cmd =~ /TPROXY\((.+?)\)$/; @@ -345,7 +330,7 @@ sub process_tc_rule( ) { fatal_error "Invalid TPROXY specification( $cmd )" unless defined $params; - ( $mark, my $port, my $ip, my $bad ) = split ',', $params; + ( my $port, my $ip, my $bad ) = split ',', $params; fatal_error "Invalid TPROXY specification( $cmd )" if defined $bad; @@ -368,7 +353,7 @@ sub process_tc_rule( ) { $target .= ' --tproxy-mark'; - $mark = "$mark/" . in_hex( $globals{PROVIDER_MASK} ); + $mark = in_hex( $globals{TPROXY_MARK} ) . '/' . in_hex( $globals{TPROXY_MARK} ); }, TTL => sub() { fatal_error "TTL is not supported in IPv6 - use HL instead" if $family == F_IPV6; @@ -1958,6 +1943,7 @@ sub setup_tc() { ensure_mangle_chain 'tcfor'; ensure_mangle_chain 'tcpost'; ensure_mangle_chain 'tcin'; + ensure_mangle_chain 'tproxy'; } my @mark_part; @@ -1975,6 +1961,7 @@ sub setup_tc() { } } + add_ijump $mangle_table->{PREROUTING} , j => 'tproxy' if $mangle_table->{tproxy}{referenced}; add_ijump $mangle_table->{PREROUTING} , j => 'tcpre', @mark_part; add_ijump $mangle_table->{OUTPUT} , j => 'tcout', @mark_part; diff --git a/Shorewall/manpages/shorewall-providers.xml b/Shorewall/manpages/shorewall-providers.xml index bf4d5be78..337a472a0 100644 --- a/Shorewall/manpages/shorewall-providers.xml +++ b/Shorewall/manpages/shorewall-providers.xml @@ -270,6 +270,19 @@ shorewall.conf. + + + tproxy + + + Added in Shorewall 4.5.4. Used for supporting the TPROXY + action in shorewall-tcrules(5). See http://www.shorewall.net/Shorewall_Squid_Usage.html. + When specified, the MARK, DUPLICATE and GATEWAY columns should + be empty, INTERFACE should be set to 'lo' and + should be the only OPTION. + + diff --git a/Shorewall/manpages/shorewall-tcrules.xml b/Shorewall/manpages/shorewall-tcrules.xml index 770a44d0c..299ea104a 100644 --- a/Shorewall/manpages/shorewall-tcrules.xml +++ b/Shorewall/manpages/shorewall-tcrules.xml @@ -408,36 +408,29 @@ SAME $FW 0.0.0.0/0 tcp 80,443 - DIVERT(mark) + DIVERT - Added in Shorewall 4.5.3. A DIVERT rule should preceed - each TPROXY rule and should specify the same - mark value. DIVERT avoids sending - packets to the TPROXY target once a socket connection to Squid3 - has been established by TPROXY. DIVERT marks the packet with the - specified mark and exempts it from - any rules that follow. + Added in Shorewall 4.5.3. Two DIVERT rule should preceed + the TPROXY rule and should select DEST PORT tcp 80 and SOURCE + PORT tcp 80 respectively (assuming that tcp port 80 is being + proxied). DIVERT avoids sending packets to the TPROXY target + once a socket connection to Squid3 has been established by + TPROXY. DIVERT marks the packet with a unique mark and exempts + it from any rules that follow. TPROXY(mark[,[port][,[address]]]) + role="bold">TPROXY([port][,address]) Transparently redirects a packet without altering the IP - header. Requires a local provider to be defined in shorewall-providers(5). - There are three parameters to TPROXY - only the first - (mark) is required: + There are three parameters to TPROXY - neither is + required: - - mark - the MARK value - corresponding to the local provider in shorewall-providers(5). - - port - the port on which the proxy server is listening. If omitted, the original @@ -451,12 +444,6 @@ SAME $FW 0.0.0.0/0 tcp 80,443 request arrives. - - - A DIVERT rule specifying the same - mark value and other column values - should preceed each TPROXY rule. - diff --git a/Shorewall6/manpages/shorewall6-providers.xml b/Shorewall6/manpages/shorewall6-providers.xml index 99c3b6f57..96d5cff99 100644 --- a/Shorewall6/manpages/shorewall6-providers.xml +++ b/Shorewall6/manpages/shorewall6-providers.xml @@ -245,6 +245,19 @@ column is assumed. + + + tproxy + + + Added in Shorewall 4.5.4. Used for supporting the TPROXY + action in shorewall-tcrules(5). See http://www.shorewall.net/Shorewall_Squid_Usage.html. + When specified, the MARK, DUPLICATE and GATEWAY columns should + be empty, INTERFACE should be set to 'lo' and + should be the only OPTION. + + diff --git a/Shorewall6/manpages/shorewall6-tcrules.xml b/Shorewall6/manpages/shorewall6-tcrules.xml index ada019d7d..d16945e3e 100644 --- a/Shorewall6/manpages/shorewall6-tcrules.xml +++ b/Shorewall6/manpages/shorewall6-tcrules.xml @@ -305,21 +305,20 @@ SAME $FW 0.0.0.0/0 tcp 80,443 - DIVERT(mark) + DIVERT - Added in Shorewall 4.5.3. A DIVERT rule should preceed - each TPROXY rule and should specify the same - mark value. DIVERT avoids sending - packets to the TPROXY target once a socket connection to Squid3 - has been established by TPROXY. DIVERT marks the packet with the - specified mark and exempts it from - any rules that follow. + Added in Shorewall 4.5.3. Two DIVERT rule should preceed + the TPROXY rule and should select DEST PORT tcp 80 and SOURCE + PORT tcp 80 respectively (assuming that tcp port 80 is being + proxied). DIVERT avoids sending packets to the TPROXY target + once a socket connection to Squid3 has been established by + TPROXY. DIVERT marks the packet with a unique mark and exempts + it from any rules that follow. TPROXY(mark][,[port][,[address]]]) + role="bold">TPROXY([port][,[address]]]) Transparently redirects a packet without altering the IP header. Requires a local provider to be defined in (mark) is required: - - mark - the MARK value - corresponding to the local provider in shorewall6-providers(5). - - port - the port on which the proxy server is listening. If omitted, the original @@ -348,12 +341,6 @@ SAME $FW 0.0.0.0/0 tcp 80,443 request arrives. - - - A DIVERT rule specifying the same - mark value and other column values - should preceed each TPROXY rule. - diff --git a/docs/PacketMarking.xml b/docs/PacketMarking.xml index 6c8e4815b..d05f85d5d 100644 --- a/docs/PacketMarking.xml +++ b/docs/PacketMarking.xml @@ -398,6 +398,10 @@ tcp 6 19 TIME_WAIT src=206.124.146.176 dst=192.136.34.98 sport=58597 dport= shorewall update (shorewall6 update) command will set the above options based on the settings of WIDE_TC_MARKS and HIGH_ROUTE_MARKS. + + In Shorewall 4.5.4, a TPROXY mark was added + for TPROXY support. It is a single bit wide and is to the immediate left + of the exclusion mark.
diff --git a/docs/Shorewall_Squid_Usage.xml b/docs/Shorewall_Squid_Usage.xml index 92e6f8851..1efbac6b8 100644 --- a/docs/Shorewall_Squid_Usage.xml +++ b/docs/Shorewall_Squid_Usage.xml @@ -312,15 +312,25 @@ ACCEPT $FW net tcp 80,443
Transparent with TPROXY - Shorewall 4.4.7 contains support for TPROXY. TPROXY differs from - REDIRECT in that it does not modify the IP header. Because the IP header - stays intact, TPROXY requires policy routing to direct the packets to the - proxy server running on the firewall. This approach requires TPROXY - support in your kernel and iptables and Squid 3. See Shorewall 4.5.4 contains support for TPROXY. TPROXY differs from + REDIRECT in that it does not modify the IP header and requires Squid 3 or + later. Because the IP header stays intact, TPROXY requires policy routing + to direct the packets to the proxy server running on the firewall. This + approach requires TPROXY support in your kernel and iptables and Squid 3. + See http://wiki.squid-cache.org/Features/Tproxy4. + + Support for the TPROXY action in shorewall-tcrules(5) and the + option in shorewall-providers(5) has been + available since Shoreall 4.4.7. That support required additional rules + to be added in the 'start' extention script to make it work + reliable. + + The following configuration works with Squid running on the firewall - itself (assume that Squid is listening on port 3128). + itself (assume that Squid is listening on port 3129 for TPROXY + connections). /etc/shorewall/interfaces: @@ -330,21 +340,25 @@ ACCEPT $FW net tcp 80,443 /etc/shorewall/providers: #NAME NUMBER MARK DUPLICATE INTERFACE GATEWAY OPTIONS COPY -Tproxy 1 1 - lo - local +Tproxy 1 - - lo - tproxy + + + Notice that the MARK, DUPLICATE and GATEWAY columns are empty and + that the only option is . + /etc/shorewall/tcrules (assume loc interface is eth1): - MARK SOURCE DEST PROTO PORT(S) -DIVERT(1) eth1 0.0.0.0/0 tcp 80 -TPROXY(1,3128) eth1 0.0.0.0/0 tcp 80 + MARK SOURCE DEST PROTO DEST SOURCE + PORT(S) PORT(S) +DIVERT - 0.0.0.0/0 tcp 80 +DIVERT - 0.0.0.0/0 tcp - 80 +TPROXY(3129) eth1 0.0.0.0/0 tcp 80 - - The DIVERT action was added in Shorewall 4.5.3; user's running - earlier versions of Shorewall will need to use the start extension script to add the - DIVERT logic mentioned in the Squid article linked above. - + The DIVERT rules are used to avoid unnecessary invocation of TPROXY + for request packets after the connection is established and to direct + response packets back to Squid3. /etc/shorewall/rules: diff --git a/docs/images/MarkGeometry.dia b/docs/images/MarkGeometry.dia index c8528dedc..f41ca2e8f 100644 Binary files a/docs/images/MarkGeometry.dia and b/docs/images/MarkGeometry.dia differ diff --git a/docs/images/MarkGeometry.png b/docs/images/MarkGeometry.png index fd921ee87..70cdbe112 100644 Binary files a/docs/images/MarkGeometry.png and b/docs/images/MarkGeometry.png differ