精华内容
下载资源
问答
  • gopacket - 为Go提供网络数据包处理功能
  • gopacket, 为Go提供数据包处理功能 GoPacket这里库为Go提供包解码功能。 有关详细信息,请参阅 godoc 。 从gopcap项目开始的fork由 Andreas Krennmair ak@synflood.at ( http://github.com/
  • 由于gopacket构建在libpcap之上,我强烈建议您了解该库的工作原理。您可以在C中学习如何使用libpcap进行更深入的了解。 1.libpcap gopacket是基于libpcap(数据包捕获函数库)的,该库提供的C函数接口用于捕捉经过...

    使用golang实现网络抓包是非常容易的,可以使用谷歌的包github.com/google/gopacket。由于gopacket构建在libpcap之上,我强烈建议您了解该库的工作原理。您可以在C中学习如何使用libpcap进行更深入的了解。

    1.libpcap

    gopacket是基于libpcap(数据包捕获函数库)的,该库提供的C函数接口用于捕捉经过指定网络接口的数据包,该接口应该是被设为混杂模式。
    著名的软件TCPDUMP就是在Libpcap的基础上开发而成的。Libpcap提供的接口函数实现和封装了与数据包截获有关的过程。Libpcap可以在绝大多数Linux平台上运行。
    主要有以下功能:
    数据包捕获:捕获流经网卡的原始数据包
    自定义数据包发送:构造任何格式的原始数据包
    流量采集与统计:采集网络中的流量信息
    规则过滤:提供自带规则过滤功能,按需要选择过滤规则

    2.先决条件

    # Get the gopacket package from GitHub
    go get github.com/google/gopacket
    # Pcap dev headers might be necessary
    sudo apt-get install libpcap-dev

    3.获取所有的网络设备信息

    package main
    
    import (
    	"fmt"
    	"github.com/google/gopacket/pcap"
    	"log"
    )
    
    func main() {
    	// Find all devices
    	devices, err := pcap.FindAllDevs()
    	if err != nil {
    		log.Fatal(err)
    	}
    
    	// Print device information
    	fmt.Println("Devices found:")
    	for _, device := range devices {
    		fmt.Println("\nName: ", device.Name)
    		fmt.Println("Description: ", device.Description)
    		fmt.Println("Devices addresses: ", device.Description)
    		for _, address := range device.Addresses {
    			fmt.Println("- IP address: ", address.IP)
    			fmt.Println("- Subnet mask: ", address.Netmask)
    		}
    	}
    }
    

    4.打开设备实时捕捉

    package main
    
    import (
    	"fmt"
    	"github.com/google/gopacket"
    	"github.com/google/gopacket/pcap"
    	"log"
    	"time"
    )
    
    var (
    	device       string = "eth0"
    	snapshot_len int32  = 1024
    	promiscuous  bool   = false
    	err          error
    	timeout      time.Duration = 30 * time.Second
    	handle       *pcap.Handle
    )
    
    func main() {
    	// Open device
    	handle, err = pcap.OpenLive(device, snapshot_len, promiscuous, timeout)
    	if err != nil {
    		log.Fatal(err)
    	}
    	defer handle.Close()
    
    	// Use the handle as a packet source to process all packets
    	packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
    	for packet := range packetSource.Packets() {
    		// Process packet here
    		fmt.Println(packet)
    	}
    
    }
    

    5.抓取结果保存为pcap格式文件

    要写一个pcap格式的文件,我们必须使用gapacket / pcapgo包。这是一个Writer接口和两个有用的函数:WriteFileHeader()和WritePacket()

    package main
    
    import (
    	"fmt"
    	"github.com/google/gopacket"
    	"github.com/google/gopacket/layers"
    	"github.com/google/gopacket/pcap"
    	"github.com/google/gopacket/pcapgo"
    	"os"
    	"time"
    )
    
    var (
    	deviceName  string = "eth0"
    	snaplen     uint32 = 1024
    	snapshotLen int32  = 1024
    	promiscuous bool   = false
    	err         error
    	timeout     time.Duration = -1 * time.Second
    	handle      *pcap.Handle
    	packetCount int = 0
    )
    
    func main() {
    	// Open output pcap file and write header
    	f, _ := os.Create("test.pcap")
    	w := pcapgo.NewWriter(f)
    	w.WriteFileHeader(snaplen, layers.LinkTypeEthernet)
    	defer f.Close()
    
    	// Open the device for capturing
    	handle, err = pcap.OpenLive(deviceName, snapshotLen, promiscuous, timeout)
    	if err != nil {
    		fmt.Printf("Error opening device %s: %v", deviceName, err)
    		os.Exit(1)
    	}
    	defer handle.Close()
    
    	// Start processing packets
    	packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
    	for packet := range packetSource.Packets() {
    		// Process packet here
    		fmt.Println(packet)
    		w.WritePacket(packet.Metadata().CaptureInfo, packet.Data())
    		packetCount++
    
    		// Only capture 100 and then stop
    		if packetCount > 100 {
    			break
    		}
    	}
    }
    

    6.读取pcap格式文件来查看分析网络数据包

    我们不用打开一个设备进行实时捕获,也可以打开pcap文件进行离线检查。您可以使用tcpdump创建要使用的测试文件。

    # Capture packets to test.pcap file
    sudo tcpdump -w test.pcap
    package main
    
    import (
    	"fmt"
    	"github.com/google/gopacket"
    	"github.com/google/gopacket/pcap"
    	"log"
    )
    
    var (
    	pcapFile string = "test.pcap"
    	handle   *pcap.Handle
    	err      error
    )
    
    func main() {
    	// Open file instead of device
    	handle, err = pcap.OpenOffline(pcapFile)
    	if err != nil {
    		log.Fatal(err)
    	}
    	defer handle.Close()
    
    	// Loop through packets in file
    	packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
    	for packet := range packetSource.Packets() {
    		fmt.Println(packet)
    	}
    }
    

    7.设置过滤器

    只抓取tcp协议80端口的数据

    package main
    
    import (
    	"fmt"
    	"github.com/google/gopacket"
    	"github.com/google/gopacket/pcap"
    	"log"
    	"time"
    )
    
    var (
    	device       string = "eth0"
    	snapshot_len int32  = 1024
    	promiscuous  bool   = false
    	err          error
    	timeout      time.Duration = 30 * time.Second
    	handle       *pcap.Handle
    )
    
    func main() {
    	// Open device
    	handle, err = pcap.OpenLive(device, snapshot_len, promiscuous, timeout)
    	if err != nil {
    		log.Fatal(err)
    	}
    	defer handle.Close()
    
    	// Set filter
    	var filter string = "tcp and port 80"
    	err = handle.SetBPFFilter(filter)
    	if err != nil {
    		log.Fatal(err)
    	}
    	fmt.Println("Only capturing TCP port 80 packets.")
    
    	packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
    	for packet := range packetSource.Packets() {
    		// Do something with a packet here.
    		fmt.Println(packet)
    	}
    
    }
    

    8.解码抓取的数据

    我们可以使用原始数据包,并且可将其转换为已知格式。它与不同的层兼容,所以我们可以轻松访问以太网,IP和TCP层。layers包是Go库中新增的,在底层pcap库中不可用。这是一个令人难以置信的有用的包,它是gopacket库的一部分。它允许我们容易地识别包是否包含特定类型的层。该代码示例将显示如何使用layers包来查看数据包是以太网,IP和TCP,并轻松访问这些头文件中的元素。
    查找有效载荷取决于所涉及的所有层。每个协议是不同的,必须相应地计算。这就是layer包的魅力所在。 gopacket的作者花了时间为诸如以太网,IP,UDP和TCP等众多已知层创建了相应类型。有效载荷是应用层的一部分。

    package main
    
    import (
    	"fmt"
    	"github.com/google/gopacket"
    	"github.com/google/gopacket/layers"
    	"github.com/google/gopacket/pcap"
    	"log"
    	"strings"
    	"time"
    )
    
    var (
    	device      string = "eth0"
    	snapshotLen int32  = 1024
    	promiscuous bool   = false
    	err         error
    	timeout     time.Duration = 30 * time.Second
    	handle      *pcap.Handle
    )
    
    func main() {
    	// Open device
    	handle, err = pcap.OpenLive(device, snapshotLen, promiscuous, timeout)
    	if err != nil {
    		log.Fatal(err)
    	}
    	defer handle.Close()
    
    	packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
    	for packet := range packetSource.Packets() {
    		printPacketInfo(packet)
    	}
    }
    
    func printPacketInfo(packet gopacket.Packet) {
    	// Let's see if the packet is an ethernet 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()
    	}
    
    	// Let's see if the packet is IP (even though the ether type told us)
    	ipLayer := packet.Layer(layers.LayerTypeIPv4)
    	if ipLayer != nil {
    		fmt.Println("IPv4 layer detected.")
    		ip, _ := ipLayer.(*layers.IPv4)
    
    		// IP layer variables:
    		// Version (Either 4 or 6)
    		// IHL (IP Header Length in 32-bit words)
    		// TOS, Length, Id, Flags, FragOffset, TTL, Protocol (TCP?),
    		// Checksum, SrcIP, DstIP
    		fmt.Printf("From %s to %s\n", ip.SrcIP, ip.DstIP)
    		fmt.Println("Protocol: ", ip.Protocol)
    		fmt.Println()
    	}
    
    	// Let's see if the packet is TCP
    	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)
    	}
    }
    

    9.构造发送数据包

    这个例子做了几件事情。首先将显示如何使用网络设备发送原始字节。这样就可以像串行连接一样使用它来发送数据。这对于真正的低层数据传输非常有用,但如果您想与应用程序进行交互,您应该构建可以识别该数据包的其他硬件和软件。接下来,它将显示如何使用以太网,IP和TCP层创建一个数据包。一切都是默认空的。要完成它,我们创建另一个数据包,但实际上填写了以太网层的一些MAC地址,IPv4的一些IP地址和TCP层的端口号。你应该看到如何伪装数据包和仿冒网络设备。TCP层结构体具有可读取和可设置的SYN,FIN,ACK标志。这有助于操纵和模糊TCP三次握手,会话和端口扫描。pcap库提供了一种发送字节的简单方法,但gopacket中的图层可帮助我们为多层创建字节结构。

    package main
    
    import (
    	"github.com/google/gopacket"
    	"github.com/google/gopacket/layers"
    	"github.com/google/gopacket/pcap"
    	"log"
    	"net"
    	"time"
    )
    
    var (
    	device       string = "eth0"
    	snapshot_len int32  = 1024
    	promiscuous  bool   = false
    	err          error
    	timeout      time.Duration = 30 * time.Second
    	handle       *pcap.Handle
    	buffer       gopacket.SerializeBuffer
    	options      gopacket.SerializeOptions
    )
    
    func main() {
    	// Open device
    	handle, err = pcap.OpenLive(device, snapshot_len, promiscuous, timeout)
    	if err != nil {
    		log.Fatal(err)
    	}
    	defer handle.Close()
    
    	// Send raw bytes over wire
    	rawBytes := []byte{10, 20, 30}
    	err = handle.WritePacketData(rawBytes)
    	if err != nil {
    		log.Fatal(err)
    	}
    
    	// Create a properly formed packet, just with
    	// empty details. Should fill out MAC addresses,
    	// IP addresses, etc.
    	buffer = gopacket.NewSerializeBuffer()
    	gopacket.SerializeLayers(buffer, options,
    		&layers.Ethernet{},
    		&layers.IPv4{},
    		&layers.TCP{},
    		gopacket.Payload(rawBytes),
    	)
    	outgoingPacket := buffer.Bytes()
    	// Send our packet
    	err = handle.WritePacketData(outgoingPacket)
    	if err != nil {
    		log.Fatal(err)
    	}
    
    	// This time lets fill out some information
    	ipLayer := &layers.IPv4{
    		SrcIP: net.IP{127, 0, 0, 1},
    		DstIP: net.IP{8, 8, 8, 8},
    	}
    	ethernetLayer := &layers.Ethernet{
    		SrcMAC: net.HardwareAddr{0xFF, 0xAA, 0xFA, 0xAA, 0xFF, 0xAA},
    		DstMAC: net.HardwareAddr{0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD},
    	}
    	tcpLayer := &layers.TCP{
    		SrcPort: layers.TCPPort(4321),
    		DstPort: layers.TCPPort(80),
    	}
    	// And create the packet with the layers
    	buffer = gopacket.NewSerializeBuffer()
    	gopacket.SerializeLayers(buffer, options,
    		ethernetLayer,
    		ipLayer,
    		tcpLayer,
    		gopacket.Payload(rawBytes),
    	)
    	outgoingPacket = buffer.Bytes()
    }
    

    10.更多的解码/构造数据包的例子

    package main
    
    import (
    	"fmt"
    	"github.com/google/gopacket"
    	"github.com/google/gopacket/layers"
    )
    
    func main() {
    	// If we don't have a handle to a device or a file, but we have a bunch
    	// of raw bytes, we can try to decode them in to packet information
    
    	// NewPacket() takes the raw bytes that make up the packet as the first parameter
    	// The second parameter is the lowest level layer you want to decode. It will
    	// decode that layer and all layers on top of it. The third layer
    	// is the type of decoding: default(all at once), lazy(on demand), and NoCopy
    	// which will not create a copy of the buffer
    
    	// Create an packet with ethernet, IP, TCP, and payload layers
    	// We are creating one we know will be decoded properly but
    	// your byte source could be anything. If any of the packets
    	// come back as nil, that means it could not decode it in to
    	// the proper layer (malformed or incorrect packet type)
    	payload := []byte{2, 4, 6}
    	options := gopacket.SerializeOptions{}
    	buffer := gopacket.NewSerializeBuffer()
    	gopacket.SerializeLayers(buffer, options,
    		&layers.Ethernet{},
    		&layers.IPv4{},
    		&layers.TCP{},
    		gopacket.Payload(payload),
    	)
    	rawBytes := buffer.Bytes()
    
    	// Decode an ethernet packet
    	ethPacket :=
    		gopacket.NewPacket(
    			rawBytes,
    			layers.LayerTypeEthernet,
    			gopacket.Default,
    		)
    
    	// with Lazy decoding it will only decode what it needs when it needs it
    	// This is not concurrency safe. If using concurrency, use default
    	ipPacket :=
    		gopacket.NewPacket(
    			rawBytes,
    			layers.LayerTypeIPv4,
    			gopacket.Lazy,
    		)
    
    	// With the NoCopy option, the underlying slices are referenced
    	// directly and not copied. If the underlying bytes change so will
    	// the packet
    	tcpPacket :=
    		gopacket.NewPacket(
    			rawBytes,
    			layers.LayerTypeTCP,
    			gopacket.NoCopy,
    		)
    
    	fmt.Println(ethPacket)
    	fmt.Println(ipPacket)
    	fmt.Println(tcpPacket)
    }
    

    11.自定义layer


    下一个程序将显示如何创建自己的layer。构建gopacket layer包不包含的协议。如果您要创建自己的l33t协议,甚至不使用TCP / IP或以太网,这是很有用的。

    package main
    
    import (
    	"fmt"
    	"github.com/google/gopacket"
    )
    
    // Create custom layer structure
    type CustomLayer struct {
    	// This layer just has two bytes at the front
    	SomeByte    byte
    	AnotherByte byte
    	restOfData  []byte
    }
    
    // Register the layer type so we can use it
    // The first argument is an ID. Use negative
    // or 2000+ for custom layers. It must be unique
    var CustomLayerType = gopacket.RegisterLayerType(
    	2001,
    	gopacket.LayerTypeMetadata{
    		"CustomLayerType",
    		gopacket.DecodeFunc(decodeCustomLayer),
    	},
    )
    
    // When we inquire about the type, what type of layer should
    // we say it is? We want it to return our custom layer type
    func (l CustomLayer) LayerType() gopacket.LayerType {
    	return CustomLayerType
    }
    
    // LayerContents returns the information that our layer
    // provides. In this case it is a header layer so
    // we return the header information
    func (l CustomLayer) LayerContents() []byte {
    	return []byte{l.SomeByte, l.AnotherByte}
    }
    
    // LayerPayload returns the subsequent layer built
    // on top of our layer or raw payload
    func (l CustomLayer) LayerPayload() []byte {
    	return l.restOfData
    }
    
    // Custom decode function. We can name it whatever we want
    // but it should have the same arguments and return value
    // When the layer is registered we tell it to use this decode function
    func decodeCustomLayer(data []byte, p gopacket.PacketBuilder) error {
    	// AddLayer appends to the list of layers that the packet has
    	p.AddLayer(&CustomLayer{data[0], data[1], data[2:]})
    
    	// The return value tells the packet what layer to expect
    	// with the rest of the data. It could be another header layer,
    	// nothing, or a payload layer.
    
    	// nil means this is the last layer. No more decoding
    	// return nil
    
    	// Returning another layer type tells it to decode
    	// the next layer with that layer's decoder function
    	// return p.NextDecoder(layers.LayerTypeEthernet)
    
    	// Returning payload type means the rest of the data
    	// is raw payload. It will set the application layer
    	// contents with the payload
    	return p.NextDecoder(gopacket.LayerTypePayload)
    }
    
    func main() {
    	// If you create your own encoding and decoding you can essentially
    	// create your own protocol or implement a protocol that is not
    	// already defined in the layers package. In our example we are just
    	// wrapping a normal ethernet packet with our own layer.
    	// Creating your own protocol is good if you want to create
    	// some obfuscated binary data type that was difficult for others
    	// to decode
    
    	// Finally, decode your packets:
    	rawBytes := []byte{0xF0, 0x0F, 65, 65, 66, 67, 68}
    	packet := gopacket.NewPacket(
    		rawBytes,
    		CustomLayerType,
    		gopacket.Default,
    	)
    	fmt.Println("Created packet out of raw bytes.")
    	fmt.Println(packet)
    
    	// Decode the packet as our custom layer
    	customLayer := packet.Layer(CustomLayerType)
    	if customLayer != nil {
    		fmt.Println("Packet was successfully decoded with custom layer decoder.")
    		customLayerContent, _ := customLayer.(*CustomLayer)
    		// Now we can access the elements of the custom struct
    		fmt.Println("Payload: ", customLayerContent.LayerPayload())
    		fmt.Println("SomeByte element:", customLayerContent.SomeByte)
    		fmt.Println("AnotherByte element:", customLayerContent.AnotherByte)
    	}
    }
    

    12.更快地解码数据包

    如果我们知道我们要预期的得到的层,我们可以使用现有的结构来存储分组信息,而不是为每个需要时间和内存的分组创建新的结构。使用DecodingLayerParser更快。就像编组和解组数据一样。

    package main
    
    import (
    	"fmt"
    	"github.com/google/gopacket"
    	"github.com/google/gopacket/layers"
    	"github.com/google/gopacket/pcap"
    	"log"
    	"time"
    )
    
    var (
    	device       string = "eth0"
    	snapshot_len int32  = 1024
    	promiscuous  bool   = false
    	err          error
    	timeout      time.Duration = 30 * time.Second
    	handle       *pcap.Handle
    	// Will reuse these for each packet
    	ethLayer layers.Ethernet
    	ipLayer  layers.IPv4
    	tcpLayer layers.TCP
    )
    
    func main() {
    	// Open device
    	handle, err = pcap.OpenLive(device, snapshot_len, promiscuous, timeout)
    	if err != nil {
    		log.Fatal(err)
    	}
    	defer handle.Close()
    
    	packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
    	for packet := range packetSource.Packets() {
    		parser := gopacket.NewDecodingLayerParser(
    			layers.LayerTypeEthernet,
    			&ethLayer,
    			&ipLayer,
    			&tcpLayer,
    		)
    		foundLayerTypes := []gopacket.LayerType{}
    
    		err := parser.DecodeLayers(packet.Data(), &foundLayerTypes)
    		if err != nil {
    			fmt.Println("Trouble decoding layers: ", err)
    		}
    
    		for _, layerType := range foundLayerTypes {
    			if layerType == layers.LayerTypeIPv4 {
    				fmt.Println("IPv4: ", ipLayer.SrcIP, "->", ipLayer.DstIP)
    			}
    			if layerType == layers.LayerTypeTCP {
    				fmt.Println("TCP Port: ", tcpLayer.SrcPort, "->", tcpLayer.DstPort)
    				fmt.Println("TCP SYN:", tcpLayer.SYN, " | ACK:", tcpLayer.ACK)
    			}
    		}
    	}
    }
    

    13.tcp流重组

    gopacket包提供了一些名为Flow和Endpoint的类型。我没有机会深入探索这些文档,但文档中有一个使用它来将特定TCP流发送到数据包通道的示例。https://godoc.org/github.com/google/gopacket

    展开全文
  • 自行下载源码包再解压也行, 还有就是存储的目录,理论上在放哪都行,只要目录和各种PATH要匹配, 但是考虑到gopacket的基础用例的相对路径名称都是: "github.com/google/gopacket" 我把gopacket存放在: /opt/go/src...

    GO基础环境配置详见之前写的一篇文章: https://blog.csdn.net/rclijia/article/details/94390242

    本例以/opt/go为GOROOT目录,ls -l /opt/go文件列表如下:

    total 216
    drwxr-xr-x.  2 root root   4096 May  6 23:05 api
    -rw-r--r--.  1 root root  55669 May  6 23:05 AUTHORS
    drwxr-xr-x.  2 root root     29 May  6 23:07 bin
    -rw-r--r--.  1 root root   1339 May  6 23:05 CONTRIBUTING.md
    -rw-r--r--.  1 root root 101673 May  6 23:05 CONTRIBUTORS
    drwxr-xr-x.  2 root root     80 May  6 23:05 doc
    -rw-r--r--.  1 root root   5686 May  6 23:05 favicon.ico
    drwxr-xr-x.  3 root root     18 May  6 23:05 lib
    -rw-r--r--.  1 root root   1479 May  6 23:05 LICENSE
    drwxr-xr-x. 12 root root    165 May  6 23:05 misc
    -rw-r--r--.  1 root root   1303 May  6 23:05 PATENTS
    drwxr-xr-x.  6 root root     76 May  6 23:08 pkg
    -rw-r--r--.  1 root root   1480 May  6 23:05 README.md
    -rw-r--r--.  1 root root     26 May  6 23:05 robots.txt
    -rw-r--r--.  1 root root    397 May  6 23:05 SECURITY.md
    drwxr-xr-x. 49 root root   4096 Jun 10 14:49 src
    drwxr-xr-x. 23 root root  12288 May  6 23:05 test
    drwxr-xr-x.  2 root root      6 Jun 10 14:30 vendor
    -rw-r--r--.  1 root root      8 May  6 23:05 VERSION

    下面简单介绍一下gopacket的入门安装配置步骤之hello world,

    安装工具集: yum install binutils

    然后是下载gopacket库,地址: https://github.com/google/gopacket

    使用git clone也行,自行下载源码包再解压也行,

    还有就是存储的目录,理论上在放哪都行,只要目录和各种PATH要匹配,

    但是考虑到gopacket的基础用例的相对路径名称都是: "github.com/google/gopacket"

    我把gopacket存放在: /opt/go/src/vendor/github.com/google/gopacket,

    这样就不用修改import的相对路径了。

    找个最简单的例子,即打印当前系统所有可用网卡的信息:

    package main
    
    import (
        "fmt"
        "log"
        "github.com/google/gopacket/pcap"
    )
    
    func main() {
        // Find all devices
        devices, err := pcap.FindAllDevs()
        if err != nil {
            log.Fatal(err)
        }
    
        // Print device information
        fmt.Println("Devices found:")
        for _, device := range devices {
            fmt.Println("\nName: ", device.Name)
            fmt.Println("Description: ", device.Description)
            fmt.Println("Devices addresses: ", device.Description)
            for _, address := range device.Addresses {
                fmt.Println("- IP address: ", address.IP)
                fmt.Println("- Subnet mask: ", address.Netmask)
            }
        }
    }

    把这个文件放在任意目录,比如/tmp/test_pcap.go

    在/opt/go/src目录执行: go run /tmp/test_pcap.go,

    如果正确执行,说明环境配置正确:

    Devices found:
    
    Name:  eth1
    Description:
    Devices addresses:
    - IP address:  192.168.100.29
    - Subnet mask:  fffffc00
    - IP address:  10.0.0.1
    - Subnet mask:  ffffff00
    - IP address:  fe80::44d4:7aff:feed:666e
    - Subnet mask:  ffffffffffffffff0000000000000000
    
    Name:  virbr0
    Description:
    Devices addresses:
    - IP address:  192.168.122.1
    - Subnet mask:  ffffff00
    
    Name:  nflog
    Description:  Linux netfilter log (NFLOG) interface
    Devices addresses:  Linux netfilter log (NFLOG) interface
    
    Name:  nfqueue
    Description:  Linux netfilter queue (NFQUEUE) interface
    Devices addresses:  Linux netfilter queue (NFQUEUE) interface
    
    Name:  usbmon1
    Description:  USB bus number 1
    Devices addresses:  USB bus number 1
    
    Name:  any
    Description:  Pseudo-device that captures on all interfaces
    Devices addresses:  Pseudo-device that captures on all interfaces
    
    Name:  lo
    Description:
    Devices addresses:
    - IP address:  127.0.0.1
    - Subnet mask:  ff000000
    - IP address:  ::1
    - Subnet mask:  ffffffffffffffffffffffffffffffff

    有了这个例子,其他更复杂的程序请参考: https://godoc.org/github.com/google/gopacket 

    展开全文
  • Go语言用GoPacket抓包

    千次阅读 2019-03-18 15:29:58
    使用的Google的gopacket包来进行。基于的是libcap包。 github地址:https://github.com/google/gopacket 我并不喜欢GoDoc的行文风格,对于demo可以看着这里的文章。(自备梯子) http://www.devdungeon.com/co...

    最近有了一个抓取网络数据包来分析的需求,最近在使用go语言,于是乎,决定是用go语言来进行抓包分析。使用的Google的gopacket包来进行。基于的是libcap包。

    github地址:https://github.com/google/gopacket

    我并不喜欢GoDoc的行文风格,对于demo可以看着这里的文章。(自备梯子)

    http://www.devdungeon.com/content/packet-capture-injection-and-analysis-gopacket
    ---------------

    Before Starting

    Install the prerequisites. You will need golibpcap and the gopacket package. Since gopacket is built on top of libpcap, I highly recommend you understand how that library works. You can learn how to use libpcap in C for a deeper understanding. These examples should work in Linux/Mac using libpcap and on Windows with WinPcap. You may need to set GOARCH=386 if you get an error like cc1.exe: sorry, unimplemented: 64-bit mode not compiled in.

    # Get the gopacket package from GitHub
    go get github.com/google/gopacket
    # Pcap dev headers might be necessary
    sudo apt-get install libpcap-dev

    You might also want to check out the gopacket project on GitHub and documentation on GoDoc gopacket.

    Find devices

    package main
    
    import (
        "fmt"
        "log"
        "github.com/google/gopacket/pcap"
    )
    
    func main() {
        // Find all devices
        devices, err := pcap.FindAllDevs()
        if err != nil {
            log.Fatal(err)
        }
    
        // Print device information
        fmt.Println("Devices found:")
        for _, device := range devices {
            fmt.Println("\nName: ", device.Name)
            fmt.Println("Description: ", device.Description)
            fmt.Println("Devices addresses: ", device.Description)
            for _, address := range device.Addresses {
                fmt.Println("- IP address: ", address.IP)
                fmt.Println("- Subnet mask: ", address.Netmask)
            }
        }
    }

    Open Device for Live Capture

    package main
    
    import (
        "fmt"
        "github.com/google/gopacket"
        "github.com/google/gopacket/pcap"
        "log"
        "time"
    )
    
    var (
        device       string = "eth0"
        snapshot_len int32  = 1024
        promiscuous  bool   = false
        err          error
        timeout      time.Duration = 30 * time.Second
        handle       *pcap.Handle
    )
    
    func main() {
        // Open device
        handle, err = pcap.OpenLive(device, snapshot_len, promiscuous, timeout)
        if err != nil {log.Fatal(err) }
        defer handle.Close()
    
        // Use the handle as a packet source to process all packets
        packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
        for packet := range packetSource.Packets() {
            // Process packet here
            fmt.Println(packet)
        }
    }

    Write Pcap File

    To write a pcap format file, we must use the gopacket/pcapgo package. This comes with a Writer and two useful functions: WriteFileHeader() and WritePacket().

    package main
    
    import (
    	"fmt"
    	"os"
    	"time"
    
    	"github.com/google/gopacket"
    	"github.com/google/gopacket/layers"
    	"github.com/google/gopacket/pcap"
    	"github.com/google/gopacket/pcapgo"
    )
    
    var (
    	deviceName  string = "eth0"
    	snapshotLen int32  = 1024
    	promiscuous bool   = false
    	err         error
    	timeout     time.Duration = -1 * time.Second
    	handle      *pcap.Handle
    	packetCount int = 0
    )
    
    func main() {
    	// Open output pcap file and write header 
    	f, _ := os.Create("test.pcap")
    	w := pcapgo.NewWriter(f)
    	w.WriteFileHeader(snapshotLen, layers.LinkTypeEthernet)
    	defer f.Close()
    
    	// Open the device for capturing
    	handle, err = pcap.OpenLive(deviceName, snapshotLen, promiscuous, timeout)
    	if err != nil {
    		fmt.Printf("Error opening device %s: %v", deviceName, err)
    		os.Exit(1)
    	}
    	defer handle.Close()
    
    	// Start processing packets
    	packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
    	for packet := range packetSource.Packets() {
    		// Process packet here
    		fmt.Println(packet)
    		w.WritePacket(packet.Metadata().CaptureInfo, packet.Data())
    		packetCount++
    		
    		// Only capture 100 and then stop
    		if packetCount > 100 {
    			break
    		}
    	}
    }

    Open Pcap File

    Instead of opening a device for live capture we can also open a pcap file for inspection offline. You can use tcpdump to create a test file to use.

    # Capture packets to test.pcap file
    sudo tcpdump -w test.pcap

    Then open the file and go through the packets with this code.

    package main
    
    // Use tcpdump to create a test file
    // tcpdump -w test.pcap
    // or use the example above for writing pcap files
    
    import (
        "fmt"
        "github.com/google/gopacket"
        "github.com/google/gopacket/pcap"
        "log"
    )
    
    var (
        pcapFile string = "test.pcap"
        handle   *pcap.Handle
        err      error
    )
    
    func main() {
        // Open file instead of device
        handle, err = pcap.OpenOffline(pcapFile)
        if err != nil { log.Fatal(err) }
        defer handle.Close()
    
        // Loop through packets in file
        packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
        for packet := range packetSource.Packets() {
            fmt.Println(packet)
        }
    }

    Setting Filters

    This code example will only return tcp packets over port 80.

    package main
    
    import (
        "fmt"
        "github.com/google/gopacket"
        "github.com/google/gopacket/pcap"
        "log"
        "time"
    )
    
    var (
        device       string = "eth0"
        snapshot_len int32  = 1024
        promiscuous  bool   = false
        err          error
        timeout      time.Duration = 30 * time.Second
        handle       *pcap.Handle
    )
    
    func main() {
        // Open device
        handle, err = pcap.OpenLive(device, snapshot_len, promiscuous, timeout)
        if err != nil {
            log.Fatal(err)
        }
        defer handle.Close()
    
        // Set filter
        var filter string = "tcp and port 80"
        err = handle.SetBPFFilter(filter)
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println("Only capturing TCP port 80 packets.")
    
        packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
        for packet := range packetSource.Packets() {
            // Do something with a packet here.
            fmt.Println(packet)
        }
    
    }

    Decoding Packet Layers

    We can take the raw packet and essentially try to cast it to known formats. It is compatible with different layers so we can access ethernet, IP, and TCP layers easily. The layers package is something new in the Go library that is not available in the underlying pcap library. This is an incredibly useful package that is part of the gopacket library. It allows us to easily identify if a packet contains a specific type of layer. This code example will show how to use the layers package to see if the packet is ethernet, IP, and TCP and to access the elements in those headers easily.

    Finding the payload depends on all the layers involved. Each protocol is different and has to be calculated accordingly. This is where the power of the layers package comes in to play. The authors of gopacket took the time to create types for many known layers like ethernet, IP, UDP and TCP. The payload is part of the application layer.

    package main
    
    import (
        "fmt"
        "github.com/google/gopacket"
        "github.com/google/gopacket/layers"
        "github.com/google/gopacket/pcap"
        "log"
        "strings"
        "time"
    )
    
    var (
        device      string = "eth0"
        snapshotLen int32  = 1024
        promiscuous bool   = false
        err         error
        timeout     time.Duration = 30 * time.Second
        handle      *pcap.Handle
    )
    
    func main() {
        // Open device
        handle, err = pcap.OpenLive(device, snapshotLen, promiscuous, timeout)
        if err != nil {log.Fatal(err) }
        defer handle.Close()
    
        packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
        for packet := range packetSource.Packets() {
            printPacketInfo(packet)
        }
    }
    
    func printPacketInfo(packet gopacket.Packet) {
        // Let's see if the packet is an ethernet 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()
        }
    
        // Let's see if the packet is IP (even though the ether type told us)
        ipLayer := packet.Layer(layers.LayerTypeIPv4)
        if ipLayer != nil {
            fmt.Println("IPv4 layer detected.")
            ip, _ := ipLayer.(*layers.IPv4)
    
            // IP layer variables:
            // Version (Either 4 or 6)
            // IHL (IP Header Length in 32-bit words)
            // TOS, Length, Id, Flags, FragOffset, TTL, Protocol (TCP?),
            // Checksum, SrcIP, DstIP
            fmt.Printf("From %s to %s\n", ip.SrcIP, ip.DstIP)
            fmt.Println("Protocol: ", ip.Protocol)
            fmt.Println()
        }
    
        // Let's see if the packet is TCP
        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)
        }
    }

    Creating and Sending Packets

    This example does a couple things. First it will show how to use the network device to send raw bytes. In that way, you can use it almost like a serial connection to send data. That's useful for really low level data transfer, but if you want to interact with an application you probably want to build a packet that other hard and software can recognize.

    The next thing it does is show how to create a a packet with the ethernet, IP, and TCP layers. Everything is default and empty though so it doesn't really do anything.

    To finish it off we create another packet but actually fill in some MAC addresses for the ethernet layer, some IP addresses for IPv4, and port numbers for the TCP layer. You should see how you can forge packets and impersonate devices with that.

    The TCP layer struct has boolean SYN, FIN, and ACK flags that can be read or set. That is good for manipulating and fuzzing TCP handshakes, sessions, and port scanning.

    The pcap library provides an easy way to send bytes, but the layers package in gopacket assists us in creating the byte structure for the many layers.

    package main
    
    import (
        "github.com/google/gopacket"
        "github.com/google/gopacket/layers"
        "github.com/google/gopacket/pcap"
        "log"
        "net"
        "time"
    )
    
    var (
        device       string = "eth0"
        snapshot_len int32  = 1024
        promiscuous  bool   = false
        err          error
        timeout      time.Duration = 30 * time.Second
        handle       *pcap.Handle
        buffer       gopacket.SerializeBuffer
        options      gopacket.SerializeOptions
    )
    
    func main() {
        // Open device
        handle, err = pcap.OpenLive(device, snapshot_len, promiscuous, timeout)
        if err != nil {log.Fatal(err) }
        defer handle.Close()
    
        // Send raw bytes over wire
        rawBytes := []byte{10, 20, 30}
        err = handle.WritePacketData(rawBytes)
        if err != nil {
            log.Fatal(err)
        }
    
        // Create a properly formed packet, just with
        // empty details. Should fill out MAC addresses,
        // IP addresses, etc.
        buffer = gopacket.NewSerializeBuffer()
        gopacket.SerializeLayers(buffer, options,
            &layers.Ethernet{},
            &layers.IPv4{},
            &layers.TCP{},
            gopacket.Payload(rawBytes),
        )
        outgoingPacket := buffer.Bytes()
        // Send our packet
        err = handle.WritePacketData(outgoingPacket)
        if err != nil {
            log.Fatal(err)
        }
    
        // This time lets fill out some information
        ipLayer := &layers.IPv4{
            SrcIP: net.IP{127, 0, 0, 1},
            DstIP: net.IP{8, 8, 8, 8},
        }
        ethernetLayer := &layers.Ethernet{
            SrcMAC: net.HardwareAddr{0xFF, 0xAA, 0xFA, 0xAA, 0xFF, 0xAA},
            DstMAC: net.HardwareAddr{0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD},
        }
        tcpLayer := &layers.TCP{
            SrcPort: layers.TCPPort(4321),
            DstPort: layers.TCPPort(80),
        }
        // And create the packet with the layers
        buffer = gopacket.NewSerializeBuffer()
        gopacket.SerializeLayers(buffer, options,
            ethernetLayer,
            ipLayer,
            tcpLayer,
            gopacket.Payload(rawBytes),
        )
        outgoingPacket = buffer.Bytes()
    }

    More on Creating/Decoding Packets

    package main
    
    import (
        "fmt"
        "github.com/google/gopacket"
        "github.com/google/gopacket/layers"
    )
    
    func main() {
        // If we don't have a handle to a device or a file, but we have a bunch
        // of raw bytes, we can try to decode them in to packet information
    
        // NewPacket() takes the raw bytes that make up the packet as the first parameter
        // The second parameter is the lowest level layer you want to decode. It will
        // decode that layer and all layers on top of it. The third layer
        // is the type of decoding: default(all at once), lazy(on demand), and NoCopy
        // which will not create a copy of the buffer
    
        // Create an packet with ethernet, IP, TCP, and payload layers
        // We are creating one we know will be decoded properly but
        // your byte source could be anything. If any of the packets
        // come back as nil, that means it could not decode it in to
        // the proper layer (malformed or incorrect packet type)
        payload := []byte{2, 4, 6}
        options := gopacket.SerializeOptions{}
        buffer := gopacket.NewSerializeBuffer()
        gopacket.SerializeLayers(buffer, options,
            &layers.Ethernet{},
            &layers.IPv4{},
            &layers.TCP{},
            gopacket.Payload(payload),
        )
        rawBytes := buffer.Bytes()
    
        // Decode an ethernet packet
        ethPacket :=
            gopacket.NewPacket(
                rawBytes,
                layers.LayerTypeEthernet,
                gopacket.Default,
            )
    
        // with Lazy decoding it will only decode what it needs when it needs it
        // This is not concurrency safe. If using concurrency, use default
        ipPacket :=
            gopacket.NewPacket(
                rawBytes,
                layers.LayerTypeIPv4,
                gopacket.Lazy,
            )
    
        // With the NoCopy option, the underlying slices are referenced
        // directly and not copied. If the underlying bytes change so will
        // the packet
        tcpPacket :=
            gopacket.NewPacket(
                rawBytes,
                layers.LayerTypeTCP,
                gopacket.NoCopy,
            )
    
        fmt.Println(ethPacket)
        fmt.Println(ipPacket)
        fmt.Println(tcpPacket)
    }

    Custom Layers

    This next program will show how to create your own layer. This is good for impelmenting a protocol that is not included with the gopacket layers package already. It is also useful if you want to create your own l33t protocol that does not even use TCP/IP or ethernet.

    package main
    
    import (
        "fmt"
        "github.com/google/gopacket"
    )
    
    // Create custom layer structure
    type CustomLayer struct {
        // This layer just has two bytes at the front
        SomeByte    byte
        AnotherByte byte
        restOfData  []byte
    }
    
    // Register the layer type so we can use it
    // The first argument is an ID. Use negative
    // or 2000+ for custom layers. It must be unique
    var CustomLayerType = gopacket.RegisterLayerType(
        2001,
        gopacket.LayerTypeMetadata{
            "CustomLayerType",
            gopacket.DecodeFunc(decodeCustomLayer),
        },
    )
    
    // When we inquire about the type, what type of layer should
    // we say it is? We want it to return our custom layer type
    func (l CustomLayer) LayerType() gopacket.LayerType {
        return CustomLayerType
    }
    
    // LayerContents returns the information that our layer
    // provides. In this case it is a header layer so
    // we return the header information
    func (l CustomLayer) LayerContents() []byte {
        return []byte{l.SomeByte, l.AnotherByte}
    }
    
    // LayerPayload returns the subsequent layer built
    // on top of our layer or raw payload
    func (l CustomLayer) LayerPayload() []byte {
        return l.restOfData
    }
    
    // Custom decode function. We can name it whatever we want
    // but it should have the same arguments and return value
    // When the layer is registered we tell it to use this decode function
    func decodeCustomLayer(data []byte, p gopacket.PacketBuilder) error {
        // AddLayer appends to the list of layers that the packet has
        p.AddLayer(&CustomLayer{data[0], data[1], data[2:]})
    
        // The return value tells the packet what layer to expect
        // with the rest of the data. It could be another header layer,
        // nothing, or a payload layer.
    
        // nil means this is the last layer. No more decoding
        // return nil
    
        // Returning another layer type tells it to decode
        // the next layer with that layer's decoder function
        // return p.NextDecoder(layers.LayerTypeEthernet)
    
        // Returning payload type means the rest of the data
        // is raw payload. It will set the application layer
        // contents with the payload
        return p.NextDecoder(gopacket.LayerTypePayload)
    }
    
    func main() {
        // If you create your own encoding and decoding you can essentially
        // create your own protocol or implement a protocol that is not
        // already defined in the layers package. In our example we are just
        // wrapping a normal ethernet packet with our own layer.
        // Creating your own protocol is good if you want to create
        // some obfuscated binary data type that was difficult for others
        // to decode
    
        // Finally, decode your packets:
        rawBytes := []byte{0xF0, 0x0F, 65, 65, 66, 67, 68}
        packet := gopacket.NewPacket(
            rawBytes,
            CustomLayerType,
            gopacket.Default,
        )
        fmt.Println("Created packet out of raw bytes.")
        fmt.Println(packet)
    
        // Decode the packet as our custom layer
        customLayer := packet.Layer(CustomLayerType)
        if customLayer != nil {
            fmt.Println("Packet was successfully decoded with custom layer decoder.")
            customLayerContent, _ := customLayer.(*CustomLayer)
            // Now we can access the elements of the custom struct
            fmt.Println("Payload: ", customLayerContent.LayerPayload())
            fmt.Println("SomeByte element:", customLayerContent.SomeByte)
            fmt.Println("AnotherByte element:", customLayerContent.AnotherByte)
        }
    }

    Decoding Packets Faster

    If we know what layers to expect, we can use existing structures to store the packet information instead of creating new structs for every packet which takes time and memory. It is faster to use DecodingLayerParser. It is like marshalling and unmarshalling data.

    package main
    
    import (
        "fmt"
        "github.com/google/gopacket"
        "github.com/google/gopacket/layers"
        "github.com/google/gopacket/pcap"
        "log"
        "time"
    )
    
    var (
        device       string = "eth0"
        snapshot_len int32  = 1024
        promiscuous  bool   = false
        err          error
        timeout      time.Duration = 30 * time.Second
        handle       *pcap.Handle
        // Will reuse these for each packet
        ethLayer layers.Ethernet
        ipLayer  layers.IPv4
        tcpLayer layers.TCP
    )
    
    func main() {
        // Open device
        handle, err = pcap.OpenLive(device, snapshot_len, promiscuous, timeout)
        if err != nil {
            log.Fatal(err)
        }
        defer handle.Close()
    
        packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
        for packet := range packetSource.Packets() {
            parser := gopacket.NewDecodingLayerParser(
                layers.LayerTypeEthernet,
                &ethLayer,
                &ipLayer,
                &tcpLayer,
            )
            foundLayerTypes := []gopacket.LayerType{}
    
            err := parser.DecodeLayers(packet.Data(), &foundLayerTypes)
            if err != nil {
                fmt.Println("Trouble decoding layers: ", err)
            }
    
            for _, layerType := range foundLayerTypes {
                if layerType == layers.LayerTypeIPv4 {
                    fmt.Println("IPv4: ", ipLayer.SrcIP, "->", ipLayer.DstIP)
                }
                if layerType == layers.LayerTypeTCP {
                    fmt.Println("TCP Port: ", tcpLayer.SrcPort, "->", tcpLayer.DstPort)
                    fmt.Println("TCP SYN:", tcpLayer.SYN, " | ACK:", tcpLayer.ACK)
                }
            }
        }
    }
    展开全文
  • gopacket 使用手册 学习笔记 中文文档

    千次阅读 2021-01-08 14:53:59
    gopacket 文档地址:https://godoc.org/github.com/google/gopacket 视频介绍:https://www.youtube.com/watch?v=APDnbmTKjgM 子包 layers: 用于解码数据包协议 pcap: 使用libpcap来读取数据包 pfring: 使用PF_RING...

    gopacket

    文档地址:https://godoc.org/github.com/google/gopacket
    视频介绍:https://www.youtube.com/watch?v=APDnbmTKjgM

    子包

    • layers: 用于解码数据包协议
    • pcap: 使用libpcap来读取数据包
    • pfring: 使用PF_RING来读取数据包
    • afpacket: 使用Linux’s AF_PACKET来读取数据包
    • tcpassembly: TCP流重组
    • gopacket使用示例:https://colobu.com/2019/06/01/packet-capture-injection-and-analysis-gopacket/
    • 流重组示例:https://github.com/google/gopacket/blob/master/examples/httpassembly/main.go

    pcap处理

    查看版本

    version := pcap.Version()
    fmt.Println(version)
    

    测试(Win10 x64):
    Npcap version 1.00, based on libpcap version 1.9.1

    网络接口

    类型:pcap.Interface

    type Interface struct {
    	Name        string
    	Description string
    	Flags       uint32
    	Addresses   []InterfaceAddress
    }
    type InterfaceAddress struct {
    	IP        net.IP
    	Netmask   net.IPMask // Netmask may be nil if we were unable to retrieve it.
    	Broadaddr net.IP     // Broadcast address for this IP may be nil
    	P2P       net.IP     // P2P destination address for this IP may be nil
    }
    

    查找网络设备:

    var devices []pcap.Interface
    devices, _ = pcap.FindAllDevs()
    fmt.Println(devices)
    

    实时捕获

    handle, err := pcap.OpenLive("\\Device\\NPF_{5C9384EF-DEBA-43A6-AE6A-5D10C952C481}", int32(65535), true, -1 * time.Second)
    if err != nil {
        log.Fatal(err)
    }
    defer handle.Close()
    

    pcap.OpenLive参数:

    • 设备名:pcap.FindAllDevs()返回的设备的Name
    • snaplen:捕获一个数据包的多少个字节,一般来说对任何情况65535是一个好的实践,如果不关注全部内容,只关注数据包头,可以设置成1024
    • promisc:设置网卡是否工作在混杂模式,即是否接收目的地址不为本机的包
    • timeout:设置抓到包返回的超时。如果设置成30s,那么每30s才会刷新一次数据包;设置成负数,会立刻刷新数据包,即不做等待
    • 要记得释放掉handle

    打开pcap

    handle, _ = pcap.OpenOffline("dump.pcap")
    defer handle.Close()
    

    创建一个数据包源

    通过监听设备的实时流量或者来自文件的数据包,得到了一个handle,通过这个handle得到一个数据包源packetSource。

    packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
    

    利用handle.LinkType()就不用知道链路类型了。

    读取数据包

    读取一个数据包:packet, _ := packetSource.NextPacket()
    获得一个可以读取数据包的channel来读取全部数据包

    packet := packetSource.Packets()
    for packet := range packet{
        fmt.Println(packet)
    }
    

    设置过滤器

    使用BPF语法即可。

    handle.SetBPFFilter("tcp and port 80")
    

    创建一个pcap用于写入

    dumpFile, _ := os.Create("dump.pcap")
    defer dumpFile.Close()
    packetWriter := pcapgo.NewWriter(dumpFile)
    packetWriter.WriteFileHeader(65535, layers.LinkTypeEthernet)
    

    packetWriter.WriteFileHeader的参数是snaplen和链路类型

    写入数据包

    packet := packetSource.Packets()
    for packet := range packet{
        packetWriter.WritePacket(packet.Metadata().CaptureInfo, packet.Data())
    }
    

    packet处理

    列出所有层

    for _, layer := range packet.Layers() {
        fmt.Println(layer.LayerType())
        fmt.Println(layer.LayerContents())
        fmt.Println(layer.LayerPayload())
    }
    
    • layer.LayerType():这层的类型
    • layer.LayerContents():当前层的内容
    • layer.LayerPayload():当前层承载的payload(不包括当前层)

    分析某层的数据

    IPv4

    ipLayer := packet.Layer(layers.LayerTypeIPv4)
    if ipLayer != nil {
        ip, _ := ipLayer.(*layers.IPv4)
        fmt.Println(ip.SrcIP, ip.DstIP)
        fmt.Println(ip.Protocol)
    }
    

    TCP

    tcpLayer := packet.Layer(layers.LayerTypeTCP)
    if tcpLayer != nil {
        ip, _ := tcpLayer.(*layers.TCP)
        fmt.Println(ip.SrcPort, ip.DstPort)
    }
    

    这里有一些需要注意的:

    • tcpLayer是通过接口packet.Layer返回的一个Layer,一个指向layers.TCP的指针
    • tcplayers.TCP这个具体类型的指针,也可以说tcp是真实的tcp层数据

    单独的解码器

    可以从多个起点对数据包进行解码。可以解码没有完整数据的数据包。

    // Decode an ethernet packet
    ethP := gopacket.NewPacket(packet, layers.LayerTypeEthernet, gopacket.Default)
    // Decode an IPv6 header and everything it contains
    ipP := gopacket.NewPacket(packet, layers.LayerTypeIPv6, gopacket.Default)
    // Decode a TCP header and its payload
    tcpP := gopacket.NewPacket(packet, layers.LayerTypeTCP, gopacket.Default)
    

    懒惰解码(Lazy Decoding)

    创建一个packet包,但是不立刻解码,只有后面需要用的时候再解码。比如第二行解码IPv4层,如果有的话,就解码IPv4层,然后不做进一步处理(不解码后续的层);如果没有会解码整个packet来寻找IPv4层。
    packet.Layers()会解码所有层并且返回,已经解码的层不会再次做解码。

    注意:这种方式并不是并发安全的,对Layers的每次调用可能会改变数据包。

    packet := gopacket.NewPacket(myPacketData, layers.LayerTypeEthernet, gopacket.Lazy)
    ip4 := packet.Layer(layers.LayerTypeIPv4)
    // Decode all layers and return them.  The layers up to the first IPv4 layer
    // are already decoded, and will not require decoding a second time.
    layers := packet.Layers()
    

    NoCopy解码

    上述两种解码方式会复制切片,对切片的字节进行更改不会影响数据包本身。如果可以保证不修改切片,可以使用NoCopy。

    for data := range myByteSliceChannel { 
    	p := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy)
    	doSomethingWithPacket(p)
    }
    

    快速解码

    不会创建新的内存结构。会重用内存结构,所以只能用于预定义好层的结构。

    for packet := range packetSource.Packets() {
        var eth layers.Ethernet
        var ip4 layers.IPv4
        var tcp layers.TCP
        parser := gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet, &eth, &ip4, &tcp)
        var decodedLayers []gopacket.LayerType
        parser.DecodeLayers(packet.Data(), &decodedLayers)
        for _, layerType := range decodedLayers {
            fmt.Println(layerType)
        }
    }
    

    自定义层数据

    注册自定义的层

    gopacket.RegisterLayerType():传入一个独有的id,和层类型对应的Metadata,包括有名字和对应的解码器。

    var MyLayerType = gopacket.RegisterLayerType(12345, gopacket.LayerTypeMetadata{Name: "MyLayerType", Decoder: gopacket.DecodeFunc(decodeMyLayer)})
    

    定义层的结构

    要实现三个方法。

    type MyLayer struct {
    	MyHeader  []byte
    	MyPayload []byte
    }
    func (m MyLayer) LayerType() gopacket.LayerType {
        return MyLayerType
    }
    func (m MyLayer) LayerContents() []byte {
        return m.MyHeader
    }
    func (m MyLayer) LayerPayload() []byte {
        return m.MyPayload
    }
    

    定义解码器

    func decodeMyLayer(data []byte, p gopacket.PacketBuilder) error {
    	p.AddLayer(&MyLayer{data[:4], data[4:]})
    	return p.NextDecoder(layers.LayerTypeEthernet)
    }
    

    对自定义的层进行解码

    pkt := gopacket.NewPacket(packet.Data(), MyLayerType, gopacket.Default)
    

    创建与发送

    创建

    创建一个新的序列化缓冲区;然后把所有层序列化到缓冲区中。

    buffer := gopacket.NewSerializeBuffer()
    options := gopacket.SerializeOptions{}
    gopacket.SerializeLayers(buffer, options, &layers.Ethernet{}, &layers.IPv4{}, &layers.TCP{}, gopacket.Payload([]byte{65, 66, 67}))
    

    发送数据包

    handle.WritePacketData(buffer.Bytes())
    

    流和端点(Flow and Endpoint)

    注意:这个地方官方文档感觉有坑

    • pkt.NetworkLayer().NetworkFlow():取网络层,网络流,IP地址
    • pkt.TransportLayer().TransportFlow():取传输层,传输端点,端口
    • interestingFlow:定义好端点,对网络数据做匹配
    pkt := gopacket.NewPacket(packet.Data(), layers.LayerTypeEthernet, gopacket.Lazy)
    netFlow := pkt.NetworkLayer().NetworkFlow()
    src, dst := netFlow.Endpoints()
    fmt.Println(src, dst)
    fmt.Println("Done.")
    tcpFlow := pkt.TransportLayer().TransportFlow()
    fmt.Println(tcpFlow.Endpoints())
    interestingFlow, _ := gopacket.FlowFromEndpoints(layers.NewUDPPortEndpoint(1000), layers.NewUDPPortEndpoint(500))
    if t := pkt.TransportLayer(); t != nil && t.TransportFlow() == interestingFlow {
        fmt.Println("Found that UDP flow I was looking for!")
    }
    
    展开全文
  • gopacket简介1. gopacket是什么?gopacket是google出品的golang三方库,质量还是靠的住,项目地址为:github.com/google/gopacketg...
  • gopacket解析DNS协议

    千次阅读 2019-08-22 16:25:11
    通过gopacket解析DNS请求协议。 读取单个数据包 ,IP层ID为19777。 读取19777数据包DNS协议的TransactionID package main import ( "fmt" "time" "github.com/google/gopacket/layers" "github....
  • 由于gopacket构建在libpcap之上,我强烈建议您了解该库的工作原理。您可以在 C 中学习如何使用libpcap进行更深入的了解。 1.libpcap gopacket是基于 libpcap(数据包捕获函数库)的,该库提供的C函数接口用于...
  • gopacket 使用

    2016-01-26 15:06:07
    原文出自http://www.devdungeon.com/content/packet-capture-injection-and-analysis-gopacket Overview Intro Before Starting...
  • 使用 google 提高的 gopacket 库包进行抓包, 拿到的数据往一个 channel 里面怼,如果队列满,则直接抛弃,可以理解为采样。这个 channel 可以多协程消费,建议就一个消费者。 从 channel 里拿到 packet 结构对象,...
  • package main ... "github.com/google/gopacket/pcap" "github.com/google/gopacket/layers" "github.com/google/gopacket" manuf "github.com/timest/gomanuf" "context" "time" "sync" ) type IP
  • 一、首先,下载gopacket包,libpcap库,配置下条件 在终端中输入以下命令: # Get the gopacket package from GitHub go get github.com/google/gopacket # Pcap dev headers might be necessary sudo apt-get ...
  • gopacket解析Dot11层

    2017-07-05 13:09:19
    <p>I'm trying to use gopacket to parse the packets of a .pcap file and pretty much to get all the information in it, until now I get either truncated information or an error IF I try to use a filter. ...
  • 使用gopacket解析协议层中的相关数据

    千次阅读 2019-08-15 09:17:33
    使用gopacket获取数据包中的相关内容
  • 声明:Linux(Ubuntu) 系统 1、导包 package main import ( ... "github.com/google/gopacket" "github.com/google/gopacket/layers" "github.com/google/gopacket/pcap" "log" "net" "time" ) 2、
  • Go语言用GoPacket抓包分析

    千次阅读 2017-10-18 17:29:53
    前言 离线pcap包解析 离线数据包分析源码分析 新建packetSource ...使用的Google的gopacket包来进行。基于的是libcap包。github地址:https://github.com/google/gopacket我并不喜欢GoDoc的行文风格,对于dem
  • packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) packetSource.NoCopy = true for packet := range packetSource.Packets() { if packet.NetworkLayer(www.tianzunyule178.com) == nil |...
  • <p>/home/go/src/github.com/google/gopacket/pcap/pcap.go:30:22: undefined: pcapErrorNotActivated /home/go/src/github.com/google/gopacket/pcap/pcap.go:52:17: undefined: pcapTPtr /home/go/src/github....
  • "github.com/google/gopacket" get_pkg.go 抓包,并且解析成string并且调用渲染成fyne的list 注意坑:NetworkLayer和TransportLayer都可能为nil package ip import ( "fmt" "fyne.io/fyne/v2/data/binding" ...
  • <p>I am using the gopacket/layers api to extract upd data out of a packet then sending it again via another udp stream, I am not sure if am doing this correct or not, also have been getting some ...
  • 前阵子有个需求是使用 golang 抓包改包,我用到了 gopacket 这个包,但是出了一些小问题。 我按照网上的方法进行使用 OpenLive 抓包,发现并不行,报错 error open adapter 啥啥啥。 经过调试发现根本找不到这个网卡...
  • <p>I am trying to construct TCP packets using the golang libraries gopacket and layers. In layers there is a struct aptly called <a href="https://godoc.org/github.com/packetb-old/gopacket/layers#TCP" ...
  • Go语言获取实时网速(gopacket实践)

    千次阅读 热门讨论 2018-10-06 16:22:23
    gopacket 是经过 cgo 封装的 libpcap 的接口,这样便于我们在 go 语言中使用 libpcap 。 前提 libpcap 是Linux平台的抓包框架,它也有Windows移植版,比如 winpcap ,但在2013年已停止维护。所以本文采用的是 ...
  • 欢迎使用Markdown编辑器写博客 本Markdown编辑器使用StackEdit修改而来,用它写博客,将会带来全新的体验哦: Markdown和扩展Markdown简洁的语法 代码块高亮 图片链接和图片上传 LaTex数学公式 ...
  • <p>I am trying to use <a href="https://github.com/google/gopacket" rel="nofollow">gopacket</a> on my windows 10. I'm using it to sniff and inject packets directly to/from the NIC. I can easily...

空空如也

空空如也

1 2 3 4 5 ... 18
收藏数 352
精华内容 140
关键字:

gopacket

友情链接: Firework.zip