15.5. 使用 netfilteriproute2ipchainssquid 实现透明 Web 缓存

本节由来自 Internet for Education (泰国) 的读者 Ram Narula 投稿。

在 Linux 中实现此目的的常用技术可能是使用 ipchains,前提是确保“出站”端口 80 (web) 流量被路由到运行 squid 的服务器。

有 3 种常用方法可以确保“出站”端口 80 流量被路由到运行 squid 的服务器,这里将介绍第 4 种方法。

让网关路由器来完成。

如果你可以告诉你的网关路由器匹配目标端口为 80 的出站数据包,并将它们发送到 squid 服务器的 IP 地址。

但是

这会给路由器带来额外的负载,并且一些商用路由器可能甚至不支持此功能。

使用 4 层交换机。

4 层交换机可以毫无问题地处理这个问题。

但是

这种设备的成本通常非常高。典型的 4 层交换机通常比典型的路由器 + 优秀的 Linux 服务器更贵。

使用缓存服务器作为网络的网关。

你可以强制所有流量都通过缓存服务器。

但是

这相当冒险,因为 Squid 会占用大量 CPU 资源,这可能会导致整体网络性能下降,或者服务器本身可能会崩溃,如果发生这种情况,网络上的任何人都将无法访问互联网。

Linux + NetFilter 路由器。

通过使用 NetFilter,可以实现另一种技术,即使用 NetFilter “标记”目标端口为 80 的数据包,并使用 iproute2 将“标记”的数据包路由到 Squid 服务器。

|----------------|
| Implementation |
|----------------|

 Addresses used
 10.0.0.1 naret (NetFilter server)
 10.0.0.2 silom (Squid server)
 10.0.0.3 donmuang (Router connected to the Internet)
 10.0.0.4 kaosarn (other server on network)
 10.0.0.5 RAS
 10.0.0.0/24 main network
 10.0.0.0/19 total network

|---------------|
|Network diagram|
|---------------|

Internet
|
donmuang
|
------------hub/switch----------
|        |             |       |
naret   silom        kaosarn  RAS etc.
首先,让所有流量都通过 naret,方法是确保它是默认网关,除了 silom。Silom 的默认网关必须是 donmuang (10.0.0.3),否则会产生 Web 流量环路。

(我网络上的所有服务器都将 10.0.0.1 作为默认网关,这是 donmuang 路由器的前一个 IP 地址,所以我所做的是将 donmuang 的 IP 地址更改为 10.0.0.3,并将 naret 的 IP 地址设置为 10.0.0.1)

Silom
-----
-setup squid and ipchains 

在 silom 上设置 Squid 服务器,确保它支持透明缓存/代理,默认端口通常是 3128,因此所有端口 80 的流量都必须本地重定向到端口 3128。这可以通过使用以下 ipchains 命令来完成

silom# ipchains -N allow1
silom# ipchains -A allow1 -p TCP -s 10.0.0.0/19 -d 0/0 80 -j REDIRECT 3128
silom# ipchains -I input -j allow1

或者,用 netfilter 的术语来说
silom# iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 3128

(注意:你可能还有其他条目)

有关设置 Squid 服务器的更多信息,请参考 Squid FAQ 页面:http://squid.nlanr.net)。

确保在此服务器上启用 IP 转发,并且此服务器的默认网关是 donmuang 路由器(不是 naret)。

Naret
-----
-setup iptables and iproute2
-disable icmp REDIRECT messages (if needed)

  1. “标记”目标端口为 80 的数据包,标记值为 2
     
    naret# iptables -A PREROUTING -i eth0 -t mangle -p tcp --dport 80 \
     -j MARK --set-mark 2

  2. 设置 iproute2,使其将“标记”为 2 的数据包路由到 silom
    naret# echo 202 www.out >> /etc/iproute2/rt_tables
    naret# ip rule add fwmark 2 table www.out
    naret# ip route add default via 10.0.0.2 dev eth0 table www.out
    naret# ip route flush cache
    

    如果 donmuang 和 naret 在同一个子网中,那么 naret 不应该发送 icmp REDIRECT 消息。在本例中是这样,因此必须禁用 icmp REDIRECT,方法是
    naret# echo 0 > /proc/sys/net/ipv4/conf/all/send_redirects
    naret# echo 0 > /proc/sys/net/ipv4/conf/default/send_redirects
    naret# echo 0 > /proc/sys/net/ipv4/conf/eth0/send_redirects
    

设置完成,检查配置

On naret:

naret# iptables -t mangle -L
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         
MARK       tcp  --  anywhere             anywhere           tcp dpt:www MARK set 0x2 

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

naret# ip rule ls
0:      from all lookup local 
32765:  from all fwmark        2 lookup www.out 
32766:  from all lookup main 
32767:  from all lookup default 

naret# ip route list table www.out
default via 203.114.224.8 dev eth0 

naret# ip route   
10.0.0.1 dev eth0  scope link 
10.0.0.0/24 dev eth0  proto kernel  scope link  src 10.0.0.1
127.0.0.0/8 dev lo  scope link 
default via 10.0.0.3 dev eth0 

(make sure silom belongs to one of the above lines, in this case
it's the line with 10.0.0.0/24)

|------|
|-DONE-|
|------|

15.5.1. 实施后的流量流向图

|-----------------------------------------|
|Traffic flow diagram after implementation|
|-----------------------------------------|

INTERNET
/\
||
\/
-----------------donmuang router---------------------
/\                                      /\         ||
||                                      ||         ||
||                                      \/         ||
naret                                  silom       ||
*destination port 80 traffic=========>(cache)      ||
/\                                      ||         ||
||                                      \/         \/
\\===================================kaosarn, RAS, etc.

请注意,由于一般出站路径上有一个额外的跃点,因此网络是不对称的。

Here is run down for packet traversing the network from kaosarn
to and from the Internet.

For web/http traffic:
kaosarn http request->naret->silom->donmuang->internet
http replies from Internet->donmuang->silom->kaosarn

For non-web/http requests(eg. telnet):
kaosarn outgoing data->naret->donmuang->internet
incoming data from Internet->donmuang->kaosarn