[好文共享]《Squid 中文權威指南》第6章 譯者:彭勇華

火星人 @ 2014-03-04 , reply:0


[好文共享]《Squid 中文權威指南》第6章 譯者:彭勇華

譯者序:
本人在工作中維護著數台Squid 伺服器,多次參閱Duane Wessels(他也是Squid 的創始人)的這本書,原書名是"Squid: The Definitive Guide",由O'Reilly 出版。我在業餘時間把它翻譯成中文,希望對中文Squid 用戶有所幫助。對普通的單位上網用戶,Squid 可充當代理伺服器;而對Sina,NetEase 這樣的大型站點,Squid 又充當WEB 加速器。這兩個角色它都扮演得異常優秀。窗外繁星點點,開源的世界亦如這星空般美麗,而Squid 是其中耀眼的一顆星。
對本譯版有任何問題,請跟我聯繫,我的Email是:yonghua_peng@yahoo.com.cn  彭勇華

--------------------------------------------------------------------------------------

6.訪問控制

6.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.1 一些基本的ACL 類型

Squid 大約有25 個不同的ACL 類型,其中的一些有通用基本類型。例如,src 和dst ACL使用IP 地址作為它們的基本類型。為避免冗長,我首先描述基本類型,然後在接下來章節里描述每種ACL 類型。

6.1.1.1 IP 地址

使用對象:src,dst,myip
squid 在ACL 里指定IP 地址時,擁有強有力的語法。你能以子網,地址範圍,域名等形式編寫地址。squid 支持標準IP 地址寫法(由」.」連接的4 個小於256 的數字)和無類域間路由規範。另外,假如你忽略掩碼,squid 會自動計算相應的掩碼。例如,下例中的每組是相等的:
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
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 地址範圍,掩碼只能取一個。你不能為範圍里的地址設置多個不同掩碼。

你也能在IP ACL 里指定主機名,例如:
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,和myip ACL 里避免使用主機名。

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'
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 列表中。


6.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 請求的主機名(或者srcdomain ACL 的客戶主機名)。第二列指明是否主機名匹配lrrr.org。第三列顯示是否主機名匹配.lrrr.org ACL。你能看到,唯一的不同在第二個實例里。
Table 6-1. Domain name matching
___________________________________________________________________
__URL hostname_____Matches ACL lrrr.org? ____Matches ACL .lrrr.org?
__lrrr.org_________Yes_______________________Yes
__i.am.lrrr.org____No________________________Yes
__iamlrrr.org______No________________________No
___________________________________________________________________
**說明:為了表現表格形狀,「__」僅代表空格分隔符,沒有任何實際意義(段譽 註釋)。

域名匹配可能讓人迷惑,所以請看第二個例子以便你能真正理解它。如下是兩個稍微不同的ACL:
acl A dstdomain foo.com
acl B dstdomain .foo.com

用戶對http://www.foo.com/的請求匹配ACL B,但不匹配A。ACL A 要求嚴格的字元串
匹配,然而ACL B 里領頭的點就像通配符。

另外,用戶對http://foo.com/的請求同時匹配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'

在該情況下你應遵循squid 的建議。刪除其中一條相關的域名,以便squid 明確知道你的意圖。注意你能在不同的ACL 里任意使用這樣的域名:
acl Foo dstdomain .lrrr.org
acl Bar dstdomain .am.lrrr.org

這是允許的,因為每個命名ACL 使用它自己的splay tree.


6.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.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.5 TCP 埠號

使用對象:port,myport

該類型是相對的。值是個別的埠號或埠範圍。回想一下TCP 埠號是16 位值,這樣它的值必須大於0 和小於65536。如下是一些示例:
acl Foo port 123
acl Bar port 1-1024


6.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.2 ACL 類型

現在我們能把焦點放在ACL 類型自身上。我在這裡按照重要性的降序來列舉它們。


6.1.2.1 src

