logo
PolskiPL Flag EnglishUK Flag Dynamic Traffic Shaper

Introduction

Firstly, let's introduce the most important assumes. These assumes are about network interfaces and internet providers uplinks. These are the same as in documentation, with second internet uplink connected to eth2 interface.

So, to be completely informed. We have router with 3 interfaces. First uplink is connected to eth0 interface, LAN network is connected to eth1 interface, and second uplink is connected to eth2. Public address of first uplink is 198.51.100.100/24, public address of second uplink is 203.0.113.100/24, and LAN side address is 192.168.0.1/24. LAN network addressing is 192.168.0.0/24.

Both uplinks are asymmetric with 8000kb/s downstream rate, 500kb/s upstream rate and 10000kb/s downstream rate, 600kb/s upstream rate.

There are many ways to use load balancing on two uplinks. In this scenario we use first uplink as default and second for http and e-mail traffic only. Both http and e-mail don't generate static traffic. Thanks to that, it's excellent to share uplink throughput between many hosts. Also using as high as possible of both downstream and upstream is a goal.

Routing

Create script, e.g.: /usr/local/sbin/routing.sh, and make it executable. This script is for reloading configuration of routing, packets marking, NAT, and NiceShaper starting.

Let's execute command written below:

FILEPATH="/usr/local/sbin/routing.sh"
touch ${FILEPATH}
chown root:root ${FILEPATH}
chmod 750 ${FILEPATH}
This script should be executed automatically with OS starting. It's ease to achieve this by creating some init script or putting path to /etc/rc.local.

After executing this script, all of TCP packets with destination ports equal to one of these from isp2_ports_tcp will be marked with 0x2 value. Thanks to that, all of such packets will be routed by second uplink and NiceShaper will be able to recognize and control them by certain sections.

Below is script content to be pasted to your file. Remember to edit configuration section.

#!/bin/sh

# === Configuration ===

wan1_iface="eth0"
wan1_net="198.51.100.0/24"
wan1_ip="198.51.100.100"
wan1_gw="198.51.100.2"

lan_iface="eth1"
lan_net="192.168.0.0/24"

wan2_iface="eth2"
wan2_net="203.0.113.0/24"
wan2_ip="203.0.113.100"
wan2_gw="203.0.113.2"

isp2_ports_tcp="80,443,25,465,143,993,110,995"

# === Operating System preparation ===

IP=`which ip`
IPT=`which iptables`
NS=`which niceshaper`
ECHO=`which echo`

if [ -z "$IP" ]; then
echo "Missing ip binary (iproute)"
exit 255
fi

if [ -z "$IPT" ]; then
echo "Missing iptables binary"
exit 255
fi

if [ -z "$NS" ]; then
echo "Missing niceshaper binary"
exit 255
fi

if [ -z "$ECHO" ]; then
echo "Missing echo binary"
exit 255
fi

$ECHO 1 > /proc/sys/net/ipv4/ip_forward
$ECHO 0 > /proc/sys/net/ipv4/conf/all/rp_filter

# === NiceShaper ===

$ECHO "Stopping NiceShaper"

$NS stop

# === Routing ===

$ECHO "Routing - Cleaning"

$IP route flush table 241 2>/dev/null
$IP route flush table 242 2>/dev/null
$IP rule del fwmark 0x1 table 241 2>/dev/null
$IP rule del fwmark 0x2 table 242 2>/dev/null

$ECHO "Routing - Table 241"

$IP route add ${wan1_net} dev ${wan1_iface} table 241 # Local route
$IP route add ${wan2_net} dev ${wan2_iface} table 241 # Local route
$IP route add ${lan_net} dev ${lan_iface} table 241 # Local route
$IP route add default via ${wan1_gw} table 241 # Default route through the uplink #1.

$ECHO "Routing - Table 242"

$IP route add ${wan1_net} dev ${wan1_iface} table 242 # Local route
$IP route add ${wan2_net} dev ${wan2_iface} table 242 # Local route
$IP route add ${lan_net} dev ${lan_iface} table 242 # Local route
$IP route add default via ${wan2_gw} table 242 # Default route through the uplink #2

$ECHO "Routing - Rules"

$IP rule add fwmark 0x1 table 241
$IP rule add fwmark 0x2 table 242

