
基于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)
}
}
}
}
}