-
Notifications
You must be signed in to change notification settings - Fork 107
Expand file tree
/
Copy pathtc_ingress_drop.sh
More file actions
executable file
·241 lines (221 loc) · 5.76 KB
/
tc_ingress_drop.sh
File metadata and controls
executable file
·241 lines (221 loc) · 5.76 KB
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
#!/bin/bash
#
# This script drop ingress packets on an interface very early in Linux
# network stack using the TC (Traffic Control) ingress hook.
#
# The primarily purpose is for doing "zoom-in" benchmarking on the
# early RX path of the kernel, to find bottlenecks (e.g. in the memory
# allocator).
#
# TC commands based on input from: Jamal Hadi Salim <[email protected]>
#
# Author: Jesper Dangaard Brouer <[email protected]>
# License: GPLv2
#
basedir=`dirname $0`
source ${basedir}/functions.sh
export TC=/sbin/tc
root_check_run_with_sudo "$@"
function usage() {
echo ""
echo "Usage: $0 [-vfh] --dev ethX"
echo " -d | --dev : (\$DEV) Ingress interface/device (required)"
echo " -v | --verbose : (\$VERBOSE) verbose"
echo " --flush : (\$FLUSH) Only flush (remove TC drop rules)"
echo " --dry-run : (\$DRYRUN) Dry-run only (echo tc commands)"
echo " -s | --stats : (\$STATS) Call TC statistics command"
echo " --port : (\$UDP_PORT) Drop given UDP port"
echo " --ip : (\$IPADDR) Drop given IP-addr"
echo " --icmp : (\$ICMP) Drop all ICMP traffic"
echo ""
}
# Using external program "getopt" to get --long-options
OPTIONS=$(getopt -o vfshd: \
--long verbose,dry-run,flush,stats,icmp,help,dev:,port:,ip: -- "$@")
if (( $? != 0 )); then
usage
err 2 "Error calling getopt"
fi
eval set -- "$OPTIONS"
## --- Parse command line arguments / parameters ---
while true; do
case "$1" in
-d | --dev ) # device
export DEV=$2
info "Ingress device set to: DEV=$DEV" >&2
shift 2
;;
-v | --verbose)
export VERBOSE=yes
# info "Verbose mode: VERBOSE=$VERBOSE" >&2
shift
;;
--dry-run )
export DRYRUN=yes
export VERBOSE=yes
info "Dry-run mode: enable VERBOSE and don't call TC" >&2
shift
;;
-f | --flush )
export FLUSH=yes
shift
;;
-s | --stats )
export STATS_ONLY=yes
shift
;;
--port )
export UDP_PORT=$2
export NO_DEFAULT_DROP="defined"
#info "Port set to: UDP_PORT=$UDP_PORT" >&2
shift 2
;;
--ip )
export IPADDR=$2
export NO_DEFAULT_DROP="defined"
shift 2
;;
--icmp )
export ICMP=yes
export NO_DEFAULT_DROP="defined"
shift 1
;;
-- )
shift
break
;;
-h | --help )
usage;
exit 0
;;
* )
shift
break
;;
esac
done
if [ -z "$DEV" ]; then
usage
err 2 "Please specify TC ingress device"
fi
function tc_ingress_flush()
{
local device="$1"
shift
info "Flush existing ingress qdisc on device :$device"
# Delete existing ingress qdisc - flushes all filters/actions
call_tc_allow_fail qdisc del dev $device ingress
# re-add ingress
call_tc qdisc add dev $device ingress
}
function tc_ingress_drop_icmp()
{
local device="$1"
shift
# Simple rule to drop all icmp
call_tc filter add dev $device parent ffff: prio 4 protocol ip \
u32 match ip protocol 1 0xff flowid 1:1 \
action drop
}
function tc_ingress_drop_udp()
{
local device="$1"
local udp_port="$2"
shift 2
digit='^[0-9]+$'
if ! [[ $udp_port =~ $digit ]] ; then
err 5 "input error UDP port must be a digit"
fi
# Simple rule to drop specific UDP port
#
# WARNING: below rule does not seem to work, because "implicit"
# nexthdr which "udp" depend on is not set.
#
# call_tc filter add dev $device parent ffff: prio 4 protocol ip \
# u32 \
# match ip protocol 17 0xff \
# match udp dst $udp_port 0xffff \
# flowid 1:1 \
# action drop
#
# This works, by manually setting offset for matching UDP header,
# assuming no IP-options thus 20 bytes IP-header
#
# call_tc filter add dev $device parent ffff: prio 4 protocol ip \
# u32 \
# match ip protocol 17 0xff \
# match udp dst $udp_port 0xffff at 21\
# flowid 1:1 \
# action drop
#
# Notice how below match use "ip dport" instead of "udp" per
# recommentation by Jamal. Further reading: man page tc-u32(8) does
# contain a warning about using this.
#
call_tc filter add dev $device parent ffff: prio 4 protocol ip \
u32 \
match ip protocol 17 0xff \
match ip dport $udp_port 0xffff \
flowid 1:1 \
action drop
}
function tc_ingress_drop_all()
{
local device="$1"
shift
# other type of filters if you want to compare instead of above
#
# a) drop all
info "Simply drop all ingress packets on device: $device"
call_tc filter add dev $device parent ffff: prio 2 protocol ip \
u32 match u32 0 0 flowid 1:1 \
action drop
}
function tc_ingress_drop_ip()
{
local device="$1"
local ip="$2"
shift 2
#b) drop dst IP
call_tc filter add dev $device parent ffff: prio 2 protocol ip \
u32 match ip dst $ip flowid 1:1 \
action drop
}
function tc_ingress_stat1()
{
local device="$1"
info "Display filter results with stats:"
call_tc -s filter ls dev $device parent ffff: protocol ip
}
function tc_ingress_stat2()
{
local device="$1"
info "Display filter results with stats:"
call_tc -s actions ls action gact
}
if [[ -n "$FLUSH" ]]; then
info "Clearing TC ingress drop rules"
call_tc_allow_fail qdisc del dev $DEV ingress
exit 0
fi
if [[ -n "$STATS_ONLY" ]]; then
tc_ingress_stat1 $DEV
#tc_ingress_stat2 $DEV
exit 0
fi
# Default always flush existing rules
tc_ingress_flush $DEV
# Apply options selected drop rules
if [[ -n "$UDP_PORT" ]]; then
tc_ingress_drop_udp $DEV "$UDP_PORT"
fi
if [[ -n "$ICMP" ]]; then
tc_ingress_drop_icmp $DEV
fi
if [[ -n "$IPADDR" ]]; then
tc_ingress_drop_ip $DEV $IPADDR
fi
# Only default drop all if not deselected by above options
if [[ -z "$NO_DEFAULT_DROP" ]]; then
tc_ingress_drop_all $DEV
fi