#!/usr/bin/perl ############################################################################### # # # IPFire.org - A linux based firewall # # Copyright (C) 2007-2021 IPFire Team # # # # This program is free software: you can redistribute it and/or modify # # it under the terms of the GNU General Public License as published by # # the Free Software Foundation, either version 3 of the License, or # # (at your option) any later version. # # # # This program is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # GNU General Public License for more details. # # # # You should have received a copy of the GNU General Public License # # along with this program. If not, see . # # # ############################################################################### use strict; # enable only the following on debugging purpose # use warnings; require '/var/ipfire/general-functions.pl'; require "${General::swroot}/lang.pl"; require "${General::swroot}/header.pl"; my %qossettings = (); my %checked = (); my %netsettings = (); my $message = ""; my $errormessage = ""; my $c = ""; my $direntry = ""; my $classentry = ""; my $l7ruleentry = ""; my $portruleentry = ""; my $tosruleentry = ""; my @tmp = (); my @classes = (); my @l7rules = (); my @portrules = (); my @tosrules = (); my @tmpline = (); my @classline = (); my @tosruleline = (); my @l7ruleline = (); my @portruleline = (); my @proto = (); my %selected= () ; my $classfile = "/var/ipfire/qos/classes"; my $level7file = "/var/ipfire/qos/level7config"; my $portfile = "/var/ipfire/qos/portconfig"; my $tosfile = "/var/ipfire/qos/tosconfig"; my @cake_options = ( # RED is by default connected to the Internet "internet" ); # Define iptables MARKs my $QOS_INC_MASK = 0x0000ff00; my $QOS_INC_SHIFT = 8; my $QOS_OUT_MASK = 0x000000ff; my $QOS_OUT_SHIFT = 0; my $QOS_INC_SKIP_MASK = $QOS_INC_MASK; my $QOS_OUT_SKIP_MASK = $QOS_OUT_MASK; &General::readhash("${General::swroot}/ethernet/settings", \%netsettings); $qossettings{'ENABLED'} = 'off'; $qossettings{'EDIT'} = 'no'; $qossettings{'OUT_SPD'} = ''; $qossettings{'INC_SPD'} = ''; $qossettings{'DEF_OUT_SPD'} = ''; $qossettings{'DEF_INC_SPD'} = ''; $qossettings{'DEFCLASS_INC'} = ''; $qossettings{'DEFCLASS_OUT'} = ''; $qossettings{'RED_DEV'} = `cat /var/ipfire/red/iface`; $qossettings{'IMQ_DEV'} = 'imq0'; $qossettings{'TOS'} = ''; $qossettings{'VALID'} = 'yes'; &General::readhash("${General::swroot}/qos/settings", \%qossettings); # Default to "conservative unless (defined $qossettings{'CAKE_PROFILE'}) { $qossettings{'CAKE_PROFILE'} = "conservative"; } push(@cake_options, $qossettings{'CAKE_PROFILE'}); my $DEF_OUT_MARK = ($qossettings{'DEFCLASS_OUT'} << $QOS_OUT_SHIFT) . "/$QOS_OUT_MASK"; my $DEF_INC_MARK = ($qossettings{'DEFCLASS_INC'} << $QOS_INC_SHIFT) . "/$QOS_INC_MASK"; open( FILE, "< $classfile" ) or die "Unable to read $classfile"; @classes = ; close FILE; open( FILE, "< $level7file" ) or die "Unable to read $level7file"; @l7rules = ; close FILE; open( FILE, "< $portfile" ) or die "Unable to read $portfile"; @portrules = ; close FILE; open( FILE, "< $tosfile" ) or die "Unable to read $tosfile"; @tosrules = ; close FILE; ############################################################################################################################ ############################################################################################################################ print < /dev/null iptables -t mangle -n -L QOS-INC -v -x 2> /dev/null exit 0 ;; esac \$0 \$1 qdisc \$0 \$1 class \$0 \$1 filter \$0 \$1 iptables exit 0 ;; start) ### ### $qossettings{'RED_DEV'} ### ### INIT KERNEL modprobe sch_htb ### ADD HTB QDISC FOR $qossettings{'RED_DEV'} tc qdisc del dev $qossettings{'RED_DEV'} root >/dev/null 2>&1 tc qdisc add dev $qossettings{'RED_DEV'} root handle 1: htb default $qossettings{'DEFCLASS_OUT'} ### MAIN RATE LIMIT tc class add dev $qossettings{'RED_DEV'} parent 1: classid 1:1 htb rate $qossettings{'OUT_SPD'}kbit ### CLASSES FOR $qossettings{'RED_DEV'} END ; foreach $classentry (sort @classes) { @classline = split( /\;/, $classentry ); if ($qossettings{'RED_DEV'} eq $classline[0]) { $qossettings{'DEVICE'} = $classline[0]; $qossettings{'CLASS'} = $classline[1]; $qossettings{'PRIO'} = $classline[2]; $qossettings{'RATE'} = $classline[3]; $qossettings{'CEIL'} = $classline[4]; $qossettings{'BURST'} = $classline[5]; $qossettings{'CBURST'} = $classline[6]; print "\ttc class add dev $qossettings{'DEVICE'} parent 1:1 classid 1:$qossettings{'CLASS'} htb rate $qossettings{'RATE'}kbit ceil $qossettings{'CEIL'}kbit prio $qossettings{'PRIO'} "; if (($qossettings{'BURST'} ne '') && ($qossettings{'BURST'} ne 0)) { print "burst $qossettings{'BURST'}k "; } if (($qossettings{'CBURST'} ne '') && ($qossettings{'CBURST'} ne 0)) { print "cburst $qossettings{'CBURST'}k"; } print "\n"; } } print "\n\t### ATTACH QDISC TO LEAF CLASSES\n"; foreach $classentry (sort @classes) { @classline = split( /\;/, $classentry ); if ($qossettings{'RED_DEV'} eq $classline[0]) { $qossettings{'DEVICE'} = $classline[0]; $qossettings{'CLASS'} = $classline[1]; print "\ttc qdisc add dev $qossettings{'DEVICE'} parent 1:$qossettings{'CLASS'} handle $qossettings{'CLASS'}: cake @cake_options\n"; } } print "\n\t### FILTER TRAFFIC INTO CLASSES\n"; foreach $classentry (sort @classes) { @classline = split( /\;/, $classentry ); if ($qossettings{'RED_DEV'} eq $classline[0]) { $qossettings{'DEVICE'} = $classline[0]; $qossettings{'CLASS'} = $classline[1]; print "\ttc filter add dev $qossettings{'DEVICE'} parent 1:0 prio 0 protocol ip"; printf(" u32 match mark 0x%x 0x%x flowid 1:%d\n", ($qossettings{'CLASS'} << $QOS_OUT_SHIFT), $QOS_OUT_MASK, $qossettings{'CLASS'}); } } print </dev/null 2>&1 tc qdisc add dev $qossettings{'RED_DEV'} handle ffff: ingress ### BRING UP $qossettings{'IMQ_DEV'} if [ ! -d "/sys/class/net/$qossettings{'IMQ_DEV'}" ]; then ip link add name $qossettings{'IMQ_DEV'} type ifb fi ip link set $qossettings{'IMQ_DEV'} up ### Pass IPSec traffic without redirect tc filter add dev $qossettings{'RED_DEV'} parent ffff: prio 1 protocol all basic \\ match "ipt(-m policy --pol ipsec --dir in)" \\ action pass ### Restore connmark and send rest of the traffic to $qossettings{'IMQ_DEV'} tc filter add dev $qossettings{'RED_DEV'} parent ffff: prio 2 protocol all u32 \\ match u32 0 0 \\ action connmark \\ action mirred egress redirect dev $qossettings{'IMQ_DEV'} ### ADD HTB QDISC FOR $qossettings{'IMQ_DEV'} tc qdisc del dev $qossettings{'IMQ_DEV'} root >/dev/null 2>&1 tc qdisc add dev $qossettings{'IMQ_DEV'} root handle 2: htb default $qossettings{'DEFCLASS_INC'} ### MAIN RATE LIMIT tc class add dev $qossettings{'IMQ_DEV'} parent 2: classid 2:1 htb rate $qossettings{'INC_SPD'}kbit ### CLASSES FOR $qossettings{'IMQ_DEV'} END ; foreach $classentry (sort @classes) { @classline = split( /\;/, $classentry ); if ($qossettings{'IMQ_DEV'} eq $classline[0]) { $qossettings{'DEVICE'} = $classline[0]; $qossettings{'CLASS'} = $classline[1]; $qossettings{'PRIO'} = $classline[2]; $qossettings{'RATE'} = $classline[3]; $qossettings{'CEIL'} = $classline[4]; $qossettings{'BURST'} = $classline[5]; $qossettings{'CBURST'} = $classline[6]; print "\ttc class add dev $qossettings{'DEVICE'} parent 2:1 classid 2:$qossettings{'CLASS'} htb rate $qossettings{'RATE'}kbit ceil $qossettings{'CEIL'}kbit prio $qossettings{'PRIO'} "; if (($qossettings{'BURST'} ne '') && ($qossettings{'BURST'} ne 0)) { print "burst $qossettings{'BURST'}k "; } if (($qossettings{'CBURST'} ne '') && ($qossettings{'CBURST'} ne 0)) { print "cburst $qossettings{'CBURST'}k"; } print "\n"; } } print "\n\t### ATTACH QDISC TO LEAF CLASSES\n"; foreach $classentry (sort @classes) { @classline = split( /\;/, $classentry ); if ($qossettings{'IMQ_DEV'} eq $classline[0]) { $qossettings{'DEVICE'} = $classline[0]; $qossettings{'CLASS'} = $classline[1]; print "\ttc qdisc add dev $qossettings{'DEVICE'} parent 2:$qossettings{'CLASS'} handle $qossettings{'CLASS'}: cake @cake_options\n"; } } print "\n\t### FILTER TRAFFIC INTO CLASSES\n"; foreach $classentry (sort @classes) { @classline = split( /\;/, $classentry ); if ($qossettings{'IMQ_DEV'} eq $classline[0]) { $qossettings{'DEVICE'} = $classline[0]; $qossettings{'CLASS'} = $classline[1]; print "\ttc filter add dev $qossettings{'DEVICE'} parent 2:0 prio 0 protocol ip"; printf(" u32 match mark 0x%x 0x%x flowid 2:%d\n", ($qossettings{'CLASS'} << $QOS_INC_SHIFT), $QOS_INC_MASK, $qossettings{'CLASS'}); } } print </dev/null 2>&1 /usr/local/bin/qosd $qossettings{'IMQ_DEV'} >/dev/null 2>&1 for i in \$(ls \$RRDLOG/class_*.rrd); do rrdtool update \$i \$(date +%s): 2>/dev/null done echo "Quality of Service was successfully started!" exit 0 ;; clear|stop) ### RESET EVERYTHING TO A KNOWN STATE killall qosd >/dev/null 2>&1 # DELETE QDISCS tc qdisc del dev $qossettings{'RED_DEV'} root >/dev/null 2>&1 tc qdisc del dev $qossettings{'RED_DEV'} ingress >/dev/null 2>&1 INTERFACE="$qossettings{'RED_DEV'}" ACTION="add" /lib/udev/network-aqm &>/dev/null # STOP IMQ-DEVICE ip link set $qossettings{'IMQ_DEV'} down >/dev/null 2>&1 ip link del $qossettings{'IMQ_DEV'} >/dev/null 2>&1 # REMOVE & FLUSH CHAINS iptables -t mangle --delete POSTROUTING -o $qossettings{'RED_DEV'} -j QOS-OUT >/dev/null 2>&1 iptables -t mangle --delete PREROUTING -i $qossettings{'RED_DEV'} -j QOS-INC >/dev/null 2>&1 iptables -t mangle --flush QOS-OUT >/dev/null 2>&1 iptables -t mangle --delete-chain QOS-OUT >/dev/null 2>&1 iptables -t mangle --flush QOS-INC >/dev/null 2>&1 iptables -t mangle --delete-chain QOS-INC >/dev/null 2>&1 for i in \$(ls \$RRDLOG/class_*.rrd); do rrdtool update \$i \$(date +%s): done echo "Quality of Service was successfully cleared!" ;; gen|generate) echo -n "Generating the QoS-Scripts..." /usr/bin/perl /var/ipfire/qos/bin/makeqosscripts.pl > /var/ipfire/qos/bin/qos.sh echo ".Done!" exit 0 ;; restart) ### FIRST CLEAR EVERYTHING \$0 clear ### THEN START \$0 start ;; esac ### EOF END ; ############################################################################################################################ ############################################################################################################################