# === Packets marking ===

$ECHO "Creating iptables filters - packets marking"

$IPT -t mangle -F PREROUTING 2>/dev/null

$IPT -t mangle -F routemark 2>/dev/null
$IPT -t mangle -X routemark 2>/dev/null
$IPT -t mangle -N routemark

$IPT -t mangle -A routemark -i ${wan1_iface} -j MARK --set-mark 0x1
$IPT -t mangle -A routemark -i ${wan2_iface} -j MARK --set-mark 0x2

$IPT -t mangle -A routemark -i ${lan_iface} -p tcp -m multiport --dports ${isp2_ports_tcp} -j MARK --set-mark 0x2

$IPT -t mangle -A routemark -i ${lan_iface} -m mark ! --mark 0x2 -j MARK --set-mark 0x1

$IPT -t mangle -A routemark -j CONNMARK --save-mark

$IPT -t mangle -A PREROUTING -m state --state ESTABLISHED,RELATED -j CONNMARK --restore-mark
$IPT -t mangle -A PREROUTING -m state --state NEW -j routemark

# === NAT ===

$ECHO "Creating iptables filters - NAT"

$IPT -t nat -F POSTROUTING
$IPT -t nat -A POSTROUTING -o ${wan1_iface} -s ${lan_net} -j SNAT --to ${wan1_ip}
$IPT -t nat -A POSTROUTING -o ${wan2_iface} -s ${lan_net} -j SNAT --to ${wan2_ip}

# === NiceShaper ===

$ECHO "Starting NiceShaper"

$NS start

NiceShaper configuration

Minimal content of config.conf file:
  • <global>
    • run dl1 ul1 dl2 ul2
    • mark-on-ifaces eth0 eth1 eth2
    • local-subnets 192.168.0.0/24
  • <dl1>
    • section speed 8000kb/s
    • section shape 7200kb/s
    • mode download
    • reload 3s
    • low 256kb/s
    • ceil 4000kb/s
  • <ul1>
    • section speed 500kb/s
    • section shape 450kb/s
    • mode upload
    • reload 1s
    • low 64kb/s
    • ceil 256kb/s
  • <dl2>
    • section speed 10000kb/s
    • section shape 9000kb/s
    • mode download
    • reload 3s
    • low 256kb/s
    • ceil 5000kb/s
  • <ul2>
    • section speed 600kb/s
    • section shape 550kb/s
    • mode upload
    • reload 1s
    • low 64kb/s
    • ceil 256kb/s
If we are talking about scenario with single uplink and NAT, we need packets marking on outgoing interface only. But in multiple uplinks scenarios we need packets marking on all of the interfaces. It's important to figure out by which uplink the packet reach the network.

Example classes

This is a complete set of classes for single host.
  • class dl1 eth1 pc10
  • match dstip 192.168.0.10 mark 0x1
  • class dl2 eth1 pc10
  • match dstip 192.168.0.10 mark 0x2
  • class ul1 eth0 pc10
  • match srcip 192.168.0.10
  • class ul2 eth2 pc10
  • match srcip 192.168.0.10
First two classes are responsible for download. Filters classify packets based on destination address and virtual mark value. This mark value changes depending on source uplink.

Last two classes are responsible for upload. Filters classify packets based on source address and outgoing interface. This interface changes depending on routing.

To summarize how to distinguish by which uplink the packets are routed. In the case of download, we use packet mark value, as outgoing interface is always the same (it's the LAN interface). In the case of upload, it's proper and comfortable to use outgoing interface. In this case, we don't need to explicitly indicate interface as it is the class interface.

Now, you should proceed to duplicate this set of classes for each host in network.

To simplify and compact the classes file, it's useful to use macro. The proposed one here is foreach-pair macro, which generates a copy of this set of classes for each defined "name - last IP octed" pair.

  • {foreach-pair pc10 10, pc11 11, pc12 12}
  • class dl1 eth1 %
  • match dstip 192.168.0.$ mark 0x1
  • class dl2 eth1 %
  • match dstip 192.168.0.$ mark 0x2
  • class ul1 eth0 %
  • match srcip 192.168.0.$
  • class ul2 eth2 %
  • match srcip 192.168.0.$
  • {/}