为了编译squid,你需要一个ANSI C 编译器。不要被ANSI 字眼吓倒。假如你已经有一个编译器,它顺从ANSI 指令,那么也一样。GNU
C 编译器(gcc)是很好的选择,它被广泛使用。大部分操作系统在其标准安装中附带了C 编译器,不过Solaris 和HP-UX
除外。假如你使用这样的操作系统,那可能没有安装编译器。
在下载完源代码后,你需要在某个目录解开它。具体哪个目录无关紧要。你能解开squid在你的家目录或任何其他地方,大概需要20M 的自由磁盘空间。我个人喜欢用/tmp。使用tar 命令来展开源代码目录:
% cd /tmp
% tar xzvf /some/where/squid-2.5.STABLE4-src.tar.gz
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
0 calls to protocol drain routines
正常来说,该过程很顺利,你可以见到大量的滚动行。
你也许见到一些编译器警告。大多数情况下,可以安全的忽略这些。假如这些警告非常多,并且一些看起来非常严重,请将它们报告给开发者,在第16.5 章中有描述。
假如编译过程没有错误,你可以转移到下一节,描述如何安装你刚才编译的程序。
为了验证编译是否成功,你可以再次运行make。你将看到如下输出:
% make
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...
另一个技术是`touch config.status`文件,它更新了该文件的时间戳。这导致make在编译源代码之前,重新运行./configure脚本:
% touch config.status
% make
如果增加或删除./configure选项,你必须重新敲入完整的命令行。假如你记不住以前的选项,请查看config.status文件的顶部。例如:
% head config.status
#! /bin/sh
# Generated automatically by configure.
# Run this file to recreate the current configuration.
Squid 中文权威指南 16
# 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.
默认的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
请将这些行放在正确的位置。http_access 的顺序非常重要,但是acl 行的顺序你不必介意。你也该注意默认的配置文件包含了一些重要的访问控制,你不应该改变或删除它们,除非你完全理解它们的意义。在你第一次编辑squid.conf 文件时,请看如下注释:
# INSERT YOUR OWN RULE(S) HERE TO ALLOW ACCESS FROM YOUR CLIENTS
你将看到类似于以下的输出:
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
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
假如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
当你指定掩码时,squid 会检查你的工作。如果你的掩码在IP 地址的非零位之外,squid会告警。例如,下列行导致告警:
acl Foo src 127.0.0.1/8
aclParseIpData: WARNING: Netmask masks away part of the specified IP in 'Foo'
squid 以一种叫做splay tree 的数据结构在内存里存储IP 地址ACL (
请见)。splay tree
有一些有趣的自我调整的特性,其中之一是在查询发生时,列表会自动纠正它自己的位置。当某个匹配元素在列表里发现时,该元素变成新的树根。在该方法中,最
近参考的条目会移动到树的顶部,这减少了将来查询的时间。
它导致squid 在cache.log 里打印警告:
WARNING: '1.2.3.4' is a subnetwork of '1.2.3.0/255.255.255.0'
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 the ACL named 'Foo'
域名匹配可能让人迷惑,所以请看第二个例子以便你能真正理解它。如下是两个稍微不同的ACL:
acl A dstdomain foo.com
acl B dstdomain .foo.com
用户对的请求匹配ACL B,但不匹配A。ACL A 要求严格的字符串
匹配,然而ACL B 里领头的点就像通配符。
另外,用户对的请求同时匹配A 和B。尽管在URL 主机名里的foo.com前面没有字符,但ACL B 里领头的点仍然导致一个匹配。
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 the ACL named 'Foo'
对该匹配规则来说,请求必须匹配ACL1,ACL2,ACL3 中的任何一个。假如这些ACL中的任何一个不匹配请求,squid 停止搜索该规则,并继续处理下一条。对某个规则来说,将最少匹配的ACL 放在首位,能使效率最佳。考虑如下示例:
acl A method http
acl B port 8080
http_access deny A B
该http_access 规则有点低效,因为A ACL 看起来比B ACL 更容易匹配。反转顺序应该更好,以便squid 仅仅检查一个ACL,而不是两个:
http_access deny B A
人们易犯的典型错误是编写永不正确的规则。例如:
acl A src 1.2.3.4
acl B src 5.6.7.8
http_access allow A B
该规则永不正确,因为某个源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 在访问列表里找到匹配规则时,搜索终止。假如没有访问规则导致匹配,默认动作是列表里最后一条规则的取反。例如,考虑如下简单访问配置:
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
为了进一步测试访问控制,你需要安装一个用于测试的squid。容易做到的方法是,编译另一份squid 到其他$prefix 位置。例如:
% tar xzvf squid-2.5.STABLE4.tar.gz
% cd squid-2.5.STABLE4
% ./configure --prefix=/tmp/squid ...
% make && make install
你也许考虑制订一项cron,定期检查ACL,以发现期望的行为,并报告任何异常。如下是可以起步的示例shell 脚本:
#!/bin/sh
set -e
TESTHOST=""
# make sure Squid is not proxying dangerous ports
#
ST=`squidclient '' | 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 '' | 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
ST=`squidclient -l $EXT_ADDR '' | head -1 | awk '{print $2}'`
if test "$ST" != 403 ; then
echo "Squid allowed request from external address $EXT_ADDR"
fi
exit 0
你可以在配置文件里放置任意数量的refresh_pattern行。squid按顺序查找它们以匹配正则表达式。当squid找到一个匹配时,它使用相应的值来决定,某个缓存响应是存活还是过期。refresh_pattern语法如下:
refresh_pattern [-i] regexp min percent max [options]
Journaling文件系统对许多操作系统可用。在Linux上,你能选择ext3fs,reiserfs,
XFS,和其他的。XFS也可用在SGI/IRIX,它原始是在这里开发的。Solaris用户能使用Veritas文件系统产品。TRU64(以前的
Digital Unix)高级文件系统(advfs)支持Journaling。
你可以不改变squid的任何配置而使用Journaling文件系统。简单的创建和挂载在操作系统文档里描述的文件系统,而不必改变squid.cf配置文件里的cache_dir行。
严格讲,你不必在storeio模块列表中指定ufs。然而,假如你以后不喜欢aufs,那么就需要指定ufs,以便能重新使用稳定的ufs存储机制。
假如愿意,你也能使用—with-aio-threads=N选项。假如你忽略它,squid基于aufs cache_dir的数量,自动计算可使用的线程数量。表8-1显示了1-6个cache目录的默认线程数量。
Table 8-1. Default number of threads for up to six cache directories
cache_dirs Threads
1 16
2 26
3 32
4 36
5 40
6 44
# 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 segments per 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)
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
2003/09/29 18:53:38| /usr/local/squid/var/cache/coss/swap.state:
(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
Packet 8
TIME: 19:54:41.448391 (0.030030)
TCP: 208.201.239.37.80 ->; 206.168.0.3.3897 AckPsh
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=".oreillynet.com/w3c/p3p.xml",CP="C
AO DSP COR CURa ADMa DEVa TAIa PSAa PSDa IVAa IVDa CONo OUR
DELa PUBi OTRa IND PHY ONL UNI PUR COM NAV INT DEM CNT STA P
RE"
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
X-Cache: MISS from 10.0.0.1
Connection: keep-alive
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
因为WCCP使用GRE,路由器可能强迫要求将来自HTTP请求的大TCP包分割成片断。幸运的是,这点不会经常发生,因为大部分HTTP请求比以太网
MTU
size(1500字节)要小。默认的TCP和IP包头部是20字节,这意味着以太网帧能实际携带1460字节的数据。GRE封装在GRE头部增加了20
字节,另外在第二个IP头部增加了20字节。这样来自客户端的正常的1500字节的TCP/IP包,在封装后变成了1540字节。这样数据包就太大而不能
在单个以太网帧里传输,所以路由器将原始包分割成两个片断。
9.3.4.1 WCCPv1
该节的配置示例在运行IOS Version 12.0(5)T的Cisco 7204路由器上测试。网络配置跟图9-5同。
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
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
注意第二条命令输出的协议版本值,与第一条命令的不一样。不幸的是,赋予了版本号太多的意义。show ip wccp
web-cache命令看起来报告WCCP协议的主版本号(例如1或2),然而show ip wccp web-cache
detail的版本号看起来匹配Squid的wccp_version指令的值。
/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
/sbin/ipfw add allow gre from 172.16.102.65 to 172.16.102.66
9.4.3 OpenBSD
本节的示例基于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
# ipfw show 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