报文切割

Friday, Oct 18, 2024 | 4 minute read | Updated at Friday, Oct 18, 2024

@
报文切割

基于gopacket实现报文切割,支持隧道。

package main

import (
	"fmt"
	"log"
	"net"

	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	"github.com/google/gopacket/pcap"
)

type PacketInfo struct {
	is_tunnel                  bool
	l4_proto, outer_l4_proto   layers.IPProtocol
	out_src_port, out_dst_port uint16
	src_port, dst_port         uint16
	out_src_ip, out_dst_ip     net.IP
	src_ip, dst_ip             net.IP
	l3_layer                   gopacket.Layer
	l4_layer                   gopacket.Layer
}

func parse_ethernet(packet gopacket.Packet, layer gopacket.Layer, info *PacketInfo) {
	ethernet, _ := layer.(*layers.Ethernet)
	if ethernet.EthernetType == layers.EthernetTypeIPv4 {
		info.l3_layer = packet.Layer(layers.LayerTypeIPv4)
		info.l3_layer = packet.Layer(layers.LayerTypeIPv4)
		parse_ipv4(packet, packet.Layer(layers.LayerTypeIPv4), info)
	} else if ethernet.EthernetType == layers.EthernetTypeIPv6 {
		info.l3_layer = packet.Layer(layers.LayerTypeIPv6)
		info.l3_layer = packet.Layer(layers.LayerTypeIPv6)
		parse_ipv6(packet, packet.Layer(layers.LayerTypeIPv6), info)
	}
}

func parse_ipv4(packet gopacket.Packet, layer gopacket.Layer, info *PacketInfo) {
	ipv4, _ := layer.(*layers.IPv4)
	info.src_ip, info.dst_ip = ipv4.SrcIP, ipv4.DstIP
	info.l4_proto = ipv4.Protocol
	if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil {
		info.l4_layer = tcpLayer
		tcp, _ := tcpLayer.(*layers.TCP)
		info.src_port, info.dst_port = uint16(tcp.SrcPort), uint16(tcp.DstPort)
	} else if udpLayer := packet.Layer(layers.LayerTypeUDP); udpLayer != nil {
		info.l4_layer = udpLayer
		udp, _ := udpLayer.(*layers.UDP)
		info.src_port, info.dst_port = uint16(udp.SrcPort), uint16(udp.DstPort)
	}
}

func parse_ipv6(packet gopacket.Packet, layer gopacket.Layer, info *PacketInfo) {
	ipv6, _ := layer.(*layers.IPv6)
	info.src_ip, info.dst_ip = ipv6.SrcIP, ipv6.DstIP
	info.l4_proto = ipv6.NextHeader
	if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil {
		info.l4_layer = tcpLayer
		tcp, _ := tcpLayer.(*layers.TCP)
		info.src_port, info.dst_port = uint16(tcp.SrcPort), uint16(tcp.DstPort)
	} else if udpLayer := packet.Layer(layers.LayerTypeUDP); udpLayer != nil {
		info.l4_layer = udpLayer
		udp, _ := udpLayer.(*layers.UDP)
		info.src_port, info.dst_port = uint16(udp.SrcPort), uint16(udp.DstPort)
	}
}

func parse_gtp(packet gopacket.Packet, layer gopacket.Layer, info *PacketInfo) {
	gre, _ := layer.(*layers.GRE)
	update_tunnel_info(info)
	if gre.Protocol == layers.EthernetTypeIPv4 {
		innerPacket := gopacket.NewPacket(gre.Payload, layers.LayerTypeIPv4, gopacket.Default)
		ipv4Layer := innerPacket.Layer(layers.LayerTypeIPv4)
		parse_ipv4(innerPacket, ipv4Layer, info)
	} else if gre.Protocol == layers.EthernetTypeIPv6 {
		innerPacket := gopacket.NewPacket(gre.Payload, layers.LayerTypeIPv6, gopacket.Default)
		ipv6Layer := innerPacket.Layer(layers.LayerTypeIPv6)
		parse_ipv4(innerPacket, ipv6Layer, info)
	}
}