IP 地址在訪問控制元素里是最普遍使用的。大部分站點使用IP 地址來控制客戶允許或不允許訪問Squid。src 類型指客戶源IP 地址。也就是說,當src ACL 出現在訪問控制列表裡時,squid 將它與發布請求的客戶IP 地址進行比較。

正常情況下你允許來自內網中主機的請求,並阻塞其他的。例如,假如你的單位使用192.168.0.0 子網,你可以這樣指定ACL:
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.2 dst

dst 類型指向原始伺服器(目標)IP 地址。在某些情況下,你能使用該類型來阻止你的用戶訪問特定web 站點。然而,在使用dst ACL 時你須謹慎。大部分squid 接受到的請求有原始伺服器主機名。例如:
GET http://www.web-cache.com/ HTTP/1.0

這裡,www.web-cache.com 是主機名。當訪問列表規則包含了dst 元素時,squid 必須找到該主機名的IP 地址。假如squid 的IP 緩存包含了該主機名的有效介面,這條ACL 被立即檢測。否則,在DNS 查詢忙碌時,squid 會延緩處理該請求。這對某些請求來說會造成延時。

為了避免延時,你該儘可能的使用dstdomain ACL 類型來代替dst。

如下是簡單的dst ACL 示例:
acl AdServers dst 1.2.3.0/24

請注意,dst ACL 存在的問題是,你試圖允許或拒絕訪問的原始伺服器可能會改變它的IP 地址。假如你不關心這樣的改變,那就不必麻煩去升級squid.conf。你可以在acl 行里放上主機名,但那樣會延緩啟動速度。假如你的ACL 需要許多主機名,你也許該預處理配置文件,將主機名轉換成IP 地址。


6.1.2.3 myip

myip 類型指Squid 的IP 地址,它被客戶連接。當你在squid 機上運行netstat -n 時,你見到它們位於本地地址列。大部分squid 安裝不使用該類型。通常所有的客戶連接到同一個IP 地址,所以該ACL元素僅僅當系統有多個IP 地址時才有用。

為了理解myip為何有用,考慮某個有兩個子網的公司網路。在子網1的用戶是程序員和工程師。子網2包括會計,市場和其他管理部門。這樣情況下的squid 有三個網路介面:一個連接子網1,一個連接子網2,第三個連接到外部網際網路。

當正確的配置時,所有在子網1 的用戶連接到squid 位於該子網的IP 地址,類似的,子網2 的用戶連接到squid 的第二個IP 地址。這樣你就可以給予子網1 的技術部員工完全的訪問權,然而限制管理部門的員工僅僅能訪問工作相關的站點。

ACL 可能如下:
acl Eng myip 172.16.1.5
acl Admin myip 172.16.2.5

然而請注意,使用該機制你必須特別小心,阻止來自某個子網的用戶連接squid 位於另一子網的IP 地址。否則,在會計和市場子網的聰明的用戶,能夠通過技術部子網進行連接,從而繞過你的限制。


6.1.2.4 dstdomain

在某些情況下,你發現基於名字的訪問控制非常有用。你可以使用它們去阻塞對某些站點的訪問,去控制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 會繼續使用舊的地址。

然而dstdomain ACL 以域名形式存儲,並非IP 地址。當squid 檢查ACL B 時,它對URL的主機名部分使用字元串比較功能。在該情形下,它並不真正關心是否www.squid-cache.org
的IP 地址改變了。

使用dstdomain ACL 的主要問題是某些URL 使用IP 地址代替主機名。假如你的目標是使用dstdomain ACL 來阻塞對某些站點的訪問,聰明的用戶能手工查詢站點的IP 地址,然後將它們放在URL 里。例如,下面的2 行URL 帶來同樣的頁面:
http://www.squid-cache.org/docs/FAQ/
http://206.168.0.9/docs/FAQ/

