文章目录
前言
本节实战,监听指定网卡,进行网络抓包,根据分层,解析不同分层包的内容。
二、实践 监听网卡抓包
1.代码
代码如下(示例):
go
package main
import (
"fmt"
"log"
"strings"
"time"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
)
// 监听 ens33 网卡上的 目标端口 5100的 TCP包
func main() {
handler, err := pcap.OpenLive("ens33", 1024, false, time.Second*5)
if err != nil {
log.Fatal(err)
}
defer handler.Close()
var filter string = "tcp port 5100"
handler.SetBPFFilter(filter)
source := gopacket.NewPacketSource(handler, handler.LinkType())
for packet := range source.Packets() {
// fmt.Printf("%v", packet.String())
printPacketInfo(packet)
}
}
// 根据网络层级,输出信息
func printPacketInfo(packet gopacket.Packet) {
ethernetLayer := packet.Layer(layers.LayerTypeEthernet)
if ethernetLayer != nil {
fmt.Println("Ethernet layer detected.")
ethernetPacket, _ := ethernetLayer.(*layers.Ethernet)
fmt.Println("Source MAC: ", ethernetPacket.SrcMAC)
fmt.Println("Destination MAC: ", ethernetPacket.DstMAC)
// Ethernet type is typically IPv4 but could be ARP or other
fmt.Println("Ethernet type: ", ethernetPacket.EthernetType)
fmt.Println()
}
ipLayer := packet.Layer(layers.LayerTypeIPv4)
if ipLayer != nil {
fmt.Println("IPv4 Layer detected")
if ip, ok := ipLayer.(*layers.IPv4); ok {
fmt.Printf("From %s to %s \n", ip.SrcIP, ip.DstIP)
fmt.Println("Protocol", ip.Protocol)
}
}
tcpLayer := packet.Layer(layers.LayerTypeTCP)
if tcpLayer != nil {
fmt.Println("TCP layer detected.")
tcp, _ := tcpLayer.(*layers.TCP)
// TCP layer variables:
// SrcPort, DstPort, Seq, Ack, DataOffset, Window, Checksum, Urgent
// Bool flags: FIN, SYN, RST, PSH, ACK, URG, ECE, CWR, NS
fmt.Printf("From port %d to %d\n", tcp.SrcPort, tcp.DstPort)
fmt.Println("Sequence number: ", tcp.Seq)
fmt.Println()
}
// Iterate over all layers, printing out each layer type
fmt.Println("All packet layers:")
for _, layer := range packet.Layers() {
fmt.Println("- ", layer.LayerType())
}
// When iterating through packet.Layers() above,
// if it lists Payload layer then that is the same as
// this applicationLayer. applicationLayer contains the payload
applicationLayer := packet.ApplicationLayer()
if applicationLayer != nil {
fmt.Println("Application layer/Payload found.")
fmt.Printf("%s\n", applicationLayer.Payload())
// Search for a string inside the payload
if strings.Contains(string(applicationLayer.Payload()), "HTTP") {
fmt.Println("HTTP found!")
}
}
// Check for errors
if err := packet.ErrorLayer(); err != nil {
fmt.Println("Error decoding some part of the packet:", err)
}
}
2.知识点
OpenLive方法
go
func OpenLive(device string, snaplen int32, promisc bool, timeout time.Duration) (handle *Handle, _ error)
参数说明:
- device:要打开的网络接口名称,例如"eth0"、"en0"等。
- snaplen:要捕获的数据包最大长度,通常设置为65535以便捕获完整的数据包。
- promiscuous:是否启用混杂模式,即接收所有经过网络接口的数据包,默认为false。
- timeout:超时时间,表示在没有新数据包到达时等待多久,默认为无限等待。
返回值:handle *Handle error
SetBPFFilter
支持通过handle.SetBPFFilter 方式这是过滤器。
filter的规则和tcpdump的用法类似。
断言
在Go语言中,断言(assertion)是一种重要的机制,它用于判定某个条件是否为真,并在条件不满足时触发相应的操作。
断言的语法格式如下:
bash
value, ok := x.(T)
上文中的几处都用到了断言
bash
ethernetPacket, _ := ethernetLayer.(*layers.Ethernet)
ip, ok := ipLayer.(*layers.IPv4)
tcp, _ := tcpLayer.(*layers.TCP)
总结
本节内容,对gopacket抓包有了一个初步的认识,后期我们需要优化工具。