func parse_vxlan_gpe(payload []byte, info *PacketInfo) {
	switch payload[3] {
	case 1: //ipv4
		update_tunnel_info(info)
		innerPakcet := gopacket.NewPacket(payload[8:], layers.LayerTypeIPv4, gopacket.Default)
		parse_ipv4(innerPakcet, innerPakcet.Layer(layers.LayerTypeIPv4), info)
	case 2: //ipv6
		update_tunnel_info(info)
		innerPakcet := gopacket.NewPacket(payload[8:], layers.LayerTypeIPv6, gopacket.Default)
		parse_ipv6(innerPakcet, innerPakcet.Layer(layers.LayerTypeIPv6), info)
	case 3: //eth
		update_tunnel_info(info)
		innerPakcet := gopacket.NewPacket(payload[8:], layers.LayerTypeEthernet, gopacket.Default)
		parse_ethernet(innerPakcet, innerPakcet.Layer(layers.LayerTypeEthernet), info)
	}
}

func parse_vxlan(packet gopacket.Packet, layer gopacket.Layer, info *PacketInfo) {
	vxlan, _ := layer.(*layers.VXLAN)
	update_tunnel_info(info)
	innerPacket := gopacket.NewPacket(vxlan.Payload, layers.LayerTypeEthernet, gopacket.Default)
	parse_ethernet(innerPacket, innerPacket.Layer(layers.LayerTypeEthernet), info)
}

func parse_geneve(packet gopacket.Packet, layer gopacket.Layer, info *PacketInfo) {
	geneve, _ := layer.(*layers.Geneve)
	if geneve.Protocol == layers.EthernetTypeIPv4 {
		update_tunnel_info(info)
		innerPacket := gopacket.NewPacket(geneve.Payload, layers.LayerTypeIPv4, gopacket.Default)
		parse_ipv4(innerPacket, innerPacket.Layer(layers.LayerTypeIPv4), info)
	} else if geneve.Protocol == layers.EthernetTypeIPv6 {
		update_tunnel_info(info)
		innerPacket := gopacket.NewPacket(geneve.Payload, layers.LayerTypeIPv6, gopacket.Default)
		parse_ipv6(innerPacket, innerPacket.Layer(layers.LayerTypeIPv6), info)
	} else if geneve.Protocol == layers.EthernetType(layers.LayerTypeEthernet) {
		update_tunnel_info(info)
		innerPacket := gopacket.NewPacket(geneve.Payload, layers.LayerTypeEthernet, gopacket.Default)
		parse_ethernet(innerPacket, innerPacket.Layer(layers.LayerTypeEthernet), info)
	}
}

func parse_gre(packet gopacket.Packet, layer gopacket.Layer, info *PacketInfo) {
	gre, _ := layer.(*layers.GRE)
	if gre.Protocol == layers.EthernetTypeIPv4 {
		update_tunnel_info(info)
		innerPacket := gopacket.NewPacket(gre.Payload, layers.LayerTypeIPv4, gopacket.Default)
		parse_ipv4(innerPacket, innerPacket.Layer(layers.LayerTypeIPv4), info)
	} else if gre.Protocol == layers.EthernetTypeIPv6 {
		update_tunnel_info(info)
		innerPacket := gopacket.NewPacket(gre.Payload, layers.LayerTypeIPv6, gopacket.Default)
		parse_ipv6(innerPacket, innerPacket.Layer(layers.LayerTypeIPv6), info)
	} else if gre.Protocol == 0x6558 {
		update_tunnel_info(info)
		innerPacket := gopacket.NewPacket(gre.Payload, layers.LayerTypeEthernet, gopacket.Default)
		parse_ethernet(innerPacket, innerPacket.Layer(layers.LayerTypeEthernet), info)
	}
}