第一行能被dstdomain ACL 輕易匹配,但第二行不能。這樣,假如你依靠dstdomain ACL,你也該同樣阻塞所有使用IP 地址代替主機名的請求。請見6.3.8 章節。


6.1.2.5 srcdomain

srcdomain ACL 也有點麻煩。它要求對每個客戶IP 地址進行所謂的反向DNS 查詢。技術上,squid 請求對該地址的DNS PTR 記錄。DNS 的響應--完整可驗證域名(FQDN)--是squid匹配ACL 值的東西。(請參考O'Reilly's DNS and BIND 找到更多關於DNS PTR 記錄的信息)使用dst ACL,FQDN 查詢會導致延時。請求會被延緩處理直到FQDN 響應返回。FQDN響應被緩存下來,所以srcdomain 查詢通常僅在客戶首次請求時延時。

不幸的是,srcdomain 查詢有時不能工作。許多組織並沒有保持他們的反向查詢資料庫與日更新。假如某地址沒有PTR 記錄,ACL 檢查失敗。在該情形下,請求可能會延時非常長時間(例如2 分鐘)直到DNS 查詢超時。假如你使用srcdomain ACL,請確認你自己的DNS in-addr.arpa 區域配置正確並且在工作中。假如這樣,你可以使用如下的ACL:
acl LocalHosts srcdomain .users.example.com


6.1.2.6 port

你很可能想使用port ACL 來限制對某些原始伺服器埠號的訪問。就像我即將講到的,squid 其實不連接到某些服務,例如email 和IRC 服務。port ACL 允許你定義單獨的埠或埠範圍。例如:
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
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.7 myport

squid 也有myport ACL。port ACL 指向原始伺服器的埠號,myport 指向squid 自己的埠號,用以接受客戶請求。假如你在http_port 指令里指定不止一個埠號,那麼squid 就可以在不同的埠上偵聽。

假如你將squid 作為站點HTTP 加速器和用戶代理伺服器,那麼myport ACL 特別有用。你可以在80 上接受加速請求,在3128 上接受代理請求。你可能想讓所有人訪問加速器,但僅僅你自己的用戶能以代理形式訪問squid。你的ACL 可能如下:
acl AccelPort myport 80
acl ProxyPort myport 3128
acl MyNet src 172.16.0.0/22
http_access allow AccelPort # anyone
http_access allow ProxyPort MyNet # only my users
http_access deny ProxyPort # deny others


6.1.2.8 method

method ACL 指HTTP 請求方法。GET 是典型的最常用方法,接下來是POST,PUT,和其他。下例說明如何使用method ACL:
acl Uploads method PUT POST

Squid 知道下列標準HTTP 方法:GET, POST, PUT, HEAD, CONNECT, TRACE,OPTIONS 和DELETE。另外,squid 了解下列來自WEBDAV 規範,RFC 2518 的方法:PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK。某些Microsoft 產品使用非標準的WEBDAV 方法,所以squid 也了解它們:BMOVE, 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
http_access allow Purge Localhost
http_access deny Purge

關於從squid 的緩存里刪除對象,請見7.6 章。


6.1.2.9 proto

該類型指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.10 time

time ACL 允許你控制基於時間的訪問,時間為每天中的具體時間,和每周中的每天。日期以單字母來表示,見如下表。時間以24 小時制來表示。開始時間必須小於結束時間,這樣在編寫跨越0 點的time ACL 時可能有點麻煩。
Code____Day
-----------------
S_______Sunday
M_______Monday
T_______Tuesday
W_______Wednesday
H_______Thursday
F_______Friday
A_______Saturday
D_______All weekdays (M-F)
-----------------

日期和時間由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
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.11 ident

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 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.12 proxy_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 可以啟動,但所有你的用戶的請求可能被拒絕。

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.13 src_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.14 dst_as

