Hello.

This is more like a pull request. If the users mailing list is not the
appropriate, I apologize and please tell me where should I submit it.

One big problem when using ifb (redirected) interfaces for download QoS
control and NAT is that you can't usually create tcfilters based on a
internal destination address. That's because when packets enter the
outside interface, they are redirected to the ifb interface before
reverse NAT or any other netfilter hooks.

However, fairly recent kernels (at least the one that comes with
RHEL/CentOS 7, which has now a few years) have a tc filter action named
connmark that helps to create a workaround, but shorewall doesn't
support it.

Using the following (crude) patch I was able to take advantage of that
feature:

--- /root/Tc.pm.bkp    2020-07-07 17:26:27.329581191 +0100
+++ /usr/lib/perl5/site_perl/Shorewall/Tc.pm    2020-07-07
17:28:14.249592180 +0100
@@ -1865,7 +1865,7 @@
         for my $rdev ( @{$devref->{redirected}} ) {
         my $phyrdev = physical_name( $rdev );
         emit ( "run_tc qdisc add dev $phyrdev handle ffff: ingress" );
-        emit( "run_tc filter add dev $phyrdev parent ffff: protocol all
u32 match u32 0 0 action mirred egress redirect dev $device > /dev/null" );
+        emit( "run_tc filter add dev $phyrdev parent ffff: protocol all
u32 match u32 0 0 action connmark action mirred egress redirect dev
$device > /dev/null" );
         }
 
         for my $class ( @tcclasses ) {


Of course this should be optional. My suggestion is to have a new
possible OPTION in tcdevices named "connmark", only valid when
REDIRECTED INTERFACES is not empty. If present, the mirred filter is
generated as above suggested, and if not present it stays as the current
behaviour.

Perhaps some extra code to determine if the tc filter action connmark is
supported and set a new capability would be nice, but since it's already
optional and should fail anyway if not supported, I don't think that
would be really necessary.Please improve as needed - my proposed patch
(against shorewall 5.2.5-2, and already with the option parsing) is
attached in this message.

A minimal example configuration using this suggested feature follows.
For this scenario, there is a single 1 Gbps Internet connection. LAN
users shouldn't use more than 50 mbps for upload and 100 for download.
The rest should be available to our servers, who can also "borrow"
bandwidth from the LAN network when it's not in use.
Let's suppose that 10.100.100.0/24 corresponds to the lan network.

Shorewall configuration files:


/etc/shorewall/zones:
#ZONE        TYPE        OPTIONS        IN_OPTIONS    OUT_OPTIONS
fw           firewall
net          ipv4
lan          ipv4        routeback
srv         ipv4        routeback

/etc/shorewall/interfaces:
#ZONE        INTERFACE        OPTIONS
net          enp1s0
lan          enp2s0
srv          enp3s0
# our ifb interface, shouldn't be necessary to declare but doesn't hurt
-            ifb0


/etc/shorewall/policy:
#SOURCE    DEST    POLICY        LOGLEVEL    RATE    CONNLIMIT
$FW        all     ACCEPT
lan        net     ACCEPT
srv        net     ACCEPT


/etc/shorewall/rules:
#ACTION         SOURCE      DEST    PROTO   DPORT   SPORT  
ORIGDEST        RATE    USER    MARK    CONNLIMIT       TIME    HEADERS
SWITCH  HELPER
?SECTION NEW
ACCEPT          lan         $FW     tcp     22
(...)


/etc/shorewall/snat:
#ACTION       SOURCE      DEST    PROTO    PORT        IPSEC    MARK   
USER    SWITCH    ORIGDEST    PROBABILITY
MASQUERADE    -           enp1s0


/etc/shorewall/shorewall.conf:
(...)
TC_ENABLED=Internal


/etc/shorewall/tcdevices:
#NUMBER:        IN-BANDWITH     OUT-BANDWIDTH   OPTIONS         REDIRECTED
#INTERFACE                                                      INTERFACES
## net upload
10:enp1s0       -               1000mbit         htb
## net download
11:ifb0         -               1000mbit         htb,connmark   enp1s0


/etc/shorewall/tcclasses:
#INTERFACE        MARK      RATE               CEIL       PRIO    OPTIONS

10:5000           111       500kbit            full       10     
tcp-ack,tos-minimize-delay
11:5000           110       500kbit            full       10     
tcp-ack,tos-minimize-delay

10:1000           100       full-50500         full       20      default
11:1000           101       full-100500        full       20      default

10:50             10        50mbit             50mbit     101    
flow=nfct-src
11:100            11        100mbit            100mbit    101     flow=dst


/etc/shorewall/tcfilters:
#INTERFACE:    SOURCE         DEST        PROTO    DEST    SOURCE  
TOS        LENGTH    PRIORITY
#CLASS                                   PORT(S)  PORT(S)
## limit LAN upload - works
10:50          10.100.100.0/24
## limit LAN download - DOESN'T WORK BECAUSE OF MASQUERADE ON enp1s0
!!!! (snat file)
#11:100        -              10.100.100.0/24


/etc/shorewall/mangle:
#ACTION            SOURCE             DEST        PROTO    DPORT   
SPORT    USER    TEST    LENGTH    TOS    CONNBYTES    HELPER   
PROBABILITY    DSCP    SWITCH
## limit downloads of connections started by LAN users to the Internet
## this only works with the aforementioned conntrack filter action when
setting up mirred ifb, as it restores the connmark to the mark
## and LAN users' download traffic will get the 11:100 class (defined in
tcclasses) applied
CONNMARK(11)       10.100.100.0/24    -


Only problem I see is when using more than one Internet provider, having
configured them in the /etc/shorewall/providers. Perhaps in that case
one is able to use xmark masks to have the best of both worlds? Any ideas?

Anyway, in hope that you also find this a useful feature... is there any
chance that shorewall officially supports this in a near future release? :)

Thanks in advance.
--- /root/Tc.pm.bkp	2020-07-07 17:26:27.329581191 +0100
+++ /usr/lib/perl5/site_perl/Shorewall/Tc.pm	2020-07-07 19:57:43.433513961 +0100
@@ -422,8 +422,8 @@
     fatal_error "Duplicate INTERFACE ($device)"    if $tcdevices{$device};
     fatal_error "Invalid INTERFACE name ($device)" if $device =~ /[:+]/;
 
-    my ( $classify, $pfifo, $flow, $qdisc, $linklayer, $overhead, $mtu, $mpu, $tsize ) = 
-	(0,         0,      '',    'htb',  '',         0,         0,    0,    0);
+    my ( $classify, $pfifo, $flow, $qdisc, $linklayer, $overhead, $mtu, $mpu, $tsize, $connmark ) = 
+	(0,         0,      '',    'htb',  '',         0,         0,    0,    0,      0);
 
     if ( $options ne '-' ) {
 	for my $option ( split_list1 $options, 'option' ) {
@@ -458,6 +458,8 @@
 		$tsize = numeric_value( $1 );
 		fatal_error "Invalid tsize ($1)" unless defined $tsize;
 		fatal_error q('tsize' requires 'linklayer') unless $linklayer; 
+	    } elsif ( $option eq 'connmark' ) {
+		$connmark = 1;
 	    } else {
 		fatal_error "Unknown device option ($option)";
 	    }
@@ -478,6 +480,8 @@
 	    fatal_error "REDIRECTED device ($rdevice) has not been defined in this file" unless $rdevref;
 	    fatal_error "IN-BANDWIDTH must be zero for REDIRECTED devices" if $rdevref->{in_bandwidth} != 0;
 	}
+    } elsif ( $connmark ) {
+	fatal_error "Option connmark can only be used when setting up a IFB device";
     }
 
     $inband = process_in_bandwidth( $inband );
@@ -503,6 +507,7 @@
 			    mpu           => $mpu,
 			    tsize         => $tsize,
 			    filterpri     => 0,
+			    connmark      => $connmark,
 			  } ,
 
     push @tcdevices, $device;
@@ -1865,7 +1870,7 @@
 	    for my $rdev ( @{$devref->{redirected}} ) {
 		my $phyrdev = physical_name( $rdev );
 		emit ( "run_tc qdisc add dev $phyrdev handle ffff: ingress" );
-		emit( "run_tc filter add dev $phyrdev parent ffff: protocol all u32 match u32 0 0 action mirred egress redirect dev $device > /dev/null" );
+		emit( "run_tc filter add dev $phyrdev parent ffff: protocol all u32 match u32 0 0 ".($devref->{'connmark'} ? ' action connmark' : '')." action mirred egress redirect dev $device > /dev/null" );
 	    }
 
 	    for my $class ( @tcclasses ) {

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
Shorewall-users mailing list
Shorewall-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/shorewall-users

Reply via email to