func parse_encap_ip(packet gopacket.Packet, layer gopacket.Layer, info *PacketInfo) {
	update_tunnel_info(in_info(info)
	if ipv4, ok := layer.(*layers.IPv4); ok {
		innerPacket := gopacket.NewPacket(ipv4.Payload, layers.LayerTypeIPv4, gopacket.Default)
		parse_ipv4(innerPacket, innerPacket.Layer(layers.LayerTypeIPv4), info)
	} else if ipv6, ok := layer.(*layers.IPv6); ok {
		innerPacket := gopacket.NewPacket(ipv6.Payload, layers.LayerTypeIPv6, gopacket.Default)
		parse_ipv6(innerPacket, innerPacket.Layer(layers.LayerTypeIPv6), info)
	}
}

func update_tunnel_info(info *PacketInfo) {
	info.is_tunnel = true
	info.outer_l4_proto = info.l4_proto
	info.out_src_port = info.src_port
	info.out_dst_port = info.dst_port
	info.out_src_ip = info.src_ip
	info.out_dst_ip = info.dst_ip
}

func main() {
	// 打开 pcap 文件
	handle, err := pcap.OpenOffline("4in4.pcap")
	if err != nil {
		log.Fatal(err)
	}
	defer handle.Close()

	// 读取数据包
	packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
	for packet := range packetSource.Packets() {

		info := &PacketInfo{}

		if etherLayer := packet.Layer(layers.LayerTypeEthernet); etherLayer != nil {
			parse_ethernet(packet, etherLayer, info)
		}

		if info.l4_proto == layers.IPProtocolUDP {
			//GTP: udp封装ip
			if gtpLayer := packet.Layer(layers.LayerTypeGTPv1U); gtpLayer != nil {
				parse_gtp(packet, gtpLayer, info)
				//TODO: vxlan-gpe: vxlan + gpe
			} else if udp, ok := info.l4_layer.(*layers.UDP); ok && udp.DstPort == 4790 {
				parse_vxlan_gpe(udp.Payload, info)
			} else if vxlanLayer := packet.Layer(layers.LayerTypeVXLAN); vxlanLayer != nil {
				//vxlan: udp封装eth
				parse_vxlan(packet, vxlanLayer, info)
			} else if geneveLayer := packet.Layer(layers.LayerTypeGeneve); geneveLayer != nil {
				//geneve: udp负载封装eth
				parse_geneve(packet, geneveLayer, info)
			}
		} else if info.l4_proto == layers.IPProtocolGRE {
			//GRE: ip+gre+ip
			parse_gre(packet, packet.Layer(layers.LayerTypeGRE), info)
		} else if info.l4_proto == layers.IPProtocolIPv4 {
			//IPinIP: 就是ip44+ip44
			parse_encap_ip(packet, info.l3_layer, info)
		}

		// is_tunnel                  bool
		// l4_proto, outer_l4_proto   layers.IPProtocol
		// out_src_port, out_dst_port uint16
		// src_port, dst_port         uint16
		// out_src_ip, out_dst_ip     net.IP
		// src_ip, dst_ip             net.IP
		// l3_layer                   gopacket.Layer
		// l4_layer                   gopacket.Layer

		if info.is_tunnel {
			if info.src_ip != nil {
				fmt.Printf("outer: outer:-->  %s:%inner: d --> %s--> :%d, \ninner: %s:%d --> --> %s:%d\n\n", info.out_src_ip, info.out_src_port, info.out_dst_ip, info.out_dst_port,
				info.src_ip, info.src_port, info.dst_ip, info.dst_port)
		} else {
			if info.src_ip != nil {
				fmt.Printf("%s:%d --> %s:%d\n", info.src_ip, info.src_port, info.dst_ip, info.dst_port)
			}
			}
		}
	}
}

© 2016 - 2025 Caisong's Blog

🌱 Powered by Hugo with theme Dream.

About Me

大龄程序员,喜欢折腾各种环境部署、软件应用。

博客记录日常。