dst_as ACL 經常與cache_peer_access 指令一起使用。在該方法中,squid 使用與IP 路由一致的方式轉發cache 丟失。考慮某ISP,它比其他ISP 更頻繁的更換路由。每個ISP 處理他們自己的cache 代理,這些代理能轉發請求到其他代理。理論上,ISP A 將ISP B 網路里主機的cache 丟失轉發到ISP B 的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.15 snmp_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.16 maxconn

maxconn ACL 指來自客戶IP 地址的大量同時連接。某些squid 管理員發現這是個有用的方法,用以阻止用戶濫用代理或者消耗過多資源。

maxconn ACL 在請求超過指定的數量時,會匹配這個請求。因為這個理由,你應該僅僅在deny 規則里使用maxconn。考慮如下例子:
acl OverConnLimit maxconn 4
http_access deny OverConnLimit

在該情況中,squid 允許來自每個IP 地址的同時連接數最大為4 個。當某個客戶發起第五個連接時,OverConnLimit ACL 被匹配,http_access 規則拒絕該請求。


6.1.2.17 arp

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 和你的用戶之間有路由器存在,你可能不能使用arp ACL。

現在你知道何時去使用它們,讓我們看看arp ACL 實際上是怎樣的。它的值是乙太網地址,當使用ifconfig 和arp 時你能看到乙太網地址。例如:
acl WinBoxes arp 00:00:21:55:ed:22
acl WinBoxes arp 00:00:21:ff:55:38


6.1.2.18 srcdom_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.19 dstdom_regex

dstdom_regex ACL 也與dstdomain 相似。下面的例子匹配以www 開頭的主機名:
acl WebSite dstdom_regex -i ^www\.

如下是另一個有用的正則表達式,用以匹配在URL 主機名里出現的IP 地址:
acl IPaddr dstdom_regex $

這樣可以工作,因為squid 要求URL 主機名完全可驗證。既然全局頂級域名中沒有以數字結尾的,該ACL 僅僅匹配IP 地址,它以數字結尾。


6.1.2.20 url_regex

url_regex ACL 用於匹配請求URL 的任何部分,包括傳輸協議和原始伺服器主機名。例如,如下ACL 匹配從FTP 伺服器的MP3 文件請求:
acl FTPMP3 url_regex -i ^ftp://.*\.mp3$


6.1.2.21 urlpath_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.22 browser

大部分HTTP 請求包含了User-Agent 頭部。該頭部的值典型如下:
Mozilla/4.51 (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字串,或者乾脆忽略它們。


6.1.2.23 req_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.24 rep_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.25 ident_regex

在本節早些時講過ident ACL。ident_regex 允許你使用正則表達式,代替嚴格的字元串匹配,這些匹配是對ident 協議返回的用戶名進行。例如,如下ACL 匹配包含數字的用戶名:
acl NumberInName ident_regex


6.1.2.26 proxy_auth_regex

該ACL 允許對代理認證用戶名使用正則表達式。例如, 如下ACL 匹配
admin,administrator 和administrators:
acl Admins proxy_auth_regex -i ^admin


6.1.3 外部ACL

Squid 2.5 版本介紹了一個新特性:外部ACL。你可以指示squid 發送某些信息片斷到外部進程,然後外部的輔助程序告訴squid,數據匹配或不匹配。

squid 附帶著大量的外部ACL 輔助程序;大部分用於確定命名用戶是不是某個特殊組的成員。請見12.5 章關於這些程序的描述,以及關於如何編寫你自己的程序的信息。現在,我解釋如何定義和使用外部ACL 類型。

external_acl_type 指令定義新的外部ACL 類型。如下是通用語法:
external_acl_type type-name 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 等)

%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:foo}的取值,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 行。這相對容易,語法如下:
acl acl-name external type-name

如下是個簡單示例:
acl MyAcl external MyAclType

squid 接受在type-name 後面的任意數量的參數。這些在每個請求里被發送到輔助程序。
請見12.5.3 章,我描述了unix_group 輔助程序,作為該功能的示例。


