http://blog.zhdata.com/tag/squid第16章 調試和故障處理
16.1 一些通用問題
在討論通用debug前,我先提起一些經常發生的問題。
16.1.1 “Failed to make swap 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.2 “Address already in 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代替。
16.1.3 “Could not determine fully qualified 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.4 “DNS name lookup tests 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.5 “Illegal character in 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 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.6 “Running out of 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.7 “icmpRecv: Connection refused”
假如pinger程序沒有正確的安裝,可見到下列消息:
icmpRecv: recv: (61) Connection refused
不過看起來更象是因為沒有打開ICMP socket的權限,pinger立刻退出了。因為該進程未在運行,當squid試圖與它會話時,會接受到I/O錯誤。為了解決該問題,請到源代碼目錄以root運行:
# make install-pinger
假如成功,你可見到pinger程序有下列文件屬主和許可設置:
# 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.8 在運行一段時間后,Squid變慢了
看起來更象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.9 調試訪問控制
假如訪問控制不能正確工作,如下是一些有用幫助。編輯squid.conf文件,設置debug_options行如下:
debug_options ALL,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 GET http://images.slashdot.org/topics/topicprivacy.gif is ALLOWED, because it matched 'all'
知道ACL的名字,並非總能知道相應的http_access行,但也相當接近了。假如必要,可以復制acl行,並給予它們唯一的名字,以便給定的ACL名字僅僅出現在一個http_access規則里。
16.2 通過cache.log進行調試
從13.1章已了解到,cache.log包含了不同的操作消息,squid認為這些消息足夠重要,從而告訴了你。我們也將這些作為debug消息考慮。可以使用debug_options指令來控制出現在cache.log里的消息的冗長度。通過增加debug等級,可以見到更詳細的消息,有助於理解squid正在做什么。例如:
debug_options ALL,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
Number | Description | Source file(s) |
0 | Client Database | client_db.c |
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 |
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_replacement.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 |
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 | NTLM Authenticator | auth/ntlm/auth_ntlm.c |
30 | Ident (RFC 1413) | ident.c |
31 | Hypertext Caching Protocol | htcp.c |
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 |
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 |
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 |
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 DISKD I/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 |
83 | SSL Accelerator Support | ssl_support.c |
84 | Helper Process Maintenance | helper.c |
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_options ALL,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增長非常快,並可能最終耗盡它的分區的剩余空間。假如這點發生,squid以致命消息退出。另一個關注點是性能可能下降明顯。因為有大量的debug消息,squid要耗費許多CPU資源來格式化和打印字符串。將所有debug消息寫往cache.log,也浪費了大量的磁盤帶寬。
16.3 Coredump,斷點,和堆棧跟蹤
假如不幸,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和某些SPARC CPU。幸運的是,它們容易修復。
異常分片錯誤不幸的更常見,且有時難以修復。SEGV通常發生在進程試圖訪問無效內存區域時(可能是個NULL指針,或超出進程空間之外的內存地址)。當bug原因和SEGV影響在不同時間呈現時,它們特別難於捕獲到。
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調試器–GNU C編譯器的配套工具。假如沒有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) 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 (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.1 不能找到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文件,用這個命令:
# sysctl kern.sugid_coredump=1
請見sysctl.conf的manpage,關於在系統啟動時如何自動設置變量的信息。
16.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 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 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 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.5 報告Bug
假如你的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每次都發生,還是偶爾發生。
- 4) 所發生事情的精確描述。類似於”它不能工作”,”請求失敗”之類的語句,本質上對bug修復者無用。記得要非常詳細。
- 5) 對斷點,總線錯誤,或異常分片的堆棧跟蹤。
記住squid開發者通常是無報酬的義務勞動,所以要有耐心。嚴重bug比小問題享有更高的解決優先級。