Linux 内核抓包功能实现基础(五) 常见问题解析
之前在部門產品上開發了內核抓包模塊,基于openwrt平臺,通過netfilter框架實現相關功能。核心功能就是在netfilter 的PRE_ROUTING 和 POST_ROUTING鏈上增加兩個鉤子函數,實現對報文的匹配,復制和發送功能。功能已經上線三個月,根據反饋結果來看,基本的抓包功能正常,不過也有幾個問題需要解決一下,之前陸陸續續寫了四篇博客介紹相關功能的開發,在本篇就把產品實際應用中遇到的問題說一下。
1. mac地址缺失問題。
抓包是要抓到報文的所有數據,包括mac首部,ip首部,udp首部以及數據層。如果是進入本機的報文,是含有mac地址的,但是對于本機出去的報文,在POST_ROUTING這個點上,是還沒有填充mac首部的,在第四篇中介紹了如何手動查找鄰居緩存來填充mac地址,但是實際應用中仍然會出現部分報文沒有mac地址,有時候看到這樣的報文還是挺困擾的。沒有查到鄰居緩存,一方面可能是真的還沒有鄰居緩存,另一方面可能是查找方式不對,因為如果是vlan環境下,還真的查不到!我查找調用的接口是 ip_route_me_harder函數。在這種情況下,想了其它一個方法來work around。既然查找鄰居緩存找不到,那就自己建立一個mac緩存。方式就是當抓包開啟的時候,在pre_routing鏈上對每一個報文記錄它的來源ip, 來源mac和目的ip,目的mac,然后建立一個鏈表來緩存,這樣當在post_routing上抓包找不到mac的時候就根據目的地址查找mac緩存,地址匹配就可以了。實際測試功能正常。有一點值得注意,在mac緩存的時候千萬不要將廣播報文也緩存下來,這樣只會浪費空間,因為廣播報文mac地址已知沒必要記錄。
2. 報文發送帶來內核奔潰問題
抓包的發送接口有兩個,一個是ip_local_out,另一個是dev_queue_xmit,后一個接口需要手動填充L2層首部,前不久測試發現一個問題,就是在調用dev_queue_xmit的時候,系統很容易重啟,根據重啟日志發現是內核奔潰,且每次報的內核錯誤都不一樣,都是和dma相關,和系統部的工程師討論了一下,發現是網卡驅動處理大包異常導致,抓包的時候,如果是tcp報文,它的報文往往會超過mtu值,這樣的報文是無法在網絡上傳輸的,需要分片。網卡有個TSO機制,就是專門利用硬件處理tcp分片。我們抓包的時候是封裝在udp里,網卡不支持udp封片,導致收到超大報文后系統不穩定直接掛掉。后來的處理方式是在調用dev_queue_xmit前判斷報文大小,如果報文太大的話就調用系統接口ip_loca_out,讓協議棧來處理分片。
?
3. vlan報文
之前遇到一個問題,就是開啟抓包后服務器端沒收到報文,但是看log發現抓包模塊的確有發送出去。使用tcpdump抓包分析才知道在復制報文的時候連同原始報文vlan標簽也復制過去,導致發出去的報文是vlan報文,這樣服務器肯定收不到,改了一下流程,抓包的時候手動設置skb->vlan_tci?= 0;
?
總結
以上是生活随笔為你收集整理的Linux 内核抓包功能实现基础(五) 常见问题解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 10转4股派20元是什么意思?
- 下一篇: linux 其他常用命令