方便菜谱
本章收录了一些“方便菜谱”,希望能够帮你解决实际问题。方便菜谱不能代替理解原理,所以你还是应该着重领会其内在道理。
而且真的不建议你照抄,想一想这是20年前(2021)写下的东西,当初作者又是借鉴其他的案例。
用不同的 SLA 运行多个网站
你有很多种方法实现这个。 Apache 的有些模块可以支持这个功能,但是我们会让你看看 Linux 如何处理这个问题, 并能够提供其它多种服务的。 这些命令都是从 Jamal Hadi 的演示中偷学来的。
比如说我们有两个顾客,需要 http、 ftp 和音频流服务,我们需要向他们出售一定量的带宽。我们在服务器上这么做。
A 顾客应该拥有最多 2Mbps 的带宽, B 顾客则交了 5M 的钱。我们在服务器上分配不同的 IP 地址来区分它们。
ip address add 188.177.166.1 dev eth0
ip address add 188.177.166.2 dev eth0
给服务器赋予那些 IP 地址完全取决于你。 当前所有的守护程序都支持这个特性。
我们首先往 eth0 上附加一个 CBQ 队列规定:
tc qdisc add dev eth0 root handle 1: cbq bandwidth 10Mbit cell 8 avpkt 1000 \
mpu 64
为我们的顾客创建类:
tc class add dev eth0 parent 1:0 classid 1:1 cbq bandwidth 10Mbit rate \
2MBit avpkt 1000 prio 5 bounded isolated allot 1514 weight 1 maxburst 21
tc class add dev eth0 parent 1:0 classid 1:2 cbq bandwidth 10Mbit rate \
5Mbit avpkt 1000 prio 5 bounded isolated allot 1514 weight 1 maxburst 21
然后为我们的客户添加过滤器:
##求助: Why this line, what does it do?, what is a divisor?
##求助: A divisor has something to do with a hash table, and the number of
## buckets - ahu
tc filter add dev eth0 parent 1:0 protocol ip prio 5 handle 1: u32 divisor 1
tc filter add dev eth0 parent 1:0 prio 5 u32 match ip src 188.177.166.1 flowid 1:1
tc filter add dev eth0 parent 1:0 prio 5 u32 match ip src 188.177.166.2 flowid 1:2
做完了。
防护 SYN 洪水攻击
根据 Alexey 的 iproute 文档和许多非正式的 netfilter 方法而设计。如果你使用这
个脚本,请认真调整其中的数值以适应你的网络。
如果你需要保护整个网络,就不要考虑这个脚本了,它最适合于单机使用。
似乎你需要很新版本的 iproute2 工具才能利用 2.4.0 的内核工作。
#! /bin/sh -x
#
# sample script on using the ingress capabilities
# this script shows how one can rate limit incoming SYNs
# Useful for TCP-SYN attack protection. You can use
# IPchains to have more powerful additions to the SYN (eg
# in addition the subnet)
#
# path to various utilities;
# change to reflect yours.
#
TC=/sbin/tc
IP=/sbin/ip
IPTABLES=/sbin/iptables
INDEV=eth2
#
# tag all incoming SYN packets through $INDEV as mark value 1
############################################################
$IPTABLES -A PREROUTING -i
$INDEV -t mangle -p tcp --syn -j MARK --set-mark 1
############################################################
#
# install the ingress qdisc on the ingress interface
############################################################
$TC qdisc add dev $INDEV handle ffff: ingress
############################################################
#
#
# SYN packets are 40 bytes (320 bits) so three SYNs equals
# 960 bits (approximately 1kbit); so we rate limit below
# the incoming SYNs to 3/sec (not very useful really; but
# serves to show the point - JHS
############################################################
$TC filter add dev $INDEV parent ffff: protocol ip prio 50 handle 1 fw \
police rate 1kbit burst 40 mtu 9k drop flowid :1
############################################################
#
echo "---- qdisc parameters Ingress ----------"
$TC qdisc ls dev $INDEV
echo "---- Class parameters Ingress ----------"
$TC class ls dev $INDEV
echo "---- filter parameters Ingress ----------"
$TC filter ls dev $INDEV parent ffff:
# deleting the ingress qdisc
#$TC qdisc del $INDEV ingress
为防止 DDoS 而对 ICMP 限速
最近一段,分布式拒绝服务攻击成了 Internet 上最让人讨厌的东西。通过对你的
网络正确地设置过滤和限速可以避免成为攻击的目标和跳板。
你应该过滤你的网络,禁止非本地 IP 源地址的数据包离开网络,这可以阻止其
它人向 Internet 上发送垃圾包。
限速就象以前所展示的那样。如果忘了,就是这张图:
[Internet] ---<E3、 T3 之类>--- [Linux 路由器] --- [办公室+ISP]
eth1 eth0
我们先进行预备设置:
tc qdisc add dev eth0 root handle 10: cbq bandwidth 10Mbit avpkt 1000
tc class add dev eth0 parent 10:0 classid 10:1 cbq bandwidth 10Mbit rate \
10Mbit allot 1514 prio 5 maxburst 20 avpkt 1000
如果你有一个 100Mbps的网卡,调整这些数据。现在你需要决定允许多大的 ICMP
流量。你可以用 tcpdump 测量段时间, 把结果写入一个文件, 看一看有多少 ICMP
数据包流经网络。别忘了适当延长监测时间!
如果没有条件进行测量,不妨就选择带宽的 5%。设置我们的类:
tc class add dev eth0 parent 10:1 classid 10:100 cbq bandwidth 10Mbit rate \
100Kbit allot 1514 weight 800Kbit prio 5 maxburst 20 avpkt 250 \
bounded
限速为 100Kbps。然后我们设置过滤器把 ICMP 数据包送给这个类:
tc filter add dev eth0 parent 10:0 protocol ip prio 100 u32 match ip protocol 1 0xFF flowid 10:100
为交互流量设置优先权
当有很多上行和下行数据充斥了你的链路,而你正在使用 telnet 或者 ssh 维护一
些系统的话, 情况会很糟。 系通它的数据包会挡住你的按键数据包。 有没有一种方
法,能让我们的交互数据包在大批数据传输中取得优先呢? Linux 可以实现!
像以前一样,我们得处理两个方向的数据流。明显地,这在链路两端都是 Linux
的时候非常有效——虽然其它的 UNIX 也能实现。问问你周围的 Solaris/BSD 大佬们。
标准的 pfifo_fast 调度器有 3 个频道。 0 频道中的数据优先传输,然后才是 1 频
道、 2 频道。关键就在于让我们的交互数据通过 0 频道!
我们改编自马上就要过期的 ipchains HOWTO:
在 IP 头部有 4 个不常使用的 bit,叫做 TOS 位。 它们影响数据包的待遇, 4 个 bit
分别代表“最小延迟”、“最大吞吐”、“最大可靠”和“最小成本”。同时只允许
设置一位。
Rob van Nieuwkerk——ipchains TOS-mangling 代码的作者——这样说:
“最小延迟”对我来说特别重要。我在一个 33k6 的 MODEM 链路后面。 Linux 把数据包区分到 3
个队列中。 我在上行(Linux)路由器上为“ 交互” 数据包打开它。这样我就可以在大批下在数据的
同时得到可接受的交互性能了。
最通常的用发就是为设置 telnet 和 ftp 控制连接设置“最小延迟”,并为 ftp 数据
连接设置“最大吞吐”。在你的上行路由器上如此实现:
iptables -A PREROUTING -t mangle -p tcp --sport telnet \
-j TOS --set-tos Minimize-Delay
iptables -A PREROUTING -t mangle -p tcp --sport ftp \
-j TOS --set-tos Minimize-Delay
iptables -A PREROUTING -t mangle -p tcp --sport ftp-data \
-j TOS --set-tos Maximize-Throughput
现在, 所有从你的 telnet/ftp 主机到达你本机方向的数据流就设置好了。 另外一个
方向的设置似乎应该由你来设置, 比如 telnet、 ssh 等等都应自动在发出的数据包
上做好 TOS 标记。你随时都可以用 netfilter 来实现。在你的本机上:
iptables -A OUTPUT -t mangle -p tcp --dport telnet \
-j TOS --set-tos Minimize-Delay
iptables -A OUTPUT -t mangle -p tcp --dport ftp \
-j TOS --set-tos Minimize-Delay
iptables -A OUTPUT -t mangle -p tcp --dport ftp-data \
-j TOS --set-tos Maximize-Throughput
终极的流量控制:低延迟、高速上/下载
Note: This script has recently been upgraded and previously only worked for Linux clients in your network! So you might want to update if you have Windows machines or Macs in your network and noticed that they were not able to download faster while others were uploading.
我试图打造圣杯:
- 让交互数据包保持较低的延迟时间:
也就是说上载或下载文件不会打扰 SSH/telnet 等。 这是最重要的, 即使是
200ms 的延迟也会感觉很差。 - 上载或下载期间有合理的速率用于网页浏览:
即使 http 属于一种大量数据传输,也不应受其它传输影响太大。 - 保证上载不会影响下载:
上载数据流会影响下载的速率,这是相当普遍的现象。
只要花费一点点带宽就可以实现它们。 之所以上载流、 下载流和 ssh 之间要互相
伤害,是因为像 Cable 或者 DSL Modem 这样的家用设备中的队列太大。
下面一节进一步解释了造成延迟的原因和如何缓解。如果你对魔术的咒语不感兴
趣,完全可以不看它,直接参考脚本那一节。
为什么缺省设置不让人满意
ISP 们知道人们评价他们的时候要看看下载的速度。 除了可用带宽之外, 丢包因
为会严重地牵制 TCP/IP 效率而极大地影响下载速度。大队列有助于改善丢包,
进而提高下载速度。所以 ISP 们都配置成大队列。
然而,大队列会破坏交互性。一次击键行为首先要在上行流队列中排队(可能长
达数秒! )才能到达对端主机。 回显的时候, 数据包还要回来, 所以还要在你 ISP
的下行流队列中排队,你的本端显示器才有显示。
这个 HOWTO 教你如何用多种方法重组和处理队列,但是,并不是所有的队列
配置我们都有权访问。 你的 ISP 的队列肯定是无法配置的。 上行流可能存在于你
的 cable modem 或 DSL 设备中,你也许可以配置,也许不可以配置。绝大多数
不能配置。
那怎么办呢?既然无法控制那些队列,那就除去它们,让数据包在我们的 Linux
路由器内排队。幸运的是,这是可能的。
- 限制上载速率:
把上载速率限制在比可用带宽稍小一些的位置上,于是你的 MODEM 中
就不会形成队列了。也就是说,队列转移到你的 Linux 路由器中了。 - 限制下载速率:
这带点欺骗的味道,因为我们实际上不能控制 Internet 向我们发包的速
率。但我们可以丢掉那些太快到来的数据包,不让他们导致 TCP/IP 的速
率低于我们期望的速率。 因为我们不希望轻易地丢弃数据包, 所以我们要
配置“ burst”来容纳突发传输。
在做完了这些之后, 我们就排除了下行队列(除了偶尔的突发), 并让上行队列存
在于我们的 Linux 路由器中,以便施展 Linux 非凡的能力。
剩下的事情就是保证交互数据包永远排在上行队列的最前面。为了保证上行数据
流不会伤害下行流,我们还要把 ACK 数据包排在队列前面。这就是当发生大批
量数据流的时候,双向传输均受到严重影响的原因。因为下行数据的 ACK 必须
同上行流进行竞争,并在处理过程中被延迟。
为了进一步配置,我们使用一个高质量的 ADSL 连接(荷兰的 xs4all)得出了如下
测量结果:
基准延迟:
round-trip min/avg/max = 14.4/17.1/21.7 ms
不进行流量控制,下载数据:
round-trip min/avg/max = 560.9/573.6/586.4 ms
不进行流量控制,上载数据:
round-trip min/avg/max = 2041.4/2332.1/2427.6 ms
进行流量控制, 220kbit/s 上行:
round-trip min/avg/max = 15.7/51.8/79.9 ms
进行流量控制, 850kbit/s 下行:
round-trip min/avg/max = 20.4/46.9/74.0 ms
上载数据时,下载得到约 80%的带宽。当上行流达到 90%时,延迟一下子增加
到 850 ms,也能说明问题。
这个脚本的期望效果极大地取决于你的实际上行速率。当你满速率上载的时候,
你击键的那个数据包前面总会有一个数据包。这就是你能够达到的上行延迟的下
限——MTU 除以上行速率。典型值会比它稍高一些。要达到更好效果,可以降
低 MTU!
然后是两个版本的脚本一个是使用 Devik 的 HTB,另一个是使用 Linux 内部自带
的 CBQ。都已经过测试,正常工作。
实际的脚本(CBQ)
适用于所有内核。我们在 CBQ 的内部放置 2 个随机公平队列,以保证多个大吞
吐量数据流之间不会互相淹没。
下行流使用带有令牌桶过滤器的 tc 过滤器进行管制。
你可以往脚本中“ tc class add … classid 1:20”那一行添加“ bounded”进行改进。
如果你降低了 MTU,同时也得降低 allot 和 avpkt!
#!/bin/bash
# The Ultimate Setup For Your Internet Connection At Home
#
#
# Set the following values to somewhat less than your actual download
# and uplink speed. In kilobits
DOWNLINK=800
UPLINK=220
DEV=ppp0
# clean existing down- and uplink qdiscs, hide errors
tc qdisc del dev $DEV root 2> /dev/null > /dev/null
tc qdisc del dev $DEV ingress 2> /dev/null > /dev/null
###### uplink
# install root CBQ
tc qdisc add dev $DEV root handle 1: cbq avpkt 1000 bandwidth 10mbit
# shape everything at $UPLINK speed - this prevents huge queues in your
# DSL modem which destroy latency:
# main class
tc class add dev $DEV parent 1: classid 1:1 cbq rate ${UPLINK}kbit \
allot 1500 prio 5 bounded isolated
# high prio class 1:10:
tc class add dev $DEV parent 1:1 classid 1:10 cbq rate ${UPLINK}kbit \
allot 1600 prio 1 avpkt 1000
# bulk and default class 1:20 - gets slightly less traffic,
# and a lower priority:
tc class add dev $DEV parent 1:1 classid 1:20 cbq rate $[9*$UPLINK/10]kbit \
allot 1600 prio 2 avpkt 1000
# both get Stochastic Fairness:
tc qdisc add dev $DEV parent 1:10 handle 10: sfq perturb 10
tc qdisc add dev $DEV parent 1:20 handle 20: sfq perturb 10
# start filters
# TOS Minimum Delay (ssh, NOT scp) in 1:10:
tc filter add dev $DEV parent 1:0 protocol ip prio 10 u32 \
match ip tos 0x10 0xff flowid 1:10
# ICMP (ip protocol 1) in the interactive class 1:10 so we
# can do measurements & impress our friends:
tc filter add dev $DEV parent 1:0 protocol ip prio 11 u32 \
atch ip protocol 1 0xff flowid 1:10
# To speed up downloads while an upload is going on, put ACK packets in
# the interactive class:
tc filter add dev $DEV parent 1: protocol ip prio 12 u32 \
match ip protocol 6 0xff \
match u8 0x05 0x0f at 0 \
match u16 0x0000 0xffc0 at 2 \
match u8 0x10 0xff at 33 \
flowid 1:10
# rest is 'non-interactive' ie 'bulk' and ends up in 1:20
tc filter add dev $DEV parent 1: protocol ip prio 13 u32 \
match ip dst 0.0.0.0/0 flowid 1:20
########## downlink #############
# slow downloads down to somewhat less than the real speed to prevent
# queuing at our ISP. Tune to see how high you can set it.
# ISPs tend to have *huge* queues to make sure big downloads are fast
#
# attach ingress policer:
tc qdisc add dev $DEV handle ffff: ingress
# filter *everything* to it (0.0.0.0/0), drop everything that's
# coming in too fast:
tc filter add dev $DEV parent ffff: protocol ip prio 50 u32 match ip src \
0.0.0.0/0 police rate ${DOWNLINK}kbit burst 10k drop flowid :1
如果你希望这个脚本在 ppp 连接时执行,就把它拷贝成/etc/ppp/ip-up.d。
如果在最后两行报错,请更新你的 tc 工具!
实际的脚本(HTB)
下面的脚本通过 HTB 完成那些功能, 参见相关章节。 你真的值得为它打个补丁!
#!/bin/bash
# The Ultimate Setup For Your Internet Connection At Home
#
#
# Set the following values to somewhat less than your actual download
# and uplink speed. In kilobits
DOWNLINK=800
UPLINK=220
DEV=ppp0
# clean existing down- and uplink qdiscs, hide errors
tc qdisc del dev $DEV root 2> /dev/null > /dev/null
tc qdisc del dev $DEV ingress 2> /dev/null > /dev/null
###### uplink
# install root HTB, point default traffic to 1:20:
tc qdisc add dev $DEV root handle 1: htb default 20
# shape everything at $UPLINK speed - this prevents huge queues in your
# DSL modem which destroy latency:
tc class add dev $DEV parent 1: classid 1:1 htb rate ${UPLINK}kbit burst 6k
# high prio class 1:10:
tc class add dev $DEV parent 1:1 classid 1:10 htb rate ${UPLINK}kbit \
burst 6k prio 1
# bulk & default class 1:20 - gets slightly less traffic,
# and a lower priority:
tc class add dev $DEV parent 1:1 classid 1:20 htb rate $[9*$UPLINK/10]kbit \
burst 6k prio 2
# both get Stochastic Fairness:
tc qdisc add dev $DEV parent 1:10 handle 10: sfq perturb 10
tc qdisc add dev $DEV parent 1:20 handle 20: sfq perturb 10
# TOS Minimum Delay (ssh, NOT scp) in 1:10:
tc filter add dev $DEV parent 1:0 protocol ip prio 10 u32 \
match ip tos 0x10 0xff flowid 1:10
# ICMP (ip protocol 1) in the interactive class 1:10 so we
# can do measurements & impress our friends:
tc filter add dev $DEV parent 1:0 protocol ip prio 10 u32 \
atch ip protocol 1 0xff flowid 1:10
# To speed up downloads while an upload is going on, put ACK packets in
# the interactive class:
tc filter add dev $DEV parent 1: protocol ip prio 10 u32 \
match ip protocol 6 0xff \
match u8 0x05 0x0f at 0 \
match u16 0x0000 0xffc0 at 2 \
match u8 0x10 0xff at 33 \
flowid 1:10
# rest is 'non-interactive' ie 'bulk' and ends up in 1:20
########## downlink #############
# slow downloads down to somewhat less than the real speed to prevent
# queuing at our ISP. Tune to see how high you can set it.
# ISPs tend to have *huge* queues to make sure big downloads are fast
#
# attach ingress policer:
tc qdisc add dev $DEV handle ffff: ingress
# filter *everything* to it (0.0.0.0/0), drop everything that's
# coming in too fast:
tc filter add dev $DEV parent ffff: protocol ip prio 50 u32 match ip src \
0.0.0.0/0 police rate ${DOWNLINK}kbit burst 10k drop flowid :1
如果你希望这个脚本在 ppp 连接时执行,就把它拷贝成/etc/ppp/ip-up.d。
如果在最后两行报错,请更新你的 tc 工具!
为单个主机或子网限速
虽然在我们的 man 和其它地方对于这个问题描述的相当详细,但是这个经常被
问到的问题存在简单的回答,不需要完全地理解流量控制。
这招就三行:
tc qdisc add dev $DEV root handle 1: cbq avpkt 1000 bandwidth 10mbit
tc class add dev $DEV parent 1: classid 1:1 cbq rate 512kbit \
allot 1500 prio 5 bounded isolated
tc filter add dev $DEV parent 1: protocol ip prio 16 u32 \
match ip dst 195.96.96.97 flowid 1:1