golang監(jiān)聽ip數(shù)據(jù)包的實現(xiàn)步驟(golang純享版)
golang 監(jiān)聽ip數(shù)據(jù)包(golang純享版)
【注】本機編譯運行平臺為linux,如需測試代碼請移至linux平臺進行代碼測試
本文以ip4 作為案例進行包抓取示范,ip6抓取與ip4方式異曲同工,可自行舉一反三得出
第一步,通過wireshark抓包拿到ip4下的tcp/udp包,通過wireshark可視化我們可以很容易找到我們需要的源/目的地址信息所在ip包字節(jié)數(shù). 這里兩張截圖,一張ip4,一張ip6的


第二步,編寫我們秘制的簡易抓包工具,此處以直接輸出來源和去向地址為例,自己可以根據(jù)需求做更改
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é)序變網(wǎng)絡字節(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自行根據(jù)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 會抓取全部網(wǎng)卡的IP數(shù)據(jù)包,如需監(jiān)聽特定的網(wǎng)卡請自行判斷
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
}
測試主函數(shù)
func main() {
fmt.Fprintln(os.Stderr, inet.Watch(inet.Print_Info()))
}
效果

以上就是golang監(jiān)聽ip數(shù)據(jù)包的實現(xiàn)步驟(golang純享版)的詳細內容,更多關于golang監(jiān)聽ip數(shù)據(jù)包的資料請關注腳本之家其它相關文章!
相關文章
Golang?Gin框架獲取請求參數(shù)的幾種常見方式
在我們平常添加路由處理函數(shù)之后,就可以在路由處理函數(shù)中編寫業(yè)務處理代碼了,但在此之前我們往往需要獲取請求參數(shù),本文就詳細的講解下gin獲取請求參數(shù)常見的幾種方式,需要的朋友可以參考下2024-02-02

