Squid中文权威指南

openkk

贡献于2010-09-06

字数:0 关键词: Squid 代理缓存服务器 缓存服务器 squid中文权威指南

Squid 中文权威指南 2 Squid 中文权威指南 Squid 中文权威指南 3 目目目目录录录录 目录.........................................................................................................................................3 第1章介绍 ...............................................................................................................................6 1.1 Web 缓存 .......................................................................................................................6 1.2 Squid 的简明历史 ........................................................................................................ 6 1.3 硬件和操作系统要求 ..................................................................................................6 1.4 squid 是开源的 .............................................................................................................7 1.5 Squid 的Web 主页 .......................................................................................................7 1.6 获取帮助 ......................................................................................................................7 第2章获取 Squid.....................................................................................................................8 2.1 版本和发布 ..................................................................................................................8 2.2 使用源代码 ..................................................................................................................9 2.4 匿名 CVS...................................................................................................................10 2.5 devel.squid-cache.org..................................................................................................11 第3章编译和安装 .................................................................................................................11 3.2 解开源代码包 ............................................................................................................12 3.3 调整内核 ....................................................................................................................13 3.4 Configure 脚本 ............................................................................................................17 3.5 编译 ............................................................................................................................26 3.6 安装 ............................................................................................................................29 3.7 打补丁 ........................................................................................................................32 3.8 重运行 configure....................................................................................................... 33 第4章快速配置向导 .............................................................................................................35 4.1 squid.conf 语法 ...........................................................................................................35 4.2 User ID........................................................................................................................37 4.3 端口号 ........................................................................................................................38 4.4 日志文件路径 ............................................................................................................39 4.5 访问控制 ....................................................................................................................40 4.6 可见主机名 ................................................................................................................41 4.7 管理联系信息 ............................................................................................................42 4.8 下一步 ........................................................................................................................43 第5章运行 Squid.................................................................................................................. 43 5.1 squid 命令行选项 .......................................................................................................43 5.2 对配置文件查错 ........................................................................................................46 5.3 初始化 cache目录 .....................................................................................................46 5.4 在终端窗口里测试 squid..........................................................................................47 5.5 将squid 作为服务进程运行 .....................................................................................49 5.6 启动脚本 ....................................................................................................................50 5.7 chroot 环境 ..................................................................................................................52 5.8 停止 squid..................................................................................................................53 Squid 中文权威指南 4 5.9 重配置运行中的 squid 进程 .....................................................................................54 5.10 滚动日志文件 ..........................................................................................................56 第6章访问控制 .....................................................................................................................57 6.1 访问控制元素 ............................................................................................................57 6.2 访问控制规则 ............................................................................................................81 6.3 常见用法 ....................................................................................................................89 6.4 测试访问控制 ............................................................................................................96 第7章磁盘缓存基础 .............................................................................................................99 7.1 cache_dir 指令 ............................................................................................................99 7.2 磁盘空间基准 ..........................................................................................................105 7.3 对象大小限制 ..........................................................................................................105 7.4 分配对象到缓存目录 ..............................................................................................106 7.5 置换策略 ..................................................................................................................107 7.6 删除缓存对象 ..........................................................................................................108 7.7 refresh_pattern...........................................................................................................111 第8章高级磁盘缓存主题 ...................................................................................................114 8.1 是否存在磁盘 I/O瓶颈? ......................................................................................114 8.2 文件系统调整选项 ..................................................................................................115 8.3 可选择的文件系统 ..................................................................................................116 8.4 aufs 存储机制 ...........................................................................................................117 8.5 diskd 存储机制 .........................................................................................................120 8.6 coss 存储机制 ...........................................................................................................126 8.7 null 存储机制 ............................................................................................................128 8.8 哪种最适合我? ......................................................................................................129 第9章Cache拦截 ................................................................................................................130 9.1 它如何工作? ...........................................................................................................130 9.2 为何要(或不要)拦截? .......................................................................................134 9.3 网络设备 ..................................................................................................................136 9.4 操作系统配置 ..........................................................................................................151 9.5 配置 Squid............................................................................................................... 157 9.6 调试问题 ..................................................................................................................158 第10 章与其他 Squid 会话 ................................................................................................. 163 10.1 某些术语 ................................................................................................................163 10.2 为何要(或不要)使用堆叠? ........................................................................... 163 10.3 配置 Squid 与邻居通信 ........................................................................................165 10.4 对邻居的请求限制 ................................................................................................169 10.5 网络度量数据库( netdb)...................................................................................173 10.6 Internet Cache协议( ICP)..................................................................................175 10.8 超文本 cache协议( HTCP)..............................................................................185 10.9 Cache数组路由协议 (CARP)................................................................................ 186 10.10 归纳所有 ..............................................................................................................188 10.11 该怎么做? ..........................................................................................................192 第11 章重定向器 .................................................................................................................194 11.1 重定向器接口 ........................................................................................................194 Squid 中文权威指南 5 11.2 重定向器示例 ........................................................................................................196 11.3 重定向器池 ............................................................................................................199 11.4 配置 Squid..............................................................................................................200 11.5 流行的重定向器 ....................................................................................................202 第12 章验证辅助器 .............................................................................................................204 12.1 配置 Squid............................................................................................................. 204 12.2 HTTP基本验证 ......................................................................................................205 12.3 HTTP摘要验证 ......................................................................................................212 12.4 Microsoft NTLM 验证 ............................................................................................215 12.5 外部 ACL...............................................................................................................218 第13 章日志文件 .................................................................................................................222 13.1 cache.log..................................................................................................................222 13.2 access.log................................................................................................................ 225 13.3 store.log...................................................................................................................243 13.4 referer.log................................................................................................................247 13.5 useragent.log........................................................................................................... 249 13.6 swap.state................................................................................................................251 13.7 轮转日志 ................................................................................................................253 13.8 隐私和安全 ............................................................................................................254 第14 章监视 Squid.............................................................................................................. 255 14.1 cache.log 告警 .........................................................................................................255 14.2 Cache管理器 ..........................................................................................................256 14.3 使用 SNMP............................................................................................................257 第15 章服务加速模式 .........................................................................................................257 15.1 概述 ........................................................................................................................257 15.2 配置 Squid............................................................................................................. 259 15.3 令人疑惑之处 ........................................................................................................263 15.4 访问控制 ................................................................................................................265 15.5 内容协商 ................................................................................................................267 15.6 补充 ........................................................................................................................268 第16 章调试和故障处理 .....................................................................................................270 16.1 一些通用问题 ........................................................................................................270 16.2 通过 cache.log 进行调试 ...................................................................................... 274 16.3 Coredump,断点,和堆栈跟踪 ............................................................................283 16.4 重现问题 ................................................................................................................287 16.5 报告 Bug................................................................................................................290 Squid 中文权威指南 6 第第第第1111章章章章介绍 介绍 介绍 介绍 1.1 Web 缓存 这节里需要明白 3个概念: cache 命中在 squid 每次从它的缓存里满 足 HTTP 请求时发生。 cache 命中率,是所 有 HTTP 请求中命中的比例。 Web 缓存典型的 cache命中率在 30%到60%之间。另一个相似的 度量单位叫做字节命中率,描绘了 cache提供服务的数据容量(字节数) 。 cache 丢失在 squid 不能从它的缓存里满足 HTTP请求时发生。cache丢失的理由有很 多 种。 最明显的,当 squid 第一次接受到对特殊资源的请求时, 就是 一个 cache丢失。 类似 的 情况是, squid 会清除缓存以释放空间给新对象。另外的可能是资源不可到达。原始服务器 会指示 cache怎样处理响应。例 如,它会提示数据不能被缓存,或在有限的时间内才被重 复使用,等等。 cache确认保证 squid 不对用户返回过时数据。在重复使用缓存对象时, squid 经常从 原 始服务器确认它。假 如服务器 指 示 squid 的拷贝仍然有效,数 据就发送 出去。 否则, squid 升级它的缓存拷贝,并且转发给客户。 1.2 Squid 的简明历史 对本节感兴趣的读者请阅读英文原文档。 1.3 硬件和操作系统要求 Squid 运行在所有流行的 Unix系统上, 也 可以在 Microsoft Windows 上运行。 尽管 squid 的Windows 支持在不断改进,但也许在 Unix 上容易一些。假如你有一个喜欢的操作系统, 我建议你使用那个。否则,假如你找人推荐,我很喜欢 FreeBSD。 squid 对硬件要求不算高。 内存是最重要的资源。内存短缺会严重影响性能。 磁盘空 间 也是另一个重要因素。更多的磁盘空间意味着更多的缓存目标和更高的命中率。快速 的磁 盘和驱动器也是有利的。 如 果你舍得花钱, SCSI磁盘比 ATA的执行性能好。 当 然快速的 CPU 也是好的,但它并不是提高性能的关键因素。 因为squid 对每个缓存响应使用少数内存,因此在磁 盘空间和内存要求 之间有一定联 系。基本规则是,每 G磁盘空间需要 32M 内存。这样, 512M 内存的系 统,能支持 16G 的 Squid 中文权威指南 7 磁盘缓存。 你 的情况当然会不同。 内 存需求依赖于如下事实: 缓存目标大小, CPU 体系 ( 32 位或 64位) , 同时在线的用户数量,和你使用 的特殊功能。 人们经常问如此问题: “我的网络有 X个用户,需要配备什么样的硬件给 squid?”因为 许多理由, 这样的问题好难回答。特别 的, 很难说 X个用户将产生多少流量。 我告诉人 们 去建立一个有足够磁盘空间, 可 存储 3-7天web 流量数据的系统。 例 如, 假 如你的用户每天 8 小时耗费 1M 流量 (仅仅 HTTP和FTP传 输 ) ,那就 是 每 天 大 约 3.5G。 所以, 我可以说, 每 兆web 传输你需要 10到25G 的磁盘空间。 1.4 squid 是开源的 Squid 是自由软件和合作项目。假如你觉得 squid 有用,请考虑以下面一种或几种方法 来回报该项目: • 1.参与 squid 用户讨论列表,回答问题和帮助新用户。 • 2.测试新版本,报告 bug 或其他问题。 • 3.致力于在线文档和 FAQ。假如你发现错误,将它报告给维护者。 • 4.将你的局部修改提交给开发者。 • 5.对开发者提供财政支持。 • 6.告诉开发者你想要的新功能。 • 7.告诉你的朋友和同学, Squid 非常 Cool。 Squid 是在 GNU 公用许可证( GPL)下发行的自由软件。关于 GPL 的更多信息请见: http://www.gnu.org/licenses/gpl-faq.html 1.5 Squid 的Web 主页 Squid 的主页在 http://www.squid-cache.org 你自己阅读该站点吧。 1.6 获取帮助 1.6.11.6.11.6.11.6.1 FAQFAQFAQFAQ Squid 的FAQ 文档在 http://www.squid-cache.org/Doc/FAQ/FAQ.html,是对新用户的好信 息资源。 Squid 中文权威指南 8 1.6.21.6.21.6.21.6.2 邮件列表 Squid 有三 个邮件列表可用。邮件列表主页在:http://www.squid-cache.org/mailing- lists.html 1.6.2.11.6.2.11.6.2.11.6.2.1 SquidSquidSquidSquid用户 订阅该邮件列表,发邮件到 squid-users-subscribe@squid-cache.org 1.6.2.21.6.2.21.6.2.21.6.2.2 SquidSquidSquidSquid公告 订阅该邮件列表,发邮件到 squid-announce-subscribe@squid-cache.org 1.6.2.31.6.2.31.6.2.31.6.2.3 SquidSquidSquidSquid开发 加入该邮件列表有所限制。它的内容发布在http://www.squid-cache.org/mail- archive/squid-dev/ 1.6.31.6.31.6.31.6.3 职业支持 即付费的支持。职业支持服务提供商列表,请见 http://www.squid- cache.org/Support/services.html 1.7 启动 Squid 请按下面的章节一步一步来吧。 第第第第2222章章章章获取获取获取获取SquidSquidSquidSquid 2.1 版本和发布 Squid 开发者定期发布源代码。每一个发布版有一个版本号,例如 2.5.STABLE4。版本 号的第三部分以 STABLE 或DEVEL(短期开发版本)开头。 Squid 中文权威指南 9 也许你能猜到, DEVEL 版本倾向于拥有更新,更试验性的功能。但也许它们有更多的 bugs。无经验的用户不应该运行 DEVEL 版本。假如你选择运行一个 DEVEL 版本,并且遇 到了问题,请将问题报告给 Squid 维护者。 在一段时间的开发期后, Squid 版本号变为 STABLE。该版本适合于普通用户。 当然, 即使稳定版可能也有一些 bugs。 高 的稳定版本 (例如 STABLE3,STABLE4) 应该 bugs 更少 。 假如你特别关心稳定性,你应该使用这些最近发布版本中的一个。 2.2 使用源代码 为什么你不能 copy 一份预编译的二进制代码到你的系统中, 并 且期望它运行良好呢 ? 主要理由是 squid 的代码需要知道特定操作系统的参数。实 际上,最重要 的参数是打开文 件描述符的最大数量。 Squid 的./configure 脚本在编译之前侦察这些值。假如你获取 一个已 编译的使用某个参数值的 squid 到另一个使用不同参数值的系统中,可能会遇到问题。 另一个理由是许多 squid 功能在编译时必须被激活。 假 如你获取一个别人已编译的 squid 文件,它不包含你所需要的功能,那么你又得再编译一遍。 最后,共享库的问题可能使得在系统之间共享可执行文件困难。共享库在运行时被装 载,如已知的动态链接一样。 squid 在编译时会侦察你系统中的 C库的某些功 能(例如它 们是否被提供, 是否能运行等) 。 尽管库功能不常改变, 但两个不同的系统的 C库之间可 能 有明显的区别。如果两个系统差别太大,就会对 Squid 造成问题。 获取 squid 的源代码是非常容易的。 请 访问 squid 的首页:http://www.squid-cache.org。首 页有链接指向不同的稳定版和开发版。 假如你不在美国, 那么请访问 squid 的众多镜像站 点 中的一个。 镜像站点通常以 "wwwN.CC.squid- cache.org"命名, N是数字, CC 是国家的两 位 代码。例如, www1.au.squid-cache.org 是澳大利亚的镜像站点,在主页上有链 接指向不同 的镜像站点。 每一个 squid 发布版分支(例如 Squid-2.5)有它自己的 HTML页面。该页面有链接指 向源代码,以及与其 他发布版的差别。假如你从一个发布版升级到下一个,你应该下载这 些差别文件,并且打上补丁,请见 3.7章节中的描述。每个版本的发布页描述新功能和重要 的改进,也有链接指向已经修正的 bugs。 如果 web 访问不可行,你能从 ftp://ftp.squid-cache.org 的FTP服务器获取源代码,或者 使用其他 FTP镜像。要获取当前版本,请访问 pub/squid-2/DEVEL 或pub/squid-2/STABLE 目录。 FTP镜像也在许多国家有,你能用同样的国家代码去猜测一些 FTP镜像站点,例如 ftp1.uk.squid-cache.org。 当前的 Squid 发布版本大约 1M 大小。在下载完压缩的打包文件后,你能继续第 3章。 Squid 中文权威指南 10 2.32.32.32.3 预编 译的 二进制 文件 一些 Unix发布版可能预包含了 Squid 的编译版。对Linux 系 统 , 你可 以 找 到 Squid 的RPM 包。通常squid RPM包含在你所买的 Linux 光碟里。Freebsd/Netbsd/OpenBSD 也在它们的 ports 或者 packages 里面包含了 squid。 虽然RPM 或者预编译的 packages 能节省你一些时间,但它们也有一些弊端。就像我 提过的一样,在你开始编译 squid 之前,某些功能必须被激活或禁 止。而你安装的预编译 的包可能不包含你想要的特定功能。 而 且, squid 的./configure 脚本侦察你系统中的特定参 数, 这些在你系统中的参数可能 与编译它的机器的参数不同。 最后,假如你想对 squid 打补丁,你必须等某个人编译更新 的 RPM 或packages,或者 你还得自己找源代码编译。 我强烈建议你从源代码编译 squid,当然怎样选择由得你。 2.4 匿名 CVS 你能匿名访问 squid 的CVS 文件(只读)以保持你的源代码同步更新。使用 CVS 的有 利面是你能轻易获取当前运行版本的补丁。这样就容易发现近来改变了什么。 将这些补丁打到你所运行的版本中,有效的保持你的源代码和官方版本的同步。 CVS 使用树型索引系统, 树 干叫做头分支。 对 Squid 而言, 这 里也是所有的新改变和 新 功能的存放之地。 头 分支通常包含试验性的, 也 许不太稳定的代码。 稳 定的代码通常在其 他 分支上。 为了有效的使用 squid 的匿名 CVS,你首先应知道版本 和分支是 怎样被 标明不同 的。 例如,版本2.5 分支被命名为SQUID_2_5 。具体的发布有长的命名,例如 SQUID_2_5_STABLE4。为了得 到 squid 版本 2.5.STABLE4,请使用 SQUID_2_5_STABLE4 标签;使用 SQUID_2_5得到最近的 2.5分支的代码。 为了使用 squid 匿名 CVS 服务,你首先必须设置 CVSROOT 环境变量: csh% setenv CVSROOT:pserver:anoncvs@cvs.squid-cache.org:/squid 或者,对 Bourne shell 用户: sh$ CVSROOT=:pserver:anoncvs@cvs.squid-cache.org:/squid Squid 中文权威指南 11 sh$ export CVSROOT 然后你就可以登陆到服务器: % cvs login (Logging in to anoncvs@cvs.squid-cache.org) CVS password: 在提示符下,敲入 anoncvs 作为密码。现在你可以用这个命令检查源代码树: % cvs checkout -r SQUID_2_5 -d squid-2.5 squid -r选项指定获取修订标签。 省 略 -r选项你将获得头分支。 -d选项改变存放文件的顶级 目 录名。假如你省略 -d选项,顶级目录名就与模块名字一样。最后的命令行参数( squid)是 要检查的模块名字。 一旦你检查完 squid 源代码树,你能运行 cvs update 命令去升级你的文件,和保持文件 同步。其他命令包括: cvs diff, cvs log, 和cvs annotate。 想获取更多 CVS 知识,请访问: http://www.cvshome.org 2.5 devel.squid-cache.org Squid 的开发者维持一个独立的站点,当前运行在 SourceForge,提供了试验性的 squid 功能。 请 检查它们在 http://devel.squid- cache.org.在这里你能发现许多正在开发的工程, 它 们 还未集成到 squid 的官方源代码里。你能通过 SourceForge的匿名 CVS 服务来访 问这些工 程,或者下载与标准版本不同的差别文件。 第第第第3333章章章章编译 和安 装 编译 和安 装 编译 和安 装 编译 和安 装 Squid 中文权威指南 12 3.1 安装之前 假如你使用 unix 有一段时间,并且已编译过许多其他软件包,那么只需快速的扫描本 章。编译安装 squid 的过程与安装其他软件相似。 为了编译 squid, 你 需要一个 ANSIC编译器。 不 要被 ANSI 字眼吓倒。 假 如你已经有 一 个编译器,它顺从 ANSI 指令,那么也一样。 GNUC编译器( gcc)是很好的选择,它被 广 泛使用。 大 部分操作系统在其标准安装中附带了 C编译器, 不过 Solaris 和HP-UX除外。 假 如你使用这样的操作系统,那可能没有安装编译器。 理论上你应该在即将运行 squid 的机器上编译 squid。安装过程侦察你的操作系统以 发 现特定的参数,例如可用文件描述符的数量。然而,假如你的系统没有 C编译器存在,你 也许会在其他机器上编译 squid, 然 后把二进制代码 copy 回来。如果 操作系统不同,那么squid 可能会遇到问题。假如操作系统有不 同的内核配置, squid 会变得混乱。 除了 C编译器,你还需要 perl 和awk。awk 是所有 unix 系统的标准程序,所以你不必 担心它。 perl 也是相当普及的, 但 它也许没有默认安装在你的系统上。 你 需要 gzip 程序来 解 压源代码发布文件。 对Solaris 用户, 请 确认 /usr/ccs/bin 包含在你的 PATH环境变量里, 即 使你使用 gcc编译 器。为了编译 squid,make 和ar 程序需要在这个目录找到。 3.2 解开源代码包 在下载完源代码后, 你 需要在某个目录解开它。 具 体哪个目录无关紧要。 你 能解开 squid 在你的家目录或任何其他地方, 大 概需要 20M 的自由磁盘空间。 我 个人喜欢用 /tmp。 使用 tar 命令来展开源代码目录: % cd /tmp % tar xzvf /some/where/squid-2.5.STABLE4-src.tar.gz 一些 tar 程序不支持 z选项, 该选项自动解压 gzip 文件。 如果这样, 你需要运行如下 命 令: % gzip -dc /some/where/squid-2.5.STABLE4-src.tar.gz | tar xvf - 一旦源代码被展开, 下 一步通常是配置源代码树。 然而, 假 如这是你第一次编译 squid, Squid 中文权威指南 13 你应确认特定的内核资源限制足够高。怎样发现,请继续。 3.3 调整内核 Squid 在高负载下,需要大量的内核资源。特别的,你需要给你的系统配置比正常情 况 更高的文件描述符和缓存。 文件描述符的限制通常很恼人。 你最好在开始编译 squid 之前 来 增加这些限制的大小。 因为这点,你可能为了避免重建内核的麻烦,而倾向于使用预编译的二进制版本。不 幸的是, 不 管如何你必须重建一个新内核。 squid 和内核通过数据结构来交换 信息, 数 据 结 构的大小不能超过设置的文件描述符的限制。 squid 在运行时检查这些设置,并且使用最安 全的(最小的)值。这样,即使预编译的二进制版本有 比你的内核更高的文件描述符,但 还是以你系统内核的实际数值为主。 为了改编一些参数, 你 需要重建新内核。 这 个过程在不同的操作系统之间不同。 假 如 需 要, 请参阅 Unix 系统管理员手册 ( Prentice Hall 出版) 或者你的操作系统文档。 假 如你正 使 用Linux,可能不必重建内核。 3.3.13.3.13.3.13.3.1 文件描述符 文件描述符是一个简单的整数, 用 以标明每一个被进程所打开的文件和 socket。第一个 打开的文件是 0,第二个是 1,依此类推。 Unix 操作系统通常给每个进程能打开的文件数量 强加一个限制。更甚的是, unix 通常有一个系统级的限制。 因为squid 的工作方式, 文 件描述符的限制可能会极大的影响性能。当 squid 用完所 有 的文件描述符后,它不能接收用户新的连 接。也就是说,用 完文件描述 符导致拒绝服务。 直到一部分当前请求 完成,相 应的文 件 和 socket 被关闭, squid 不能接收新请求。 当 squid 发现文件描述符短缺时,它会发布警 告。 在运行 ./configure 之前,检查你的系统的文件描述符限制是否合适, 能给你避免一些 麻 烦。 大多数情况下, 1024个文件描述符足够了。 非常忙的 cache可能需要 4096或更多。 在 配 置文件描述符限制时,我推荐设置系统级限制的数量为每个进程限制的 2倍。 通常在你的 Unix shell 中能找到系统的文件描述符限制。 所 有的 C shell 及其类似的 shell 有内建的 limit 命令。更新的 Bourne shell 及其类似的 shell 有一条叫做 ulimit 的命令。为了 发现你的系统的文件描述符限制,试运行如下命令: csh% limit descriptors unlimited csh% limit descriptors Squid 中文权威指南 14 descriptors 4096 或者 sh$ ulimit -n unlimited sh$ ulimit -n 4096 在Freebsd 上,你能使用 sysctl 命令: % sysctl -a | grep maxfiles kern.maxfiles: 8192 kern.maxfilesperproc: 4096 如果 你不能确认文件描述符限制,squid 的./configure 脚本 能替你做到。当你运 行./configure 时,请见 3.4章节,观察末尾这样的输出: checking Maximum number of file descriptors we can open... 4096 假如其他的 limit,ulimit,或者 ./configure 报告这个值少于 1024,你不得不在编译 squid 之 前,花费时间来增加这个限制值的大小。否则, squid 在高负载时执行性能将很低。 增加文件描述符限制的方法因系统不同而不同。下面的章节提供一些方法帮助你开始。 3.3.1.13.3.1.13.3.1.13.3.1.1 Freebsd,NetBSD,OpenBSDFreebsd,NetBSD,OpenBSDFreebsd,NetBSD,OpenBSDFreebsd,NetBSD,OpenBSD 编辑你的内核配置文件,增加如下一行: options MAXFILES=8192 在OpenBSD 上,使用 option 代替 options。然后, configure,编译, 和安装新内核。 最 后重启系统以使内核生效。 3.3.1.23.3.1.23.3.1.23.3.1.2 LinuxLinuxLinuxLinux 在Linux 上配置文件描述符有点复杂。 在 编译 squid 之前, 你 必须编辑系统 include 文件 中的 一个,然后执行一些shell 命令 。 请 首 先 编 辑 /usr/include/bits/types.h 文件 , 改 变 _ _FD_SETSIZE 的值: #define __FD_SETSIZE 8192 Squid 中文权威指南 15 下一步,使用这个命令增加内核文件描述符的限制: # echo 8192 > /proc/sys/fs/file-max 最后,增加进程文件描述符的限制,在你即将编译 squid 的同一个 shell 里执行: sh# ulimit -Hn 8192 该命令必须以 root 运行,仅仅运行在 bash shell。不必重启机器。使用这个技术,你必 须在每一次系统启动后执行上述 echo 和ulimit 命令, 或 者至少在 squid 启动之前。 假 如你 使 用某个 rc.d脚本来启动 squid,那是一个放置这些命令的好地方。 3.3.1.33.3.1.33.3.1.33.3.1.3 SolarisSolarisSolarisSolaris 增加该行到你的 /etc/system 文件: set rlim_fd_max = 4096 然后,重启机器以使改动生效。 3.3.23.3.23.3.23.3.2 MbufMbufMbufMbuf ClustersClustersClustersClusters BSD 基础的网络代码使用一个叫 做 mbuf(参阅 W.R.Stevens 的TCP/IP描述卷 2)的数 据结构。 Mbuf 典型的是小块内存 ( 例如 128字节) 。 较 大的网络包的数据存储在 mbuf clusters 里。 内 核可能给系统可用的 mbuf clusters的总数量强加一个最高限制。 你 能使用 netstat 命令 来发现这个限制: % netstat -m 196/6368/32768 mbufs in use (current/peak/max): 146 mbufs allocated to data 50 mbufs allocated to packet headers 103/6182/8192 mbuf clusters in use (current/peak/max) 13956 Kbytes allocated to network (56% of mb_map in use) 0 requests for memory denied 0 requests for memory delayed Squid 中文权威指南 16 0 calls to protocol drain routines 在这个例子里, 有 8192个mbuf clusters可用, 但 是永远不会同时用到 6182个。 当 系统 用 尽mbuf clusters时, I/O机制例如 read()和write()返回 “无缓存空间可用 ”的错误信息。 NetBSD 和OpenBSD 使用 netstat -m不会显示 mbuf 的输出。代替的,它们在 syslog 里 报告: "WARNING: mclpool limit reached" 。 为了增加 mbuf clusters的数量,你必须在内核配置文件里增加一个选项: options NMBCLUSTERS=16384 3.3.33.3.33.3.33.3.3 临时端口范围 临时端口是 TCP/IP栈分配给出去连接的本地端口。换句话说 , 当 squid 发起一条连接 到另一台服务器,内核给本地 socket 分配一个端口号。这些本地端口号有特定的范围限制 。 例如,在 FreeBSD 上,默认的临时端口范围是 1024-5000。 临时端口号的短缺对非常忙的代理服务器 ( 例如每秒数百个连接) 来 说, 会 较大的影 响 性能 。 这 是 因 为 一 些 TCP 连接 在它们被关闭时进入TIME_WAIT 状态 。 当 连 接 进 入 TIME_WATI状态时,临时端口号不能被重用。 你能使用 netstat 命令来显示有多少个连接进入这个状态: % netstat -n | grep TIME_WAIT Proto Recv-Q Send-Q Local Address Foreign Address (state) tcp4 0 0 192.43.244.42.19583 212.67.202.80.80 TIME_WAIT tcp4 0 0 192.43.244.42.19597 202.158.66.190.80 TIME_WAIT tcp4 0 0 192.43.244.42.19600 207.99.19.230.80 TIME_WAIT tcp4 0 0 192.43.244.42.19601 216.131.72.121.80 TIME_WAIT tcp4 0 0 192.43.244.42.19602 209.61.183.115.80 TIME_WAIT tcp4 0 0 192.43.244.42.3128 128.109.131.47.25666 TIME_WAIT tcp4 0 0 192.43.244.42.3128 128.109.131.47.25795 TIME_WAIT tcp4 0 0 192.43.244.42.3128 128.182.72.190.1488 TIME_WAIT Squid 中文权威指南 17 tcp4 0 0 192.43.244.42.3128 128.182.72.190.2194 TIME_WAIT 注意这个例子中既有客户端连接又有服务器端的连接。 客 户端连接有 3128作为临时端 口 号, 服 务器端连接有 80作为远程主机的端口号。 临 时端口号出现在本地地址栏里。 在 该例 子 里,它们是 19000秒。 如果你没有看到数千个临时端口在 TIME_WAIT 状态,那也许不必增加这个端口范围。 在Freebsd 上,用如下命令增加临时端口范围: # sysctl -w net.inet.ip.portrange.last=30000 在OpenBSD 上,命令类似,但 sysctl 变量有不同的名字: # sysctl -w net.inet.ip.portlast=49151 在NetBSD 上,事情稍有不同。默认的值是 49152-65535.为了增加这个范围,需改变最 低限制: # sysctl -w net.inet.ip.anonportmin=10000 在Linux 上,简单的写一对数字到下列指定文件: # echo "1024 40000" > /proc/sys/net/ipv4/ip_local_port_range 不要忘记将这些命令加到你的系统启动脚本中,以使机器每一次重启后都生效。 3.43.43.43.4 Configure Configure Configure Configure 脚本 象许多其他 Unix 软件一样,squid 在开始编译之前使用 ./configure 脚本来了解操作系 统 信息。 ./configure 脚本由流行的 GNU autoconf 程序产生。当 script 运行时, 它用不同的方 法 来侦察系统,以发现关于库,函数,类型 ,参数,和有没有 功能被提供 等。 ./configure 所 做的第一件事情是去找一个 C编译器。假如 C编译器没有找到,或者编译一个简单的测试 程序失败, ./configure 脚本不 能继续。 . /configure 脚本有大量的选项。 最重要的是安装 prefix。 在运行 ./configure 之前, 你需 要 决定 squid 被安装在哪里。 prefix 选项指定 squid 日志,二进制文件,和配置文件的默认位 置。你可以在安装之后改变这些文件的位置,但假如你现在决定,事情更容易。 默认的安装位置是 /usr/local/squid.squid 将文件放在 prefix 指定目录下面的 7个子目录: % ls -l /usr/local/squid Squid 中文权威指南 18 total 5 drwxr-x--- 2 wessels wheel 512 Apr 28 20:42 bin drwxr-x--- 2 wessels wheel 512 Apr 28 20:42 etc drwxr-x--- 2 wessels wheel 512 Apr 28 20:42 libexec drwxr-x--- 3 wessels wheel 512 Apr 28 20:43 man drwxr-x--- 2 wessels wheel 512 Apr 28 20:42 sbin drwxr-x--- 4 wessels wheel 512 Apr 28 20:42 share drwxr-x--- 4 wessels wheel 512 Apr 28 20:43 var Squid 使用 bin,etc,libexec,man,sbin,和share 目录存放 一些 相对 较小 的文 件( 或 其他目 录) , 这些文件不经常改变。但 var 目录的文 件别有洞天。这里你可以发现 squid 的日志文 件 , 它增 长 得 非 常 大 (数 十 或 数 百 兆 ) 。 var 也是实际磁盘 cache的默认位置。 你 也许想将 var 目录放在 磁盘空间足够的位置,这样做较容易的方法是使用 --localstatedir 选项: %./configure --localstatedir=/bigdisk/var 当配置 squid 时,你不必对这些路径名称担心太多。你以后可以在 squid.conf 文件里改 变这些路径名。 3.4.13.4.13.4.13.4.1 configureconfigureconfigureconfigure选项 ./configure 脚本有大量的不同选项,它 们以 -开始。当你敲入 ./configure --help 时,能看 到选项的完整列表。 一 些选项对所有 configure 脚本是通用的, 还 有一些是 squid 专有的。 下 面是你可能用得到的标准选项: --perfix =PREFIX 如前面描述的一样, 这 里设置安装目录。 安装目录是所有可执行文件, 日 志, 和配置 文 件的默认目录。在整本书中, $prefix 指你选择的安装目录。 --localstatedir =DIR 该选项允许你改变 var 目录的安装位置。默认是 $prefix/var,但也许你想改变它,以使 squid 的磁盘缓存和日志文件被存储在别的地方。 --sysconfdir =DIR Squid 中文权威指南 19 该选项允许你改变 etc 目录的位置。默认的是 $prefix/etc.假如你想使用 /usr 作为安装位 置,你也许该配置 --sysconfdir 为/etc. 以下是 squid 的专有 ./configure 选项: --enable-dlmalloc[=LIB] 在一些系统上,内建的内存 分配机制( malloc)在使用 squid 时表现不尽人意。使用 -- enable-dlmalloc 选项将 squid 源代码包中的 dlmalloc 包编译和链接进来。假如你的系统中已 安装 dlmalloc, 你能 使 用 =LIB 参数指定库的路径。 请见 http://g.oswego.edu/dl/html/malloc.html 更多关于 dlmalloc 的信息。 --enable-gnuregex 在访问控制列表和其他配置指令里, squid 使用正则表达式作为匹配机制。 GNU 的正 则表达式 库包 含 在 squid 的源代码 包里 ;它 可以 在没 有内 建 正则 表达 式 的操作系 统中使 用。 ./configure 脚本侦察你系统中的正则表达式库,假如必要,它可以激活使 用 GNU 正则 表达 式。如果因为某些理由,你想强制使用GNU 正则 表 达 式 , 你 可 以 将 这 个 选 项加 到./configure 命令后。 --enable-carp Cache数组路由协议(CARP) 用 来转发丢失的 cache到父 cache的数组或 cluster。在10.9 章有更多关于 CARP 的细节。 --enable-async-io[=N_THREADS] 异步 I/O是squid 技术之一,用以 提升存储性能。aufs模块使用大量的线程来执行磁盘 I/O 操作。 该 代码仅仅工作在 linux 和solaris 系统中。 =N_THREADS 参数改变 squid 使用的线 程 数量。 aufs 和异步 I/O在8.4章中被讨论。 请注意 --enable-async-io 是打开其他三个 ./configure 选项的快捷方式,它等同于: --with-aufs-threads=N_THREADS --with-pthreads --enable-storeio=ufs,aufs --with-pthreads 该选项导致编译过程链接到你系统中的 P线程库。 aufs 存储模块是 squid 中唯一需要 使 用线程的部分。 通常来说, 如果你使用 --enable-saync-io 选项, 那么不必再单独指定该选项 , 因为它被自动激活了。 --enable-storeio=LIST Squid 中文权威指南 20 Squid 支持大量的不同存储模块。 通过使用该选项, 你 告诉 squid 编译时使用哪个模块 。 在squid-2.5中, 支持 ufs,aufs,diskd,和null 模块。 通过查询 src/fs 中的目录, 你能得到一个 模 块列表。 LIST是一个以逗号分隔的模块列表,例如: %./configure --enable-storeio=afus,diskd,ufs ufs 模块是默认的,看起来问题最少。不幸的是,它性能有限。其他模块可能在某些操 作系统中不必编译。关于 squid 存储模块的完整描述,请见第 8章。 --with-aufs-threads=N_THREADS 指定 aufs 存储机制使用的线程数量(见 8.4章)。squid 默认根据缓存目录的数量,自动 计算需要使用多少线程。 --enable-heap-replacement 该选项不再使用, 但 被保留用于向后兼容性。 你 该使用 --enable-removal-policies 来代 替。 --enable-removal-policies=LIST 排除策略是 squid 需要腾出空间给新的 cache目标时, 用 以排除旧目标的机制。 squid-2.5 支持 3个排除策略:最少近 期使用 (LRU),贪婪对 偶大小 (GDS),最少经常使用 (LFU)。然而, 因为一些理由, ./configure 选项使指定的替代策略和需要执行它们的基本数据结构之间的 差 别模 糊化。 LRU 是默认的, 它 以双链表数据结构执行。 GDS 和LFU 使用堆栈的数据结构 。 为了使用 GDS 或LFU 策略,你指定: %./configure --enable-removal-policies=heap 然后你在 squid 的配置文件里选择使用 GDS 或LFU。 假 如你想重新使用 LRU,那么指 定: %./configure --enable-removal-policies=heap,lru 更多的关于替换策略的细节请见 7.5章。 --enable-icmp 如在 10.5章中描述的一样, squid 能利用 ICMP 消息来确定回环时间尺寸,非常 象 ping 程序。你能使用该选项来激活这些功能。 --enable-delay-pools Squid 中文权威指南 21 延时池是 squid 用于传输形状 或带 宽限制 的技 术。该 池由 大量的 客户 端 IP 地址组成。 当来自这些客户端的请求处于 cache丢失状态, 他 们的响应可能被人工延迟。 关于延时池 的 更多细节请见附录 C。 --enable-useragent-log 该选项激活来自客户请求的 HTTP用户代理头的日志。更多细节请见 13.5章。 --enable-referer-log 该选项激活来自客户请求的 HTTP referer 日志。更多细节请见 13.4章。 --disable-wccp Web cache协调协议 (WCCP)是CISCO 的专有协议,用于阻止或分发 HTTP请求到一个 或多个 caches。WCCP 默认被激活,假如你愿意,可以使用该选项来禁止该功能。 --enable-snmp 简单网络管理协议 (SNMP)是监视网络设备和服务器的流行方法。该选项导致编译过程 去编译所有的 SNMP 相关的代码,包括一个裁切版本的 CMU SNMP 库。 --enable-cachemgr -hostname[=hostname] cachemgr 是一个 CGI 程序,你能使用它来管理查 询 squid。默认 cachemgr 的hostname 值是空的,但你能使用该选项来指定一个默认值。例如: %./configure --enable-cachemgr-hostname=mycache.myorg.net --enable-arp-acl squid 在一些操作系统中支持 ARP,或者以太地址访问控制列表。 该 代码使用非标准的 函 数接口,来执行 ARP 访问控制列表,所以它默认被禁止。假如你在 linux 或solaris 上使用 squid,你可能用的上这个功能。 --enable-htcp HTCP 是超文本缓存协议 --类似于 ICP 的内部缓存协议。更多细节请见 10.8章。 --enable-ssl 使用该选项赋予 squid 终止 SSL/TLS 连接的能力。注意这仅仅工 作 在 web 加速器中用 以加速请求。更多细节请见 15.2.2章节。 Squid 中文权威指南 22 --with-openssl[=DIR] 假如必要,你使用该选项来 告 诉 squid 到哪里找到 OpenSSL 库或头文件。假如它们不 在默认位置,在该选项后指定它们的父路径。例如: %./configure --enable-ssl --with-ssl=/opt/foo/openssl 在这个例子中,你的编译器将在/opt/foo/openssl/include 目录中找头文件,在 /opt/foo/openssl/lib 中找库文件。 --enable-cache-digests Cache消化是 ICP 的另一个替代,但有着截然不同的特性。请见 10.7章。 --enable-err-languages="lang1 lang2 ..." squid 支持定制错误消息, 错误消息可以用多种语言报告。 该选项指定复制到安装目 录 ($prefix/share/errors)的语言。 假 如你不使用该选项, 所 有可用语言被安装。 想 知道何种语 言 可用,请见源代码包里 errors目录下的目录列表。如下显示如何激活多种语言: %./configure --enable-err-languages="Dutch German French" ... --enable-default-err-language=lang 该选项设置 error_directory 指令的默认值。 例 如, 假 如你想使用荷兰语, 你 能这样指定 : %./configure --enable-default-err-language=Dutch 你也能在 squid.conf 里指定 error_directory 指令,在附录 A中有描述。假如你忽略该选 项,英语是默认错误语言。 --with-coss-membuf-size=N 循环目录存储系统( coss)是 squid 的试验性存储机制。该选项设置 coss 缓存目录的 内 存缓冲大小。注意为了使用 coss,你必须在 --enable-storeio 选项里指定存储类型。 该参数以字节形式赋值,默认是 1048576字节或 1M。你能指定 2M 缓冲如下: %./configure --with-coss-membuf-size=2097152 --enable-poll unix 提供 两个相似的函数用以在I/O事件 里扫描开放文件描述符:select()和 poll()./configure脚本通常能非常好的计算出何时使用 poll()来代替 select().假如你想强制使 用 Squid 中文权威指南 23 poll(),那么指定该选项。 --desable-poll 类似的,如果不使用 poll(),那么指定该选项。 --disable-http-violations squid 默认可以被配置成违背 HTTP协议规范。你能使用该选项来删除违背 HTTP协议 的代码。 --enable-ipf-transparent 在第 9章中, 我 将描述如何配置 squid 来拦截缓存。 一 些操作系统使用 IP Filter 包来协 助 拦截缓存。在这些环境下你应该使用该 ./configure 选项。如果你使用了该选项, 但是编译 器 提示 src/client_side.c 文件出错,那是因为 IP Filter 包没有或没有正确的安装在你的系统中。 --enable-pf-transparent 你可能需要指定该选项,使 用 PF包过滤器在操作系统中拦 截 HTTP。PF是OpenBSD 的标 准包 过 滤 器 , 也 可 能被 发 布 到 其 他 系统 中 。 假 如 你 使 用该 选 项 , 但 是 编译 器 提 示 src/client_side.c 文件出错,那是因为 PF没有实际安装到你的系统中。 --enable-linux-netfilter Netfilter 是linux 2.4系列内核的包过滤器名字。 假 如你想在 linux2.4或以后的版本中使 用 HTTP拦截功能,那么激活该选项。 --disable-ident-lookups ident 是一个简单的协议,允许服务器利用客户端的特殊 TCP 连接来发现用户名。假 如 你使用该选项, 编 译器将把执行这些查询的代码排除出去。 即 使你在编译时保留了这些代 码, 除非你在 squid.conf 文件里指定, squid 不会执行 ident 查询。 --disable-internal-dns squid 源代码包含两个不同的 DNS 解决方案, 叫做 “内部的 ”和“外部的 ”。 内部查询是 默 认的,但某些人可能要使用外部技术。该选项禁止内部功能,转向使用旧的方式。 内部查询使用 squid 自己的 DNS 协议执行工具。也就是说, squid 产生未完成的 DNS 查询并且将它们发送到一个解析器。 假 如超时, 它 重新发送请求, 你 能指定任意数量的解 析 器。该工具的有利处之一是, squid 获得准确无误的 DNS 响应的 TTLs。 外部查询利用 C库的 gethostbyname()和gethostbyaddr()函数。 squid 使用一个外部进 程 Squid 中文权威指南 24 池来制造并行查询。使用外部 DNS 解析的主要弊端是你需要更多的辅助进程,增加 squid 的负载。另一个麻烦是 C库函数不在响应里传输 TTLs,这样 squid 使用 postive_dns_ttl 指 令提供的一个常量值。 --enable-truncate truncate() 系统调用是 unlink()的替代品。 unlink()完全删除 cache文件, truncate()将文 件 大小设为零。这样做释放了分配给该文件的磁盘 空间,但留下适当的目录接口。该选项存 在的理由是,某些人相信(或希望) truncate()比unlink()性能表现更好。然而,压力测试显 示两者有 很少的或根本没有区别。 --disable-hostname-checks 默认的, squid 要求 URL 主机名在一定程度上遵守古老的 RFC 1034规范: 标签必须遵循下列 ARPANET 主机名规则。它们必须以字母开始,以字母或数字结尾, 仅仅包含字母,数字和下划线。 这里字母意味着 ASCII 字符,从 A到Z。既然国际域名日益流行,你可能希望使 用该 选项来移除限制。 --enable-underscores 该选项控制 squid 针对主机名里下划线的行为。通用的标准 是主机名里不包含 下划线 字符,尽管有些人不赞成这点。 squid 默认会对 URL 主机名里带下划线 的请求产生一条错 误消息。你能使用该选项, 让 squid 信任它们,把它们当作合法的。然而,你 的 DNS 解析 器也许强迫使用非下划线请求,并且对带下划线的 主机名解析失败。 --enable-auth[=LIST] 该选项控制在 squid 的二进制文件里支持哪种验证机制。你能 选择下列机制的任 意组 合: basic,digest,ntlm.假如你忽略该选项, squid 仅仅支持 basic 验证。假如你使用不带参数 的--enable-auth 选项,编译进程将增加对所有验证机制的支持。你可以使用以逗号分隔的 验 证机制列 表: %./configure --enable-auth=digest,ntlm 我在第六章和第十二章里会谈得更多。 --enable-auth-helpers=LIST 这个旧选项现在已舍弃了, 但为了保持向后兼容性仍保留着。 你可以使用 --enable-basic- auth-helperes=LIST 来代替。 Squid 中文权威指南 25 --enable-basic-auth-helpers=LIST 使用该选项,你能将 helpers/basic_auth 目录的一个或多个 HTTP Basic 验证辅助程序编 译进来。请见 12.2章找到它们的名字和描述。 --enable-ntlm-auth-helpers=LIST 使用该选项, 你 能将 helpers/ntlm_auth 目录的一个或多个 HTTP NTLM 验证辅助程序 编 译进来。请见 12.4章找到它们的名字和描述。 --enable-digest-auth-modules=LIST 使用该选项,你能 将 helpers/digest_auth 目录的一个或多个 HTTP Digest 验证辅助程序 编译进来。请见 12.3章找到它们的名字和描述。 --enable-external-acl-helpers=LIST 使用该选项,你能编译一个或多个扩展 ACL 辅助程序,这些在 12.5章中讨论。例如: %./configure --enable-external-acl-helpers=ip_user,ldap_group --disable-unlinkd unlinkd 是另一个 squid 的外部辅助进程。它的基本工作是对 cache文件执行 unlink()或 truncate()系统调用。 通 过在外部进程里执行文件删除工作, 能给 squid 带来明显的性能提 升。 使用该选项来禁止外部 unlink 进程功能。 --enable-stacktrace 某些系统支持在程序崩溃时, 自 动产生数据追踪。 当 你激活该功能后, 如果 squid 崩溃, 数据追踪信息被写到 cache.log 文件。这些信息对开发和程序 bug 调试有用。 --enable-x-accelerator-vary 该高级功能可能在 squid 被配置成加速器时使用。它建议 squid 在响应请求时,从后台 原始服务器中寻找 X-Accelerator-Vary 头。请见 15.5章。 3.4.23.4.23.4.23.4.2 运行configureconfigureconfigureconfigure 现在我们准备运行 ./configure 脚本。 进 入源代码的顶级目录敲入 ./configure, 后 面跟上 前 面提到过的任意选项,例如: % cd squid-2.5.STABLE4 Squid 中文权威指南 26 %./configure --enable-icmp --enable-htcp ./configure 的工作就是侦察你的操作系统,以发现什么东西可用, 什么不可用。它首 先 做的事情之一就是确认你的 C编译器可用。 假 如 ./configure检测到你的 C编译器有问题, 脚 本会退出,返回如下错误: configure: error: installation or configuration problem: C compiler cannot create executables. 很可能你从不会看到这个消息。 假如看到了, 那意味着你的系统中没有 C编译器存在 , 或者编译器没有正确安装。请 见 config.log 文件找到解决问题的建 议。假如你的系统中有 多个 C编译器,你可以在运行 ./configure 之前设置 CC 环境变量,来告诉 ./configure 使用哪 个: % setenv CC/usr/local/bin/gcc %./configure ... 在./configure 检查完该编译器后, 它查找头文件, 库 文件和函数的长列表。 通常你不 必 担心该部分。在某些实际情况中, ./configure 会终止以引起你的注意,某些事 情可能有问 题, 例 如没有足够的文件描述符。 假 如你指定不完整的或不合理的命令行选项, 它 也会终 止。 假如有错误发生,请检查 config.log 输出。 ./configure 的最终任务是创造 Makefiles 和其他 文件,这些文件基于 squid 从你系统中了解到的知识。到此为止,你准备做编译工作。 3.53.53.53.5 编译 一旦 ./configure 完成了它的工作,你简单的敲入 make 开始编译源代码: %make 正常来说,该过程很顺利,你可以见到大量的滚动行。 你也许见到一些编译器警告。 大 多数情况下, 可 以安全的忽略这些。 假 如这些警告非 常 多,并且一些看起来非常严重,请将它们报告给开发者,在第 16.5章中有描述。 假如编译过程没有错误,你可以转移到下一节,描述如何安装你刚才编译的程序。 为了验证编译是否成功,你可以再次运行 make。你将看到如下输出: % make Squid 中文权威指南 27 Making all in lib... Making all in scripts... Making all in src... Making all in fs... Making all in repl... 'squid' is up to date. 'client' is up to date. 'unlinkd' is up to date. 'cachemgr.cgi' is up to date. Making all in icons... Making all in errors... Making all in auth_modules... 因为许多理由,编译步骤也许会失败,包括: 源代码 bugs 通常 squid 源代码是完整的调试过的。 然而,你也 许会遇到某 些 bugs 或问题从而阻止 你编译。这种问题在新的开发版本中更容易出现,请将它们报告给开发者。 编译器安装问题 不正确安装的 C编译器不能够编译 squid 或其他软件包。通常编译器随着操作系统预 安装,所以你不必担心它。然而,假如你在操作系统安装完后,试图升级编译 器,那么可 能会犯错误。 绝 对不要把已经安装好的编译器从一台机器拷贝到另一台, 除 非你绝对清楚 你 在做什么。我觉得在每台机上独立的安装编译器总是最好的。 请确认你的编译器的头文件总是与库文件同步。 头 文件通常在 /usr/include 目录, 而 库 文 件在 /usr/lib 目录。 Linux 的流行 RPM 系统允许它去升级其中之一,但并非另一个。假如库 文件基于不同的头文件, squid 不能编译。 假如你想在开源 BSD 变种之一中升级编译器, 请 确认在 /usr/src 目录中运行 make world, 这好过从 /usr/src/lib或/usr/src/include 中运行。 Squid 中文权威指南 28 如下是一些通用的编译器问题和错误消息: Solaris: make[1]: *** [libmiscutil.a] Error 255 这意味着 ./configure 不能发现 ar 程序。请确认 /usr/ccs/bin 位于你的 PATH 环境变量里。 假如你没有安装Sun 的编译器,那么需要GNU 的工具。 (http://www.gnu.org/directory/binutils.html). Linux: storage size of 'rl' isn't known 这是因为头文件和库文件不匹配所致,象前面描述的一样。请确认同时升级两者。 Digital Unix: Don't know how to make EXTRA_libmiscutil_a_SOURCES. Stop. Digital Unix的make程序不能兼容 automake包产生的 Makefile 文件。例如,lib/Makefile.in 包含如下行: noinst_LIBRARIES = \ @LIBDLMALLOC@\ libmiscutil.a \ libntlmauth.a \ @LIBREGEX@ 在替换后,当 lib/Makefile 被创建时,它看起来如下: noinst_LIBRARIES = \\ libmiscutil.a \ libntlmauth.a \ 象上面显示的一样, 最后一行包括一个不可见的 TAB字符, 它阻止了 make。 通过安 装 和使用 GNU make,或者手工编辑 lib/Makefile 如下,来解决这个问题: noinst_LIBRARIES = \ libmiscutil.a \ Squid 中文权威指南 29 libntlmauth.a 假如你在编译 squid 时遇到问题, 请 先检查 FAQ。 你 也许该在 Squid 的web 站点上搜 索 (使用主页里的搜索栏) 。 最后,假如你仍有问题,请发邮件到 squid-users@squid-cache.org 列表。 3.63.63.63.6 安装 在编译完后, 你 需要把程序安装到指定的目录。 可 能需要超级用户权限来把它们放置 到 安装目录。所以,请先切换到 root: %su password: #make install 假如你通过使用 --enable-icmp选 项 , 激活 了 squid 的ICMP 衡量功能, 那 么必须安装 pinger 程序。 pinger 程序必须以超级用户权限安装,因为仅仅允许 root 来发送和接受 ICMP 消息。 下列命令以相应的许可来安装 pinger 程序: #make install-pinger 在安装完后, 你 将在 squid 的安装目录里 ( 默认是 /usr/local/squid) 见 到下列目录和文 件: sbin sbin 目录的程序正常只能被 root 启动 sbin/squid Squid 的主程序 bin bin 目录包含对所有用户可用的程序 bin/RunCache Squid 中文权威指南 30 RunCache 是一个 shell 脚本,你能用它来启 动 squid 。假如 squid 死掉,该脚本自动重 启它, 除非它检测到经常的重启。 RunCache 是一个时间遗留的产 物, 那时 Squid 还不是 后 台服务进程。在最近的版本里, RunCache 很少用到,因为 Squid 自动重启它自身,当你不 使用 -N选项时。 bin/RunAccel RunAccel 与RunCache 几乎一致,唯一的不同是它增加了一个命令行参数,告 诉 squid 在哪里侦听 HTTP请求。 bin/squidclient squidclient 是个简单的 HTTP 客户端程序,你能用它来测 试 squid 。它也有一些特殊功 能,用以对运行的 squid 进程发起管理请求。 libexec libexec 目录传统的包含了辅助程序。有一些命令 你不能正常的启动 。然而,这些程序 通常被其他程序启动。 libexec/unlinkd unlinkd 是一个辅助程序,它 从 cache 目录里删除文件。如你后面 看到的一样 ,文件删 除是个性能瓶颈。通过在外部进程里执行删除操作, Squid 提升了一些执行性能。 libexec/cachemgr.cgi cachemgr.cgi 是Squid 管理功能的 CGI接口。 为 了使用它, 你 需要拷贝该程序到你的 WEB 服务器的 cgi-bin 目录。在 14.2章中有更多描述。 libexec/diskd(optional) 假如你指定了 --enable-storeio=diskd,你才能看到它。 libexec/pinger(optional) 假如你指定了 --enable-icmp,你才能看到它。 etc etc 目录包含 squid 的配置文件。 etc/squid.conf Squid 中文权威指南 31 这是 squid 的主要配置文件。 初始的该文件包含了大量的注释, 用以解释每一个选项 做 什么。在你理解了这些配置指令后,建议你删除这些注释,让配置文件更小和更容易阅读。 注意假如该文件存在,安装过程不会覆盖该文件。 etc/squid.conf.default 这是从源代码目录中拷贝过来的默认配置文件。 在升级了 squid 安装后, 你也许发现 有 一份当前默认配置文件的拷贝是有用的。 可 能会增加新的配置指令, 一 些存在的旧指令可 能 有所改变。 etc/mime.conf mime.conf 文件告诉 squid 对从 FTP和Gopher 服务器获取的数据使用何种 MIME类型 。 该文件是一个关联文 件名扩展 到 MIME类型的表。正常而言 ,你不必 编辑该 文件。然 而, 你可能需要增加特殊文件类型的接口,它们在你的组织内使用。 etc/mime.conf.default 这是从源代码目录里拷贝过来的默认 mime.conf 文件。 share share 目录通常包括 squid 的只读数据文件。 share/mib.txt 这是 squid 的SNMP 管理信息基础( MIB)文件。 squid 自身不使用该文件,然而,你 的SNMP 客户端软件(例如 snmpget 和多路由走向图 (MRTG))需要该文件, 用以理解来 自 squid 的SNMP 对象可用。 share/icons share/icons 目录包含大量的小图标文件, squid 用在 FTP和Gopher 目录列举里。 正 常 而 言,你不必担心这些文件,但如果需要,你可以改变它们。 share/errors share/errors 目录包含了 squid 显示给用户看的错误消息模 板。这些文 件在你安 装 squid 时, 从源代码目录拷贝而来。 如果需要你可以编辑它们。 然而, 在每次运行 make install 时, 安装过程总会覆盖它们。所以假如你想定制错误消息,建议你把它们放在不同的目录。 var var 目录包含了不是很重要的和经常变化的文件。这些文件你不必正常的备份它们。 Squid 中文权威指南 32 var/logs var/logs 目录是 squid 不同日志文件的默认位置。当你第一次安装 squid 时,它是空的。 一旦 squid 开始运行,你能在这里看到名字为 access.log,cache.log 和store.log 这样的文件。 var/cache 假如你不在 squid.conf 文件里指定,这是默认的缓存目录 (cache_dir)。第七章有关于缓 存目录的所有细节。 3.73.73.73.7 打补 丁 在你运行 squid 一段时间后,你可能发现需要打源代码补 丁,用以修 正 bug 或者增加 试验性的功能。在 squid-cache.org 站点上,对重要的 bug 修正会发布补丁。假如你不 想等 到下一个官方发布版本, 你 能下载补丁, 并 且打到你的源代码中。 然 后你需要重新编译 squid。 为了打补丁 -或者有时候叫差别文件 -你需要一个叫做 "patch"的程序。 你的操作系统必 须 有该程序。 如 果没有, 你 可以从 GNU 工具集里下载 (http://www.gnu.org/directory/patch.html). 注意假如你在使用匿名 CVS(见 2.4节) , 你 不必担心补丁文件。 当你升级源代码树时, CVS 系统自动升级了补丁。 为了打补丁,你必须把补丁文件存放在系 统中某处。然后进 入 到 squid 的源代码目录, 运行如下命令: % cd squid-2.5.STABLE4 % patch < /tmp/patch_file 默认的,在 patch 程序运行时,它告诉你它正在做什么。 通常输出滚动非常快,除非 有 问题。你能安全的忽略它输出的 offset NNN lines 警告。假如你不想见到所有这些输出,使 用-s选项选择安静模式。 当补丁更新了源代码后, 它创造了原始文件的拷贝。例如, 假如你对 src/http.c打一 个 补丁,备份文件名就是 src/http.c.orig.这样,假 如你在打了补丁后想撤销这个操作,简单 的 重命名所有的 .orig 文件到它们以前的格式。为了成功的使用 该技术,建议你在 打补丁之前 删除所有的 .orig 文件。 假如 patch 程序遇到问题,它停止运行并且给出建议。通常问题如下: • 在错误的目录运行 patch 程序。 解决的方法是,进入到正确的目录, 或者使 用 patch 的-p选项。 Squid 中文权威指南 33 • 补丁已打过。 patch 会告诉你是否已打过补丁文件。在这样的情况下,它会问 你是否撤销这个文件的补丁。 • patch 程序不能理 解你 赋给 它的 文件 。补丁 文件 通常 有三 个风 格: 正常 的, context 的和 unified 的。旧版本的 patch 程序可能不理解后两者的差异输出。从 GNU 的 FTP站点获取最近的版本能解决该问题。 • 损坏的补丁文件。假如你在下载和存储补丁文件时不小心,它有可能被损坏。 有时候人们以 email 消息发送补丁文件,在新的窗口里,它们被简单的剪切和粘贴。 • 在这样的系统中, 剪 切和粘贴能将 Tab 字符改变为空格, 或 者不正确的捆绑 长 行。这些改变混乱了 patch。-l选项也许有用,但最好是正确的拷贝和存储补丁文件。 某些时候 patch 不能应用部分或所有的差别文件。在这样的情况下,你能见到类似于 Hunk 3 of 4 failed 的消息。失 败的 部分 被存 储在 命名为 .rej的文件里。 例如 ,假 如在 处 理 src/http.c时失败, patch 程序将该差别文件片断存为 src/http.c.rej.在这样的情况下,你也许 能手工修正这些问题, 但 它通常不值得这么做。 假如你有大量的 "failed hunks"或者 .rej文件 , 建议你去下载最近源代码版本的完整新拷贝。 在你打完补丁后, 你 必须重新编译 squid。make 的先进功能之一就是它仅仅编译改变 了 的文件。 但有时候 make 不能理解错综复杂的依赖关系, 它没有完整的重编译所需文件。 为 了安全起见,通常建议你去重编译所有文件。最好的方法是在开始编译之前清除源代码树: %make clean %make 3.83.83.83.8 重运 行 configureconfigureconfigureconfigure 有时候你可能发现有必要重新运行 ./configure。例如,假如你调整了内核参数,你必须 再次运行 ./configure 以使它能发现新设置。 当 你阅读本书时, 你 也发现你必须使用 ./configure 选项来激活所需的功能。 以相同的选项重运行 ./configure,使用如下命令: %config.status --recheck 另一个技术是 `touch config.status`文件, 它 更新了该文件的时间戳。 这 导致 make 在编 译 源代码之前,重新运行 ./configure 脚本: % touch config.status Squid 中文权威指南 34 % make 如果增加或删除 ./configure 选项,你必须重新敲入完整的命令行。 假如你记不住以前 的 选项,请查看 config.status 文件的顶部。例如: % head config.status #!/bin/sh # Generated automatically by configure. # Run this file to recreate the current configuration. # This directory was configured as follows, # on host foo.life-gone-hazy.com: # #./configure --enable-storeio=ufs,diskd --enable-carp \ #--enable-auth-modules=NCSA # Compiler output produced by configure, useful for debugging # configure, is in ./config.log if it exists. 在运行 ./configure之后, 你 必须再次编译和安装 squid。 安全 起 见 , 建议 先 运 行 make clean: %make clean %make 请回想一下, ./configure 会缓存它在你系统中发现的东西。在这样 的形式下,你可能 想清除这些缓存, 从头开始编译过程。 假如喜欢, 你可以简单的删除 config.cache 文件。 然 后,下一次 ./configure 运行时,它不会使用以前的数值。你也能恢复 squid 源代码树到它的 configure 之前的状态,使用如下命令: %make distclean 这将删除所有的目标文件和其他被 ./configure 和make 程序产生的文件。 Squid 中文权威指南 35 第第第第4444章章章章快速 配置 向导 快速 配置 向导 快速 配置 向导 快速 配置 向导 4.14.14.14.1 squid.conf squid.conf squid.conf squid.conf 语法 Squid 的配置文件相对规范。 它与其他许多 unix 程序相似。 每行以配置指令开始, 后 面 跟着数字值或关键字。在读取配置文件时, squid 忽略空行和注释掉的行(以 #开 始 ) 。如 下 是一些配置行示例: cache_log /squid/var/cache.log # define the localhostACL acl Localhost src 127.0.0.1/32 connect_timeout 2 minutes log_fqdn on 某些指令取唯一值。 在 这些情形下, 重 复赋予该指令不同的值, 将 覆盖前面的值。 例 如, 下面是一个连接超时值。第一行无效,因为第二行覆盖了它: connect_timeout 2 minutes connect_timeout 1 hour 另外, 某些指令取列表值。 在这些情形下, 每一个新增的值都有效。 "扩展方式 "指令 以 这种方法工作: extension_methods UNGET Squid 中文权威指南 36 extension_methods UNPUT extension_methods UNPOST 对这些基于列表的指令,你通常能在同一行中赋予多个值: extension_methods UNGET UNPUT UNPOST 许多指令有通用类型。例如,连接超时值是一个时间规范,在数字后面跟着时间单元。 例如: connect_timeout 3 hours client_lifetime 4 days negative_ttl 27 minutes 类似的, 大 量的指令指向文件大小或者内存额度。 例如, 你 可以这样编写大小规范: 十 进制数字后面跟 bytes,KB,MB 或GB.例如: minimum_object_size 12 bytes request_header_max_size 10 KB maximum_object_size 187 MB 另一种值得提起的类型是触发器,它的值是 on 或者 off。许多指令使用该类型。例如: server_persistent_connections on strip_query_terms off prefer_direct on 通常, 配 置文件指令能以任何顺序出现。 然 而, 如 果某个指令指向的值被其他指令所 定 义,那么顺序就很重要。访问控制列表是个好的例子。 acl 被用在 http_access规则之前必须 被定义: acl Foo src 1.2.3.4 http_access deny Foo squid.conf 文件里的许多东 西是大 小写敏 感的, 例如指 令名。 你不能 将 http_port 写成 HTTP_port。 Squid 中文权威指南 37 默认的 squid.conf 文件包含了对每个指令的大量注释,以及指令的默认值。例如: #TAG: persistent_request_timeout # How long to wait for the next HTTP request on a persistent # connection after the previous request completes. # #Default: # persistent_request_timeout 1 minute 每次安装 squid 后, 当前默认配置文件存放在 $prefix/etc 目录下的 squid.conf.default。既 然指令每次都有所改变,你能参考该文档,以获取最近的更新。 该章剩下的部分是关于在开始运行 squid 之前,你必须知道的少数指令。 4.24.24.24.2 UserUserUserUser IDIDIDID 你可能知道, unix 进程和文件拥有文件和组属主的属性。你必须选择某个用户和组 给 squid。该用户和组的组合,必须对大部分 squid 相关的文件和目录有读和写的权限。 我高度推荐创建名为 "squid"的用户和组。 这避免了某人利用 squid 来读取系统中的其 他 文件。假如不止一个人拥有对 squid 的管理权限,你可以将他们加到 squid 组里。 unix进程继承了它们父进程的属主属性。 那 就是说, 假 如你以 joe 用户来启动 squid,squid 也以 joe 来运行。假如你不想以 joe 来运行 squid,你需要预先改变你的用户 ID。这是 su命 令的典型功能。例如: joe% su - squid squid% /usr/local/squid/sbin/squid 不幸的是, 运行 squid 并非总是如此简单。 在 某些情况下, 你 必须以 root 来启动 squid, 这依赖于你的配置。 例如, 仅仅 root 能绑定 TCP 套接字到 特权端口上, 如 80。 假如你必 须 以root 来启动 squid, 你 必须设置 cache_effective_user 指令。 它 告诉 squid, 在 执行完需要 特 别权限的任务后,变成哪个用户。例如 : Squid 中文权威指南 38 cache_effective_user squid 你提供的该名字必须是有效用户(在 /etc/passwd 文件里) 。 请注意仅仅当你以 root 来启 动squid 时,你才需要用到该指令。仅仅 root 有能力来随意改变用户身份。假如你以 joe 来 启动 squid,它不能改变到 squid 用户。 你可能尝试不设置 cache_effective_user, 直接以 root 来运行 squid。 假如你试过,你 会 发现 squid 拒绝运行。这违背了安全规 则。假如外部攻击者有能力危及或利用 squid,他 能 获取对系统的全部访问权。尽管我们努力使 squid 安全和少 bug,但还是稳重点好。 假如你没有设置 cache_effective_user,以root 来启动 squid,squid 使用 nobody 作为默 认 值。不管你选择什么用户ID,请确认它有对下面目录的读访问权: $prefix/etc,$prefix/libexec,$prefix/share.该用户 ID也必须有对日志文件 和缓存目录的写访问 权。 squid 也有一个 cache_effective_group 指令,但你也许不必设置它。默认的, squid 使用 cache_effective_user 的默认组(从 /etc/passwd 文件读取)。 4.34.34.34.3 端口 号 http_port 指令告诉 squid 在哪个端口侦听 HTTP请求。默认端口是 3128: http_port 3128 假如你将 squid 作为加速器运行(见 15章) , 你也许该将它设为 80。 你能使用附加的 http_port 行, 来 指示 squid 侦听在多个端口上。 假 如你必须支持客户 组 (它们被配置得不一致) , 这 点就经常有用。 例如, 来 自某个部门的浏览器发送请求到 3128, 然而另一个部门使用 80端口。简单的将两个端口号列举出来: http_port 3128 http_port 8080 你也能使用 http_port 指令来使 squid 侦听在指定的接口地址上。当 squid 作为防火墙运 行时,它有两个网络接口:一个内部的和 一个外部的。你可 能不想接受来自 外部 的 http 请 求。为了使 squid 仅仅侦听在内部接口上,简单的将 IP地址放在端口号前面: http_port 192.168.1.1:3128 Squid 中文权威指南 39 4.44.44.44.4 日志 文件 路径 我将在第 13章讨论所有 squid 的日志细节。你现在你关注的唯一事情是, squid 将它 的 日志放在何处。 默 认的日志目录是 squid 安装位置下的 logs 目 录 。 例如 , 假如 你 在 ./configure 时没有使用 --prefix=选项,那么默认的日志文件路径是 /usr/local/squid/var /logs. 你必须确认日志文件所存放的磁盘位置空 间足够。 在 squid 写日志时如果接受到错误, 它会退出和重启。该行为的主要理由应引起你的注意。 squid 想确认你不会丢失任何重要的 日志信息,特别是你的系统被滥用或者被攻击时。 squid 有三个主要的日志文件: cache.log,access.log,store.log.第一个文件即 cache.log,包 含状态性的和调试性的消息。 当你刚开始运行 squid 时, 你 应密切的关注该文件。 假如 squid 拒绝运行, 理由也许会出现在 cache.log 文件的结尾处。 在正常条件下, 该文件不 会变得 很 大。也请注意,假如你以 -s选项来运行 squid,重要的 cache.log 消息也可被送到你的 syslog 进程。通过使用 cache_log 指令,你可以改变该日志文件的路径: cache_log /squid/logs/cache.log access.log 文件包含了对 squid 发起的每个客户请求的单一 行。每行平 均约 150个字节。 也就是说, 在 接受一百万条客户请求后, 它 的体积约是 150M。 请 使用 cache_access_log 指令 来改变该日志文件的路径: cache_access_log /squid/logs/access.log 假如因为某些理由,你不想 squid 记录客户端请求日志,你能指定日志文件 的路径为 /dev/null. store.log 文件对大多数 cache管理员来说并非很有用。它包含了进入和离开缓存 的 每个目标的记录。 平 均记录大小典型的是 175-200字节。然而,squid 不在 store.log 里对 cache 点击创建接口, 所 以它比 access.log 包含少得多的记录。 请 使用 cache_store_log 指令来改 变 它的位置: cache_store_log /squid/logs/store.log 通过指定路径为 none,你能轻易的完全禁止 store.log 日志: cache_store_log none 假如你不小心, squid 的日志文件增加没有限制。 某 些操作系统对单个文件强制执行 2G 的大小限制,即使你有充足的磁盘空间。超过该限制会导致写错误,这样 squid 就会退出。 为了保证日志文件大小合理,你应创建任务来有规律的重命名和打包日志。 squid 有内建功 Squid 中文权威指南 40 能来使这个容易做到。请见 13.7章关于日 志轮循的解释。 4.54.54.54.5 访问 控制 在第 6章里有更多的关于访问控制的描述。现在,我只讲述少量的访问控制方法,以使 热心的读者能快速开始使用 squid。 squid 默认的 配置 文 件拒 绝 每一 个 客户 请 求。 在 任何 人 能使 用 代理 之 前, 你 必须 在 squid.conf 文件里加入附加的访问控制规则。最简单的方法就是定义一个针对 客户 IP地址 的ACL 和一个访问规则,告诉 squid 允许来自这些地址的 HTTP请求。 squid 有许多不同 的 ACL 类型。 src 类型匹配客户 IP地址, squid 会针对客户 HTTP请求检查 http_access规则 。 这样,你需要增加两行: acl MyNetwork src 192.168.0.0/16 http_access allow MyNetwork 请将这些行放在正确的位置。 http_access的顺序非常重要,但是 acl 行的顺序你不必介 意。 你 也该注意默认的配置文件包含了一些重要的访问控制, 你 不应该改变或删除它们, 除 非你完全理解它们的意义。在你第一次编辑 squid.conf 文件时,请看如下注释: #INSERTYOUROWNRULE(S)HERETOALLOWACCESSFROMYOURCLIENTS 在该注释之后, 以及 "http_access deny all"之前插入你自己的新规则。 为了彻底说明, 如 下是一个合理的初始访问控制配置,包括推荐的默认控制和早先的例子: acl All src 0/0 acl Manager proto cache_object acl Localhost src 127.0.0.1/32 acl Safe_ports port 80 21 443 563 70 210 280 488 591 777 1025-65535 acl SSL_ports 443 563 acl CONNECT method CONNECT acl MyNetwork src 192.168.0.0/16 Squid 中文权威指南 41 http_access allow Manager Localhost http_access deny Manager http_access deny !Safe_ports http_access deny CONNECT!SSL_ports http_access allow MyNetwork http_access deny All 4.64.64.64.6 可见 主机 名 希望你不必担心 visible_hostname 指令。然而,假如 squid 不能发现它所运行的机器的 主机名,你就必须设置它。如果发生这样的事, squid 抱怨和拒绝运行: % squid -Nd1 FATAL: Could not determine fully qualified hostname. Please set 'visible_hostname' 有大量的理由使 squid 需要知道主机名: • 主机名出现在 squid 的错误消息里,这帮助用户验证潜在问题的源头。 • 主机名出现在 squid 转发的 cache 单元的 HTTP Via 头里。当请求到达原始主 机时,Via 头包含了在传输过程中涉及的代理列表。 squid 也使用 Via 头来检测转发环 路。 我将在第 10章里讨论转发环路。 • squid 对特定事务使用内部 URL,例如 FTP目录列表的图标。当 squid 对FTP 目录产生 HTML页面时,它插入小图标用以指明该目录中的文件类型。图标 URL 包含 了cache的主机名,以便 web 浏览器能直接从 squid 请求它们。 • 每个从 squid 响应的 HTTP 回复包含 了 X-Cache 头。这并非 官 方 HTTP 头。 它是一个扩展头, 用 以指明该响应是 cache点击还是 cache丢失。 既然请求和响应可 能 经过多个 cache,每个 X-Cache头包含了 cache 报告点击或丢失的名字。如 下是一个通 过2个cache的响应示例: Squid 中文权威指南 42 HTTP/1.0 200 OK Date: Mon, 29 Sep 2003 22:57:23 GMT Content-type: text/html Content-length: 733 X-Cache: HIT from bo2.us.ircache.net X-Cache: MISS from bo1.us.ircache.net • squid 在启动时试图自动获取主机名。 首先它调用 gethostname()函数, 这通 常 能返回正确的主机名。 接 着, squid 调用 gethostbyname()函数尝试对主机名进行 DNS 查 询。 该 函数典型的返回 IP地址和系统的规范名。 假如 gethostbyname()成功, squid 在错 误消息里, Via 头里等地方使用这个规范名。 • 因为大量的理由, squid 可能不能检测到它的规范主机名,包括: • 主机名可能未设置。 • 主机名可能从 DNS 区域或 /etc/hosts文件里丢失。 • squid 系统的 DNS 客户端配置可能不正确或丢失。 在 unix 系统上,你该检查 /etc/resolv.conf 和/etc/host.conf 文件。 假如你看到上述的致命错误, 你必须修正主机名和 DNS 信息, 或者显式的给 squid 指 明主机名。在大多数情况下,请确认 "hostname"命令返回一个完 全规范的主机名,并且在 /etc/hosts文件里增加这个接口。假如这样不成功,请在 squid.conf 里设置可见主机名: visible_hostname squid.packet-pushers.net 4.74.74.74.7 管理 联系 信息 你应该设置 cache_mgr 指令作为对用户的帮助。它 是一 个 email 地址,假如问题发生, 用户能写信给它。 cache_mgr 地址默认出现在 squid 的错误消息里。例如: Squid 中文权威指南 43 cache_mgr squid@web-cache.net 4.84.84.84.8 下一 步 在创建了初步的配置文件后, 你多少准备首次运行 squid 了。 请遵循下面章节的建议 。 当你掌握了启动和停止 squid 后,你该花费一些时间来改善配置文件。 你可能想增加更高 级的访问控制, 这 在第 6章里有描述。 既 然我在这里没有讨论磁盘 cache, 你 该花些时间阅 读 第7和第 8章。 第第第第5555章章章章运行运行运行运行SquidSquidSquidSquid 5.15.15.15.1 squid squid squid squid 命令 行选 项 在开始其他事情之前, 让我们先看一下 squid 的命令行选项。 这里的许多选项你从不 会 使用,另外有些仅仅在调试问题时有用。 -a port 指定新的 http_port值。 该 选项覆盖了来自 squid.conf 的 值 。 然而 请 注 意 , 你能 在 squid.conf 里指定多个值。-a选项仅仅覆盖配置文件里的第一个值。 ( 该选项使用字母 a是因为在 Harvest cache里, HTTP端口被叫做 ASCII 端口) -d level Squid 中文权威指南 44 让squid 将它的调试信息写到标准错误(假如配置 了,就 是 cache.log 和syslog)。level 参数指定了显示在标准错误里的消息的最大等级。 在多数情况下, d1工作良好。 请见 16.2章 关于调试等级的描述。 -f file 指定另一个配置文件。 -h 显示用法。 -k function 指示squid 执行不同的管理功能。功能参数是下列之 一: reconfigure, rotate, shutdown, interrupt, kill, debug, check, or parse. reconfigure 导致运行中的 squid 重新读取配置文件。 rotate 导致 squid 滚动它的日志,这包括了关闭日志,重命名,和再次打开它们。 shutdown 发送 关闭 squid 进程的信号。 interrupt 立刻关闭 squid ,不必等待活动会话 完成。 kill 发送 KILL 信号给 squid,这是关闭 squid 的最后保证。 debug 将squid 设置成完全的调试模式, 假 如 你 的cache很忙,它能迅速的用完你的磁盘空间。 check 简单的检 查运行中的 squid 进程,返 回的值显示 squid 是否在运行。 最后, parse简单的解析 squid.conf 文件, 如果配置文件包 含 错误,进程返回非 零值。 -s 激活将日志记录到 syslog 进程。 squid 使用 LOCAL4 syslog 设备。 0级别调试信息以优 先级 LOG_WARNING 被记录, 1级别消息以 LOG_NOTICE 被记录。 更 高级的调试信息不 会 被发送到 syslogd.你可以在 /etc/syslogd.conf 文件里使用如下接口: local4.warning /var/log/squid.log -u port 指定另一个 ICP 端口号,覆盖掉 squid.conf 文件里的 icp_port。 -v 打印版本信息。 -z 初始化 cache,或者交换, 目录。在首次运行 squid,或者增加新的 cache目录时,你 必 须使用该选项。 Squid 中文权威指南 45 -C 阻止安装某些信号句柄, 它 们捕获特定的致命信号例如 SIGBUS 和SIGSEGV。 正常 的 , 这些信号被 squid 捕获, 以便它能干净的关闭。然而, 捕获这些信号可能让以后调试问题 困 难。使用该选项,致命的信号导致它们的默认动作,通常是 coredump。 -D 禁止初始化 DNS 测试。正常情况下, squid 直到验证它的 DNS 可用才能启动。该选项 阻止了这样的检测。你也能在 squid.conf 文件里改变或删除 dns_testnames 选项。 -F 让squid 拒绝所有的请求, 直到它重新建立起存储元数据。假如你的系统很忙, 该选 项 可以减短重建存储元数据的时间。 然而, 如果你的 cache很大, 重建过程可能会花费很长 的 时间。 -N 阻止 squid 变成后台服务进程。 -R 阻止 squid 在绑定 HTTP端口之前使用 SO_REUSEADDR 选项。 -V 激活虚拟主机加速模式。类似于 squid.conf 文件里的 httpd_accel_host virtual 指令。 -X 强迫完整调试模式,如你在 squid.conf 文件里指定 debug_options ALL,9一样。 -Y 在重建存储元数据时, 返回 ICP_MISS_NOFETCH 代替 ICP_MISS.忙碌的父 cache在重 建时,该选项可以导致最少的负载。请见 10.6.1.2章。 Squid 中文权威指南 46 5.25.25.25.2 对配 置文 件查错 在开启 squid 之前,你应该谨慎的验证配置文件。这点容易做到,运行如下命令即可: %squid -k parse 假如你看不到输出, 配 置文件有效, 你能继续后面的步骤。 然 而, 如果配置文件包含 错 误, squid 会告诉你: squid.conf line 62: http_access allow okay2 aclParseAccessLine: ACL name 'okay2' not found. 这里你可以看到, 62行的 http_access指令指向的 ACL 不存在。有时候错误信息很少: FATAL: Bungled squid.conf line 76: memory_pools 在这个情形里,我们忘记了在 76行的 memory_pools 指令后放置 on 或off. 建议你养成 习惯: 在每次修改配置文件后, 使用 squid -k parse。 假如你不愿麻烦, 并且你的配置文件 有 错误, squid 会告诉你关于它们而且拒绝启动。 假 如你管理着大量的 cache, 也 许你会编辑 脚 本来自动启动, 停 止和重配置 squid。 你 能在脚本里使用该功能, 来确认配置文件是有效的 。 5.35.35.35.3 初始 化 cache cache cache cache 目录 在初次运行 squid 之前,或者无论何时你增加了新的 cache_dir,你必须初始化 cache目 录。命令很简单: %squid -z 对UFS 相关的存储机制( ufs,aufs,and diskd;见第 8章) ,该命令在每个 cache_dir 下面创 建了所需的子目录。你不必担心 squid 会破坏你的当前 cache目录(如果有的话) 。 在该 阶段属主和许可权是通常遇到的问题。squid 在特 定 的 用 户 ID下运 行 , 这 在 squid.conf 文件里的 cache_effective_user 里指定。用户 ID必须对每个 cache_dir 目录有读和 写权限。否则,你将看到如下信息: Creating Swap Directories Squid 中文权威指南 47 FATAL: Failed to make swap directory /usr/local/squid/var/cache/00: (13) Permission denied 在这样的情形下 ,你该 确认 /usr/local/squid/var/cache 目录的所有组成 都可 被 squid.conf 给定的用户 ID访问。最终的组件 --cache 目录 --必须对该用户 ID可写。 cache目录初始化可能花费一些时间,依赖于 cache目录的大小和数量,以及磁盘驱动 器的速度。假如你想观察这个过程,请使用 -X选项: %squid -zX 5.45.45.45.4 在终 端窗 口里测 试 squidsquidsquidsquid 一旦你已经初始化 cache目录,就可以在终端窗口里运 行 squid,将日志记录到标准错 误。 这样, 你 能轻易的定位任何错误或问题, 并且确认 squid 是否成功启动。 使用 -N选项 来 保持 squid 在前台运行, -d1选项在标准错误里显示 1级别的调试信息。 %squid -N-d1 你将看到类似于以下的输出: 2003/09/29 12:57:52| Starting Squid Cache version 2.5.STABLE4 for i386-unknown-freebsd4.8... 2003/09/29 12:57:52| Process ID 294 2003/09/29 12:57:52| With 1064 file descriptors available 2003/09/29 12:57:52| DNS Socket created on FD 4 2003/09/29 12:57:52| Adding nameserver 206.107.176.2 from /etc/resolv.conf 2003/09/29 12:57:52| Adding nameserver 205.162.184.2 from /etc/resolv.conf 2003/09/29 12:57:52| Unlinkd pipe opened on FD 9 2003/09/29 12:57:52| Swap maxSize 102400 KB, estimated 7876 objects Squid 中文权威指南 48 2003/09/29 12:57:52| Target number of buckets: 393 2003/09/29 12:57:52| Using 8192 Store buckets 2003/09/29 12:57:52| Max Mem size: 8192 KB 2003/09/29 12:57:52| Max Swap size: 102400 KB 2003/09/29 12:57:52| Rebuilding storage in /usr/local/squid/var/cache (DIRTY) 2003/09/29 12:57:52| Using Least Load store dir selection 2003/09/29 12:57:52| Set Current Directory to /usr/local/squid/var/cache 2003/09/29 12:57:52| Loaded Icons. 2003/09/29 12:57:52| Accepting HTTP connections at 0.0.0.0, port 3128, FD 11. 2003/09/29 12:57:52| Accepting ICP messages at 0.0.0.0, port 3130, FD 12. 2003/09/29 12:57:52| WCCP Disabled. 2003/09/29 12:57:52| Ready to serve reques 假如你看到错误消息,你该首先修正它。请检查输出信息的开始几行以发现警告信息。 最普通的错误是文件 /目录许可问题,和配置文件语法错误。假如你看到一条不引起注意的 错误消息,请见 16章中关于 squid 故障处理的建议和信息。如果还不行,请检查 squid FAQ, 或查找邮件列表来获得解释。 一旦你见到 "Ready to serve requests"消息,就可用一些 HTTP 请求来测试 squid 。配置 你的浏览器使用 squid 作为代理, 然 后打开某个 web 页面。 假如 squid 工作 正常, 页 面被 迅 速载入,就象没使用 squid 一样。另外,你可以使用 squidclient 程序,它随 squid 发布: % squidclient http://www.squid-cache.org/ 假如它正常工作, squid 的主页 html 文件会在你的终端窗口里滚动。一旦确认 squid 工 作正常,你能中断 squid 进程(例如使用 ctrl-c)并且在后台运行 squid。 Squid 中文权威指南 49 5.55.55.55.5 将squid squid squid squid 作为 服务 进程运 行 正常情况下你想将 squid 以后台进程运行(不出现在终端窗口里) 。最容易的方法是简 单执行如下命令: %squid -s -s 选项导致 squid 将重要的状态和警告信息写到 syslogd。squid 使用 LOCAL4设备, 和 LOG_WARNING 和LOG_NOTICE 优先 权。 syslog 进程实际可能会或不会记 录 squid 的消 息, 这 依赖于它被如何配置。 同 样的消息被写进 cache.log 文件, 所 以假如你愿意, 忽 略 -s 选 项也是安全的。 当你不使用 -N选项来启动 squid,squid 自动在后台运行并且创建父 /子进程对。子进程 做所有的实际工作。父进程确 认子进程总在运行。这样,假如子进程意外终止,父进程启 动另外一个子进程以使 squid 正常工作。 通 过观察 syslog 消 息 , 你能 看 到 父 /子进程交互作 用。 Jul 31 14:58:35 zapp squid[294]: Squid Parent: child process 296 started 这里显示的父进程 ID是294, 子 进程是 296。 当 你查看 ps 的输出, 你 可以看到子进程 以 (squid)形式出现: % ps ax | grep squid 294 ?? Is 0:00.01 squid -sD 296 ??S 0:00.27 (squid) -sD (squid) 假如 squid 进程意外终止,父进程启动另一个。例如: Jul 31 15:02:53 zapp squid[294]: Squid Parent: child process 296 exited due to signal 6 Jul 31 15:02:56 zapp squid[294]: Squid Parent: child process 359 started 在某些情形下, squid 子进程可能立即终止。为了防止频繁的启动子进程,假如子进程 连续 5次没有运行至少 10秒钟,父进程会放弃。 Jul 31 15:13:48 zapp squid[455]: Squid Parent: child process 474 exited with status 1 Jul 31 15:13:48 zapp squid[455]: Exiting due to repeated, frequent failures 如果发生这样的事,请检查 syslog 和squid 的cache.log 以发现错误。 Squid 中文权威指南 50 5.5.15.5.15.5.15.5.1 squid_start squid_start squid_start squid_start 脚本 当squid 以后台进程运行时, 它查 找 squid 执行程序目录下的名 为 squid_start 的文件。 假如发现, 该 程序在父进程创建子进程之前被执行。 你 能 使用该脚本完成特定的管理任务 , 例如通知某人 squid 在运行, 管 理日志文件等。 除非 squid_start 程序存在, squid 不会创建 子 进程。 squid_start 脚本在你使用绝对或相对路径启动 squid 时才开始工作。 换句话说, squid 不 使用 PATH环境变量来定位 squid_start.这样,你应该养成习惯这样启动 squid: %/usr/local/squid/sbin/squid -sD 而不要这样: %squid -sD 5.65.65.65.6 启动 脚本 通常你希望 squid 在每次计算机重启后自动启动。 对不同的操作系统, 它们的启动脚 本 如何工作也很不同。 我 在这里描述一些通用的环境, 但 对你自己的特殊操作系统, 也 许该 有 特殊的处理方法。 5.6.15.6.15.6.15.6.1 /etc/rc.local/etc/rc.local/etc/rc.local/etc/rc.local 最容易的机制之一是 /etc/rc.local 脚本。这是个简单的 shell 脚本,在每次系统启动时以 root 运行。使用该脚本来启动 squid 非常容易,增加一行如下: /usr/local/squid/sbin/squid -s 当然你的安装位置可能不同,还有你可能 要使用其他命令行 选项。不要在这 里使用 -N 选项。 假如因为某些理由, 你 没有使用 cache_effective_user 指令, 你 可以尝试使用 su来让 squid 以非 root 用户运行: /usr/bin/su nobody -c '/usr/local/squid/sbin/squid -s' Squid 中文权威指南 51 5.6.25.6.25.6.25.6.2 init.dinit.dinit.dinit.d和rc.drc.drc.drc.d init.d 和rc.d机制使用独立的 shell 脚本来启动不同的服务。 这 些脚本通常在下列目录 之 中: /sbin/init.d, /etc/init.d, /usr/local/etc/rc.d.脚本通常获取单 一命令 行参数 , 是 start 或stop。 某些系统仅仅使用 start 参数。如下是启动 squid 的基本脚本: #!/bin/sh # thisscript starts and stops Squid case "$1" in start) /usr/local/squid/sbin/squid -s echo -n ' Squid' ;; stop) /usr/local/squid/sbin/squid -k shutdown ;; esac Linux 用户可能在启动 squid 之前需要设置文件描述符限制。例如: echo 8192 > /proc/sys/fs/file-max limit -HSn 8192 为了使用该脚本, 先 找到脚本存放的目录。 给 它一个有意义的名字, 类 似于其他的系 统 启动脚本。 可以是 S98squid 或squid.sh。 通过重启计算机来测试该脚本, 而不要假想它会 正 常工作。 5.6.35.6.35.6.35.6.3 /etc/inittab/etc/inittab/etc/inittab/etc/inittab 某些操作系统支持另一种机制,是 /etc/inittab 文件。在这些系统中, init进程启动和停 止基于运行等级的服务。典型的 inittab接口类似如此: sq:2345:once:/usr/local/squid/sbin/squid -s 使用该接口, init进程启动 squid 一次并且随后忘记它。 squid 确认它驻留在运行状态, 象前面描述的一样。或者,你能这样做 : Squid 中文权威指南 52 sq:2345:respawn:/usr/local/squid/sbin/squid -Ns 这里我们使用了 respawn 选项,假如进程不存在 init会重启 squid。假如使用 respawn, 请确认使用 -N选项。 在编辑完 inittab文件后, 使 用下面的命令来使 init重新读取它的配置文件和启动 squid: # init q 5.75.75.75.7 chroot chroot chroot chroot 环境 某些人喜欢在 chroot 环境运行 squid。这是 unix 的功能,给予进程新的 root 文件系统 目录。在 squid 受安全威胁时,它提供额外等级的安全保 护。假如攻击者在某种程度上通 过squid 获取了对操作系统的访问权,她仅仅能访问在 chroot 文件系统中的文件。在 chroot 树之外的系统文件,她 不可访问。 最容易在 chroot 环境里运行 squid 的方法是,在 squid.conf 文件里指定新的 root 目录, 如下: chroot /new/root/directory chroot()系统调用需要超级用户权限,所以你必须以 root 来启动 squid。 chroot 环境不是为 unix 新手准备的。它有点麻烦,因为你必须在新的 root 目录里重复 放置大量的文件。例如,假如默认的配置文件正常在 /usr/local /squid/etc/squid.conf,并且你 使用 chroot 指令,那么文件必须位于 /new/root/directory/usr /local/squid/etc/squid.conf.你必须 将位 于 $prefix/etc,$prefix/share,$prefix /libexec 下的 所 有 文 件 拷 贝 到 chroot 目录 。 请 确 认 $prefix/var 和cache目录在 chroot 目录中存在和可写。 同样的,你的操作系统 需要将大 量的文 件放 在 chroot 目录里,例如 /etc/resolv.conf 和 /dev/null.假如你使用外部辅助程序, 例如 重定向器 (见 11章) 或者验证器(见 12章),你也 需要来自 /usr/lib 的某些共享库。你可以使用 ldd 工具来查找给定的程序需要哪些共享库: % ldd /usr/local/squid/libexec/ncsa_auth /usr/local/squid/libexec/ncsa_auth: libcrypt.so.2 => /usr/lib/libcrypt.so.2 (0x28067000) Squid 中文权威指南 53 libm.so.2 => /usr/lib/libm.so.2 (0x28080000) libc.so.4 => /usr/lib/libc.so.4 (0x28098000) 你可以使用 chroot 命令来测试辅助程序: # chroot /new/root/directory /usr/local/squid/libexec/ncsa_auth /usr/libexec/ld-elf.so.1: Shared object "libcrypt.so.2" not found 更多的关于 chroot 的信息,请见你系统中 chroot()的manpage. 5.85.85.85.8 停止squidsquidsquidsquid 最安全的停止 squid 的方法是使用 squid -k shutdown 命令: %squid -k shutdown 该命令发送 TERM 信号到运行中的 squid 进程。 在接受到 TERM 信号后, squid 关闭 进 来的套接字以拒收新请求。 然 后它等待一段时间, 用以完成外出请求。 默 认时间是 30秒, 你 可以在 shutdown_lifetime 指令里更改它。 假如因为某些理由, squid.pid 文件丢失或不可读, squid -k命令会失败。在此情 形下, 你可以用 ps 找到 squid 的进程 ID,然后手工杀死 squid。例如: %ps ax |grep squid 假如你看到不止一个 squid 进程,请杀死以 (squid)显示的那个。例如: % ps ax | grep squid 294 ?? Is 0:00.01 squid -sD 296 ??S 0:00.27 (squid) -sD (squid) % kill -TERM 296 在发送 TERM 信号后,你也许想查看日志,以确认 squid 已关闭: Squid 中文权威指南 54 % tail -f logs/cache.log 2003/09/29 21:49:30| Preparing for shutdown after 9316 requests 2003/09/29 21:49:30| Waiting 10 seconds for active connections to finish 2003/09/29 21:49:30| FD 11 Closing HTTP connection 2003/09/29 21:49:31| Shutting down... 2003/09/29 21:49:31| FD 12 Closing ICP connection 2003/09/29 21:49:31| Closing unlinkd pipe on FD 9 2003/09/29 21:49:31| storeDirWriteCleanLogs: Starting... 2003/09/29 21:49:32| Finished. Wrote 253 entries. 2003/09/29 21:49:32| Took 0.1 seconds (1957.6 entries/sec). 2003/09/29 21:49:32| Squid Cache (Version 2.5.STABLE4): Exiting normally. 假如你使用 squid -k interrupt 命令,squid 立即关闭, 不 用等待完成活动请求。 这 与在 kill 里发送 INT 信号相同。 5.95.95.95.9 重配 置运 行中 的 squid squid squid squid 进程 在你了解了更多关于 squid 的知识后,你会发现对 squid.conf 文件做了许多改动。为了 让新设置生效,你可以关闭和重启 squid,或者在 squid 运行时,重配置它。 重配置运行中的 squid 最好的方法是使用 squid -k reconfigure 命令: %squid -k reconfigure 当你运行该命令时, HUP 信号被发送到运行中 的 squid 进程。然后 squid 读取和解析 squid.conf 文件。假如操作成功,你可以在 cache.log 里看到这些: Squid 中文权威指南 55 2003/09/29 22:02:25| Restarting Squid Cache (version 2.5.STABLE4)... 2003/09/29 22:02:25| FD 12 Closing HTTP connection 2003/09/29 22:02:25| FD 13 Closing ICP connection 2003/09/29 22:02:25| Cache dir '/usr/local/squid/var/cache' size remains unchanged at 102400 KB 2003/09/29 22:02:25| DNS Socket created on FD 5 2003/09/29 22:02:25| Adding nameserver 10.0.0.1 from /etc/resolv.conf 2003/09/29 22:02:25| Accepting HTTP connections at 0.0.0.0, port 3128, FD 9. 2003/09/29 22:02:25| Accepting ICP messages at 0.0.0.0, port 3130, FD 11. 2003/09/29 22:02:25| WCCP Disabled. 2003/09/29 22:02:25| Loaded Icons. 2003/09/29 22:02:25| Ready to serve requests. 在使用 reconfigure 选项时你须谨慎,因为所做的改变可能会 导致致命错误。例 如,请 注意 squid 关闭和重新打开进来的 HTTP和ICP 套接字;假如你将 http_port 改变为 squid 不 能打开的端口,它会发生致命错误并退出。 在squid 运行时,某些指令和和选项不能改变,包括: • 删除 cache目录( cache_dir 指令) • 改变 store_log 指令 • 改变 coss cache_dir 的块大小数值。事实上,无论何时你改变了该值,你必须 重新初始化 cosscache_dir. • coredump_dir 指令在重配置过程中 不被检查 。所以 , 在 squid 已经启动了后, 你不能让 squid 改变它的当前目录。 solaris 用户在重 配 置 squid 过程中可 能 遇到 其他 问 题。 solaris 的stdio 执行组件 里 的 fopen()调用要求使用小于 256的未用文件描述符。 FILE结构以 8位值存储该文件描述符。 正 Squid 中文权威指南 56 常情况下这不构成问题,因为 squid 使用底层 I/O(例如 open())来打开 cache文件。然而, 在重配 置过程中的某些任务使用 fopen(),这就有可能失败,因为前面的 256个文件描述符 已被分配出去。 5.105.105.105.10 滚动 日志 文件 除非你在 squid.conf 里禁止, squid 会写大量的日志文件。你必须周期性的滚 动日志文 件, 以阻止它们变得太大。 squid 将大量的重要信息写入日志, 假如写不进去了, squid 会发 生错误并退出。为了合理控制磁盘空间消耗,在 cron 里使用如下命令: %squid -k rotate 例如,如下任务接口在每天的早上 4点滚动日志: 0 4 ***/usr/local/squid/sbin/squid -k rotate 该命令做两件事。首先,它关闭当前打开的日志文件。然后,通过在文件名后加数字 扩展名, 它 重命名 cache.log,store.log,和access.log。例如,cache.log 变成 cache.log.0,cache.log.0 变成 cache.log.1,如此继续,滚动到 logfile_rotate 选项指定的值。 squid 仅仅保存每个日志文件的最后 logfile_rotate 版本。更老的版本在重命名过程中被 删除。 假 如你想保存更多的拷贝, 你需要增加 logfile_rotate 限制, 或者编写脚本用于将日 志 文件移动到其他位置。 请见 13.7章关于滚动日志的其他信息。 Squid 中文权威指南 57 第第第第6666章章章章访问 控制 访问 控制 访问 控制 访问 控制 6.16.16.16.1 访问 控制 元素 ACL 元素是 Squid 的访问控制的基础。这里告诉你如何指定包括 IP地址,端口号,主 机名, 和 URL 匹配等变量。 每个 ACL 元素有个名字, 在 编写访问控制规则时需要引用它 们。 基本的 ACL 元素语法如下: acl name type value1 value2 ... 例如: acl Workstations src 10.0.0.0/16 在多数情况下, 你 能对一个 ACL 元素列举多个值。 你 也可以有多个 ACL 行使用同一 个 名字。例如,下列两行配置是等价的: acl Http_ports port 80 8000 8080 acl Http_ports port 80 acl Http_ports port 8000 acl Http_ports port 8080 6.1.16.1.16.1.16.1.1 一些基本 的 ACL ACL ACL ACL 类型 Squid 大约有 25个不同的 ACL 类型, 其 中的一些有通用基本类型。 例 如, src 和dst ACL 使用 IP地址作为它们的基本类型。为避免冗长,我首先描述基本类型,然后在接下来章节 里描述每种 ACL 类型。 6.1.1.16.1.1.16.1.1.16.1.1.1 IP IP IP IP 地址 使用对象: src,dst,myip squid 在ACL 里指定 IP地址时,拥有强有力的语法。你能以子网,地址范围,域名等 形式编写地址。 squid 支持标准 IP地址写法(由 ”.”连接的 4个小于 256的数字)和无类域间 路由规范。另外,假如你忽略掩码, squid 会自动计算相应的掩码。例如,下例中的每组是 相等的: Squid 中文权威指南 58 acl Foo src 172.16.44.21/255.255.255.255 acl Foo src 172.16.44.21/32 acl Foo src 172.16.44.21 acl Xyz src 172.16.55.32/255.255.255.248 acl Xyz src 172.16.55.32/28 acl Bar src 172.16.66.0/255.255.255.0 acl Bar src 172.16.66.0/24 acl Bar src 172.16.66.0 当你指定掩码时, squid 会检查你的工作。 如 果你的掩码在 IP地址的非零位之外, squid 会告警。例如,下列行导致告警: acl Foo src 127.0.0.1/8 aclParseIpData: WARNING: Netmask masks away part of the specified IP in 'Foo' 这里的问题是 /8掩码 ( 255.0.0.0) 在最后三个字节里都是零值,但是 IP地址 127.0.0.1不 是这样的。 squid 警告你这个问题,以便你消除歧义。正确的写法是: acl Foo src 127.0.0.1/32 or: acl Foo src 127.0.0.0/8 有时候你可能想列举多个相邻子网,在这样的情况下,通过指定地址范围很容易做到。 例如: acl Bar src 172.16.10.0-172.16.19.0/24 这等价但高效于下面的行: acl Foo src 172.16.10.0/24 acl Foo src 172.16.11.0/24 acl Foo src 172.16.12.0/24 Squid 中文权威指南 59 acl Foo src 172.16.13.0/24 acl Foo src 172.16.14.0/24 acl Foo src 172.16.15.0/24 acl Foo src 172.16.16.0/24 acl Foo src 172.16.18.0/24 acl Foo src 172.16.19.0/24 注意使用 IP地址范围, 掩 码只能取一个。 你 不能为范围里的地址设置多个不同掩码。 你 也能在 IPACL 里指定主机名,例如: acl Squid dst www.squid-cache.org squid 在启动时,将主机名转换成 IP地址。一旦启动, squid 不会对主机名的地址发起 第二次 DNS 查询。这样,假如在 squid 运行中地址已改变, squid 不会注意到。 假如主机名被解析成多个 IP地址, squid 将每一个增加到 ACL 里。注意你也可以对主 机名使用网络掩码。 在基于地址的 ACL 里使用主机名通常是坏做法。 squid 在初始化其他组件之前,先解 析配置文件,所以这些 DNS 查询不使用 squid 的非阻塞 IP缓存接 口。代替的,它们使用 阻塞机制的 gethostbyname()函数。这样,将 ACL 主机名转换到 IP地址的过程会延缓 squid 的启动。除非绝对必要, 请在 src,dst,和myipACL 里避免使用主机名。 squid 以一种叫做splay tree 的数据结构在内存里存储IP地址ACL (请见 http://www.link.cs.cmu.edu/splay/)。splay tree 有一些有趣的自我调整的特性,其中之一 是在 查询发生时, 列 表会自动纠正它自己的位置。 当 某个匹配元素在列表里发现时, 该 元素变 成 新的树根。在该方法中,最近参考的条目会移动到树的顶部,这减少了将来查询的时间。 属于同一 ACL 元素的所有的子网和范围不能重迭。 如 果有错误, squid 会警告你。 例 如, 如下不被允许: acl Foo src 1.2.3.0/24 acl Foo src 1.2.3.4/32 它导致 squid 在cache.log 里打印警告: WARNING:'1.2.3.4' is a subnetwork of '1.2.3.0/255.255.255.0' Squid 中文权威指南 60 WARNING: because of this'1.2.3.4' is ignored to keep splay tree searching predictable WARNING: You should probably remove '1.2.3.4' from theACL named 'Foo' 在该情形下,你需要修正这个问题,可以删除其中一个 ACL 值,或者将它们放置在不 同的 ACL 列表中。 6.1.1.26.1.1.26.1.1.26.1.1.2 域名 使用对象: srcdomain,dstdomain,和cache_host_domain 指令 域名简单的就是 DNS 名字或区域。例如,下面是有效的域名: www.squid-cache.org squid-cache.org org 域名 ACL 有点深奥,因为相对于匹配 域名和子域 有点微妙的 差别。 当 ACL 域名以 "." 开头, squid 将它作为通配符,它匹配在该域的任何主机名,甚至域名自身。相反的,如果 ACL 域名不以 "."开头, squid 使用精确的字符串比较,主机名同样必须被严格检查。 表6-1显示了 squid 的匹配域和主机名的规则。 第 一列显示了取自 URL 请求的主机名(或 者srcdomainACL 的客户主机名) 。第二列指明是否主机名匹配 lrrr.org。第三列显示是否主 机名匹配 .lrrr.orgACL。你能看到,唯一的不同在第二个实例里。 Table 6-1. Domain name matching URL hostname Matches ACL lrrr.org? Matches ACL .lrrr.org? lrrr.org Yes Yes i.am.lrrr.o rg No Yes Squid 中文权威指南 61 域名匹配可能让人迷惑, 所 以请看第二个例子以便你能真正理解它。 如 下是两个稍微 不 同的 ACL: acl A dstdomain foo.com acl B dstdomain .foo.com 用户对 http://www.foo.com/的请求匹配 ACLB,但不匹配 A。ACLA要求严格的字符串 匹配,然而 ACLB里领头的点就像通配符。 另外,用户对 http://foo.com/的请求同时匹配 A和B。尽管在 URL 主机名里的 foo.com 前面没有字符,但 ACLB里领头的点仍然导致一个匹配。 squid 使用 splay tree的数据结构来存储域名 ACL, 就 像它处理 IP地 址 一 样 。 然而 , squid 的域名匹配机制给 splay tree提供了一个有趣的问题。 splay tree技术要求唯一键去匹配任意 特定搜索条目。例如,让我们假设搜索条目是i.am.lrrr.org。该主机名同时匹 配.lrrr.org 和.am.lrrr.org。事实上就是两个 ACL 值匹配同一个主机名扰乱 了 splay 机制。换 句话说,在配置文件里放置如下语句是错误的: acl Foo dstdomain .lrrr.org .am.lrrr.org 假如你这样做, squid 会产生如下警告信息: WARNING:'.am.lrrr.org' is a subdomain of '.lrrr.org' WARNING: because of this'.am.lrrr.org' is ignored to keep splay tree searching predictable WARNING: You should probably remove '.am.lrrr.org' from theACL named 'Foo' 在该情况下你应遵循 squid 的建议。删除其中一条相关的域名,以便 squid 明确知道你 的意图。注意你能在不同的 ACL 里任意使用这样的域名: acl Foo dstdomain .lrrr.org acl Bar dstdomain .am.lrrr.org iamlrrr.or g No No Squid 中文权威指南 62 这是允许的,因为每个命名 ACL 使用它自己的 splay tree. 6.1.1.36.1.1.36.1.1.36.1.1.3 用户 名 使用对象: ident,proxy_auth 该类型的 ACL被设计成匹配用户名。 squid 可能通过 RFC 1413 ident协议或者通过 HTTP 验证头来获取用户名。 用户名必须被严格匹配。 例 如, bob 不匹配 bobby。squid 也有相关 的 ACL 对用户名使用正则表达式匹配( ident_regex 和proxy_auth_regex)。 你可以使用单词 "REQUIRED"作为特殊值去匹配任意用户名。假如 squid 不能查明用户 名, ACL 不匹配。当使用基于用户名的访问控制时, squid 通常这样配置。 6.1.1.46.1.1.46.1.1.46.1.1.4 正则 表达 式 使用对 象: srcdom_regex, dstdom_regex, url_regex, urlpath_regex, browser, referer_regex, ident_regex, proxy_auth_regex, req_mime_type, rep_mime_type 大量的 ACL 使用正则表达式来匹配字符串(完整的正则表达式参考,请 见 O'Reilly 的 Mastering Regular Expressions 一 书 ) 。对 squid 来说, 最 常使用的正则表达式功能用以匹配 字 符串的开头或结尾。例如, ^字符是特殊元字符,它匹配行或字符串的开头: ^http:// 该正则表达式匹配任意以 http://开头的 URL。$也是特殊的元字符,因为它匹配行或字 符串的结尾: .jpg$ 实际上,该示例也有些错误,因为 .字符也是特殊元字符。它是匹配任意单个字符的通 配符。我们实际想要的应该是: \.jpg$ 反斜杠对这个 "."进行转义。 该 正则表达式匹配以 .jpg 结尾的任意字符串。 假 如你不使 用 ^或$字符, 正 则表达式的行为就象标准子串搜索。 它 们匹配在字符串里任何位置出现的单 词 或词组。 对所有的 squid 正则表达式类, 你可以使用大小写敏感的选项。 匹配是默认大小写敏 感 的。为了大小写不敏感,在 ACL 类型后面使用 -i选项。例如: acl Foo url_regex -i ^http://www 6.1.1.56.1.1.56.1.1.56.1.1.5 TCP TCP TCP TCP 端口 号 Squid 中文权威指南 63 使用对象: port,myport 该类型是相对的。值是个别的端口号或端口范围。回想一 下 TCP 端口号是 16位值,这 样它的值必须大于 0和小于 65536。如下是一些示例 : acl Foo port 123 acl Bar port 1-1024 6.1.1.66.1.1.66.1.1.66.1.1.6 自主 系统 号 使用对象: src_as,dst_as Internet 路由器使用自主系统 (AS)号来创建路由表。基本上, 某 个 AS 号指向被同一组 织管理的 IP网络范围。 例如 ,我 的 ISP分配了如下 网络 块: 134.116.0.0/16, 137.41.0.0/16, 206.168.0.0/16,和其他更多。在 Internet 路由表里,这些网络被公布为属于 AS 3404。当路 由 器转发包时, 它 们典型的选择经过最少 AS 的路径。 假 如这些对你不重要, 请 不必关注它 们。 AS 基础的 ACL 仅仅被网络 gurus 使用。 如下是基于 AS 的类型如何工作的: 当 squid 首先启动时, 它 发送一条特殊的查询到 某 个whois 服务器。查询 语句基本是:“告诉我哪个 IP网络属于该 AS 号”。 这样 的 信 息 被 RADB 收集和管理。一 旦 Squid 接受到 IP网络列表,它相 似的将 它们作 为 IP基础的 ACL 对待。 基于 AS 的类型仅仅在 ISP将他们 的RADB 信息保持与日更新时才工作良好。某些 ISP更 新RADB 比其 他人做得更好;而许多根本不更新它。请注意squid 仅仅 在 启 动 或 者 reconfigure 时才将 AS 号转换为网络地址。 假如 ISP更新了它的 RADB 接口 , 除 非你重启 或 者重配置 squid,squid 不会知道这个改变。 另外的情况是, 在 你的 squid 启动时,RADB可能不可到达。 假如 Squid 不能联系上 RADB 服务器,它从访问控制配置 里删 除 AS 接口。默认的 whois 服务器是 whois.ra.net,对许多 用户来说太遥远了而不可信赖。 6.1.26.1.26.1.26.1.2 ACL ACL ACL ACL 类型 现在我们能把焦点放在 ACL 类型自身上。我在这里按照重要性的降序来列举它们。 6.1.2.16.1.2.16.1.2.16.1.2.1 srcsrcsrcsrc IP地址在访问控制元素里是最普遍使用的。大部分站点使用 IP地址来控制客户允许或 不允许访问 Squid。src 类型指客户源 IP地址。也就是说,当 src ACL 出现在访问控制列表 里时, squid 将它与发布请求的客户 IP地址进行比较。 正常情况下你允许来自内网 中主机的请 求,并阻塞 其他的。例 如,假如你 的单位使用 192.168.0.0子网,你可以这样指定 ACL: Squid 中文权威指南 64 acl MyNetwork src 192.168.0.0 假如你有许多子网,你能在同一个 acl 行里面列举它们: acl MyNetwork src 192.168.0.0 10.0.1.0/24 10.0.5.0/24 172.16.0.0/12 squid 有许多其他 ACL 类型用以检查客户地址。 srcdomain 类型比较客户的完整可验证 域名。它要求反向 DNS 查询,这可能会延缓处理该请求。 srcdom_regex ACL 是类似的, 但 它允许你使用正则表达式来匹配域名。最后, src_as 类型比较客户的 AS 号。 6.1.2.26.1.2.26.1.2.26.1.2.2 dstdstdstdst dst 类型指向原始服务器(目标) IP地址。在某些情况下,你能使用该类型来阻止你 的 用户访问特定 web 站点。 然而,在使用 dstACL 时你须谨慎。大部分 squid 接受到的请求 有 原始服务器主机名。例如: GET http://www.web-cache.com/ HTTP/1.0 这里, www.web-cache.com 是主机名。当访问列表规则包含了 dst 元素时, squid 必须 找到该主机名的 IP地址。假如 squid 的IP缓存 包含了该主机名的有效接口,这条 ACL 被 立即检测。 否则,在 DNS 查询忙碌时, squid 会延缓处理该请求。 这对某些请求来说会造 成 延时。为了避免延时, 你该尽可能的使用 dstdomainACL 类型来代替 dst。 如下是简单的 dstACL 示例: acl AdServersdst 1.2.3.0/24 请注意, dstACL 存在的问题是,你试图允许或拒绝访问的 原始服务器可能会 改变它 的IP地址。 假 如你不关心这样的改变, 那 就不必麻烦去升级 squid.conf。你可以在 acl 行里 放上主机名,但那样会延缓启动速度。假如你的 ACL 需要许多主机名,你也许该预处理配 置文件,将主机名转换成 IP地址。 6.1.2.36.1.2.36.1.2.36.1.2.3 myipmyipmyipmyip myip 类型指 Squid 的IP地址,它被客户连接。当你在 squid 机上运行 netstat -n时,你 见到它们位于本地地址列。 大部分 squid 安装不使用该类型。 通常所有的客户连接到同一 个 IP地址,所以该 ACL 元素仅仅当系统有多个 IP地址时才有用。 为了理解 myip 为何有用,考虑某个有两个子网的公司网 络。在子网 1的用户是程序员 和工程师。子网 2包括会计,市场 和其他 管理部 门。这 样情况 下 的 squid 有三个网络接口: 一个连接子网 1,一个连接子网 2,第三个连接到外部因特网。 Figure 6-1. An application of the myip ACL 当正确的配置时,所有在子网 1的用户连接到 squid 位于该子网的 IP地址,类似的,子网 2的用户连接到 squid 的第二个 IP地址。这样你 Squid 中文权威指南 65 就可以给予子网 1的技术部员工完全的访问权,然而限制管理部门的员工仅仅能访问工作相 关的站点。 ACL 可能如下: acl Eng myip 172.16.1.5 acl Admin myip 172.16.2.5 然而请注意, 使用该机制你必须特别小心, 阻止来自某个子网的用户连接 squid 位于 另 一子网的 IP地址。 否 则, 在会计和市场子网的聪明的用户, 能 够通过技术部子网进行连接 , 从而绕过你的限制。 6.1.2.46.1.2.46.1.2.46.1.2.4 dstdomaindstdomaindstdomaindstdomain 在某些情况下, 你 发现基于名字的访问控制非常有用。 你 可以使用它们去阻塞对某些 站 点的访问,去控制 squid 如何转发请求,以及让某些响应不可缓存 。 dstdomain 之所以非常 有用,是因为它检查请求 url 里的主机名。然而首先我想申明如下两行的不同: acl A dst www.squid-cache.org acl B dstdomain www.squid-cache.org A实际上是 IP地址 ACL。当 Squid 解析配置文件时, 它 查询 www.squid-cache.org 的IP 地址,并将它们存在内存里。它不保存名字。假如在 squid 运行时 IP地址改变了, squid 会 继续使用旧的地址。 然而 dstdomainACL 以域名形式存储, 并非 IP地址。 当 squid 检查 ACLB时, 它对 URL 的主机名部分使用字符串比较功能。 在 该情形下, 它 并不真正关心是否 www.squid-cache.org 的IP地址改变了。 使用 dstdomainACL 的主要问题是某些 URL 使用 IP地址代替主机名。 假 如你的目标 是 使用 dstdomainACL 来阻塞对某些站点的访问,聪明的用户能 手工查询站点 的 IP地址,然 后将它们放在 URL 里。例如,下面的 2行URL 带来同样的页面: http://www.squid-cache.org/docs/FAQ/ http://206.168.0.9/docs/FAQ/ 第一行能被 dstdomainACL 轻 易 匹 配 , 但第 二 行 不 能 。 这样 , 假如 你 依 靠 dstdomain ACL, 你也该同样阻塞所有使用 IP地址代替主机名的请求。请见 6.3.8章节。 6.1.2.56.1.2.56.1.2.56.1.2.5 srcdomainsrcdomainsrcdomainsrcdomain srcdomainACL 也有点麻烦。它要求对每个客户 IP地址进行所谓的反向 DNS 查询。技 术上,squid 请求对该地址的 DNSPTR记录。DNS 的响应 --完整可验证域名 (FQDN)--是squid Squid 中文权威指南 66 匹配 ACL 值 的 东 西 。 (请 参 考 O'Reilly's DNS and BIND 找到更多关于 DNSPTR记录的信息 ) 使用 dstACL,FQDN 查询会导致延时。 请 求会被延缓处理直到 FQDN 响应返回。 FQDN 响应 被缓存下来,所以 srcdomain 查询通常仅在客户首次请求时延时。 不幸的是, srcdomain 查询有时不能工作。许多组织并没有保持他们的反向查询数据库 与日更新。假如某地址没有 PTR记录, ACL 检查失败。在该情形下,请求可能会延时非 常 长时间 ( 例如 2分钟) 直到 DNS 查询超时。 假 如你使用 srcdomainACL, 请 确认你自己的 DNS in-addr.arpa 区域配置正确并且在工作中。假如这样,你可以使用如下的 ACL: acl LocalHosts srcdomain .users.example.com 6.1.2.66.1.2.66.1.2.66.1.2.6 portportportport 你很可能想使用 portACL 来限制对某些原始服务器端口号的访问。 就 像我即将讲到的 , squid 其实不连接到某些服务,例如 email 和IRC 服务。 portACL 允许你定义单独的端口或 端口范围。例如: acl HTTPports port 80 8000-8010 8080 HTTP 在设计上与其他协议类似,例如 SMTP。这意味着聪明的用户通过转发 email 消 息到 SMTP服务器能欺骗 squid。Email转发是垃圾邮件的主要原 因之一, 我们必须处理 它 们。 历 史上, 垃圾邮件有真正的邮件服务器。 然 而近来, 越来越多的垃圾邮件制造者使用 开 放HTTP代理来隐藏他们的踪迹。你肯定不想 Squid 被当成垃圾邮件转发器。假如是这样 , 你的 IP地址很可能被许多邮件转发黑名单冻结 ( MAPS,ORDB,spamhaus 等)。除email 之外, 还有其他许多 TCP/IP服务是 squid 不与其通信的。 这 些 包括 IRC,Telnet,POP,和NNTP。你 的 针对端口的策略必须被配置成拒绝已 知危险端口, 并 允许剩下的; 或 者允许已知安全端口 , 并拒绝剩下的。 我的态度比较保守,仅仅允 许安全的端 口。默认 的 squid.conf 包含了下面的安全端 口 ACL: acl Safe_ports port 80 # http acl Safe_ports port 21 # ftp acl Safe_ports port 443 563 # https, snews acl Safe_ports port 70 # gopher acl Safe_ports port 210 # wais acl Safe_ports port 1025-65535 # unregistered ports acl Safe_ports port 280 # http-mgmt Squid 中文权威指南 67 acl Safe_ports port 488 # gss-http acl Safe_ports port 591 # filemaker acl Safe_ports port 777 # multiling http http_access deny !Safe_ports 这是个较明智的配置。它允许用户连接到任何非特权端口( 1025-65535) ,但 仅 仅 指 定的特权端口可以被连接。假如你的用户试图访问某个 URL 如下: http://www.lrrr.org:123/, squid 会返回访问拒绝错误消息。在某些情形下,为了让你的用户满意,你可能需要增加另 外的端 口号。 宽松的做法是,拒绝对特别危险的端口的访问。 Squid FAQ包括了如下示例: acl Dangerous_ports 7 9 19 22 23 25 53 109 110 119 http_access deny Dangerous_ports 使用Dangerous_ports的弊端是 squid 对几乎每个请求都要搜索整个列表。 这对 CPU 造 成了额外的负担。 大多数情况下, 99%到达 squid 的请求是对 80端口的, 它不出现在危险 端 口列表里。 所 有请求对该表的搜索不会导致匹配。 当然, 整 数比较是快速的操作, 不会显 然 影响性能。 (译 者注:这里的意思是,两者都要对列表进行搜索和匹配。在第一种情况下,它搜 索安全端口列表并匹配 80,显然第一个元素就匹配成功了。而第二种情况中,会搜 索危险 端口列表并试图匹配 80, 当 然危险端口不会包括 80, 所 以每次对 80的请求都要搜索完整个 列 表,这样就会影响性能。 ) 6.1.2.76.1.2.76.1.2.76.1.2.7 myportmyportmyportmyport squid 也有 myport ACL。port ACL 指向原始服务器的端口号, myport 指向 squid 自己的 端口号, 用以接受客户请求。 假 如你在 http_port 指令里指定不止一个端口号, 那么 squid 就 可以在不同的端口上侦听。 假如你将 squid 作为站点 HTTP加速器和用户代理服务器, 那么 myportACL 特别有用 。 你可以在 80上接受加速请求, 在 3128上接受代理请求。 你 可能想让所有人访问加速器, 但 仅 仅你自己的用户能以代理形式访问 squid。你的 ACL 可能如下: acl AccelPort myport 80 acl ProxyPort myport 3128 acl MyNet src 172.16.0.0/22 Squid 中文权威指南 68 http_access allow AccelPort # anyone http_access allow ProxyPort MyNet # only my users http_access deny ProxyPort # deny others 6.1.2.86.1.2.86.1.2.86.1.2.8 methodmethodmethodmethod method ACL 指HTTP请求方法。 GET 是典型的最常用方法,接下来是 POST,PUT,和 其他。下例说明如何使用 method ACL: acl Uploads method PUTPOST Squid 知道下列标准 HTTP方法:GET,POST,PUT,HEAD,CONNECT,TRACE,OPTIONS 和DELETE。另外 , squid 了解下 列来 自 WEBDAV 规范, RFC 2518的方法 : PROPFIND, PROPPATCH,MKCOL,COPY,MOVE,LOCK,UNLOCK。某些 Microsoft 产品使用非标准的 WEBDAV 方法,所以 squid 也了解它们: BMO VE, BDELETE,BPROPFIND。最后, 你可 以 在extension_methods 指令里配置 squid 去理解其他的请求方法。请见附录 A。 注意 CONNECT 方法非常特殊。它是用于通 过 HTTP 代理来封装某种请求的方法(请 见RFC 2817:Upgrading to TLS Within HTTP/1.1)。在处理CONNECT 方法和远程服务器的 端 口号时应特别谨慎。 就像前面章节讲过的一样,你不希望 squid 连接到某些远程服务。 你 该 限制 CONNECT 方法仅仅能连接到 HTTPS/SSL或NNTPS端口(443和563)。默认的squid.conf 这样做: acl CONNECT method CONNECT acl SSL_ports 443 563 http_access allow CONNECT SSL_ports http_access deny CONNECT 在该配 置里 , squid 仅仅允 许加 密 请求 到 端口 443(HTTPS/SSL)和 563(NNTPS)。 CONNECT 方法对其他端口的请求都被拒绝。 PURGE 是另一个特殊的请求方法。它是 Squid 的专有方法,没有在任何 RFC 里定义。 它让管理员能强制删除缓存对象。既然该方法有些危险, squid 默认拒绝 PURGE 请求,除 非你定义了 ACL 引用了该方法。否则 ,任何能 访 问 cache 者也许能够删除任意 缓存对象。 我推荐仅仅允许来自 localhost 的PURGE: acl Purge method PURGE acl Localhost src 127.0.0.1 Squid 中文权威指南 69 http_access allow Purge Localhost http_access deny Purge 关于从 squid 的缓存里删除对象,请见 7.6章。 6.1.2.96.1.2.96.1.2.96.1.2.9 protoprotoprotoproto 该类型指 URI 访问(或传输) 协议。如下是有效值: http, https(same as HTTP/TLS), ftp, gopher, urn, whois, 和cache_object。 也 就是说, 这 些是被 squid 支持的 URL 机制名字。 例 如, 假如你想拒绝所有的 FTP请求,你可以使用下列指令: acl FTP proto FTP http_access deny FTP cache_object 机制是 squid 的特性。它用于访问 squid 的缓存管理接口,我将在 14.2章讨 论它。 不幸的是,它并非好名字, 可能会被改变。默认的 squid.conf 文件有许多行限制缓 存 管理访问: acl Manager proto cache_object acl Localhost src 127.0.0.1 http_access allow Manager Localhost http_access deny Manager 这些配置行仅允许来自本机地址的缓存管理请求, 所 有其他的缓存管理请求被拒绝。 这 意味着在 squid 机器上有帐号的人, 能访问到潜在的敏感缓存管理信息。 你也许想修改缓 存 管理访问控制,或对某些页面使用密码保护。我将在 14.2.2章里谈论到。 6.1.2.106.1.2.106.1.2.106.1.2.10 timetimetimetime time ACL 允许你控制基于 时间的 访问, 时间为 每天中 的具体 时间, 和每周 中的每 天。 日期以单字母来表示, 见 如下表。 时间以 24小时制来表示。 开 始时间必须小于结束时间, 这 样在编写跨越 0点的 time ACL 时可能有点麻烦。 Table 6-2. Day codes for the time ACL C ode Day Squid 中文权威指南 70 日期和时间由 localtime()函数来产生。 请确认你的计算机位于正确的时区,你也该让 你 的时钟与标准时间同步。 为了编写 time ACL 来匹配你的工作时间,你可以这样写: acl Working_hours MTWHF 08:00-17:00 or: acl Working_hours D 08:00-17:00 让我们看一个麻烦的例子。 也许你是某个 ISP, 在下午 8点到早上 4点这段不忙的时间 内 放松访问。 既然该时间跨越子夜, 你不能编写 “20:00-04:00”。 代替的, 你需要把它们分成 两 个ACL 来写,或者使用否定机制来定义非忙时。例如: acl Offpeak1 20:00-23:59 S Sunday M Monday T Tuesday W Wednesday H Thursday F Friday A Saturday D All weekdays (M-F) Squid 中文权威指南 71 acl Offpeak2 00:00-04:00 http_access allow Offpeak1 ... http_access allow Offpeak2 ... 另外,你可以这样写: acl Peak 04:00-20:00 http_access allow !Peak ... 尽管 squid 允许,你也不应该在同一个 time ACL 里放置多个日期和时间范围列表。对 这些 ACL 的解析不一定是你想象的那样。例如,假如你输入: acl Blah time M 08:00-10:00 W 09:00-11:00 实际能做到的是: acl Blah time MW 09:00-11:00 解析仅仅使用最后一个时间范围。正确的写法是,将它们写进两行: acl Blah time M 08:00-10:00 acl Blah time W 09:00-11:00 6.1.2.116.1.2.116.1.2.116.1.2.11 identidentidentident ident ACL 匹配被 ident 协议返回的用户名。这是个简单的协议,文档是 RFC 1413。它 工作过程如下: • 1.用户代理(客户端)对 squid 建立 TCP 连接。 • 2.squid 连接到客户系统的 ident 端口( 113)。 • 3.squid 发送一个包括两个 TCP 端口号的行。 squid 端的端口号可能是 3128(或 者你在 squid.conf 里配置的端口号) , 客户端的端口号是随机的。 • 4.客户端的 ident 服务器返回打开第一个连接的进程的用户名。 • 5.squid 记录下用户名用于访问控制目的,并且记录到 access.log。 当squid 遇到对特殊请求的 ident ACL 时,该请 求被延时,直到ident 查询完成。这样,ident Squid 中文权威指南 72 ACL 可以对你的用户请求造成延时。 我们推荐仅仅在本地局域网中, 并且大部分客户工作站运行 ident 服务时, 才使用 ident ACL。 假如 squid 和客户工作站连在一个局域网里, ident ACL 工作良好。 跨 广域网使用 ident 难以成功。 ident 协议并非很安全。 恶意的用户能替换他们的正常 ident 服务为假冒服务, 并返回 任 意的他们选择的用户名。 例如, 假 如我知道从 administrator 用户的连接总是被允许, 那么 我 可以写个简单的程序,在回答每个 ident 请求时都返回这个用户名。 你可以使用 ident ACL 拦截 cache(请见第 9章)。当squid 被配置成拦截 cache 时,操 作系统假设它自己是原始服务器。 这意味着用于拦截 TCP 连接的本地 socket 地址有原始 服 务器的 IP地址。假如你在 squid 上运行 netstat -n时,你可以看到大量的外部 IP地址出现 在 本地地址栏里。当 squid 发起一个 ident 查询时,它创建一个新的 TCP 套接字,并绑定本地 终点到同一个 IP地址上, 作 为客户 TCP 连接的本地终点。 既 然本地地址并非真正是本地 的 (它可能与原始服务器 IP地址相距遥远),bind()系统调用失败。squid 将这个作为失败的 ident 查询来处理。 注意 squid 也有个特性, 对客户端执行懒惰 ident 查询。 在该情形下,在等待 ident 查询 时,请求不会延时。在 HTTP 请求完成时, squid 记录 ident 信息,假如它可用。你能使 用 ident_lookup_access指令来激活该特性,我将在本章后面讨论。 6.1.2.126.1.2.126.1.2.126.1.2.12 proxy_authproxy_authproxy_authproxy_auth squid 有一套有力的,在某 种程度上 有点混 乱的特性 ,用以支 持 HTTP 代理验证功能。 使用代理验证,客户的包括头部 的 http 请求包含了验证信用选项。通常,这简单 的是用户 名和密码。 squid 解密信用选项,并调用外部验证程序以发现该信用选项是否有效。 squid 当前支持三种技术以接受用户验证: HTTP基本协议, 数字认证协议,和 NTLM。 基本认证已经发展了相当长时间。 按 今天的标准, 它 是非常不安全的技术。 用 户名和密码 以 明文同时发送。 数 字认证更安全, 但也更复杂。 基 本和数字认证在 RFC 2617文档里被描述 。 NTLM 也比基本认证更安全。然而,它 是 Microsoft 发展的专有协议。少数 squid 开发者已 经基本完成了对它的反向工程。 为了使用代理验证,你必须配 置 squid 使用大量的外部辅助程序。 squid 源代码里包含 了一些程序, 用 于对许多标准数据库包括 LDAP,NTLM,NCSA 类型的密码文件, 和 标准 Unix 密码数据库进行认证。 auth_param 指令控制对所有辅助程序的配置。我将在 12章里讨 论这 些细节。 auth_param 指令和 proxy_auth ACL 是少数在 配置 文件 里顺 序重 要的 实 例。 你必 须 在 proxy_auth ACL 之前定义至少一个验证辅助程序(使用 auth_param) 。 假如你没有这样做, squid 打印出错误消息,并且忽略 proxy_auth ACL。这并非致命错误,所以 squid 可以启动 , 但所有你的用户的请求可能被拒绝。 Squid 中文权威指南 73 proxy_auth ACL 取用户名作为值。然而,大部分安装里简单的使用特殊值 REQUIRED: auth_param ... acl Auth1 proxy_auth REQUIRED 在该情况中,任何具有有效信用选项的请求会匹配该 ACL。假如你需要细化控制,你 可以指定独立的用户名: auth_param ... acl Auth1 proxy_auth allan bob charlie acl Auth2 proxy_auth dave eric frank 代理验证不支持 HTTP拦截, 因 为用户代理不知道它在与代理服务器, 而 非原始服务 器 通信。用户代理不知道在请求里发送 Proxy-Authorization 头部。见 9.2章更多细节。 6.1.2.136.1.2.136.1.2.136.1.2.13 src_assrc_assrc_assrc_as 该类型检查客户源 IP地址所属的具体 AS 号(见6.1.1.6关于 squid 如何将 AS 号映射到 IP 地址的信息)。 作为示例,我们虚构某ISP使用AS 64222 并且通告使用 10.0.0.0/8,172.16.0.0/12,192.168.0.0/16网络。你可以编写这样的 ACL,它允许来自该 ISP地 址空间的任何主机请求: acl TheISP src 10.0.0.0/8 acl TheISP src 172.16.0.0/12 acl TheISP src 192.168.0.0/16 http_access allow TheISP 当然,你还可以这样写: acl TheISP src_as 64222 http_access allow TheISP 第二种写法不但更短,而且假如 ISP增加了新的网络,你不必更新 ACL 配置。 6.1.2.146.1.2.146.1.2.146.1.2.14 dst_asdst_asdst_asdst_as dst_asACL 经常与 cache_peer_access指令一起使用。 在该方法中, squid 使用与 IP路由 Squid 中文权威指南 74 一致的方式转发 cache丢失。 考虑某 ISP, 它比 其他 ISP更频繁的更换路由。 每个 ISP处理 他们自己的 cache代理,这些代理能转发请求到其他代理。 理论上, ISPA将ISPB网络里 主机的 cache丢失转发到 ISPB的cache代理。使用 AS ACL 和cache_peer_access指令容易 做到这点: acl ISP-B-AS dst_as 64222 acl ISP-C-AS dst_as 64333 cache_peer proxy.isp-b.net parent 3128 3130 cache_peer proxy.isp-c.net parent 3128 3130 cache_peer_access proxy.isb-b.net allow ISP-B-AS cache_peer_access proxy.isb-c.net allow ISP-C-AS 我将在第 10章里讨论更多关于 cache协作。 6.1.2.156.1.2.156.1.2.156.1.2.15 snmp_communitysnmp_communitysnmp_communitysnmp_community snmp_community ACL 对SNMP 查询才有意义,后者 被 snmp_access 指令控制。例如, 你可以这样写: acl OurCommunityName snmp_community hIgHsEcUrItY acl All src 0/0 snmp_access allow OurCommunityName snmp_access deny All 在该情况中,假如 community 名字设置为 hIgHsEcUrItY,SNMP 查询才被允许。 6.1.2.166.1.2.166.1.2.166.1.2.16 maxconnmaxconnmaxconnmaxconn maxconn ACL 指来自客户 IP地址的大量同时连接。某些 squid 管理员发现这是个有用 的方法,用以阻止用户滥用代理或者消耗过多资源。 maxconn ACL 在请求超过指定的数量时, 会匹配这个 请求。因为 这个理由, 你应该仅 仅在 deny 规则里使用 maxconn。考虑如下例子: acl OverConnLimit maxconn 4 Squid 中文权威指南 75 http_access deny OverConnLimit 在该情况中, squid 允许来自每个 IP地址的同时连接数最大为 4个。当某个客户发起第 五个连接时, OverConnLimit ACL 被匹配, http_access规则拒绝该请求。 6.1.2.176.1.2.176.1.2.176.1.2.17 arparparparp arp ACL 用于检测 cache 客户端的 MAC 地址(以太网卡 的物理 地址) 。地址解析协议 (ARP)是主机查找对应于 IP地址的 MAC 地址的方法。某些大学学生发现,在 Microsoft Windows 下,他们可以 改变 系统 的 IP地址到任意值 ,然 后欺 骗 squid 的基于地址的 控制。 这时 arp 功能就派上用场了,聪明的系统管理员会配置 squid 检查客户的以太网地址。 不幸的是, 该 特性使用非移植性代码。 假 如你运行 Solaris 或Linux, 你 能使用 arp ACL。 其他系统不行。当你运行 ./configure 时增加 --enable-arp-acl 选项,就可以激活该功能。 arp ACL 有另一个重要限制。 ARP 是数据链路层协议,假如客户主机和 squid 在同一 子 网,它才能工作。你不容易发现不同子网主机的 MAC 地址。假如在 squid 和你的用户之间 有路由器存在,你可能不能使用 arpACL。 现在你知道何时去使用它们, 让 我们看看 arpACL 实际上是怎样的。 它 的值是以太网 地 址,当使用 ifconfig 和arp 时你能看到以太网地址。例如: acl WinBoxes arp 00:00:21:55:ed:22 acl WinBoxes arp 00:00:21:ff:55:38 6.1.2.186.1.2.186.1.2.186.1.2.18 srcdom_regexsrcdom_regexsrcdom_regexsrcdom_regex srcdom_regex ACL 允许你使用正则表达式匹配客户域名。 这与 srcdomain ACL 相似, 它 使用改进的的子串匹配。 相 同的限制是: 某些客户地址不能反向解析到域名。 作 为示例, 下 面的 ACL 匹配以 dhcp 开头的主机名: acl DHCPUser srcdom_regex -i ^dhcp 因为领头的^符号,该ACL 匹配主机名dhcp12.example.com ,但不匹配 host12.dhcp.example.com。 6.1.2.196.1.2.196.1.2.196.1.2.19 dstdom_regexdstdom_regexdstdom_regexdstdom_regex dstdom_regex ACL 也与 dstdomain 相似。下面的例子匹配以 www 开头的主机名: acl WebSite dstdom_regex -i ^www\. 如下是另一个有用的正则表达式,用以匹配在 URL 主机名里出现的 IP地址: Squid 中文权威指南 76 acl IPaddr dstdom_regex [0-9]$ 这样可以工作,因为 squid 要求 URL 主机名完全可验证。既然全局顶级域名中 没有以 数字结尾的,该 ACL 仅仅匹配 IP地址,它以数字结尾。 6.1.2.206.1.2.206.1.2.206.1.2.20 url_regexurl_regexurl_regexurl_regex url_regexACL 用于匹配请求 URL 的任何部分, 包 括传输协议和原始服务器主机名。 例 如,如下 ACL 匹配从 FTP服务器的 MP3文件请求: acl FTPMP3 url_regex -i ^ftp://.*\.mp3$ 6.1.2.216.1.2.216.1.2.216.1.2.21 urlpath_regexurlpath_regexurlpath_regexurlpath_regex urlpath_regex 与url_regex 非常相似,不过传输协议和 主机名不包 含在匹配条 件里。这 让某些类型的检测非常容易。例如, 假设你必须拒绝 URL 里的 "sex",但仍允许在主机名 里 含有 "sex"的请求,那么这样做: acl Sex urlpath_regex sex 另一个例子,假如你想特殊处理 cgi-bin 请求,你能这样捕获它们: acl CGI1 urlpath_regex ^/cgi-bin 当然, CGI 程序并非总在 /cgi-bin/目录下,这样你应该编写其他的 ACL 来捕获它们。 6.1.2.226.1.2.226.1.2.226.1.2.22 browserbrowserbrowserbrowser 大部分 HTTP请求包含了 User-Agent 头部。该头部的值典型如下: Mozilla/4.51 [en] (X11; I; Linux 2.2.5-15 i686) browser ACL 对user-agent 头执行正则表达式匹配。 例 如, 拒 绝不是来自 Mozilla 浏览 器 的请求,可以这样写: acl Mozilla browser Mozilla http_access deny !Mozilla 在使用 browser ACL 之前,请确认你完全理解 cache接受到的 User-Agent 字符串。某 些user-agent 与它们的来源相关。 甚至 squid 可以重写它转发 的请求的 User-Agent 头部。 某 些浏览器例如 Opera 和KDE 的Konqueror,用户可以对不同的原始服务器发送不同的 user- agent 字串,或者干脆忽略它们。 Squid 中文权威指南 77 6.1.2.236.1.2.236.1.2.236.1.2.23 req_mime_typereq_mime_typereq_mime_typereq_mime_type req_mime_type ACL 指客户 HTTP请求里的 Content-Type头部。 该 类型头部通常仅仅 出 现在请求消息主体里。 POST和PUT 请求可能包含该头部,但 GET 从不。 你 能使用该类 型 ACL 来检测某些文件上传, 和 某些类型的 HTTP隧道请求。 req_mime_type ACL 值是正则 表 达式。你可以这样编写 ACL 去捕获音频文件类型: acl AuidoFileUploads req_mime_type -i ^audio/ 6.1.2.246.1.2.246.1.2.246.1.2.24 rep_mime_typerep_mime_typerep_mime_typerep_mime_type 该类 型 ACL 指原 始 服 务 器 的 HTTP 响应 里 的 Content-Type 头部 。 它 仅 在 使 用 http_reply_access 规则时才有用。 所 有的其他访问控制形式是基于客户端请求的。该 ACL 基 于服务器响应。假如你想使用 squid 阻塞 Java代码,你可以这样写: acl JavaDownload rep_mime_type application/x-java http_reply_access deny JavaDownload 6.1.2.256.1.2.256.1.2.256.1.2.25 ident_regexident_regexident_regexident_regex 在本节早些时讲过 ident ACL。ident_regex 允许你使用正则表达式,代替严格的字符串 匹配, 这 些匹配是对 ident 协议返回的用户名进行。 例 如, 如下 ACL 匹配包含数字的用户 名: acl NumberInName ident_regex [0-9] 6.1.2.266.1.2.266.1.2.266.1.2.26 proxy_auth_regexproxy_auth_regexproxy_auth_regexproxy_auth_regex 该ACL 允许对代理认证用户名使用正则表达式。例如,如下ACL 匹配 admin,administrator 和administrators: acl Admins proxy_auth_regex -i ^admin 6.1.36.1.36.1.36.1.3 外部ACLACLACLACL Squid 2.5版本介绍了一个新特性: 外部 ACL。 你可以指示 squid 发送某些信息片断到 外 部进程,然后外部的辅助程序告诉 squid,数据匹配或不匹配。 squid 附带着大量的外部 ACL 辅助程序; 大 部分用于确定命名用户是不是某个特殊组 的 成员。 请见 12.5章关于这些程序的描述, 以及关于如何编写你自己的程序的信息。现在, 我 解释如何定义和使用外部 ACL 类型。 Squid 中文权威指南 78 external_acl_type 指令定义新的外部 ACL 类型。如下是通用语法: external_acl_type type-name [options] format helper-command type-name 是用户定义的字 串。你 也可以 在 acl 行里引用它。 Squid 当前支持如下选项 (options): ttl=n 时间数量,单位是秒,用以缓存匹配值的时间长短。默认是 3600秒,或 1小时。 negative_ttl=n 时间数量,单位是秒,用以缓存不匹配值的时间长短。默认是 3600秒,或 1小时。 concurrency=n 衍生的辅助程序的数量,默认是 5。 cache=n 缓存结果的最大数量。默认是 0,即不限制 cache大小。格式是以 %字符开始的一个或 多个关键字。 squid 当前支持如下格式: %LOGIN 从代理验证信用选项里获取的用户名。 %IDENT 从RFC 1413 ident 获取的用户名。 %SRC 客户端 IP地址。 %DST 原始服务器 IP地址。 %PROTO 传输协议(例如 HTTP,FTP 等) Squid 中文权威指南 79 %PORT 原始服务器的 TCP 端口。 %METHOD HTTP请求方法。 %{Header} HTTP请求头部的值;例如, %{User-Agent}导致 squid 发送这样的字串到验证器: "Mozilla/4.0 (compatible; MSIE 6.0; Win32)" %{Hdr:member} 选择某些数量的 基于列 表 的 HTTP 头部,例如 Caceh-Control;例如,给出如 下 HTTP 头部: X-Some-Header: foo=xyzzy, bar=plugh, foo=zoinks 对%{X-Some-Header:f oo}的取值, squid 发送这样的字串到外部 ACL 进程: foo=xyzzy, foo=zoinks %{Hdr:;member} 与%{Hdr:member}相同, 除 了 ";"是列表分隔符外。 你 能使用任何非字母数字的字符作 为 分隔符。辅助命令是 squid 为辅助程序衍生的命令。你也可以在这里 包含命令参数。例 如, 整条命令可能类似如此: /usr/local/squid/libexec/my-acl-prog.pl -X-5 /usr/local/squid/etc/datafile 将这些放在一个长行里。 squid 不支持如下通过反斜杠分隔长行的技术,所以请记住所 有这些必须放在单行里: external_acl_type MyAclType cache=100 %LOGIN%{User-Agent} \ /usr/local/squid/libexec/my-acl-prog.pl -X-5 \ /usr/local/squid/share/usernames \ /usr/local/squid/share/useragents 现在你知道如何定义外部 ACL,下一步是编写引 用 它的 acl 行。这相对容易,语法如下: Squid 中文权威指南 80 acl acl-name external type-name [args ...] 如下是个简单示例: acl MyAcl external MyAclType squid 接受在 type-name 后面的任意数量的参数。 这些在每个请求里被发送到辅助程序 。 请见 12.5.3章,我描述了 unix_group 辅助程序,作为该功能的示例。 6.1.46.1.46.1.46.1.4 处理 长 ACL ACL ACL ACL 列表 ACL 列表某些时候非常长。 这 样的列表在 squid.conf 文件里难以维护。 你 也可能想从 其 他资源里自动产 生 squidACL 列表。在如此情况下 ,你可以 从外部 文件里包 含 ACL 列表。 语法如下: acl name "filename" 这里的双引号指示 squid 打开 filename, 并且将它里面的内容分配给 ACL。 例如,如 下 的ACL 太长了: acl Foo BadClients 1.2.3.4 1.2.3.5 1.2.3.6 1.2.3.7 1.2.3.9 ... 你可以这样做: acl Foo BadClients "/usr/local/squid/etc/BadClients" 将IP地址放在 BadClients 文件里: 1.2.3.4 1.2.3.5 1.2.3.6 1.2.3.7 1.2.3.9 ... 文件可以包含以 #开头的注释。 注 意在该文件里的每个 IP地址必须是一个单独的行。 acl 行里的任何地方,以空格来分隔值,新行是包含 ACL 值的文件的分界。 Squid 中文权威指南 81 6.1.56.1.56.1.56.1.5 SquidSquidSquidSquid如何匹配访问控制 元素 理解 squid 如何搜索 ACL 元素去匹配是很重要的。当 ACL 元素有多个值时, 任何单 个 值能导致匹配。换句话说, squid 在检查 ACL 元素值时使用 OR 逻辑。当 squid 找到第一个 值匹配时,它停止搜索。这意味着把最可能匹配的值放在列表开头处,能减少延时。 让我们看一个特殊的例子,考虑如下 ACL 定义: acl Simpsons ident Maggie Lisa Bart Marge Homer 当squid 在访问列表里遇到 Simpsons ACL 时, 它 执行 ident 查询。 让 我们看一下, 当 用 户ident 服务返回 Marge 时,会发生什么呢? squid 的ACL 代码在成功匹配 Marge 前, 会 先后将这个值与 Maggie,Lisa,和Bart 对比。当搜索完成时,我们认 为 Simpsons ACL 匹配了 这个请求。 实际上,这有点欺骗。 ident ACL 值并非存储在无序列表里。它们存储在 splay tree 中。 这意味着, 在 非匹配事件中, squid 不会搜索完所有的名字。 对 一个 splay tree搜索 N个条 目 需要记录 N个比较。 许多其他的 ACL 类型也使用 splay tree。 然而, 基 于正则表达式的类 型 不使用。 既然正则表达式不能这样存储,它们以链表形式存储。这使得在大链表里它们特别低 效, 特 别是不匹配链表里任何正则表达式的请求。 为 了改进这个形式, 当 匹配发生 时,squid 将正则表达式移到列表的顶部。 实 际上, 因为 ACL 匹配代码的天然特性, squid 将匹配的 条 目移到列表的第二个位置。 这 样, 普 通的匹配值自 然移到 ACL 列表的顶部, 这 样会减少 比 较数量。 让我们看另一个简单示例: acl Schmever port 80-90 101 103 107 1 2 3 9999 该ACL 匹配到原始服务器 80-90端口, 和 其他独立端口的请求。 对 80端口的请求, squid 通过查看第一个值就匹配了该 ACL。对9999端口, 其他每 个值都先被检查。 对某个不在 列 表里的端口, squid 要检查所有值才宣布它不匹配。就像我已经讲过的,将最常用的值放在 第一位能优化 ACL 匹配。 6.26.26.26.2 访问 控制 规则 前面提过, ACL 元素是建立访问控制的第一步。第二步是访问控制规则,用来允许或 拒绝某些动作。在早先的例子里,你已见过 http_access规则。 squid 有大量其他的访问控制 Squid 中文权威指南 82 列表: http_access 这是最重要的访问控制列表。 它 决定哪些客户 HTTP请求被允许, 和 哪些被拒绝。 假 如 http_access配置错误, squid cache容易遭受攻击或被不当利用。 http_reply_access http_reply_access 与http_access类似。不同之处是前者在 squid 接受到来自原始服务器 或上级代理的响应时 ,才会被 检测。 大部分访 问控制基 于客户请 求的方 式,对 这些使用 http_access就够了。 然而, 某 些人喜欢基于响应内容类型来允许或拒绝请求。 更多信息请 见 6.3.9章。 icp_access 假如你的 squid 被配置来服务 ICP 响应 (见 10.6章) , 那 么该使用 icp_access列表。 大 部 分情况下,你该仅仅允许来自邻居 cache的ICP 请求。 no_cache 你能使用 no_cache 访问列表来指 示 squid ,它不必存储某 些响应 (在磁 盘或内 存里) 。 该列表典型的与 dst,dstdomain,url_regexACL 结合使用。 对no_cache使用 "否"条件,这样的双重否定会导致某些混乱。被 no_cache列表拒绝的 请求不被缓存。换句话说, no_cache deny...是让目标不被缓存。见 6.3.10章的示例。 miss_access miss_access 列表主要用于 squid 的邻居 cache。 它决 定 squid 怎样处理 cache丢失的请 求。 如果 squid 使用集群技术,那么该功能必需。见 6.3.7的示例。 redirector_access 该访问列表决定哪个请求被发送到重定向进程 ( 见 11章 ) 。 默认 情 况 下 ,假如 你 使 用 重 定向器, 那么所有的请求都通过重定向器。 你可以使用 redirector_access 列表来阻止某些 请 求被重写。 这 点特别有用, 因为这样的访问列表, 使 重定向器相对于访问控制系统, 接受 的 请求信息要少一 些。 ident_lookup_access ident_lookup_access列表与 redirector_access 类似。它允许你对某些请求执行懒 惰 ident 查询。 squid 默认不发 布 ident 查询。假如 请求 被 ident_lookup_access 规则(或 ident ACL) 允许,那么 squid 才会进行 ident 查询。 Squid 中文权威指南 83 always_direct 该访问列表影响 squid 怎样处理与邻居 cache转发 cache丢失。通常squid 试图转发 cache 丢失到父 cache,和/或squid 使用 ICP 来查找临近 cache响 应 。 然而 , 当请 求 匹 配 always_direct 规则时, squid 直接转发请求到原始服务器。 使用该规则,对 "allow"规则的匹配导致 squid 直接转发请求,见 10.4.4章的更多细节和 示例。 never_direct never_direct 与always_direct相反。 匹 配该列表的 cache丢失请求必须发送到邻居 cache。 这点对在防火墙之后的代理特别有用。使 用该列表, 对"allow"规则的匹配导致 squid 转发 请求到邻居 cache。见 10.4.3章的更多细节和示例。 snmp_access 该访问列表应用到发送给 squid 的SNMP 端口的查询。你能配合该列表使用的 ACL 是 snmp_community 和src。 假如 你 确 实 想 使 用 它 , 那也 能 使 用 srcdomain,srcdom_regex,和src_as。 见14.3章的示例。 broken_posts 该访问列表影响 squid 处理某些 POST请求的方法。某些老的用户代理在请求主 体的 结尾处发送一个特别的回车换行符。那就是说,消息主体比 content-length 头部指示的长度 要多 2个字节。更糟糕的是,某些老的 HTTP服务器实际上依赖于这种不正确的行为。当请 求匹配该访问列表 时, squid 模拟这种客户端并且发送特殊的回车换行符。 Squid 有大量的 使用 ACL 元素的其他配置指令。它们中的某些过去 是全局配置,后被 修改来使用 ACL 以 提供更灵活的控制。 cache_peer_access 该访问列表控制发送到邻 居 cache 的HTTP 请求和 ICP/HTCP 查询。见 10.4.1章的更多 信息和示例。 reply_body_max_size 该访问列表限制对 HTTP响应主体的最大可接受 size。见附录 A的更多信息。 delay_access 该访问规则列表控制是否延时池被应用到某个请求的 cache丢失响应。见附录 C。 tcp_outgoing_address Squid 中文权威指南 84 该访问列表绑定服务端 TCP 连接到指定的本地 IP地址。见附录 A。 tcp_outgoing_tos 该访问列表能设置到原始服 务器和邻 居 cache 的TCP 连接的不同 TOS/Diffserv 值,见 附录 A。 header_access 使用该指令, 你能配置 squid 从它转发的请求里删除某些 HTTP头部。 例如,你也许 想 过滤掉发送到某些原始服务器的请求里的 Cookie 头部。见附录 A。 header_replace 该指令允许你替换,而不是删除, HTTP 头部的内容。例如,你能设置 user-agent 头部 为假值,满足某些原始服务器的要求,但仍保护你的隐私。见附录 A。 6.2.16.2.16.2.16.2.1 访问规则语法 访问控制规则的语法如下: access_list allow|deny [!]ACLname ... 例如: http_access allow MyClients http_access deny !Safe_Ports http_access allow GameSitesAfterHours 当读取配置文件时, squid 仅仅扫描一遍访问控制行。这样,在访问 列表里引 用 ACL 元素之前,你必须在 acl 行里定义它们。甚至,访问列表规则的顺 序也非 常重要。你以怎 样的顺序编写访问列表,那 么 squid 就按怎样的顺序来检查它们。将最常用 的 ACL 放在列 表的开始位置,可以减少 squid 的CPU 负载。 对大部分访问列表, deny 和allow 的意义明显。然而,它们中的某些,却并非如此含 义清楚。 请 谨慎的编写 always_direct,never_direct,和no_cache规则。在always_direct 中,allow 规则意味着匹配的请求直接 转发到原始服务器。 always_direct deny 规则意味着匹配的请求 不强迫发送到原始服务器, 但假如邻居 cache不可到达, 那可能还是会这么做。 no_cache规 则也有点麻烦。这里,你必 须对不必被 cache的请求使用 deny。 Squid 中文权威指南 85 6.2.26.2.26.2.26.2.2 SquidSquidSquidSquid如何匹配访问规则 回想一下 squid 在搜索 ACL 元素时使用的 “或”逻辑。在 acl 里的任何单值都可以导致 匹 配。 然而,访问规则恰好相反。对 http_access和其他规则设置, squid 使用 “与”逻辑。考虑 如下示例: access_list allow ACL1 ACL2 ACL3 对该匹配规则来说, 请求必须匹配 ACL1,ACL2,ACL3中的任何一个。 假如这些 ACL 中 的任何一个不匹配请求, squid 停止搜索该规则,并继续处理下一条。对某个规则来说,将 最少匹配的 ACL 放在首位,能使效率最佳。考虑如下示例: acl A method http acl B port 8080 http_access deny AB 该http_access规则有点低效, 因为 A ACL 看起来比 B ACL 更容易匹配。 反 转顺序应 该 更好,以便 squid 仅仅检查一个 ACL,而不是两个: http_access deny BA 人们易犯的典型错误是编写永不正确的规则。例如: acl A src 1.2.3.4 acl B src 5.6.7.8 http_access allow AB 该规则永不正确, 因 为某个源 IP地址不可能同时等同于 1.2.3.4和5.6.7.8。 这 条规则的 真 正意图是: acl A src 1.2.3.4 5.6.7.8 http_access allow A 对某个 ACL 值的匹配算法是, squid 在访问列表里找到匹配规则时, 搜 索终止。 假如 没 有访问规则导致匹配, 默 认动作是列表里最后一条规则的取反。 例 如, 考 虑如下简单访问 配 置: Squid 中文权威指南 86 acl Bob ident bob http_access allow Bob 假如用户 Mary 发起请求,她会被拒绝。列表里最后的(唯一的)规则 是 allow 规则, 它不匹配用户名 mary。这样,默认的动作是 allow 的取反,故请 求被拒绝。类似的,假如 最后的规则是 deny 规则,默认动作是允许请求。在访问列表的最后加上一条,明确允许或 拒绝所有请求,是好的实际做法。为清楚起 见,以前的示例应该如此写: acl All src 0/0 acl Bob ident bob http_access allow Bob http_access deny All src 0/0ACL 表示匹配每一个和任意类型的请求。 6.2.36.2.36.2.36.2.3 访问列表风格 squid 的访问控制语法非常强大。大多数情况下,你可以使用两种或多种方法来完成同 样的事。通常,你该将更具体的和受限制的访问列表放在首位。例如,如下语句并非很好: acl All src 0/0 acl Net1 src 1.2.3.0/24 acl Net2 src 1.2.4.0/24 acl Net3 src 1.2.5.0/24 acl Net4 src 1.2.6.0/24 acl WorkingHours time 08:00-17:00 http_access allow Net1 WorkingHours http_access allow Net2 WorkingHours http_access allow Net3 WorkingHours http_access allow Net4 Squid 中文权威指南 87 http_access deny All 假如你这样写,访问控制列表会更容易维护和理解: http_access allow Net4 http_access deny !WorkingHours http_access allow Net1 http_access allow Net2 http_access allow Net3 http_access deny All 无论何时,你编写了一个带两个或更多 ACL 元素的规则,建议你在其后紧跟一条相反 的, 更广泛的规则。 例如, 默认的 squid 配置拒绝非来自本机 IP地址的 cache管理请求, 你 也许试图这样写: acl CacheManager proto cache_object acl Localhost src 127.0.0.1 http_access deny CacheManager !Localhost 然而, 这里的问题是, 你没有允许确实来自本机的 cache管理请求。 随后的规则可能 导 致请求被拒绝。如下规则就产生了问题: acl CacheManager proto cache_object acl Localhost src 127.0.0.1 acl MyNet 10.0.0.0/24 acl All src 0/0 http_access deny CacheManager !Localhost http_access allow MyNet http_access deny All 既然来自本机的请求不匹配 MyNet,它被拒绝。编写本规则的更好方法是: Squid 中文权威指南 88 http_access allow CacheManager localhost http_access deny CacheManager http_access allow MyNet http_access deny All 6.2.46.2.46.2.46.2.4 延时检查 某些ACL 不能在一个过程里被检查,因为必要的信息不可用。 ident,dst,srcdomain 和 proxy_auth 类型属于该范畴。当 squid 遇到某个 ACL 不能被检查时,它延迟决定并且发布 对必要信息的查询( IP地址,域名,用户名等) 。当信息可用时, squid 再次在列表的开头 位置检查这些规 则。它不会从前次检查剩下的位置继续。假如可能,你应该将这些最可能 被延时的 ACL 放在规则的顶部,以避免不必要的,重复的检查。 因为延时 的代价太大, squid 会尽可能缓存查询获取的信息。 ident 查询在每个连接里 发生, 而不是在每个请求里。这意味着, 当你使用 ident 查询时, 持续 HTTP连接切实对 你 有利。 DNS 响应的主机名和 IP地址也被缓存, 除 非你使用早期的外部 dnsserver 进程。 代 理 验证信息被缓存,请见 6.1.2.12章节的描述。 6.2.56.2.56.2.56.2.5 减缓和加速规则检查 Squid 内部考虑某些访问规则被快速检查,其他的被减缓检查。区别 是 squid 是否延迟 它的决定, 以 等待附加信息。 换 句话说, 在 squid 查询附加信息时, 某 个减缓检查会被延 时, 例如: • 反向 DNS 查询:客户 IP地址的主机名 •RFC 1413 ident 查询:客户 TCP 连接的用户名 • 验证器:验证用户信用 • DNS 转发查询:原始服务器的 IP地址 • 用户定义的外部 ACL 某些访问规则使用快速检查。例如, icp_access规则被快速检查。为了快速响应 ICP 查 询,它必须被快速检 查。甚至 ,某 些 ACL 类型例如 proxy_auth,对 ICP 查询来说无意义。 下列访问规则被快速检查: header_access Squid 中文权威指南 89 reply_body_max_size reply_access ident_lookup delay_access miss_access broken_posts icp_access cache_peer_access redirector_access snmp_access 下列 ACL 类型可能需要来自外部数据源( DNS,验证器等)的信息,这样与快速的访 问规则不兼容: srcdomain, dstdomain, srcdom_regex, dstdom_regex dst, dst_as proxy_auth ident external_acl_type 这意味着,例如,不能在 header_access规则里使用 ident ACL。 6.36.36.36.3 常见 用法 因为访问控制可能很复杂,本节包含一些示例。它们描述了一些访问控制的普通用法。 你可以在实际中调整它们。 Squid 中文权威指南 90 6.3.16.3.16.3.16.3.1 仅仅允许本地客户 几乎每个 squid 安装后,都限制基于客 户 IP地址的访问。这是保护你的 系统不被滥用 的最好的方法之一。做到这点最容易的方法是, 编写包含 IP地址空间的 ACL,然后允许 该 ACL 的HTTP请求,并拒绝其他的。 acl All src 0/0 acl MyNetwork src 172.16.5.0/24 172.16.6.0/24 http_access allow MyNetwork http_access deny All 也许该访问控制配置过于简单,所以你要 增加更多行。记 住 http_access的顺序至关重 要。不要在 deny all 后面增加任何语句。假如必要,应该在 allow MyNetwork 之前或之后 增 加新规则。 6.3.26.3.26.3.26.3.2 阻止恶意客户 因为某种理由, 你 也许有必要拒绝特定客户 IP地址的访问。 这 种情况可能发生, 例如 , 假如某个雇员或学生发起一个异常耗费网 络带宽或其他资源 的 web 连接,在根本解决这个 问题前,你可以配置 squid 来阻止这个请求: acl All src 0/0 acl MyNetwork src 172.16.5.0/24 172.16.6.0/24 acl ProblemHost src 172.16.5.9 http_access deny ProblemHost http_access allow MyNetwork http_access deny All 6.3.36.3.36.3.36.3.3 内容过滤 阻塞对特定内容的访问是棘手的问题。 通常,使用 squid 进行内容过滤最难的部分, 是 被阻塞的站点列表。 你 也许想自己维护一个这样的列表, 或 从其他地方获取一个。 squid FAQ 的“访问控制 ”章节有链接指向免费的可用列表。 使用这样的列表的 ACL 语法依赖于它的内容。假如列表包含正则表达式,你可能要这 Squid 中文权威指南 91 样写: acl PornSites url_regex "/usr/local/squid/etc/pornlist" http_access deny PornSites 另一方面,假如列表包含原始服务器主机名,那么简单的更改 url_regex 为dstdomain。 6.3.46.3.46.3.46.3.4 在工作时间的受限使用 某些公司喜欢在工作时间限制 web 使用, 为了节省带宽, 或者是公司政策禁止员工 在 工作时做某些事情。 关 于这个最难的部分是, 所 谓合适的和不合适的 internet 使用之间的 区 别是什么。 不幸的是, 我 不能对这个问题作出回答。 在该例子里, 假设你已收集了一份 web 站点域名列表,它包含已知的不适合于 你的站点名,那么这样配置 squid: acl NotWorkRelated dstdomain "/usr/local/squid/etc/not-work-related-sites" acl WorkingHours time D 08:00-17:30 http_access deny !WorkingHours NotWorkRelated 请注意在该规则里首先放置 !WorkingHoursACL。 相对于字符串或列表, dstdomain ACL 产生的性能代价较大,但 time ACL 检查却很简单。下面的例子,进一步理解如何结合如下 方法和前面描述的源地址控制,来控制访问。 acl All src 0/0 acl MyNetwork src 172.16.5.0/24 172.16.6.0/24 acl NotWorkRelated dstdomain "/usr/local/squid/etc/not-work-related-sites" acl WorkingHours time D 08:00-17:30 http_access deny !WorkingHours NotWorkRelated http_access allow MyNetwork http_access deny All 上面的方法可行, 因 为它实现了我们的目标, 在 工作时间内拒绝某些请求, 并 允许来 自 你自己网络的请求。然而,它也许有点低效。注意 NotWorkRelatedACL 在所有请求里被搜 Squid 中文权威指南 92 索,而不管源 IP地址。假如那个列表非常长,在列表里对外部网络请求的搜索,纯粹是浪 费CPU 资源。所以,你该这样改变规则: http_access deny !MyNetwork http_access deny !WorkingHours NotWorkRelated http_accessAllowAll 这里,将代价较大的 检查放在 最后。 试图滥 用 squid 的外部用户不会再浪 费你 的 CPU 资源。 6.3.56.3.56.3.56.3.5 阻止squidsquidsquidsquid与非HTTP HTTP HTTP HTTP 服务器会话 你必须尽可能不让 squid 与某些类型的 TCP/IP服务器通信。例如,永不能够使用 squid 缓存来转发 SMTP传输。我在前面介 绍 port ACL 时提到过这点。然而 ,它是至 关重要 的, 所以再强调一下。 首先, 你必须关注 CONNECT 请求方法。 使用该方法的用户代理, 通过 HTTP代理 来 封装 TCP 连接。 它被创造用于 HTTP/TLS 请求, 这是 CONNECT 方法的主要用途。 某些 用 户代理也可以通过防火墙代理来封装 NNTP/TLS 传输。 所有其他的用法应该被拒绝。 所以 , 你的访问列表,应该仅仅 允许到 HTTP/TLS 和NNTP/TLS 端口的 CONNECT 请求。 第二,你应该阻止 squid 连接到某些服务,例如 SMTP。你也可以开放安全端口和拒绝 危险端口。我对这两种技术给出示例。让我们看看默认的 squid.conf 文件提供的规则: acl Safe_ports port 80 # http acl Safe_ports port 21 # ftp acl Safe_ports port 443 563 # https, snews acl Safe_ports port 70 # gopher acl Safe_ports port 210 # wais acl Safe_ports port 280 # http-mgmt acl Safe_ports port 488 # gss-http acl Safe_ports port 591 # filemaker acl Safe_ports port 777 # multiling http Squid 中文权威指南 93 acl Safe_ports port 1025-65535 # unregistered ports acl SSL_ports port 443 563 acl CONNECT method CONNECT http_access deny !Safe_ports http_access deny CONNECT!SSL_ports Safe_ports ACL 列举了所有的 squid 有合法响应的特权端口 ( 小于 1024) 。 它也 列 举 了 所 有非特权端口范围。注 意 Safe_ports ACL 也包括了安全 HTTP 和NNTP 端口( 443和563), 即使它们也出现在 SSL_portsACL 里。 这是因为 Safe_ports在规则里首先被检查。 假如你 交 换了两个 http_access行的顺序,你也许能从 Safe_ports列表里删 除443和563,但没必要这 么麻烦。与此相似的其他方法是,列举已知不安全的特权端口: acl Dangerous_ports 7 9 19 22 23 25 53 109 110 119 acl SSL_ports port 443 563 acl CONNECT method CONNECT http_access deny Dangerous_ports http_access deny CONNECT!SSL_ports 假如你不熟悉这些奇特的端口号,也不要担心。你可以阅读 unix 系统的 /etc/services 文 件,或者阅读 IANA 的注册 TCP/UDP 端口号列表: http://www.iana.org/assignments/port-numbers 6.3.66.3.66.3.66.3.6 授予某些用户特殊的访 问 使用基于用户名进行访问控制的组织,通常需要授予某些用户特殊的权限。在该简单 示例里,有三个元素: 所有授权用户,管理员用户名,限制访问的 web 站点列 表。正常 的 用户不允许访问受限站点,但管理员有维护这个列表的任务。他们必须连接到所有服务器, 去验证某个特殊站点是否该放到受限站点列表里。如下显示如 何完成这个任务: auth_param basic program /usr/local/squid/libexec/ncsa_auth Squid 中文权威指南 94 /usr/local/squid/etc/passwd acl Authenticated proxy_auth REQUIRED acl Admins proxy_auth Pat Jean Chris acl Porn dstdomain "/usr/local/squid/etc/porn.domains" acl All src 0/0 http_access allowAdmins http_access deny Porn http_access allowAuthenticated http_access deny All 首先, 有 三个 ACL 定义。Authenticated ACL 匹配任何有效的代理验证信用。 Admins ACL 匹配来自用户 Pat,Jean,和Chris 的有效信用。 Porn ACL 匹配某些原始服务器主机名, 它们 在 porn.domains 文件里找到。 该示例有四个访问控制 规则。第 一个仅 仅检 查 Admins ACL,允许所有来 自 Pat,Jean, 和Chris 的请求。对其他用户, squid 转移到下一条规则。对第二条规则,假如 原始主机名 位于 porn.domains 文件,那么该请求被拒绝。对不匹 配 Porn ACL 的请求, squid 转移到第 三条规则。 第 三条规则里, 假如请求包含有效的验证信用, 那 么该请求被允许。 外部验证 器 (这里的 ncsa_auth)决定是否信用有效。 假 如它们无效, 最 后的规则出现, 该 请求被拒 绝。 注意 ncsa_auth 验证器并非必需。你可以使用 12章里描述的任何验证辅助程序。 6.3.76.3.76.3.76.3.7 阻止邻 近 cache cache cache cache 的滥用 假如你使用了 cache集群,你必须付出多余的小心。 cache通常使用 ICP 来发现哪些对 象被缓存在它们的邻居机器上。你仅该接受来自已知授权的邻居 cache的ICP 查询。 更进一步,通过使用 miss_access 规则列表,你能配置 squid 强制限制邻近关系。 squid 仅仅在 cache丢失,没有 cache命中时才检查这些规则。这样,在 miss_access 列表生效前, 所有请求必须首先通过 http_access规则。 在本示例里,有三个独立的 ACL。一个是直接连接到 cache的本地用户;另一个是子 cache, 它 被允许来转发 cache丢失的请求; 第 三个是邻近 cache, 它 必须从不转发导致 cache 丢失的请求。如下是它们如何工作: alc All src 0/0 Squid 中文权威指南 95 acl OurUsers src 172.16.5.0/24 acl ChildCache src 192.168.1.1 acl SiblingCache src 192.168.3.3 http_access allow OurUsers http_access allow ChildCache http_access allow SiblingCache http_access deny All miss_access deny SiblingCache icp_access allowChildCache icp_access allowSiblingCache icp_access deny All 6.3.86.3.86.3.86.3.8 使用IPIPIPIP地址拒绝请求 我在6.1.2.4章节里提过, dstdomain 类型是阻塞对指定原始主机访问的好选择 。然而, 聪明的用户通过替换 URL 主机名成 IP地址,能够绕过这样 的规则。假如你想彻底阻止这 样的 请求,你可能得阻塞所有包含IP地址 的请求。你可以使用重定向器,或者使用 dstdom_regexACL 来完成。例如: acl IPForHostname dstdom_regex ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ http_access deny IPForHostname 6.3.96.3.96.3.96.3.9 http_reply_access http_reply_access http_reply_access http_reply_access 示例 回想一下,当 squid 检查 http_reply_access 规则时,响应的内容类型是唯一的可用新信 息。 这样, 你能保持 http_reply_access 规则简单化。 你只需检查 rep_mime_type ACL。 例如 , 如下示例告诉你如何拒绝某些内容类型的响应: acl All src 0/0 acl Movies rep_mime_type video/mpeg Squid 中文权威指南 96 acl MP3s rep_mime_type audio/mpeg http_reply_access deny Movies http_reply_access deny MP3s http_reply_access allowAll 你不必在 http_reply_access 列表里重复 http_access规则。这里的 allowALL 规则不意 味 着所有对squid 的请求被允许。任何被http_access 拒绝的请求,从来不会再被 http_reply_access 检查。 6.3.106.3.106.3.106.3.10 阻止对本地站点 的 cache cache cache cache 命中 假如你有许多原始服务器在本地网络中,你也许想配置 squid,以便它们的响应永不被 缓存。 因为服务器就在附近, 它们不会从 cache命中里获益很多。 另外, 它释放存储空间 给 其他远程原始主机。 第一步是定义本地服务器的 ACL。你可能使用基于地址的 ACL,例如: acl LocalServers dst 172.17.1.0/24 假如服务器不位于单一的子网,你也许该创建 dstdomainACL: acl LocalServers dstdomain .example.com 接下来,你简单的使用 no_cache access规则,拒绝这些服务器的 cache: no_cache deny LocalServers no_cache 规则不会阻止客户发送请求 到 squid 。没有办法配置 squid 阻止这样的请求进 来。代替的,你必须配置用户代理自身。 假如你在 squid 运行一段时间后增加 no_cache规则, cache可能包含一些匹配新规则的 对象。 在 squid2.5之前的版本, 这 些以前缓存的对象可能以 cache命中返回。 然 而现在, squid 清除掉所有匹配 no_cache规则的缓存响应。 6.46.46.46.4 测试 访问 控制 访问控制配置越长, 它 就越复杂。 强 烈建议你在将它们用于产品环境之前, 先 测试访 问 Squid 中文权威指南 97 控制。当然,首先做的事是确认 squid 能正确的解析配置文件。使用 -k parse功能: % squid -k parse 为了进一步测试访问控制,你需要安装一个用于测试的 squid。容易做到的方法是,编 译另一份 squid 到其他 $prefix 位置。例如: % tar xzvf squid-2.5.STABLE4.tar.gz % cd squid-2.5.STABLE4 %./configure --prefix=/tmp/squid ... % make && make install 在安装完后,你必须编辑新的 squid.conf 文件,更改一些指令。假如 squid 已经运行在 默认端口,那么请改变 http_port。为了执行简单的测试,创建单一的小目录: cache_dir ufs /tmp/squid/cache 100 4 4 假如你不想重编译 squid,你也能创建一份新的配置文件。该方法的弊端是你必须设置 所有的日志文件路径为临时目录,以便不会覆盖真正的文件。 你可以使用 squidclient 程序来轻松的测试某些访问控制。 例 如, 假如你有一条规则, 它 依赖于原始服务器主机名 ( dstdomain ACL),或者某些URL 部分(url_regex 或urlpath_regex), 简单的输入你期望被允许或拒绝的 URI: % squidclient -p 4128 http://blocked.host.name/blah/blah or: % squidclient -p 4128 http://some.host.name/blocked.ext 某些类型的请求难以控制。假如你有 src ACL,它们阻止来自外部网络的请求, 你也 许 需要从外部主机测试它们。测试 time ACL 也很困难,除非你能改变系统时钟,或者等待足 够长时间。 你能使用 squidclient 的-H选项来设置任意请求头。 例 如, 假 如你需要测试 browser ACL, 那么这样做: % squidclient -p 4128 http://www.host.name/blah \ -H'User-Agent: Mozilla/5.0 (compatible; Konqueror/3)\r\n' Squid 中文权威指南 98 更多的复杂请求,包括多个头部,请参考 16.4章中描述的技术。 你也许考虑制订一项 cron,定期检查 ACL,以发现期望的行为,并报告任何异常。如 下是可以起步的示例 shell 脚本: #!/bin/sh set -e TESTHOST="www.squid-cache.org" # make sure Squid is not proxying dangerous ports # ST=`squidclient 'http://$TESTHOST:25/' | head -1 | awk '{print $2}'` if test "$ST" != 403 ; then echo "Squid did not block HTTP request to port 25" fi # make sure Squid requires user authentication # ST=`squidclient 'http://$TESTHOST/' | head -1 | awk '{print $2}'` if test "$ST" != 407 ; then echo "Squid allowed request without proxy authentication" fi # make sure Squid denies requests from foreign IP addresses # elsewhere we already created an alias 192.168.1.1 on one of # the system interfaces # EXT_ADDR=192.168.1.1 Squid 中文权威指南 99 ST=`squidclient -l $EXT_ADDR 'http://$TESTHOST/' | head -1 | awk '{print $2}'` if test "$ST" != 403 ; then echo "Squid allowed request from external address $EXT_ADDR" fi exit 0 第第第第7777章章章章磁盘 缓存 基础 磁盘 缓存 基础 磁盘 缓存 基础 磁盘 缓存 基础 7.17.17.17.1 cache_dir cache_dir cache_dir cache_dir 指令 cache_dir 指令是 squid.conf 配置文件里最重要的指令之一。它告诉 squid 以何种方式存 储cache文件到磁盘的什么位置。 cache_dir 指令取如下参数: cache_dir scheme directory size L1 L2 [options] 7.1.17.1.17.1.17.1.1 参数: SchemeSchemeSchemeScheme Squid 支持许多不同的存储 机制。默 认的( 原始的) 是 ufs。依赖于操作系统的 不同, 你可以选择不同的存储机制。在 ./configure 时,你必须使用 --enable-storeio=LIST 选项来编 译其他存储机制的附加代码。 我 将在 8.7章讨论 aufs,diskd,coss和null。现在,我仅仅讨论 ufs 机制,它与 aufs 和diskd 一致。 7.1.27.1.27.1.27.1.2 参数: DirectoryDirectoryDirectoryDirectory Squid 中文权威指南 100 该参数是文件系统目录, squid 将cache对象文件存放在这个目录下。 正 常的, cache_dir 使用整个文件系统或磁盘分区。 它 通常不介意是否在单个 文件系统分区里放置了多个 cache 目录。然而,我推荐在每个物理磁盘中,仅仅设置一 个 cache目录。例如,假如你有 2个无 用磁盘,你可以这样做: # newfs /dev/da1d # newfs /dev/da2d # mount /dev/da1d /cache0 # mount /dev/da2d /cache1 然后在 squid.conf 里增加如下行: cache_dir ufs /cache0 7000 16 256 cache_dir ufs /cache1 7000 16 256 假如你没有空闲硬盘, 当 然你也能使用已经存在的文件系统分区。 选 择有大量空闲空 间 的分区,例如 /usr或/var,然后在下面创建一个新目录。例如: # mkdir /var/squidcache 然后在 squid.conf 里增加如下一行: cache_dir ufs /var/squidcache 7000 16 256 7.1.37.1.37.1.37.1.3 参数: SizeSizeSizeSize 该参数指定了 cache目录的大小。 这是 squid 能使用的 cache_dir 目录的空间上限。 计 算 出合理的值也许有点难。 你 必须给临时文件和 swap.state日志, 留 出足够的自由空间 ( 见 13.6 章) 。 我推荐挂载空文件系统,可以运行 df: % df -k Filesystem 1K-blocks Used Avail Capacity Mounted on /dev/da1d 3037766 8 2794737 0% /cache0 /dev/da2d 3037766 8 2794737 0% /cache1 这里你可以看到文件系统有大约 2790M 的可用空间。记住, UFS 保留了部分最小自由 Squid 中文权威指南 101 空间,这里约是 8%,这就是 squid 为什么不能使用全部 3040M 空间的原因。 你也许试图分配 2790M 给cache_dir。 如果 cache不很繁忙, 并 且你经常轮转日志, 那 么 这 样 做 也 许 可 行 。 然而 , 为安 全 起 见 , 我推 荐 保 留 10%的空间。 这 些额外的空间用于存放 squid 的swap.state文件和临时文件。 注意 cache_swap_low 指令也影响了 squid 使用多少空间。我将在 7.2章里讨论它的上限 和下限。 底线是,你在初始时应保守的估计 cache_dir 的大小。将 cache_dir 设为较小的值,并 允许写满 cache。在squid 运行一段时间 后,cache目录会填满, 这 样你可以重新评估 cache_dir 的大小设置。假如你有大量的自由空间,就可以轻松的增加 cache目录的大小了。 7.1.3.17.1.3.17.1.3.17.1.3.1 InodesInodesInodesInodes Inodes(i 节点)是 unix 文件系统的基本结构。它们包含磁盘文件 的信息,例如许可, 属主,大小,和时间 戳。假如 你的文 件系统运 行超出 了 i节点限制,就不能创 造新文 件, 即使还有空间可用。超出 i节点的系统运行非常糟糕,所以在运行 squid 之前,你应该确认 有足够的 i节点。 创建新文件系统的程序(例 如,newfs或mkfs)基于总空间的大小, 保留了一定数量 的 i节点。 这 些程序通常允许你设置磁盘空间的 i节点比率。 例 如, 请阅读 newfs和mkfs 手册 的-i选项。 磁盘空间对 i节点的比率, 决定了文件系统能实际支持的文件大小。大部分 unix 系统每 4KB 创建一个 i节点,这对 squid 通常是足够 的。研究显示,对大部分 cache代理, 实际文件大小大约是 10KB。你也许能以每 i节点 8KB 开始,但这有风险。 你能使用 df -i命令来监视系统的 i节点,例如: % df -ik Filesystem 1K-blocks Used Avail Capacity iused ifree %iused Mounted on /dev/ad0s1a 197951 57114 125001 31% 1413 52345 3% /dev/ad0s1f 5004533 2352120 2252051 51% 129175 1084263 11% /usr /dev/ad0s1e 396895 6786 358358 2% 205 99633 0% /var /dev/da0d 8533292 7222148 628481 92% 430894 539184 44% /cache1 /dev/da1d 8533292 7181645 668984 91% 430272 539806 44% /cache2 Squid 中文权威指南 102 /dev/da2d 8533292 7198600 652029 92% 434726 535352 45% /cache3 /dev/da3d 8533292 7208948 641681 92% 427866 542212 44% /cache4 如果i节点的使用( %iused)少于空间使用( Capacity) , 那就很好。不幸的是,你不 能对已经存在的文件系统增加更多 i节点。假如你发现运行超出 了i节点,那就必须停止 squid,并且重新创建文件系统。假如你不愿意这样做,那么请削减 cache_dir 的大小。 7.1.3.27.1.3.27.1.3.27.1.3.2 在磁 盘 空间和进 程大小 之间 的联 系 Squid 的磁盘空间使用也直接影响了它的内存使用。 每 个在磁盘中存在的对象, 要求 少 量的内存。 squid 使用内存来索引磁盘数据。 假如你增加了新的 cache目录, 或者增加了 磁 盘cache大小,请确认你已有足够的自由内存。假如 squid 的进程大小达到或超过了系统的 物理内存容量, squid 的性能下降得非常 块。 Squid 的cache目录里的每个对象消耗 76或112字节的内存, 这 依赖于你的系统。 内 存 以 StoreEntry, MD5 Digest, 和LRU policy node 结构来分配。 小指令 (例如, 32位) 系统,象 那 些基于 Intel Pentium 的, 取 76字节。 使用 64位指令 CPU 的系统, 每个目标取 112字节。 通 过 阅读 cache 管理的 内存 管 理文 档 ,你 能 发现 这 些结 构 在你 的 系统 中 耗费 多 少内 存 (请见 14.2.1.2章)。 不幸的是, 难 以精确预测对于给定数量的磁盘空间, 需 要使用多少附加内存。 它 依赖 于 实际响应大小, 而 这个大小基于时间波动。 另 外, Squid 还为其他数据结构和目的分配内 存。 不要假设你的估计正确。 你 该经常监视 squid 的进程大小, 假 如必要, 考 虑削减 cache大小 。 7.1.47.1.47.1.47.1.4 参数: L1L1L1L1和L2L2L2L2 对ufs,aufs,和diskd 机制, squid 在cache目录下创建二级目录树。 L1和L2参数指定了 第 一级和第二级目录的数量。 默 认的是 16和256。图7-1显示文件系统结构。 Figure 7-1. 基于 ufs Squid 中文权威指南 103 储机制的 cache目录结构 某些人认为 squid 依赖于 L1和L2的特殊值, 会 执行得更好或更差。 这 点听起来有关 系, 即小目录比大目录被检索得更快。 这样, L1和L2也许该足够大, 以 便L2目录的文件更少 。 例如, 假 设你的 cache目录存储了 7000M, 假 设实际文件大小是 10KB, 你 能在这个 cache_dir 里存储 700,000 个文件。 使 用 16个L1和256个L2目录, 总 共有 4096个二级目录。 700,000/4096 的结果是,每个二级目录大约有 170个文件。 如果 L1和L2的值比较小, 那 么使用 squid -z创建交换目录的过程, 会 执行更快。 这样 , 假如你的 cache文件确实小,你也许该减少 L1和L2目录的数量。 Squid 给每个 cache目标分配一个唯一的文件号。这是个 32位的整数,它唯一标明磁 盘 中的文件。 squid 使用相对简单的算法,将文件号转换位路径名。 该算法 使用 L1和L2作为 参数。这样,假如你改变 了 L1和L2,你改变了从文件号到路径 名的映射关 系。对非空 的 cache_dir 改变这些参数, 导 致存在的文件 不可访问。 在 cache目录激活后, 你 永不要改变 L1 和L2值。 Squid 在cache 目录顺序中分配文件号。文件号到路径名的算法(例如, storeUfsDirFullPath( )) , 用以将每组 L2文件映射到同样的二级目录。 Squid 使用了参考位置 来做到这点。 该 算法让 HTML文件和它内嵌的图片更可能的保存在同一个二级目录 中。 某 些人希望 squid 均匀的将 cache文件放在每个二级目录中。然而, 当 cache初始写入时,你 可以发现仅仅开头的少数目录包含了一些文件,例 如: % cd /cache0; du -k 2164 ./00/00 2146 ./00/01 2689 ./00/02 Squid 中文权威指南 104 1974 ./00/03 2201 ./00/04 2463 ./00/05 2724 ./00/06 3174 ./00/07 1144 ./00/08 1 ./00/09 1 ./00/0A 1 ./00/0B 这是完全正常的,不必担心。 7.1.57.1.57.1.57.1.5 参数: OptionsOptionsOptionsOptions Squid 有2个依赖于不同存储机制的 cache_dir 选项: read-only 标签和 max-size 值。 7.1.5.17.1.5.17.1.5.17.1.5.1 read-onlyread-onlyread-onlyread-only read-only 选项 指 示 Squid 继续 从 cache_dir 读取 文件,但不往里面写新目标。它在 squid.conf 文件里看起来如下: cache_dir ufs /cache0 7000 16 256 read-only 假如你想把 cache文件从一个磁盘迁移到另一个磁盘,那么可使用该选项。如果你简 单的增加一个 cache_dir,并且删除另一个,squid 的命中率会 显著下降。 在 旧目录是 read-only 时,你仍能从那里获取 cache命中。在一段时间后,就可以从配置文件 里删 除 read-only 缓 存目录。 7.1.5.27.1.5.27.1.5.27.1.5.2 max-sizemax-sizemax-sizemax-size 使用该选项,你可以指定存储在 cache目录里的最大目标大小。例如: cache_dir ufs /cache0 7000 16 256 max-size=1048576 注意值是以字节为单位的。 在 大多数情况下, 你不必增加该选项。 假 如你做了, 请尽 力 Squid 中文权威指南 105 将所有 cache_dir 行以 max-size 大小顺序来存放(从小到大) 。 7.27.27.27.2 磁盘 空间 基准 cache_swap_low 和cache_swap_high 指令控制了存储在磁盘上的对象的置换。 它 们的 值 是最大 cache体积的百分比,这个最大 cache体积来自于所有 cache_dir 大小的总和。例如: cache_swap_low 90 cache_swap_high 95 如果总共磁盘使用低于 cache_swap_low,squid 不会删除 cache目标。如果 cache体积 增加,squid 会逐渐删除目标。 在 稳定状态 下, 你 发现磁盘使用总是相对接近 cache_swap_low 值。 你 可以通过请求 cache管理器的 storedir 页面来查看当前磁盘使用状况 ( 见 14.2.1.39章)。 请注意, 改变 cache_swap_high 也许不会对 squid 的磁盘使用有太大效果。 在 squid 的早 期版本里,该参数有重要作用;然而现在,它不是这样了。 7.37.37.37.3 对象 大小 限制 你可以控制缓存对象的最大和最小体积。比 maximum_object_size 更大的响应不会被 缓 存在磁盘。 然 而, 它们仍然是代理方式的。 在 该指令后的逻辑是, 你不想某个非常大的响 应 来浪费空间,这些空间能被许多小响应更好的利用。该语法如下: maximum_object_size size-specification 如下是一些示例: maximum_object_size 100 KB maximum_object_size 1 MB maximum_object_size 12382 bytes maximum_object_size 2 GB Squid 以两个不同的方法来检查响应大小。假如响应包含了 Content-Length 头部, squid 将这个值与 maximum_object_size 值进行比较。假如前者大于 后者,该对 象立刻不可 缓存, Squid 中文权威指南 106 并且不会消耗任何磁盘空间。 不幸的是,并非每个响应都 有 Content-Length 头部。在这样的情形下, squid 将响应写 往磁盘,把它当作来自原始 服务器的数 据。在响应 完成后, squid 再检查对象大小。这样, 假如对象的大小达到 maximum_object_size 限制,它继续消耗磁盘空间。仅仅当 squid 在做 读取响应的动作时,总共 cache大小才会增大。 换句话说, 活动的, 或 者传输中的目标, 不会对 squid 内在的 cache大小值有影响。 这 点有好处, 因 为它意味着 squid 不会删除 cache里的其他目 标, 除 非目标不可缓存, 并 对 总 共cache大小有影响。然而,这点也有坏处,假如 响应非常大, squid 可能运行超出了磁盘 自由空间。 为了减少发生这种情 况的机会, 你应该使用 reply_body_max_size 指令。 某个 达 到reply_body_max_size 限制的响应立即被删除。 Squid 也有一个 minimum_object_size 指令。它允许你对缓存对象的大小设置最低限制。 比这个值更小的响应不会被缓存在磁盘或内存里。 注 意这个大小是与响应的内容长度 ( 例 如, 响应 body 大小)进行比较,后者包含在 HTTP头部里。 7.47.47.47.4 分配 对象 到缓存 目录 当squid 想将某个可缓存的响应存储到磁盘时, 它 调用一个函数, 用 以选择 cache目录。 然后它在选择的 目录里 打开一 个磁盘 文件用 于写。 假如因 为某些 理 由, open()调用失败, 响应不会被存储。在这样的情况下, squid 不会试图在其他 cache目录里打开另一个磁盘文 件。 Squid 有2个cache_dir 选择算法。 默 认的算法叫做 lease-load ; 替 代的算法是 round-robin。 least- load 算法,就如其名字的意义一样,它选择当 前工作负载最小 的 cache目录。负 载概念依赖于存储机制。 对 aufs,coss和diskd 机制来说,负载与挂起操作的数量有关。 对 ufs 来说,负载是不变的。在 cache_dir 负载相等的情况下,该算法使用自由空间和最大目标大 小作为附加选择条件。 该选择算法也取决于 max-size 和read-only 选项。 假如 squid 知道目标大小超出了限制 , 它会跳过这个 cache目录。它也会跳过任何只读目录。 round-robin 算法也使用负 载作 为衡量 标准 。它选 择某 个负载 小于 100%的cache 目录, 当然,该目录里的存储目标没有超出大小限制,并且不是只读的。 在某些情况下, squid 可能选择 cache 目录失败。假如所有 的 cache_dir 是满负载,或 者所有目录的实际目 标大小超 出 了 max-size 限制,那 么这种情况可能发生 。这时, squid Squid 中文权威指南 107 不会将目标写往 磁盘。 你可以 使 用 cache 管理器来跟 踪 squid 选择 cache 目录失败的次数。 请见 store_io 页( 14.2.1.41章 ) ,找 到 create.select_fail 行。 7.57.57.57.5 置换 策略 cache_replacement_policy 指令控制了 squid 的磁盘 cache的置换策略。 Squid2.5版本提 供 了三种不同的置换策略:最少近来使用( LRU) , 贪婪对偶大小次数( GDSF) ,和 动 态 衰 老 最少经常使用( LFUDA)。 LRU 是默认的策略, 并非对 squid, 对其他大部分 cache产品都是这样。 LRU 是流行 的 选择,因为它容易执行,并提供了非常好的性能。在 32位系统上, LRU 相对于其他使用更 少的内存(每目标 12对16字 节 ) 。在 64位系统上,所有的策略每目标使用 24字节。 在过去,许多研究者已经提议选择 LRU。其他策略典型的被设计来改善 cache的其他 特性,例如响应时间,命中率,或字节命 中率。然而研究者 的改进结果也可 能在误导人。 某些研究使用并不现实的小 cache目标;其他研究显示当 cache大小增加时,置换策略的选 择变得不那么重要。 假如 你 想 使 用 GDSF 或LFUDA 策略 , 你 必 须 在 ./configure 时使 用 --enable-removal- policies 选项(见 3.4.1章)。Martin Arlitt 和HP 实验室的 John Dilley 为squid 写了 GDSF 和 LFUDA 算法。你可以在线阅读他们的文档: http://www.hpl.hp.com/techreports/1999/HPL-1999-69.html 我在 O'Reilly 出版的书 "Web Caching",也讨论了这些算法。 cache_replacement_policy 指令的值是唯一的, 这 点很重要。 不象 squid.conf 里的大部 分 其他 指令,这个指令的位置很重要。cache_replacement_policy 指令 的 值 在 squid 解析 cache_dir 指令时, 被 实际用到。 通 过预先设置替换策略, 你 可以改变 cache_dir 的替换策略 。 例如: cache_replacement_policy lru cache_dir ufs /cache0 2000 16 32 cache_dir ufs /cache1 2000 16 32 cache_replacement_policy heap GDSF cache_dir ufs /cache2 2000 16 32 Squid 中文权威指南 108 cache_dir ufs /cache3 2000 16 32 在该情形中, 头 2个cache目录使用 LRU 置换策略, 接 下来 2个cache目录使用 GDSF。 请记住,假如你已决定使 用 cache 管理器的 config 选项(见 14.2.1.7章) ,这个置换策略指 令的特性就非常重要。 cache管理器仅仅输出最后一个置换策略的值, 将 它置于所有的 cache 目录之前。例 如,你可能在 squid.conf 里有如下行: cache_replacement_policy heap GDSF cache_dir ufs /tmp/cache1 10 4 4 cache_replacement_policy lru cache_dir ufs /tmp/cache2 10 4 4 但当你从 cache管理器选择 config 时,你得到: cache_replacement_policy lru cache_dir ufs /tmp/cache1 10 4 4 cache_dir ufs /tmp/cache2 10 4 4 就象你看到的一样,对头 2个cache目录的 heap GDSF 设置被丢失了。 7.67.67.67.6 删除 缓存 对象 在某些情况下,你必须从 squid 的cache里手工删除一个或多个对象。这些情况可能包 括: • 你的用户抱怨总接收到过时的数据; • 你的 cache因为某个响应而 “中毒 ”; • Squid 的cache索引在经历磁盘 I/O错误或频繁的 crash 和 重 启 后 , 变得 有 问 题; • 你想删除一些大目标来释放空间给新的数据; • Squid 总从本地服务器中 cache响应,现在你不想它这样做。 Squid 中文权威指南 109 上述问题中的一 些可以 通过强 迫 web 浏览器 reload 来解决。然而, 这并非 总是可 靠。 例如, 一些浏览器通过载入另外的程序, 从而显示某些类容类型; 那个程序可能没有 reload 按钮,或甚至它了解 cache的情况。 假如必要,你总可以使用 squidclient 程序来 reload 缓存目标。简单的在 uri 前面使用 -r 选项: % squidclient -r http://www.lrrr.org/junk >/tmp/foo 假如你碰巧在 refresh_pattern 指令里设置了 ignore-reload 选项,你和你的用户将不能强 迫缓存响应更新。在这样的情形下,你最好清除这些有错误的缓存对象。 7.6.17.6.17.6.17.6.1 删除个别对象 Squid 接受一种客户请求方式,用 于删 除 cache 对象。 PURGE 方式并非官方 HTTP 请 求方式之一。 它与 DELETE 不同, 对后者, squid 将其转发到原始 服务器。 PURGE 请求 要 求squid 删除在 uri 里提交的目标。 squid 返回 200(OK)或 404(Not Found)。 PURGE 方式某种程度 上有 点危险 ,因 为它删 除 了 cache 目标。除非你 定义 了相应 的 ACL,否则 squid 禁止 PURGE 方式。正常的, 你仅仅 允许来 自本机 和少数 可信任 主机 的 PURGE 请求。配置看起来如下: acl AdminBoxes src 127.0.0.1 172.16.0.1 192.168.0.1 acl Purge method PURGE http_access allowAdminBoxes Purge http_access deny Purge squidclient 程序提供了产生 PURGE 请求的容易方法,如下: % squidclient -m PURGE http://www.lrrr.org/junk 代替的, 你 可以使用其他工具 ( 例如 perl 脚本) 来 产生你自己的 HTTP请求。 它 非常 简 单: PURGE http://www.lrrr.org/junk HTTP/1.0 Accept: */* Squid 中文权威指南 110 注意某个单独的 URI 不唯一标明一个缓存响应。 Squid 也在 cache 关键字里使用原始 请求方式。假如响应包含了不同的头部,它也可以使用其他请求头。当 你发布 PURGE 请 求时, Squid 使用 GET 和HEAD 的原始请求方式来查找缓存目标。 而 且, Squid 会删除响 应 里的所有 variants,除非你在 PURGE 请求的相应头部里指定了要删除的 variants。Squid 仅 仅删除 GET 和HEAD 请求的 variants。 7.6.27.6.27.6.27.6.2 删除一组对象 不幸的是, Squid 没有提供一个好的机制,用以立刻删除一组对象。这种要求通常出 现 在某人想删除所有属于同一台原始服务器的对象时。 因为很多理由, squid 不提供这种功能。首先, squid 必须遍历所有缓存对象,执行线 性搜索,这很耗 费 CPU,并且耗时较长。 当 squid 在搜索时,用 户会面临性能下降问 题。 第二, squid 在内存里对 URI 保持 MD5算法, MD5是单向哈希,这意味着,例如,你不能 确认是否某个给定的 MD5哈希是由包 含"www.example.com"字符串的 URI 产生而来。 唯 一 的方法是从原始 URI 重新计算 MD5值, 并且看它们是否匹配。 因为 squid 没有保持 原始 的 URI,它不能执行这个重计算。 那么该怎么办呢? 你可以使用 access.log 里的数据来获取 URI 列表,它们可能位于 cache里。然后,将 它 们用于 squidclient 或其他工具来产生 PURGE 请求,例如: % awk '{print $7}' /usr/local/squid/var/logs/access.log \ | grep www.example.com \ | xargs -n 1 squidclient -m PURGE 7.6.37.6.37.6.37.6.3 删除所有对象 在极度情形下,你可能需要删除整个 cache,或至少某个 cache目录。首先,你必须确 认squid 没有在运行。 让squid 忘记所有缓存对象的最容易的方法之一,是覆盖 swap.state文件。注意你不 能 简单的删除 swap.state文件,因为 squid 接着要 扫描 cache目录和打开所有的目标文件。 你 也不能简单的截断 swap.state为0大小。代替的,你该放置一个单字节在里面,例如: # echo '' > /usr/local/squid/var/cache/swap.state Squid 中文权威指南 111 当squid 读取 swap.state文件时,它获取到了错误,因为在这里的记录太短了。下一行 读取就到了文件结尾, squid 完成重建过程,没有装载任何目标元数据。 注意该技术不会从磁盘里删除 cache文件。 你仅仅使 squid 认为它的 cache是空的。 当 squid 运行时, 它增加新文件到 cache里, 并且可能覆盖 旧文件。 在某些情形下,这可能 导 致你的磁盘使用超出了自由空间。 假如这样的事发生, 你必须在再次重启 squid 前删除旧 文 件。 删除 cache文件的方法之一是使用 rm。 然 而, 它 通常花费很长的时间来删除所有被 squid 创建的文件。为了让 squid 快速启动,你可以重命名旧 cache目录,创建一个新目录,启动 squid,然后同时删除旧目录。例如: # squid -k shutdown # cd /usr/local/squid/var # mv cache oldcache # mkdir cache # chown nobody:nobody cache # squid -z # squid -s # rm -rf oldcache & 另一种技术是简单的在 cache文件系统上运行 new fs(或 mkfs) 。 这点 仅 在 你 的 cache_dir 使用整个磁盘分区时才可以运行。 7.77.77.77.7 refresh_patternrefresh_patternrefresh_patternrefresh_pattern refresh_pattern 指令间接的控制磁盘缓存。 它 帮助 squid 决定, 是 否某个给定请求是 cache 命中, 或 作为 cache丢失对待。 宽 松的设置增加了你的 cache命中率, 但也增加了用户接 收 过时响应的机会。另一方面,保守的设置,降低了 cache命中率和过时响应。 refresh_pattern 规则仅仅应用到没有明确过时期限的响应。 原 始服务器能使用 Expires 头 部,或者 Cache-Control:max-age 指令来指定过时期限。 你可以在配置文件里放置任意数量的 refresh_pattern 行。squid 按顺序查找它们以匹配 正 Squid 中文权威指南 112 则表达式。当 squid 找到一个匹配时, 它使用相应的值来决定,某个缓存响应是存活还是 过 期。 refresh_pattern 语法如下: refresh_pattern [-i] regexp min percent max [options] 例如: refresh_pattern -i \.jpg$ 30 50% 4320 reload-into-ims refresh_pattern -i \.png$ 30 50% 4320 reload-into-ims refresh_pattern -i \.htm$ 0 20% 1440 refresh_pattern -i \.html$ 0 20% 1440 refresh_pattern -i . 5 25% 2880 regexp 参数是大小写敏感的 正则表达 式。你 可以使用 -i选项来使它们大小写 不敏感。 squid 按顺序来检查 refresh_pattern 行;当正则表达式之一匹配 URI 时,它停止搜索。 min参数是分钟数量。它是过时响应的最低时间限制。如果某个响应驻留在 cache里的 时间没有超过这个最低限制, 那 么它不会过期。 类 似的, max 参数是存活响应的最高时间 限 制。如果某个响应驻留在 cache里的时间高于这个最高限制,那么它必须被刷新。 在最低和最高时间限制之间的 响应,会面 对 squid 的最后修改系数 (LM-factor)算法。 对这样的响应, squid 计算响应的年龄和最后修改 系数,然后 将它作为百 分比值进行 比较。 响应年龄简单的就是从原始服务器产 生,或最后一次验证响应后,经历的时间数量。源年 龄在 Last-Modified 和Date 头部之间是不同的。 LM-factor 是响应年龄与源年龄的比 率。 图7-2论证了 LM-factor算法。squid 缓存了某个目标 3个 小 时 (基 于 Date和Last-Modified 头部)。LM-factor 的值是 50%,响应在接下来的 1.5个小时里是存活的,在这之后,目标会 过期并被当作过时处理。 假 如用户在存活期间请求 cache目标,squid 返回没有确认 的cache 命中。若在过时期间发生请求, squid 转发确认请求到原始服务器。 图7-2 基于 LM-factor 计算过期时间 Squid 中文权威指南 113 理解 squid 检查不同值的顺序非常重要。 如 下是 squid 的refresh_pattern算法的简单描 述: • 假如响应年龄超过 refresh_pattern 的max 值,该响应过期; • 假如 LM-factor 少于 refresh_pattern 百分比值,该响应存活; • 假如响应年龄少于 refresh_pattern 的min值,该响应存活; • 其他情况下,响应过期。 refresh_pattern 指令也有少数选项导致 squid 违背 HTTP协议规范。它们如下: override-expire 该选项导致 squid 在检查 Expires 头部之前,先检查 min值。这样,一个非零的 min时 间让 squid 返回一个未确认的 cache命中,即使该响应准备过期。 override-lastmod 改选项导致 squid 在检查 LM-factor 百分比之前先检查 min值。 reload-into-ims 该选项让 squid 在确认请求里,以 no-cache 指令传送一个请求。 换句话说, squid 在转 发请 求之前,对该请求增加一个If-Modified- Since 头部 。注意这点仅仅在目标有Last- Modified 时间戳时才能工作。外面进来的请求保留 no-cache 指令,以便它到达原始服务器 。 ignore-reload 该选项导致 squid 忽略请求里的任何 no-cache 指令。 Squid 中文权威指南 114 第第第第8888章章章章高级 磁盘 缓存 主题 高级 磁盘 缓存 主题 高级 磁盘 缓存 主题 高级 磁盘 缓存 主题 8.18.18.18.1 是否 存在 磁 盘 I/O I/O I/O I/O 瓶颈 ? Web 缓存器例如 squid,通常在磁盘 I/O变成瓶颈时,不会正确的体现和告知你。代替 的是,随着负载的增加,响应时间和 /或命中率会更低效。当然,响应时间和命中率可能因 为其他原因而改变,例如网络延时和客户请求方式的改变。 也许探测 cache性能瓶颈的最好方式是做压力测试,例 如 Web Polygraph。压力测试的 前提是你能完全控制环境,消除未知因素。你可以用不同 的 cache配置来重复相同的测试。 不幸的是,压力测试通常需要大量的时间,并要求有空闲的系统(也许它们正在使用中) 。 假如你有资源执行 squid 压力测试, 请 以标准的 cache工作负载开始。 当 你增加负载 时, 在某些点上你能看到明显的响应延时和 /或命中率下降。 一 旦你观察 到这样的性能降低, 就 禁止掉磁盘缓存, 再 测试一次。 你 可以配置 squid 从来不缓存任何响应 ( 使用 null 存储机 制, 见8.7章) 。代替的,你能配置工作 负载到 100%不可 cache响应。假如不使用 cache时,平 均响应时间明显更好,那么可以确认磁盘 I/O是该水平吞吐量的瓶颈。 假如你没有时间或没有资源来执行 squid 压力测试,那么可检查 squid 的运行时统计来 查找磁盘 I/O瓶颈。cache管理器的 General Runtime Information 页面(见14章 ) 会显 示 出 cache 命中和 cache丢失的中值响应时间。 Median Service Times (seconds) 5 min 60 min: HTTP Requests (All): 0.39928 0.35832 Cache Misses: 0.42149 0.39928 Cache Hits: 0.12783 0.11465 Near Hits: 0.37825 0.39928 Not-Modified Replies: 0.07825 0.07409 对健壮的 squid 缓存来说, 命 中显然快于丢失。 中 值命中响应时间典型的少于 0.5秒或 更 少。 我 强烈建议你使用 SNMP 或其他的网络监视工具来从 squid 缓存采集定期测量值。 如 果 平均命中响应时间增加得太明显,意味着系统有磁盘 I/0瓶颈。 Squid 中文权威指南 115 假如你认为产品 cache面临此类问题,可以用前面提到的同样的技术来验证你的推测。 配置 squid 不cache任何响应, 这 样就避开了所有磁盘 I/O。 然 后仔细观察 cache丢失响应 时 间。假如它降下去,那么你的推测该是正确的。 一旦你确认了磁盘吞吐能力是 squid 的性能瓶颈, 那么可做许多事来改进它。 其中一 些 方法要求重编译 squid,然而另一些相对较简单,只需调整 Unix文件系统。 8888.2.2.2.2 文件 系统 调整选 项 首先,从来不在 squid 的缓存目录中使用 RAID。以我的经验看, RAID 总是降低 squid 使用的文件系统的性能。 最 好有许多独立的文件系统, 每 个文件系统使用单独的磁盘驱动 器。 我发现 4个简单的方法来改进 squid 的UFS 性能。其中某些特指某种类型的操作系统例 如BSD 和Linux,也许对你的平台不太合适: • 1.某些 UFS 支持一个 noatime 的mount 选项。 使用 noatime 选项来 mount 的文 件系统,不会在读取时,更新相应的 i节点访问时间。使用该选项的最容易的方法是在 /etc/fstab 里增加如下行: # Device Mountpoint FStype Options Dump Pass# /dev/ad1s1c /cache0 ufs rw,noatime 0 0 • 2. 检查 mount(8)的manpage 里的 async选项。 设 置了该选项, 特 定的 I/O操作 (例如更新目录)会异步执行。某些系统的文档会标明这是个危险 的标签。某天你的 系统崩溃,你也许会丢失整个文件系统。对许多 squid 安装来说,执行性能的提高值得 冒此风险。 假如你不介意丢失整个 cache内容, 那 么可以使用该选项。 假如 cache数据 非常有价值, async选项也许不适合你。 • 3.BSD 有一个功能叫做软更新。软 更新 是 BSD 用于 Journaling 文件系统的代 替品。在 FreeBSD 上, 你 可以在没有 mount 的文件系统中, 使用 tunefs 命令来激活该 选 项: # umount /cache0 # tunefs -n enable /cache0 # mount /cache0 Squid 中文权威指南 116 • 4.你对每个文件系统运行一次 tunefs 命令就可以了。 在系统重启时, 软更新 自 动在文件系统中激活了。 在OpenBSD 和NetBSD 中,可使用 softdep mount 选项: # Device Mountpoint FStype Options Dump Pass# /dev/sd0f /usr ffs rw,softdep 1 2 假如你象我一样, 你 可能想知道在 async选项和软更新选项之间有何不同。 一 个重要 的 区别是, 软更新代码被设计成在系统崩溃事件中, 保持文件系统的一致性,而 async选项 不 是这样的。 这 也许让你推断 async执行性能好于软更新。 然 而, 如我在附录 D中指出的, 事 实相反。 以前我提到过, UFS 性能特别是写性能,依赖于空闲磁盘的数量。对空文件系统的 磁 盘写操作,要比满文件系统快得多。这 是 UFS 的最小自由空间参数,和空间 / 时间优化权 衡参数背后的理由之一。假如 cache磁盘满了, squid 执行性能看起来很糟,那么试着减少 cache_dir 的容量值,以便更多的自由 空间 可用。当然,减少 cache 大小也会降低命中率, 但响应时间的改进也许值得这么做。 假如你给 squid 缓存配置新的设备, 请考虑使用超过 你 需要的更大磁 盘,并且仅仅使用空间的一半。 8.38.38.38.3 可选 择的 文件系 统 某些操作系统支持不同于 UFS(或 ext2fs) 的文件系统。 Journaling 文件系统是较普 遍 的选择。在 UFS 和Journaling 文件系统之间的 主要不同在于它们处理更新的方式。在 UFS 下, 更 新是实时的。 例如, 当 你改变了某个文件并且将它存储到磁盘, 新数据就替换了旧 数 据。当你删除文件 时, UFS 直接更新了目录。 Journaling 文件系统与之相反,它将更新写往独立的记帐系统,或日志文件。典型的你 能选择是否记录文件 改变或元数据改变, 或 两者兼备。 某 个后台进程在空闲时刻读取记帐 , 并且执行实际的改变操作。 Journaling 文件系统典型的在系统崩溃后比 UFS 恢复 更快。在 系统崩溃后, Journaling 文件系统简单的读取记帐,并且提交所有显著的改变。 Journaling 文件系统的主要弊端在于它们需要额外的磁盘写操作。改变首先写往日志文 件,然后才写往实际的文件或目录。这对 web 缓存影响尤其明显,因为首先 web 缓存倾向 于更多的磁盘写操作。 Journaling 文件系统对许 多操 作系统 可用 。 在 Linux 上,你能选 择 ext3fs,reiserfs, XFS, 和其他的。 XFS 也可用在 SGI/IRIX,它原始是在这里开发的。 Solaris 用户能使用 Veritas 文 件系统产品。 TRU64(以前的 Digital Unix)高级文件系统( advfs)支持 Journaling。 你可以不改变 squid 的任何配置而使用 Journaling 文件系统。简单的创建和挂载在操作 系统文档里描述的文件系统,而不必改变 squid.cf 配置文件里的 cache_dir 行。 Squid 中文权威指南 117 用类似如下命令在 Linux 中制作 reiserfs 文件系统: #/sbin/mkreiserfs /dev/sda2 对XFS,使用: # mkfs -t xfs -f /dev/sda2 注意 ext3fs 其实简单的就是激活了记帐 的 ext2fs。当创建该文件系统时, 对 mke2fs 使 用-j选项: #/sbin/mke2fs -j /dev/sda2 请参考其他操作系统的相关文档。 8.48.48.48.4 aufsaufsaufsaufs存储 机制 aufs 存储机制已经发展到超出了改进 squid 磁盘 I/O响应时间的最初尝试。 "a"代表着 异 步I/O。 默 认的 ufs 和aufs 之间的唯一区别, 在于 I/O是否被 squid 主进程执行。 数 据格式 都 是一样的,所以你能在两者之间轻松选择,而不用丢失任何 cache数据。 aufs 使用大量线程进行磁盘 I/O操作。每次 squid 需要读写,打开关闭,或删 除 cache 文件时, I/O请求被分派到这些线程之一。当线程完成了 I/O后, 它给 squid 主进程发送 信 号,并且返回一个状态码。 实际上在 squid2.5中,某些文件操作默认不是异步执行的。 最 明 显 的 , 磁盘 写 总 是 同 步 执 行 。 你可 以修改 src/fs/aufs/store_asyncufs.h文件,将ASYNC_WRITE 设为 1,并且重编译 squid。 aufs 代码需要 pthreads 库。 这是 POSIX定义的标准线程接口。 尽 管许多 Unix系统支 持 pthreads 库,但我经常遇到兼容性问题。 aufs 存储系 统看起来仅仅在 Linux 和Solaris 上运 行良好。在其他操作系统上,尽管代码能编译,但也许会面临严重的问题。 为了使用 aufs,可以在 ./configure时增加一个选项: %./configure --enable-storeio=aufs,ufs 严格讲,你不必在 storeio 模块列表中指定 ufs。然而,假如你以后不喜欢 aufs,那么 就 需要指定 ufs,以便能重新使用稳定的 ufs 存储机制。 假如 愿 意 , 你 也 能 使 用 —with-aio-threads=N 选项 。 假 如 你 忽 略 它 , squid 基于 aufs Squid 中文权威指南 118 cache_dir 的数量,自动计算可使用的线程数量。表 8-1显示了 1-6个cache目录的默认线程 数 量。 Table 8-1. Default number of threads for up to six cache directories 将aufs 支持编译进 squid 后,你能在 squid.conf 文件里的 cache_dir 行后指定它: cache_dir aufs /cache0 4096 16 256 在激活了 aufs 并启动 squid 后,请确认每件事仍 能工作正 常。可 以运 行 tail -f store.log 一会儿, 以确认缓存目标被交换到磁盘。 也可以运行 tail -f cache.log 并且观察任何新的错 误 或警告。 8.4.18.4.18.4.18.4.1 aufsaufsaufsaufs如何工作 Squid 通过调用 pthread_create()来创建大量的线程。 所 有线程在任何磁盘活动之上创建 。 这样,即使 squid 空闲,你也能见到所有的线程。 无论何时, squid 想执行某些磁盘 I/O操作(例如打开文件读) , 它分配一对数据结构, 并将 I/O请求放进队列中。 线程循环读取队列,取得 I/O请求并执行它们。 因为请求队列 共 cache _dirs Th reads 1 16 2 26 3 32 4 36 5 40 6 44 Squid 中文权威指南 119 享给所有线程, squid 使用独享锁来保证仅仅一个线程能在给定时间内更新队列。 I/O操作阻塞线程直到它们被完成。然后,将操作状态放进一个完成队列里。作为完 整 的操作, squid 主进程周期性的检查完成队列。请求磁盘 I/O的模块被通知操作已完成,并 获取结果。 你可能已猜想到, aufs 在多 CPU 系统上优势更明显。唯一的锁操作发生在请求和结果 队列。 然 而, 所 有其他的函数执行都是独立的。 当 主进程在一个 CPU 上执行时, 其 他的 CPU 处理实际的 I/O系统调用。 8.4.28.4.28.4.28.4.2 aufsaufsaufsaufs发行 线程的有趣特性是所有线程共享相同的资源,包括内存和文件描述符。例如,某个线 程打开一个文件,文件描述符为 27,所有其他线程能以相同的文件描述符来 访问 该文件。 可能你已知道, 在 初次管理 squid 时, 文 件描述符短缺是较普遍问题。 Unix内核典型的有 两 种文件描述符限制: 进程级的限制和系统级的限制。你也许认为每个进程拥有 256个文件描述符足够了(因 为使用线程) , 然而并非如此。在这样的情况下,所有线程共享少量的文件描述符。请确认 增加系统的进程文件描述符限制到 4096或更高,特别在使用 aufs 时。 调整线程数量有点棘手。在某些情况下,可在 cache.log 里见到如下警告: 2003/09/29 13:42:47| squidaio_queue_request: WARNING- Disk I/O overloading 这意味着 squid 有大量的 I/O操作请求充满队列,等待着可用的线程。你首先会想到增 加线程数量,然而我建议,你该减少线程数量。 增加线程数量也会增加队列的大小。超过 一定数量,它不会 改 进 aufs 的负载能力。它 仅仅意味着更多的操作变成队列。太长的队列导致响应时间变长,这绝不是你想要的。 减少线程数量和队列大小,意 味 着 squid 检测负载条件更快。当某 个 cache_dir 超载, 它会从选择算法里移除掉 ( 见 7.4章 ) 。然 后 , squid 选择 其他的 cache_dir 或简单的不存储 响 应到磁盘。这可能是较好的解决方法。尽管命中率下降,响应时间却保持相对较低。 8.4.38.4.38.4.38.4.3 监视aufsaufsaufsaufs操作 Cache 管理器菜单里的 AsyncIO Counters 选项,可以显示涉及 到 aufs 的统计信息。它 显示打开,关闭,读写, stat,和删除接受到的请求的数量。例如: % squidclient mgr:squidaio_counts... Squid 中文权威指南 120 ASYNCIO Counters: Operation # Requests open 15318822 close 15318813 cancel 15318813 write 0 read 19237139 stat 0 unlink 2484325 check_callback 311678364 queue 0 取消 (cancel)计数器正常情况下等同于关闭 (close)计数器。这是因为 close函数总是调用 cancel 函数,以确认任何未决的 I/O操作被忽略。 写(write)计数器为 0,因为该版本的 squid 执行同步写操作,即使是 aufs。 check_callbak 计数器显示 squid 主进程对完成队列检查了多少次。 queue 值显示当前请求队列的长度。正常情况下 ,队列长度少于线 程数量的 5倍。假如 你持续观察到队列长度大于这个值,说 明 squid 配得有问题。增加更多的线程也许有帮助, 但仅仅在特定范围内。 8.58.58.58.5 diskd diskd diskd diskd 存储 机制 diskd(disk 守护进程的短称 )类似 于 aufs,磁盘 I/O被外部进程来执 行。不 同 于 aufs 的是, diskd 不使用线程。代替的,它通过消息队列和共享内存来实现内部进程间通信。 消息队列是现代 Unix 操作系统的标准功能。许多年以前 在 AT&T 的Unix System V的 版本 1上实现了它们。进程间的队列消息以较少的字节传递: 32-40字节。每个 diskd 进程使 用一个队列来接受来自 squid 的请求,并使用另一个队列来传回请求。 Squid 中文权威指南 121 8.5.18.5.18.5.18.5.1 diskddiskddiskddiskd如何工作 Squid 对每个 cache_dir 创建一个 diskd 进程。这不同 于 aufs,aufs 对所有的 cache_dir 使用一个大的线程池。对每个 I/O操作, squid 发送消息到相应的 diskd 进程。当该操作完 成后, diskd 进程返回一个状态消息给 squid。squid 和diskd 进程维护队列里的 消息的顺序 。 这样,不必担心 I/O会无序执行。 对读和写操作, squid 和diskd 进程使用共享内存区域。两个进程能对同 一内存区域进 行读和写。 例 如,当 squid 产生读请求时, 它 告诉 diskd 进程在内存中何处放置数据。 diskd 将内存位置传递给 read()系统调用, 并且通过发送队 列消息, 通知 squid 该过程完成了。 然 后squid 从共享内存区域访问最近的可读数据。 diskd 与aufs本质上都支持 squid 的无 阻塞磁盘 I/O。当diskd 进程在 I/O操作上阻塞 时, squid 有空去处理其他任务。 在 diskd 进程能跟上负载情况下, 这 点确实工作良好。 因 为 squid 主进程现在能够去做更多工作,当然它有 可能会加 大 diskd 的负载。 diskd 有两个功能来帮 助解决这个问题。 首先, squid 等待 diskd 进程捕获是否队列超 出了某种 极限。 默认值是 64个排队消息。 假如 diskd 进程获取的数值远大于此, squid 会休眠片刻,并等待 diskd 完成一些未决操作。 这本质上让 squid 进入阻塞 I/O模式。它也让更多的 CPU 时间对 diskd 进程可用。通过指 定 cache_dir 行的 Q2参数的值,你可以配置这个极限值: cache_dir diskd /cache0 7000 16 256 Q2=50 第二, 假 如排队操作的数量抵达了另一个极限, squid 会停止要求 diskd 进程打开文 件。 这里的默认值是 72个消息。假如 squid 想打开一个磁盘文件读 或写,但选中的 cache_dir 有 太多的未完成操作, 那么打开请求会失败。 当打开文件读时,会导致 cache丢失。 当打开 文 件写时, 会 阻碍 squid 存储cache响应。 这 两种情况下用户仍能接受到有效响应。 唯 一实 际 的影响是 squid 的命中率下降。这个极限用 Q1参数来配置: cache_dir diskd /cache0 7000 16 256 Q1=60 Q2=50 注意在某些版本的 squid 中, Q1和Q2参数混杂在默认的配置文件里。最佳选择是, Q1 应该大于 Q2。 8.5.28.5.28.5.28.5.2 编译和配 置 diskddiskddiskddiskd 为了使用 diskd,你必须在运行 ./configure 时,在 --enable-storeio 列表后增加一项: %./configure --enable-storeio=ufs,diskd diskd 看起来是可移植的, 既 然共享内存和消息队列在现代 Unix系统上被广泛支持。 然 而,你可能需要调整与这两者相关的内核限制。内核典型的有如下可用参数: Squid 中文权威指南 122 MSGMNB 每个消息队列的最大字节限制。 对 diskd 的实际限制是每个队列大约 100个排队消息。 squid 传送的消息是 32-40字节,依赖于你的 CPU 体系。这样, MSGMNB 应该是 4000或更 多。为安全起见,我推荐设置到 8192。 MSGMNI 整个系统的最大 数量的 消息队 列。 squid 对每个 cache_dir 使用两个队列。 假如你 有 10 个磁盘, 那 就有 20个队列。 你 也许该增加更多, 因为其他应用程序也要使用消息队列。 我 推 荐的值是 40。 MSGGSZ 消息片断的大小 ( 字节) 。 大 于该值的消息被分割成多个片断。 我 通常将这个值设为 64, 以使 diskd 消息不被分割成多个片断。 MSGSEG 在单个队列里能存在的最大数量的消息片断。 squid 正常情况下, 限 制队列的长度为 100 个排队消息。记住,在 64位系统中,假如你没有增加 MSGSSZ 的值到 64,那么每个消息就 会被分割成不止 1个片断。为了安全起见,我推荐设置该值到 512。 MSGTQL 整个系统的最大数量的消息。 至 少是 cache_dir 数量的 100倍。在10个cache目录情况 下, 我推荐设置到 2048。 MSGMAX 单个消息的最大 size。对 Squid 来说, 64字节足够了。然而, 你系统中的其他应用程 序 可能要用到更大的消息。在某些操作系统例如 BSD 中,你不必设置这个。 BSD 自动设置 它 为MSGSSZ*MSGSEG。其他操作系统中,你也许需要改变这个 参数的默认值,你 可以设 置它与 MSGMNB 相同。 SHMSEG 每个进程的最大数量 的共享内 存片断 。 squid 对每个 cache_dir 使用 1个共享内存标签。 我推荐设置到 16或更高。 SHMMNI 共享内存片断数量的系统级的限制。大多数情况下,值为 40足够了。 Squid 中文权威指南 123 SHMMAX 单个共享内存片断的最大 size。 默认的, squid 对每个片断使用大约 409600字节。 为安 全起见,我推荐设置到 2MB,或 2097152。 SHMALL 可分配的共享内存数 量的系统 级限制 。在某些 系统上, SHMALL 可能表示成页数量, 而不是字节数量。 在 10个cache_dir 的系统上, 设置该值到 16MB(4096页) 足够了, 并有 足 够的保留给其他应用程序。 在BSD 上配置消息队列,增加下列选项到内核配置文件里: # System V message queues and tunable parameters options SYSVMSG# include support for message queues options MSGMNB=8192 # max characters per message queue options MSGMNI=40 # max number of message queue identifiers options MSGSEG=512 # max number of message segmentsper queue options MSGSSZ=64 # size of a message segment MUST be power of 2 options MSGTQL=2048 # max number of messages in the system options SYSVSHM options SHMSEG=16 # max shared mem segments per process options SHMMNI=32 # max shared mem segments in the system options SHMMAX=2097152 # max size of a shared mem segment options SHMALL=4096 # max size of all shared memory (pages) 在Linux 上配置消息队列,增加下列行到 /etc/sysctl.conf: kernel.msgmnb=8192 kernel.msgmni=40 kernel.msgmax=8192 Squid 中文权威指南 124 kernel.shmall=2097152 kernel.shmmni=32 kernel.shmmax=16777216 另外,假如你需要更多的控制,可以手工编辑内核资源文件中的 include/linux/msg.h 和 include/linux/shm.h。 在Solaris 上,增加下列行到 /etc/system,然后重启: set msgsys:msginfo_msgmax=8192 set msgsys:msginfo_msgmnb=8192 set msgsys:msginfo_msgmni=40 set msgsys:msginfo_msgssz=64 set msgsys:msginfo_msgtql=2048 set shmsys:shminfo_shmmax=2097152 set shmsys:shminfo_shmmni=32 set shmsys:shminfo_shmseg=16 在Digital Unix(TRU64)上,可以增加相应行到 BSD 风格的内核配置文件中,见前面所 叙。另外,你可使用 sysconfig 命令。首先,创建如下的 ipc.stanza 文件: ipc: msg-max = 2048 msg-mni = 40 msg-tql = 2048 msg-mnb = 8192 shm-seg = 16 shm-mni = 32 Squid 中文权威指南 125 shm-max = 2097152 shm-max = 4096 然后,运行这个命令并重启: # sysconfigdb -a -f ipc.stanza 一旦你在操作系统中配置了 消息队列和 共享内存, 就可以 在 squid.conf 里增加如下的 cache_dir 行: cache_dir diskd /cache0 7000 16 256 Q1=72 Q2=64 cache_dir diskd /cache1 7000 16 256 Q1=72 Q2=64 ... 8.5.38.5.38.5.38.5.3 监视diskddiskddiskddiskd 监视 diskd 运行的最好方法是使用 cache管理器。请求 diskd 页面,例如: % squidclient mgr:diskd ... sent_count: 755627 recv_count: 755627 max_away: 14 max_shmuse: 14 open_fail_queue_len: 0 block_queue_len: 0 OPSSUCCESSFAIL open 51534 51530 4 create 67232 67232 0 Squid 中文权威指南 126 close 118762 118762 0 unlink 56527 56526 1 read 98157 98153 0 write 363415 363415 0 请见 14.2.1.6章关于该输出的详细描述。 8.68.68.68.6 coss coss coss coss 存储 机制 循环目标存储机制( Cyclic Object Storage Scheme,coss)尝试为 squid 定制一个新的文 件系统。在 ufs 基础的机制下,主要的性能瓶颈来自频繁的 open()和unlink()系统调 用。 因 为每个 cache响应都存储在独立的磁盘文件里, squid 总是在打开,关闭,和删除文件。 与之相反的是, coss 使用 1个大文件来存储所有响应。 在 这种情形下, 它 是特定供 squid 使用的,小的定制文件系统。 coss 实现许多底层文件系统的正常 功能,例如给新数据分配 空间, 记忆何处有自由空间等。 不 幸的是, coss 仍没开发完善。 coss 的开发在过去数年里 进 展缓慢。虽然如此,基于有人喜欢冒险 的事实,我还是在这里描述它。 8.6.18.6.18.6.18.6.1 coss coss coss coss 如何工作 在磁盘上,每个 coss cache_dir 是一个大文件。文件大小一直增加,直到抵达它的大小 上限。这样, squid 从文件的开头处开始,覆盖掉任何存储在这里的数据。然后,新的目标 总是存储在该文件的末尾处。 squid 实际上并不立刻写新的目标数据到磁盘上。 代替的, 数据被拷贝进 1MB 的内存 缓 冲区, 叫做 stripe。在 stripe 变满后, 它被写往磁盘。 coss 使用异步写操作, 以便 squid 主进 程不会在磁盘 I/O上阻塞。 象其他文件系统一样, coss 也使用块大小概念。在 7.1.4章里,我谈到了文件号码。每 个cache目标有一个文件号码,以便 squid 用于定位磁盘中的 数据。对 coss 来说,文件号 码与块号码一样。例如,某个 cache目标,其交换文件号码等于 112,那它在 coss 文件系统 中就从第 112块开始。 因此 coss 不分配文件号码。 某些文件号码不可用,因为 cache目标 通 常在 coss 文件里占用了不止一个块。 coss块大小在 cache_dir选项中配置。因为squid 的文件号码仅仅 24位, 块 大小决定了 coss 缓存目录的最大 size:size = 块大小 x (2的24次方 )。 例如 , 对 512字节的块大小, 你 能在 coss cache_dir 中存储 8GB 数据。 Squid 中文权威指南 127 coss 不执行任何 squid 正常的 cache置换算法(见 7.5章 ) 。代 替 的 , cache命中被 "移动 " 到循环文件的末尾。这本质上是 LRU 算法。不幸的是,它确实意味着 cache命中导致磁盘 写操作,虽然是间接的。 在coss 中,没必要去删除 cache目标。 squid 简单的忘记无用目标所分配的空间。当循 环文件的终点再次抵达该空间时,它就被重新利用。 8.6.28.6.28.6.28.6.2 编译和配 置 cosscosscosscoss 为了使用 coss,你必须在运行 ./configure时,在 --enable-storeio 列表里增加它: %./configure --enable-storeio=ufs,coss ... coss 缓存目录要求 max-size 选项。它的值必须少于 stripe 大小(默认 1MB,但可以用 -- enable-coss-membuf-size 选项来配置) 。也请注意你必须忽略 L1和L2的值,它们被 ufs 基础 的文件系统使用。如下是示例: cache_dir coss /cache0/coss 7000 max-size=1000000 cache_dir coss /cache1/coss 7000 max-size=1000000 cache_dir coss /cache2/coss 7000 max-size=1000000 cache_dir coss /cache3/coss 7000 max-size=1000000 cache_dir coss /cache4/coss 7000 max-size=1000000 甚至,你可以使用 block-size 选项来改变默认的 coss 块大小。 cache_dir coss /cache0/coss 30000 max-size=1000000 block-size=2048 关于 coss 的棘手的事情是, cache_dir 目录参数(例如 /cache0/coss)实际上不是目录, 它是 squid 打开或创建的常规文件。 所 以你可以用裸设备作为 coss 文件。 假 如你错误的创 建 coss 文件作为目录,你可以在 squid 启动时见到如下错误: 2003/09/29 18:51:42| /usr/local/squid/var/cache: (21) Is a directory FATAL: storeCossDirInit: Failed to open a coss file. 因为 cache_dir 参数不是目录, 你 必须使用 cache_swap_log 指 令 (见 13.6章)。否则squid 试图在 cache_dir 目录中创建 swap.state文件。在该情形下,你可以见到这样的错误: 2003/09/29 18:53:38| /usr/local/squid/var/cache/coss/swap.state: Squid 中文权威指南 128 (2) No such file or directory FATAL: storeCossDirOpenSwapLog: Failed to open swap log. coss 使用异步 I/O以实现更好的性能。 实 际上, 它 使用 aio_read()和aio_write()系统调 用。 这点也许并非在所有操作系统中可用。 当前它们可 用在 FreeBSD,Solaris,和Linux 中。 假 如 coss 代码看起来编译正常,但你得到 "Function not implemented"错误消息,那就必须在内核 里激活这些系统调用。在 FreeBSD 上,必须在内核配置文件中有如下选项: options VFS_AIO 8.6.38.6.38.6.38.6.3 coss coss coss coss 发行 coss 还是实验性的功能。 没 有充分证实源代码在日常使用中的稳定性。 假 如你想试验 一 下,请做好存储在 cosscache_dir 中的资料丢失的准备。 从另一面说, coss 的初步性能测试表现非常优秀。示例请见附录 D。 coss 没有 很好 的 支 持 从 磁 盘 重 建 cache 数据 。当 你 重 启 squid 时, 你也 许 会 发 现 从 swap.state文件读取数据失败, 这样就丢失了所有的缓存数据。 甚至, squid 在重启后, 不 能 记忆它在循环文件里的位置。它总是从头开始。 coss 对目标置换采用非标准的方式。相对其他存储机制来说,这可能导致命中率更低。 某些操作系统在单个文件大于 2GB 时,会有问题。假如这样的事发生,你可 以创建更多小 的coss 区域。例如: cache_dir coss /cache0/coss0 1900 max-size=1000000 block-size=128 cache_dir coss /cache0/coss1 1900 max-size=1000000 block-size=128 cache_dir coss /cache0/coss2 1900 max-size=1000000 block-size=128 cache_dir coss /cache0/coss3 1900 max-size=1000000 block-size=128 使用裸磁盘设备 (例如 /dev/da0s1c) 也不会工作得很好。 理由之一是磁盘设备通常要 求 I/O发生在 512个字节的块边界(译者注:也就是块设备访问) 。 另外直接的磁盘访问绕过 了 系统高速缓存,可能会降低性能。然而,今天的许多磁盘驱动器,已经内建了高速缓存。 8.78.78.78.7 null null null null 存储 机制 Squid 有第 5种存储机制叫做 null。 就 像名字暗示的一样, 这 是最不健壮的机制。 写往 null Squid 中文权威指南 129 cache_dir 的文件实际上不被写往磁盘。 大多数人没有任何理由要使用 null 存储系统。 当 你想完全禁止 squid 的磁盘缓存时, null 才有用。 你不能简单的从 squid.conf 文件里删除所有 cache_dir 行, 因为这样的话 squid 会增 加默认的 ufscache_dir。null 存储系统有些时候在测试 squid, 和压力测试时有用。 既然文 件 系统是典型的性能瓶颈,使用 null 存储机制能获取基于当前硬件的 squid 的性能上限。 为了使用该机制,在运行 ./configure 时,你必须首先在 --enable-storeio 列表里指定它: %./configure --enable-storeio=ufs,null ... 然后在 squid.conf 里创建 cache_dir 类型为 null: cache_dir /tmp null 也许看 起 来 有 点奇 怪 , 你 必须 指 定 目 录 给 null 存储机 制 。 squid 使用目 录 名 字 作 为 cache_dir 标识符。例如,你能在 cache管理器的输出里见到它。 8.88.88.88.8 哪种 最适 合我 ? Squid 的存储机制选择看起来有点 混乱和迷惑 。 aufs 比diskd 更好?我的系统支 持 aufs 或coss 吗?假如我使用新的机制,会丢失数据吗?可否混合使用存储机制? 首先,假如 Squid 轻度使用(就是说每秒的请求数少于 5个 ) ,默 认 的 ufs 存储机制足 够 了。在这样的低请求率中,使用其他存储机制,你不会观察到明显的性能改进。 假如你想决定何种机制值得一试,那你的 操作系统可能是个 决定因素。例如 , aufs 在 Linux 和Solaris 上运行良好, 但 看起来在其他系统中有问题。 另 外, coss 代码所用到的函 数, 当前不可用在某些操作系统中(例如 NetBSD)。 从我的观点看来,高性能的存储机制在系统崩溃事件中,更易受数据丢失的影响。这 就是追求最好性能的权衡点。然而对大多数人来说, cache数据相对价值较 低。假如 squid 的缓存因为系统崩溃而破坏掉,你会发现这很容易,只需简单的 newfs磁盘分区,让 cache 重新填满即可。 如 果你觉得替换 Squid 的缓存内容较困难或代价很大, 你 就应该使用低速 的, 但可信的文件系统和存储机制。 近期的 Squid 允许你对每 个 cache_dir 使用不同的文件 系统和 存储机 制。然 而实际 上, 这种做法是少见的。假如所有的 cache_dir 使用相同的 size 和相同的存储机制,可能冲突更 少。 Squid 中文权威指南 130 第第第第9999章章章章Cache Cache Cache Cache 拦截 拦截 拦截 拦截 Cache拦截是让传输流向 Squid 的流行技术, 它 不用配置任何客户端。 你 可以配置路 由 器或交换机将 HTTP连接转发到 squid 运行的主机。 squid 运行的操作系统被配置成接 受外 部数据包, 并 将其递交给 squid 进程。 为 了让 HTTP拦截生效, 你 必须配置 3个独立的因 素: 网络设备, squid 运行的操作系统,和 squid 自身。 (译者注: Cache拦截实际上指的是 Squid 的透明代理) 9.1 9.1 9.1 9.1 它如 何工 作? Cache拦截包含了某些网络欺骗,它对理解在客户端和 Squid 之间的会话有用。我使 用 图9-1和如下的 tcpdump 示例输出,来解释当数据包通过网络时,如何被拦截。 Figure 9-1. How HTTP interception works Squid 中文权威指南 131 1.用户代理 (user-agent)想请求某个资源,它 对原始服 务器发 起 index.html 请求,例如: www.oreilly.com。它需要原始服务器的 IP地址,所以先发起一个 DNS 请求: Packet 1 TIME: 19:54:41.317310 UDP: 206.168.0.3.2459 -> 206.168.0.2.53 DATA:.d...........www.oreilly.com..... --------------------------------------------------------------------------- Packet 2 TIME: 19:54:41.317707 (0.000397) UDP: 206.168.0.2.53 -> 206.168.0.3.2459 DATA:.d...........www.oreilly.com.............PR.....%........PR. ....$........PR...ns1.sonic.net.........PR...ns2.Q........PR ...ns...M...............h.............!.z.......b...... 2.现在有了 IP地址,用户代理初始化到原始服务器 80端口的 TCP 连接: Packet 3 TIME: 19:54:41.320652 (0.002945) TCP: 206.168.0.3.3897 -> 208.201.239.37.80 Syn DATA: 3. 路由器或交换机注意到目的地址是 80端口的 TCP SYN 包。 下 一步会发生什么依赖 于 特定的拦截技术。 在 4层交换和路由策略上, 网络设备简单的将 TCP 包转发到 Squid 的数 据 链路地址。 当 squid 直接 挂在网络设备上时, 就 这样工作。 对 WCCP 来说, 路 由器封装 TCP 包为 GRE 包。因为GRE 包有它自己的 IP地址, 它 可能被通过多个子网进行路由。 换 句话 说, WCCP 不要求 squid 直接挂在路由器上。 Squid 中文权威指南 132 4.Squid 主机的操作系统接受到拦截包。对 4层交换来说, TCP/IP包并没有改变。假如 包使用了 GRE 封装,主机会剥离外部的 IP和GRE 头部,并将原始的 TCP/IP包放在输入 队列里。注意 squid 主机接受到的包是针对外部地址的(原始 服务器的) 。 正常情况下,这 个包不匹配任何本地地址,它会被丢弃。为了让主 机接受外部数据包,你必须在大多数操 作系统上激活 IP转发。 5.客户端的 TCP/IP包被包过滤代码处理。数据包必须匹配某个规则,该规则指示内核 转交这个包给 squid。如果没有这样的规则,内核简单的将包按照它自己的方式转发给原始 服务器,这不是你想要的。 注意 SYN 包的目的端口是 80,但 squid 可能侦听在不同的端口,例如 3128。包过滤规 则允许你改变端口号。你不必让 squid 侦听在 80端口。通过 tcpdump,你能见到这步,因为 转发的包不会再次通过网络接口代码。 即使 squid 侦听在 80端口,包过滤器的重定向规则仍是必要的。可以让 squid 不在这些 端口上接受拦截包。重定向规则有点神奇,它转交外部数据包给 squid。 6.Squid 接受到新连接的通知, 它接受这个连接。 内核发送 SYN/ACK 包返回给客户端 : Packet 4 TIME: 19:54:41.320735 (0.000083) TCP: 208.201.239.37.80 -> 206.168.0.3.3897 SynAck DATA: 就象你见到的一样, 源 地址是原始服务器, 尽 管这个包不会抵达原始服务器。 操 作系 统 只是简单的将源地址和目的地址交换一下,并将它放进响应数据包里。 7.用户代理接受到 SYN/ACK 包, 建 立起完整的 TCP 连接。 用 户代理现在相信它是连 接 到原始服务器,所以它发送 HTTP请求: Packet 5 TIME: 19:54:41.323080 (0.002345) TCP: 206.168.0.3.3897 -> 208.201.239.37.80Ack DATA: --------------------------------------------------------------------------- Packet 6 Squid 中文权威指南 133 TIME: 19:54:41.323482 (0.000402) TCP: 206.168.0.3.3897 -> 208.201.239.37.80AckPsh DATA:GET/ HTTP/1.0 User-Agent: Wget/1.8.2 Host: www.oreilly.com Accept: */* Connection: Keep-Alive 8.Squid 接受 HTTP 请求。它使用 HTTP Host 头部来转换局部 URL 为完整的 URL。在 这种情形下,可在 access.log 文件里见到 http://www.oreilly.com。 9.从这点开始, squid 正常的处理请求。一般 cache命中会立刻返回。 cache丢失会转发 到原始服务器。 10.最后,是 squid 从原始服务器接受到的响应: Packet 8 TIME: 19:54:41.448391 (0.030030) TCP: 208.201.239.37.80 -> 206.168.0.3.3897AckPsh DATA: HTTP/1.0 200 OK Date: Mon, 29 Sep 2003 01:54:41 GMT Server: Apache/1.3.26 (Unix) PHP/4.2.1 mod_gzip/1.3.19.1a mo d_perl/1.27 P3P: policyref="http://www.oreillynet.com/w3c/p3p.xml",CP="C AODSPCOR CURa ADMa DEVa TAIa PSAa PSDa IVAa IVDa CONo OUR DELa PUBi OTRa INDPHYONLUNIPURCOMNAVINTDEMCNTSTAP RE" Squid 中文权威指南 134 Last-Modified: Sun, 28 Sep 2003 23:54:44 GMT ETag: "1b76bf-b910-3ede86c4" Accept-Ranges: bytes Content-Length: 47376 Content-Type: text/html X-Cache: MISS from www.oreilly.com X-Cache: MISS from 10.0.0.1 Connection: keep-alive 不应该让交换机或路由器来拦截 squid 到原始服务器的连接。 假 如这种情况发生, squid 结束与自己的会话, 并且不能 满足任 何 cache 丢失。防止这类转 发死循环的最好方法 是, 确认用户和 squid 连接到交换机或路由器的独立接口。 无论何时, 应该在指定接口上应用 拦 截规则。最明显的,不该在 squid 使用 的接口上激活拦截。 9.2 9.2 9.2 9.2 为何 要( 或不要 )拦 截 ? 许多单位发现, cache拦截很有用, 因为他们不能,或不愿意配置所有用户的 web 浏览 器。相对于配置成百上千台工作站来说,在单个交换机或路由器上做一点网络欺骗更容易。 从我们面临的许多选择来看, cache拦截确实有好也有坏。它可能让你的生活更容易,但也 许会更难。 Cache 拦截的最明显的贡献是, 所有 HTTP请求通过 squid 自动离开你的网络。 你不 必 担心配置任何浏览器, 用户可能在浏览器上禁止他们的代理设置。 cache 拦截让网络管理 员 完全控制 HTTP会话。你可以改变, 增加,或删除 squid 的缓存,而不会显著影响你的用 户 上网冲浪。 关于 HTTP拦截的 主要不利点就是该技术违背了 TCP/IP的标准。 这 些协议要求路由 器 或交换机转发 TCP/IP包到目的 IP地址里指定的主机。然而转发包 到 cache代理 破坏了这 些规则。 代 理伪装身份接受转交过来的连接。 用户代理被欺骗了, 以 为它们在与真正的 web 服务器会话。 这样的混乱导致在老版本的 Microsoft IE浏览器中产生严重问题。浏览器 的 Reload 按 钮是刷新 HTML页面的最容易的方法。 当 浏览器被配置成使用 cache代理时, reload 请求 包 含了 一个 Cache-Control:no-cache头部, 它强迫产生 cache丢失 (或 cache确 认 ) ,并确 保 响 Squid 中文权威指南 135 应是最近更新的。假如没有明确配置使用 代理,浏览器会忽略该头部。当使用 cache拦截 时,浏览器认为它在连接到原始服务器,因此没必要发送该头部。在这种情形下, squid 不 会告知用户的 Reload 按钮, 也 许不会验证 cache响应。 squid 的ie_refresh 提供了解决此 bug 的局部解决方法(见附录 A)。Microsoft 已经在其 IE 5.5 SP1中解决了这个问题。 因为类似的理由,你不能结合 cache拦截使用 HTTP 代理验 证。因为客户端不知道这 个代理,它不会发送必要的 Proxy-Authorization 头部。另外, 407(代理验证请求)响应代 码也不恰当,因为响应 看起来象来自原始服务器,原始服务器从来不会发送如此响应。 也不能在 cache拦截中使用 RFC 1413 ident 查询 ( 见 6.1.2.11章节)。Squid 不能对必要 的 IP地址建立新的 TCP Socket 连接。操作系统在转发拦截连接 到 squid 时,它执行欺骗。然 后,当 squid 希望 bind 新的 TCP Socket 到外部 IP地址时, 它 不能执行欺骗。 它想 bind 的地 址实际上并非真正本地的,所以 bind 系统调用失败。 cache 拦截 也与设计成阻止地址欺骗的IP过滤 冲 突 ( 见 RFC 2267:Network Ingress Filtering: Defeating Denial of Service Attacks Which Employ IP Source AddressSpoofing)。考虑 如图 9-2显示的网络。路由器有 2个LAN 接口 :lan0和lan1。网络管理员在路由器上使用包过 滤器,以确保 没有内部主机传送假冒源地址的数据包。路由器只会转发源地址对应相连网 络的数据包。包过滤规则也许看起来如下: # lan0 allow ip from 172.16.1.0/24 to any via lan0 deny ip from any to any via lan0 # lan1 allow ip from 10.0.0.0/16 to any via lan1 deny ip from any to any via lan1 Figure 9-2. Interception caching breaks address spoofing filters Squid 中文权威指南 136 现在看看,当路 由器 和 lan1中的 squid 主机配置成拦 截来 自 lan0中的 HTTP 连接后, 会发生什么。 Squid 装扮成原始服务器, 这 意味着从 squid 到用户的响应 TCP 包欺骗了源 地 址。 lan0过滤规则导致路由器拒绝这些包。为了让 cache拦截生效,网络管理员须移除 lan0 规则。这样就 让网络有漏洞,从而易遭拒绝服务攻击。 我在先前的章节里描述过,客户端在打开连接之前必须先进行 DNS 查询。在某些防火 墙环境中, 这样做可 能有问题。 你想进行 HTTP拦截的主机必须能够查询 DNS。 如果客 户 端了解自己正使 用代理 (因为 手工配 置或代 理自动 配置) ,它通常就不去解析 主机名 。代 替的,它简单的将完整 URL 转发给 squid,由 squid 来查询原始服务器的 IP地址。 另一个小问题是, squid 接受任意目的 IP地址的连接。 例如, 某个 web 站点当机了, 但 它仍然有 DNS 记录存在。 squid 伪装这个站点接受 TCP 连接。客户端会认为该站点仍然在 运行,因为连接有效。当 squid 连接到原始服务器失败时,它强迫返回错误消息。 万一形势不清, HTTP拦截在初次使用时有些棘手或困难。 许多不同的组件必须组合 工 作, 并 且要配置正确。 甚至, 从 内存中恢复整个配置也很困难。 我强烈建议你在将其应用 于 生产环境之前,先建立测试环境。一旦你让它正常运行,请记录每一步细节。 9.39.39.39.3 网络 设备 现在你了解了 cache拦截的相关细节, 让 我们看看如何实际让它工作。 我们先配置网 络 设备,它们用来拦截 HTTP连接。 Squid 中文权威指南 137 9.3.19.3.19.3.19.3.1 内置SquidSquidSquidSquid 在该配置中, 你 无需交换或网络路由设备来拦截 HTTP 连 接 。 代替 的 , squid 运行的 Unix 系统,也就是路由器(或网桥) , 请见图 9-2。 Figure 9-3. A system that combines routing and caching can easily intercept HTTP traffic 该配置本质上跳过了 9.1章的头三步。 squid 主机充当网络路由器, 它 接受 HTTP连接 包。 假如你采用此方法,请直接跳到 9.4章。 9.3.29.3.29.3.29.3.2 四层交换 许多单位使用四层交换机来支持 HTTP拦截。 这 些产品提供更多的功能, 例 如健壮性 检 测和负载均衡。 我 在这里仅仅讲讲拦截。 关 于健壮性检测和负载均衡的信息, 请见 O'Reilly's Server Load Balancing and Load Balancing Servers, Firewalls, and Caches (John Wiley & Sons). 下面的章节包含了许多产品和技术的示例配置。 9.3.2.19.3.2.19.3.2.19.3.2.1 Alteon/NortelAlteon/NortelAlteon/NortelAlteon/Nortel 下面的配置来自 ACEswitch 180和Alteon's WebOS 8.0.21。网络设置请见图 9-4。 Figure 9-4. Sample network for layer four switch interception, for Alteon and Foundry examples 客户端连接到端口 1, 通 过端口 2连接到因特网, squid 运行在端口 3。 下 面的行是交换 机 的/cfg/dump 命令的输出。你无须敲入所有这些行。甚至,在 Alteon 的新版软件里,某些 命 令可能改变了。注意 Alteon 把这个功能叫做 Web Cache重定向( WCR) 。如 下 是 处 理 步 骤 : Squid 中文权威指南 138 • 1. 首先, 你必须分配给 Alteon 交换机一个 IP地址。 这是必要的, 以 便交换 机 能检查 squid 的存活状态。 /cfg/ip/if 1 ena addr 172.16.102.1 mask 255.255.255.0 broad 172.16.102.255 • 2.Alteon 的WCR 属于服务负载均衡 (SLB)配置。所以,必须使用如下命令在 交换机上激活 SLB 功能: /cfg/slb on • 3. 现在,用 squid 的IP地址定义 real server: /cfg/slb/real 1 ena rip 172.16.102.66 • 4. 必须定义一个组,并分配给 real server 一个组号: /cfg/slb/group 1 health tcp add 1 • 5. 下一步定义 2个过滤规则。第1条规则匹配 HTTP连接 ( 目的端口是 80的TCP 包),并重 定向它们到组1里的 server。第2条规则匹配所有其他数据包, 并 正常转发它 们。 /cfg/slb/filt 1 ena action redir Squid 中文权威指南 139 sip any smask 0.0.0.0 dip any dmask 0.0.0.0 proto tcp sport any dport http group 1 rport 0 /cfg/slb/filt 224 ena action allow sip any smask 0.0.0.0 dip any dmask 0.0.0.0 proto any • 6. 最后一步是给 SLB 配置指定的交换端口。 在 端口 1上, 处 理客户端连接 ( 这 也是客户端连接的端口) , 并 增加 2条过滤规则。 在端口 2上, 仅须配置它正常服务 (例 如,向上连接到 Internet): cfg/slb/port 1 client ena filt ena Squid 中文权威指南 140 add 1 add 224 /cfg/slb/port 2 server ena 为了验证 HTTP 拦截配置正确并工作良好,你可以使用 /stats/slb 和/info/slb 菜单里的命 令。 /info/slb/dump 是快速有效的查看整个 SLB 配置的方法: >> Main# /info/slb/dump Real server state: 1: 172.16.102.66, 00:c0:4f:23:d7:05, vlan 1, port 3, health 3, up Virtual server state: Redirect filter state: 1: dport http, rport 0, group 1, health tcp, backup none real servers: 1: 172.16.102.66, backup none, up Port state: 1: 0.0.0.0, client filt enabled, filters: 1 224 2: 0.0.0.0, server filt disabled, filters: empty 3: 0.0.0.0 filt disabled, filters: empty 在该输出里,注意到交换机显示 Squid 在端口 3上可到达,并且运行正常。你也能见到 过滤规则 1应用到端口 1。 在 端口状态节里, 端 口 1定义为客户端连接端口, 端 口 2简单的标 记 为服务端口。 Squid 中文权威指南 141 /stats/slb/real 命令显示 real server(squid)的有用统计: >> Main# /stats/slb/real 1 ------------------------------------------------------------------ Real server 1 stats: Health check failures: 0 Current sessions: 41 Total sessions: 760 Highest sessions: 55 Octets: 0 大部分统计与任务(例如 TCP 连接)数量相关。假如再次运行该命令,总共的任务计 数会增加。最后, /stats/slb/group 命令显示几乎同样的信息: >> Main# /stats/slb/group 1 ------------------------------------------------------------------ Real server group 1 stats: Current Total Highest Real IP address Sessions Sessions Sessions Octets ------------------------------------------------------------ 1 172.16.102.66 65 2004 90 0 ------------------------------------------------------------ 65 2004 90 0 假如不止 1个real server 在组里,该输出会更有趣。 9.3.2.29.3.2.29.3.2.29.3.2.2 FoundryFoundryFoundryFoundry 下面的配置示例来自 ServerIron XL,运行的软件版本是 07.0.07T12。跟前面一样,客 Squid 中文权威指南 142 户端在端口 1,Internet 连接在端口 2,squid 运行在端口 3。然而,这样的配置少 了点东西, 因为这 里 可 以 激 活 HTTP 全局拦 截 。 Foundry 的cache 拦截的 名 字 叫 做 Transparent Cache Switching(TCS) 。请 参 考 图 9-4。首先请给交换机分配 1个IP地址,以便执行健壮性检测: ip address 172.16.102.1 255.255.255.0 Foundry 允许你在特定端口上激活或禁用 TCS。然而简单起见,这里全局激活它: ip policy 1 cache tcp http global 在该行里, cache 是针对 TCS 功能的关键字。下 1行定义 web cache,我定义其名字为 squid1,并且告诉交换机它的 IP地址: server cache-name squid1 172.16.102.66 最后的步骤是将 web cache加进 cache组里: server cache-group 1 cache-name squid1 假如在转发连接时有问题,请参阅 show cache-group 命令的输出: ServerIron#show cache-group Cache-group 1 has 1 membersAdmin-status = Enabled Active = 0 Hash_info: Dest_mask = 255.255.255.0 Src_mask = 0.0.0.0 Cache Server Name Admin-status Hash-distribution squid1 6 3 HTTP Traffic From <-> to Web-Caches Name: squid1 IP: 172.16.102.66 State: 6 Groups = 1 Host->Web-cache Web-cache->Host State CurConn TotConn Packets Octets Packets Octets Client active 441 12390 188871 15976623 156962 154750098 Web-Server active 193 11664 150722 151828731 175796 15853612 Squid 中文权威指南 143 Total 634 24054 339593 167805354 332758 170603710 某些输出有些模糊, 但 通过重复该命令, 并 且观察计数器的增长, 你 能了解拦截是否 在 进行。 show server real 提供几乎同样的信息: ServerIron#show server real squid1 Real ServersInfo Name : squid1 Mac-addr: 00c0.4f23.d705 IP:172.16.102.66 Range:1 State:Active Wt:1 Max-conn:1000000 Src-nat (cfg:op):(off:off) Dest-nat (cfg:op):(off:off) squid1 is a TRANSPARENTCACHE in groups 1 Remote server : No Dynamic : No Server-resets:0 Mem:server: 02009eae Mem:mac: 045a3714 Port State Ms CurConn TotConn Rx-pkts Tx-pkts Rx-octet Tx-octet Reas ----------------------------------------------------------- http active 0 855 29557 379793 471713 373508204 39425322 0 default active 0 627 28335 425106 366016 38408994 368496301 0 Server Total 1482 57892 804899 837729 411917198 407921623 0 最后,使用 show logging 命令来观察交换机是否显示 squid 正常或异常: ServerIron#show logging... 00d00h11m51s:N:L4 server 172.16.102.66 squid1 port 80 is up 00d00h11m49s:N:L4 server 172.16.102.66 squid1 port 80 is down 00d00h10m21s:N:L4 server 172.16.102.66 squid1 port 80 is up 00d00h10m21s:N:L4 server 172.16.102.66 squid1 is up Squid 中文权威指南 144 注意 ServerIron 认为服务运行在 80端口。以后你会见 到 squid 运行在 3128端口的示例。 包过滤规则实际上将包的目 的地址从 80改变为 3128。这导致一些与状态检测有 关的有趣结 果,我在 9.3.2.5节里会讲到。 9.3.2.39.3.2.39.3.2.39.3.2.3 ExtremeExtremeExtremeExtreme NetworksNetworksNetworksNetworks 在该示例里, 硬 件是 Summit1i, 软件 版 本 是 6.1.3b11。 再 次将客户端分配在端口 1,Internet 在端口 2,squid 在端口 3。网络配置见图 9-5。 Figure 9-5. Sample network for intercepting with a router, for the Extreme and Cisco policy routing examples Extreme 交换机仅仅对在不同子网间进行路由的数据包进行 HTTP连接的拦截。 换 句 话 说, 如 果你配置 Extreme 交换机使用二层模式 ( 单一 VLAN 里 ) , 就不 能 将 包转发给 squid。 为了让 HTTP拦截正常工作,必须给用户, Squid,和 Internet 配置不同的 VLAN。 configure Default delete port 1-8 create vlan Users configure Users ip 172.16.102.1 255.255.255.192 configure Users add port 1 create vlan Internet configure Internet ip 172.16.102.129 255.255.255.192 configure Internet add port 2 create vlan Squid Squid 中文权威指南 145 configure Squid ip 172.16.102.65 255.255.255.192 configure Squid add port 3 下一步是激活和配置交换机的路由: enable ipforwarding configure iproute add default 172.16.102.130 最后,配置交换机重定向 HTTP连接到 Squid: create flow-redirect http tcp destination any ip-port 80 source any configure http add next-hop 172.16.102.66 9.3.2.49.3.2.49.3.2.49.3.2.4 CiscoCiscoCiscoCisco ArrowpointArrowpointArrowpointArrowpoint 下类配置基于我以前的测试笔记。 然 而, 最 近我没有使用这类型的交换机, 不 能确保 如 下命令仍然正确: circuit VLAN1 ip address 172.16.102.1 255.255.255.0 service pxy1 type transparent-cache ip address 172.16.102.66 port 80 protocol tcp active owner foo content bar add service pxy1 protocol tcp Squid 中文权威指南 146 port 80 active 9.3.2.59.3.2.59.3.2.59.3.2.5 关于HTTP HTTP HTTP HTTP 服 务和健 壮性 检测的评 论 在上面的示例里, 路由器 /交换机都直接转发包, 不会改变目的 TCP 端口。 在 9.4章里 用 到的包过滤规则改变了目的端口。如果试图在同一主机上运行 HTTP服务和 squid,那么就 产生了一个有趣的问题。 为了在 3128端口运行 Squid 的同时,还要在 80端口运行 HTTP,包过滤配置必须有 1条 特殊的规则,它接受到本机 HTTP服务的 TCP 连接。否则,连 接会直接转交给 Squid。该 规则易于建立。假如目的端口是 80,并且目的地址是服务器的,那么主机正常接受这个包。 然而所有的拦截包有外部目的地址,所 以它们不会匹配该规则。 然而,当路由器 /交换机进行 HTTP 健壮性检测时,它连接到服务器 的 IP地址。这样, 健壮性检测的数据包匹配了上述规则, 它 不会转交给 Squid。 路 由器 /交换机检测了错误的 服 务。假如 HTTP服务 down 掉了,而 squid 还在运行,那健壮性检测就产生错误结果。 解决这个问题的一些选择是: • 1.不要在 Squid 主机上运行 HTTP服务; • 2.增加 1条特殊的包过滤规则 ,将来自 路由器 /交换机的状态检测的 包转交 给 squid; • 3.配置路由器 /交换机,改变目的端口为 3128; • 4.禁止 4层状态检测。 9.3.39.3.39.3.39.3.3 Cisco Cisco Cisco Cisco 策略路由 策略路由与 4层交换并非不同。 它在 Cisco 和其他公司的路由产品上执行。 主 要的区 别 是策略路由不包括任何健壮性检测。这样 ,假 如 squid 超载或完全不可 响应,路由器还会 继续转发包到 squid,而不是将包路由到原始服务器。策略路 由要 求 squid 位于路由器直接 相连的子网中。 在本示例里,使用了 Cisco 7204路由器,运行 IOS Version 12.0(5)T。网络配置与前面 的 一样,见图 9-5。 首先的配置步骤是定义访问列表, 匹 配来自客户端的到 80端口的数据包。 必 须确保 Squid 发起的到 80端口的数据包不会被再次拦截。 做 到这点的方法之一 是, 定 义 1个特殊规则, 拒 绝来自 squid 的数据包,紧跟 1条规则允许所有其他的数据包: Squid 中文权威指南 147 access-list 110 deny tcp host 172.16.102.66 any eq www access-list 110 permit tcp any any eq www 另外, 如果 Squid 和用户位于不同的子网, 你 可以仅仅允许来自用户所在网络的数据 包: access-list 110 permit tcp 10.102.0.0 0.0.255.255 any eq www 下一步是定义路由映射。在这里你告诉路由器转发拦截包到何处去: route-map proxy-redirect permit 10 match ip address 110 set ip next-hop 172.16.102.66 这些命令表明, “假如 IP地址匹配访问列表 110, 就转发该包到 172.16.102.66”。在 route- map 行的数字 10是一个序列号, 假 如你有多个路由映射的话。 最 后一步是应用路由映射到 客 户端连接的接口: interface Ethernet0/0 ip policy route-map proxy-redirect IOS 不对策略路由提供很多调试方法。然而, show route-map 命令足够可用: router#show route-map proxy-redirect route-map proxy-redirect, permit, sequence 10 Match clauses: ip address (access-lists): 110 Set clauses: ip next-hop 172.16.102.66 Policy routing matches: 730 packets, 64649 bytes 9.3.49.3.49.3.49.3.4 WebWebWebWeb CacheCacheCacheCache Coordination Coordination Coordination Coordination 协议 Squid 中文权威指南 148 Cisco 对4层交换技术的响应叫做 Web Cache Coordination Protocol(WCCP).WCCP 在许 多 方面与典型的 4层拦截不同。 首先,拦截包被封装在 GRE(路由封装类)里。这点允许数据包跨子网传输,也就意 味着 squid 不必直接连在路 由器上 。因为 数据包 是封装 的, squid 主机必须对其进 行解包。 并非所有的 Unix 系统有解开 GRE 包的代码。 第二个不同是,路由器如何决定将负载分摊到多个 cache上。事实上,路由器不做这 个决定,由 cache来做。当路由器有一组支持 WCCP 的cache时, 其中一个 cache主动成 为组的领导。 由 领导 cache来决定如何分摊负载和通知路由器。 在 路由器重定向然任何连 接 之前,这是一个额外的必要步骤。 因为WCCP 使用 GRE,路由器可能强迫要求将来自 HTTP请求的大 TCP 包分割成片 断。 幸 运的是, 这点不会经常发生, 因 为大部分 HTTP请求比以太网 MTU size(1500字节 ) 要小。默认的 TCP 和IP包头部是 20字节,这意味着以太网帧能实际携带 1460字节的数据。 GRE 封装在 GRE 头部增加了 20 字节, 另外在第二个 IP头部增加了 20字节。 这样来自客 户 端的正常的 1500字节的 TCP/IP包, 在 封装后变成了 1540字节。 这 样数据包就太大而不能 在 单个以太网帧里传输,所以路由器将原始包分割成两个片断。 9.3.4.19.3.4.19.3.4.19.3.4.1 WCCPv1WCCPv1WCCPv1WCCPv1 该节的配置示例在运行 IOS Version 12.0(5)T 的Cisco 7204路由器上测试。 网 络配置跟 图 9-5同。 首先,在 IOS 配置中输入如下两行,激活路由器的 WCCP: ip wccp version 1 ip wccp web-cache 接着,必须在单独的路由器 接口上激 活 WCCP。在 HTTP 包离开路由器的接口上激活 WCCP,也就是路由器连接到外部原始服务器或 Internet 网关的接口: interface Ethernet0/1 ip address 172.16.102.129 255.255.255.192 ip wccp web-cache redirect out 请确认保存了配置改变。 你也许想使用访问列表来阻止某 些 web 站点的拦截。可以使用访问列表来防止循 环转 发。例如: Squid 中文权威指南 149 ! don't re-intercept connections coming from Squid: access-list 112 deny tcp host 172.16.102.66 any eq www ! don't intercept thisbroken web site access-list 112 deny tcp any 192.16.8.7 255.255.255.255 eq www ! allow other HTTP traffic access-list 110 permit tcp any any eq www ip wccp web-cache redirect-list 112 路由器不发送任何数据 到 squid ,直到 squid 宣称它自己是路由器。我在 9.5.1节里解释 如何配置 squid 的WCCP。 9.3.4.29.3.4.29.3.4.29.3.4.2 WCCPv2WCCPv2WCCPv2WCCPv2 当前标准的 Squid 发布仅支持 WCCPv1。然而,可在 http://devel.squid-cache.org/找到 WCCPv2的补丁。该代码仍是实验性的。注意从路 由器发送 到 Squid 的GRE 包,包含了额 外的 4个字节。 WCCPv2在GRE 头部和封装的 IP包之间,插入了一个重定向头部。也许需 要修改内核代码来计算这个额外的头部。 9.3.4.39.3.4.39.3.4.39.3.4.3 调试 IOS 提供许多命令来监视和调 试 WCCP。show ip wccp web-cache命令提供一些基本的 信息: router#show ip wccp web-cache Global WCCP information: Router information: Router Identifier: 172.16.102.129 Protocol Version: 1.0 Service Identifier: web-cache Number of Cache Engines: 1 Number of routers: 1 Squid 中文权威指南 150 Total Packets Redirected: 1424 Redirect access-list: -none- Total Packets Denied Redirect: 0 Total Packets Unassigned: 0 Group access-list: -none- Total Messages Denied to Group: 0 Total Authentication failures: 0 欲了解更多细节,在前叙命令后加一个 detail 单词: router#show ip wccp web-cache detail WCCP Cache-Engine information: IP Address: 172.16.102.66 Protocol Version: 0.4 State: Usable Initial Hash Info: 00000000000000000000000000000000 00000000000000000000000000000000 Assigned Hash Info: FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF HashAllotment: 256 (100.00%) Packets Redirected: 1424 Connect Time: 00:17:40 这里可以看到 squid 的IP地址和状态。假如不 止一 个 cache 与路由器会话,那 么 hash 分配信息看起来不同。大多数情况下,每个 cache接受到相等的 hash 值。 注意第二条命令输出的协议版本值, 与 第一条命令的不一样。 不 幸的是, 赋 予了版本 号 Squid 中文权威指南 151 太多的意义。 show ip wccp web-cache命令看起来报告 WCCP 协议的主版本号(例如 1或2), 然而 show ip wccp web-cache detail 的版本号看起来匹配 Squid 的wccp_version 指令的值。 9.49.49.49.4 操作 系统 配置 为了让 cache拦截正常工作, 必 须在操作系统中激活某些网络功能。 首先, 必 须激活 IP 包转发。这就允许操作系统接受目的地址是外部 IP的数据包。接着,必须激活和配置内核 中的相关代码,以重定向外部包到 Squid。 9.4.19.4.19.4.19.4.1 LinuxLinuxLinuxLinux 本节的指导适合 2.4系列 Linux 内核。我使用 RedHat Linux7.2(内核是 2.4.7-10)。假如 你使用的版本不同,那可能不能运行。建议搜索下 Squid 的FAQ 或其他地方,找到关于内 核的更新的或历史的信息。 在我测试 iptables 过程中,不必激活 IP转发。然而,你也可以试试在一开始就激活它, 并在一切运行良好后,看看能否禁掉它。激活包转发的最好的方法是在 /etc/sysctl.conf 文件 里增加如下行: net.ipv4.ip_forward = 1 一般来说,在 HTTP 拦截生效前,不必编译新内核。假如你不知道如何配置和创建 新 Linux 内核,请参阅 O'Reilly's Running Linux by Matt Welsh, Matthias Kalle Dalheimer, and Lar Kaufman。当你配置内核时,请确认如下选项被激活: o General setup Networking support (CONFIG_NET=y) Sysctl support (CONFIG_SYSCTL=y) o Networking options Network packet filtering (CONFIG_NETFILTER=y) TCP/IP networking (CONFIG_INET=y) Netfilter Configuration Connection tracking (CONFIG_IP_NF_CONNTRACK=y) Squid 中文权威指南 152 IP tables support (CONFIG_IP_NF_IPTABLES=y) Full NAT(CONFIG_IP_NF_NAT=y) REDIRECT target support (CONFIG_IP_NF_TARGET_REDIRECT=y) o File systems /proc filesystem support (CONFIG_PROC_FS=y) 另外,请确认该选项没被激活: o Networking options Fast switching (CONFIG_NET_FASTROUTE=n) 重定向外部数据包到 squid 的代码是 Netfilter 软件的一部分。如下是发送 HTTP拦截 连 接到 squid 的规则: iptables -t nat -APREROUTING-i eth0 -p tcp --dport 80 -j REDIRECT--to-port 3128 Linux 内核维护许多不同的 tables。-t nat 选项表明我们正在修改 NAT(网络地址转换) 表。本质上,我们使用 iptables 将原始服务器的 TCP/IP地址转换为 squid 的本地 TCP/IP地 址。 每个 iptables 表有许多链。 -A PREROUTING 表明我们增加了一条规则到内建的链叫做 PREROUTING。PREROUTING 链仅对从外部网络进入系统的数据包有效。 接下来的三个选项决定哪个包匹配该规则。 -i eth0选项限制规则仅对 eth0接口上接受的 数据包有效。 -p tcp选项指定 TCP 包, --dport 80指定包的目的端口是 80。 假如这三个条件 都 是true,那么包匹配该规则。 -j REDIRECT 选项表明对匹配规则的包, 采取何种动作。 REDIRECT 是内建的动作名 , 它导致 iptables 改变包的目的地址为 127.0.0.1。--to-port 3128选项也指示 iptables 改变目的 TCP 端口为 3128。 假如你在 squid 主机上运行 HTTP服务(例如 Apache) , 就必须增加另外的 iptables 规 则。 该 必要规则允许连接到 HTTP服务。否则,REDIRECT 规则导致 iptables 转发连接到 squid 的3128端口。可以使用 -I选项在列表顶部插入一条新规则: iptables -t nat -IPREROUTING-i eth0 -p tcp -d 172.16.102.66 --dport 80 -jACCEPT 一旦确认所有 iptables 规则工作正确,记得运行如下命令来保存配置: Squid 中文权威指南 153 /sbin/service iptables save 将当前规则保存到 /etc/sysconfig/iptables,当系统重启时,这些规则自动载入。 9.4.1.19.4.1.19.4.1.19.4.1.1 Linux Linux Linux Linux 和WCCPWCCPWCCPWCCP 2.4版本的 Linux 内核自带 1个GRE 伪装接口。然而,它不能解码 WCCP 任务里封装的 GRE 包。 问 题看起来在于路由器设置了 WCCP/GRE包的协议类型域为 0x883E。Linux 的GRE 驱动不知道如何处理这类型包,因为它不了解 0x883E 类型的协议。 可以试试给 Linux 打GRE 模块的补丁,以便它能在 WCCP 下工作。 Squid FAQ包含了 对这个补丁的链接。然而,假如使 用 WCCP 指定的 Linux 模块,事情会容易些。可以在这 里找到它: http://www.squid-cache.org/WCCP-support/Linux/ip_wccp.c 必须编译 ip_wccp.c 文件为可装载内核模块。有点棘手的是, 依赖于内核版本的 不同, 编译选项可能不同。你可以进入内核源代码目录,敲 入 make modules 并观察编译器命令的 滚动。 然 后拷贝这些命令中的一个, 然 后改变最后一个参数为 ip_wccp.c。 如下 是 我 在 2.4.7-10 Linux 内核中使用的命令 : % gcc -Wall -D__KERNEL__-I/usr/src/linux-2.4.7-10/include \ -DMODULE-DMODVERSIONS-DEXPORT_SYMBAB\ -include /usr/src/linux-2.4.7-10/include/linux/modversions.h \ -O2 -cip_wccp.c gcc命令在当前目录会生成 ip_wccp.o 文件。 下一步使用 insmod 命令, 装载模块到内 核 中: # insmod ip_wccp.o 注意 ip_wccp 模块接受来自任何源地址的 GRE/WCCP 包。换句话说,恶意用户可能发 送数据到 squid cache。假如使用该模块,应该安装一条 iptables 规则,拒绝外部的 GRE 包。 例如: # iptables -AINPUT-p gre -s 172.16.102.65 -jACCEPT # iptables -AINPUT-p gre -j DROP 不要忘记敲入 /sbin/service iptables save命令来保存配置。 9.4.29.4.29.4.29.4.2 FreeBSDFreeBSDFreeBSDFreeBSD Squid 中文权威指南 154 本节的例子基于 FreeBSD-4.8,并可以在任何 FreeBSD-4和5系列的后续版本上运行。要 激活 IP包转发,在 /etc/sysctl.conf 中增加如下行: net.inet.ip.forwarding=1 需要在内核中激活 2个特殊选项。 假 如你不知道如何编译内核, 参见 FreeBSD Handbook 第9章(http://www.freebsd.org/handbook/index.html). 编辑内核配置文件,确保有如下行: options IPFIREWALL options IPFIREWALL_FORWARD 假如squid 主机位于无人照看的机房中,我也推荐使用 IPFIREWALL_DEFAULT_TO_ACCEPT 选项。假如你被防火 墙的规则 困扰, 仍然可以 登陆 系统中。 ipfw 命令告诉内核重定向拦截连接到 squid: /sbin/ipfw add allow tcp from 172.16.102.66 to any out /sbin/ipfw add allow tcp from any 80 to any out /sbin/ipfw add fwd 127.0.0.1,3128 tcp from any to any 80 in /sbin/ipfw add allow tcp from any 80 to 172.16.102.66 in 第一条规则匹配 squid 主机发起的数据包。它确保外出的 TCP 连接不会被重新定向回 squid。第二条规则匹配 squid 响应客户端的数据包。我在这里列 出它,因为随后会有另外 的ipfw 规则, 这些规则会拒绝这些包。 第三条规则实际重定向进来的连接到 squid。 第四 条 规则匹配从原始服务器返回 squid 的数据包。这里又一次假设随后会有相应的拒绝规则。 假如在 squid 主机上运行 HTTP服务, 就 必须增加另外的规则, 它 放过, 而 不是重定 向, 目的地址是原始服务器的 TCP 包。下列规则在 fwd规则之前: /sbin/ipfw add allow tcp from any to 172.16.102.66 80 in FreeBSD 典型的将 ipfw 规则存储在 /etc/rc.firewall 里。一旦你确认规则设置正确,记得 保存它们。将如下行加入 /etc/rc.local 文件,让 FreeBSD 在启动时自动运行 /etc/rc.firewall 脚 本。 firewall_enable="YES" 9.4.2.19.4.2.19.4.2.19.4.2.1 FreeBSD FreeBSD FreeBSD FreeBSD 和WCCPWCCPWCCPWCCP FreeBSD 版本 4.8和后续版本 内建 了 对 GRE 和WCCP 的支持。早 期的 版本 需要 补丁, 你可以在这里找到 : http://www.squid-cache.org/WCCP-support/FreeBSD/ . 内建代码的性能非 Squid 中文权威指南 155 常好,它是真正的内核组织编写的。可能也需要编译支持 GRE 的新内核。将如下行加入内 核配置文件里: pseudo-device gre 对Freebsd-5,使用 device 代替了 pseudo-device。当然,你 也需 要前 面章 节里 提到 的 FIREWALL 选项。 在安装和重启了新内核后,必须配置 GRE 通道来接受来自路由器的 GRE 包。例如: # ifconfig gre0 create # ifconfig gre0 172.16.102.66 172.16.102.65 netmask 255.255.255.255 up # ifconfig gre0 tunnel 172.16.102.66 172.16.102.65 # route delete 172.16.102.65 ifconfig 命令在 gre0接口上,增加了一个到路由器( 172.16.102.65)的路由表入口。我 发现必须删除该路由,以便 squid 能与其他路由器会话。 你也许想或必须对来自路由器的 GRE 包,增加一条 ipfw 规则: /sbin/ipfw add allow gre from 172.16.102.65 to 172.16.102.66 9.4.39.4.39.4.39.4.3 OpenBSDOpenBSDOpenBSDOpenBSD 本节的示例基于 OpenBSD 3.3。 为了激活包转发,在 /etc/sysctl.conf 文件里增加该行: net.inet.ip.forwarding=1 现在,在 /etc/pf.conf 文件里增加如下类似行,配置包过滤规则: rdr inet proto tcp from any to any port = www -> 127.0.0.1 port 3128 pass out proto tcp from 172.16.102.66 to any pass out proto tcp from any port = 80 to any pass in proto tcp from any port = 80 to 172.16.102.66 Squid 中文权威指南 156 假如你没有使用 OpenBSD 的包过滤器,需要在 /etc/rc.conf.local 文件里增加一行来激 活 它: pf=YES 9.4.3.19.4.3.19.4.3.19.4.3.1 OpenBSDOpenBSDOpenBSDOpenBSD和WCCPWCCPWCCPWCCP 首先,增加如下行到 /etc/sysctl.conf 文件,告诉系统接受和处理 GRE 和WCCP 包: net.inet.gre.allow=1 net.inet.gre.wccp=1 然后,用如下命令配置 GRE 接口: # ifconfig gre0 172.16.102.66 172.16.102.65 netmask 255.255.255.255 up # ifconfig gre0 tunnel 172.16.102.66 172.16.102.65 # route delete 172.16.102.65 跟Freebsd 一样,我发现必须删除 ifconfig 自动产生的路由。最后,依赖于包过滤器的 配置,必须增加一条规则以允许 GRE 包: pass in proto gre from 172.16.102.65 to 172.16.102.66 9.4.49.4.49.4.49.4.4 在NetBSD NetBSD NetBSD NetBSD 和其他系统上 的 IPFilterIPFilterIPFilterIPFilter 本节的示例基于 NetBSD 1.6.1。它们也能运行在 Solaris,HP-UX,IRIX,和Tru64上,既然 这些系统本身就配备了 IPFilter. 激活 NetBSD 的包转发,将如下行加进 /etc/sysctl.conf: net.inet.ip.forwarding=1 然后,将如下行插入 NAT 配置文件 /etc/ipnat.conf 中: rdr fxp0 0/0 port 80 -> 172.16.102.66 port 3128 tcp 你的接口名可能与本例的 fxp0不同。 9.4.4.19.4.4.19.4.4.19.4.4.1 NetBSD NetBSD NetBSD NetBSD 和WCCPWCCPWCCPWCCP Squid 中文权威指南 157 我不能在 NetBSD 上运行 WCCP,即使打了 GRE 补丁来接受 WCCP 包。该问题看起 来根源在 IPFilter rdr 规则阻塞了特定的端口。 来 自路由器的包通过 NetBSD 的gre0接口 ( 在 这里它们被解包) 。 然 而, 包回到路由器时, 走 另一条通道, 未被封装并且不 走同一网络 接 口。这样, IPFilter 代码没有将 squid 的本地 IP地址转换回原始服务器的地址。 9.59.59.59.5 配置SquidSquidSquidSquid 假如你使 用 Linux 2.4和iptables ,在运行 ./configure 时,可使 用 --enable-linux-netfilter 选项。它激活某些 Linux 的特殊 代码,以发现发起请求的原始服务器的 IP地址。 Squid 正 常情况下从 Host 头部, 得到原始服务器的名字 ( 和 /或地址)。--enable- linux-netfilter 功能 仅 对没有 Host 头部的请求来说是必要的。 统 计显示几乎所有的请求有 Host 头部, 所 以实际 中 可以不使用 --enable-linux-netfilter 选项。 假如正在使用 IPFilter 包( NetBSD,Solaris,或其他) ,因为同样的理由,你应该 使用 -- enable-ipf-transparent 选项 。 在 OpenBSD 上, 请 使 用 --enable-pf-transparent 选项 。 每 次运 行./configure 时,必须重编译 squid,见3.8章的描述。 在运行了 ./configure 和重编译了 squid 后, 可 以编辑 squid.conf 文件。 作 为起点, 请 确 认 下列指令定义了给定的值: httpd_accel_host virtual httpd_accel_port 80 httpd_accel_uses_host_header on httpd_accel_with_proxy on httpd_accel_single_host off http_accel_host 指令 是 关 键 。 它 指 示 squid 接受 包 含 局 部 URI 的HTTP 请求 。 httpd_accel_uses_host_header 被激活, 允许 squid 使用 Host 头部来重新构建完整 URI。virtual 关键字指示 squid 在缺乏 Host 头部时,将原始服务器的 IP地址放进 URL 里。 httpd_accel_with_proxy 指令控制 squid 是否既接受 HTTP服务 (部分 URI) 请求, 又 接 受代理(完整 URI)请求。在 cache拦截里,它应该被激活。如果没有用户明确的配 置使 用squid 做代理,那即使 httpd_accel_with_proxy 没被激活, squid 也能工作。 httpd_acces_single_host 指令正常情况下被禁止, 在早期版本的 squid 里, 它可能被默 认 激活。在 cache拦截里,它应明确被禁止。 Squid 中文权威指南 158 假如拦截不止针对 80端口,你也许该将 httpd_accel_port 设为 0。见附录 A的更多信息。 假如你没有使用 WCCP, 就该准备开始发起拦截会话到 squid 了。 通过使用浏览器来 上 网冲浪, 或者使用 squidclient 发起测试请求, 就可以放手一试。 假 如你使用 WCCP, 那么 还 有许多步骤要完成。 9.5.19.5.19.5.19.5.1 配置WCCPv1WCCPv1WCCPv1WCCPv1 路由器不发送任何会话到 squid, 直到 squid 宣称它自己是路由器。 为 了让 squid 那样 做, 在squid.conf 中增加如下行: wccp_router 172.16.102.65 wccp_version 4 路由器有多个接口。请确认 使用 与 squid 相连的接口的 IP地址。这点是必要的,因为 来自 路 由 器 的 WCCP 消息 , 将 源 IP地址 设置为外出接口的地址。假如源地址不匹配 wccp_router 值, squid 会拒绝 WCCP 消息。 WCCPv1文档规定 4作为协议版本号。然而,某些用户报告, Cisco IOS 11.2仅支持协议 版本 3。假如你使用该版本的 IOS,请在 squid.conf 里改变版本号: wccp_version 3 9.69.69.69.6 调试 问题 HTTP拦截比较复杂, 因为许多不同设备必须组合正确工作。 为了帮助你跟踪问题, 如 下是一个问题解答检查列表: •* 客户端数据包正在通过路由器 /交换机吗? • 在简单网络里,这点显而易见。你可以 trace线缆并观察指示灯的活动闪烁。 然而在大而复杂的网络, 数 据包可能走不同的路线。 假 如你的组织够大, 并 有网络 sniffer 设备, 就 可以观察线路中 web 客户端的请求数据包。 低 技术的方法是, 断开有问题的 线 路,并观察是否影响客户端的 web 浏览。 •* 路由器 /交换机配置是否正确? • 你也许要再次检查路由器 /交换机配置。假如你已配置了某个接口,那能否确 保它正确呢?是否新的配置真正在设备上运行?也许在你保存配置之前, 路 由器 /交换 机 Squid 中文权威指南 159 已重启了。在改变生效前,你或许需要 reboot 设备。 •* 交换机 /路由器能与 squid 主机会话吗? • 能从路由器 /交换机上 ping 通squid 吗?大部分 4层拦截配置要求网络设备 和 squid 在同一子网里。登陆路由器 /交换机,确认能 ping 通squid 的IP地址。 •* 交换机 /路由器相信 squid 在运行吗? • 许多传输拦截设备不会发送 会话 到 squid ,除非它们知道 squid 是健壮的。使 用调试命令来预览 squid 的健壮性状态。也许会发现三层健壮性检测(例如 ICMP ping) 比四层检测(例如 HTTP)更容易,它使网络设备更容易将 squid 标记为存活状态。 •* Squid 实际在运行吗 ? • 请再次确认 squid 真正在运行,特别是在系统近期重启过的情况下。 •* 数据包正在抵达 squid 主机吗? • 使用 tcpdump 能见到拦截的 TCP 连接。如下是示例: # tcpdump -n -i eth0 port 80 • 假如使用 WCCP,请检查来自路由器的 GRE 包: # tcpdump -n -i eth0 ip proto gre • 假如没有看到 tcpdump 的任何输出, 则 路由器 /交换机可能没有发送任何数据 。 在这种情况下,返回到以前的建议。 注意,假如设备正使用四层健壮性检测,你可以 在tcpdump 的输出里见到这些。健壮性检测来自路由器 /交换机的 IP地址,所以它们容 易被认出。假如你见 到健壮性检测,但没有其他数据,那可能意味着路由器 /交换机正 把squid 的响应理解为不健壮。例如,设备可能想 见到 200(OK)响应,但 squid 返回一 个错误,例如 401(未授权)或 404(未发现) 。 请对 access.log 运行 tail -f命令。 •* 激活了 IP转发吗? • 请再次确认 squid 运行的操作系统配置 了 IP包转发。假如没有,主机可 能会 丢弃拦截数据包,因为目的 IP地址并非本地。 •* 配置包过滤了吗? • 请确认包过滤器 ( 例如 ipfw,iptables,pf 等) 配 置正确。 当 每件事都运行良好 时, 你能定期运行命令来显示过滤规则,并观察计数器增长。例如: Squid 中文权威指南 160 •# ipfwshow 300 ; sleep 3; ipfw show 300 00300 86216 8480458 fwd 127.0.0.1,3128 tcp from any to any 80 in 00300 86241 8482240 fwd 127.0.0.1,3128 tcp from any to any 80 in • 注意该示例在 FreeBSD 上,包和字节计数器(第二和第三列)正在增长。 •* 环路接口起来和配置了吗? • 假如有一条规则转发 /重定向包到 127.0.0.1,请确认环路接口(例如 lo0,lo 等) 起来了,并配置过它。假如没有,内核简单的跳过这条转发 /重定向规则。 •* WCCP/GRE 包被正确解开了吗? • 假如使用 WCCP,请确认 GRE 包被正确解开。假如因为某些理由,系统不 知 道该如何处理 GRE 包,那就在 netstat -s的输出里会见到 "unknown/unsupported protocol" 计数器在增长。 # netstat -s| grep unknown 46 packets for unknown/unsupported protocol • 假如 OS 有GRE 接口,请频繁运行 netstat -i命令,观察不断增长的包数量: # netstat -in | grep ^gre0 Name Mtu Network Address Ipkts Ierrs Opkts Oerrs Coll gre0 1476 304452 0 0 4 0 • 另外,在 GRE 接口上运行 tcpdump: # tcpdump -n -i gre0 •* Squid 能响应客户端吗? • 有可能路由器 /交换机能发送包到 squid,但 squid 不能将包发送回客户端。这 种情况可能发生在: 防 火墙过滤规则拒绝外出数据包,或 squid 没有到客户端 IP地址 的 路由。为了检查这种情况,请运行 netstat -n并观察 SYN_RCVD 状态的 sockets: Squid 中文权威指南 161 % netstat -n Active Internet connections Proto Recv-Q Send-Q Local Address Foreign Address (state) tcp4 0 0 10.102.129.246.80 10.102.0.1.36260 SYN_RCVD tcp4 0 0 10.102.129.226.80 10.102.0.1.36259 SYN_RCVD tcp4 0 0 10.102.128.147.80 10.102.0.1.36258 SYN_RCVD tcp4 0 0 10.102.129.26.80 10.102.0.2.36257 SYN_RCVD tcp4 0 0 10.102.129.29.80 10.102.0.2.36255 SYN_RCVD tcp4 0 0 10.102.129.226.80 10.102.0.1.36254 SYN_RCVD tcp4 0 0 10.102.128.117.80 10.102.0.1.36253 SYN_RCVD tcp4 0 0 10.102.128.149.80 10.102.0.1.36252 SYN_RCVD • 假如你看到这些, 请 使用 ping 和traceroute来确认 squid 能与客户端双向通信 。 •* Squid 能与原始服务器会话吗? • 假如 squid 不能连接到原始服务器, 拦截 HTTP连接会无法进行。 如果这点 发 生, netstat 会显示许多连接在 SYN_SENT 状态: % netstat -n Active Internet connections Proto Recv-Q Send-Q Local Address Foreign Address (state) tcp4 0 0 172.16.102.66.5217 10.102.129.145.80 SYN_SENT tcp4 0 0 172.16.102.66.5216 10.102.129.224.80 SYN_SENT tcp4 0 0 172.16.102.66.5215 10.102.128.71.80 SYN_SENT tcp4 0 0 172.16.102.66.5214 10.102.129.209.80 SYN_SENT tcp4 0 0 172.16.102.66.5213 10.102.129.62.80 SYN_SENT Squid 中文权威指南 162 tcp4 0 0 172.16.102.66.5212 10.102.129.160.80 SYN_SENT tcp4 0 0 172.16.102.66.5211 10.102.128.129.80 SYN_SENT tcp4 0 0 172.16.102.66.5210 10.102.129.44.80 SYN_SENT tcp4 0 0 172.16.102.66.5209 10.102.128.73.80 SYN_SENT tcp4 0 0 172.16.102.66.5208 10.102.128.43.80 SYN_SENT • 再次用 ping 和traceroute来确认 squid 能与原始服务器会话。 •* 外出连接正被拦截吗? • 假如squid 能ping 通原始服务器, 并 且仍然见到大量的连接在 SYN_SENT 状 态, 那 么路由器 /交换机可能正在拦截 squid 的外出 TCP 连接。 在 某 些情况下, squid 能 检测到这种转发循环,并写警告日志 到 cache.log。如此的转发死循环能迅速耗 光 squid 的所有文件描述符,这样也会在 cache.log 里产生警告。 假如你怀疑这个问题, 请 使用 squidclient 程序来发起一些简单的 HTTP请求。 例 如, 该 命令发起一条直接到原始服务器的 HTTP请求: %/usr/local/squid/bin/squidclient -p 80 -h slashdot.org / 假如该命令成功, 你 可以在屏幕上见到来自 Slashdot 站点的许多难看的 HTML。 然后 通 过squid 来试试同样的请求: %/usr/local/squid/bin/squidclient -r -p 3128 -h 127.0.0.1 http://slashdot.org/ 假如没有在 cache.log 里看到错误消息,就可以再次在屏幕上看到一些 HTML。假如看 到转发循环错误,就必须重新配置交换机 /路由器,以便它允许 squid 的外出连接正常通过, 而不被拦截。 Squid 中文权威指南 163 第第第第10101010章章章章与其 他 与其 他 与其 他 与其 他 Squid Squid Squid Squid 会话 会话 会话 会话 10.110.110.110.1 某些 术语 通常把一组互相转发请求 的 cache(或代理)叫做 cache 堆叠。把 cache 堆叠的成员叫 做邻居或对等伙伴 。邻居 cache有2种关系:父子或姐妹。从拓扑上看,父 cache在堆叠里位于顶层,而 姐妹 cache位于同一层。两者真正的不同在于,父 cache能为 子cache转发 cache丢失, 然 而姐妹 cache之间不允许转发 cache丢失。这意味着,在发送请求到姐妹 cache前,发起者 应该知道这是个 cache命中。 类 似于 ICP,HTCP 和Cache Digests 之类的堆叠协议, 能 预知 邻 居的 cache命中。然而 CARP 不能这样。 某些时候, cache堆叠并非真正层次性的。 例 如, 考 虑 1组5个姐妹 cache。 因 为它们没 有 父子关系, 故 而不存在上或下。 在 这种情况下, 你可以叫它 cache结网, 或 甚至 cache编队 , 而不是堆叠。 10.210.210.210.2 为何 要( 或不要 )使 用堆 叠? 邻居cache通过提供某些额外的 cache命中而改进了执行性能。 换 句话说, 某 些请求 的 cache 丢失,在邻 居 cache 里可能会命中 。假 如你的 cache 从邻居 cache 里下载这些命 中, 比从原始服务器快,那 cache堆叠可全面改善性能。底线是邻居 cache能提供一小部分的请 求命中。大约 5%或10%(假如幸运的话)的 cache丢失请求,会在邻居 cache中命中。在 某些情况下,这点小 作用价值 不高。 然而有的 情形下, 例如网络 连接不 尽人 意时, cache 堆叠非常明显的改进了终端用户的访问性能。 假如在有防火墙的网络中使用 squid,就有必要配置防火墙作为父代理。在该情形中, squid 转发每个请求到防火墙,因为它不直接连接到外部原始服务器。假如有某些原始服务 器在防火墙里面,就可以配置 squid 直接连接到它们。 也可以使用堆叠来在不同方向上传送 web 数据。 这点有时候叫做应用层路由, 或更 近 的叫法:内容路由。例如, 考虑某个大公司,它有 2个Internet 连接。 也许第二个连接比 第 一个成本更低。 该 公司可能想利用第二个连接作为次优先性传输, 例 如下载游戏、 音 频或 视 频,或其他形式的大文件传输。或者,也许他们想利 用某条链路进行 HTTP访问,而在另 一条链路上进行非 HTTP访问。 再 或者, 也 许某些用户的数据通过低优先级链路传输, 而 付 费用户的数据通过更贵的链路传 输。可以使用 cache代理堆叠来完成上述设想。 Squid 中文权威指南 164 信任机制对 cache 堆叠来说,是最重要的因素 。你必须信 任邻 居 cache 会服务正确的、 未修改的响应。必须在敏感信息上信任它们,例如用户请求的 URI。 它们会维护一个安全的, 不 断更新的系统, 将 未授权访问和拒绝服务的机会降至最低 。 关于堆叠的另一个问 题,在于 它们正 常传播错 误的途径 。当邻 居 cache 经历 了某个错误, 例如服务不可到达,它产生一 个 HTML页面来解释该错误及错误源头。假如邻 居 cache位 于公司之外,它返回错误时,用户会觉得迷惑。假如该 问题继续,用户将很难找到帮它们 解决问题的管理员。 姐妹关系也有一个已知的问题, 叫做假命中。假如 squid 发送某个请求到它的姐妹, 它 认为这是个 cache命中,然而它的姐妹没有联系过原始服务器,因此不能满足该请求,这 时就会发生假命中。 有 很多情况导致假命中, 但 通常可能性很低。 甚 至,squid 和其他 HTTP 代理有自动重新请求假命中的功能,不会让用户感觉到已发生的问题。 转发循环有时候是 cache堆叠的另一个问题。当 squid 转发某个请求到某处,但该请求 又被转发回 squid,这就发生了转发循环。请见图 10-1(略图)。 Figure 10-1. A forwarding loop 转发循环典型的发生在 2个cache互相把对方当作父 cache的情况。假如你遇到这样的问题, 请确认使 用 cache_peer_access 指令来阻止 这类循环。例 如, 假如邻 居 cache 的IP地址是 192.168.1.1,下面的行让 squid 不会产生转发循环: acl FromNeighbor src 192.168.1.1 cache_peer_access the.neighbor.name deny FromNeighbor 转发循环在 HTTP拦截里也能发生, 特 别是当拦截设备位于 squid 和原始服务器之间 的 路径上时。 Squid 通过检查 Via 头部里的主机名, 来 检测转发循环。 假 如 2个协作 cache有相同的 主 机名, 实际上就会得到假转发循环。在该情形 下, unique_hostname 指令很有用。 注意, 假 如Via 头部被过滤掉了(例如使用 headers_access指令),squid 就不能检测到 转发循环。 Squid 中文权威指南 165 10.310.310.310.3 配置Squid Squid Squid Squid 与邻 居通 信 cache_peer 指令定义邻居 cache,并告诉 squid 如何与它的邻居通信: cache_peer hostname type http-port icp-port [options] 第1个参数是邻居的主机 名, 或 IP地址。可以安全的在 这里使用 主机名 ,因 为 squid 会解析它们。在 squid 运行期间,主机名对应的 IP地址可能会改变, 所以实际上 squid 会 周期性的解析主机名 。邻居主 机名必 须唯一: 不能在 2个邻居 cache 上使用同样的主机名, 即使它们有不同的端口。 第2个参数指定邻居 cache的类型。 有 3个选择: 父亲,姐妹, 或广播。父亲和姐妹关 系 容易理解。我在 10.6.3节里会详细谈到广播。 第3个参数是邻居 HTTP 端口号。它应该等同于邻居 的 http_port 设置。总是应该指定 1 个非零的 HTTP端口号。 第4个参数指定 ICP 或HTCP 端口号。 squid 默认使用 ICP 来查询其他 cache。也就是 说, squid 发送 ICP 查询到邻居 cache的指定端口。 假如你增加了 htcp 选项, squid 就会发 送HTCP 查询到这个端口。默认的 ICP 端口是 3130,默认的 HTCP 端口是 4827。假如增加 了htcp 选项, 请记得改变它的端口号。 将端口号设为 0, 会禁止 ICP 和HTCP。 然而, 应 该 使用 no-query 选项来禁止这些协议。 10.3.110.3.110.3.110.3.1 cache_peercache_peercache_peercache_peer选项 cache_peer 指令有很多选项。 我在这里描述其中的一些, 其 他的参数在与之相关的协 议 的章节里有描述。 proxy-only 该选项指示 squid 不存储它接受自邻居的任何响应。如果你有 cache集群,并且不希望 资源存储在多个 cache上,那么该选项有用。 weight=n 该选项指定给 ICP/HTCP。请见 10.6.2.1章节。 ttl=n 该选项指定给广播 ICP。见 10.6.3节。 no-query Squid 中文权威指南 166 该选项指定给 ICP/HTCP。见 10.6.2.1节。 default 在缺少其他线索时, 该 选项指定邻居 cache作为适当的选择。正常 情况下,squid 将cache 丢失转发给父 cache,父 cache看起来有特定资源的 缓存拷贝。有时候 squid 没有任何线索 (例如使用 no-query 禁用了 ICP/HTCP),这时squid 会寻找父 cache, 并 将其作为默认选择 。 round-robin 该选项是简单的负载共享技术。仅仅当你指定了 2个或多个父 cache作为轮转时,它才 有用。 squid 对每个父 cache维持一个计数器。当需要转发 cache丢失时, squid 选择计数器 值最低的父 cache。 multicast-responder 该选项指定给广播 ICP。见 10.6.3节。 closest-only 该选项指定给 ICP/HTCP。见 10.6.2.1节。 no-digest 该选项指定给 cache digest,见 10.7章。 no-netdb-exchange 该选项告诉 squid,不要请求邻居 cache的netdb 数据库(见 10.5节)。 no-delay 该选项告诉 squid,忽略任何对邻居 cache请求的延迟池设置。见附录 C关于延迟池的 更多信息。 login= credentials 该选项指示 squid 发送 HTTP验证信息到邻居 cache。它有 3个不同的格式: login =user:password 这是最通用的形式。它导致 squid 在每个到邻居 cache的请求里,增加相同的用户名和 密码。用户无须填写任何验证信息。 Squid 中文权威指南 167 login=PASS 将值设为 PASS,导致 squid 让用户的验证信息直接 pass 到邻居 cache。它仅仅工作在 HTTP基础的验证机制下。 squid 不会增加或修改任何验证信息。 假如 squid 被配置成需要代理验证 ( 例如使用 proxy_auth ACL),邻居cache就必须使 用 同样的用户名和密码数据库。 换 句话说, 应该只在被同一组织拥有和操作的一组 cache中使 用PASS形式。该功能是危险的,因为 squid 不会从转发请求里移除验证信息。 login =* :password 使用该形式, squid 改变它转发的请求里的密码 ,但不改变 用户名。它 允许邻 居 cache 来验证独立的用户, 但不暴露其密码。 该形式比使用 PASS危险少一些, 但确实有一些隐 私 牵连。 使用该功能需要额外小心。 即 使你不管隐私条目, 该 功能也可能对上级代理产生不良 的 副作用。例如,我知道至少 1个其他的 cache产品,它仅仅查看持续连接里第一个请求的信 用信息。它看起来(不正确的)假设在单个连接里的所有请求,都来自同一用户。 connect-timeout= n 该选项指定,在 squid 建立 TCP 连接到邻居 cache时,等待的超时时间。若没有该选 项, 超 时值就取自全局 connect_timeout 指令, 它 的默 认值是 120秒。 使 用低的超时值, squid 会迅速放弃到邻居 cache的会话,并且试着发送请求到其他邻居 cache,或直接请求原始服 务器。 digest-url= url 该选项指定给 cache digest。见 10.7章。 allow-miss 该选项指 示 squid 忽略 Cache-Control: only-if-cached 指令,该 指令 是针 对发 送给 姐 妹 cache的请求的。 仅 在如下情况下使用它: 邻居 cache激活了 icp_hit_stale 指令, 并 且没有 使 用miss_access 列表。 max-conn= n 该选项对 squid 打开到邻居 cache的同时连接的数量进行限制。 当 抵达了该限制时, squid 从它的选择算法里排除掉该邻居 cache。 htcp 该选项指定邻居 cache为HTCP 服 务 器 。 换句 话 说 , squid 发送 HTCP 查询, 而 不是 ICP Squid 中文权威指南 168 查询, 到邻居 cache。 注意 squid 不会在同一端口上 接受 ICP 和HTCP 查询。 若你增加了 该 选项,不要忘了改 变 icp-port 的值。见 10.8.1节。 HTCP 支持需要在运行 ./configure 时, 使 用--enable-htcp 选项。 carp-load-factor= f 该选项让邻居 cache(它必须是父 cache) 成为 CARP 的成员。 对所有父 cache的f值的 总和,必须等于 1。我在 10.9章里讲到 CARP。CARP 支持需要在运行 ./configure 时,使用 -- enable-carp 选项。 10.3.210.3.210.3.210.3.2 邻居状态 Squid 对其每个邻居 cache,维持着多种统计和状态信息。最重要的信息之一,是其邻 居cache的存活状态。 邻居 cache的存活 /死亡状态影响了 squid 选择算法的许多方面。 确 定 邻居 cache的存活 /死亡状态的机制有点复杂, 所 以我在这里不讲它。 假 如你想通过阅读源 代 码来了解这点,请查看 neighborUp()函数。 Squid 使用 TCP(HTTP)和UDP(ICP/HTCP)通讯来确定邻居 cache的状态。 TCP 状态默 认是存活的,但如果连续 10个TCP 连接失败,状态会改变为死亡。如果发生这种事, squid 会发起探查连接, 在每个 connect_timeout 期间内 (全局指令, 并非 cache_peer 选项),连接 不会超过 1次。邻居 cache会保持死亡状态,直到探查连接之一成功。 假如 no- query 选项没有设置 ( 意味着 squid 正发送 ICP/HTCP 查询到邻居 cache),UDP 层通讯也参与到存活 /死亡算法里来。 UDP 状态默认是存 活的, 但假如 squid 在超时范围 内 (dead_peer_timeout 指令的值) , 没有接受到任何 ICP/HTCP 响应, UDP 状态就会改变为 死 亡。 假如邻居 cache 的主机名不可解析, squid 也会将其标记为死亡。 当 squid 确定其邻居 cache死亡时,它在 cache.log 里增加类似如下的日志记录: 2003/09/29 01:13:46| Detected DEAD Sibling: bo2.us.ircache.net/3128/3130 当与邻居 cache的通信重新建立起来时, squid 记录类似如下的日志: 2003/09/29 01:13:49| Detected REVIVED Sibling: bo2.us.ircache.net/3128/3130 邻居 cache的状态,在下述几个方面影响邻居选择算法: • 1)Squid 不希望接受来自死亡邻居的ICP/HTCP 响应。squid 在每个 dead_peer_timeout 期间内,只发送 1次ICP 查询到死亡的邻居。见附录 A。 • 2)死亡 的 父 cache 从下 列 算 法 里 排 除 掉 :Digests, round-robin parent, first up parent, default parent, 和closest parent。 Squid 中文权威指南 169 • 3)CARP 特殊:任何失败的 TCP 连接,会从 CARP 算法里排除掉父 cache。 没有办法强迫 squid 发送 HTTP请求到死亡的邻居 cache。 假 如所有的邻居 cache都死 亡, squid 会试图连接到原始服务器。假如你不允许 squid 与原始服务器会话(使用 never_direct 指令),squid 会返回 cannot forward 的错误消息: This request could not be forwarded to the origin server or to any parent caches. The most likely cause for this error is that: * The cache administrator does not allow this cache to make direct connections to origin servers, and * All configured parent caches are currently unreachable 10.3.310.3.310.3.310.3.3 改变关系 neighbor_type_domain 指令允许你改 变与 基于原 始服 务器主 机名 的邻 居 cache 的关系。 假如邻居 cache期望服务任何请求的 cache命中,但仅仅服务某些临近域的 cache丢失,那 么这个指令就很有用。语法是: neighbor_type_domain neighbor.host.name relationship [!]domain ... 例如: cache_peer squid.uk.web-cache.net sibling 3128 3130 neighbor_type_domain squid.uk.web-cache.net parent .uk 当然,该示例里的 squid.uk.web-cache.net 缓存,会利用相应的 miss_access 规则来强迫 姐妹关系给 non-UK 请求。注意域名会按照 6.1.1.2章节里描述的那样,匹配主机名。 10.410.410.410.4 对邻 居的 请求限 制 许多使用 cache堆叠的用户,想控制或限制 squid 发送到邻居 cache的请求。 squid 有7 个不 同的指令可以影响请求路由:cache_peer_access, cache_peer_domain, never_direct, always_direct, hierarchy_stoplist,nonhierarchical_direct, 和prefer_direct。 10.4.110.4.110.4.110.4.1 cache_peer_accesscache_peer_accesscache_peer_accesscache_peer_access Squid 中文权威指南 170 cache_peer_access指令定义对邻居 cache的访问列表。也就是说,它决定哪个请求允 许 或不允许发送到邻居 cache。 例如,可以使用这点来对 FTP和HTTP 请求进行分流。你可以发送所有的 FTP URI 到 某个父 cache,所有的 HTTP URI 到另一个父 cache: cache_peer A-parent.my.org parent 3128 3130 cache_peer B-parent.my.org parent 3128 3130 acl FTP proto FTP acl HTTP proto HTTP cache_peer_access A-parent allow FTP cache_peer_access B-parent allow HTTP 改配置确保父 cache A仅接受 FTP URI 请求,而父 cache B仅接受 HTTP URI 请求。当 然也包括 ICP/HTCP 请求。 也可以使用 cache_peer_access,在一天中的某段时间来激活或禁止邻居 cache: cache_peer A-parent.my.org parent 3128 3130 acl DayTime time 07:00-18:00 cache_peer_access A-parent.my.org deny DayTime 10.4.210.4.210.4.210.4.2 cache_peer_domaincache_peer_domaincache_peer_domaincache_peer_domain cache_peer_domain 指令是 cache_peer_access指令的早期形式。相对于使用完整的访问 控制特性, 它 仅使用 URI 里的域名。 它 常用于通过域名区分一组父 cache。 例 如, 假如你 有 一个遍布全球的内部网,你也许想发送请求到位于各自大陆的 cache: cache_peer europe-cache.my.org parent 3128 3130 cache_peer asia-cache.my.org parent 3128 3130 cache_peer aust-cache.my.org parent 3128 3130 cache_peer africa-cache.my.org parent 3128 3130 Squid 中文权威指南 171 cache_peer na-cache.my.org parent 3128 313 cache_peer sa-cache.my.org parent 3128 3130 cache_peer_domain europe-cache.my.org parent .ch .dk .fr .uk .nl .de .fi ... cache_peer_domain asia-cache.my.org parent .jp .kr .cn .sg .tw .vn .hk ... cache_peer_domain aust-cache.my.org parent .nz .au .aq ... cache_peer_domain africa-cache.my.org parent .dz .ly .ke .mz .ma .mg ... cache_peer_domain na-cache.my.org parent .mx .ca .us ... cache_peer_domain sa-cache.my.org parent .br .cl .ar .co .ve ... 当然,该机制不匹配流行的全球顶级域名,例如 .com。 10.4.310.4.310.4.310.4.3 never_directnever_directnever_directnever_direct never_direct 指令是对从来不必直接发送到原始服务器 的请求的访问列表 。当请求匹配 该访问列表,它必须被发送到邻居 cache(通常是父 cache)。 例如, 假如 squid 位于防火墙之后, 它也许能够直接与内部服务器会话,但必须通过 防 火墙代理(父 cache)发送所有的请求到外部服务器。你可以告诉 squid:“永不要直接连到 防火墙之外的站点 ”。为了做到这点,请告诉 squid 有什么在防火墙之内: acl InternalSites dstdomain .my.org never_direct allow !InternalSites 语法有点奇怪。 never_direct allow foo 意味着 squid 不会直接放过匹配 foo 的请求。 既 然 内部站点容易指定,我使用否操作符 (!)来匹配外部站点,这些站点 squid 不会直接联系。 注意该示例不会强迫 squid 直接连接到匹配 InternalSites ACL 的站点。 never_direct 访问 规则仅仅强迫 squid 不直接联系某些原始服务器。 你 必须使用 always_direct 规则来强迫直 接 连接到原始服务器。 在结合其他控制请求路由的指令来使用 never_direct 时,必须谨慎。可能很容易就建立 一件不可能做到的事件。如下是个示例: cache_peer A-parent.my.org parent 3128 3130 Squid 中文权威指南 172 acl COM dstdomain .com cache_peer_access A-parent.my.org deny COM never_direct allow COM 该配置自相矛盾, 因为任何域名以 .com 结尾的请求必须通过邻居 cache。 然而仅仅定 义 了一个邻 居 cache,并且不 允许 .com 请求通过 它。 若发 生这 种情 况, squid 会发布 “cannot forward”的错误消息。 10.4.410.4.410.4.410.4.4 always_directalways_directalways_directalways_direct 也许你已猜到,always_direct 规则列表告诉 squid 某些请求必须直接转发到原始服务器 。 例如, 许 多单位想保持他们的内网通信本地化。 容 易做到的方法是, 定 义基于 IP地址的 ACL, 并将它放入 always_direct 规则列表: acl OurNetwork src 172.16.3.0/24 always_direct allow OurNetwork 10.4.510.4.510.4.510.4.5 hierarchy_stoplisthierarchy_stoplisthierarchy_stoplisthierarchy_stoplist Squid 内在的将每个客户端请求标记为层叠或不可层叠。不可层叠的请求看起来不会 导 致cache命中。 例如, POST请求的响应几乎从不会被 cache。在 squid 能简单的连接到原 始 服务器时,转发不可 cache目标的请求到邻居 cache,纯粹是浪费资源。 某些区分层叠和不可层叠请求的规则,在 squid 里难于编码。例如, POST和PUT 方 式总是不可层叠的。 然 而, hierarchy_stoplist 指令 允许你定制这种算法。 它 包含一个字符 串 列表,当在 URI 里发现它们时, squid 将请求标记为不可层叠。默认的该列表是: hierarchy_stoplist ? cgi-bin 这样,任何包含问号或 cgi-bin 字符串的请求匹配该列表,变成不可层叠。 默认的, squid 直接发送不可层叠的请求到 原始服务器 。因为这些 请求不会导 致 cache 命中 , 它 们 通 常 是 邻 居 cache 的额 外 负 担 。 然 而 , never_direct 访问 控 制 规 则 凌 驾 于 hierarchy_stoplist 规则之上。具体而言, squid 这样做: • 1)从不对不可层叠 的请求 发 送 ICP/HTCP 查询,除非该请 求匹 配 never_direct 规则; • 2)从不对不可层叠的请求发送 ICP/HTCP 查询到姐妹 cache; Squid 中文权威指南 173 • 3)从不对不可层叠的请求查询邻居的 cache digest。 10.4.610.4.610.4.610.4.6 nonhierarchical_directnonhierarchical_directnonhierarchical_directnonhierarchical_direct 该指令控制 squid 转发不可层叠的请求的方法。 squid 默认直接发送不可层叠的请求 到 原始服务器。这是因为这些请求不会导致 cache命中。我觉得直接 从原始服务器获取它们 总是好的, 而不要浪费时间在邻居 cache上查询它们。 假如因为某些理由, 你想路由这些 请 求通过邻居 cache,请禁止该指令: nonhierarchical_direct off 10.4.710.4.710.4.710.4.7 prefer_directprefer_directprefer_directprefer_direct 该指令控 制 squid 转发层叠请 求的 方法 。默 认的 , squid 首先发送这 样的 请求 到邻 居 cache,然后再到原始服务器。通过激活该指令,你能反转这种行为: prefer_direct on 这样,假如 squid 与原始服务器的通信失败,邻居 cache就变成了备份。 10.510.510.510.5 网络 度量 数据库 ( netdbnetdbnetdbnetdb) Squid 的网络度量数据库 ( netdb) 被 设计来测量到原始服务器的远近。 换句话说, 通 过 查询该数据库, squid 知道它离原始服务器有多远 。该数据库 包含 ICMP 往返时间( RTT) 测量值和路由跳计数。 正常情况下, squid 仅使用 RTT测量值, 但在某些情形下也使用路 由 跳计数。 为了激活 netdb, 必须使用 --enable-icmp 选项来配置 squid。 也必须以超级用户权限来 安 装pinger 程序, 请 见 3.6章的描述。 当 运行正确后, 可 以在 cache.log 里见到类似如下的消 息: 2003/09/29 00:01:03| Pinger socket opened on FD 28 当激活了 nebdb 时, squid 发送 ICMP ping 到原始服务器。 ICMP 消息实际上由 pinger 程序来发送和接受, pinger 以root 运行。 squid 会小心的不至于频繁发送 ping 消息,以避 免骚扰 web 站点管理员。 默认的, squid 在发送另一个 ping 到同一主机, 或同一 24位子网 中 主机时,会至少等待 5分钟。可以使用 netdb_ping_period 指令来调整这个时间间隙。 ICMP ping 消息通常非常小(少于 100字节)。squid 在ICMP 消息的有效载荷里包含了 Squid 中文权威指南 174 原始服务器的主机名,紧跟一个时间戳。 为了减少内存需求, squid 以24位子网来合计 netdb 数据。 squid 假设所有位于同一 24位 子网里的主机,有相似的 RTT和路由跳计数。若某台新的原始主机所在子网的其他主机已 被测量过,该机制也允许 squid 去估算这台新原始主机的远近。 随同 RTT和路由跳计数, squid 也维护着一份主机名结合子网的列表。 典型的记录看 起 来类似如下: Subnet 140.98.193.0 RTT 76.5 Hops 20.0 Hosts services1.ieee.org www.spectrum.ieee.org www.ieee.org netdb 度量值主要被 ICP 和HTCP 使用。当你在 squid.conf 里激活 query_icmp 指令时, squid 在发送到邻居 cache的ICP/HTCP 查询里设置一个标记。该标记请求 在 ICP/HTCP 响 应里包含远近测量值。假如邻居 cache也激活了 netdb,它们的响应将包含 RTT和路由跳 计 数(假如可用) 。 注意 squid 总是立刻响应 ICP。在响应 ICP 查询前,它不会等待 ICMP 测 量。见 10.6.2.2节关于 ICP 如何使用 netdb 的细 节。 Squid 会记住它从 ICP/HTCP 响应里学到的 RTT值。 这 些值在随后的决定最佳转发途 径 时, 也 许会用到。 通 过叫做 netdb 交换 的机制, squid 也支持 netdb 度量值的批量迁移。 squid 周期性的通过 HTTP请求邻居 cache的netdb数据。在cache_peer 行里 设置 no-netdb-exchange 选项,就可以禁止这些请求。 netdb_low 和netdb_high 指令控制度量数据库的大小。 当 存储子网的数量抵达 netdb_high 时, squid 删除最少近来使用的条目,直到数量低于 netdb_low。 minimum_direct_hops 和minimum_direct_rtt 指令指示 squid 直接连接到低于一定数量路 由跳 计数,或少于一定毫秒的原始服务器。匹配该标准的请求在access.log 里以 CLOSEST_DIRECT 形式记载。 cache管理器的 netdb 页显示完整的网络度量数据库,包括来自邻居 cache的值。例如: Network recv/sent RTT Hops Hostnames 63.241.84.0 1/ 1 25.0 9.0 www.xyzzy.com Squid 中文权威指南 175 sd.us.ircache.net 21.5 15.0 bo1.us.ircache.net 27.0 13.0 pb.us.ircache.net 70.0 11.0 206.100.24.0 5/ 5 25.0 3.0 wcarchive.cdrom.com ftp.cdrom.com uc.us.ircache.net 23.5 11.0 bo1.us.ircache.net 27.7 7.0 pb.us.ircache.net 35.7 10.0 sd.us.ircache.net 72.9 10.0 146.6.135.0 1/ 1 25.0 13.0 www.cm.utexas.edu bo1.us.ircache.net 32.0 11.0 sd.us.ircache.net 55.0 8.0 216.234.248.0 2/ 2 25.0 8.0 postfuture.com www1.123india.com pb.us.ircache.net 44.0 14.0 216.148.242.0 1/ 1 25.0 9.0 images.worldres.com sd.us.ircache.net 25.2 15.0 bo1.us.ircache.net 27.0 13.0 pb.us.ircache.net 69.5 11.0 这 里 , 你可 以 见 到 www.xyzzy.com服务器有一个 IP地址位于 63.241.84.0/24子网。从cache 到这台原始服务器的 RTT值是 25毫秒。邻居 cache: sd.us.ircache.net 更近一点,在 21.5毫秒。 10.610.610.610.6 InternetInternetInternetInternet Cache Cache Cache Cache 协议 ( ICPICPICPICP) ICP 是轻量级的目标定位协议,它作为 Harvest 项目的一部分而被发明。 ICP 客户发送 查询消息到一个或多个 ICP 服务器,询问它们是否缓存了某个 URI。每个服务器响应一个 Squid 中文权威指南 176 ICP_HIT(ICP 命中),ICP_MISS(ICP 丢失) , 或其他类型的 ICP 消息。 ICP 客户使用 ICP 响应里的信息来做转发 决定。 除了指示 cache命中, ICP 也用于提供关于 squid 和邻居 cache之间网络条件的线索。 从 这点看, ICP 消息类似于 ICMP ping。通过计算查询 /响应往返时间, squid 能估算网络拥塞 情况。 在极端情况下, ICP 消息可能丢失, 这意味着两者之间的链路断掉,或线路拥塞。 在 这种情况下, squid 会避免请求这个邻居 cache。 增加延时可能是使用 ICP 的最显然的弊端。查询 /响应交换要花费一些时间。 cache代 理被设计来减少响应时间, 而 不是增加延时。 如果 ICP帮助我们发现在 邻居 cache上的 cache 命中,这样它应该全面减少响应时间。见 10.10章关于 squid 的查询算法实现的描述。 ICP 也得承受某些设计不足带来的责难: 安 全性, 伸 缩性, 假 命中, 和 请求方式的缺 乏。 该协议不包括任何安全机制。 通常 squid 不能确认某个 ICP 消息是可信的; 它依赖于基于 地 址的访问控制来过滤掉不想要的 ICP 消息。 ICP 的伸缩性也很差。 ICP 消息的数量(和带宽 )增长, 与邻 居 cache 的数量成正比。 除非使用某种隔离机制, 这 实际上限制了你能使用的邻居 cache的数量。 我 不推荐拥有超 过 5或6个邻居 cache。 ICP 查询仅包含 URI,没有另外的请求头部。这让它很难精确的指示 cache命中。某 个 HTTP请求可能包含附加的头部 ( 例如 Cache-Control: max-stale=N)将cache命中转换为 cache 丢失。对姐妹关系的 cache来说,这些假命中的弊端特别明显。 从ICP 查询消息里丢失的还有请求方式。 ICP 假设所有的查询采用 GET 请求。 cache代 理不能使用非 GET 请求方式的 ICP 来查找缓存目标。 通过阅读如下资料,你可以找到其他的关于 ICP 的信息: • 1)我写的书: Web Caching (O'Reilly) • 2)RFCs 2186 and 2187 • 3)我的论文: "ICP and the Squid Web Cache" in the IEEE Journal on Selected Areas in Communication, April 1998 • 4) http://icp.ircache.net/ 10.6.110.6.110.6.110.6.1 成为ICP ICP ICP ICP 服务器 当你使用 icp_port 指令时, squid 自动成为 ICP 服务器。 也就是说, 它在你指定的端 口 侦听 ICP 消息,或默认的 3130端口。假如决定使用非标准 端口,别忘了告知姐妹和 /或子 cache。squid 默认拒绝所有 ICP 查询。必须使用 icp_access 规则列表,允许来自邻 居 cache Squid 中文权威指南 177 的查询。使 用srcACL 容易做到这点。例如: acl N1 src 192.168.0.1 acl N2 src 172.16.0.2 acl All src 0/0 icp_access allow N1 icp_access allow N2 icp_access denyAll 注意仅仅 ICP_QUERY 消息从属于 icp_access规则。 ICP 客户端的功能, 例 如发送查 询 和接受 响应 , 不需 要 任何 特 殊访 问 控制 。 我也 推 荐使 用 操作 系统的 包过 滤 功能 ( 例 如 ipfw,iptables,和pf) 。 允许来自可信任邻居的 UDP 消息到 ICP 端口,并拒绝所有其他的。 如果 squid 因为 icp_access规则而拒绝某个 ICP 查询,它返回一个 ICP_DENIED 消息。 然而, 假如 squid 检测到超过 95%的近来查询被拒绝, 它 停止响应 1个小时。 若 发生这种情 况, squid 在cache.log 里写如下消息: WARNING: Probable misconfigured neighbor at foo.web-cache.com WARNING: 150 of the last 150 ICP replies are DENIED WARNING: No replies will be sent for the next 3600 seconds 假如你看到这样的消息,你该联系错误配置了 cache的管理员。 squid 被设计为迅速响应 ICP 查询。 也 就是说, squid 通过检查内存索引, 能 告知它是 否 有更新的、 缓 存的响应。 这 也就是为什么 squid 如此耗内存的原因。 当 ICP 查询进来时, squid 计算 URI 的MD5 hash 值,并且在索引里查找它。假如没有找到 , squid 返回 ICP_MISS 消 息。假如找到了, squid 检查超时时间。假如目标没有刷新, squid 返回 ICP_MISS。对刷新 的目标, squid 返回 ICP_HIT。 默认的, squid 记录所有的 ICP 查询(但非响应)到 access.log。假如拥有许多繁忙的 邻居 cache, 日志文件可能变得太大而难于管理。 使用 log_icp_queries 指令来阻止记录这 些 查询。尽管会丢失 ICP 的详细日志,你仍可以通过 cache管理器来获取一些合计信息。 假如有姐妹邻居, 你也许想使用 miss_access 指令来强迫其关系。 它指定 cache丢失 的 访问规则。它与 http_access相似,但仅检查必须被 转发的请求。默认的规则是允许所有 的 cache丢失。除非增加一些 miss_access 规则,任何姐妹 cache都可能变成子 cache,并通过 你的网 络连接来转发 cache丢失,这样就盗用了带宽。 Squid 中文权威指南 178 miss_access 规则相对简单。 不要忘记包含本地客户端 (例如 web 浏 览 器 ) 。如下 是 个 简 单示例: acl Browsers src 10.9.0.0/16 acl Child1 src 172.16.3.4 acl Child2 src 192.168.2.0/24 acl All src 0/0 miss_access allow Browsers miss_access allow Child1 miss_access allow Child2 miss_access deny All 注意我没有在这里列举任何 姐 妹 cache。子 cache 允许通过我们请求 cache 丢失,但姐 妹cache不允许。它们的 cache丢失请求被 deny all 规则拒绝。 10.6.1.110.6.1.110.6.1.110.6.1.1 icp_hit_staleicp_hit_staleicp_hit_staleicp_hit_stale指令 ICP 的问题之一是,它 对 cache 住的,但陈旧的响应 返 回 ICP_MISS。这点确实存在, 即使响应陈旧但有效。 考虑一个简单的堆叠, 有 1个子 cache和2 个父 cache。 某个目标缓 存 在其中 1个父 cache上。缓存的响应是陈旧的,但未改变,需 要确认。 子 cache的ICP 查询 导致 2条ICP_MISS 响应。 由 于不知道陈旧的响应存在于第 1个父 cache中, 子 cache会转 发 它的请求到第 2个父 cache。现在目标存储在 2个父 cache中,浪费资源。 在该情形下, icp_hit_stale 指令有用。 它告诉 squid 对任何 cache住的目标, 即使它是 陈 旧的,都返回 ICP_HIT。这在父子关系的 cache中很安全,但对姐妹关系的 cache有问题。 回想一下姐妹关系,客户 cache仅仅允许发送 cache命中的请求。激活了 icp_hit_stale 指令,增加了假命中的数量,因为 squid 必须确认 陈旧响应。正常情况下, squid 这样处 理 假命中:在发送给姐妹 cache的HTTP请求里增加 Cache-Control: only-if-cached 指令。假如 姐妹 cache不能满足 HTTP请求为 cache命中, 它 返回一个 HTTP 504(网关超时) 消 息。 当 squid 接受到 504响应,它再次转发请求到父 cache或原始服务器。 假如必须转 发所有的假命中, 激活 icp_hit_stale 就会给姐妹关系 cache带来麻烦。 这 时 ICP 客户端 cache_peer 的allow-miss 选项就 变得有用。当设置了 allow-miss 选项时, squid 忽略它发送到姐妹 cache的HTTP请求里的 only-if-cached 指令。 假如激活了 icp_hit_stale, 必 须确保 miss_access不会拒绝来自姐妹 cache的cache丢失 Squid 中文权威指南 179 请求。不幸的是,没有办法让 squid 只允许 cache住的,但陈旧的目标的 cache丢失。允许 姐妹 cache的cache丢失请求,也让 squid 容易被滥用。姐妹 cache的管理员可能 没经过你 的同意,而擅自改变它为父 cache。 10.6.1.210.6.1.210.6.1.210.6.1.2 ICP_MISS_NOFETC H ICP_MISS_NOFETC H ICP_MISS_NOFETC H ICP_MISS_NOFETC H 功能 命令行-Y选项的作用是:在squid 重建内存索引时,它导致squid 返回 ICP_MISS_NOFETCH, 而 不是 ICP_MISS。 接受 到 ICP_MISS_NOFETCH 响应的 ICP 客户 , 不会对这些目标发送 HTTP请求。这减少了 squid 的负载,并让重建过程快速完成。 10.6.1.310.6.1.310.6.1.310.6.1.3 test_reachabilitytest_reachabilitytest_reachabilitytest_reachability 指令 假如激活了 netdb 功能(见 10.5章) , 你也许会对 test_reachability 指令感兴趣。它背 后 的目 的 是 , squid 仅接 受某些请求,这些请求的 原 始 服 务 器 squid 能访 问 到 。 激 活 了 test_reachability 指令, 在 原始服务器不响应 ICMP ping 时,squid 返回 ICP_MISS_NOFETCH, 而不是 ICP_MISS。这点有助于减少假 HTTP 请求的数量,并增加终端用户迅速接受数 据 的机会。 然而,一定比率的原始服务器站点过滤掉了 ICMP 传输。 对这些站点,即使 HTTP 连接成功, squid 也会返回 ICP_MISS_NOFETCH。 激活 test_reachability 也导致 squid 在ICP 查询的响应里, 发 起 netdb 度量。假如 squid 没有请求中的原始服务器的任何 RTT度量值,它会发出一个 ICMP ping 消息。 10.6.210.6.210.6.210.6.2 成为ICP ICP ICP ICP 客户 首先,必须使用 cache_peer 指令来定义邻居 cache。见 10.3章。 接着,必须使用 icp_port 指令,即使 squid 仅作为 ICP 客户。这是因为 squid 使用同样 的socket 来发送和接受 ICP 消息。这也许是个不好的设计思路。假如 仅作 为 ICP 客户,请 使用 icp_access来阻塞查询。例如: acl All src 0/0 icp_access denyAll Squid 默认的对大多数请求发送 ICP 查询到其邻居。见 10.10章关于 squid 决定何时查 询 其邻居 cache的方法的完整描述。 在发送一个或多个查询后, squid 等待一定数量的时间, 等候 ICP 响应抵达。 假如 squid 从某个邻居 cache 接受到 ICP_HIT,它会立刻转发 请求到 那里。 会则, squid 会一直等待, 直到所有的响应抵达,或超时发生。 squid 基于下列算法,动态的计算超时。 Squid 从最近的 ICP 传输中,知道从它自己到每个邻居 cache之间的平均往返时间。在 查询一组邻居时, squid 计算所有邻居 ICPRTT的平均数,然后将该数值翻 倍。换句话 说, Squid 中文权威指南 180 查询超时值是每个邻居 cache查询的 RTT的平均值的 2倍。 在 计算超时值时, squid 忽略看 起 来已 down 掉的邻居。 在某些情形下 ,该 算法不 会工 作良好 ,特 别在邻 居 cache 的RTT变化很大的情 况下。 使用maximum_icp_query_timeout 指令可以改变超时的上限。另外,也可以通过 icp_query_timeout 指令,让 squid 使用一个常量超时值。 10.6.2.110.6.2.110.6.2.110.6.2.1 ICPICPICPICP 客户 的 cache_peercache_peercache_peercache_peer选项 weight=n 允许你在使用 ICP/HTCP 时 , 手工 加 权 父 cache。 它仅 当 所 有 父 cache报告 cache 丢失时, 才变得有用。 正常情况 下, squid 选择响应首先抵达的父 cache。 实际上, squid 会 记住查询中哪个父 cache有最好的 RTT。squid 实际上通过权重来区分 RTT, 所以 weight=2 的父 cache,不管其实际距离如何,都会被对待为离 squid 很近。 no-query 禁止对邻居 cache的ICP/HTCP。也就是说,你的 cache不会发送任何对 cache 丢失的查询到邻居。它通常以 default 选项被使用。 closest-only 指squid 的netdb 功能之一。 它 指示 squid 仅基于 netdb RTT度量值来选择 父 cache,而不是响应抵达的顺序。该选项要求 netdb 在两端都被激活。 10.6.2.210.6.2.210.6.2.210.6.2.2 ICPICPICPICP 和netdbnetdbnetdbnetdb 就像 10.5章里提到的一样, netdb 主要用于 ICP 查询。在本节里,我们跟随在这个过程 中,所有的步骤调用。 • 1. 作为 ICP 客户的 squid cache, 准 备发送查询到一个或多个邻居 cache。假 如 设置了 query_icmp,squid 在ICP 查询里设置 SRC_RTT 标记。 这 通知 ICP 服务器, squid 想在 ICP 响应里接受 RTT度量值。 • 2.邻居 cache接受到带有 SRC_RTT 标记的查询。假如邻居 cache配置了使 用netdb 度量, 它 会在数据库里搜索原始服务器的主机名。 注 意邻居 cache不会查询 DNS 来解析原始服务器的 IP地址。 这样, 假 如指定的主机已经被度量过, 它才能在 netdb 里 找到相关条目。 • 3.假如主机存在于 netdb 数据库里,邻居 cache在ICP 响应里返回 RTT和路 由跳数。并在响应里设置 SRC_RTT 标记,指示度量值已提供。 • 4.当 squid 接受到设置了 SRC_RTT 标记的 ICP 响应,它剥离出 RTT和路由 跳数。 这些被追加到本地 netdb, 以便将来 squid 了解从邻居 cache到原始服务器的近 似 RTT。 • 5.ICP_HIT 响应导致 squid 立刻转发 HTTP 请求。然而假 如 squid 仅接受到 ICP_MISS 应答, 它就选择具有到原始服务器的最小 ( 非零) RTT的父 cache。 该请求 以 CLOSEST_PARENT_MISS 被记录到 access.log。 Squid 中文权威指南 181 • 6.假如没有父 cache的ICP_MISS 响应中包含 RTT值, squid 选择 ICP 应答 最先到达的父 cache。这时,请求以FIRST_PARENT_MISS 被 记 日 志 。 然而 , 假如 父 cache 设置了 losest-only 选项, squid 就从不会选择它作为第一个父 cache。 换句话说, 仅当 该 父cache离原始服务器最近时,才会被选中。 10.6.310.6.310.6.310.6.3 广播ICPICPICPICP 你已知道, ICP 的伸缩性差。 消息的数量与邻居 cache的数量成正比。 因为 squid 发送 同样的 ICP_QUERY 消息到每个邻居,你可以使 用广播来减 少 在网络中传输的消息数量。 相对于发送 N条消息到 N个邻居, squid 仅发送一个消息到广播地址。 广 播路由结构确保 每 个邻居能接受到消息的复制品。 请 参阅书 籍: Interdomain Multicast Routing: Practical Juniper Networks and Cisco Systems Solutions by Brian M. Edwards, Leonard A. Giuliano, and Brian R. Wright (Addison Wesley) 关于内部网络广播的更多信息。 注意 ICP 应答总是通过单点传播发送。这是因 为 ICP 应答可能不一样,并且单点传播 和广播的路由拓扑不同。因 为 ICP 也用于指示网络条件,故 ICP 应答应走 HTTP 应答所采 取的同样路径。广播仅减少了查询的消息数量。 历史上, 我 发现广播结构不稳定和不可信。 许多 ISP以低优先级来对待广播。 广 播工 作 一天, 某 些事情可能在数天或数周后崩溃。 在 你自己的网络里使用广播可能是安全的, 但 我 不推荐在公共 Internet 上使用广播 ICP。 10.6.3.110.6.3.110.6.3.110.6.3.1 广播ICPICPICPICP服 务器 广播 ICP 服务器加入 1个或多个广播组地址来接受消息。 mcast_groups 指令指定这些组 地址。它的值必须是广播 IP地址,或可被解析到广播地址的主机名。 IPv4广播地址的范围 是: 224.0.0.0-239.255.255.255。例如: mcast_groups 224.11.22.45 关于广播有意思的事情是主机, 而 不是应用, 加 入一个组。 当 某台主机加入广播组时 , 它接受到发送给该组的所有数据包。这意味着,在选择一个广播组用 于 ICP 时,你必须小 心一点。 不 能选择某个已被其他应用所使用的地址。 若 这种组交迭情况发生, 两 个组会串 起 来,并接受彼此的数据传输。 10.6.3.210.6.3.210.6.3.210.6.3.2 广播ICPICPICPICP客户 广播 ICP 客户发送查询到某个或多个广播组地址。这样, cache_peer 行的主机名参数, 必须是(或能解析到)一个广播地址。例如: cache_peer 224.0.14.1 multicast 3128 3130 ttl=32 HTTP端口号(例如 3128)在该情形下是无关的,因为 squid 从来不会发起 HTTP连接 Squid 中文权威指南 182 到广播邻居。 应该认识到,广播组没有任何访问控制。任何主机能加入任何的广播组地址。这意味 着, 除非足够小心, 其 他人也能接受到你的 squid 发送的广播 ICP 查询。 IP广播有 2个方 法 来阻止包传得太远: TTL和管理范围。因为 ICP 查询可能携带敏感信息(例如用户访问的 URI) , 我推荐使用管理范围地址,并正确的配 置路由器。见 RFC 2365的更多信息。 ttl=n选项仅针对广播邻居。它是用于 ICP 查询的广播 TTL值。它控制 ICP 查询能传 送 多远。 有效值范围是 0-128。 较大的取值允许广播查询传送更远, 并 有可能被外面的人截获 。 使用较低的 TTL值,可以保证查询不会离源头太远,并位于自己网络中。 广播ICP 客户也必须告诉 squid 关于响应查询的邻居的情况。 squid 不盲目信任任何 发 送ICP 应答的 cache。 你 必须告诉 squid 合法的, 可 信任 的邻居。cache_peer 指令的 multicast- responder 选项用以确定这样的邻居。 例 如, 假 如知道 172.16.2.3是位于广播组里 的可信任 的 邻居,你可以在 squid.conf 行里增加如下行: cache_peer 172.16.3.2 parent 3128 3130 multicast-responder 当然也 能 使用 主 机 名代 替 IP地址。 来 自外 部 邻 居 的 ICP 应答被 忽 略了 , 但 记录 在 cache.log 里。 正常情况下, squid 希望对其发送的每个请求都接受到 ICP 应答。 在 广播机制下情况 会 不同, 因 为每个查询会导致多个响应。 为了统计这点, squid 周期性 的对广播组地址发送 探 测消息。 这些探测告诉 squid, 多少服务器在侦听。 squid 统计特定数量时间内抵达的应答 数 量。 该时间数量由 mcast_icp_query_timeout 指令给定。 然后,当 squid 发送真正的 ICP 查询 到广播组时,它期望返回前述数量的 ICP 应答。 10.6.3.310.6.3.310.6.3.310.6.3.3 广播ICPICPICPICP示例 既然广播 ICP 有点棘手,如下是另一个示例。假设你的 ISP有3个父 cache侦听在广播 地址,等待 ICP 查询。 ISP在其配置文件里仅需要一行: mcast_groups 224.0.14.255 子cache的配置有点复杂。 首 先, 必 须列出 squid 能发送查询的广播邻居。 也 必须列出 3 个父 cache的单点传送地址,以便 squid 能接受它们的应答: cache_peer 224.0.14.225 multicast 3128 3130 ttl=16 cache_peer parent1.yourisp.net parent 3128 3130 multicast-responder cache_peer parent2.yourisp.net parent 3128 3130 multicast-responder cache_peer parent3.yourisp.net parent 3128 3130 multicast-responder Squid 中文权威指南 183 mcast_icp_query_timeout 2 sec 请记住, squid 从不会发起 HTTP请求到广播邻居,也从不发送 ICP 查询到广播应答邻 居。 10.710.710.710.7 Cache Cache Cache Cache 摘要 (Cache(Cache(Cache(Cache Digest)Digest)Digest)Digest) 关于 ICP 的最常见的抱怨在于它增加了每个请求的延时。 许多情况下,在 squid 作出 转 发决定前,它会等待所有的 ICP 响应抵达。 squid 的cache摘要提供了类似的功能,但没有 每个请求的网络延时。 Cache 摘要基于 由 Pei Cao 首先发布的一 项技 术,叫 做摘 要缓存 。基 本思路 是用 一 个 Bloom filter 来表现 cache内容。 邻居 cache下载其他每个 cache的Bloom filter(也即摘要)。 然后,通过查询摘要来决定某个 URI 是否在邻居的 cache里。 相对于 ICP,cache摘要以空间交换时间。 ICP 查询浪费时间(延时) , cache摘要浪费 空间(内存,磁 盘) 。在 squid 中,邻居的摘要 完全存 放在内 存里。 在一个 典型的 摘要里, 每百万目标需要大约 625KB 的内存。 Bloom filter 是一种有趣的数据结构,它提供对条目集合的有损耗编码。 Bloom filter 自 身简单的是一个大的位数组。给定某个 Bloom filter(和用于产生它的参数) , 你会发现, 不 能确定是否某个特定条目位于集合中。 在 squid 中,条目就是 URI,摘要大小是每个 cache 目标 5 位。 例 如, 要 呈现 1,000,000个cache目标的集合, 需 要用到 5,000,000位或 625,000字节 的filter。 因为它们的天性, Bloom filter 不能完整的呈现条目集合。 它们有时候不正确的指示 某 个条目位于集合中,因为 2个或多个条目可能在同一位上打开。换句 话说, filter 可能显 示 目标 X位于 cache中, 即使 X从来没被缓存或请求过。 通过调整 filter 的参数,你可以在 一 定程度上控制这种假情况。例如,增加每个目标的位数量, 可以减少这种假情况。请见我 在O'Reilly 出版的书 :Web Caching,可以找到关于 Caceh 摘要的更多细节。 10.7.110.7.110.7.110.7.1 配置squidsquidsquidsquid的cache cache cache cache 摘要 首先,必须在 编 译 squid 时激活 Cache Digest 代码。在运行 ./configure 时简单的增加 -- enable-cache-digests 选项。采用这步导致在运行 squid 时发生 2件事: • 1)Squid cache产生它自己内容的摘要。邻居 cache如果也配置了使用 cache摘 要,那可能就会请求这个摘要。 • 2)Squid 请求每个邻居的 cache摘要。 Squid 中文权威指南 184 • 假如不想请求某个邻居的 cache摘要,就在cache_peer行里使用 no-digest 选项, 例如: cache_peer neighbor.host.name parent 3128 3130 no-digest Squid 在下述 URL 中保存它自己的摘要: http://my.host.name:port/squid-internal-periodic/store_digest. 当squid 请求邻居的摘 要时, 它简单请求: http://neighbor.host.name:port/squid-internal- periodic/store_digest. 明显的,这 种 命名机制特 指 squid 。假如邻居 cache 支持 cache 摘要,但它不 是 squid ,你必须告 诉 squid 邻居摘要的不同地址。 cache_peer 指令的 digest-url=url 选项允许你配 置邻居的 cache摘要 URL。例如: cache_peer neighbor.host.name parent 3128 3130 digest-url=http://blah/digest squid.conf 有许多指令控制squid 产生它自己的cache 摘要的方法。首先, digest_generation 指令控 制 squid 是否产生 自 己 的 cache 摘要。假如 你 的 cache 是一个 子 cache,而不是其他任何 cache的父或姐妹 cache,那么你也许想禁止产生摘要。其他指令 控 制产生摘要的低层次细 节。 只 有当你完全理解了 cache摘要的执行原理, 你 才能改变它们 。 digest_bits_per_entry 决定摘要的大小。 默 认值是 5。 增 加该值导致更大的摘要 (浪费 更 多内存和带宽) 和 更低的假命中可能性。 降 低该值导致更小的摘要和更多的假命中。 我 觉 得 默认值非常合理。等于或低于 3的设置导致太多的假命中而不可用,等于或高于 8的设置简 单的浪费带宽。 Squid 使用 2个步骤来创建 cache摘要。首先, 它建立 cache摘要数据结构。这基本上 是 1个大的 Bloom filter 和包含了摘要参数的小头部。一旦写入了数据结构, squid 就会对摘要 创建缓存的 HTTP响应。 它 预先包含某些 HTTP头部, 并 和其他缓存响应一起, 存 储该响 应 到磁盘。 Cache 摘要对某时刻的 cache内容维护一个快照。 digest_rebuild_period 控制 squid 重建 摘要数据结构 ( 并非 HTTP 响 应 ) 的频 率 。 默 认是每个小时 1次。 更 频繁的重建意味着 squid 的摘要更新更快,但会浪费更多的 CPU 时间。重建过程对 CPU 影响相对较大。在 squid 重 建摘要过程 中,用户会感觉到速度降低。 digest_rebuild_chunk_percentage指令控制每次调用重建函数时, 多少 cache 增加到摘 要 里。 默 认是 10%。 在 每次调用重建函数过程中, squid 增加一定百分比的 cache到摘要里。 在 该函数运行时, squid 不处理用户请求。 在 增加了指定的百分比后, 该 函数重新安排它自 己 的时间表并退出,以便 squid 能正常处理 HTTP 请求。在处理完等待请求后, squid 返回重 建函数,并增 加另外的 cache块到摘要里。减少该值将给予用户更多的响应时间,然而增 加了重建摘要所需的总时间。 digest_rewrite_period 指令控制 squid 从摘要数据结构创建 HTTP响应的频率。 大 部分 情 形下, 这个频率应该匹配 digest_rebuild_period 值。 默认是 1小时 1次。 重写过程由对某个 函 Squid 中文权威指南 185 数的数次调用组成, 该 函数简单的添加一定数量的摘要数据结构到 cache条目里 ( 就象 squid 正在从网络中读取原始服务器的响应)。每 次 调 用 该 函 数 , squid 添加appends digest_swapout_chunk_size 字节的摘要。 10.810.810.810.8 超文 本 cache cache cache cache 协议 ( HTCPHTCPHTCPHTCP) HTCP 和ICP 有许多共同的特征, 尽管 HTCP 范围更广, 并 且通常更复杂。 两者都使 用 UDP 传输,并且两者都是请求执行的协议。然而, HTCP 也有很多与 ICP 不同之处,即: • 1)ICP 查询仅包 括 URI ,甚至没有请 求方 式。 HTTP 查询包括完整 的 HTTP 请求头部。 • 2)ICP 不提供安全保证。 HTCP 通过共享密钥,提供附加的 消息验证, 尽管 它还没有在 squid 中实现。两者都不支持加密消息。 • 3)ICP 使用简单的,修正大小的二进制消息格式,难于扩展。 HTCP 使用复杂的,可变大小的二进制消息格式。 HTCP 支持 4种基本的编码: TST 测试缓存响应是否存在 SET 告诉邻居更新缓存目标头部 CLR 告诉邻居从其 cache里删除一个目标 MON 监视邻居 cache的活动 在squid 里,当前仅实现了 TST编码。本书不讨论其他方面。 使用HTCP 相对于 ICP 的主要优势在于更少的假命中。 HTCP 有更少的假命中,因为 查询消息包含了完整的 HTTP请求头部, 包含了来自客户端的任何 Cache-Control 要求。 使 用HTCP 的主要不足在于 HTCP 查询更大,要求更多的 CPU 来处理产生和解析消息。测 量 显示, HTCP 查询大约是 ICP 查询的 6倍大, 这归咎于 HTTP请求头部的存在。 然而, squid 的HTCP 响应典型的比 ICP 响应小。 Squid 中文权威指南 186 HTCP 的文档在 RFC 2756里,它被作为实验性协议。关系消息格式的更多信息,请 见 RFC:http://www.htcp.org 或者我的 O'Reilly 的书, Web Cacheing 10.8.110.8.110.8.110.8.1 配置Squid Squid Squid Squid 使用HTCPHTCPHTCPHTCP 为了使用 HTCP,必须配置 squid 使用 --enable-htcp 选项。当该选项激活时, squid 默认 变成 HTCP 服务器。htcp_port 指定 HTCP 端口号, 默 认是 4827。 将 端口号设为 0禁止了 HTCP 服务模式。 要成为 HTCP 客户端, 必 须在 cache_peer 行里增加 htcp 选项。当你 增加该选项时,squid 总是发送 HTCP 消息, 而 不是 ICP,到邻居cache。 不 能对单一邻居既使用 HTCP 又使用 ICP。 放置 ICP 端口号的那个域实际上变成 了 HTCP 端口号,所以你必须也要改变它。例如,假 如你想将 某个 ICP 邻居变成 HTCP 的,如下是邻居 cache的ICP 配置: cache_peer neighbor.host.name parent 3128 3130 为了转换到 HTCP,该行变成: cache_peer neighbor.host.name parent 3128 4827 htcp 有时候人们忘记改变端口号,这样在发送 HTCP 消息到 ICP 端口时,就会犯致命错误 。 若这点发生, squid 在cache.log 里写警告日志: 2003/09/29 02:28:55| WARNING: Unused ICP version 23 received from 64.216.111.20:4827 与对待 ICP 查询不同, Squid 当前不记录 HTCP 查询。 HTCP 查询也不可在 client_list 页面跟踪到。然而,若为对 等 cache 激活了 HTCP,cache 管理器的 server_list 页面就(见 14.2.1.50节)会显示命中和丢失的 HTCP 响应的计数和百分比。 Histogram of PINGSACKED: Misses 5085 98% Hits 92 2% 注意,当前还没有哪个 squid 版本支持 HTCP 验证。 10.910.910.910.9 Cache Cache Cache Cache 数组 路由 协议 (CARP)(CARP)(CARP)(CARP) CARP 是一种在一组缓存代理中,区分开 URI 的算法。换句话说,每个 URI 被分配到 cache中的一个。 CARP 在一组 cache中,最大化了命中率, 最小化了 目标重复。该协议 由 Squid 中文权威指南 187 2个主要的成分组 成:路 由函数 和代理 数组成 员表。 不 象 ICP,HTCP,和Cache 摘要, CARP 不会预示某个请求是否 cache命中。这样,你不能在姐妹关系中使用 CARP--仅在父 cache 中有效。 CARP 背后的基本想法是,你有一组 (或一个数组)的父 cache,它们处理所有来自 用 户或子 cache的负载。 cache数组是用来处理日益增长的负载的方法之一。无论何时你需要 更高的性能,只需增加更多的 数组成员。 CARP 是一个确定性的算法。也就是说,同样的 请求总是走向同一数组成员(只要数组大 小不改变) 。 不象 ICP 和HTCP,CARP 不使用查 询消 息。 关于 CARP 另一个有趣的事情是,你可以选择用多种 不同方法来扩展它 。例如,方法 之一是让所有用户代 理 (user-agent)执行 CARP 算法。使用一 个 JavaScript 写的 Proxy Auto- Configuration(PAC)函数(附录 F) , 你也许能做到这点。然而,某些用户代理可能不能执行 或支持 PAC文件。方法之二是使用二 级cache堆叠。子 cache接受来自所有用户代理的请 求,然后它们执行 CARP 算法,为每个请求选择父 cache。然而, 除非你的网络够大,否 则 太多 的cache带来的负担可能大过受益 。 最后一种方法,你也能在数组自身内执行 CARP。 也就是说,用户代理连接到 cache数组中的随机成员,但每个成员 转发 cache丢失到基于 CARP 算法的数组的其他成员。 CARP被设计为比简单的哈希算法更好, 后 者典型的通过应用某个哈希函数 ( 例如 MD5) 到URI 来工作。 然后该算法计算数组成员数量的系数。 它可能象如下这段伪代码一样简单 : N = MD5(URI) % num_caches; next_hop = Caches[N]; 该技术在所有 cache中均一的分摊 URI。 它 也提供兼容性映射 ( 最大化 cache命中),只 要cache的数量保持不变。然而,当增加或删除 cache时,该算法改变大部分 URI 的映射。 CARP 的路由函数在该技术中以 2种方式得以改进。首先,它允许不均衡共享负载。例 如,可以配置一个父 cache接受的请求数量是另一个的 2倍。第二,增或删数组成员最小化 了被再分配的 URI 的片断。 CARP 的负面影响是它相对消耗 CPU 时间。对每个请求, squid 为每个父 cache打分。 该请求被发送到分数最高的父 cache。 该 算法的复杂性与父 cache的数量成正比。 换 句话说 , CPU 负载的增加,与CARP 父cache的 数 量 成 正 比 。 然而 , CARP 里的算术已被设计成比 MD5 和其他加密哈希函 数更快。 除了负载共享算法, CARP 也有个协议成分。 成员表有定义良好的结构和语法, 以 便 单 一数组里的所有客户端能有相同的配置。假如某些 客户端配置得不同, CARP 变得没什么 用,因为并非所有客户端发送同样的请求 到同一 父 cache。注意 squid 当前没有实现成员表 功能。 Squid 的CARP 实现在另外一方面也有缺陷。 协 议认为, 假 如某个请求不能被转发 到 最高分的父 cache,它就被发送到次高分的成员。假如又失败,应用就会放弃。 squid 当前 仅使用最高分的父 cache。 Squid 中文权威指南 188 CARP的原始文档是一份 1998年的 Internet草 稿 , 现在 已 经 过 期 。 它由 下 述 2人开发:Vinod Valloppillil of Microsoft and Keith W. Ross of the University of Pennsylvania。 查 询一下, 你 还 可 以在 Internet 上找到老文档。 甚 至能在 Microsoft 的站点上找到一些文档。 在 我的 O'Reilly 的 书Web Caching 里,你能找到更多信息。 10.9.110.9.110.9.110.9.1 配置Squid Squid Squid Squid 使用CARPCARPCARPCARP 为了在 squid 里使用 CARP,必须首先在运行 ./configure 脚本时使用 --enable-carp 选项。 接着,必须为属于数组成员的父 cache,增加 carp-load-factor 选项到 cache_peer 行。如下是 示例: cache_peer neighbor1.host.name parent 3128 0 carp-load-factor=0.3 cache_peer neighbor2.host.name parent 3128 0 carp-load-factor=0.3 cache_peer neighbor3.host.name parent 3128 0 carp-load-factor=0.4 注意, 所有的 carp-load-factor 值必须合计为 1.0。Squid 会检查该条件, 假如有差错, 它 会抱怨。另外, cache_peer 行必须以负载因素值的增量来列举。仅仅近来的 squid 版本会检 查该条件是否真。 记住,在关于邻居 cache的存活 /死亡状态方面, CARP 在一定程度上有些特殊。正常 情况下,在 10次失败连接后, squid 宣布邻居死亡(并中止发送请 求到它) 。 然而在 CARP 情况中, squid 会跳过某个有 1次或多次失败连 接的 父 cache。一旦 squid 使用 CARP 工作, 就可以使用 cache管理 器的 carp 页面来监视它。请见 14.2.1.49的更多信息。 10.1010.1010.1010.10 归纳 所有 现在你可能意识到, squid 有许多不同的方法,来决定 请求如何转 发,和转发 到哪里。 许多情况下, 你 可能同时使用不止一种的协议或技术。 然而, 仅 仅通过观察配置文件, 难 以 发现 squid 如何联合使用这些不同技术。在本节我将解释, squid 实际上怎样做出转发决定 。 显而易见,一切从 cache 丢失开始。任何作为未确认 的 cache 命中而得到满足的请求, 不会在下述节里描述。 选择程序的目的是,创建适当的下一跳位置列表。下一跳位置可能是邻居 cache,或原 始服务器。依赖于配置不同, squid 可能选择 3个下一跳。假如请求不能首先满足, squid 接 着尝试第 2个,然后是第 3个。 10.10.110.10.110.10.110.10.1 步骤 1111:直接决定选项 第一步决定某个请求: 它可能, 必 须, 或不必直接发送到原始服务器。 squid 会参考 该 Squid 中文权威指南 189 请求的 never_direct 和always_direct 访问规则 列表。目的是为了给下面 3个值设置 1个标记: DIRECT_YES,DIRECT_MAYBE, 或DIRECT_NO。该标记随后决定 squid 是否为该请求选 择1个邻居 cache。squid 按顺序检查下述条件。 假 如任何一个条件为真, 它 设置 direct 标记 , 并跳到步骤 2。假如你在跟进源代码,该步相应于 peerSelectFoo( )函数的开始: • 1.Squid 首先查找 always_direct 列表。 假如请求匹配该列表, direct 标记设 为 DIRECT_YES。 • 2.Squid 接着查找 never_direct 列表。假如请求匹配该列表, direct 标记设为 DIRECT_NO。 • 3.对看起来陷入转发死循环的请求, squid 有特殊的检查方法。当 squid 检查 到1个转发死循环,它将 direct 标记设为 DIRECT_YES 来打破循环。 • 4.仅在激活了netdb 情况下,squid 才检查minimum_direct_hops 和 minimum_direct_rtt 的设置。假如 测量跳计数,或往 返时间低于配置的值,squid 设置 direct 标记为 DIRECT_YES。 • 5.假如前述条件没有真的, squid 设置 direct 标记为 DIRECT_MAYBE。 10.10.210.10.210.10.210.10.2 步骤 2222:邻居选择协议 在这里, squid 使用堆叠协议之一来选择邻居 cache。象以前一样, 一旦 squid 在本步 里 选择了邻居,它直接跳到步骤 3。该步粗略的相当于 peerGetSomeNeighbor( )函数: • 1.Squid 检查邻居的 Cache 摘要。假如摘要指示 cache命中,该邻居就放到 下一跳列表。 • 2.Squid 尝试 CARP(假如激活了)。CARP 总是成功 ( 例如选择一个父 cache), 除非 cache_peer_access 或cache_peer_domain 规则,禁 止某 条特 殊请 求与 任何 父 cache 通信。 • 3.Squid 检查 netdb 度量(假如激活了) , 选择最近父 cache。假如 squid 了解 到,从 1台或多台父 cache到原始服务器的往返时间,少于它自己到原始服务器的 RTT, squid 就选择最少 RTT的父 cache。这点若发生,必须符合下列条件: 1)Squid 和父 cache都必须激活 netdb 功能; o2)query_icmp 必须在配置文件里激活; o3)原始服务器必须响应 ICMP ping 消息; o4)父 cache以前必须测量过到原始服务器 的 RTT,并在 ICP/HTCP 应答 Squid 中文权威指南 190 里(或通过 netdb 交换)返回这些测量值。 o4. 作 为最后的手段, Squid 发送 ICP/HTCP 查询。 squid 遍历所有的邻居 , 并检查许多条件。 squid 在如下情况下不查询邻居: 1)direct 标记是 DIRECT_MAYBE, 请求不可层叠(见 10.4.5节 ) 。因 为 squid 能 直接到达原始服务器, 它不会将这个请求转发到邻居,该请求看起来不可缓存 。 o2)direct 标记是 DIRECT_NO, 邻居是姐妹关系, 并且请求不可层叠。 因 为squid 被强迫要求使用邻居 cache,它就仅查询父 cache,后者总能处理 cache 丢失。 o3)cache_peer_access或cache_peer_domain 规则禁止发送该请求到邻居。 o4)邻居设置了 no-query 标记,或者其 ICP/HTCP 端口号是 0。 o5)邻居是广播应答者。 • 5.Squid 计算它发出了多少查询,并 估计该收到 多少应答。 假如它期望 至少 一个应答,下一跳选择过程会延时,直到应答到达,或超时发生。 Squid 期望从生存着 的邻居 cache那里接受到应答,而不是死亡的邻居(见 10.3.2节)。 10.10.310.10.310.10.310.10.3 步骤 2a:ICP/HTCP 2a:ICP/HTCP 2a:ICP/HTCP 2a:ICP/HTCP 应答处理 假如Squid 发出任何 ICP 或HTCP 查询, 它 会等待一定数量的应答。 在 发送出查询后 , Squid 知道它期待多少应答,和等待应答的最长时间。 Squid 期待来自被查询的生存的邻居 的1个应答。 假 如使用广播, squid 将当前组大小的估计值增加到期待的应答计数里。 在 等 待 应答时,有可能 1个或多个应答迟迟 不来,这样 squid 会安排 1个超时时间表。 当squid 接受到来自邻居 cache的ICP/HTCP 应答时,它采取如下动作: • 1.假如应答是 1个命中, squid 立即转发请求到那个邻居。在该点后抵达的任 何应答都被忽略。 • 2.假如应答是 1个丢失,并且它来自姐妹 cache,那么就被忽略。 • 3.Squid 不立刻对来自父 cache的ICP/HTCP 丢失采取动作。 代替的, 它记 住 哪个父 cache符合下列标准: oclosest-parent miss o假如应答包含 netdb RTT值, squid 会记住到原始服务器的 RTT最少的父 Squid 中文权威指南 191 cache。 ofirst-parent miss oSquid 会记住第一应答的 父 cache。换句话说,就是到你 的 cache 的RTT 最少的父 cache。2个cache_peer 选项影响这种选择算 法: weight=N 和closest- only。weight=N 选项让父 cache比它实际更近。 在估算 RTT时, squid 使用该 权 重来划分实际 RTT。通过增加父 cache的权重,可以给予它们更高的优先级。 closest-only 禁止邻居的第一父 cache丢失特性。换句话说, squid 仅在父 cache 离原始服务器最近时,才会选择这个父 cache(基于 ICP/HTCP 丢失应答)。 • 4.假如 squid 接受到期待数量的应答(所有丢失) , 或 超时发生,它选择最 近 父cache(closest-only) 丢失 邻 居 (假 如 设 置 了 ) 。 否则 , 它选 择 第 一 父 cache(first-parent) 丢失邻居(假如设置了) 。 Squid 也许不会接受到任何来自父 cache的ICP/HTCP 应答, 因 为父 cache有可能没被 查 询到,或因为网络丢包。在该情形下, squid 信赖从父 cache选择算法,在下面节里描述。 假如在接受到期待数量的应答前, ICP/HTCP 查询超时, squid 预先考虑将 access.log 里 的字符串 TIMEOUT_的值设为结果码。 10.10.410.10.410.10.410.10.4 步骤 3333:从 父 cache cache cache cache 选择 该步有点棘手。记住假如 direct 标记是 DIRECT_YES,squid 就不会执行这步。假如这 个标记是 DIRECT_NO, 并且 第 2步选择失败, squid 会调用 getSomeParent( )函数 ( 随后描 述) 来选择备份父 cache。 接着, squid 将所有它认为是存活的父 cache追加到列表。 这样,在 返 回错误消息到用户前,它会尝试所有可能的父 cache。 在DIRECT_MAYBE 情形下, squid 会同时增加父 cache和原始服务器到列表。顺序 依 赖于 prefer_direct 设置。 假如激活了 prefer_direct,squid 首先将原始服务器插入列表中。 接 着, 假如请求是可层叠的,或假如禁用了nonhierarchical_direct 指令 , squid 会调 用 getSomeParent()函数。 最终, 假如禁止了 prefer_direct,squid 才最后将原始服务器加到列 表 中。 getSomeParent()函数基于下列标准来选择父 cache之一。在每种情形下,父 cache必须 是存活的,并允许依照 cache_peer_access和cache_peer_domain 规则来处理请求: • 1)第一个父 cache,有默认的 cache_peer 选项。 • 2)父 cache的round-robin cache_peer 选项,有最低的请求数量。 • 3)第一个父 cache,已知是存活的。 Squid 中文权威指南 192 10.10.510.10.510.10.510.10.5 重试 偶然情况下,因为某些理由, squid 试图转发请求到原始服务器或邻 居 cache可能会失 败。 这就是为什么 squid 在邻居选择过程中, 要创建一个下一跳位置列表的原因。当下列 类 型的错误之一发生时, squid 重新尝试请求列表里的下一个服务器: • 1)网络拥塞或其他错误可能导致 “连接超时 ”。 • 2)原始服务器或邻居 cache可能临时不可到达,导致 “连接拒绝 ”错误。 • 3)假如请求导致 cache丢失,姐妹 cache可能返回 504(网关超时)错误。 • 4)假如 2个cache在访问控制策略里配错了,邻居 cache可能返回 “访问拒绝 ” 错误消息。 • 5)在 squid 读HTTP消息主体前,可能在已建立的连接上发生读错误。 • 6)持久连接可能存在紊乱情 况。 Squid 的重试失败请求的算法相对 强健。与 其让 squid 对用户返回错误,不如让它再试一次(当然会有延时) 。 10.1110.1110.1110.11 该怎 么做 ? Squid 新手经常问同样的或相似的问题,关于如何让 squid 正确的转发请求。这里我将 告诉你,在普通这种情况下,如何配置 Squid。 10.11.110.11.110.11.110.11.1 通过另外的代理发送所 有请求? 简单的只需定义父 cache,并告诉 squid 它不允许直接连接到原始服务器。例如: cache_peer parent.host.name parent 3128 0 acl All src 0/0 never_direct allowAll 该配置的弊端是,假如父 cache down 掉, squid 不能转发 cache丢失。假如这种情况发 生,用户会接受到 “不能转发 ”的错误消息。 10.11.210.11.210.11.210.11.2 通过另外的代理发送所 有请求,除非 它 down down down down 了? Squid 中文权威指南 193 试试这个配置: nonhierarchical_direct off prefer_direct off cache_peer parent.host.name parent 3128 0 default no-query 或者,假如你喜欢对其他代理使用 ICP: nonhierarchical_direct off prefer_direct off cache_peer parent.host.name parent 3128 3130 default 在该配置下, 只 要父 cache存活, squid 就会将所有 cache丢失转发给它。 使用 ICP 可以 让squid 快速检测到死亡的父 cache, 但 同时在某些情形下, 可 能不正确的宣称父 cache死亡。 10.11.310.11.310.11.310.11.3 确认squidsquidsquidsquid对某些请求,不使 用邻 居 cache cache cache cache 吗? 定义 1条ACL 来匹配特殊的请求: cache_peer parent.host.name parent 3128 0 acl Special dstdomain special.server.name always_direct allow Special 在该情形下 , 对 special.server.name 域的请求 的 cache 丢失,总是 发送 到原 始服 务器。 其他请求也许,或也许不,通过父 cache。 10.11.410.11.410.11.410.11.4 通过 父 cache cache cache cache 发送某些请求来绕过本 地过滤器? 某些 ISP(或其他组织) 有上级服务提供者,他们强迫 HTTP传输通过包过滤代理( 也 许使用 HTTP 拦截) 。 假如你能在他们的网络之外使 用不同的代 理,那就能 绕过其过滤 器。 这里显示你怎样仅发送特殊的请求到远端的代理: cache_peer far-away-parent.host.name parent 3128 0 acl BlockedSites dstdomain www.censored.com Squid 中文权威指南 194 cache_peer_access far-away-parent.host.name allow BlockedSites never_direct allow BlockedSites 第第第第11111111章章章章重定 向器 重定 向器 重定 向器 重定 向器 重定向器是 squid 的外部程序,它重写来自客户请求的 URI。例如, 尽管某个用户请 求 这个页面: http://www.example.com/page1.html ,重定向器可以将请求改变到别的地方,例 如: http://www.example.com/page2.html 。squid 自动抓取新的 URI, 就像是客户端的原始 请 求一样。假如响应可被缓存, squid 将它存储在新的 URI 下。 重定向功能允许你执行与 squid 相关的许多有趣事情。 许 多站点使用它们实现如下目 的: 访问控制,移除广告,本地镜像,甚至用以绕开浏览器的 bug。 关于使用重定向器进行访问 控制的好处 之一是,你 可以将用户 的请求重定 向到某个页 面, 这个页面详细解释为何她的请求被拒绝。 你也会发现重定向器比 squid 内建的访问控 制 提供更多的弹性。然而不久你会看到,重定向器并不能访问包含在客户请求里的完整信息。 许多人使用重定向器来过 滤 web 页面广告。大部分情形下, 可以将 对 GIF 或JPEG 广 告图片的请求, 改变为请求位于本地服务器上的, 小 而空的图片。 这样, 广告就消失了, 然 而不会影响页面布局。 所以在本质上,重定 向器其实 就是一 个程序, 它从标准 输入里读 取 URI 和其他信息, 并将新的 URI 写往标准输出。 Per 和Python 是写重定向器的流行语言,尽管某些作者 使用 编译性语言(例如 C)以求更好的性能。 Squid 的源代码没有包含任何重定向程序。 作 为管理员, 你 有责任编写自己的重定向 器, 或者下载别人编写的。该章开头部分描述 在 squid 和重定向进程之间的接口。 我也提供几 个简单的 Perl重定向器示例。 假 如你志在使用别人的重定向器, 而 不是自己编写, 请 跳到 11.3 章。 11.111.111.111.1 重定 向器 接口 重定向器在其标准输入里, 每 次一行的接受来自 squid 的数据。 每 行包括下列四个元 素, 以空格分开: • 1)请求 URI Squid 中文权威指南 195 • 2)客户 IP地址和完全可验证域名 • 3)用户名,通过 RFC 1413 ident 或代理验证 • 4)HTTP 请求方式 例如: http://www.example.com/page1.html 192.168.2.3/user.host.name jabroni GET 请求 URI 取自客户请求, 包括任何查询条件。然而, 分段标记(例如 #字符和随后的 文 本)被移除了。 第二个元素包含客户 IP地址, 和 可选的完整可验证域名 ( FQDN) 。 假如 激 活 了 log_fqdn 指令或使用了 srcdomainACL 元素, FQDN 才会设置。 尽管那样, FQDN 也许仍未知, 因 为 客户网络管理员没有在其 DNS里正确的设置反向指针区域。 假如 squid 不知道客户的 FQDN, 它用一个短横线 (-)代替。例如: http://www.example.com/page1.html 192.168.2.3/- jabroni GET 假如squid 了解请求背后的用户名, 客户 ident 域才会设置。 假 如使用了代理验证, ident ACL 元素, 或 激活了 ident_lookup_access, 这 点才会发生。 然 而请记住, ident_lookup_access 指令不会导致 squid 延缓请求处理。 换 句话说, 假 如你激活了该指令, 但 没有使用访问控 制, squid 在写往重定向进程时,也许仍不知道用户名。假如 squid 不知道 用户名,它显示一 个 短横线 (-)。例如: http://www.example.com/page1.html 192.168.2.3/- -GET Squid 从重定向进程里读回一个元素: URI。假如 squid 读取一个空行,原始 URI 保留 不变。 重定向程序永不退出,除非在标准输入里发生 end-of-file。假如重定向进程确实过早退 出, squid 在cache.log 里写一条警告信息: WARNING: redirector #2 (FD 18) exited 假如 50%的重定向进程过早退出, squid 会以致命错误消息退出。 11.1.111.1.111.1.111.1.1 处理包含空格 的 URIURIURIURI 假如请求 URI 包含空格,并且 uri_whitespace指令设置为 allow,那么任何在 URI 里的 空格被递交到重定向器。 如 果重定向器的解析器很简单, 那 它在这种情况下会很困惑。 在 使 用重定向器时,有 2个选项来处理 URI 里的空格。 Squid 中文权威指南 196 一个选项是设置 uri_whitespace指令为任何值, 除了 allow。 默 认的设置 strip, 在 大多 数 情况下可能是个好的选择,因为 squid 在解析 HTTP 请求时,它简单的从 URI 里删除空格。 该指令的其他值的信息,请见附录 A。 假如上述方法不可行, 你 必须确保重定向器的解析器足够巧妙, 以 检测额外的元素。 例 如, 假 如它发现接受自 squid 的行里的元素不止 4个, 它 会假设最后 3个元素是 IP地址,ident, 和请求方式。在最后 3个元素之前的任何东西,组成请求 URI。 11.1.211.1.211.1.211.1.2 产生HTTP HTTP HTTP HTTP 重定向消息 当某个重定向器改变客户的 URI 时, 它 通常不知道 squid 决定抓取新的资源。 也 就是 说, 这点违背了 HTTPRFC。假如你想友好而保留兼容性,有一个小窍门可让 squid 返回 HTTP 重定向消息。简单的让重定向器在新的 URI 前面插入 301:, 302:, 303:, 或307:。 例如,假如重定向器在其标准输出里写如下行: 301:http://www.example.com/page2.html Squid 返回类似如下的响应到客户端: HTTP/1.0 301 Moved Permanently Server: squid/2.5.STABLE4 Date: Mon, 29 Sep 2003 04:06:23 GMT Content-Length: 0 Location: http://www.example.com/page2.html X-Cache: MISS from zoidberg Proxy-Connection: close 11.211.211.211.2 重定 向器 示例 示例 11-1是用 perl 写的非常简单的重定向器。 它 的目的是, 将对 squid-cache.org 站点 的 HTTP 请求,发送到位于澳洲的本地镜像站点。 对看起来是请 求 www.squid-cache.org 或其 镜像站点之一的 URI,该脚本输出新的 URI,将主机名设为 www1.au.squid-cache.org. 重定向程序遇到的通用问题是缓存 I/O。注意这里我确保 stdout 不可缓存。 Squid 中文权威指南 197 Example 11-1. A simple redirector in Perl #!/usr/bin/perl -wl $|=1; # don't buffer the output while (<>) { ($uri,$client,$ident,$method) = (); ($uri,$client,$ident,$method) = split; next unless ($uri =~ m,^http://.*\.squid-cache\.org(\S*),); $uri = "http://www1.au.squid-cache.org$1"; } continue { print "$uri"; } 示例 11-2是另一个稍微复杂点的脚本。 在 这里我做了个初步尝试, 当 URI 包含不当词 汇 时,拒绝该请求。该脚本论证了解析输入 域的另一个方法。 假如没有得到所 有 5个请求域, 重定向器返回一个空行,请求保留不变。 该示例也优待某些用户。假 如 ident 等于 "Big Boss," ,或来自 192.168.4.0子网,请求就 直接通过。最后,我使用 301:窍门来让 squid 返回 HTTP重定向消息到客户端。注意,本程 序既非有效的,又非足够巧妙的,来正确拒绝坏请求。 Example 11-2. A slightly less simple redirector in Perl #!/usr/bin/perl -wl $|=1; # don't buffer the output $DENIED = "http://www.example.com/denied.html"; &load_word_list( ); while (<>) { unless (m,(\S+) (\S+)/(\S+) (\S+) (\S+),) { Squid 中文权威指南 198 $uri = ''; next; } $uri = $1; $ipaddr = $2; #$fqdn = $3; $ident = $4; #$method = $5; next if ($ident eq 'TheBoss'); next if ($ipaddr =~ /^192\.168\.4\./); $uri = "301:$DENIED" if &word_match($uri); } continue { print "$uri"; } sub load_word_list { @words = qw(sex drugs rock roll); } sub word_match { my $uri = shift; foreach $w (@words) { return 1 if ($uri =~ /$w/); } return 0; } Squid 中文权威指南 199 关于编写自己的重定向器的更多主意,我推荐阅读 11.5章里提到的重定向器的源代码。 11.311.311.311.3 重定 向器 池 重定向器可能经过任意长的时间才返回应答。 例 如, 它 可能要查询数据库, 搜 索正则 表 达式的长列表,或进行复杂的计算。 squid 使用重定向进程池以便它们能并行工作。当某个 重定向器忙时, squid 将请求递交给另一个。 对每个新请求, squid 按顺序检查重定向进程池。它将请求提交给第一个空闲进程。假 如请求率非常低,第一个重定向器也许自己能处理所有请求。 可以使用 redirect_children指令来控制重定向器池的 size。 默认 值 是 5个进程。注意squid 不会根据负载来动态的增或减进程池的 size。这 样,建议你适当的放宽 size 限制。假如所 有的重定向器忙碌, squid 会将请求排队。 假 如队列变得太大 ( 大于进程池 size 的2倍),squid 以致命 错误消息退出: FATAL: Too many queued redirector requests 在该情形下, 你 必须增加重定向器池的 size, 或 改变其他东西以让重定向器能更快的 处 理请求。你可以使用 cache管理器的 redirector 页面来发现是否有太少,或太多重定向器在 运行。例如: % squidclient mgr:redirector ... Redirector Statistics: program: /usr/local/squid/bin/myredir number running: 5 of 5 requests sent: 147 replies received: 142 queue length: 2 avg service time: 953.83 msec #FDPID# Requests Flags Time Offset Request Squid 中文权威指南 200 1 10 35200 46 AB 0.902 0 http://... 2 11 35201 29 AB 0.401 0 http://... 3 12 35202 25 AB 1.009 1 cache_o... 4 14 35203 25 AB 0.555 0 http://... 5 15 35204 21 AB 0.222 0 http://... 在该示例里, 假 如你见到最后一个重定向器的请求数量, 几 乎和倒数第二个一样多, 就 应该增加重定向器池的 size。 另一方面, 假如你见到许多重定向器没有请求, 就 该减少进 程 池的 size。 11.411.411.411.4 配置SquidSquidSquidSquid 下列 5个squid.conf 指令,控制 squid 里的重定向器的行为。 11.4.111.4.111.4.111.4.1 redirect_programredirect_programredirect_programredirect_program redirect_program 指令指定重定向程序的命令行。例如: redirect_program /usr/local/squid/bin/my_redirector -xyz 注意,重定向程序必须能被 squid 的用户 ID执行。假如因为某些理由, squid 不能执 行 重定向器,你将在 cache.log 里见到错误消息。例如: ipcCreate: /usr/local/squid/bin/my_redirector: (13) Permission denied 因为 squid 的工作方式,主 squid 进程可能不知道执行重定向程序的问题所在。 squid 不 会检测到错误,直到它试图写一个请求和读到一个响应。然后它打印: WARNING: redirector #1 (FD 6) exited 这样, 假 如你见到发送给 squid 的第一个请求的如此错误, 请 仔细检查 cache.log 的其 他 错误,并确保重定向程序可被 squid 执行。 11.4.211.4.211.4.211.4.2 redirect_childrenredirect_childrenredirect_childrenredirect_children redirect_children 指令指定 squid 应该开启多少重定向进程。例如: Squid 中文权威指南 201 redirect_children 20 当所有重定向器同时忙碌时, squid 会通过 cache.log 发出警告: WARNING:All redirector processes are busy. WARNING: 1 pending requests queued. 假如见到这样的警告,你应该增加子进程 的数量,并重启( 或 reconfigure)Squid。假 如队列的 size 变成重定向器数量的 2倍, squid 以致命错误退出。 不要试图将 redirect_children 设为 0来禁止 squid 使用重定向器。简单的 从 squid.conf 里 删除 redirect_program 行就可以了。 11.4.311.4.311.4.311.4.3 redirect_rewrites_host_headerredirect_rewrites_host_headerredirect_rewrites_host_headerredirect_rewrites_host_header 正常情况下, squid 在使用重定向器时,会更新请求的 Host 头部。也就是说,假如重 定向器返回的新 URI 里包含不同的主机名, squid 将新的主机名放 在Host 头部。假如使用 squid 作为代理人(surrogate,见15章),你也许想将redirect_rewrites_host_header 指令设为 off 来禁止这种行为: redirect_rewrites_host_header off 11.4.411.4.411.4.411.4.4 redirector_accessredirector_accessredirector_accessredirector_access 正常情况下, squid 将每个请求发送往重定向器。 然而, 可 以使用 redirector_access 规则 来有选择的发送某些请求。该语法与 http_access相同: redirector_access allow|deny [!]ACLname ... 例如: acl Foo src 192.168.1.0/24 acl All src 0/0 redirector_access deny Foo redirector_access allowAll 在该情形里,对任何匹配 Foo ACL 的请求, Squid 跳过重定向器。 11.4.511.4.511.4.511.4.5 redirector_bypassredirector_bypassredirector_bypassredirector_bypass Squid 中文权威指南 202 假如激活了 redirector_bypass 指令, squid 在所有重定向器忙碌时, 会 绕过它们。 正 常 情 况下, squid 将未处理请求排队,直到某个重定向进程可用。假如该队列增长得太大, squid 以致命错误退出。激活该指令确保 squid 永不会达到那种状态。 当然,折衷点是当负载高时,某些用户请求可能不会被重定向。假如这样对你没问题, 简单的激活该指令即可: redirector_bypass on 11.511.511.511.5 流行 的重 定向器 我已经提过,squid 的源代码未包含任何重定向器。 然 而, 通过 http://www.squid-cache.org 的Related Software页面的链接,可以找到许多有用的第三方重定向器。如下是一些流行的 重定向器: 11.5.111.5.111.5.111.5.1 SquirmSquirmSquirmSquirm http://squirm.foote.com.au/ Squirm 出自 Chris Foote 之手。它用 C编写,并在 GNU 公用许可证( GPL)下发布源 代码。 Squirm 的功能包括: • 1)非常快速,最少的内存使用 • 2)完全正则表达式匹配和替换 • 3)对不同的客户组应用不同的重定向列表 • 4)命令行的交互式模式的测试 • 5)防故障模式,假如配置文件包含错误,它不对请求作任何改变 • 6)将debug 信息,错误信息,和其他更多信息写往不同日志文件 11.5.211.5.211.5.211.5.2 JesredJesredJesredJesred http://www.linofee.org/~elkner/webtools/jesred/ Jesred 出自 Jens Elkner 之手。 它用 C编写, 基于 Squirm 而来, 也在 GNU GPL 下发行 。 其功能包括: Squid 中文权威指南 203 • 1)比Squirm 更快,但内存使用稍多 • 2)在运行时能重读配置文件 • 3)完全正则表达式匹配和替换 • 4)防故障模式,假如配置文件包含错误,它不对请求作任何改变 • 5)可选择的记录重写请求到日志文件 11.5.311.5.311.5.311.5.3 squidGuardsquidGuardsquidGuardsquidGuard http://www.squidguard.org/ squidGuard 出自 Tele Danmark InterNordia的Pal Baltzersen和Lars Erik Haland。它在GNU GPL 下发行。 作 者确保 squidGuard 在现代 Unix 系统上能轻松编译。 他 们的站点包含了许 多 好文档。如下是 squidGuard 的一些功能: • 1)高度可配置;你能在不同的时间,应用不同的规则到不同的客户组 • 2)URI 置换,而非仅仅替换 • 3)printf 形式的置换,允许递交参数给 CGI 脚本来定制消息 • 4)支持重定向器的 301/302/303/307 HTTP重定向状态码功能 • 5)可选择的重写规则日志记录 在squidGuard 的站点,还可以找到 超过 100,000个站点的黑名单,它 们以色情 ,暴力, 毒品,黑客,广告,和其他更多形式来分类。 11.5.411.5.411.5.411.5.4 AdZapperAdZapperAdZapperAdZapper http://www.adzapper.sourceforge.net AdZapper 是个流行的重 定向 器,因 其明 确的目 标是 从 HTML 页面里移除广 告。 它是 Cameron Simpson 所写的 Perl脚本。 AdZapper 能阻止横幅图 片, 弹出式 窗口 , flash 动画, 页面计数器,和 web bug。该脚本包含正则表达式列表, 用以匹配某些已知包含广告,弹 窗 等的 URI。Cameron 定期更新该脚本的模式匹配。你也能维护你自己的模式匹配列表。 Squid 中文权威指南 204 第第第第12121212章章章章验证 辅助 器 验证 辅助 器 验证 辅助 器 验证 辅助 器 先前我在 6.1.2.12章里谈起过代理验证。然而,我仅仅解释了如何编写用于代理验证的 访问控制规则。这里,我将告诉你如何选择和配置部分验证辅助器。 回想一下, Squid 支持三种方式用于从 用户端采 集验证 信用项: 基本,摘 要 (Digest), 和NTLM。这些方式指定 squid 如何从客户端接受用户名和 密码。从安全观点看,基本验 证非常脆弱。 摘要和 NTML 验证显然更强壮。 对每种方式, squid 提供一些验证模块, 或 辅 助进程,用于实际处理认证的过程。 我提 到的所有验证辅助器都包含在squid 的源 代码发布里。你可以在编译时使 用./configure 选项来指定它们的目录名。例如: % ls helpers/basic_auth LDAPNCSA getpwnam MSNTPAM multi-domain-NTLM Makefile SASL winbind Makefile.am SMB Makefile.in YP %./configure --enable-basic-auth-helpers=LDAP,NCSA ... 辅助器程序正常安装在 $prefix/libexec 目录。 如同重定向器一样, squid 使用一个验证辅助器进程池。 某 个验证请求会被送往第一 个 空闲辅助器。 当 所有验证器进程都忙时, squid 将未处理请求放进队 列。 假 如队列变得太 大, squid 会以致命错误消息退出。 大部分情况下, squid 缓存验证结果。 这样就减少了辅助器 进 程的负载,并改进了响应时间。 12.112.112.112.1 配置SquidSquidSquidSquid auth_param 指令控制了配置 squid 的验证辅助器的每个方面。 不 同的方式 ( 基本, 摘 要, NTLM) 有 一些共性, 也 有一些唯一的参数。 紧 跟在 auth_param 后的第一个参数必须是 basic, digest, 或ntlm 之一。我将在随后章节里,详细讲解每种验证机制的配置细节。 除了 auth_param 外, squid 还有 2个指令影响到 代理 验证。 可以 使 用 max_user_ip ACL Squid 中文权威指南 205 来阻止用户与其他人 共享用户 名和密 码。假 如 squid 检测到相同的用户名 来自太多 不 同 IP 地址,该 ACL 被匹配,就可以拒绝这样的请求。例如: acl FOO max_user_ip 2 acl BAR proxy_auth REQUIRED http_access deny FOO http_access allow BAR 在该情形中,假如用户 从 3个或更多的不 同 IP地址提交请求, squid 就拒绝该请求。 authenticate_ip_ttl 指令控制 squid 记住每个用 户的源 IP地址多长时间。 对于经常改变 IP地 址的用户, 更小的 TTL可能好点。 在一个用户的 IP地址很长时间不变的环境里, 可以使 用 较大的 TTL。 12.212.212.212.2 HTTP HTTP HTTP HTTP 基本 验证 基本验证最简单, 然 而最不安全。 它 本质上以明文来传送用户密码, 尽 管密码被编码 成 可打印字符。 例 如, 假 如用户敲入其用户名 Fannie 和密码 FuRpAnTsClUb, 用 户代理首先 将 这2者结合到一个单一串里,以冒号来分割用户名和密码: Fannie:FuRpAnTsClUb 然后它用 base64方法(定义在 RFC 2045)来编码这个串。它在 HTTP 头部里看起来如 此: Authorization: Basic RmFubmllOkZ1UnBBblRzQ2x VYgo= 若有人碰巧捕获到用户的 HTTP请求,他能轻易获取到用户名和密码: % echo RmFubmllOkZ1UnBBblRzQ2x VYgo= | /usr/local/lib/python1.5/base64.py -d Fannie:FuRpAnTsClUb 遵循 HTTP/1.1 RFC 的要求, squid 不会转发验证信用项到其他服务器。 换 句话说, 假 如 信用项是用于访问 squid 的, Authorization 头部会从外出请求里移除。 你会注意到, 某 些基本验证器可被配置来检查系统密码文件。 因 为基本信用项不被加 密, 所以在 cache访问密码里包含登陆密码是个坏想法。假如选择使用 getpwnam 验证器,你应 该完全理解让用户密码以明文在网络中传送的意义。 Squid 中文权威指南 206 HTTP基本验证支持下列 auth_param 参数: auth_param basicprogram command auth_param basicchildren number auth_param basicrealm string auth_param basiccredentialsttl time-specification program 参数指定验证辅助程序的命令及其参数。 大多数情况下,这里是到某个验证 辅 助程序的路径名。它们默认安装在 /usr/local/squid/libexec 下。 children 参数告诉 squid 使用多少辅助器进程。 默认值是 5, 假如你不了解需要多少进 程 来处理请求,这个值就是个好起点。假如指定得太少, squid 会在 cache.log 里告警。 realm 参数是在提示输入用户名和密码时,用户代理显示给用户看的验证域字符串。可 以使用一些简单的句子,例如 “访问 squid 的缓存代理 ”。 credentialsttl 参数指定 squid 内在的缓存验证结果的时间数量。较大的值减少了外部验 证器进程的负载,但加长了刷新期,直 到 squid 检测到验证数据库的改变。注意, 这仅影 响到积极结果(例如成功的验证) , 消极的结果不会被 squid 缓存。默认的 TTL值是 2小时。 如下是个完整的示例: auth_param basicprogram /usr/local/squid/libexec/pam_auth auth_param basicchildren 10 auth_param basicrealm My Awesome Squid Cache auth_param basiccredentialsttl 1 hour acl KnownUsers proxy_auth REQUIRED http_access allow KnownUsers 下面我将讨论 squid 自带的基本验证辅助器程序。 12.2.112.2.112.2.112.2.1 NCSANCSANCSANCSA ./configure —enable-basic-auth-helpers=NCSA NCSA 验证辅助器相对流行, 这 归咎于它的简单性和历史原因。 它 将用户名和密码存 储 Squid 中文权威指南 207 在一个单独的文本文件里,类似于 Unix 的/etc/passwd 文件。这个密码文件格式最初是作为 NCSAHTTP服务器项目的一部分发展而来的。在 squid.conf 里,只须指定密码文件的路径 作为程序的单一命令行参数。 auth_param basicprogram /usr/local/squid/libexec/ncsa_auth /usr/local/squid/etc/passwd 可以使用Apache 自带的htpasswd 程序来创建和更新密码文件。也可以在 http://www.squid-cache.org/htpasswd/ 这里下载。在 该页 面里, 你也 可以下 载 chpasswd CGI 脚本,它允许用户改变自己的密码(假如必要) 。 12.2.212.2.212.2.212.2.2 LDAPLDAPLDAPLDAP ./configure —enable-basic-auth-helpers=LDAP LDAP 辅助器是到轻量级目 录访问协 议 (LDAP)服务器的接口。在编 译 squid_ldap_auth 辅助器 之前 , OpenLDAP 库和头 文件 必 须安 装 到系 统 中。 可 以在 这 里找 到 OpenLDAP: http://www.openldap.org/. squid_ldap_auth 程序至少需要 2个参数: 基 本开放名 (DN)和LDAP 服务器主机名。 例 如: auth_param basicprogram /usr/local/squid/libexec/squid_ldap_auth -b "ou=people,dc=example,dc=com" ldap.example.com LDAP 辅助器有 Unix的man 页,描述了其所有选项和参数。 然而,在运行 make install 时, 通 常并未安装 squid 的这个 man 页。 进 入源代码树, 手 工运行 nroff, 你 可以读到这个 man 页。例如: % cd helpers/basic_auth/LDAP % nroff -man squid_ldap_auth.8 | less 12.2.312.2.312.2.312.2.3 MSNTMSNTMSNTMSNT ./configure —enable-basic-auth-helpers=MSNT MSNT 验证器是通过服务消息块 (SMB)协议到 Microsoft NT 域数据库的接口。 它 使用 一 个小配置文件,叫做 msntauth.conf,它必须放在 $prefix/etc 或--sysconfidr 目录。在该配置 文 件里,最多可以指定 5个NT 域控制器。例如: server pdc1_host bdc1_host my_nt_domain Squid 中文权威指南 208 server pdc2_host bdc2_host another_nt_domain 默认情况下, MSNT 验证器允许服务器验证任何用户。然而,它也能允许或拒绝指定 用户名。 假如创建一个 allowusers文件, 仅仅在该文件里列出的用户 可允许访问 squid。假 如你的 NT 服务器上有很多用户, 但 仅仅允许少数用户使用 cache, 那 就可以用到这个功能 。 另外, 可以创建一个 denyusers文件。 任何列举在该文件里的用户会被拒绝访问, 这点甚 至 发生在检查 allowusers文件之前。 可选择的,还可以把用户名放 在 proxy_auth ACL 里,从而允许或拒绝指定用户名,请 见6.1.2.12章的描述。 附加的文档,请见 helpers/basic_auth/MSNT 目录下的 README.html 文件。 12.2.412.2.412.2.412.2.4 Multi-domain-NTLMMulti-domain-NTLMMulti-domain-NTLMMulti-domain-NTLM ./configure —enable-basic-auth-helpers=multi-domain-NTLM multi-domain-NTLM 验证器类似于 MSNT, 两者都会查询 Windows NT 域数据库。 不 同 于MSNT 最多查询 5个域控制器,multi-domain-NTLM验证器要求用户在其用户名前插入 NT 域名,象这样: ntdomain\username multi- domain-NTLM 辅助 器程序是个相对较短的perl 脚本 。 它 依 赖 于 CPAN 的 Authen::SMB 包。 假如你没有在 perl 脚本里硬编码域控制器 的主机名, 它会利用 Samba 包 里的 nmblookup 程序来自动查找它们。 perl 脚本命名为 smb_auth.pl, 它在 squid.conf 里看 起 来如下: auth_param basicprogram /usr/local/squid/libexec/smb_auth.pl multi-domain-NTLM 的文档很少, 但 假如你熟悉 perl, 通 过阅读源代码就可以了解更 多。 12.2.512.2.512.2.512.2.5 PAMPAMPAMPAM ./configure —enable-basic-auth-helpers=PAM 感觉上, 插 件式验证模块 (PAM)是在验证方式 ( 例如一次性密码, kerberos, smart cards ) 和要求验证服务的应用 (例如 ssh,ftp,imap) 之间的胶合剂。 系 统的 /etc/pam.conf 文件描述 了 对每种应用使用何种验证方式。 为了使用 squid 的PAM 验证辅助器, 你 必须将 "squid"作为一个服务增加到 /etc/pam.conf 文件,并且指定使用哪个 PAM 模块。例如,为了使用 FreeBSD 的Unix 密码文件,必须将 Squid 中文权威指南 209 这个放在 pam.conf 里: squid auth required pam_unix.so try_first_pass 为了检查 Unix 密码数据库, pam_auth 进程必须以 root 运行。 这是个安全风险, 你必 须 手工设置可执行 setuid root。假如 pam_auth 不以 root 运行,并且它被配置为检查 Unix密码 数据库,那么每个验证请求都会失败。 PAM 验证器的文档以 man 页形式提供,可在 helpers/basic_auth/PAM 目录下找到。 12.2.612.2.612.2.612.2.6 SASLSASLSASLSASL ./configure —enable-basic-auth-helpers=SASL 简单验证和安全层 (SASL)是个 IETF提议标准,文档在 RFC 2222里。它是个为面向连 接的协议 ( 例如 FTP,SMTP,HTTP) 提供 安 全 参 数 协 商 的 协 议 。 然而 , SASL验证器类似于 PAM 验证器。它使用第三方库接口,查询许多不同的验证数据库。 特别的, squid 的SASL验证器要 求 Cyrus SASL库,它 由 Carnegie Mellon 大学开发。 可在这里找到: http://asg.web.cmu.edu/sasl/. 可以配置 SASL验证器来检查传统密码文件, PAM 系统, 或 任何其他被 CMU 的库支 持 的数据库。更多信息,请见 helpers/basic_auth/SASL 目录的 README 文件。 12.2.712.2.712.2.712.2.7 SMBSMBSMBSMB ./configure —enable-basic-auth-helpers=SMB SMB 是另一个对 Microsoft Windows 数据库的验证器。 该 验证器自身是一个 C程序。 该 程序在每次与 Windows域控制器会话时, 执 行一个 shell 脚本。这个shell脚本包含来自 Samba 包的命令。这样,在使用 SMB 验证器之前,你必须安装 Samba。 SMB 验证器程序, smb_auth 取Windows 域名作为参数。例如: auth_param basicprogram /usr/local/squid/libexec/smb_auth -WMYNTDOMAIN 通过重复 -W选项,可以列举多个域。完全的文档,请见: http://www.hacom.nl/~richard/software/smb_auth.html 12.2.812.2.812.2.812.2.8 YPYPYPYP Squid 中文权威指南 210 ./configure —enable-basic-auth-helpers=YP YP 验证器检查系统的 "Yellow Pages"(例如 NIS)目录。为了在 squid 里使用它,必须 在验证器命令行里提供 NIS 域名和密码数据库的名字,通常是 passwd.byname: auth_param basicprogram /usr/local/squid/libexec/yp_auth my.nis.domain passwd.byname yp_auth 程序相对简单,但没有任何文档。 12.2.912.2.912.2.912.2.9 getpwnamgetpwnamgetpwnamgetpwnam ./configure —enable-basic-auth-helpers=getpwnam 该验证器是个简单的到 getpwnam()函数的接口,该函数在 Unix 系统的 C库里。对给 定的用户名, getpwnam()函数查询系统的密码文件。假如 使用 YP/NIS,getpwnam()也检 查 那些数据库。 在 某些操作系统上, 它 也利用 PAM 系统。 假 如你的 cache用户在 squid 运行 的 系统上也有 登陆帐号, 就 可使用该验证器。 另 外, 可 在密码文件里对 cache用户建立 nologin 帐号。 12.2.1012.2.1012.2.1012.2.10 winbindwinbindwinbindwinbind ./configure —enable-basic-auth-helpers=winbind Winbind 是Samba 套件的功能之一。它允许 Unix 系统利用 Windows NT 的用户帐号信 息。 winbind 验证器是 Samba winbindd 服务进程的客户端。 在使用该验证器之前, 必须安 装 Samba 和运行 winbindd 服务。 winbind 基本验证器的名字是 wb_basic_auth。它在 squid.conf 里看起来如下: auth_param basicprogram /usr/local/squid/libexec/wb_basic_auth 12.2.1112.2.1112.2.1112.2.11 基本验 证 APIAPIAPIAPI 在squid 和基本验证器 之间 的接口 非常 简单。 squid 发送用户名和 密码 到验证 器进 程, 它们以空格分开并以新行结 束。验证器 在 其 stdin 里读取用户名和密码。在检 查信用项后, 验证器将 OK 或ERR 写入 stdout。 任何 “不安全的 URL”字符会参照 RFC 1738规则进行编码。这样,名字 "jack+jill"变成 了"jack%2bjill" 。squid 接受包含空格的用户名和密码。例如"a password" 变成了 "a%20password"。在解码用户名和密码后,验证器程序能处理空格和其他的特殊字符。 可在命令行上轻易测试基本验证器。 简 单的在终端窗口里运行验证器程序, 并 输入用 户 Squid 中文权威指南 211 名和密码。或者,可以这样做: % echo "bueller pencil" | ./ncsa_auth /tmp/passwd OK 如下是个用 perl 写成的简单的验证器模板: #!/usr/bin/perl -wl use URI::Escape; $|=1; # don't buffer stdout while (<>) { ($u,$p) = split; $u = uri_unescape($u); $p = uri_unescape($p); if (&valid($u,$p)) { print "OK"; } else { print "ERR"; } } sub valid { my $user = shift; my $pass = shift; ... } Squid 中文权威指南 212 12.312.312.312.3 HTTP HTTP HTTP HTTP 摘要 验证 摘要验证被设计为比基本验证更安全。它广泛利用了加 密 hash 函数和其他技巧。本质 上, 与 发送明文密码不同, 用 户代理发送密码、 用 户名和其他信息的 "消息摘要 "(见 RFC 2617 和O'Reilly's HTTP: The Definitive Guide 的更多信息)。 HTTP摘要验证支持下列 auth_param 参数: auth_param digest program command auth_param digest children number auth_param digest realm string auth_param digest nonce_garbage_interval time-specification auth_param digest nonce_max_duration time-specification auth_param digest nonce_max_count number auth_param digest nonce_strictness on|off program, children, 和realm 参数与基本验证的一样。 与摘要验证相关的唯一不同参数 是 nonce。 nonce是个特殊的数据串, 它偶尔改变。 在 验证过程中, 服务器 ( 这里就是 squid)提供 一个 nonce值到客户端。 客户端在产生摘要时要用到这个 nonce值。 没有 nonce数据,攻 击 者能简单的拦截和重现 (replay)摘要值来获取对 squid 的访问。 nonce_garbage_interval 参数告诉 squid 每隔多久清空 nonce缓存。 默 认值是每 5分钟。 对 于有许多摘要验证客户端的非常忙的 cache,更频繁的回收 nonce碎片可能有益。 nonce_max_duration 参数指定每个 nonce值保持多长时间的有效期。 当 客户端试图使 用 某个已过期的 nonce值时, squid 产生 401(未验证)响应,并随之发送一个新的 nonce值, 以便客户端能重新认证。默认值是 30分钟。注意任何被截获的 Authorization 头部能被用于 replay 攻击, 直到 nonce值过 期。 然而将 nonce_max_duration 值设得过低, 导致 squid 过频 繁的产生 401响应。对每个 401响应,客户端和服务器要重新协商它们的 验证信用项,这本 质上浪费了用户的时 间。 nonce_max_count 参数对 nonce值可使用多少次设置一个上限。在指定数量的请求后, squid 返回 401(未验证)响应和一个新的 nonce值。默认是 50个请求。 nonce 计数是另一个设计成阻止 replay 攻击的功能。 squid 在401响应里发送 qop=auth。 Squid 中文权威指南 213 这导致用户代理在它们的响应里包含 nonce计数,并在 产生摘要自身时使用这个 nonce计 数。 nonce计数值必须逐次增加。下降的 nonce计数意味着 replay 攻击。然而,计数可能跳 跃的增加,跨 过某 些数值,例如 : 5,6,8,9。nonce_strictness 参数决定在这 种情 形 下 squid 如何做。若设置为 on,假如某个 nonce计数不等于前次 nonce计数加 1,squid 会返回 401响 应。若设置为 off,squid 允许不连续的 nonce计数值。 如下是个完整示例: auth_param digest program /usr/local/squid/libexec/digest_pw auth_param digest children 8 auth_param digest realm Access to Squid auth_param digest nonce_garbage_interval 10 minutes auth_param digest nonce_max_duration 45 minutes auth_param digest nonce_max_count 100 auth_param digest nonce_strictness on acl KnownUsers proxy_auth REQUIRED http_access allow KnownUsers 下面我将讨论 squid 自带的摘要验证辅助器程序。 12.3.112.3.112.3.112.3.1 passwordpasswordpasswordpassword ./configure —enable-auth=digest —enable-digest-auth-helpers=password 这是 squid 摘要验证的简单可参考执行的方法。 它 展示了如何编写基于摘要验证的辅 助 器。这个代码简单的从明文文件里读取用户名和密码。该文件的格式类似如下: username:password 密码文件的路径是 digest_pw_auth 程序的单一参数,例如: auth_param digest program /usr/local/squid/libexec/digest_pw_auth Squid 中文权威指南 214 /usr/local/squid/etc/digest_passwd auth_param digest realm Some Nifty Realm squid 不提供任何工具来维护这种格式的密码文件。假如你选择使用摘要验证,就必须 管理自己的密码文件,可使用文本编辑器或 perl 脚本来做到。 12.3.212.3.212.3.212.3.2 摘要验 证 APIAPIAPIAPI 假如要编写自己的摘要验证辅助器, 你必须理解在 squid 和辅助器进程间的通信。 数 据 交换类似于基本验证,但稍微复杂点。 第一个不同是 squid 将用户名和域值, 而不是用户名和密码,写往辅助器进程。 这些 串 被引用起来,并以冒号分隔。例如: "bobby":"Tom Landry Middle School" 第二个不同是 假如 用户名 有效 ,辅助 器进 程返回 一 个 MD5摘要串,而不 是返 回 OK。 与基本验证一样, 假 如用户不存在, 或 者来自 squid 的输入不可解析, 辅 助器进程返回 ERR。 辅助器随着用户名, 域 值和密码返回一个 MD5摘要。这3个串连在一起, 并 以冒号分 割: username:realm:password 记住密码不会在 HTTP 请求里发送。辅助器从数据库里(类似于 password 辅助器使用 的明文文件)获取用户的密码。例如,假 设 Bobby 的密码是 CapeRs。辅助器从 squid 接受 用户名和域值,从它的数据库里获取密码,并计算这个串的 MD5校验和: bobby:Tom Landry Middle School:CapeRs Squid 的源代码包含一个库函数叫做 DigestCalcHA1( ), 它用来执行这个计算。 我 们可 以 在终端窗口里来测试这些,并观察辅助器返回什么: % echo 'bobby:CapeRs' > /tmp/pw % echo bogus_input | digest_pw_auth /tmp/pw ERR % echo "nouser":"some realm" | digest_pw_auth /tmp/pw Squid 中文权威指南 215 ERR % echo '"bobby":"Tom Landry Middle School"' | digest_pw_auth /tmp/pw c7ca3efda238c65b2d48684a51baa90e Squid 存储这个 MD5校验和,并将其用于摘要验证算法的其他 部分。注意这个校 验和 仅在用户改变其 密码时 才会改 变。 在 squid 的当前摘要执行 里,只 要用户 保持活 跃状态, 这些校验和就保存在内存里。 假 如用户不活跃的时间达到 authenticate_ttl 秒, MD5校验和 可 能从 squid 的内存里移除。若该用户 下次请求, squid 会要求外部辅助器进程重新计算校 验 和。 12.412.412.412.4 MicrosoftMicrosoftMicrosoftMicrosoft NTLM NTLM NTLM NTLM 验证 NTLM 是Microsoft 的私有连接验证协议。许多组织,包 括 squid 的开发者,通过少许 可用信息 以及 检查 网络 传输 ,已 经 反向 工程 了该 协议 。可 以在 这里 找 到一 些技 术细 节: http://www.innovation.ch/java/ntlm.html. NTLM 使用三次握手来验证一个连接。首先,客 户端发送请求,它 带一对标识符。接 着, 服务器发送回一个挑战消息 ( 译者注: 即用于加密的随机种子) 。 第 三 步, 客户端再 次 发送其请求, 包 含了对这个种子的响应。 这时, 连 接验证成功, 在同一连接里的任何进一 步 的请求, 不再需要挑战 /响应信息。 假如关闭了连接, 客 户端和服务器必须重复整个三次 握 手过程。持续连接有助于减少 NTLM 验证的负载。 NTLM 使用加密的 hash 函数和 nonce值, 类似于摘要验证,尽管专家认为 NTLM 要脆 弱一些。 NTLM 验证支持下列 auth_param 参数: auth_param ntlm program command auth_param ntlm children number auth_param ntlm max_challenge_reuses number auth_param ntlm max_challenge_lifetime time-specification program 和children 参数与基本验证和摘要验证 的相同。剩 余的参数决 定 squid 每隔多 久重用某个挑战令牌。 max_challenge_reuses 参数指定某个挑战令牌可被重用多少次。 默 认值是 0, 所 以这个 令 Squid 中文权威指南 216 牌永不会被重用。 增 加该值可以减少 squid 和NTLM 辅助器进程的计算负载, 但 带来了弱 化 协议安全的风险。 类似的,max_challenge_lifetime 参数对令牌重用设置了一个时间限制,即使 max_challenge_reuses 次数还没有用完。默认值是 60秒。 如下是个完整示例: auth_param ntlm program /usr/local/squid/libexec/ntlm_auth foo\bar auth_param ntlm children 12 auth_param ntlm max_challenge_reuses 5 auth_param ntlm max_challenge_lifetime 2 minutes acl KnownUsers proxy_auth REQUIRED http_access allow KnownUsers Squid 自带了下列 NTLM 验证辅助器程序: 12.4.112.4.112.4.112.4.1 SMBSMBSMBSMB ./configure —enable-auth=ntlm —enable-ntlm-auth-helpers=SMB NTLM 的服务消息块 (SMB)验证器与基本验证的相似。 用 户简单的提供他们的 windows NT 域名,用户名和密码即可。该验证器能在多个域控制器间负载均衡。域和控制器名字 出 现在命令行中: auth_param ntlm program /usr/local/squid/libexec/ntlm_auth domain\controller [domain\controller ...] 12.4.212.4.212.4.212.4.2 winbindwinbindwinbindwinbind ./configure —enable-auth=ntlm —enable-ntlm-auth-helpers=winbind 该验证器类似于基本验证的 winbind。两者都要求安装和运行了 Samba winbindd 服务。 NTLM 的winbind 验证器名字是 wb_nltm_auth。它在 squid.conf 里的配置看起来如下: auth_param basicprogram /usr/local/squid/libexec/wb_ntlm_auth Squid 中文权威指南 217 12.4.312.4.312.4.312.4.3 NTLM NTLM NTLM NTLM 验证APIAPIAPIAPI 在squid 和NTLM 验证器之间的通信相对于基本和摘要验证而言, 要 复杂得多。 理 由 之 一是每个辅助器进程实际创建了它自己的 挑战令牌。这样, 辅助器变得与状 态相关, squid 必须记住哪个连接属于哪个辅助器。 Squid 和辅助器进程使用一些 2字符的代码来指示它们正在发送什么。这些代码如下: YR 在squid 需要新的挑战令牌时, 它发送这个给辅助器。 这总是在两个进程间的第一个 通 信。它也可能在squid 需要新挑战令牌的任何时候发生,归咎于auth_param max_challenge_lifetime 和max_challenge_uses 参数的设置。辅助器响应一个 TT消息。 TT 挑战令牌 辅助器发回这个消息给 squid,包含了一个挑战令牌。它是对 YR 请求的响应。挑战令 牌用 base64编码,在 RFC 2045里有定义。 KK 信用项 当squid 想要验证某个用户的信用项时, 它发送这个到辅助器。 辅助器响应如下几个 代 码: AF,NA,BH, 或LD。 AF 用户名 当用户的验证信用项有效时,辅助器发回这个消息给 squid。辅助器在本消息里发送用 户名,是因为 squid 不去尝试解码 NTLM 验证头部。 NA 理由 当用户的信用项无效时, 辅 助器发回这个消息给 squid。 它 也包含了一个 “理由 ”字符串 , squid 能将其显示到错误页面。 BH 理由 当验证过程失败时,辅助器发回这个消息给 squid。这点可能发生在,例如,辅助器进 程无法与 windows NT 域控制器通信的时候。 squid 拒绝用户请求。 LD 用户名 这个辅助器到 squid 的响应类似于 BH,除了 squid 允许用户请求之外。类似于 AF,它 返回用户名。为了使用该功能,必须在编译 squid 时使用 —enable-ntlm-fail-open 选项。 Squid 中文权威指南 218 既然该协 议相 对复 杂, 你最 好从 包 含 在 squid 源代码发 布里 的 2个基本验 证器 起步。 no_check 辅助器用 perl 写的, fakeauth 用C写的。可以在 helpers/ntlm_auth 目录找到它们。 12.512.512.512.5 外部ACLACLACLACL 在版本 2.5,Squid 包含了一个新功能,叫做外 部 ACL。这些 ACL 元素在外部辅助器 进程里被执行。你指 示 squid 将某些信息写往辅助 器,然后 辅助器 以OK 或ERR 来响应 squid。 请参考 6.1.3章关于 external_acl_type 语法的描述。 这里, 我仅仅讨论一些特殊的外 部 ACL 辅助器程 序,它们随着 squid 的源代码发布。 12.5.112.5.112.5.112.5.1 ip_userip_userip_userip_user ./configure —enable-external-acl-helpers=ip_user 该辅助器读取用户名和客户端 IP地址作为输入。 它 根据配置文件来检查这 2个值, 以 决 定其是否有效。为了使用这个 ACL 辅助器,要在 squid.conf 里增加如下行: external_acl_type ip_user_helper %SRC%LOGIN /usr/local/squid/libexec/ip_user -f /usr/local/squid/etc/ip_user.conf acl AclName external ip_user_helper 对每个请求, %SRC 替换成客户端的 IP地址, %LOGIN 替换成用户名。 ip_user.conf 配 置文件有如下格式: ip_addr[/mask] user|@group|ALL|NONE 例如: 127.0.0.1 ALL 192.168.1.0/24 bob 10.8.1.0/24 @lusers 172.16.0.0/16 NONE 该配置文件导致 ip_user 对任何来自 127.0.0.1的请求返回 OK,对来自 192.168.1.0/24网 络的 Bob 的请求返回 OK,对来自10.8.1.0/24网络的, 位于 luser 组里的任何用户名返回 OK。 对来自 172.16.0.0/16网络的任何请求返回 ERR。它也对任何不在这 个列表里出现的地址和 用户名对返回 ERR。 Squid 中文权威指南 219 12.5.212.5.212.5.212.5.2 ldap_groupldap_groupldap_groupldap_group ./configure —enable-external-acl-helpers=ldap_group 该辅助器决定是否某个用户属于一个特殊的 LDAP 组。在 acl 行里指定 LDAP 组名。 它 可能在你的配置文件里看起来如下: external_acl_type ldap_group_helper %LOGIN/usr/local/squid/libexec/squid_ldap_group -b "ou=people,dc=example,dc=com" ldap.example.com acl AclName external ldap_group_helper GroupRDN ... 注意 为 了 编 译 squid_ldap_group 辅助 器程序,你必须在系统中安装OpenLDAP 库 (http://www.openldap.org )。 12.5.312.5.312.5.312.5.3 unix_groupunix_groupunix_groupunix_group ./configure —enable-external-acl-helpers=unix_group 该辅助器在 Unix 组数据库 (例如 /etc/group 文件) 里查找用户名。 在辅助器的命令行 指 定要检查的组: external_acl_type unix_group_helper %LOGIN /usr/local/squid/libexec/check_group -g group1 -g group2 ... acl AclName external unix_group_helper 另外,可在 acl 行指定组。这样就允许对不同的组使用相同的辅助器: external_acl_type unix_group_helper %LOGIN/usr/local/squid/libexec/check_group acl AclName1 external unix_group_helper group1 ... acl AclName2 external unix_group_helper group2 ... 12.5.412.5.412.5.412.5.4 wbinfo_groupwbinfo_groupwbinfo_groupwbinfo_group ./configure —enable-external-acl-helpers=wbinfo_group 该辅助器是个简短的 perl 脚本, 它利用了 Samba 包的 wbinfo 程序。 wbinfo 是winbindd 服务的客户端。对每个请求,该脚本期待一个单一的 Unix 组名跟随在用户名后。这样,必 Squid 中文权威指南 220 须在 acl 行里放置组名: external_acl_type wbinfo_group_helper %LOGIN/usr/local/squid/libexec/wbinfo_group.pl acl AclName external wbinfo_group_helper group 12.5.512.5.512.5.512.5.5 winbind_groupwinbind_groupwinbind_groupwinbind_group ./configure —enable-external-acl-helpers=winbind_group 该辅助器 用 C写成,也要 求 winbindd 服务提供 的 windows NT 用户名的组 成员 关系。 它基于基本验证和 NTLM 验证的 winbind 辅助器。可在 acl 命令行指定多个组名: external_acl_type winbind_group_helper %LOGIN/usr/local/squid/libexec/wb_check_group acl AclName external winbind_group_helper group1 group2 ... 12.5.612.5.612.5.612.5.6 编写自己的外 部 ACL ACL ACL ACL 辅助器 外部ACL 接口提供了许多兼容性, 可 以用它来执行几乎任何不被 squid 内在支持的 访 问控制检测。编写外部 ACL 分2步走。首先,你必须决定辅助器程序需要 对什么样的请求 信息来作出决定。在 external_acl_type 行上放置相应的关键字,紧跟着辅助器程 序的路径。 例如,假如你想编写一个外部 ACL 辅助器,它使用了客户端 IP地址,用户名,和 Host 头 部的值,那就可这样写: external_acl_type MyAclHelper %SRC%LOGIN%{Host} /usr/local/squid/libexec/myaclhelper 第2步是编写 myaclhelper 程序。它必须 在 stdin 里读取请求元素,作 出它自己 的决定, 然后将 OK 或ERR 写往 stdout。继续以前的示例,该 perl 脚本描述了如何去做: #!/usr/bin/perl -wl require 'shellwords.pl'; $|=1; while (<>) { ($ip,$name,$host) = &shellwords; Squid 中文权威指南 221 if (&valid($ip,$name,$host)) { print "OK"; } else { print "ERR"; } } sub valid { my $ip = shift; my $name = shift; my $host = shift; ... } 参考 6.1.3章关于从 squid 传递到辅助器的元素列表( %SRC,%LOGIN 等 ) 。注 意 当 某 个 元素包 含 空格 时 , squid 会在双 引 号里 封 装 它。 如 同 示例 显 示的 那 样 ,可 以 使 用 perl 的 shellwords 库来解析被双引号封装的元素。 当然, 为了利用外部 ACL, 你必须在某个 acl 行里引入它。 无论何时, 若 外部辅助器 返 回OK,则 ACL 元素匹配成功。 外部 ACL 辅助器接口允许从辅助器提交附加的信息到 squid(在 OK/ERR 行 ) 。这 些 以 keyword=value 对的形式出现。例如: OK user=hank 当前 squid 了解的 唯 一 关 键字 是 error 和user。假如 设 置 了 user 值, squid 将它用 于 access.log。squid 当前没有用到 error 值。 Squid 中文权威指南 222 第第第第13131313章章章章日志 文件 日志 文件 日志 文件 日志 文件 13.113.113.113.1 cache.logcache.logcache.logcache.log cache.log 包含多种消息,例如 Squid 的配置信息、性能警告、以及严重错误。 如下 是 cache.log 的输出样本: 2003/09/29 12:09:45| Starting Squid Cache version 2.5.STABLE4 for i386- unknown-freebsd4.8... 2003/09/29 12:09:45| Process ID 18990 2003/09/29 12:09:45| With 1064 file descriptors available 2003/09/29 12:09:45| Performing DNS Tests... 2003/09/29 12:09:45| Successful DNS name lookup tests... 2003/09/29 12:09:45| DNS Socket created at 0.0.0.0, port 1154, FD 5 2003/09/29 12:09:45| Adding nameserver 24.221.192.5 from /etc/resolv.conf 2003/09/29 12:09:45| Adding nameserver 24.221.208.5 from /etc/resolv.conf 2003/09/29 12:09:45| helperOpenServers: Starting 5 'redirector.pl' processes 2003/09/29 12:09:45| Unlinkd pipe opened on FD 15 2003/09/29 12:09:45| Swap maxSize 10240 KB, estimated 787 objects 2003/09/29 12:09:45| Target number of buckets: 39 2003/09/29 12:09:45| Using 8192 Store buckets 2003/09/29 12:09:45| Max Mem size: 8192 KB Squid 中文权威指南 223 2003/09/29 12:09:45| Max Swap size: 10240 KB 2003/09/29 12:09:45| Rebuilding storage in /usr/local/squid/var/cache (CLEAN) 2003/09/29 12:09:45| Using Least Load store dir selection 2003/09/29 12:09:45| Set Current Directory to /usr/local/squid/var/cache 2003/09/29 12:09:45| Loaded Icons. 2003/09/29 12:09:45| Accepting HTTP connections at 0.0.0.0, port 3128, FD 16. 2003/09/29 12:09:45| Accepting ICP messages at 0.0.0.0, port 3130, FD 17. 2003/09/29 12:09:45| WCCP Disabled. 2003/09/29 12:09:45| Ready to serve requests. 每个cache.log 条目以时间戳开始,指示消息何时产生。 本示例里的日志报 告 了 squid 的版本 ( 2.5.STABLE4) ,以 及 squid 所运行的操 作系统标识符 ( i386-unknown-freebsd4.8)。 接下来 是 进 程 ID(18990) 。许多 cache.log 条目看 起 来含 义 不 明( 例 如 Target number of buckets: 39) 。 大 多数正常情形下, 可以忽略这些不易理解的条目。 另 一方面, 你 也许该仔 细 看一下本质的配置细节,例如名字服务器的地址,或 HTTP服务器地址。本 示例日志最后 陈述了 Squid 准备接受请求。此时 Squid 可以接受来自客户端的 HTTP连接。 通常, cache.log 增长缓慢。 然而, 不正常的 HTTP事务或类似的事件可以导致 squid 发 布一个 debug 消息。假如这样的事件经常发生(例如 DOS 攻击、新的病毒、磁盘意外等), 日志文件会增长很快。定期轮转日志减少了用光磁盘的风险。 主要的错误和异常条件最可能报告在 cache.log 里。我推荐存档这些日志,以便以后回 查事件的源头。 当在 Squid 的邮件列表或类似论坛描述这些故障 时, 相应的 cache.log 非常 有用。 某 些情形下, 你 也许应该调大日志的 debug 级别, 以 便其他人能更好的理解和修正 你 的问题。 13.1.113.1.113.1.113.1.1 debug debug debug debug 级别 debug_options 指令控制 cache.log 的日志级别。默认值( ALL,1)通常是最佳选择。在 更高级别上, 不重要的消息会混淆视线。请参考 16.2节关于 debug_options 指令的完整描述 。 请注意最高级别的 debug(9或10)会对每个请求产生数千行日志,快速消 耗磁盘空间 和显著影响 squid 的性能。 可以使用 squid 的-X命令行选项来对所有情形激活完整的 debug。假如squid 拒绝启 动, 并且 squid.conf 里的 debug 级别不足以诊断问 题时,该模式特别有用。这也是在配置文件 Squid 中文权威指南 224 解析器解析到 debug_options 指令之前, 激 活它的完整 debug 的好方法。 在 squid 运行正常 时, 请勿使用 -X。 对运行的 squid 进程, 可 使用 squid 的-k debug 命令行选项来立刻激活完整 debug。这 个 命令是循环使用的:第一次调用打开完 整 debug,第二次调用则关闭它。请见第 5章关于 -k 选项的通用讨论。 如前所述,完整 debug 会产生难以控制的日志增长。这会 使 squid 和操作系统运行缓 慢。 在 极端情形下, 你 会发现终端 session 在运行第一个 squid -k debug 命令后, 变 得没有 响 应。在 squid 狂写日志的同时让操作无法进行,这情形并不好。 如下技巧也许有用,它获 取 5秒钟的 debug 数据快照: % squid -k debug; sleep 5; squid -k debug 13.1.213.1.213.1.213.1.2 转发cache.log cache.log cache.log cache.log 消息到系统日志 为了让 squid 发送 cache.log消息的拷贝到系统日志, 请 使用 -s命令行选项。 仅 仅在 debug 级别 0和1的消息会被转发。级别 0的消息以 syslog 级别 LOG_WARNING 记录,级别 1的消 息以 syslog 级别 LOG_NOTICE 记录。所有消息使用 LOCAL4的syslog 设备。 如下是配置 syslogd 的一个方法,以便这些消息能保存下来: local4.warning /var/log/squid.log 在维护多个 squid 主机时,使用 syslog 来记录 cache.log 特别方便。可以配置每个本地 syslog 进程, 转 发这些消息到中央日志主机, 这 样就可在一个地方统一浏览所有 cache日志。 例如,可在 /etc/syslogd.conf 里使用如下接口: local4.notice @192.168.45.1 13.1.313.1.313.1.313.1.3 dumpdumpdumpdump cache.log cache.log cache.log cache.log 消息到终端 -d level 命令行选项指示 squid 去dump cache.log 消息到终端 ( 例如 stderr)。level 参数 指 明dump 出的消 息 的最 大 级 别。 注 意 你只 会 见到 出 现 在 cache.log 里的消 息 , 它遵循 于 debug_options 设置。例如,假如设 置 了 debug_optionsALL,1,然后运行 squid -d2,你不会 见到级别 2的debug 消息。 -d level 和-N选项在 debug squid 问题或快速测试配置文件的改变时, 特 别有用。 它 们 允 许你容易启动 squid 和观察 cache.log 消息。在 squid 从crontab 或类似 的设备启动时, 该 选 项也有用, crontab 会捕获 squid 的标准错误并将其报告回用户。 例如,可能有如下 crontab, 它自动重配运行中的 squid 进程: 15 */4 ***/usr/local/squid/sbin/squid -d1 -k reconfigure Squid 中文权威指南 225 13.213.213.213.2 access.logaccess.logaccess.logaccess.log Squid 把关于 HTTP 事务的关键信息存放在 access.log 里。该文件是基于行的,也就是 说每行对应一个客户端请求。 squid 记录客户端 IP(或主机名) 、 请求 URL、响应 size、和 其他信息。 Squid 在access.log 里记录所有 HTTP 访问,除了那些在还没有发送数据前就断开的连 接。 Squid 也记录所有的 ICP(非 HTCP)事务,除非你使用 log_icp_queries 指令关闭了这 个功能。第 13.2.4节描述了其他影响 access日志的 squid.conf 指令。 默认的 access.log 格式包含了 10个域。如下是日志样本,长行分割并且缩进排版: 1066037222.011 126389 9.121.105.207 TCP_MISS/503 1055 GET http://home.gigigaga.com/n8342133/Miho.DAT.019 - DIRECT/203.187.1.180 - 1066037222.011 19120 12.83.179.11 TCP_MISS/200 359 GET http://ads.x10.com/720x300/Z2FtZ3JlZXRpbmcxLmRhd/7/AMG - DIRECT/63.211.210.20 text/html 1066037222.011 34173 166.181.33.71 TCP_MISS/200 559 GET http://coursesites.blackboard.com:8081/service/collab/./1010706448190/ - DIRECT/216.200.107.101 application/octet-stream 1066037222.011 19287 41.51.105.27 TCP_REFRESH_MISS/200 500 GET http://fn.yam.com/include/tsemark/show.js - DIRECT/210.59.224.59 application/x-javascript 1066037222.011 19395 41.51.105.27 TCP_MISS/304 274 GET http://fnasp.yam.com/image/coin3.gif - DIRECT/211.72.254.133 - 1066037222.011 19074 30.208.85.76 TCP_CLIENT_REFRESH_MISS/304 197 Squid 中文权威指南 226 GET http://ads.icq.com/content/B0/0/..bC6GygEYNeHGjBUin5Azfe68m5hD1jLk$/aol - DIRECT/64.12.184.121 - 1066037222.011 19048 12.83.179.11 TCP_MISS/200 261 GET http://ads.adsag.com/js.ng/...ne&cat=friendship&subcat=girltalk - DIRECT/209.225.54.119 application/x-javascript 1066037222.118 106 41.51.105.27 TCP_HIT/200 536 GET http://rcm-images.amazon.com/./images/G/01/rcm/privacy.gif - NONE/- image/gif 1066037222.352 19475 27.34.49.248 TCP_MISS/200 12387 GET http://espanol.geocities.com/lebastias/divulgacion/budismo-tarot.html - DIRECT/209.1.225.139 text/html 1066037222.352 132 144.157.100.17 TCP_MISS/504 1293 GET http://ar.atwola.com/image/93101912/aol - NONE/-- 如下是对每个域的详细解释: 1.时间戳 请求完成时间,以 Unix 纪元( UTC 1970-01-01 00:00:00 )以来的秒数表示,它是毫秒 级的。 squid 使用这种格式而不是人工可读的时间格式,是为了简化某些日志处理程序的工 作。 可以使用一个简单的 perl 命令来转化 Unix 时间戳到本地时间,例如: perl -pe 's/^\d+\.\d+/localtime($&)/e;' access.log 2.响应时间 对HTTP 事务来说,该域表 明 squid 花了多少时间来处理请求。 在 squid 接受到 HTTP Squid 中文权威指南 227 请求时开始计时,在响应完全送出后计时终止。响应时间是毫秒级的。 对ICP 查询来说, 响 应时间通常是 0。 这是 因 为 squid 回答 ICP 查 询 非 常 迅 速 。 甚至 , squid 在接受到 ICP 查询和发送完响应之间,不会更新进程时钟。 尽管时间值是毫秒级的, 但是精度可能是 10毫秒。在 squid 负载繁重时, 计时变得没 那 么精确。 3.客户端地址 该域包含客户端的 IP地址, 或 者是主机名 --假如激活了 log_fqdn。 出 于安全或隐私的 理 由,你可能需要使用 client_netmask 指令来掩盖客户端地址的一部分。然而,这样让来自 同 一客户端的组请求变得不可能。 4.结果 /状态码 该域包含 2个token,以斜杠分隔。第一个 token 叫结果码,它把协议和事务结果(例 如TCP_HIT 或UDP_DENIED) 进 行归类。 这些是 squid 专有的编码, 在 13.2.1节里有定义 。 以TCP_开头的编码指 HTTP请求,以 UDP_开头的编码指 ICP 查询。 第2个token 是HTTP 响应状态码(例如 200,304,404等) 。状态码通常来自原始服务器。 在某些情形下, squid 可能有义务自己选择状态码。 这些编码在 HTTP的RFC 里定义, 在 随 后的 Table 13-1里有概述。 5.传输 size 该域指明传给客户端的字节数。 严格的讲, 它是 squid 告诉 TCP/IP协议栈去发送给 客 户端的字节数。 这就是说,它不包括 TCP/IP头部的 overhead。 也请注意,传输 size 正常 来 说大于响应的 Content-Length。 传输 size 包括了 HTTP响应头部, 然而 Content- Length 不包 括。 传输 size 可用于近似的带宽使用分析,但并非精确 的 HTTP 实体 size 计算。假如需要 了解响应的 Content-Length,可在 store.log 里找到它。 6.请求方式 该域包含请求方式。 因为 squid 客户端可能使用 ICP 或HTTP, 请 求方式就可能是 HTTP- 或ICP-这2种。 最 普通的 HTTP请求方式是 GET。ICP 查询总以 ICP_QUERY 的形式被记 载。 请见 6.1.2.8节关于 squid 了解的 HTTP方式列表。 7.URI 该域包含来自客户端请求的 URI。大多数记录下来的 URI 实际是 URL(例如,它们有 主机名)。 Squid 中文权威指南 228 Squid 对某些失败使用特殊的记录格式。例如 Squid 不能解析 HTTP请求,或者不能决 定URI,这时你可能见到类似于 "error:invalid-request." 的字串出现在 URI 的位置。例如: 1066036250.603 310 192.0.34.70 NONE/400 1203 GET error:invalid-request -NONE/-- 另外在该域里,也请留心 URI 里的空格字符。取决于 uri_whitespace设置, squid 可能 在日志文件里打印 URI 时带空格字符。 若 发生这种情况, 则 阅读 access.log 文件的日志分 析 工具可能会遇到麻烦。 在记 日 志 时 , squid 删掉 了 在 第 一 个 问 号 (?)之后 的 所 有 URI 字符 , 除 非 禁 用 了 strip_query_terms 指令。 8.客户端身份 Squid 有2种不同的办法来 决定用 户的身 份。一 种 是 RFC 1413身份协议,另一 种来 自 HTTP验证头部。 Squid 试图基于 ident_lookup_access规则进行身份查询,假如有的话。 另外,假如使 用 代理验证(或在代理人模式下的规范服务验证) , squid 会在该域放置给定的用户名。假如 2 者都提供给 squid 一个用户名,并且你使用了原 始 access.log 格式,那么 HTTP 验证名字会 记录下来, RFC 1413名字会忽略掉。普通日志文件格式会把两者都独立的记录。 9.对端编码 /对端主机 对端信息包含了 2个token, 以 斜杠分隔。 它 仅仅与 cache丢失的请求有关。 第 一个 token 指示如何选择下一跳,第二个 token 是下一跳的地址。对端编码列在 13.2.3节里。 当squid 发送一个请求到邻居 cache时, 对端主机地址是邻居的主机名。 假如请求是 直 接送 到原始服务器的,则squid 会写 成 原 始 服 务 器 的 IP地址 或 主 机名 --假如 禁 用 了 log_ip_on_direct。NONE/-这个值指明 squid 不转发该请求到任何其他服务器。 10.内容类型 原始 access.log 的默认的最后一个域, 是 HTTP响应的内容类型。 squid 从响应的 Content- Type头部获取内容类型值。假如该头部丢失了, squid 使用一个横杠 (-)代替。 假如激活了 log_mime_headers 指令, squid 在每行追加 2个附加的域: 11.HTTP 请求头部 Squid 编码 HTTP请求头部, 并且在一对方括号之间打印它们。 方括号是必须的, 因 为 squid 不编码空格字符。 编码方案稍许奇怪。 回车 ( ASCII 13) 和换行 ( ASCII 10) 分别打 印 成\r和\n。其他不可打印的字符以 RFC 1738风格来编码,例如 Tab(ASCII 9)变成了 %09。 Squid 中文权威指南 229 12.HTTP 响应头部 Squid 编码 HTTP响应头部,并且在一对方括号之间打印它们。注意这些是发往客户 端 的头部,可能不同于从原始服务器接受到的头部。 Squid 只有在整个响应 发送到 客户端 完成以 后,才 写 access.log 日志。这点允 许 squid 在日志文件里包含请求和响应两者信息。然而,需要花费数分钟甚至 数小时才能完成的事 务,请求期间的 日志 在 access.log 里不可见。当这 类型的 事务呈 现出性 能或策 略问题 时, access.log 可能对你没有帮助。 代替的,可使用 cache管理器来浏览挂起事务的列表(见 14 章)。 13.2.113.2.113.2.113.2.1 access.log access.log access.log access.log 结果编码 相应于 HTTP请求,下列标签可能出现在 access.log 文件的第四个域。 TCP_HIT Squid 发现请求资源的貌似新鲜的拷贝,并将其立即发送到客户端。 TCP_MISS Squid 没有请求资源的 cache拷贝。 TCP_REFERSH_HIT Squid 发现请求资源的貌似陈旧的拷贝,并发送确认请求到原始服务器。原始服务器 返 回304(未修改)响应,指示 squid 的拷贝仍旧是新鲜的。 TCP_REF_FAIL_HIT Squid 发现请求资源的貌似陈旧的拷贝,并发送确认请求到原始服务器。然而,原始 服 务器响应失败, 或 者返回的响应 Squid 不能理解。在此 情形下,squid 发送现有 cache 拷贝(很 可能是陈旧的)到客户端。 TCP_REFRESH_MISS Squid 发现请求资源的貌似陈旧的拷贝,并发送确认请求到原始服务器。原始服务器 响 应新的内容,指示这个 cache拷贝确实是陈旧的。 TCP_CLIENT_REFRESH_MISS Squid 发现了请求资源的拷贝,但 客户端的请 求包含 了 Cache-Control: no-cache 指令。 Squid 转发客户端的请求到原始服务器,强迫 cache确认。 Squid 中文权威指南 230 TCP_IMS_HIT 客户端发送确认请求, Squid 发现更近来的、貌似新鲜的请求资源的拷 贝。 Squid 发送 更新的内容到客户端,而不联系原始服务器。 TCP_SWAPFAIL_MISS Squid 发现请求资源的有效拷贝,但从磁盘装载它失败。这 时 squid 发送请求到原始服 务器,就如同这是个 cache丢失一样。 TCP_NEGATIVE_HIT 在对原始服务器的请求导致 HTTP 错误时, Squid 也会 cache这个响应。在短时间内对 这些资源的重复请求, 导致了否命中。 negative_ttl 指令控制这些错误被 cache的时间数量 。 请注意这些错误只在内存 cache, 不 会写往磁盘。 下列 HTTP状态码可能导致否定 cache(也 遵循于其他约束):204, 305, 400, 403, 404, 405, 414, 500, 501, 502, 503, 504。 TCP_MEM_HIT Squid 在内存 cache里发现请求资源的有效拷贝,并将其立即发送到客户端。注意这点 并非精确的呈现了所有从内存服务的响应。 例 如, 某些 cache在内存里, 但 要求确认的响 应, 会以 TCP_REFRESH_HIT,TCP_REFRESH_MISS 等形式记录。 TCP_DENIED 因为 http_access或http_reply_access 规则, 客户端的请求被拒绝了。注意被 http_access 拒绝的请求在第 9域的值是 NONE/-, 然 而被 http_reply_access 拒绝的请求, 在 相应地方有 一 个有效值。 TCP_OFFLINE_HIT 当offline_mode 激活时, Squid 对任何 cache响应返回 cache命中, 而 不用考虑它的新 鲜 程度。 TCP_REDIRECT 重定向程序告诉 Squid 产生一个 HTTP 重定向到新的 URI(见 11.1节 ) 。正 常 的 , Squid 不会记录这些重定向。 假 如要这样做, 必 须在编译 squid 前 , 手工 定 义 LOG_TCP_REDIRECTS 预处理指令。 NONE 无分类的结果用于特定错误,例如无效主机名。 Squid 中文权威指南 231 相应于 ICP 查询,下列标签可能出现在 access.log 文件的第四域。 UDP_HIT Squid 在cache里发现请求资源的貌似新鲜的拷贝。 UDP_MISS Squid 没有在 cache里发现请求资源的貌似新鲜的拷贝。 假 如同一目标通过 HTTP请求 , 就可能是个 cache丢失。请对比 UDP_MISS_NOFETCH。 UDP_MISS_NOFETCH 跟UDP_MISS 类似,不同的是这里也指示 了 Squid 不愿去处理相应的 HTTP 请求。假 如使 用 了 -Y命令 行 选 项 , Squid 在启 动并编译其内 存索引时,会返回这个标签而不是 UDP_MISS。 UDP_DENIED 因为 icp_access 规则 , ICP 查询 被拒 绝 。 假 如 超 过 95%的到 某客 户 端 的 ICP 响应 是 UDP_DENIED, 并 且客户端数据库激活了 ( 见附录 A),Squid 在1小时内, 停 止发送任何 ICP 响应到该客户端。若这点发生,你也可在 cache.log 里见到一个警告。 UDP_INVALID Squid 接受到无效查询(例如截断的消息、 无效协议版本、 URI 里的空格等)。Squid 发 送UDP_INVALID 响应到客户端。 13.2.213.2.213.2.213.2.2 HTTP HTTP HTTP HTTP 响应状态码 Table 13-1列出了数字 HTTP 响应 CODE 和理由短句。注意 Squid 和其他 HTTP 客户端 仅仅关注这些数字值。理由短句是纯解释性的,不会影响响应的意 义。对每个状态码,也 提供了一个到 RFC 2616的具体节的索引。 注 意状态码 0和600是squid 使用的非标准的值, 不 会在 RFC 里提到。 Table 13-1. HTTP response status codes Co de Reason phrase RFC 2616 section 0 No Response Received (Squid-specific) N/A Squid 中文权威指南 232 1x x Informational 10.1 10 0 Continue 10.1.1 10 1 Switching Protocols 10.1.2 2x x Successful 10.2 20 0 OK 10.2.1 20 1 Created 10.2.2 20 2 Accepted 10.2.3 20 3 Non-Authoritative Information 10.2.4 20 4 No Content 10.2.5 20 5 Reset Content 10.2.6 20 6 Partial Content 10.2.7 Squid 中文权威指南 233 3x x Redirection 10.3 30 0 Multiple Choices 10.3.1 30 1 Moved Permanently 10.3.2 30 2 Found 10.3.3 30 3 See Other 10.3.4 30 4 Not Modified 10.3.5 30 5 Use Proxy 10.3.6 30 6 (Unused) 10.3.7 30 7 Temporary Redirect 10.3.8 4x x Client Error 10.4 40 0 Bad Request 10.4.1 Squid 中文权威指南 234 40 1 Unauthorized 10.4.2 40 2 Payment Required 10.4.3 40 3 Forbidden 10.4.4 40 4 Not Found 10.4.5 40 5 Method Not Allowed 10.4.6 40 6 Not Acceptable 10.4.7 40 7 Proxy Authentication Required 10.4.8 40 8 Request Timeout 10.4.9 40 9 Conflict 10.4.10 41 0 Gone 10.4.11 41 1 Length Required 10.4.12 Squid 中文权威指南 235 41 2 Precondition Failed 10.4.13 41 3 Request Entity Too Large 10.4.14 41 4 Request-URI Too Long 10.4.15 41 5 Unsupported Media Type 10.4.16 41 6 Requested Range Not Satisfiable 10.4.17 41 7 Expectation Failed 10.4.18 5x x Server Error 10.5 50 0 Internal Server Error 10.5.1 50 1 Not Implemented 10.5.2 50 2 Bad Gateway 10.5.3 50 3 Service Unavailable 10.5.4 Squid 中文权威指南 236 假如 Squid 从原始服务器没有接受到任何响应, 你 可在 access.log 里看到状态码 0。假如 Squid 接受到的响应没有包含 HTTP 头部,就会出现状态码 600。在少数情况下,某些原始 服务器仅发送响应 body,而忽略了任何头部。 13.2.313.2.313.2.313.2.3 access.log access.log access.log access.log 对端编码 下列编码可能出现在 access.log 的第 9域 。 请参 考 10.10节关于 Squid 如何对 cache丢失 情 况,选择有效的下一跳。 NONE 这指明 Squid 对本次请求, 不会与任何其他服务器 (邻居或原始服务器) 通信。 它通 常 与cache命中、拒绝请求、 cache管理请求、错误、和所有的 ICP 查询这些类型联合出现。 DIRECT Squid 直接转发请求到原始服务器。该域的第 2半部分显示原始服务器的 IP地址,或主 机名 --假如禁止了 log_ip_on_direct。 SIBLING_HIT 在姐妹 cache返回 ICP 或HTCP 命中后, Squid 发送请求到姐妹 cache。 PARENT_HIT 50 4 Gateway Timeout 10.5.5 50 5 HTTP Version Not Supported 10.5.6 6x x Proxy Error N/A 60 0 Unparseable Response Headers (Squid- specific) N/A Squid 中文权威指南 237 在父 cache返回 ICP 或HTCP 命中后, Squid 发送请求到父 cache。 DEFAULT_PARENT Squid 选择该父 cache,因为其在 squid.conf 的cache_peer 行里被标志为 default。 FIRST_UP_PARENT Squid 转发请求到该父 cache,因为它是位于已知活跃列表里的第一个父 cache。 FIRST_PARENT_MISS Squid 转发请求到该父 cache, 它 第一个响应 ICP/HTCP 丢失消息。 换 句话说, 对 这个 特 殊的 ICP/HTCP 查询,在这个特殊时刻,被选 中的父 cache有最佳的往返时间( RTT)。注 意标准 RTT可能被人工矫正过,取决于 cache_peer 指令的 weight 选项。 CLOSEST_PARENT_MISS Squid 选择该父 cache, 因为它报告到原始服务器的 RTT最低。 这点仅在 2个cache都激 活了 netdb,并且原始服务器(或在同一子网内的其他 server)返回 ICMP ping 消息。 CLOSEST_PARENT 这点类似 CLOSEST_PARENT_MISS,除了 RTT计算不是来自 ICP/HTCP 响应消息外。 代替的,它们来自 Squid 保留的更老的计算方式,例如 netdb 交换功能。 CLOSEST_DIRECT Squid 基于 netdb 算法,转发请求到原始服务器。这点在满足下述任何条件时发生: • 1)在 Squid 和原始服务器之间的 RTT小于配置的 minimum_direct_rtt 值。 • 2)在Squid 和原始服务器之间的标准路由跳数少于配置的 minimum_direct_hops 值。 • 3)在 ICP/HTCP 响应里返回的 RTT值,指示 Squid 离原始服务器近于任何 其 他邻居。 ROUNDROBIN_PARENT Squid 转发请求到该父 cache,因为设置了 round-robin 选项,并且它有最低的使用计数 Squid 中文权威指南 238 器。 CD_PARENT_HIT Squid 基于 cache摘要算法(见 10.7节)转发请求到该父 cache。 CD_SIBLING_HIT Squid 基于 cache摘要算法转发请求到该姐妹 cache。 CARP Squid 选择该父 cache,基于 cache数组路由协议算法(见 10.9节)。 ANY_PARENT 作为最后的手段, Squid 选择该父 cache,因为没有其他方法能选择可行的下一跳。 注意大部分上述编码可能 以 TIMEOUT_开头,这表明在等 待 ICP/HTCP 响应时发生超 时。例如: 1066038165.382 345 193.233.46.21 TCP_MISS/200 2836 GET http://www.caida.org/home/./images/home.jpg TIMEOUT_CLOSEST_DIRECT/213.219.122.19 image/jpeg 可使用 icp_query_timeout 指令来调整超时。 13.2.413.2.413.2.413.2.4 影响access.log access.log access.log access.log 的配置指令 下列配置文件指令会影响到 access.log。 13.2.4.113.2.4.113.2.4.113.2.4.1 log_icp_querieslog_icp_querieslog_icp_querieslog_icp_queries 该指令默认激活 ,导 致 squid 记录所有的 ICP 查询。假如运行 了一个 繁忙的 父 cache, 这点可能让 access.log 文件变得巨大。为了节省磁盘空间,可禁止该指令: log_icp_queries off 假如禁止了 ICP 查询的日志,我建议你监视查询数量 --通过 cache管理器或 SNMP。 13.2.4.213.2.4.213.2.4.213.2.4.2 emulate_httpd_logemulate_httpd_logemulate_httpd_logemulate_httpd_log Squid 中文权威指南 239 access.log 文件有 2种格式: 普 通格式和原始格式。 普 通格式就如同大部分 HTTP服务 器 (如 Apache) 的 日志格式一样。 它 包含的信息少 于Squid 的原始格式。 然 而, 假 如运行 Squid 在代理人模式下(见 15章) , 你可能想要普通日志文件格式。普通格式或许也对你现有的日 志文件分析工具 有用。使用该指令来激活普通格式: emulate_httpd_log on 请见 http://www.w3.org/Daemon/User/Config/Logging.html#common-logfile-format 关于 该格式的描述。 13.2.4.313.2.4.313.2.4.313.2.4.3 log_mime_hdrslog_mime_hdrslog_mime_hdrslog_mime_hdrs 使用 log_mime_hdrs 让squid 记录 HTTP请求和响应的头部: log_mime_headers on 在激活时, squid 追加请求和响应头部到 access.log。这会在每行增加 2个域。每个域都 以方括号引用起来,便于分析。某些字符会被编码来保证日志文件可读。 Table 13-2显示了 这些编码方案。 Table 13-2. Character encoding rules for HTTP headers in access.log Charact er Encoding Newlin e \n Carriag e return \r Backsla sh \\ [%5b ]%5d Squid 中文权威指南 240 13.2.4.413.2.4.413.2.4.413.2.4.4 log_fqdnlog_fqdnlog_fqdnlog_fqdn Squid 默认把客户端 IP地址放在 access.log 里。也可以记录可用的主机名,激活如下 指 令: log_fqdn on 这点让 Squid 在接受到请求时,对客户端的地址发起反向 DNS 查询。假如在请求完成 时查到了主机名, Squid 就将它放在第 3域。 13.2.4.513.2.4.513.2.4.513.2.4.5 ident_lookup_accessident_lookup_accessident_lookup_accessident_lookup_access 该访问规则列表决定 Squid 是否对客户端的 TCP 连接发起 RFC 1413身份查询。默认情 况下, Squid 不会发布身份查询。为了激活这点,简单的增加一个或多个规则: acl All src 0/0 ident_lookup_access allowAll 假如在请求完 成时 查到了 答案 , Squid 将其放在第 8域。假如同时 使用 了 HTTP 验证, 从验证得到的用户名会取代身份查询答案。 13.2.4.613.2.4.613.2.4.613.2.4.6 log_ip_on_directlog_ip_on_directlog_ip_on_directlog_ip_on_direct 当Squid 转发 cache丢失到原始服务器时,它在第 9域记录原始服务器的 IP地址。可以 禁止这个指令,以便 squid 记录主机名: log_ip_on_direct off 在此情形下,主机名来自于 URI。假如 URI 包含了 IP地址, Squid 不会将其转换为主 机名。 %%25 ASCII 0-31 %xx (hexadecimal value) ASCII 127-255 %xx (hexadecimal value) Squid 中文权威指南 241 13.2.4.713.2.4.713.2.4.713.2.4.7 client_netmaskclient_netmaskclient_netmaskclient_netmask 该指令存在主要是为了保护用户的隐私。不同于记录完整的 IP地址,你也可以掩盖一 些位。例如: client_netmask 255.255.255.0 在此设置下, access.log 里的所有客户端 IP地址的最后一个八位组是 0: 1066036246.918 35 163.11.255.0 TCP_IMS_HIT/304 266 GET http://... 1066036246.932 16 163.11.255.0 TCP_IMS_HIT/304 266 GET http://... 1066036247.616 313 140.132.252.0 TCP_MISS/200 1079 GET http://... 1066036248.598 44459 140.132.252.0 TCP_MISS/500 1531 GET http://... 1066036249.230 17 170.210.173.0 TCP_IMS_HIT/304 265 GET http://... 1066036249.752 2135 140.132.252.0 TCP_MISS/200 50230 GET http://... 1066036250.467 4 170.210.173.0 TCP_IMS_HIT/304 265 GET http://... 1066036250.762 102 163.11.255.0 TCP_IMS_HIT/304 265 GET http://... 1066036250.832 20 163.11.255.0 TCP_IMS_HIT/304 266 GET http://... 1066036251.026 74 203.91.150.0 TCP_CLIENT_REFRESH_MISS/304 267 GET http://... 13.2.4.813.2.4.813.2.4.813.2.4.8 strip_query_termsstrip_query_termsstrip_query_termsstrip_query_terms 该指令是另一个隐私保护功能。在记录请求前, Squid 删除了查询条件。假如日志文 件 不幸落入坏人之手,他们不会找到任何用 户名和密码。当该 指令激活时,在 问号 (?)之后的 所有字节被删除。例如,某个 URI 如下: http://auto.search.msn.com/response.asp?MT=www.kimo.com.yw&srch=3&prov=&utf8 会被记录为: http://auto.search.msn.com/response.asp? 13.2.4.913.2.4.913.2.4.913.2.4.9 uri_whitespaceuri_whitespaceuri_whitespaceuri_whitespace Squid 中文权威指南 242 早前我提到过出现在某些 URI 里的空格字符的问题。 RFC 申明 URI 必须不包括空格 字 符,但在实际中情况并非如此。 uri_whitespace指令指明 Squid 如何处理这种情况。允许的 设置是: strip (default), deny, allow, encode, 和chop。在这些设置里, strip,encode 和chop 保 证URI 域不包含任何空格字符(空格字符会给 access.log 增加多余的域)。 allow 设置允许请求不加修改的通 过 Squid。它很可能会给重定向器和 日志文件解 析器 带来麻烦。 与之相反的是 deny 设置, 它导致 Squid 拒绝这种请求。 用户会接受到错误消息 , 但请求仍带着空格字符被记录到 access.log。 假如设置为 encode,Squid 将空格字符按 RFC 1738规范来编码。 这 点其实用户代理应 该 先做到。 chop 设置导致 Squid 把第一个空格字符后的 URI 都截断。 默认设置是 strip,它让 Squid 从URI 里移除空格字符。这确保日 志文件解析 器和重定 向器工作正常,但可能会破坏某些事情,例如不正确编码的搜索引擎查询。 13.2.4.1013.2.4.1013.2.4.1013.2.4.10 buffered_logsbuffered_logsbuffered_logsbuffered_logs 默认情况下, Squid 禁止写 cache.log 文件的 buffer,这允许你运行 tail -f 命令实时的观 察日志文件变化。假如你认为这点导致不必要的性能开销,就可以禁用 buffer: buffered_logs off 然而,除非以完 整 debug 模式运行 Squid,这点可能无关 紧要。 注意该 选项仅 仅影 响 cache.log。其他的日志文件总使用非缓冲的写方式。 13.2.513.2.513.2.513.2.5 access.log access.log access.log access.log 分析工具 access.log 包含很多信息,远不止你简单的浏览该文件所见。为了完整的浏览,必须使 用第三方的日志文件分析包。 你 可在 Squid 的web 页面的链接里, 找 到它们的列表。 或 者 直 接访问: http://www.squid-cache.org/Scripts/. 最流行的工具之一是 Calamaris -- 一个 Perl脚本,解析日志文件并产生基于文本的或 HTML的报告。它提供关于会话的详细分类包括请求方式、客户端 IP地址、原始服务器域 名、内容类型、 文件名扩展、响应 size、以及更多。 Calamaris 也报告 ICP 查询会话,甚 至 其他 cache产品的日志分析。其站点是: http://calamaris.cord.de. Squeezer 以及它的派生 Squeezer2,是 Squid 专有的分析工具。它们提供许多统计,能 帮助你了解 Squid 的性能,特别是在有邻居 cache时。两者都产 生HTML文件作为输出。 squid-cache.org 站点的 LogfileAnalysis 页有这些程序的链接。 Webalyzer 是另一个有用工 具。它 运行快 速,并 且产生 带表格 和柱形 统计表 的 HTML 页面。它原始是设计成分析原始服务器的访问日志的。尽管它能解 析 Squid 的日志, 但不 会报告诸如命中率和响应时间的事件。 它 使用的某些条款不同于我的做法。 例 如, Webalyzer Squid 中文权威指南 243 把任何请求叫做一个 "命中 ", 这不同于 cache命中。 它也把 "页面 "和"文件 "加以区别。 更 多 信息请访问 Webalyzer 的主页: http://www.mrunix.net/webalyzer/. 13.313.313.313.3 store.logstore.logstore.logstore.log store.log 记录 Squid 关于存储或 删 除 cache 目标的决定 。对 每个 存 在 cache 里的目标、 每个不可 cache的目标、 以 及每个被轮换策略删除的目标, Squid 都会创建相应的日志条目 。 该日志文件内容既包含了内存 cache又包含了磁盘 cache。 store.log 提供了下述不能从 access.log 获取的内容: • 1)某个特定的响应是否被 cache。 • 2)cache目标的文件号。对 UFS 基础的存储机制,你可转换该文件号到路径 名,并且检查 cache文件的内容。 • 3)响应的内容长度:包括 Content-Length 值和实际的 body 大小。 • 4)Date, Last-Modified, 和Expires 头部的值。 • 5)响应的 cache关键字(例如 MD5哈希值)。 如你所见, 这 些都是相对低级的信息, 在 日常管理中可能用不上。 除 非你要做专业的 分 析,或打算 debug 某程序,否则 store.log 可有可无。可以如下来禁止它: cache_store_log none 跟其他日志文件一样, Squid 将最新的日志条目写到该文件的末尾。 某 个给定的 URI 可 能出现在日志文件里多次。例如,它先被 cache,然后删除,接着又 cache住。仅仅最近来 的日志条目才反映目标的当前值。 store.log 是文本基础的,看起来如下: 1067299212.411 RELEASE-1 FFFFFFFFA5964B32245AC98592D83F9B6EA10B8D 206 1067299212 1064287906 -1 application/octet-stream 6840/6840 GET http://download.windowsupdate.com/msdownload/update/v3-19990518/cab... 1067299212.422 SWAPOUT 02 0005FD5F 6F34570785CACABC8DD01ABA5D73B392 200 Squid 中文权威指南 244 1067299210 1057899600 -1 image/gif 1125/1125 GET http://forum.topsportsnet.com/shf./images/nav_members1.gif 1067299212.641 RELEASE-1 FFFFFFFF B0616CB4B7280F67672A40647DD08474 200 1067299212 -1 -1 text/html -1/67191 GET http://www.tlava.com/ 1067299212.671 RELEASE-1 FFFFFFFF 5ECD93934257594825659B596D9444BC 200 1067299023 1034873897 1067299023 image/jpeg 3386/3386 GET http://ebiz0.ipixmedia.com/abc/ebiz/_EBIZ_3922eabf57d44e2a4c3e7cd234a... 1067299212.786 RELEASE-1 FFFFFFFF B388F7B766B307ADEC044A4099946A21 200 1067297755 -1 -1 text/html -1/566 GET http://www.evenflowrocks.com/pages/100303pic15.cfm 1067299212.837 RELEASE-1 FFFFFFFF ABC862C7107F3B7E9FC2D7CA01C8E6A1 304 1067299212 -1 1067299212 unknown -1/0 GET http://ebiz0.ipixmedia.com/abc/ebiz/_EBIZ_3922eabf57d44e2a4c3e7cd234a... 1067299212.859 RELEASE-1 FFFFFFFF 5ED2726D4A3AD83CACC8A01CFDD6082B 304 1066940882 1065063803 -1 application/x-javascript -1/0 GET http://www.bellsouth.com/scripts/header_footer.js 每个日志条目包含如下 13个域: • 1. 时间戳 事件何时发生,表现为 Unix 纪元以来的秒数,它是毫秒级的。 • 2. 动作 ocache目标发生的动作。该域有 3个可能值: SWAPOUT,RELEASE,和 Squid 中文权威指南 245 SO_FAIL。 1)SWAPOUT 在Squid 成功的存储目标到磁盘时发生。某些目标例如那些消极 cache的,仅保存在内存而不是磁盘, Squid 不会在 store.log 里记录它们。 o2)SO_FAIL 表明 Squid 不能完整的存储目标到磁盘。多半意味着存储机 制拒绝以写方式打开新的磁盘文件。 o3)RELEASE 在Squid 从cache里删除目标, 或首先就决定响应不可存 储 时发生。 • 3. 目录号 • 目录号是十进制小数形式,它是个到 cache目录的 7位索引。对没有存储到磁 盘的目标,该域包含 -1值。 • 4. 文件号 • 文件号是 25位的标识符, 内 在的被 squid 使用。 它 被写成 8字符的十六进制 号。 对UFS 基础的存储机制,有算法可以转换文件号到路径名(见 13.3.1 节 ) 。没 有 存 储 到 磁盘的目标, 没 有有效的文件号。 对 这些目标, 该 域的值是 FFFFFFFF。 仅 仅在 RELEASE 和SO_FAIL情况下才会出现这个值。 • 5. cache关键字 Squid 使用 MD5哈希值作为主要的索引来定位目标。该关键字基于请求方式、 URI、和 其他可能的信息计算得来。 可以从 cache关键字来查找 store.log 条目。 然而请注意, 目 标的 cache关键字可能改变。 当 Squid 在access.log里记录 TCP_REFRESH_MISS 请求 时, 这点会发生。情况类似如下: 1065837334.045 SWAPOUT... 554BACBD2CB2A0C38FF9BF4B2239A9E5 ... http://blah 1066031047.925 RELEASE... 92AE17121926106EB12FA8054064CABA ... http://blah 1066031048.074 SWAPOUT... 554BACBD2CB2A0C38FF9BF4B2239A9E5 ... http://blah • 发生了什么呢?该目标原本 cache在某个关键字下( 554B...) 。一 段 时 间 后 , Squid 接受到对该目标的另一请求, 并 转发确认请求到原始服务器。 当响应以新内容 返 回时, Squid 改变旧目标的 cache关键字 ( 92AE...) , 以便它能授予新目标正确的关键 字 (554B...) 。然 后 旧 目 标 删 除,新目标存储到磁盘。 • 6. 状态码 • 该域显示响应的 HTTP状态码,跟 access.log 一样。表 13.1是状态码列表。 Squid 中文权威指南 246 • 7. 日期 •HTTP响应的 Date 头部值, 表 现为 Unix纪元以来的秒数。 值 -1表示 Date 头部 不可解析, -2意味着头部完缺。 • 8. 最后修改时间 • HTTP 响应的 Last-Modified 头部值,表现为 Unix 纪元以来的秒数。值 -1表示 Last-Modified 头部不可解析, -2意味着头部完缺。 • 9. 过期时间 •HTTP响应的 Expires 头部值, 表 现为 Unix 纪元以来的秒数。 值 -1表示 Expires 头部不可解析, -2意味着头部完缺。 • 10. 内容类型 •HTTP响应的 Content-Type头部值, 排 除了任何 media-type 参数。 假如 Content- Type丢失了, Squid 插入值 unknown。 • 11. 内容长度 /大小 • 该域包含 2个数字,以斜杠分开 。第一个 是 Content-Length 头部值。 -1表明 Content-Length 头部不存在。第二个是 HTTP消息 body 的实际大小。你可使用这 2个数 字来部分的验证接受到的响应, 并验证原始服务器是否不正确的计算了内容长度。 大 多 数情形下,这 2个数字相等。 • 12. 方式 • 请求目标的 HTTP方式,跟 access.log 里的一样。 • 13. URI • 最后一个域是请求 URI,跟 access.log 里的一样。该域也有前述章节提到的 空 格问题。然而,这里不必为此担忧,因为你可安全的忽略任何多余的域。 • 对许多 RELEASE 的条目, 在 最后 8个域出现的是疑问号 (?)。 这 是因为这些 域 的大部分值来自 squid 称为 MemObject 的结构。该结构仅在目标已 被接受时,或目标 被完整存储 在内 存时 ,才 会出 现。 Squid cache 里的大部分 目标 没 有 MemObject 结构, 因为它们仅存在于磁盘。对这些情况, Squid 在相应域放置一个疑问号。 13.3.113.3.113.3.113.3.1 转换文件号到路径名 Squid 中文权威指南 247 假如想要检查某个特定的 cache文件, 你 可稍费工夫将文件号转换到路径名。 另外目 录 号和 L1和L2值也是必需的。在 squid 的源代码 里, storeUfsDirFullPath( )函数做这个事情。 可在 src/fs/ufs/store_dir_ufs.c文件里找到它。如下短小的 perl 脚本模拟了当前算法: #!/usr/bin/perl $L1 = 16; $L2 = 256; while (<>) { $filn = hex($_); printf("%02X/%02X/%08X\n", (($filn / $L2) / $L2) % $L1, ($filn / $L2) % $L2, $filn); } 这样使用它: % echo 000DCD06 | ./fileno-to-pathname.pl 0D/CD/000DCD06 要在第 N个cache_dir 里找到该文件, 简 单的进入到相应的目录, 并 列出或查看该文 件: % cd /cache2 % ls -l 0D/CD/000DCD06 -rw------- 1 squid squid 391 Jun 3 12:40 0D/CD/000DCD06 % less 0D/CD/000DCD06 13.413.413.413.4 referer.logreferer.logreferer.logreferer.log 可选 的 referer.log 包含 了来自客户端请求的Referer 头部 。为了使用该功能,必须 Squid 中文权威指南 248 在./configure 时打开 --enable-referer-log 选项。 还必须用 referer_log 指令来指定一个路径。 例 如: referer_log /usr/local/squid/var/logs/referer.log 假如想禁止 referer.log,则可设置文件名为 none。 Referer 头部正常情况下包含一个 URI, 从 这个 URI 获取到了请求 (见 RFC2616的14.36 节) 。 例如,当 web 浏览器发布请求到某个内嵌图片 时, Referer 头部被设置成包含该图片 的HTML网页的 URI。 当你点击 HTML超链接时, 它也被设置。 某些 web 站点管理员使 用 Referer 值来 查找死链接。在使用 Squid 作为代理人模式时,你也许发 现 referer.log 特别有 用。 referer.log 格式简单,仅有 4个域。如下是一些示例: 1068047502.377 3.0.168.206 http://www.amazon.com/exec/obidos/search-handle-form/002-7230223-8205634 http://www.amazon.com/exec/obidos/ASIN/0596001622/qid=1068047396/sr=2-1/... 1068047503.109 3.0.168.206 http://www.amazon.com/exec/obidos/ASIN/0596001622/qid=1068047396/sr=2-1/... http://g-images.amazon.com/./images/G/01/gourmet/gourmet-segway.gif 1068047503.196 3.0.168.206 http://www.amazon.com/exec/obidos/ASIN/0596001622/qid=1068047396/sr=2-1/... http://g-images.amazon.com/./images/G/01/marketing/cross-shop/arnold/appar... 1068047503.198 3.0.168.206 http://www.amazon.com/exec/obidos/ASIN/0596001622/qid=1068047396/sr=2-1/... http://g-images.amazon.com/./images/G/01/marketing/cross-shop/arnold/appar... 1068047503.825 3.0.168.206 http://www.amazon.com/exec/obidos/ASIN/0596001622/qid=1068047396/sr=2-1/... http://images.amazon.com/./images/P/B00005R8BC.01.TZZZZZZZ.jpg Squid 中文权威指南 249 1068047503.842 3.0.168.206 http://www.amazon.com/exec/obidos/ASIN/0596001622/qid=1068047396/sr=2-1/... http://images.amazon.com/./images/P/0596001622.01._PE_PI_SCMZZZZZZZ_.jpg 注意缺少 Referer 头部的请求不会被记录。这 4个域描述如下: • 1. 时间戳 • 请求时间,表现为 Unix 纪元以来的秒数,是毫秒级的。 注意的是, 不像 access.log,referer.log 在Squid 接受到完整请求时, 会 立刻记录。 这样 , referer.log 条目在 access.log 之前发生,后者等待响应完成才记录。 • 2. 客户端地址 • 客户端地址跟 access.log 里的一样。log_fqdn 和client_netmask 指令也影响该 日 志文件。 • 3. referer • 来自客户端请求的 Referer 头部值。注意referer值可能有空格字符或其他字 符, 在写 referer.log 前Squid 不会对其进行编码。 • 4. URI • 客户端正请求的 URI。它匹配 access.log 里的 URI。 13.513.513.513.5 useragent.loguseragent.loguseragent.loguseragent.log 可选的 useragent.log 包含来自客户端请求的 User-Agent 头部值。 为 了使用该功能, 必 须 在运行 ./configure 时打开 --enable-useragent-log 选项。 还 必须使用 useragent_log 指令来提供 一 个路径名。例如: useragent_log /usr/local/squid/var/logs/useragent.log User- Agent 头部正常情况下包含了发起请求的 user-agent 的描述。 大多数情形下, 该 描 述只是简单的产品名 列表和版 本信息 。你应该 清楚应用 程序可以 轻 易的提供伪造 的 user- agent 信息。现代 user-agent 提供途径可定制该描述。甚 至 Squid 在转发请求里能改变这个 User-Agent 头部。 Squid 中文权威指南 250 useragent.log 格式相对简单,看起来如下: 3.0.168.206 [05/Nov/2003:08:51:43 -0700] "Mozilla/5.0 (compatible; Konqueror/3; FreeBSD)" 3.0.168.207 [05/Nov/2003:08:52:18 -0700] "Opera/7.21 (X11; FreeBSD i386; U)[en]" 4.241.144.204 [05/Nov/2003:08:55:11 -0700] "Mozilla/5.0 (Macintosh; U;PPC Mac OSX; en-us)AppleWebKit/103u (KHTM..." 3.0.168.206 [05/Nov/2003:08:51:43 -0700] "Java1.3.1_01" 64.68.82.28 [05/Nov/2003:08:52:50 -0700] "Googlebot/2.1 (http://www.googlebot.com/bot.html)" 3.0.168.205 [05/Nov/2003:08:52:50 -0700] "WebZIP/4.1 (http://www.spidersoft.com)" 4.241.144.201 [05/Nov/2003:08:52:50 -0700] "Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt; Hotbar 3.0)" 3.0.168.206 [05/Nov/2003:08:54:40 -0700] "Bookmark Renewal Check Agent [http://www.bookmark.ne.jp/] (Version 2.0..." 不像其他日志文件,它仅有 3个域: • 1. 客户端地址 • 跟access.log 里的一样。 log_fqdn 和client_netmask 指令也影响该日志文件。 • 2. 时间戳 • 不像其他日志文件那样,用 Unix 纪元以来的秒数来描述时间,这里使用人工 可读的格式。它是 HTTP通用日志文件格式的时间戳,看起来如下: Squid 中文权威指南 251 [10/Jun/2003:22:38:36 -0600] • 注意方括号界定时间戳,它包含一个空格。 也请注意,跟 referer.log 一样, 这 些条目在 Squid 接受到完整请求时,立刻被记录。 • 3. user-agent • User-Agent 头部的值。这些字串 几乎总包 含空格 。在将其 写入日志 文件时, Squid 不会编码 User-Agent 值。 13.613.613.613.6 swap.stateswap.stateswap.stateswap.state swap.state 文件是目标写入 cache目录、 或从 cache目录删除的日志写照。 每个 cache_dir 有它自己的 swap.state文件。当 Squid 启动时,它 读取 swap.state文件来重建 cache目标的 内存索引。这些文件对 Squid 管理来说,至关重要。 默认情况下, 每个 cache.state文件位于它相应的 cache目录。 这 样, 每个 state 文件自 动 驻留在每个 cache_dir 下。 这 点很有用--假如你想重新排序 cache_dir 行, 或 想从 cache_dir 列表里删除条目的话。 如果想将它们放在其他位置,可使用 cache_swap_log 指令来做: cache_swap_log /usr/local/squid/var/logs/swap.state 在此情况下, Squid 对每个 cache目录创建一个 swap.state 文件,并增 加数字后缀。例如, 假如有 4个cache目录, Squid 创建如下日志: /usr/local/squid/var/logs/swap.state.00 /usr/local/squid/var/logs/swap.state.01 /usr/local/squid/var/logs/swap.state.02 /usr/local/squid/var/logs/swap.state.03 在 这 个 情 形 下 , 如果 你 要 增 加 、 删除 、 或重 排 序 cache_dir行, 就 必须手工重命名 swap.state 文件,以保持事情一致。 技术上, swap.state格式是独立于存储机制的。 然而,在当前版本的 Squid 里, 所有 的 存储机制使用同一种格式。 swap.state文件使用修正 大小 ( 48位) 的二进制格式。 各个域 值 以主机字节顺序记录,这样在不同的操作系统之间不便迁移。表 13-3描述了 swap.state日志 Squid 中文权威指南 252 条目的各个域的 说明。 Table 13-3. swap.state entry fields Na me Size, in bytes Description op 1 Operation on the entry: added (1) or deleted (2). file number 4 Same as the fourth field of store.log, except it is stored in binary. time stamp 4 A timestamp corresponding to the time when the response was generated or last validated. Taken from the Date header for responses that have one. Stored as the number of seconds since the Unix epoch. lastr ef 4 A timestamp corresponding to the most recent access to the object. expi res 4 The object's expiration time, taken from an Expires header or Cache- Control max-age directive. last- modified 4 The object's Last-Modified value. swa p file size 4 The amount of space the object occupies on disk. This includes HTTP headers and other Squid-specific meta-information. refc ount 2 The number of times this object has been requested. flag s 2 Various internal flags used by Squid. Squid 中文权威指南 253 13.713.713.713.7 轮转 日志 Squid 不断的写日志,假如 cache非常忙,那么在一段时间后,这些日志文件可能变得 很大。某些操作系统甚至限制了文件的最大 size(例如 2G) , 假如写文件超过了这个 size 就 会报错。为了保持日志文件容易管理,以及让 Squid 正常工作,必须定期轮转日志。 Squid 有内建的功能用于轮转日志。 可 通过 squid -k rotate命令来调用它, 然 后告诉 Squid 对每个日志文件保持多少份旧拷贝。例如,假如设置它为 7,对每个日志文件会有 8个版本: 1个当前的,和 7个旧的。 旧日志文件以数字扩展来重命名。 例 如, 当 执行一次轮转时, Squid 重命名 log.6到log.7, 然后是 log.5到log.6,依此类推。当前 log 变成 log.0,并且 Squid 创建一个新的空文件,命 名为 log。 每次执 行 squid -k rotate 时, Squid 轮转 下 述 文 件 : cache.log, access.log, store.log, useragent.log (假如激活 ), 以及 referer.log (假如激活 )。Squid 也会创建最新版本 的 swap.state 文件。然而请注意, swap.state不会以数字扩展形式来轮转。 Squid 不会自己轮转日志,最好的办法是在 crontab 里自动执行。例如: 0 0 ***/usr/local/squid/sbin/squid -k rotate 假如你想编写自己的脚本来管理日志文件, Squid 提供了一个有用的模式,简单的设 置 logfile_rotate 指令为 0。这样,当你运行 squid -k rotate命令时, Squid 简单的关闭当前日志 文件,并且打开新的。如果操作系统允许重命名被其他进程打开的文件,则这点非常有用。 下述 shell 脚本描述了一个思路: #!/bin/sh set -e yesterday_secs=`perl -e 'print time -43200'` yesterday_date=`date -r $yesterday_secs +%Y%m%d` key 16 The MD5 hash of the corresponding URI. Same as the key in store.log, except this one is stored in binary. Squid 中文权威指南 254 cd /usr/local/squid/var/logs # rename the current log file without interrupting the logging process mv access.log access.log.$yesterday_date # tell Squid to close the current logs and open new ones /usr/local/squid/sbin/squid -k rotate # give Squid some time to finish writing swap.state files sleep 60 mv access.log.$yesterday_date /archive/location/ gzip -9 /archive/location/access.log.$yesterday_date 13.813.813.813.8 隐私 和安 全 Squid 的日志文件特别是 access.log, 包含了用户的活跃记录,因此它受隐私问题支配 。 作为 Squid 管理员,你必须采取额外的小心来保证日志文件安全。 最好的办法是限制访问 Squid 主机的人员的数量。假如这点行不通,那么就要谨慎的检查文件和目录许可,确保 日 志文件不会被非信任的、或未授权的用户访 问。 也可利用 client_netmask 和strip_query_terms指令来保护用户隐私。 前 者让识别 access.log 里的用户困难;后者移除了 URI 查询条件以避免泄露用户私人信息。更多信息见 13.2.4节。 如果想要保持历史数据相当长的时间,你也许可裁减日志来保证日志文件匿名。假如 你仅对哪个 URI 被访问感兴趣, 而 不是谁访问了它们, 就 可从 access.log 里抽取出该域。 这 样也让文件更小,并且减少了隐私违背的风险。另一个技术是随机处理客户端 IP地址。换 句话说,就是创建一个过滤器, 把真正的 IP地址映射到假的地址,前提是同一个真 IP地 址总是映射到同一个假 IP。假如你在使用 RFC 1413身份验证协议或 HTTP认证,也可考虑 保持这些域匿名。 Squid 中文权威指南 255 第第第第14141414章章章章监视监视监视监视SquidSquidSquidSquid 14.114.114.114.1 cache.log cache.log cache.log cache.log 告警 在碰到 Squid 有问题时,应该首先查看 cache.log 里的警告信息。在正常运行时,你可 发现不同的警告或信息, 它 们会或不会表明问题存在。 我 在 13.1节里讲到了 cache.log 的结 构。 这里我重提一些可能在日志文件里见到的警告信息。 在中值响应时间超过限制时, high_response_time_warning 指令让 Squid 打印一条警告。 该值是毫秒级的,默认禁止。假如增加如下行到 squid.conf: high_response_time_warning 1500 如果大于 1分钟的时间范围内的中值响应时间超过 1.5秒, Squid 会发布如下警告: 2003/09/29 03:17:31| WARNING: Median response time is 2309 milliseconds 在设置该指令前,你应 该 对 Squid 的正常响应时间级别 有较好理 解。假 如设置过 低, 会导致很多假报警。 在上述示例里, 意味着一半用户的请求需要花费 2.3秒去完成。 高响 应 时间可能由 本地 程序 产生 ,例 如运行 超出 文件 描述 符; 也可 能是 远程问 题, 例如 拥挤 的 Internet 连接。 high_page_fault_warning 作用类似。 假如每分钟的页面错误次数超过给定限制, 它会 导 致Squid 发布一条警告。 高页面错误率通常意味着 Squid 进程不能完全放在内存, 必须被 交 换到磁盘。 这种交换严重影响了 Squid 的性能, 所以你必须尽快解决问题, 见 16.1.8节的 描 述。 Squid 使用 Unix 的getrusage()函数来 获 取页 面 错 误计 数 。 在某 些 操作 系 统 上( 例 如 Solaris) , 页 面错误计数器表现异常。 这样, high_page_fault_warning 在这些系统上会导致 假 报警。 high_memory_warning 指令也类似于前面提到的报警。在此情况下,它检查 Squid 进程 的size,假如 size 超过了限制,就会在 cache.log 里告警。在某些操作系统上,进 程 size 只 增不降。这样,除非 Squid 关闭,你会经常得到这个警告。 进程 size 来自于如下 3个函数之一: mallinfo( ), mstats( ), 或sbrk( )。 假 如这些函数在 你 的操作系统上不可用,则 high_memory_warning 不能工作。 Squid 中文权威指南 256 Squid 有其他一些硬编码的告警,可在 cache.log 里见到: DNS lookup for 'neighbor.host.name' failed! 在Squid 查询邻居 cache的IP地址失败时,这点会发生。 Squid 大约每小时刷新一次 邻 居的地址。只要邻居的地址不可知, Squid 不会发送会话到那边。 Detected DEAD Sibling: neighbor.host.name/3128/3130 在Squid 不能与某个邻居 cache通信时, 它记录这个消息。例如, 太多连续的 ICP 查询 没有得到响应,这点就会发生。见 10.3.2节的更多信息。 95% of replies from 'neighbor.host.name' are UDP_DENIED 该消息表明邻居 cache拒绝回答 Squid 的查询。 可 能意味着 Squid 发送未经许可的查 询 到邻居 cache。 假如邻居 cache使用地址基础的访问控 制, 并且你近来更改了地址, 那它 们 就不会知道这个更改。在检测到该条件后, Squid 拒绝发送更多查询到邻居 cache。 Probable misconfigured neighbor at 192.168.121.5 若有未经授权的 cache客户端向你发送 ICP 或HTCP 查询, 这 点就会发生。 最 好的处 理 方法就是找到负责这个 cache的组织或个人,询问他们为什么要查询你的 cache。 Forwarding loop detected for: 回想一下,当单个请求遍历 Squid 2次时,就发生了转发循环。请求 的 Via 头部包含了 遍历过的所有代理的列表。 假如 Squid 在Via 列表里检测到了自己的名字, 它发布转发循 环 警告,并将请求直接发送到原始服务器。见 10.2节关于转发循环的解释。 Closing client 192.168.121.5 connection due to lifetime timeout client_lifetime 指令对单个 HTTP 请求的存活期设置一个上限 。当这样的 请求终止时, Squid 发布警告, 它 可能意味着某人正发起长时间连接来滥用 cache, 例 如, 无 穷的 download 目标。 如你所见,caceh.log 仅提供了异常事件的通知。 对 周期性的监控, 还 需要其他工具。 cache 管理器可能是最好的选择,尽管它的接口还不完美。 14.214.214.214.2 Cache Cache Cache Cache 管理 器 译者注: 由 于本节的内容本人从未涉及, 为 避免误导, 请 读者自行阅读原书的该章节。 也 Squid 中文权威指南 257 有可能以后会更新本节内容,请关注本书中文版 release 的web 目录: http://home.arcor.de/jeffpang/squid 14.314.314.314.3 使用SNMPSNMPSNMPSNMP 译者注: 由 于本节的内容本人从未涉及, 为 避免误导, 请 读者自行阅读原书的该章节。 也 有可能以后会更新本节内容,请关注本书中文版 release 的web 目录: http://home.arcor.de/jeffpang/squid 第第第第15151515章章章章服务 加速 模式 服务 加速 模式 服务 加速 模式 服务 加速 模式 15151515.1.1.1.1 概述 假如你已在某台机器上运行了原始服务器,就必须将它移到不同 的 IP地址或 TCP 端 口。例如,可以这样做: (1)在独立的主机上安装 squid;(2)给原始 服务器分配一个新的 IP 地址; (3)将旧的 IP地址分配给 squid。 为 了安全起见,在 squid 和后台服务器通信的链路 上, 可使用私网地址。见图 15-1。 Figure 15-1.How to replace your origin server with Squid Squid 中文权威指南 258 另一个方法是配置 squid 成HTTP 拦截,见第 9章的描述。例如,可以配置离原始服务 器最近的路由器或交换机,拦截 HTTP请求,将其驱向 squid。 假如你资源有限,不能将 squid 运行在独立的系统上,就可以让它随 着 HTTP 服务一 起运行。然而,这 2个应用不能共享相同的 IP地址和端口号。必须将后台 服务绑定在不同 的地址 (例如 127.0.0.1) 或将它移到另一个端口。 看起来改变端口最容易, 但 我推荐改变 IP 地址。 改变端口可能会带来问题。 例 如, 当 后台服务产生错误消息时, 它 可能会泄露错误的 端 口。 更糟的是, 假如服务产生一个 HTTP重定向, 它典型的将非标准端口号追加到 Location URI 后面。 HTTP/1.1 301 Moved Permanently Date: Mon, 29 Sep 2003 03:36:13 GMT Server: Apache/1.3.26 (Unix) Location: http://www.squid-cache.org:81/Doc/ 假如客户端接受到这样的响应,它会发起连接到非标准断口( 81) , 这样就绕过了服务 加速器。 假如你必须让 squid 和后台服务运行在同一主机上, 那最好让后台服务侦听在本 地 回路地址上 (127.0.0.1)。在 apache上,可以这样做: BindAddress 127.0.0.1 Squid 中文权威指南 259 ServerName www.squid-cache.org 一旦你决定如何重新部署原始服务器,下一步就是配置 squid。 15151515.2.2.2.2 配置SquidSquidSquidSquid 技术上,一个单一的配置文 件指令,足 以 让 squid 从cache 代理状态转换到加速状态。 不幸的是, 生活总非如此简单。 因 为许多组织的 web 服务器以不同方法实现, 所以 squid 也 有很多指令要考虑。 15.2.115.2.115.2.115.2.1 http_porthttp_porthttp_porthttp_port 一般 squid 仅对 80端口的 HTTP服务加速。使用 http_port 指令让 squid 侦听在该端口: http_port 80 假如想让 squid 既作 cache代理,又作加速器,那么列出这 2个端口: http_port 80 http_port 3128 你也可以配置客户端发送代理请求到 80端口, 但 我强烈不鼓励那样做。 使 用独立的端 口, 假如以后必要,你可以更容易将 2个服务迁移到不同的主机上。 15.2.215.2.215.2.215.2.2 https_porthttps_porthttps_porthttps_port 可以配置 squid 来处理加密的 HTTP(SSL和TLS) 连 接。 该 功能要求在运行 ./configure 时,激活 --enable-ssl 选项。在该模式 下, squid 解密来自客户端的 SSL/TLS 连接,并将未 加密的请求转发到后台服务器。 https_port 指令有如下格式: https_port [host:]port cert=certificate.pem [key=key.pem] [version=1-4] [cipher=list] [options=list] cert 和key 参数是 OpenSSL 兼容的 证 书和 私 钥 文件 的 路 径。 假 如忽 略 了 key 参数, OpenSSL 库会在证书文件里寻找私钥。 可选的 version 参数指定支持何种 SSL/TLS 协议: 1为自动选择, 2为支持 SSLv2,3为 支持 SSLv3,4为支持 TLSv1。 Squid 中文权威指南 260 可选的cipher 参数是冒号分隔的密码列表。squid 简单的将它传递给 SSL_CTX_set_cipher_list( )函数。更多信息, 请阅读系统中的 ciphers(1) manpage,或试着 运 行: openssl ciphers. 可选 的 options 参数 是 冒 号 分 隔 的 OpenSSL 选项 列 表 。 squid 简单 的 将 它 传 递 给 SSL_CTX_set_options( )函数。 更 多信息, 请 阅读系统中的 SSL_CTX_set_options(3) manpage。 如下是一些 https_port 行的示例: https_port 443 cert=/usr/local/etc/certs/squid.cert https_port 443 cert=/usr/local/etc/certs/squid.cert version=2 https_port 443 cert=/usr/local/etc/certs/squid.cert cipher=SHA1 https_port 443 cert=/usr/local/etc/certs/squid.cert options=MICROSOFT_SESS_ID_BUG 15.2.315.2.315.2.315.2.3 httpd_accel_hosthttpd_accel_hosthttpd_accel_hosthttpd_accel_host 在这里告诉 squid 后台服务器的 IP地址或主机名。假如后台服 务器使用前 面描述的本 地环路地址,那么这样写: httpd_accel_host 127.0.0.1 Squid 会预先将这个值作为要加速的 URI。 它 也会改变 Host 头部的值。 例 如, 假 如客 户 端发起这样的请求: GET/index.html HTTP/1.1 Host: squidbook.org Squid 会将它改变成这个形式: GET http://127.0.0.1/index.html HTTP/1.1 Host: 127.0.0.1 你可以看到,请求不再包含 对 squidbook.org 的任何信息。只要后台服务没有配置成多 域虚拟主机,这样做就不会有问题。 假如想让 squid 使用原始服务器的主机名,那么可将它放在 httpd_accel_host 指令里: httpd_accel_host squidbook.org Squid 中文权威指南 261 这样请求如下: GET http://squidbook.org/index.html HTTP/1.1 Host: squidbook.org 另一个选项是激活 httpd_accel_uses_host_header 指令。这时 squid 对大部分请求,会将 Host 头部插入 URI 里;仅对那些缺少 Host 头部的请求, squid 才使用 httpd_accel_host 值。 当使用主机名时, squid 通过正常途径来查询其 IP地址。因为期望该主机名被解析到 2 个不同的地址(一个是客户端连接到 squid 的地址,另一个是 squid 连接到后台服务器的地 址) , 你应该增加静态的 DNS 接口到系统的 /etc/hosts文件里。例如: 127.0.0.1 squidbook.org 也可以使用重定向器代替。例如,可以编写一个简单的perl 程序,将 http://squidbook.org/...改变为 http://127.0.0.1/... 见11章关于重定向客户请求的具体细节。 httpd_accel_host 指令有 1个特殊值。假如将它 设 为 virtual,在 Host 头部丢失时, squid 将原始服务器的 IP地址插入 URI 里。然而,该功能仅在使用 HTTP拦截时有用。 15.2.415.2.415.2.415.2.4 httpd_accel_porthttpd_accel_porthttpd_accel_porthttpd_accel_port 该指令告诉 squid 后台服务器的端口号。 默认是 80。 不必改变该值,除非后台服务器 运 行在不同端口。如下是示例: httpd_accel_port 8080 假如在多个端口上加速原始服务器,可以将该值设为 0。在该情形下, squid 从Host 头 部里获取端口号。 15.2.515.2.515.2.515.2.5 httpd_accel_uses_host_headerhttpd_accel_uses_host_headerhttpd_accel_uses_host_headerhttpd_accel_uses_host_header 该指令控制 squid 如何决定它插入加 速 URI 里的主机名。假如激活了, 请求里 的 Host 头部值,会优先于 httpd_accel_host 值。 httpd_accel_uses_host_header 指令与后台服务器上运行的虚拟域配合工作。假如后台服 务器仅处理 1个域,那么可禁用它。然而,假如你在加速多个域名,就请打开它: httpd_accel_uses_host_header on 假如激活了 httpd_accel_uses_host_header 指令, 记 得要配置一些本章后面描述的访问 控 Squid 中文权威指南 262 制。为什么要这样做?请考虑如下配置: httpd_accel_host does.not.exist httpd_accel_uses_host_header on 因为大 多 数 请 求 有 Host 头部 , squid 会忽 略 掉 httpd_accel_host 设置 , 很 少 将 does.not.exist 名字插入到 URI 里。那些非 常聪明的假冒 HTTP 请求的人,会让 squid 从加 速模式进入 cache代理模式。假如我知道你正在使用 squid 作为加速器,并且没有正确的访 问控制, 那我能发送这样的请求: GET/index.html HTTP/1.1 Host: www.mrcranky.com 假如你已经激活了 httpd_accel_uses_host_header,并且没有任何基于目的地址的访问控 制,squid 会转发这个请求到 www.mrcranky.com 。 阅读 15.4章, 配 置访问控制, 以 确保 squid 不会与外部原始服务器会话。 15.2.615.2.615.2.615.2.6 httpd_accel_single_hosthttpd_accel_single_hosthttpd_accel_single_hosthttpd_accel_single_host 前面的 httpd_accel_uses_host_header 指令决定 squid 插入 URI 里的主机名, 这 里的指 令 决定 squid 转发它的 cache丢失到哪里。 默 认的 ( httpd_accel_single_host 禁止),squid 转发 cache丢失到 URI 里的主机。 假如 URI 里包含主机名, squid 执行 DNS 查询来获取后台服 务 器的 IP地址。 当激活了 httpd_accel_single_host 时, squid 总是转发 cache 丢失到 httpd_accel_host 里 定义的主机。 换句话 说, URI 里的内容和 Host 头部不会影响到转发决定。 也许激活该指 令 的最好的理由是避免 DNS 查询。简单的将 httpd_accel_host 设置为后 台服务器的 IP地址。 激活它的另一个理由是假如你有其他设备 (负载均衡器,病毒扫描器等)在 squid 和后台 服 务器之间。你可以让 squid 转发请求到这 样的设备,不用对 HTTP请求作任何改变。 注意同时激活 httpd_accel_single_host 和httpd_accel_uses_host_header 是危险的, 可 能 让 攻击者破坏 cache。考虑如下配置: httpd_accel_single_host on httpd_accel_host 172.16.1.1 httpd_accel_uses_host_header on 和这样的 HTTP请求: Squid 中文权威指南 263 GET/index.html HTTP/1.0 Host: www.othersite.com Squid 将请求转发到172.16.1.1 的后台服务器,但存储响应在URI http://www.othersite.com/index.html 下。 既然 172.16.1.1实际上并非 www.othersite.com,squid 现在包含了对该 URI 的伪响应。 假 如激活了 httpd_accel_with_proxy(下一节的),或者 cache 参与了某个层叠, 它 可能对信任用户发布坏的响应。 为 了阻止这样的滥用, 记 得阅读 15.4章。 假如使用了 httpd_accel_single_host 指令,服务端 持久 连接可 能不 能工作 。这 是因 为 squid 存储空闲连接在原始 服务器主 机名下 面,但连 接建立 代码会查找由 httpd_accel_host 值命名的空闲连接。 假如 2个值不同, squid 查找相应的空闲连接会失败。 在超时后, 空闲 连 接关闭, 不 会被 重用。 可 以用 server_persistent_connections 指令 ( 见附录 A) 来 禁止服务 端 持久连接,就避免了这个小问题。 15.2.715.2.715.2.715.2.7 httpd_accel_with_proxyhttpd_accel_with_proxyhttpd_accel_with_proxyhttpd_accel_with_proxy 默认的,无论何 时你 激活 了 httpd_accel_host 指令, squid 进入加速模式 。那 就是说, 它拒绝代理 http 请求, 仅 仅接受加速请求, 就 好像它 真正是原始服务器一样。 squid 也禁 用 了ICP 端口 ( 但不是 HTCP, 如 果你激活它的话) 。 假 如想让 squid 既接受加速请求又接受 代 理请求,请激活这 个指令: httpd_accel_with_proxy on 15151515.3.3.3.3 令人疑惑之处 诚然, 杂 乱的配置让我也疑惑。 让我们换种方法来看它。 实 际使用的配置, 依赖于有 多 少后台服务器,以及需要加速多少原始服务器主机名。让我们考虑如下 4个独立的案例。 15.3.115.3.115.3.115.3.1 一个主机,一个主机名 这是最简单的配置。因为你只有一个主机 和一个主机名, Host 头部就无关紧要。可以 这样做: httpd_accel_host www.example.com httpd_accel_single_host on httpd_accel_uses_host_header off 假如愿意,可以在 httpd_accel_host 后使用 IP地址,尽管它将出现在 access.log 的URI Squid 中文权威指南 264 里。 15.3.215.3.215.3.215.3.2 一个主机,多个主机名 因为有多个虚拟主机的主机名, Host 头部就变得重要。 我 们想让 squid 将它插入转发 URI 里。这样配置: httpd_accel_host www.example.com httpd_accel_single_host on httpd_accel_uses_host_header on 在该情 形 下 , squid 基于 Host 头部 产 生 URI 。假 如 缺 少 Host 头部 , squid 会插 入 www.example.com。假 如愿 意 , 你 可 以 禁 止 httpd_accel_single_host。跟 前面 一 样 , 可 在 httpd_accel_host 后使用 IP地址,以避免 DNS 查询。 15.3.315.3.315.3.315.3.3 多个主机,一个主机名 这点听起来象负载均衡配置。实现它的方法之一是,对多个 IP地址的后台服务器创建 一个 DNS 名字。对每个 cache 丢失, squid 会轮循请求所有后台 地址。在 该情形 下, squid 配置与单主机 /单主机名的情况一样: httpd_accel_host roundrobin.example.com httpd_accel_single_host on httpd_accel_uses_host_header off 唯一不同之处是 httpd_accel_host 名被解析到多个 IP地址。在 BIND zone 文件里, DNS 配置可能看起来如下: $ORIGIN example.com. roundrobin INA 192.168.1.2 INA 192.168.1.3 INA 192.168.1.4 在这样的 DNS 配置里, squid 每次打开到 roundrobin.example.com 的新连接时, 都使 用 列表里的下一个地址。当抵达列表末尾时,又会从头开始。注 意 squid 内在的根据 TTLs来 Squid 中文权威指南 265 缓存 DNS 响应。对每次 DNS 查询,不能依赖于名字服务器以不同顺序返回地址列表。 另一个选择是使用重定向器(见 11章)来选择后台服务器。可以编写一个简单的脚本, 将URI 主机名(例如 roundrobin.example.com)替换成不同的主机名 或 IP地址。如果重定 向器足够智能,它甚至可以基于后台服务器的当前状态来进行选择。使用下列配置: httpd_accel_host roundrobin.example.com httpd_accel_single_host off httpd_accel_uses_host_header off 15.3.415.3.415.3.415.3.4 多个主机,多个主机名 在该情形下,要使用 Host 头部。也要让 squid 基于原始服务器名字(例如,一个 DNS 查询)来选择后台服务器。配置如下: httpd_accel_host www.example.com httpd_accel_single_host off httpd_accel_uses_host_header on 也许你凭错觉将 httpd_accel_host 设为 virtual。然而,除非使用 HTTP 拦截,否则那将 是一个错误。 15.415.415.415.4 访问控制 典型配置的加速器接受来自整个 Internet 的HTTP请求。然而这不意味着, 可以忘记 访 问控制。 你 不应 该 让 squid 接受指向 外 部原 始服 务 器的 请求 。 唯一 的例 外 是当 你激 活 了 httpd_accel_with_proxy 时。 对仅作为加速器的配置, 请 使用目的基础的访问控制。 例如, dst 类型可执行这个任务 : acl All src 0/0 acl TheOriginServer dst 192.168.3.2 Squid 中文权威指南 266 http_access allow TheOriginServer http_access deny All 另外,假如愿意,可使用 dstdomainACL: acl All src 0/0 acl TheOriginServer dstdomain www.squidbook.org http_access allow TheOriginServer http_access deny All 注意激活了 httpd_accel_single_host 某种程度上绕过了访问控制规则。这是因为在 squid 执行了访问控制检测后,原始服务器域(例如 httpd_accel_host 值)才被设置。 若在单个 squid 实例里, 既使用加速模式又使用代理模式,访问控制会变得很麻烦。 你 不能简单的拒绝到外部原始服务器的所有请求。 然 而你能确保外部用户不允许对任意原始 主 机发起代理请求。例如: acl All src 0/0 acl ProxyUsers src 10.2.0.0/16 acl TheOriginServer dst 192.168.3.2 http_access allow ProxyUsers http_access allow TheOriginServer http_access deny All 可以在访问控制规则里使用本地端口号。 它实际上不会真正保护 squid 不被滥用, 但 确 实能保证, 例 如, 用 户代理发送其代理请求到正确的端口。 这 点也让你以后可以方便的将 加 速服务和代理服务分拆到独立的主机上。假设配置 squid 侦听在 80和3128端口,可以使用: acl All src 0/0 acl ProxyPort myport 3128 acl ProxyUsers src 10.2.0.0/16 acl SurrogatePort myport 80 Squid 中文权威指南 267 acl TheOriginServer dst 192.168.3.2 http_access allow ProxyUsers ProxyPort http_access allow TheOriginServer SurrogatePort http_access deny All 不幸 的是,若同时激活了httpd_accel_single_host, httpd_accel_uses_host_header, 和 httpd_accel_with_proxy,则这些访问控制规则不能阻止用户破坏 cache的企图。这是因为有 效的代理请求: GET http://www.bad.site/ HTTP/1.1 Host: www.bad.site 和假的加速请求: GET/ HTTP/1.1 Host: www.bad.site 有同样的访问控制结果,但被转发到不同的服务器。它们有相同的访问控制结果是因 为,在 squid 重写了加速请求后,它有和代理请求相同 的 URI。然而,它们 不会被送到同 一地方。 加 速请求到达由 httpd_accel_host 定义的服务器, 因 为激活了 httpd_accel_single_host。 可以采取步骤来解决这个问题。确保后台 服务器对未知的服 务名(例如, Host 头部指 向非本地服务)产生一个错误。然而,最好不要同时运行 squid 作为加速和代理服务。 15.515.515.515.5 内容协商 近来的 squid 版本支持 HTTP/1.1 Vary 头部。假如后台服务器使用内容协商,这 就是个 好消息。例如,它能依赖于哪种 web 浏览器发起请求( User-Agent 头部) , 或基于用户语 言 参数( Accept-Language 头部) , 来发送不同的响应。 当对某 URI 的响应基于请求行为而变化时,原始(后 台)服务器包含了 一 个 Vary 头 部。该头部包含用于选择变量的请求头部 列表。这些 是 selecting 头部。当 squid 接受到带 有Vary 头部的响应时, 在 它产生内部 cache key 过程中, 会 包含这个 selecting 头部值。这样, 随后而来的带有同样 selecting 头部值的请求会产生 cache命中。 Squid 中文权威指南 268 假如 在运行 ./configure 时,使用了 —enable-x-accelerator-vary 选项, squid 会查找一个 名为 X-Accelerator-Vary 的响应头部。 squid 严格 的把这个头部和 Vary 头部一样对待。 然 而, 因为这是个扩展头部, 它被下游用户代理忽略。它本质上提供一个方法, 用于 squid 和后 台 服务器之间的私有内 容协商。为了使用它,你也必须修改服务应用,以使其在响应里发送 这个头部。 我 不知道该头部在何种情形下有用。 假 如你服务于协商响应, 你 也许该使用标 准 的Vary 头部,以便所有的用户 代理知道什么在进行。 15.615.615.615.6 补充 使用 squid 作为加速器可能改进原始服务器的安全和性能。 然而, 也有一些潜在的消 极 影响。请记住如下事情。 15.6.115.6.115.6.115.6.1 日志 当使用加速器时,原始服务器的访问日志仅包含了来自 squid 的cache丢失。并且,这 些日志文件只记录 了 squid 的IP地址,而不是客户端的。换 句话说, squid 的access.log 才 是所有有用信息的存放之处。 回想一下, squid 默认不使用通用日志文件格式。可以使用 emulate_httpd_log 指令,来 让squid 的access.log 看起来象 Apache的默认日志文件格式。 15.6.215.6.215.6.215.6.2 忽略ReloadReloadReloadReload 大部分浏览器的 reload 按钮产生带 Cache-Control: no-cache 指令的 HTTP 请 求 。 虽然 这 点对客户端缓存代理来说很有用, 但它可能破坏 squid 加速器的性能。 假如后台服务器负 载 很高, 这点尤其明 显。 reload 请求强迫 squid 刷新当前 cache响应, 并从原始服务器重新 获 取新的响应。 假 如原始服务器的响应抵达很慢, squid 会耗费超出正常 数量的文件描述符 和 网络资源。 为了解决这个问题, 可 使用 refresh_pattern 的一个选项。 当 设置了 ignore-reload 选项时 , squid 假装请求没有包含 no-cache 指令。 ignore-reload 选项对加速器来说通常是安全的,尽 管它在技术上确实违背了 HTTP协议。 为了让 squid 忽略所有请求里的 reload,在 squid.conf 里这样写: refresh_pattern . 0 20% 4320 ignore-reload 其他的一种更安全的选择,你可以使 用 reload-into-ims 选项。当请求包含 no-cache 时, 它导致 squid 去验证其 cache响应。 然 而请注意, 这 点仅在响应有 cache验证选项 ( 例如 Last- Squid 中文权威指南 269 Modified 时间戳)时才能工作。 15.6.315.6.315.6.315.6.3 不可cache cache cache cache 的内容 作为加速器, squid 对来自后台服务器的 cache响应,遵从标准 HTTP 头部规范。这意 味着,例如, 某些动态响应可能不被 cache。你也许想使用 refresh_pattern 指令来强迫 cache 这些目标。例如: refresh_pattern \.dhtml$ 60 80% 180 这样的欺骗仅对某些类型的响 应有效,也 就是说,那 些没 有 Last-Modified 或Expires 头部的响应。 squid 默认不 cache这样的响应。然 而,在 refresh_pattern 规则里使用非零的 最小时间, 会让 squid 去cache这些响应, 并 在该数量的时间范围内, 将 响应作为 cache命中 处理。请见 7.7章的细节。 假如后台服务器产生其他类型的不可 cache响应,你也许不能欺骗 squid 来缓存它们。 15.6.415.6.415.6.415.6.4 错误 把squid 作为原始服务器前面的加速器,你应该知道站点访问者有可能见到 squid 产生 的错误消息,而不是原始服务器产生的。 换句话说,你 的 squid 的用法通过某些错误消息 可能会暴露出来。例如,当 squid 解析客户 HTTP 请求失败时,它会返回自己的错误消息, 假如请求不完整或畸形构造,就可能发生 这 种情况。若 squid 因为某些理由不能连接到后 台服务器,它也会返回错误消息。 如果站点调整得好, 可能不必担心 squid 的错误消息。 虽然如此,你也应该经常仔细 观 察access.log,看看有何错误;任何错误,都有可能被你的用户看到。 15.6.515.6.515.6.515.6.5 刷新目标 在操作加速器时, 你 也许发现 PURGE 方式特别有用。 如 果你对服务的内容有良好理 解, 就该知道何时 cache目标必须被刷新。 刷 新目标的技术跟我以前提过的一样。 请 见 7.6章的 细 节。 15.6.615.6.615.6.615.6.6 邻居 尽管我不推荐, 你 仍可以配置 squid 作为加速器, 并 且作为 cache层叠的一部分。 假 如 选择了如此部署,请注意, squid 默认转发 cache丢失到父 cache(而不是后台服务器) 。 假 如这不是你想要的, 请 确保使用 cache_peer_access指令, 以 便对后台服务器的请求不会抵 达 邻居 cache。 Squid 中文权威指南 270 第第第第16161616章章章章调试 和故 障处理 调试 和故 障处理 调试 和故 障处理 调试 和故 障处理 16.116.116.116.1 一些通用问题 在讨论通用 debug 前,我先提起一些经常发生的问题。 16.1.116.1.116.1.116.1.1 "Failed"Failed"Failed"Failed totototo makemakemakemake swapswapswapswap directory"directory"directory"directory" Failed to make swap directory /var/spool/cache: (13) Permission denied 这点发生在你运行 squid -z,并且 squid 的用户 ID没有对 /var/spool 目录的写权限的时 候。记住假如以 root 来启动 squid,并且没有增加 cache_effective_user 行,那么 squid 默认 以nobody 用户运行。解决方法很简单: # chown nobody:nobody /var/spool 16.1.216.1.216.1.216.1.2 "Address"Address"Address"Address alreadyalreadyalreadyalready inininin use"use"use"use" commBind: Cannot bind socket FD 10 to *:3128: Address already in use 这个消息出现在 bind()系统调用失败时, 因为请求端口已经被其他应用程序所打开。 通 常, 若已有一个 squid 在运行, 而又试图启动第 2个squid 实例, 就会发生这种情况。 假如 你 见到这个错误消息,请使用 ps 来观察是否 squid 已经在运行。 Squid 使用 SO_REUSEADDR socket 选项,以便 bind()调用总能成功,即使仍有一些残 余的 socket 位于 TIME_WAIT 状态。 若该消息出现,尽管 squid 没有在运行, 但你的操作 系 统可能在处理这个问题上有 bug。重启操作系统是解决问题的一个方法。 另一个可能性是端口 ( 例如 3128) 当 前已被其他应用程序使用。 假如你怀疑这点, 就 可 使用 lsof 程序来发现哪个应用正在该端口上侦听。 FreeBSD 用户能使用 sockstat 代替。 Squid 中文权威指南 271 16.1.316.1.316.1.316.1.3 "Could"Could"Could"Could notnotnotnot determinedeterminedeterminedetermine fullyfullyfullyfully qualifiedqualifiedqualifiedqualified hostname"hostname"hostname"hostname" FATAL: Could not determine fully qualified hostname. Please set 'visible_hostname' 假如 squid 不能识别它自己的完整可验证域名,就会报这个错。如下 是 squid 使用的算 法: • 1) 假如你将 squid 的HTTP 端口绑定在指定的接口地址上, squid 试图对该地 址执行反向 DNS 查询。假如成功,查询答案就被用上。 • 2) Squid 调用 gethostname( )函数,然后使用 gethostbyname( )函数,试着解析 其IP地址。假如成功, squid 使用后者函数返回的官方主机名串。 假如以上 2项技术都不能工作, squid 以前面提到的致命错误消息退出。 在 该情形下, 必 须使用 visible_hostname 指令来告诉 squid 它的主机名。例如: visible_hostname my.host.name 16.1.416.1.416.1.416.1.4 "DNS"DNS"DNS"DNS namenamenamename lookuplookuplookuplookup teststeststeststests failed"failed"failed"failed" 默认情况下, squid 在启动前执行一 些 DNS 查询。这点确保你 的 DNS 服务器可到达, 并且运行正确。假如测试失败,可在 cache.log 或syslog 里见到如下消息: FATAL: ipcache_init: DNS name lookup tests failed 假如 你 在 内 网 里 使 用 squid ,squid 可能 不能查询到它的标准主机名列表。可使用 dns_testnames 指令来指定你自己的主机名。 只 要接受到响应, squid 就会认为 DNS 测试成 功。 假如你想完全跳过 DNS 测试,简单的在启动 squid 时,使用 -D命令行选项: % squid -D... 16.1.516.1.516.1.516.1.5 "Illegal"Illegal"Illegal"Illegal charactercharactercharactercharacter inininin hostname"hostname"hostname"hostname" urlParse: Illegal character in hostname 'super_bikes.tripod.com' 默认情况下, squid 检查 URL 的主机名部分的字符, 假 如它发现了非标准的字符, squid 会抱怨。 参考 RFC 1034和1035, 名字必须由字母 A-Z,数字 0-9, 以及短横线 (-)组成。 下划 线 (_)是最有问题的字符之一。 Squid 验证主机名是因为,在某些情形下, DNS 对畸形字符的解析会很困难。例如: % host super_bikes.tripod.com Squid 中文权威指南 272 super_bikes.tripod.com has address 209.202.196.70 % ping super_bikes.tripod.com ping: cannot resolve super_bikes.tripod.com: Unknown server error Squid 事先检查主机名, 这 好过于以后返回 Unknown server error 消息。 然 后它会告诉 用 户主机名包含畸形字符。 某些DNS 解析器确实能处理下划线和其他非标准字符。 假 如你想让 squid 不检查主 机 名,请在运行 ./configure 时,使用 —disable- hostname-checks 选项。假如你允许下划线作为 唯一的例外,那么使用 —enable-underscores 选项。 16.1.616.1.616.1.616.1.6 "Running"Running"Running"Running outoutoutout ofofofof filedescriptors"filedescriptors"filedescriptors"filedescriptors" WARNING! Your cache is running out of filedescriptors 上述消息出现在 squid 用完了所有可用文件描述符时。 假如这点发生在正常条件下, 就 有必要增加内核的文件描述符限制,并且重新编译 squid。请见 3.3.1章。 假如 squid 成为了拒绝服务攻击的目标, 那也会见到这条消息。 某些人可能有意或无 意 的,同时对 squid 发送成百上千条请求。在这种情形下, 可以增加一条包过滤规则,阻止 来 自恶意地址的 TCP 进入连接。 假如攻击是分布式的, 或 使用假冒源地址, 就很难阻止它们 。 转发循环(见 10.2章)也可能耗尽 squid 的所有文件描述符,但仅仅发生在 squid 不能 检测到死循环时。 Via 头部包含了某个请求遍历过的所有代理的 主机名。 squid 在头部里查 找它自己的主机名,假如发现了, 就报告这个循环。假如因为某些理由, Via 头部从外出 或 进入 HTTP请求里过滤掉 了, squid 就不能检测到循环。 在 该情形下, 所有文件描述符被 循 环遍历 squid 的同一请求迅速耗完。 16.1.716.1.716.1.716.1.7 "icmpRecv:"icmpRecv:"icmpRecv:"icmpRecv: ConnectionConnectionConnectionConnection refused"refused"refused"refused" 假如 pinger 程序没有正确的安装,可见到下列消息: icmpRecv: recv: (61) Connection refused 不过看起来更象是因为没有打开 ICMP socket 的权限, pinger 立刻退出了。因为该进程 未在运行,当 squid 试图与它会话时,会接受到 I/O错误。为了解决该问题,请到源代码目 录以 root 运行: # make install-pinger 假如成功,你可见到 pinger 程序有下列文件属主和许可设置: Squid 中文权威指南 273 # ls -l /usr/local/squid/libexec/pinger -rws--x--x 1 root squid 140728 Sep 16 19:58 /usr/local/squid/libexec/pinger 16.1.816.1.816.1.816.1.8 在运行一段时间后, SquidSquidSquidSquid变慢了 看起来更象 squid 与其他进程,或与它自己,在竞争系统中的内存。当 squid 进程的内 存不再充足时,操作系统被迫从交换空间进行内存读写。这对 squid 的性能有强烈影响。 为了证实这个想法,请使用 top 和ps 等工具检查 squid 的进程大小。也检查 squid 自己 的页面错误计数器, 见 14.2.1.24章的描述。 一旦你已确认内存耗费是问题所在, 请执行下 列 步骤来减少 squid 的内存使用: • 1. 减少 cache_mem 值,见附录 B。 • 2. 关掉内存池,用该选项: memory_pools off 3. 通过降低一个或多个 cache目录的 size,减少磁盘 cache大小。 16.1.916.1.916.1.916.1.9 调试访问控制 假如 访问控制不能正确工作,如下是一些有用帮助。编辑squid.conf 文件 , 设 置 debug_options 行如下: debug_optionsALL,1 33,2 然后,重配置 squid: % squid -k reconfigure 现在,对每个客户端请求以及每个响应, squid 都写一条消息到 cache.log。该消息包含 了请求方式, URI, 是 否请求 /响应被允许或拒绝, 以 及与之匹配的最后 ACL 的名字。 例如 : 2003/09/29 20:22:05| The request GET http://images.slashdot.org:80/topics/topicprivacy.gif is ALLOWED, because it matched 'localhost' 2003/09/29 20:22:05| The reply for Squid 中文权威指南 274 GET http://images.slashdot.org/topics/topicprivacy.gif is ALLOWED, because it matched 'all' 知道 ACL 的名字,并非总能知道相应 的 http_access行,但也相当接近了。假如 必要, 可以复制 acl 行, 并 给予它们唯一的名字, 以 便给定的 ACL 名字仅仅出现在一个 http_access 规则里。 16.216.216.216.2 通过cache.log cache.log cache.log cache.log 进行调试 从13.1章已了解到, cache.log 包含了不同的操作消息, squid 认为这些消息足够重要, 从而告诉了你。 我 们也将这些作为 debug 消息考虑。 可 以使用 debug_options 指令来控制 出 现在 cache.log 里的消息的冗长度。通过增加 debug 等级,可以见到更详细的消息,有助于 理解 squid 正在做什么。例如: debug_optionsALL,1 11,3 20,3 在squid 源代码里的每个 debug消息有 2个数字特征:1个节和 1个 等 级 。 节范 围 从 0到100, 等级范围从 0到10。 通 常来说, 节号对应着源代码的组成 成分。 换 句话说, 在单一源文件 里 的所有消息, 有相同的节号。 在 某些情形下, 多个文件使用同一 debug 节, 这意味着某个 源 文件变得太大,从而被拆分成多个 小块。 每个源文件的顶部有一行,用于指示 debug 节。它看起来如此: *DEBUG: section 9 File Transfer Protocol (FTP) 我不指望你通过查看源文件来查找节号,所有相关信息定义在表 16-1里。 Table 16-1. Debugging section numbers for the debug_options directive Nu mber Description Source file(s) 0 Client Database client_db.c Squid 中文权威指南 275 1 Startup and Main Loop main.c 2 Unlink Daemon unlinkd.c 3 Configuration File Parsing cache_cf.c 4 Error Generation errorpage.c 5 Socket Functions comm.c 5 Socket Functions comm_select.c 6 Disk I/O Routines disk.c 7 Multicast multicast.c 8 Swap File Bitmap filemap.c 9 File Transfer Protocol (FTP) ftp.c 10 Gopher gopher.c 11 Hypertext Transfer Protocol (HTTP) http.c 12 Internet Cache Protocol icp_v2.c 12 Internet Cache Protocol icp_v3.c 13 High Level Memory Pool Management mem.c Squid 中文权威指南 276 14 IP Cache ipcache.c 15 Neighbor Routines neighbors.c 16 Cache Manager Objects cache_manager.c 17 Request Forwarding forward.c 18 Cache Manager Statistics stat.c 19 Store Memory Primitives stmem.c 20 Storage Manager store.c 20 Storage Manager Client-Side Interface store_client.c 20 Storage Manager Heap-Based Replacement repl/heap/store_heap_replace ment.c 20 Storage Manager Logging Functions store_log.c 20 Storage Manager MD5 Cache Keys store_key_md5.c 20 Storage Manager Swapfile Metadata store_swapmeta.c 20 Storage Manager Swapin Functions store_swapin.c 20 Storage Manager Swapout Functions store_swapout.c Squid 中文权威指南 277 20 Store Rebuild Routines store_rebuild.c 21 Misc Functions tools.c 22 Refresh Calculation refresh.c 23 URL Parsing url.c 24 WAIS Relay wais.c 25 MIME Parsing mime.c 26 Secure Sockets Layer Proxy ssl.c 27 Cache Announcer send-announce.c 28 Access Control acl.c 29 Authenticator auth/basic/auth_basic.c 29 Authenticator auth/digest/auth_digest.c 29 Authenticator authenticate.c 29 NTLMAuthenticator auth/ntlm/auth_ntlm.c 30 Ident (RFC 1413) ident.c 31 Hypertext Caching Protocol htcp.c Squid 中文权威指南 278 32 Asynchronous Disk I/O fs/aufs/async_io.c 33 Client-Side Routines client_side.c 34 Dnsserver Interface dns.c 35 FQDN Cache fqdncache.c 37 ICMP Routines icmp.c 38 Network Measurement Database net_db.c 39 Cache Array Routing Protocol carp.c 40 Referer Logging referer.c 40 User-Agent Logging useragent.c 41 Event Processing event.c 42 ICMP Pinger Program pinger.c 43 AIOPS fs/aufs/aiops.c 44 Peer Selection Algorithm peer_select.c 45 Callback Data Registry cbdata.c 45 Callback Data Registry leakfinder.c Squid 中文权威指南 279 46 Access Log access_log.c 47 Store COSS Directory Routines fs/coss/store_dir_coss.c 47 Store Directory Routines fs/aufs/store_dir_aufs.c 47 Store Directory Routines fs/diskd/store_dir_diskd.c 47 Store Directory Routines fs/null/store_null.c 47 Store Directory Routines fs/ufs/store_dir_ufs.c 47 Store Directory Routines store_dir.c 48 Persistent Connections pconn.c 49 SNMP Interface snmp_agent.c 49 SNMP Support snmp_core.c 50 Log File Handling logfile.c 51 File Descriptor Functions fd.c 52 URN Parsing urn.c 53 AS Number Handling asn.c 54 Interprocess Communication ipc.c Squid 中文权威指南 280 55 HTTP Header HttpHeader.c 56 HTTP Message Body HttpBody.c 57 HTTP Status-Line HttpStatusLine.c 58 HTTP Reply (Response) HttpReply.c 59 Auto-Growing Memory Buffer with printf MemBuf.c 60 Packer: A Uniform Interface to Store Like Modules Packer.c 61 Redirector redirect.c 62 Generic Histogram StatHist.c 63 Low Level Memory Pool Management MemPool.c 64 HTTP Range Header HttpHdrRange.c 65 HTTP Cache Control Header HttpHdrCc.c 66 HTTP Header Tools HttpHeaderTools.c 67 String String.c 68 HTTP Content-Range Header HttpHdrContRange.c Squid 中文权威指南 281 69 HTTP Header: Extension Field HttpHdrExtField.c 70 Cache Digest CacheDigest.c 71 Store Digest Manager store_digest.c 72 Peer Digest Routines peer_digest.c 73 HTTP Request HttpRequest.c 74 HTTP Message HttpMsg.c 75 WHOIS Protocol whois.c 76 Internal Squid Object handling internal.c 77 Delay Pools delay_pools.c 78 DNS Lookups; interacts with lib/rfc1035.c dns_internal.c 79 Squid-Side DISKDI/O Functions fs/diskd/store_io_diskd.c 79 Storage Manager COSS Interface fs/coss/store_io_coss.c 79 Storage Manager UFS Interface fs/ufs/store_io_ufs.c 80 WCCP Support wccp.c 82 External ACL external_acl.c Squid 中文权威指南 282 debug 等级这样分配:重要消息有较低值,非重 要消息有较高值。 0等级是非常重要的 消息, 10等级是相对不紧要的消息。 另 外, 关于等级其实并没有严格的向导或要求。 开 发 者 通常自由选择适应的 debug 等级。 debug_options 指令决定哪个消息出现在 cache.log,它的语法是: debug_options section,level section,level ... 默认设置是 ALL,1,这意味着 squid 会将所有等级是 0或1的debug 消息打印出来。假 如 希望 cache.log 里出现更少的 debug 消息,可设置 debug_options 为ALL,0。 假如 想观察某个组件的其他debug 信息 ,简单的将相应的节号和等级增加到 debug_options 列表的末端。例如,如下行对 FTP服务端代码增加了等级 5的debug: debug_optionsALL,1 9,5 如同其他配置指令一样,可以改变 debug_options,然后给 squid 发送重置信号: % squid -k reconfigure 注意 debug_options 参数是按顺序处理的, 后 来的值会覆盖先前的值。 假 如使用 ALL 关 键字,这点尤其要注意。考虑如下示例: debug_options 9,5 20,9 4,2 ALL,1 在该情形下, 最 后的值覆盖了所有先前的设置, 因为 ALL,1对所有节设置了 debug 等级 为1。 选择合适的 debug 节号和等级有时非常困难,尤其是 对 squid 新手而言。许多更详细 的debug 消息仅对 squid 开发者和熟悉源代码的用户有意义。 无 经验的 squid 用户会发现 许 多debug 消息无意义和不可理解。进一步的说, 假如 squid 相对忙的话,你可能对某个特 殊 请求或事件进行独立 debug 有困难。 假 如你能一次用一个请求来测试 squid, 那 么高的 debug 等级通常更有用。 若以高 debug 等级来运行 squid 较长时间,需 要特别谨慎。假如 squid 繁忙, cache.log 83 SSL Accelerator Support ssl_support.c 84 Helper Process Maintenance helper.c Squid 中文权威指南 283 增长非常快, 并 可能最终耗尽它的分区的剩余空间。 假如这点发生, squid 以致命消息退出 。 另一个关 注点是性能可能下降明显。因为有大量的 debug 消息, squid 要耗费许多 CPU 资 源来格式化和打印字符串。将所有 debug 消息写往 cache.log,也浪费了大量的磁盘带宽。 16.316.316.316.3 CoredumpCoredumpCoredumpCoredump,断 点, 和堆栈 跟踪 假如不幸, squid 可能在运行时遭遇致命错误。 这类型的错误来自 3个风格: 断点, 总 线 错误,和异常分片。 断点是源代码里的正常检测。 它 是一个工具, 被 开发者用来确认在处理某事情前, 相 应 的条件总为真。假如 条件为假 ,程序 退出并创 建一 个 core 文件,以便开发者能 分析形势。 如下是个典型的示例: int some_array[100]; Void some_func(int idx){ ... assert(idx < 100); some_array[idx]++; ...} 这里, 断 点确保数组索引的值位于数组范围内。 假 如去访问大于或等于 100的数组元素 , 就会遇到错误。假如不知何故, idx 的值不小于 100,程序运行时会打印如下消息: assertion failed: filename.c:123: "idx < 100" 假如这点发生在 squid 上, 就可在 cache.log 里见到 "assertion failed"消息。 另外, 操 作 系 统会创建一个 core 文件, 这 对事后分析有用。 在 本节结尾, 我会解释如何去处理 core 文件 。 总线错误是: 由 于处理器检测到其总线上的异常条件, 会 引发机器语言指令执行时致 命 失败。 当 处理器试图操作非连续的内存地址时, 通 常会发生这种错误。 在 64位处理器系统 上 可能更容易见到总线错误,例如 Alpha 和某些 SPARCCPU。幸运的是,它们容易修复。 异常分片错误不幸的更常见, 且 有时难以修复。 SEGV 通常发生在进程试图访问无效 内 存区域时(可能是个 NULL 指针,或超出进程空间之外的内存地址) 。当 bug 原因和 SEGV 影响在不同时间呈现时,它们特别难于捕获到。 Squid 中文权威指南 284 Squid 默认捕获总线错误和异常分片, 当 它们发生时, squid 试图执行一个 clean shutdown (清理关闭) 。 可在 cache.log 里见到类似的语句: FATAL: Received Bus Error...dying. 2003/09/29 23:18:01| storeDirWriteCleanLogs: Starting... 大多数情形下, squid 能够写 swap.state文件的 clean 版本。 在 退出前, squid 调用 abort() 函数来创建 core 文件。 core 文件可以帮助你或其他开发者来捕获和修复 bug。 在错误发生时马上创建 core 文件, 而 不是先调用 clean shutdown 过程, 这 样更利于调 试。 使用 -C命令行选项,可以告诉 squid 不去捕获总线错误和异常分片: % squid -C... 注意某些操作系统使用文件名 core, 而另外一些优先考虑进程名 ( 例如 squid.core)。一 旦找到 core 文件,请使用调试器来进行堆栈跟踪。 gdb 是GNU 调试器 --GNUC编译器的 配 套工具。 假如没有 gdb, 可试着运行 dbx 或adb 代替。 如下显示如何使用 gdb 来进行堆栈 跟 踪: % gdb /usr/local/squid/sbin/squid /path/to/squid.core ... Core was generated by 'squid'. Program terminated with signal 6,Abort trap.... 然后,敲入 where来打印堆栈轨迹: (gdb) where #0 0x28168b54 in kill () from /usr/lib/libc.so.4 #1 0x281aa0ce in abort () from /usr/lib/libc.so.4 #2 0x80a2316 in death (sig=10) at tools.c:301 #3 0xbfbfffac in ??() #4 0x80abe0a in storeDiskdSend (mtype=4, sd=0x82101e0, id=1214000, sio=0x9e90a10, size=4096, offset=-1, shm_offset=0) Squid 中文权威指南 285 at diskd/store_io_diskd.c:485 #5 0x80ab726 in storeDiskdWrite (SD=0x82101e0, sio=0x9e90a10, buf=0x13e94000 "...", size=4096, offset=-1, free_func=0) at diskd/store_io_diskd.c:251 #6 0x809d2fb in storeWrite (sio=0x9e90a10, buf=0x13e94000 "...", size=4096, offset=-1, free_func=0) at store_io.c:89 #7 0x80a1c2d in storeSwapOut (e=0xc5a7800) at store_swapout.c:259 #8 0x809b667 in storeAppend (e=0xc5a7800, buf=0x810f9a0 "...", len=57344) at store.c:533 #9 0x807873b in httpReadReply (fd=134, data=0xc343590) at http.c:642 #10 0x806492f in comm_poll (msec=10) at comm_select.c:445 #11 0x8084404 in main (argc=2, argv=0xbfbffa8c) at main.c:742 #12 0x804a465 in _start () 你可见到, 堆 栈轨迹打印了每个函数的名字, 它的参数, 以 及源代码文件名和行数。 当 捕获 bug 时, 这 些信息特别有用。 然而在某些情形下, 这 些还不够。 可能要求你在调试器 里 执行其他命令,例如打印来自某个函数的变量的值: (gdb) frame 4 #4 0x80abe0a in storeDiskdSend (mtype=4, sd=0x82101e0, id=1214000, sio=0x9e90a10, size=4096, offset=-1, shm_offset=0) at diskd/store_io_diskd.c:485 485 x = msgsnd(diskdinfo->smsgid, &M, msg_snd_rcv_sz, IPC_NOWAIT); (gdb) set print pretty Squid 中文权威指南 286 (gdb) print M $2 = { mtype = 4, id = 1214000, seq_no = 7203103, callback_data = 0x9e90a10, size = 4096, offset = -1, status = -1, shm_offset = 0 } 在报告了某个 bug 后,请保留 core 文件一些天,可能还需要从它获取其他信息。 16.3.116.3.116.3.116.3.1 不能找 到 core core core core 文件? core 文件写在进程的当前目录。 squid 在启动时默认不改变其当前目录。这样你的 core 文件(如果有的话) , 会 写在启动 squid 的目录。假如文件系统没有 足够的自由空间,或 进 程属主没有对该目录的写权限, 就 无法产生 core文 件 。 可以 使 用 coredump_dir指令来让 squid 使用指定的 coredump 目录 --位于其他地方的有充足自由空间和完全权限的目录。 进程资源限制也会阻止产生 core 文件。 进 程限制参数之一是 coredump 文件的大小。 大 部分操作系统默认设置这个值为 "无限 "。 在 当前 shell 里使用 limits 或ulimit 命令, 可 以检 查 当前限制。然而 请注意,你的 shell 的限制可能不同于 squid 的进程限制,特别是 当 squid 随系统启动而自动启动时。假如怀疑进程限制阻止了 core 文件的产生, 试试这样: csh% limit coredumpsize unlimited csh% squid -NCd1 在FreeBSD 上,某个sysctl 参数控制了操作系统对调用了 setuid()或setgid()函数的进 程, 是否产生 core 文件。 假 如以 root 启动, squid 会用到这些函数。 这 样为了得到 coredump,必 须告诉内核创建 core 文件,用这个命令: Squid 中文权威指南 287 # sysctl kern.sugid_coredump=1 请见 sysctl.conf 的manpage,关于在系统启动时如何自动设置变量的信息。 16.416.416.416.4 重现 问题 有时候可能遇到这样的问题:某个请求, 或原始服务器看起 来不能 与 squid 协调工作。 可以使用下面的技术来确定问题在 于 squid,客户端,或原始服务器。技巧就是捕 获 HTTP 请求,然后用不同的方法响应它,直到你验证了问题。 捕获 HTTP 请求意味着获取 除 了 URL 外的更多信息, 包括请 求方式 , HTTP 版本号, 和所有请求头部。捕获请求的一个方法是,短期激活 squid 的完整 debug 模式。在 squid 主 机上,敲入: % squid -kdebug 然后,到web 浏览器上发布请求。 squid 几乎会立刻接受到请求。 在 若干秒后, 回到 squid 主机,并发布同样的命令: % squid -kdebug 现在 cache.log 文件包含了上述客户端的请求。 假如 squid 繁忙, cache.log 会包含大量 的 请求,所以你必须查找它。它看起来如下: 2003/09/29 10:37:40| parseHttpRequest: Method is 'GET' 2003/09/29 10:37:40| parseHttpRequest: URI is 'http://squidbook.org/' 2003/09/29 10:37:40| parseHttpRequest: Client HTTP version 1.1. 2003/09/29 10:37:40| parseHttpRequest: req_hdr = { User-Agent: Mozilla/5.0 (compatible; Konqueror/3) Pragma: no-cache Cache-control: no-cache Accept: text/*, image/jpeg, image/png, image/*, */* Accept-Encoding: x-gzip, gzip, identity Squid 中文权威指南 288 Accept-Charset: iso-8859-1, utf-8;q=0.5, *;q=0.5 Accept-Language: en Host: squidbook.org 注意 squid 把首行元素分开打印,必须手工组合它们如下: GET http://squidbook.org/ HTTP/1.1 捕获完整请求的另一个方法是使用工具例如netcat 或socket (http://www.jnickelsen.de/socket/ )。启动 socket 程序侦听在某个端口 ,然后配 置浏览 器使用 该端口作为代理地址。当再次发起请求时, socket 打印出 HTTP请求: % socket -s 8080 GET http://squidbook.org/ HTTP/1.1 User-Agent: Mozilla/5.0 (compatible; Konqueror/3) Pragma: no-cache Cache-control: no-cache Accept: text/*, image/jpeg, image/png, image/*, */* Accept-Encoding: x-gzip, gzip, identity Accept-Charset: iso-8859-1, utf-8;q=0.5, *;q=0.5 Accept-Language: en Host: squidbook.org 最后,还可以使用网络包分析工具例如 tcpdump 或ethereal。使用 tcpdump 捕获到一些 包后,可以使用 tcpshow 来查看它们: # tcpdump -w tcpdump.log -c 10 -s 1500 port 80 # tcpshow-noHostNames -noPortNames < tcpdump.log | less ... Packet 4 Squid 中文权威指南 289 TIME: 08:39:29.593051 (0.000627) LINK: 00:90:27:16:AA:75 -> 00:00:24:C0:0D:25 type=IP IP: 10.0.0.21 -> 206.168.0.6 hlen=20 TOS=00 dgramlen=304 id=4B29 MF/DF=0/1 frag=0 TTL=64 proto=TCP cksum=15DC TCP: port 2074 -> 80 seq=0481728885 ack=4107144217 hlen=32 (data=252) UAPRSF=011000 wnd=57920 cksum=EB38 urg=0 DATA:GET/ HTTP/1.0. Host: www.ircache.net. Accept: text/html, text/plain, application/pdf, application/ postscript, text/sgml, */*;q=0.01. Accept-Encoding: gzip, compress. Accept-Language: en. Negotiate: trans. User-Agent: Lynx/2.8.1rel.2 libwww-FM/2.14.. 注意 tcpshow 按数据里的新行字符为周期来进行打印。 一旦捕获到了某个请求, 就 将它存到文件。 然 后可以使用 netcat 或socket 来让它重新 通 过squid: % socket squidhost 3128 < request | less 假如响应看起来正常, 问 题可能在于用户代理。 否 则, 可 以改变不同事情来孤立问题 。 例如,假如你看到一些古怪的 HTTP头部,那就从请求里删除它们,然后再试 一次。让请 求直接 到 达原 始 服 务器 , 而 不是 经 过 squid ,这样 做 也可 调 试 。方 法 就 是从 请 求里 删 除 http://host.name/,并将请求发送到原始 服务器: % cat request GET/ HTTP/1.1 Squid 中文权威指南 290 User-Agent: Mozilla/5.0 (compatible; Konqueror/3) Pragma: no-cache Cache-control: no-cache Accept: text/*, image/jpeg, image/png, image/*, */* Accept-Encoding: x-gzip, gzip, identity Accept-Charset: iso-8859-1, utf-8;q=0.5, *;q=0.5 Accept-Language: en Host: squidbook.org % socket squidbook.org 80 < request | less 以这种方式使用 HTTP 时,请参考 RFC 2616和Oreilly的HTTP:The Definitive Guide 这 本书。 16.516.516.516.5 报告BugBugBugBug 假如你的 squid 版本已经有几个月未更新了, 在报告 bug 前你应该更新它。 因为其他 人 可能也注意了同样的 bug,并且它已被修复。 假如你发现了 squid 的合理 bug, 请将 它 填 入 到 squid 的bug 跟踪数据库:http://www.squid- cache.org/bugs/ 。它当前是个 "bugzilla"数据库, 需 要你创建一个帐号。当 bug 被squid 开发 者处理了时,你会接到更新通知。 假如 你 对 报 告 bug 很陌 生,请先花时间阅读Simon Tatham 写的 "How to Report Bugs Effectively" (http://www.chiark.greenend.org.uk/~sgtatham/bugs.html )。 当报告 bug 时,确认包含下列信息: • 1) Squid 版本号。假如 bug 发生在不止一个版本上,就也要写上其他版本号。 • 2) 操作系统名字和版本。 • 3) bug 每次都发生,还是偶尔发生。 Squid 中文权威指南 291 • 4) 所发生事情的精确描述。 类 似于 "它不能工作 ","请求失败 "之类的语句, 本 质上对 bug 修复者无用。记得要非常详细。 • 5) 对断点,总线错误,或异常分片的堆栈跟踪。 记住 squid 开发者通常是无报酬的义务劳动, 所以要有耐心。 严重 bug 比小问题享有 更 高的解决优先级。

下载文档,方便阅读与编辑

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 20 金币 [ 分享文档获得金币 ] 3 人已下载

下载文档

相关文档