6.1.4 處理長ACL 列表

ACL 列表某些時候非常長。這樣的列表在squid.conf 文件里難以維護。你也可能想從其他資源里自動產生squid ACL 列表。在如此情況下,你可以從外部文件里包含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 值的文件的分界。


6.1.5 Squid 如何匹配訪問控制元素

理解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.2 訪問控制規則

前面提過,ACL 元素是建立訪問控制的第一步。第二步是訪問控制規則,用來允許或拒絕某些動作。在早先的例子里,你已見過http_access 規則。squid 有大量其他的訪問控制列表:

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_regex ACL 結合使用。
對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 查詢。

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
該訪問列表綁定服務端TCP 連接到指定的本地IP 地址。見附錄A。

tcp_outgoing_tos
該訪問列表能設置到原始伺服器和鄰居cache 的TCP 連接的不同TOS/Diffserv 值,見附錄A。

header_access
使用該指令,你能配置squid 從它轉發的請求里刪除某些HTTP 頭部。例如,你也許想Squid過濾掉發送到某些原始伺服器的請求里的Cookie 頭部。見附錄A。

header_replace
該指令允許你替換,而不是刪除,HTTP 頭部的內容。例如,你能設置user-agent 頭部為假值,滿足某些原始伺服器的要求,但仍保護你的隱私。見附錄A。


6.2.1 訪問規則語法

訪問控制規則的語法如下:
access_list allow|deny [!]ACLname ...

例如:
http_access allow MyClients
http_access deny !Safe_Ports
http_access allow GameSites AfterHours

當讀取配置文件時,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。


6.2.2 Squid 如何匹配訪問規則

回想一下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 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

src 0/0 ACL 表示匹配每一個和任意類型的請求。


6.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
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,它被拒絕。編寫本規則的更好方法是:
http_access allow CacheManager localhost
http_access deny CacheManager
http_access allow MyNet
http_access deny All


6.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.5 減緩和加速規則檢查

Squid 內部考慮某些訪問規則被快速檢查,其他的被減緩檢查。區別是squid 是否延遲它的決定,以等待附加信息。換句話說,在squid 查詢附加信息時,某個減緩檢查會被延時,例如:
+ 反向DNS 查詢:客戶IP 地址的主機名
+ RFC 1413 ident 查詢:客戶TCP 連接的用戶名
+ 驗證器:驗證用戶信用
+ DNS 轉發查詢:原始伺服器的IP 地址
+ 用戶定義的外部ACL

某些訪問規則使用快速檢查。例如,icp_access 規則被快速檢查。為了快速響應ICP 查詢,它必須被快速檢查。甚至,某些ACL 類型例如proxy_auth,對ICP 查詢來說無意義。下列訪問規則被快速檢查:
header_access
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.3 常見用法

因為訪問控制可能很複雜,本節包含一些示例。它們描述了一些訪問控制的普通用法。你可以在實際中調整它們。

6.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.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.3 內容過濾

阻塞對特定內容的訪問是棘手的問題。通常,使用squid 進行內容過濾最難的部分,是被阻塞的站點列表。你也許想自己維護一個這樣的列表,或從其他地方獲取一個。squid FAQ的「訪問控制」章節有鏈接指向免費的可用列表。

使用這樣的列表的ACL 語法依賴於它的內容。假如列表包含正則表達式,你可能要這樣寫:
acl PornSites url_regex "/usr/local/squid/etc/pornlist"
http_access deny PornSites

另一方面,假如列表包含原始伺服器主機名,那麼簡單的更改url_regex 為dstdomain。


6.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

請注意在該規則里首先放置!WorkingHours ACL。相對於字元串或列表,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

