Linux 内核抓包功能实现基础(三) 抓包服务器的实现
上回博客我們講到了內(nèi)核抓包內(nèi)核端的實(shí)現(xiàn),通過上篇博客的例子我們就能夠開始抓包了,整個(gè)抓包的拓?fù)鋱D如下:
當(dāng)開始抓包后,抓包機(jī)器將抓到的報(bào)文送到服務(wù)器上,假設(shè)服務(wù)器地址是192.168.199.123:8099,如果在抓包服務(wù)器上打開wireshark可以看到送過來的報(bào)文,如下圖這樣子:
可以看到抓包服務(wù)器上收到了報(bào)文,但是這樣子的報(bào)文我們是無法直接拿來分析的,因?yàn)閷?shí)際的報(bào)文是封裝起來的,需要把數(shù)據(jù)提取出來封裝成wireshark能夠識(shí)別的格式才行,本篇博客就介紹一下抓包服務(wù)器的實(shí)現(xiàn)原理。
在看實(shí)際的代碼之前,我們先來看一下抓包服務(wù)器開啟后的樣子,首先監(jiān)聽本地8099端口
其次將送到該端口的數(shù)據(jù)封裝成pcap格式,使用wireshark打開后如下:
這是實(shí)際抓到的報(bào)文,能夠清楚看到報(bào)文里面的各項(xiàng)數(shù)據(jù)。
下面介紹抓包服務(wù)器實(shí)現(xiàn)的原理。
抓包服務(wù)器功能大致如下:
1. 啟動(dòng)后監(jiān)聽報(bào)文送來的地址,在本例中是8099
2. 收到數(shù)據(jù)后將數(shù)據(jù)保存到文件中并以wireshark可識(shí)別的格式保存。
通常使用wireshark抓包保存的文件都已.pcap為后綴名。里面存儲(chǔ)報(bào)文的實(shí)際數(shù)據(jù)。pcap文件格式如下:
每個(gè)pcap文件都有一個(gè)pcap首部,占24字節(jié),之后就是pcap報(bào)文頭和報(bào)文數(shù)據(jù),報(bào)文頭存儲(chǔ)了抓包的時(shí)間戳等信息。
抓包服務(wù)器的任務(wù)就是新建一個(gè)pcap文件,寫入pcap文件頭后,之后每收到一個(gè)數(shù)據(jù)就寫入一個(gè)pcap報(bào)文頭和報(bào)文數(shù)據(jù)。這樣等保存文件后就可以直接使用wireshark打開了。
winpcap是windows版本的開源抓包庫,里面提供了包括pcap文件創(chuàng)建、保存等一系列接口,可以直接拿來使用,我這里的例子是windows64位的 golang版本的,Linux版本下有l(wèi)ibpcap庫可供使用。
代碼如下:
// main.go package mainimport ("fmt""net""os""os/signal""strconv""syscall""time""github.com/google/gopacket""github.com/google/gopacket/layers"//"github.com/google/gopacket/pcap""github.com/google/gopacket/pcapgo" )type CaptureManager struct {F *os.File //抓包文件W *pcapgo.Writer //用于寫文件conn *net.UDPConn //udp連接 }func CaptureSaveFile() {for {//套接字接收緩存buffer := make([]byte, 65535)//接收數(shù)據(jù)num, _, err := CapMng.conn.ReadFromUDP(buffer)if nil != err {continue} else {captureInfo := gopacket.CaptureInfo{Timestamp: time.Now().UTC(),CaptureLength: num,Length: num,InterfaceIndex: 0,}//寫入pcap數(shù)據(jù)包頭以及數(shù)據(jù)CapMng.W.WritePacket(captureInfo, buffer[:num])CapMng.F.Seek(0, os.SEEK_END)}} }var CapMng *CaptureManagerfunc main() {//全局管理控制塊CapMng = &CaptureManager{}//創(chuàng)建目錄os.MkdirAll("capture_packet", 0777)//創(chuàng)建文件名字t := time.Now()fil := "capture_packet" + "/" + "capture" + "_" + t.Format("20060102150405") + ".pcap"//創(chuàng)建文件CapMng.F, _ = os.Create(fil)//填充pcap文件頭部24字節(jié)CapMng.W = pcapgo.NewWriter(CapMng.F)CapMng.W.WriteFileHeader(1024, layers.LinkTypeEthernet)//設(shè)置監(jiān)聽地址Addr, err := net.ResolveUDPAddr("udp", "0.0.0.0:"+strconv.Itoa(8099))if nil != err {fmt.Println("resulve udp addr fail")return} else {//創(chuàng)建udp連接CapMng.conn, err = net.ListenUDP("udp", Addr)if nil != err {fmt.Println("create conn fail")return} else {fmt.Println("Capture Start")go CaptureSaveFile()}}chSignal := make(chan os.Signal, 5)//signal.Notify(chSignal)//監(jiān)聽指定信號(hào)signal.Notify(chSignal, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT,syscall.SIGSEGV, syscall.SIGABRT)fmt.Println("capture server start")//阻塞直至有信號(hào)傳入sig := <-chSignalswitch sig {case syscall.SIGSEGV, syscall.SIGABRT:default:}fmt.Println("*************Server Recive signal %s, program exit", sig.String())CapMng.F.Close()CapMng.conn.Close()fmt.Println("CLOSE")time.After(1 * time.Second) }代碼在github上,下載后可在安裝了go環(huán)境下的windows上直接運(yùn)行。
git@github.com:FuYuanDe/capture_demo.git
編譯go程序可能有點(diǎn)麻煩,但既然都看到這了,估計(jì)這點(diǎn)麻煩也不會(huì)難道你?
到目前位置,內(nèi)核抓包功能基本的框架已經(jīng)搭起來了,但是和tcpdump相比,還有很多不足之處,比方說能否根據(jù)過濾條件抓取報(bào)文?其次,送到遠(yuǎn)端服務(wù)器上的時(shí)候如果mtu值很小怎么辦?要不要分片?還有就是在POST_ROUTING上的hook函數(shù)抓到的報(bào)文是沒有mac地址的!!!啥?沒MAC地址! 沒錯(cuò),本機(jī)出去的報(bào)文在IP層還沒有填寫MAC地址,這時(shí)候抓包的話是無法得到目的mac地址的。有空的話再聊聊這些問題的解決方法。有問題的同志想要交流的話可以加群討論一下奧
參考資料:
1.
Winpcap的安裝使用方法和問題總結(jié)
https://blog.csdn.net/yu314092706/article/details/52937189
2.?
golang使用gopacket包進(jìn)行數(shù)據(jù)包捕獲,注入和分析
https://blog.csdn.net/ptmozhu/article/details/72652310?utm_source=itdadao&utm_medium=referral
3. pcap文件格式分析
https://www.cnblogs.com/2017Crown/p/7162303.html
またね!
總結(jié)
以上是生活随笔為你收集整理的Linux 内核抓包功能实现基础(三) 抓包服务器的实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 年份怎么读?
- 下一篇: Linux环境编程 哈希链表结构 hli