Squid Web Cache Wiki

Squid Web Cache 文档

🔗 功能:TPROXY v4.1+ 支持

🔗 详细信息

支持 TPROXY v4.1,实现完整的 IPv4 和 IPv6 HTTP 透明拦截。

此功能由 Balabit 赞助,由 Laszlo Attilla Toth 和 Amos Jeffries 开发。在 Krisztian Kovacs 和 Nicholas Ritter 的帮助下进行了生产测试和调试。

WCCPv2 配置源自 Steven Wilton 和 Adrian Chadd 的测试。与旧版 TPROXY 相比,变化不大。

🔗 最低要求(IPv6 和 IPv4)

  | ------------------------- | ----------------------------------------------------------------------------------- |
| Linux Kernel 2.6.37       | [Official releases page](https://linuxkernel.org.cn/)                                    |
| iptables 1.4.10           | [Official releases page](http://www.netfilter.org/projects/iptables/downloads.html) |
| Squid 3.1                 | [Official releases page](https://squid.org.cn/Versions/)                      |
| libcap-dev or libcap2-dev | any                                                                                 |
| libcap 2.09 or later      | any                                                                                 |

:information_source: 运行时需要 libcap2。编译时需要开发者版本(*-dev)才能与 Squid 编译。

:information_source: 注意:以上版本是针对以下配置的预期工作版本的最低要求。

🔗 Squid 配置

配置构建选项

./configure --enable-linux-netfilter

squid.conf 设置

http_port 3128
http_port 3129 tproxy

:information_source: 注意:TPROXY 需要一个专用的 Squid 端口。TPROXYv4 的工作方式使其与 NAT 拦截、反向代理加速和标准代理流量不兼容。interceptaccel 和相关标志不能与 tproxy 标志在同一个 http_port 上设置。

:information_source: Balabit 文档仍提到使用 tproxy transparent 选项。不要这样做。它仅在短期内用于修复一个现已修复的错误。

🔗 Linux 内核配置

:warning: 需要使用指定的配置选项编译的内核。

    NF_CONNTRACK=m
    NETFILTER_TPROXY=m
    NETFILTER_XT_MATCH_SOCKET=m
    NETFILTER_XT_TARGET_TPROXY=m

目前我们有这个:

🔗 路由配置

还需要配置内核中的路由功能,以启用对进出系统的拦截数据包的正确处理。

# IPv4-only
ip -f inet rule add fwmark 1 lookup 100
ip -f inet route add local default dev eth0 table 100

# IPv6-only
ip -f inet6 rule add fwmark 1 lookup 100
ip -f inet6 route add local default dev eth0 table 100

每个操作系统在您可以在此处执行的操作方面都有不同的安全性和限制。

:warning: 某些系统要求 TPROXY 使用 lo 接口。

:warning: 某些系统要求 TPROXY 使用 ethN 接口。

:warning: 某些系统要求每个接收接口都有自己的唯一表。

:warning: 某些操作系统会阻止将多个接口链接到同一表。当向表中添加第二个 ip -f inet route 时,您会看到一个被拒绝的路由。要删除自定义路由条目,请使用 del 代替 add 重复规则。

每次启动时设置:

echo 1 > /proc/sys/net/ipv4/ip_forward
echo 0 > /proc/sys/net/ipv4/conf/default/rp_filter
echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter
echo 0 > /proc/sys/net/ipv4/conf/eth0/rp_filter

或配置 /etc/sysctl.conf

net.ipv4.ip_forward = 1
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.eth0.rp_filter = 0

:warning: 您的操作系统可能还需要在每个 sysctl.conf 行前面加上关键字 set

:warning: 由于我们正在移除对‘default’和‘all’sysctl 的 RP 过滤,您可能希望将其设置为 1 或 2,分别应用于所有使用 TPROXY 的设备。

🔗 需要注意的一些路由问题

:warning: 具有严格本地主机接口安全边界的系统需要每个接口都有一个单独的“表”条目,以便通过该设备查找数据包。

:x: 在这种情况下,表通常不能使用相同的编号。在实验时,了解如何删除路由表很有用。

:information_source: 上面显示的是 eth0,请根据您的 TPROXY 接口进行更改。

:x: 所需的特定设备因操作系统而异。eth0 似乎最不容易出错。虽然 dev lo 可能是唯一有效的。

:warning: 您的操作系统可能需要在每个 sysctl.conf 行前面加上关键字 set

🔗 iptables 配置

🔗 路由器设备上的 iptables

:information_source: 对于 IPv6,规则是相同的。但需要使用 ip6tables 工具代替 iptables

设置一个 DIVERT 链来标记数据包。

iptables -t mangle -N DIVERT
iptables -t mangle -A DIVERT -j MARK --set-mark 1
iptables -t mangle -A DIVERT -j ACCEPT

使用 DIVERT 防止现有连接两次通过 TPROXY。

iptables  -t mangle -A PREROUTING -p tcp -m socket -j DIVERT

标记所有其他(新)数据包,并使用 TPROXY 将其传递给 Squid。

iptables  -t mangle -A PREROUTING -p tcp --dport 80 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 3129

🔗 桥接设备上的 ebtables

Linux 中的桥接配置使用 ebtables 工具完成。

您还需要遵循设置 Squid 盒作为路由器设备的所有步骤。这些桥接规则是为将数据包从桥接模式移至路由模式而添加的额外步骤。

    ## interface facing clients
    CLIENT_IFACE=eth0

    ## interface facing Internet
    INET_IFACE=eth1


    ebtables -t broute -A BROUTING \
            -i $CLIENT_IFACE -p ipv6 --ip6-proto tcp --ip6-dport 80 \
            -j redirect --redirect-target DROP

    ebtables -t broute -A BROUTING \
            -i $CLIENT_IFACE -p ipv4 --ip-proto tcp --ip-dport 80 \
            -j redirect --redirect-target DROP

    ebtables -t broute -A BROUTING \
            -i $INET_IFACE -p ipv6 --ip6-proto tcp --ip6-sport 80 \
            -j redirect --redirect-target DROP

    ebtables -t broute -A BROUTING \
            -i $INET_IFACE -p ipv4 --ip-proto tcp --ip-sport 80 \
            -j redirect --redirect-target DROP


    if test -d /proc/sys/net/bridge/ ; then
      for i in /proc/sys/net/bridge/*
      do
        echo 0 > $i
      done
      unset i
    fi

:warning: 桥接口还需要配置公共 IP 地址,以便 Squid 在其正常运行流量(DNS、ICMP、TPROXY 失败的请求、对等请求等)中使用。

🔗 绕过 TPROXY 拦截

一如既往,绕过防火墙规则总是一个选项。它们当然需要优先。

如果您不理解如何执行此操作或在绕过规则中写入什么,请查找任何关于 iptables 或 ebtables 的入门指南并了解如何使用它们。

🔗 SELinux 策略调整

在启用了 SELinux 的 Linux 版本上,您还需要调整 SELinux 策略以允许 Squid 使用 TPROXY。默认情况下,Squid 的 SELinux 策略会拒绝 TPROXY 所需的某些操作。您可以通过设置几个 SELinux 布尔值来调整策略以允许这些操作。

setsebool squid_connect_any=yes
setsebool squid_use_tproxy=yes

如果您的 SELinux 策略版本缺少其中任何一个,请参阅故障排除部分以获取替代方法。

🔗 WCCP 配置(仅当您使用 WCCP 时)

作者:Steve Wilton

:information_source: $ROUTERIP 需要替换为 Squid 用来联系 WCCP 路由器的 IP 地址。

🔗 squid.conf

强烈建议为这两个 wccp 服务使用这些定义,否则如果您拥有多个缓存,情况将变得一团糟(特别是,当一个 Web 服务器的名称解析为多个 IP 地址时,您将遇到问题)。

wccp2_router $ROUTERIP
wccp2_forwarding_method gre
wccp2_return_method gre
wccp2_service dynamic 80
wccp2_service_info 80 protocol=tcp flags=src_ip_hash priority=240 ports=80
wccp2_service dynamic 90
wccp2_service_info 90 protocol=tcp flags=dst_ip_hash,ports_source priority=240 ports=80

🔗 路由器配置

在路由器上,您需要确保所有进出客户的流量都将由两个 WCCP 规则处理。我们的实现方式是应用:

例如:

interface GigabitEthernet0/3.100
 description ADSL customers
 encapsulation dot1Q 502
 ip address x.x.x.x y.y.y.y
 ip wccp 80 redirect in
 ip wccp 90 redirect out

interface GigabitEthernet0/3.101
 description Dialup customers
 encapsulation dot1Q 502
 ip address x.x.x.x y.y.y.y
 ip wccp 80 redirect in
 ip wccp 90 redirect out

interface GigabitEthernet0/3.102
 description proxy servers
 encapsulation dot1Q 506
 ip address x.x.x.x y.y.y.y
 ip wccp redirect exclude in

🔗 单个 Squid 在 WCCP 拦截器后面

🔗 WCCP 拦截器后面的 Sibling Squid 集群

当两个 sibling peers 都位于 WCCP 拦截网关之后并使用 TPROXY 来欺骗客户端 IP 时,WCCP 网关会因两个相同的源而感到困惑,并将数据包重定向到错误的 sibling。

现在通过向集群 sibling 的 cache_peer 行添加 no-tproxy 标志来解决此问题。这会在通过集群中的另一个 peer 接收到的请求上禁用 TPROXY 欺骗。

cache_peer ip.of.peer sibling 3128 0 no-tproxy ...

🔗 故障排除

🔗 Squid 未欺骗客户端 IP

可能有几个原因。检查 cache.log 中是否有此处“故障排除”部分列出的类似消息。

:warning: 关于缺少 libcap 的警告似乎在 cache.log 启动之前就已发出。因此,在 Squid 启动时并不总是显示。通过手动确保此依赖项来开始测试此问题。

🔗 停止完全透明:启用所需功能时出错。

在设置高级权限时出现了一些问题。具体是什么,我们目前还不知道。不幸的是,它也没有记录在任何地方。也许您的 syslog 或 /var/log/messages 日志会包含操作系统记录的详细信息。

🔗 停止完全透明:缺少所需功能支持。

libcap 支持似乎缺失。该库需要被构建到 Squid 中,因此在安装了系统相关的包之后需要重新构建。

🔗 commBind:无法将套接字 FD X 绑定到 X.X.X.X:(99)无法分配请求的地址

此错误有多种原因。

当 Squid 配置为 TPROXY 运行时,可能会反复看到此错误。

它也可能仅在启动时出现,原因与其他问题无关:

🔗 流量通过 Squid,但然后超时。

这通常发生在网络设计阻止数据包返回 Squid 时。

🔗 Squid 未直接运行在路由器上的超时问题

:information_source: :warning: 上述配置假设 Squid 运行在路由器上,或与 Internet 有直接连接,无需再次通过捕获路由器。适用于出站和返回流量。

如果您的网络拓扑中使用一个 Squid 盒位于路由器内部,并将数据包传递给 Squid。那么您将需要显式添加一些额外的配置。

WCCPv2 示例是为使用 Cisco 设备的人提供的。对于其他人,我们无法指向确切的路由配置,因为它将取决于您的路由器。但是您将需要找出一些规则来识别 Squid 的出站流量。专用路由器接口、服务组、Squid tcp_outgoing_tos 设置的服务以及 MAC 源在特定情况下都被证明是有用的。基于 IP 地址的规则是唯一保证会失败的。

:information_source: 我们其实不必再说,但这些例外规则必须放在任何捕获 TPROXY/DIVERT 规则之前。

🔗 Squid 作为桥接器或多网卡运行时出现超时

在使用桥接配置或多网卡系统时,需要注意确保默认路由正确,并将数据包路由到 Internet。理想情况下只有一个默认路由,但对于启用路由的桥接器或多网卡系统可能存在多个。

:warning: 已确认一个案例,其中默认路由被操作系统自动设置为仅用于管理桥接器的死端路由/网卡。

🔗 Wccp2 dst_ip_hash 数据包循环

参考上面详细的 wccps_service_info 设置。

第一种方法:

将特定 Web 服务器绑定到特定缓存。

第二种方法:

将特定客户端绑定到特定缓存。

使用 TPROXY 时,必须使用第二种方法。第一种方法存在以下事件序列,从而开始出现问题:

假设一个客户端想要访问 http://some-large-site,他们的 PC 解析该地址并得到 x.x.x.1。

  1. GET 请求发送到网络,Cisco 看到它并对 dst_ip 进行哈希。
  2. 此 IP 的哈希指向缓存 A。
  3. 路由器将请求发送到缓存 A。

此缓存接收 GET 请求并再次对该主机进行 DNS 查找。这次解析为 x.x.x.2。

  1. 缓存将请求发送到 Internet。
  2. 回复从 x.x.x.2 返回,并到达 Cisco。
  3. Cisco 对 src_ip 进行哈希,这恰好映射到缓存 B。
  4. 回复到达缓存 B,而它对此一无所知。糟糕!:x:

🔗 SELinux 策略拒绝

在 Fedora 12 上配置 TPROXY 支持时,使用 Fedora 提供的 Squid,SELinux 最初阻止了 Squid 使用 TPROXY 功能。

快速修复是完全禁用 SELinux,但这通常不被推荐。

在 Squid 部分的 SELinux 策略更新之前,一个更永久的修复方法是创建一个自定义 SELinux 策略模块,允许 Squid 访问其 TPROXY 所需的网络操作。

# Temporarily set eslinux in permissive mode and test..
setenforce 0
service squid start
# Make a request via Squid and verity that it works.
service squid stop
setenforce 1
# build & install selinux module based on the denials seen
grep AVC.*squid /var/log/audit/autdit.log | audit2allow -M squidtproxy
semodule -i squidtproxy.pp

🔗 参考资料

🔗 spoof_client_ip 配置指令(仅从 Squid-3.4 开始存在)

类别:功能

导航:站点搜索站点页面类别🔼 向上