上面的方法可行,因為它實現了我們的目標,在工作時間內拒絕某些請求,並允許來自你自己網路的請求。然而,它也許有點低效。注意NotWorkRelated ACL 在所有請求里被搜索,而不管源IP 地址。假如那個列表非常長,在列表裡對外部網路請求的搜索,純粹是浪費CPU 資源。所以,你該這樣改變規則:
http_access deny !MyNetwork
http_access deny !WorkingHours NotWorkRelated
http_access Allow All

這裡,將代價較大的檢查放在最後。試圖濫用squid 的外部用戶不會再浪費你的CPU資源。


6.3.5 阻止squid 與非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
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
<additional http_access lines as necessary...>;

Safe_ports ACL 列舉了所有的squid 有合法響應的特權埠(小於1024)。它也列舉了所有非特權埠範圍。注意Safe_ports ACL 也包括了安全HTTP 和NNTP 埠(443 和563),即使它們也出現在SSL_ports ACL 里。這是因為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
<additional http_access lines as necessary...>;

假如你不熟悉這些奇特的埠號,也不要擔心。你可以閱讀unix 系統的/etc/services 文件,或者閱讀IANA 的註冊TCP/UDP 埠號列表:
http://www.iana.org/assignments/port-numbers


6.3.6 授予某些用戶特殊的訪問

使用基於用戶名進行訪問控制的組織,通常需要授予某些用戶特殊的許可權。在該簡單示例里,有三個元素:所有授權用戶,管理員用戶名,限制訪問的web 站點列表。正常的用戶不允許訪問受限站點,但管理員有維護這個列表的任務。他們必須連接到所有伺服器,去驗證某個特殊站點是否該放到受限站點列表裡。如下顯示如何完成這個任務:
auth_param basic program /usr/local/squid/libexec/ncsa_auth
/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 allow Admins
http_access deny Porn
http_access allow Authenticated
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.7 阻止鄰近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
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 allow ChildCache
icp_access allow SiblingCache
icp_access deny All


6.3.8 使用IP 地址拒絕請求

我在6.1.2.4 章節里提過,dstdomain 類型是阻塞對指定原始主機訪問的好選擇。然而,聰明的用戶通過替換URL 主機名成IP 地址,能夠繞過這樣的規則。假如你想徹底阻止這樣的請求,你可能得阻塞所有包含IP 地址的請求。你可以使用重定向器,或者使用dstdom_regex ACL 來完成。例如:
acl IPForHostname dstdom_regex ^+\.+\.+\.+$
http_access deny IPForHostname


6.3.9 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
acl MP3s rep_mime_type audio/mpeg
http_reply_access deny Movies
http_reply_access deny MP3s
http_reply_access allow All

你不必在http_reply_access 列表裡重複http_access 規則。這裡的allow ALL 規則不意味著所有對squid 的請求被允許。任何被http_access 拒絕的請求,從來不會再被http_reply_access 檢查。


6.3.10 阻止對本地站點的cache 命中

假如你有許多原始伺服器在本地網路中,你也許想配置squid,以便它們的響應永不被緩存。因為伺服器就在附近,它們不會從cache 命中里獲益很多。另外,它釋放存儲空間給其他遠程原始主機。

第一步是定義本地伺服器的ACL。你可能使用基於地址的ACL,例如:
acl LocalServers dst 172.17.1.0/24

假如伺服器不位於單一的子網,你也許該創建dstdomain ACL:
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.4 測試訪問控制
訪問控制配置越長,它就越複雜。強烈建議你在將它們用於產品環境之前,先測試訪問控制。當然,首先做的事是確認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'

更多的複雜請求,包括多個頭部,請參考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
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
《解決方案》

樓主。辛苦了。繼續支持你
《解決方案》

文章雖長,但看起來一點不吃力,說明樓主翻譯得還是很好的。謝謝。




[火星人 via ] [好文共享]《Squid 中文權威指南》第6章 譯者:彭勇華已經有798次圍觀

http://www.coctec.com/docs/service/show-post-19642.html