golang使用tshark解码IP数据包并创建分析结构的网络抓包插件goshark

goshark

goshark 是一个使用 tshark 解码 IP 数据包并创建数据结构来分析数据包的 Go 语言包。

依赖

  • tshark

示例

以下是一个完整的示例代码,展示如何使用 goshark 解码 pcap 文件并分析数据包:

package main

import (
	"fmt"
	"log"

	"github.com/sunwxg/goshark"
)

func main() {
	// 指定pcap文件路径
	file := "2.pcap"
	
	// 创建解码器
	d := goshark.NewDecoder()
	
	// 开始解码
	if err := d.DecodeStart(file); err != nil {
		log.Println("Decode start fail:", err)
		return
	}
	
	// 确保解码结束后释放资源
	defer d.DecodeEnd()

	// 获取下一个数据包
	f, err := d.NextPacket()
	if err != nil {
		log.Println("Get packet fail:", err)
		return
	}

	// 检查数据包中是否包含特定字段
	key := "igmp.maddr"
	value, ok := f.Iskey(key)
	if ok {
		fmt.Printf("key: %s\nvalue: %s\n", key, value)
	}
}

输出示例:

key: igmp.maddr
value: 224.0.0.251

代码说明

  1. 首先创建一个新的解码器实例 d := goshark.NewDecoder()
  2. 使用 DecodeStart() 方法开始解码指定的 pcap 文件
  3. 使用 defer d.DecodeEnd() 确保程序结束时释放资源
  4. 通过 NextPacket() 方法逐个获取数据包
  5. 使用 Iskey() 方法检查数据包中是否包含特定字段并获取其值

这个示例展示了如何从 pcap 文件中提取 IGMP 组播地址,但 goshark 可以用于分析各种网络协议的数据包。


更多关于golang使用tshark解码IP数据包并创建分析结构的网络抓包插件goshark的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang使用tshark解码IP数据包并创建分析结构的网络抓包插件goshark的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用Go和tshark解码IP数据包的网络抓包插件

下面我将介绍如何使用Go语言创建一个名为goshark的网络抓包插件,该插件利用tshark(Wireshark的命令行版本)来解码IP数据包并创建分析结构。

设计思路

  1. 使用Go的os/exec包调用tshark命令
  2. 解析tshark的JSON输出
  3. 将解析结果转换为结构化的Go数据
  4. 提供分析功能接口

代码实现

package goshark

import (
	"bytes"
	"encoding/json"
	"fmt"
	"os/exec"
	"strings"
)

// Packet 表示解码后的网络数据包
type Packet struct {
	Timestamp   string            `json:"timestamp"`
	Source      string            `json:"source"`
	Destination string            `json:"destination"`
	Protocol    string            `json:"protocol"`
	Length      int               `json:"length"`
	Info        string            `json:"info"`
	Layers      map[string]interface{} `json:"layers"`
}

// Goshark 主结构体
type Goshark struct {
	Interface string   // 网络接口
	Filter    string   // BPF过滤器
	Count     int      // 抓包数量
	Fields    []string // 要提取的字段
}

// New 创建一个新的Goshark实例
func New(iface string) *Goshark {
	return &Goshark{
		Interface: iface,
		Count:     10, // 默认抓10个包
		Fields: []string{
			"frame.time",
			"ip.src",
			"ip.dst",
			"ip.proto",
			"frame.len",
			"_ws.col.info",
		},
	}
}

// Capture 执行抓包并解码
func (g *Goshark) Capture() ([]Packet, error) {
	// 构建tshark命令
	args := []string{
		"-i", g.Interface,
		"-c", fmt.Sprintf("%d", g.Count),
		"-T", "json",
		"-e", strings.Join(g.Fields, ","),
	}

	if g.Filter != "" {
		args = append(args, "-f", g.Filter)
	}

	cmd := exec.Command("tshark", args...)
	var out bytes.Buffer
	cmd.Stdout = &out

	// 执行命令
	if err := cmd.Run(); err != nil {
		return nil, fmt.Errorf("tshark执行失败: %v", err)
	}

	// 解析JSON输出
	var rawPackets []map[string]interface{}
	if err := json.Unmarshal(out.Bytes(), &rawPackets); err != nil {
		return nil, fmt.Errorf("解析JSON失败: %v", err)
	}

	// 转换为Packet结构
	var packets []Packet
	for _, raw := range rawPackets {
		layers, ok := raw["_source"].(map[string]interface{})
		if !ok {
			continue
		}

		packet := Packet{
			Timestamp:   getString(layers, "frame.time"),
			Source:      getString(layers, "ip.src"),
			Destination: getString(layers, "ip.dst"),
			Protocol:    getString(layers, "ip.proto"),
			Length:      getInt(layers, "frame.len"),
			Info:        getString(layers, "_ws.col.info"),
			Layers:      layers,
		}

		packets = append(packets, packet)
	}

	return packets, nil
}

// getString 从map中安全获取字符串值
func getString(m map[string]interface{}, key string) string {
	if val, ok := m[key]; ok {
		if str, ok := val.(string); ok {
			return str
		}
	}
	return ""
}

// getInt 从map中安全获取整数值
func getInt(m map[string]interface{}, key string) int {
	if val, ok := m[key]; ok {
		switch v := val.(type) {
		case string:
			var i int
			fmt.Sscanf(v, "%d", &i)
			return i
		case float64:
			return int(v)
		}
	}
	return 0
}

// AnalyzeProtocolDistribution 分析协议分布
func (g *Goshark) AnalyzeProtocolDistribution(packets []Packet) map[string]int {
	distribution := make(map[string]int)
	for _, p := range packets {
		if p.Protocol != "" {
			distribution[p.Protocol]++
		}
	}
	return distribution
}

使用示例

package main

import (
	"fmt"
	"log"

	"github.com/yourusername/goshark"
)

func main() {
	// 创建goshark实例
	gs := goshark.New("eth0") // 替换为你的网络接口
	gs.Filter = "ip"          // 只抓取IP数据包
	gs.Count = 5              // 抓取5个包

	// 执行抓包
	packets, err := gs.Capture()
	if err != nil {
		log.Fatal(err)
	}

	// 打印抓包结果
	for i, p := range packets {
		fmt.Printf("Packet #%d:\n", i+1)
		fmt.Printf("  Time: %s\n", p.Timestamp)
		fmt.Printf("  Source: %s -> Destination: %s\n", p.Source, p.Destination)
		fmt.Printf("  Protocol: %s, Length: %d\n", p.Protocol, p.Length)
		fmt.Printf("  Info: %s\n", p.Info)
		fmt.Println("----------------------------------------")
	}

	// 分析协议分布
	dist := gs.AnalyzeProtocolDistribution(packets)
	fmt.Println("\nProtocol Distribution:")
	for proto, count := range dist {
		fmt.Printf("  %s: %d packets\n", proto, count)
	}
}

功能扩展建议

  1. 实时抓包模式:添加持续抓包功能而不是只抓固定数量的包
  2. 深度包解析:支持解析更多协议层(TCP/UDP/HTTP等)
  3. 统计分析:添加流量统计、异常检测等功能
  4. 输出格式:支持多种输出格式(CSV、文本表格等)
  5. 过滤功能:增强过滤条件支持

注意事项

  1. 使用前需要安装tshark/Wireshark
  2. 可能需要root权限才能抓包
  3. 不同版本的tshark可能有不同的输出格式

这个实现提供了基本的网络抓包和解码功能,你可以根据需要进一步扩展和完善它。

回到顶部