golang監(jiān)聽ip數據包的實現步驟(golang純享版)
更新時間:2024年02月25日 09:45:38 作者:docker真的爽爆了
這篇文章主要給大家介紹了golang監(jiān)聽ip數據包的實現步驟,本文以ip4 作為案例進行包抓取示范,ip6抓取與ip4方式異曲同工,可自行舉一反三得出,文中通過圖文結合給大家介紹的非常詳細,需要的朋友可以參考下
golang 監(jiān)聽ip數據包(golang純享版)
【注】本機編譯運行平臺為linux,如需測試代碼請移至linux平臺進行代碼測試
本文以ip4 作為案例進行包抓取示范,ip6抓取與ip4方式異曲同工,可自行舉一反三得出
第一步,通過wireshark抓包拿到ip4下的tcp/udp包,通過wireshark可視化我們可以很容易找到我們需要的源/目的地址信息所在ip包字節(jié)數. 這里兩張截圖,一張ip4,一張ip6的
第二步,編寫我們秘制的簡易抓包工具,此處以直接輸出來源和去向地址為例,自己可以根據需求做更改
package inet import ( "encoding/binary" "fmt" "strconv" "syscall" "unsafe" ) func reverse(b []byte) { var ( mid uint8 blen = len(b) ) if blen > 1 { for i := 0; i < blen/2; i++ { mid = b[i] b[i] = b[blen-i-1] b[blen-i-1] = mid } } } //主機字節(jié)序變網絡字節(jié)序 func Htons[T uint | uint16 | uint32 | uint64](t T) T { var ( b []byte = make([]byte, unsafe.Sizeof(t)) ptr *T = (*T)(unsafe.Pointer(&b[0])) ) *ptr = t reverse(b) return *ptr } //ip包必選,ip6自行根據wireshark進行編寫,此處ip4為例 type IPHeader struct { Version_And_Len uint8//前4個bit為version(4 ip4,6 ip6),后bit個字節(jié)為首部length xxxx xxxx DiffernetialtedService uint8 Tot_Len uint16 Id uint16 Flag_And_Seek uint16//前3bit 為flag后面13bit為seek TTL uint8 Protocol uint8 CheckSum uint16 Source uint32 Dest uint32 } type PortInfo struct { Source uint16 Dest uint16 } var ( __IP_DEFAULT IPHeader IPHEADER_SIZE = int(unsafe.Sizeof(__IP_DEFAULT)) ) func Watch(watcher func([]byte, int)) error { //socket af_packet 會抓取全部網卡的IP數據包,如需監(jiān)聽特定的網卡請自行判斷 fd, _, err_ := syscall.Syscall(syscall.SYS_SOCKET, syscall.AF_PACKET, syscall.SOCK_DGRAM, uintptr(Htons[uint16](syscall.ETH_P_IP))) if int(fd) < 0 { return err_ } ifd := int(fd) var ( buff []byte = make([]byte, 512) lang int err error ) defer syscall.Close(ifd) fmt.Println("start watch raw stream", ifd) for { lang, _, err = syscall.Recvfrom(ifd, buff, 0) if lang <= 0 { break } watcher(buff, lang) } return err } //輸出所有來源去向 func print_info(info []byte, size int) { if size <= IPHEADER_SIZE { return } var ( ipheader *IPHeader = (*IPHeader)(unsafe.Pointer(&info[0])) portinfo *PortInfo ) if size > IPHEADER_SIZE+4 { portinfo = (*PortInfo)(unsafe.Pointer(&info[IPHEADER_SIZE])) fmt.Printf("src %s:%d dst %s:%d\n", Raw2String(ipheader.Source), portinfo.Source, Raw2String(ipheader.Dest), portinfo.Dest) } else { fmt.Printf("src %s dst %s\n", Raw2String(ipheader.Source), Raw2String(ipheader.Dest)) } } func Raw2String(src uint32) string { raw := make([]byte, 4) binary.LittleEndian.PutUint32(raw, src) return strconv.FormatUint(uint64(raw[0]), 10) + "." + strconv.FormatUint(uint64(raw[1]), 10) + "." + strconv.FormatUint(uint64(raw[2]), 10) + "." + strconv.FormatUint(uint64(raw[3]), 10) } func Print_Info() func([]byte, int) { return print_info }
測試主函數
func main() { fmt.Fprintln(os.Stderr, inet.Watch(inet.Print_Info())) }
效果
以上就是golang監(jiān)聽ip數據包的實現步驟(golang純享版)的詳細內容,更多關于golang監(jiān)聽ip數據包的資料請關注腳本之家其它相關文章!