Directory Not Empty, 刪不掉的幽靈

沒法刪除的文件
最近部門NAS測試團隊遇到一個很是詭異的問題,在刪除一棵存在SMB共享文件夾的文件樹時,刪除完子目錄的全部文件後,再刪除這個子目錄的時候竟然系統報出「Directory Not Empty」的錯誤從而致使用例測試未經過,打開這個目錄一看,確實有一個文件並未刪除成功,再查看I/O工具的日誌,報告全部的文件都已經成功刪除。難道是I/O工具出了問題而沒有正確報出錯誤,這個通過工具開發者的研究後確認後貌似工具沒有任何問題,這個問題起初被開發團隊踢皮球,死活不認可是SMB2服務器的問題。死活非得讓抓取網絡包來證明。服務器

做爲一個網絡分析的僞專家,本身也厚着臉皮主動蹭入NAS測試團隊強行出力,但願把這個懸案搞個誰落石出。網絡

抓包重現
首先,設置好抓包參數,同時重現問題,這一步很順利。因爲測試參數沒有任何更改,很順利的重現了問題,而且將出問題對應時間點的網絡包悉數抓到。工具

在Windows2106的客戶端開啓抓包工具wireshark(其對應的命令行工具爲 tshark), 而且設置好相關參數:測試

$ tshark -i ens1 -B 4096 -s 1024 -w client-traffic.pcap

參數的含義就是在接口ens1上抓取長度爲1024字節的每個幀, 並把這些幀存在client-traffic.pcap的文件裏spa

分析
在抓取到網絡包之後,咱們開始解包分析:命令行

一樣經過tshark命令解包分析, 並將揭開的內容分別重定向到摘要文件client-traffic.summary和詳細展開格式的client-traffic.detail文件當中:日誌

$ tshark -t ud -Y "ip.addr==<server-ip>" -r client-traffic.pcap >>client-traffic.summary

$ tshark -t ud -O smb2 -Y "ip.addr==<server-ip>" -r client-traffic.pcap >>client-traffic.detail

打開client-traffic.summary文件後的一步就是要找到對應未刪除成功的文件(文件名: VCg8iMkGWgll2VJoEFMUa0FKp1DJHEG2)最後一次出現的幀,簡單的經過文本搜索即可定位,找到對應的幀之後發現,這個操做是一個Create操做,根據協議[MS-SMB2], 刪除操做是經過一組三元操做 Create/SetInfo/Close來實現的,稱爲Delete-On-Close,因爲咱們正要尋找的是刪除操做,藉此能夠大膽推測,這個Create (Frame #210725)請求正是三元刪除重的第一步, 再日後的幀一個個尋找,果真找到了第二步SetInfo (Frame #210727) 和第三步Close (Frame #210757, 經過該幀展開後確認其FileID屬性與前兩步操做對象一致) 兩個請求以及對應的服務器端的回覆:
最後Close並未獲得服務器回覆
clipboard.pngcode

Delete-On-Close 操做中的前兩步
Delete-On-Close 操做中的前兩步
然而最後的一步的close 請求(Frame #210757)並未獲得服務器端的回覆,那麼問題顯然出在了這裏,繼續往下分析,爲何服務器沒有對最後一步close操做做出響應呢?server

最後Close並未獲得服務器回覆
clipboard.png對象

奇怪的是,這個close操做發出後在0.1秒內沒有獲得任何回覆,因而出發了TCP層的超時重傳(RTO)(Frame #210765),按道理說在同一個實驗室的內部網絡下,網絡情況是十分好的,基本上不可能發生RTO的狀況(即使連快速重傳也是極爲罕見的),除非服務器出現了宕機。此時我忽然想到咱們測試當中爲了測試SMB2的CA功能(Continues Availability:高可靠性,容忍服務器重啓或者故障轉移), 常常會引入錯誤注入的測試用例,再次翻看測試日誌,果真發如今建立和刪除文件操做的同時有重啓服務器節點的操做執行,查看時間戳和發生問題的時間點一直,如今基本能夠明確的是,發生的問題和CA有關了。

刪除文件同時服務器重啓
clipboard.png

如今來看看正常的CA流程,當客戶端一個SMB2請求遇到服務器重啓的狀況下,網絡會暫時斷開,發出的請求在若干次超時重傳之後會收到服務重啓後發出的TCP重置請求(RST)(Frame #210769), 客戶端在收到此請求後即可得知網絡發生了斷連,爲是後續操做得以延續,必須再次創建TCP的鏈接(經過三次握手 Frame #210770, #210771, #210772), 從新協商(Negotiate. Frame #210773)創建會話(Session Setup. Frame #210776)和共享文件根目錄的鏈接(Tree Connect. Frame #210785), 最後,由於客戶端知道在網絡斷連以前最後一次沒有響應的操做即目標文件,此時客戶端會經過Create操做(Frame #210787)從新發起一個對目標文件的鏈接(在client-traffic.detail可看到展開後的Create操做的RECONNECT信息),從而接續上服務器從其前的步驟,實現CA的功能特性

Frame #210773 - #210786 重建會話
clipboard.png

在client-traffic.detail中找到第210787幀的展開後詳細信息,即可得知這是一個試圖重連(RECONNECT)操做:

Frame #210787 展開詳細信息
clipboard.png

到目前爲止,客戶端的全部操做均是按協議規定來進行的,那麼是否是此次重連以後文件就能接續服務器重啓前的操做進而把目標文件刪除成功呢?要知道答案的話咱們必需要檢查一下服務對於重連操做的回覆響應,找到服務器回覆的那個幀,展開:

Frame #210790
clipboard.png

服務器回答說,你重連的文件沒有找到(STATUS_OBJECT_NAME_NOT_FOUND),這時候客戶端理所固然的認爲在服務重啓以前目標文件已經成功刪除,只是由於重啓致使網絡斷連致使回覆並未成功發出。 因此客戶端繼續往下進行剩餘文件的刪除知道遇到刪除目錄出錯(Frame #210838) 到這裏咱們能夠確定的是客戶端是嚴格按照協議來進行請求的,而服務器這是在重連的回覆裏(Frame #210790) 錯誤地告知文件已經刪除成功從而誤導了客戶端。因此這個已經很是明顯是一個SMB2服務器的Bug。

Frame #210838
clipboard.png

咱們看看協議裏對於這一個服務器回覆(Frame #210790)的定義:

SMB2協議定義
clipboard.png

若是Persistent的文件句柄並未在全局句柄表裏找到(假設已經被成功close),那麼便返回STATUS_OBJECT_NAME_NOT_FOUND的回覆

結尾
根據這些網絡包,再與開發團隊確實交流後,他們接受了這個Bug並進行了修復。

能夠看到,藉助於wireshark, 不少複雜且奇怪的問題均可以探究其背後祕密談話,從而獲取任何的蛛絲馬跡找到問題的根源所在。

SMB2協議:

相關文章
相關標籤/搜索