-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathsupershaper.init
executable file
·338 lines (283 loc) · 12 KB
/
supershaper.init
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
#!/bin/bash
### BEGIN INIT INFO
# Provides: supershaper
# Required-Start: $remote_fs $syslog $network
# Required-Stop: $remote_fs $syslog $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: traffic shaping rules for DSL
# Description: traffic shaping rules for DSL
### END INIT INFO
##############################################################################
#
# SuperShaper-SOHO 2.0
#
# Bandwidth shaper for small/home office DSL connection.
#
# Copyright (C) 2004-2017 Robin Smidsrød <robin@smidsrod.no>
#
# License details and more available at:
# https://github.com/robinsmidsrod/SuperShaper-SOHO
#
# Contact information available at:
# http://robin.smidsrod.no/contact/
#
# This script is designed to shape your upstream bandwidth to
# minimize latency for interactive applications like SSH and making
# sure P2P applications doesn't saturate your upstream. Standard surfing/mail
# software is also given priority over P2P to make them snappy.
# Typical VoIP traffic (SIP/RTP/Skype) is given priority to make sure IP
# telephony doesn't suffer even on a very congested link.
#
# Ingress (inbound) policing is not set up at all, as it is questionable how
# well it works. Only egress (outbound) shaping, which is known to be effective, is
# set up.
#
# This script needs iproute2 (tc) and HTB/FQ_CODEL Linux kernel netfilter
# schedulers. The fq_codel scheduler was shipped with Linux kernel and
# iproute2 3.6, but is most effective with kernels from 3.12 onwards. See
# https://www.bufferbloat.net/projects/codel/wiki/ for more details. The
# HTB scheduler has been part of Linux since the 2.x versions, so no current
# systems should miss it. If you don't have access to fq_codel it is viable
# to replace it with the SFQ scheduler.
#
# The TC filter howto can be found here: http://lartc.org/howto/lartc.qdisc.filters.html
# Man page for u32 classifier can be found here: http://man7.org/linux/man-pages/man8/tc-u32.8.html
#
##############################################################################
# Change these values to reflect your own setup. Make sure to comment out
# filter commands in the advanced section if you don't use all features
# mentioned below.
# Your outbound interface
DEV=ppp0
# Your downstream capacity in kilobits/second
# Not currently used for anything
DOWNLOAD_BW=24490 # 24.5Mbps, measured 2017-08-31
# Your upstream capacity in kilobits/second
# Run speedtest.net while pinging upstream first hop and look at max latency
# and packet loss summary after test is complete
UPLINK_BW=3422 # 3.4Mbps, measured 2017-08-31
# DSL modems usually have large queues that break latency. This phenomenon
# is called "bufferbloat". Set this value high as your DSL modem can
# handle without queuing packets itself. The value is in percent. I
# usually saturate the upstream with traffic/uploads and use iptraf to
# measure the outbound traffic on the interface to determine when the
# shaping takes effect. If iptraf reports higher bandwidth than your
# calculated bandwidth (see UPLINK below) you modem is probably still
# queuing packets. This can only be set by trial an error, but 90% is
# probably a good ballpark number.
UPLINK_PERCENT=90
# Skype normally uses a random UDP/TCP port, but specify it manually to be
# able to control it better
PORT_SKYPE=15000
# Additional BitTorrent port (the standard BitTorrent port is already defined)
PORT_BT=50000
# This is the source port for the internal OpenVPN server
PORT_OPENVPN=1194
# IP address where your work VPN client traffic goes to
WORK_VPN_IP=1.2.3.4
# IP address where your Lync (Skype for Business) traffic goes to.
# You can (usually) get hold of this information by holding Ctrl down while
# right-clicking the Lync tray icon, then you'll find an option called
# "Configuration information". You might also need to check for established
# connections using the "conntrack -L" command while doing a "Check call
# quality" action in Lync. That might indicate an additional IP address.
# If so you might need to add another IP in a separate environment variable
# and add another entry in the advanced section.
LYNC_IP=1.2.3.5
#LYNC_IP2=1.2.3.6
# The IP address your cloud backup traffic goes to
CLOUD_BACKUP_IP=74.126.144.105 # SpiderOakOne
# Set full path to TC command, unless it's in PATH
TC=tc
# Where to store flow labels, accessible for other tools
FLOWS_FILENAME="/run/tc-flows.csv"
##############################################################################
######## Nothing to change below this line unless you're adventurous #########
##############################################################################
# Calculate actual max bandwidth
UPLINK=$((UPLINK_PERCENT*UPLINK_BW/100))
# Which qdisc to use for HFSC leaves
# Turns out that the old sfq seems to work better than fq_codel in
# conjunction with HFSC Try out both and decide for yourself
LEAF_QDISC="sfq divisor 65536 headdrop"
#LEAF_QDISC="fq_codel noecn"
filter_prio=1
function filter_for_flow {
flowid="$1"; shift
$TC filter add dev $DEV parent 1: protocol ip prio $((filter_prio++)) u32 "$@" flowid "1:$flowid"
}
used_bw_percent=0
function define_ls_flow {
flowid="$1"; min_bw_percent="$2"; label="$3"; shift 3
min_bw=$((min_bw_percent*UPLINK/100))
$TC class add dev $DEV parent 1:1 classid "1:$flowid" hfsc ls m2 "${min_bw}kbit"
$TC qdisc add dev $DEV parent "1:$flowid" handle "$flowid:" $LEAF_QDISC
used_bw_percent=$((used_bw_percent+min_bw_percent))
printf "Flow 1:$flowid allocates a minimum rate of %4d Kbps (%2d%%) - %s\n" $min_bw $min_bw_percent "$label"
printf "$DEV|hfsc|1:$flowid|$label\n" >> "$FLOWS_FILENAME"
printf "$DEV|sfq|$flowid:|$label\n" >> "$FLOWS_FILENAME"
}
function start_me {
stop_me quiet # Remove existing flows and filters
printf "Turning on packet shaping on $DEV at rate ${UPLINK} Kbps\n"
################### FLOW DEFINITIONS ###################
# Add root qdisc
$TC qdisc add dev $DEV root handle 1: hfsc default 50
# Add main class, setting interface rate limit (your upstream max bandwidth)
$TC class add dev $DEV parent 1: classid 1:1 hfsc ls m2 "${UPLINK}kbit" ul m2 "${UPLINK}kbit"
printf "$DEV|hfsc|1:1|Main\n" >> "$FLOWS_FILENAME"
# define_ls_flow <flowid> <min_bw_percent> <label>
# min_bw_percent is how much bandwidth (in percent) to use for each flow
# if link is fully saturated. Only use integers. The numbers should
# add up to exactly 100. Definition order doesn't matter, but they are
# defined here in terms of how I mentally think of their latency
# priorities.
define_ls_flow 10 10 "TCP/ACK (pkt len < 64)"
define_ls_flow 11 1 "ICMP (pkt len < 128)"
define_ls_flow 12 4 "DNS (pkt len < 128)"
define_ls_flow 13 10 "Small packets (len < 128)" # SSH interactive traffic hits mostly this one
define_ls_flow 14 1 "Small packets (len < 256)" # Some SSH interactive traffic here as well
define_ls_flow 20 1 "VoIP (SIP)"
define_ls_flow 21 3 "VoIP (RTP)"
define_ls_flow 22 3 "VoIP (Skype)" # 100Kbps audio only, 1.5Mbps with HD video
define_ls_flow 23 5 "VoIP (Lync)" # Skype for Business, 160Kbps audio only, 1.66Mbps with HD video
define_ls_flow 30 11 "VPN"
define_ls_flow 40 9 "SMTP"
define_ls_flow 41 9 "IMAP/POP3"
define_ls_flow 45 10 "HTTP (browsing)"
define_ls_flow 48 9 "FTP"
define_ls_flow 50 9 "default" # unclassified traffic
define_ls_flow 51 1 "HTTP reverse proxy"
define_ls_flow 52 1 "OpenVPN server"
define_ls_flow 60 1 "Usenet"
define_ls_flow 61 1 "BitTorrent"
define_ls_flow 70 1 "Cloud backup" # SpiderOakONE
printf "All flows combined use %d%%.\n" $used_bw_percent
################### FLOW FILTERS ###################
# Remember that filters for flows are defined in order of how they
# should match IP packet data. It's crucial that you match on very
# narrow terms first and leave the broad matches for last.
# Cloud backup
filter_for_flow 70 match ip dst $CLOUD_BACKUP_IP
# Skype for Business / Lync
filter_for_flow 23 match ip dst $LYNC_IP
#filter_for_flow 23 match ip dst $LYNC_IP2
# VPN
filter_for_flow 30 match ip dst $WORK_VPN_IP
# Usenet (with and without SSL)
filter_for_flow 60 match ip dport 119 0xffff
filter_for_flow 60 match ip dport 563 0xffff
# BitTorrent uploads
filter_for_flow 61 match ip sport 6881 0xffff
filter_for_flow 61 match ip sport $PORT_BT 0xffff
# TCP/ACK (small packets)
# IP protocol == 6
# IP header length == 5
# IP packet total length < 64
# TCP flags == 0x10 (only ACK bit set)
filter_for_flow 10 \
match ip protocol 6 0xff \
match u8 5 0x0f at 0 \
match u16 0x0000 0xffc0 at 2 \
match u8 0x10 0xff at 33
# ICMP (small packets)
# IP protocol == ICMP
# IP packet total length < 128
filter_for_flow 11 \
match ip protocol 1 0xff \
match u16 0x0000 0xff80 at 2
# DNS (small packets)
# IP dst port == 53
# IP packet total length < 128
filter_for_flow 12 \
match ip dport 53 0xffff \
match u16 0x0000 0xff80 at 2
# VoIP (SIP packets)
filter_for_flow 20 match ip sport 5060 0xffff
filter_for_flow 20 match ip dport 5060 0xffff
filter_for_flow 20 match ip sport 5061 0xffff # With TLS
filter_for_flow 20 match ip dport 5061 0xffff # With TLS
# VoIP (RTP data)
filter_for_flow 21 match ip sport 16384 0xffff
# Skype VoIP (UDP/TCP data)
filter_for_flow 22 match ip sport $PORT_SKYPE 0xffff
# SMTP (with and without SSL)
filter_for_flow 40 match ip dport 25 0xffff
filter_for_flow 40 match ip dport 465 0xffff
filter_for_flow 40 match ip dport 587 0xffff
# IMAP (with and without SSL)
filter_for_flow 41 match ip dport 143 0xffff
filter_for_flow 41 match ip dport 993 0xffff
# POP3 (with and without SSL)
filter_for_flow 41 match ip dport 110 0xffff
filter_for_flow 41 match ip dport 995 0xffff
# HTTP (browsing) (with and without SSL)
filter_for_flow 45 match ip dport 80 0xffff
filter_for_flow 45 match ip dport 443 0xffff
# FTP (with and without SSL)
filter_for_flow 48 match ip dport 20 0xffff
filter_for_flow 48 match ip dport 21 0xffff
filter_for_flow 48 match ip dport 989 0xffff
filter_for_flow 48 match ip dport 990 0xffff
# HTTP/HTTPS reverse proxy
filter_for_flow 51 match ip sport 80 0xffff
filter_for_flow 51 match ip sport 443 0xffff
# OpenVPN server
filter_for_flow 52 match ip sport $PORT_OPENVPN 0xffff
# NB: These filters should be last because they match on very broad terms
# Small packets < 128 bytes
# IP packet total length < 128
filter_for_flow 13 \
match u16 0x0000 0xff80 at 2
# Small packets < 256 bytes
# IP packet total length < 256
filter_for_flow 14 \
match u16 0x0000 0xff00 at 2
}
function stop_me {
# Remove existing qdisc
active_qdisc=$(tc qdisc show dev $DEV| head -n 1 | cut -d" " -f 2)
if [ -n "$active_qdisc" -a "$active_qdisc" = "hfsc" ]; then
if [ -z "$1" -o "$1" != "quiet" ]; then
printf "Turning off packet shaping on $DEV\n"
fi
$TC qdisc del dev $DEV root 2>&1 >/dev/null
fi
# Remove existing flows file if it exists
[ -e "$FLOWS_FILENAME" ] && rm -f "$FLOWS_FILENAME"
}
function status_me {
# Report settings
printf "************************* QDISC ******************************\n"
$TC qdisc show dev $DEV
printf "************************* CLASS ******************************\n"
$TC -s class show dev $DEV | grep -v 'tokens:' | grep -v 'lended:'
}
function filter_me {
# Report filter settings
printf "************************* FILTER *****************************\n"
$TC -p filter show dev $DEV
}
case "$1" in
start)
start_me
;;
stop)
stop_me
;;
restart)
stop_me
start_me
;;
status)
status_me
;;
filter)
filter_me
;;
*)
printf "Usage: $0 {start|stop|restart|status|filter}\n" >&2
exit 1
esac
exit 0