• gopacket使用示例


    gopacket使用

    简介

    gopacket是goole写的golang抓包库,针对libpcap和npcap进行封装,提供更方便的go接口,并且

    安装

    前提:

    • windows系统需要npcap,你可以到npcap官网进行下载。
    • linux系统需要libpcap,你可以使用以下命令安装,也可以到官网进行下载。
    sudo apt-get install libpcap-dev
    
    • 1

    安装gopacket

    go get github.com/google/gopacket
    
    • 1

    项目结构

    示例

    查找设备

    package main
    
    import (
    	"fmt"
    	"log"
    
    	"github.com/google/gopacket/pcap"
    )
    
    func main() {
    	// 得到所有的(网络)设备
    	devices, err := pcap.FindAllDevs()
    	if err != nil {
    		log.Fatal(err)
    	}
    	// 打印设备信息
    	fmt.Println("Devices found:")
    	for _, device := range devices {
    		fmt.Println("\nName: ", device.Name)
    		fmt.Println("Description: ", device.Description)
    		fmt.Println("Devices flag: ", device.Flags)
    		for _, address := range device.Addresses {
    			fmt.Println("- IP address: ", address.IP)
    			fmt.Println("- Subnet mask: ", address.Netmask)
    			fmt.Println("- Broadaddr:  ", address.Broadaddr)
    			fmt.Println("- P2P:  ", address.P2P)
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    pcap包是gopacket针对pcap库的封装,FindAllDevs可以列出本机所有的网络设备,其定义如下

    func FindAllDevs() (ifs []Interface, err error)
    
    • 1

    下面列出Interface的定义,

    type InterfaceAddress struct {
    	IP        net.IP	// IP地址
    	Netmask   net.IPMask 	// 子网掩码
    	Broadaddr net.IP    	// 广播地址
    	P2P       net.IP     	// p2p地址
    }
    
    
    type Interface struct {
    	Name        string	// 设备名称
    	Description string	// 设备描述
    	Flags       uint32	// 设备标志
    	Addresses   []InterfaceAddress
    }
    
    flag取值
    ● PCAP_IF_LOOPBACK: 设备是否为环回接口 
    ● PCAP_IF_UP: : 设备是否启动 
    ● PCAP_IF_WIRELESS: 设备是否为无线接口,包括IrDA以及基于无线电的网络,不仅仅是wifi 
    ● PCAP_IF_CONNECTION_STATUS: 设备是否已连接的位掩码, 
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    打开设备

    在pcap包中定义了两种打开设备的方式和两种打开文件的方式:

    • OpenLive1

    • NewInactiveHandle2

    • OpenOffline3

    • OpenOfflineFile4

    打开设备进行实时捕获

    package main
    
    import (
    	"fmt"
    	"log"
    	"time"
    
    	"github.com/google/gopacket"
    	"github.com/google/gopacket/pcap"
    )
    
    var (
    	device       string = " \\Device\\NPF_{C410B1B0-56DE-4CD5-BC7A-5A5ACAB7619F}\n"
    	snapshot_len int32  = 65536
    	promiscuous  bool   = true
    	err          error
    	timeout      time.Duration = -1 * time.Second
    	handle       *pcap.Handle
    )
    
    func main() {
    	// 打开设备进行实时捕获
    	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() {
    		// 打印包
    		fmt.Println(packet)
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    上面示例中,我们通过OpenLive1打开一个实时设备,然后将句柄传递给PacketSource5进行处理,下面我们来解释下gopacket.NewPacketSource:

    NewPacketSource6只是构造一个PacketSource5对象,但是当我们调用Packet7函数时会启动一个协程来进行读取数据包,并将其写入到返回的管道中

    打开pcap文件

    package main
    
    import (
    	"fmt"
    	"log"
    
    	"github.com/google/gopacket"
    	"github.com/google/gopacket/pcap"
    )
    
    var (
    	pcapFile string = "test.pcap"
    	handle   *pcap.Handle
    	err      error
    )
    
    func main() {
    	// 打开pcap文件
    	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)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    捕获包并写入到pcap文件

    下面示例了捕获包,并且转储到文件中,其过程如下:

    1. 打开一个文件句柄
    2. 通过NewWriter8构造writer
    3. WriteFileHeader9写入文件头
    4. 关闭文件
    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 (
    	device      string = "\\Device\\NPF_{C410B1B0-56DE-4CD5-BC7A-5A5ACAB7619F}"
    	snaplen     int32  = 65536
    	promiscuous bool   = true
    	err         error
    	timeout     time.Duration = -1 * time.Second
    	handle      *pcap.Handle
    	packetCount int = 0
    )
    
    func main() {
    	// 打开一个输出的文件句柄
    	f, _ := os.Create("test.pcap")
    	// 创建一个writer对象
    	w := pcapgo.NewWriter(f)
    	// 写入文件头,必须在调用前调用
    	w.WriteFileHeader(uint32(snaplen), layers.LinkTypeEthernet)
    	defer f.Close()
    	// 打开一个实时捕获设备
    	handle, err = pcap.OpenLive(device, snaplen, promiscuous, timeout)
    	if err != nil {
    		fmt.Printf("Error opening device %s: %v", device, err)
    		os.Exit(1)
    	}
    	defer handle.Close()
    
    	// 创建包数据源
    	packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
    	// 读取包
    	for packet := range packetSource.Packets() {
    		// 打印包
    		fmt.Println(packet)
    		// 写入包
    		w.WritePacket(packet.Metadata().CaptureInfo, packet.Data())
    		packetCount++
    
    		// Only capture 100 and then stop
    		if packetCount > 100 {
    			break
    		}
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    解析各个层

    package main
    
    import (
    	"fmt"
    	"log"
    	"strings"
    	"time"
    
    	"github.com/google/gopacket"
    	"github.com/google/gopacket/layers"
    	"github.com/google/gopacket/pcap"
    )
    
    var (
    	device      string = "\\Device\\NPF_{C410B1B0-56DE-4CD5-BC7A-5A5ACAB7619F}"
    	snaplen     int32  = 65536
    	promiscuous bool   = true
    	err         error
    	timeout     time.Duration = -1 * time.Second
    	handle      *pcap.Handle
    )
    
    func printEthInfo(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()
    	}
    }
    
    func printNetworkInfo(packet gopacket.Packet) {
    	// 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()
    	}
    }
    func printTransportInfo(packet gopacket.Packet) {
    	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()
    	}
    }
    func printApplicationInfo(packet gopacket.Packet) {
    	applicationLayer := packet.ApplicationLayer()
    	if applicationLayer != nil {
    		fmt.Println("Application layer/Payload found.")
    		fmt.Printf("%s\n", applicationLayer.LayerType())
    		// Search for a string inside the payload
    		if strings.Contains(string(applicationLayer.Payload()), "HTTP") {
    			fmt.Println("HTTP found!")
    		}
    	}
    }
    
    func printLayer(packet gopacket.Packet) {
    	fmt.Println("All packet layers:")
    	for _, layer := range packet.Layers() {
    		fmt.Println("- ", layer.LayerType())
    	}
    }
    
    func printErrInfo(packet gopacket.Packet) {
    	// Check for errors
    	if err := packet.ErrorLayer(); err != nil {
    		fmt.Println("Error decoding some part of the packet:", err)
    	}
    }
    
    func main() {
    	// Open device
    	handle, err = pcap.OpenLive(device, snaplen, promiscuous, timeout)
    	if err != nil {
    		log.Fatal(err)
    	}
    	defer handle.Close()
    	packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
    	for packet := range packetSource.Packets() {
    		fmt.Println("=========================")
    		printEthInfo(packet)
    		printNetworkInfo(packet)
    		printTransportInfo(packet)
    		printApplicationInfo(packet)
    		printLayer(packet)
    		printErrInfo(packet)
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109

    pcapgo捕获包

    pcapgo在linux系统上支持使用原生的接口进行捕获包,不需要依赖与libpcap

    package main
    
    import (
    	"log"
    	"os"
    
    	"github.com/google/gopacket"
    	"github.com/google/gopacket/layers"
    	"github.com/google/gopacket/pcapgo"
    )
    
    func main() {
    	f, err := os.Create("/tmp/lo.pcap")
    	if err != nil {
    		log.Fatal(err)
    	}
    	defer f.Close()
    	pcapw := pcapgo.NewWriter(f)
    	if err := pcapw.WriteFileHeader(1600, layers.LinkTypeEthernet); err != nil {
    		log.Fatalf("WriteFileHeader: %v", err)
    	}
    
    	handle, err := pcapgo.NewEthernetHandle("lo")
    	if err != nil {
    		log.Fatalf("OpenEthernet: %v", err)
    	}
    
    	pkgsrc := gopacket.NewPacketSource(handle, layers.LayerTypeEthernet)
    	for packet := range pkgsrc.Packets() {
    		if err := pcapw.WritePacket(packet.Metadata().CaptureInfo, packet.Data()); err != nil {
    			log.Fatalf("pcap.WritePacket(): %v", err)
    		}
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    解析FTP

    package main
    
    import (
    	"fmt"
    	"io"
    	"log"
    	"time"
    
    	"github.com/bin-work/go-example/npacket/08-ftpCapture/layer"
    	"github.com/google/gopacket"
    	"github.com/google/gopacket/layers"
    	"github.com/google/gopacket/pcap"
    )
    
    var (
    	device       string = "\\Device\\NPF_{48641DC5-6BD6-4752-9CA4-5C9706829705}"
    	snapshot_len int32  = 65536
    	promiscuous  bool   = true
    	err          error
    	timeout      time.Duration = -1 * time.Second
    	handle       *pcap.Handle
    	// Will reuse these for each packet
    	ethLayer layers.Ethernet
    	ipLayer  layers.IPv4
    	tcpLayer layers.TCP
    	ftpLayer layer.FTPLayer
    )
    
    func main() {
    	// Open device
    	handle, err = pcap.OpenLive(device, snapshot_len, promiscuous, timeout)
    	if err != nil {
    		log.Fatal(err)
    	}
    	defer handle.Close()
    	//var filter string = "tcp and port 10021"
    	//err = handle.SetBPFFilter(filter)
    	//if err != nil {
    	//	log.Fatal(err)
    	//}
    
    	layers.RegisterTCPPortLayerType(layers.TCPPort(21), layer.LayerTypeFTP)
    	dlp := gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet)
    	dlp.SetDecodingLayerContainer(gopacket.DecodingLayerSparse(nil))
    	//var eth layers.Ethernet
    	dlp.AddDecodingLayer(&ethLayer)
    	dlp.AddDecodingLayer(&ipLayer)
    	dlp.AddDecodingLayer(&tcpLayer)
    	dlp.AddDecodingLayer(&ftpLayer)
    
    	// ... 添加层并照常使用 DecodingLayerParser...
    	packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
    
    	for {
    		packet, err := packetSource.NextPacket()
    		if err == io.EOF {
    			break
    		} else if err != nil {
    			log.Println("Error:", err)
    			continue
    		}
    		foundLayerTypes := []gopacket.LayerType{}
    		err = dlp.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)
    			//}
    			if layerType == layer.LayerTypeFTP {
    				fmt.Println(ftpLayer.Command)
    			}
    
    		}
    	}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    // Copyright 2018 Google, Inc. All rights reserved.
    //
    // Use of this source code is governed by a BSD-style license
    // that can be found in the LICENSE file in the root of the source
    // tree.
    
    package layer
    
    import (
    	"bytes"
    	"fmt"
    	"io"
    	"regexp"
    	"strconv"
    	"strings"
    
    	"github.com/google/gopacket"
    )
    
    var LayerTypeFTP = gopacket.RegisterLayerType(147, gopacket.LayerTypeMetadata{Name: "FTP", Decoder: gopacket.DecodeFunc(DecodeFTP)})
    
    // FTPCommand defines the different commands fo the FTP Protocol
    type FTPCommand uint16
    
    // Here are all the FTP commands
    const (
    	FTPCommandAbor FTPCommand = iota + 1 // ABOR Abort an active file transfer.
    	FTPCommandAcct                       // ACCT Account information.
    	FTPCommandAdat                       // ADAT RFC 2228 Authentication/Security Data
    	FTPCommandAllo                       // ALLO Allocate sufficient disk space to receive a file.
    	FTPCommandAppe                       // APPE Append (with create)
    	FTPCommandAuth                       // AUTH RFC 2228 Authentication/Security Mechanism
    	FTPCommandAvbl                       // AVBL Streamlined FTP Command Extensions Get the available space
    	FTPCommandCcc                        // CCC RFC 2228 Clear Command Channel
    	FTPCommandCdup                       // CDUP Change to Parent Directory.
    	FTPCommandConf                       // CONF RFC 2228 Confidentiality Protection Command
    	FTPCommandCsid                       // CSID Streamlined FTP Command Extensions Client / Server Identification
    	FTPCommandCwd                        // CWD RFC 697 Change working directory.
    	FTPCommandDele                       // DELE Delete file.
    	FTPCommandDsiz                       // DSIZ Streamlined FTP Command Extensions Get the directory size
    	FTPCommandEnc                        // ENC RFC 2228 Privacy Protected Channel
    	FTPCommandEprt                       // EPRT RFC 2428 Specifies an extended address and port to which the server should connect.
    	FTPCommandEpsv                       // EPSV RFC 2428 Enter extended passive mode.
    	FTPCommandFeat                       // FEAT RFC 2389 Get the feature list implemented by the server.
    	FTPCommandHelp                       // HELP Returns usage documentation on a command if specified, else a general help document is returned.
    	FTPCommandHost                       // HOST RFC 7151 Identify desired virtual host on server, by name.
    	FTPCommandLang                       // LANG RFC 2640 Language Negotiation
    	FTPCommandList                       // LIST Returns information of a file or directory if specified, else information of the current working directory is returned.
    	FTPCommandLprt                       // LPRT RFC 1639 Specifies a long address and port to which the server should connect.
    	FTPCommandLpsv                       // LPSV RFC 1639 Enter long passive mode.
    	FTPCommandMdtm                       // MDTM RFC 3659 Return the last-modified time of a specified file.
    	FTPCommandMfct                       // MFCT The 'MFMT', 'MFCT', and 'MFF' Command Extensions for FTP Modify the creation time of a file.
    	FTPCommandMff                        // MFF The 'MFMT', 'MFCT', and 'MFF' Command Extensions for FTP Modify fact (the last modification time, creation time, UNIX group/owner/mode of a file).
    	FTPCommandMfmt                       // MFMT The 'MFMT', 'MFCT', and 'MFF' Command Extensions for FTP Modify the last modification time of a file.
    	FTPCommandMic                        // MIC RFC 2228 Integrity Protected Command
    	FTPCommandMkd                        // MKD Make directory.
    	FTPCommandMlsd                       // MLSD RFC 3659 Lists the contents of a directory if a directory is named.
    	FTPCommandMlst                       // MLST RFC 3659 Provides data about exactly the object named on its command line, and no others.
    	FTPCommandMode                       // MODE Sets the transfer mode (Stream, Block, or Compressed).
    	FTPCommandNlst                       // NLST Returns a list of file names in a specified directory.
    	FTPCommandNoop                       // NOOP No operation (dummy packet; used mostly on keepalives).
    	FTPCommandOpts                       // OPTS RFC 2389 Select options for a feature (for example OPTS UTF8 ON).
    	FTPCommandPass                       // PASS Authentication password.
    	FTPCommandPasv                       // PASV Enter passive mode.
    	FTPCommandPbsz                       // PBSZ RFC 2228 Protection Buffer Size
    	FTPCommandPort                       // PORT Specifies an address and port to which the server should connect.
    	FTPCommandProt                       // PROT RFC 2228 Data Channel Protection Level.
    	FTPCommandPwd                        // PWD Print working directory. Returns the current directory of the host.
    	FTPCommandQuit                       // QUIT Disconnect.
    	FTPCommandRein                       // REIN Re initializes the connection.
    	FTPCommandRest                       // REST RFC 3659 Restart transfer from the specified point.
    	FTPCommandRetr                       // RETR Retrieve a copy of the file
    	FTPCommandRmd                        // RMD Remove a directory.
    	FTPCommandRmda                       // RMDA Streamlined FTP Command Extensions Remove a directory tree
    	FTPCommandRnfr                       // RNFR Rename from.
    	FTPCommandRnto                       // RNTO Rename to.
    	FTPCommandSite                       // SITE Sends site specific commands to remote server (like SITE IDLE 60 or SITE UMASK 002). Inspect SITE HELP output for complete list of supported commands.
    	FTPCommandSize                       // SIZE RFC 3659 Return the size of a file.
    	FTPCommandSmnt                       // SMNT Mount file structure.
    	FTPCommandSpsv                       // SPSV FTP Extension Allowing IP Forwarding (NATs) Use single port passive mode (only one TCP port number for both control connections and passive-mode data connections)
    	FTPCommandStat                       // STAT Returns the current status.
    	FTPCommandStor                       // STOR Accept the data and to store the data as a file at the server site
    	FTPCommandStou                       // STOU Store file uniquely.
    	FTPCommandStru                       // STRU Set file transfer structure.
    	FTPCommandSyst                       // SYST Return system type.
    	FTPCommandThmb                       // THMB Streamlined FTP Command Extensions Get a thumbnail of a remote image file
    	FTPCommandType                       // TYPE Sets the transfer mode (ASCII/Binary).
    	FTPCommandUser                       // USER Authentication username.
    	FTPCommandXcup                       // XCUP RFC 775 Change to the parent of the current working directory
    	FTPCommandXmkd                       // XMKD RFC 775 Make a directory
    	FTPCommandXpwd                       // XPWD RFC 775 Print the current working directory
    	FTPCommandXrcp                       // XRCP RFC 743
    	FTPCommandXrmd                       // XRMD RFC 775 Remove the directory
    	FTPCommandXrsq                       // XRSQ RFC 743
    	FTPCommandXsem                       // XSEM RFC 737 Send, mail if cannot
    	FTPCommandXsen                       // XSEN RFC 737 Send to terminal
    )
    
    func (fc FTPCommand) String() string {
    	switch fc {
    	case FTPCommandAbor:
    		return "ABOR"
    	case FTPCommandAcct:
    		return "ACCT"
    	case FTPCommandAdat:
    		return "ADAT"
    	case FTPCommandAllo:
    		return "ALLO"
    	case FTPCommandAppe:
    		return "APPE"
    	case FTPCommandAuth:
    		return "AUTH"
    	case FTPCommandAvbl:
    		return "AVBL"
    	case FTPCommandCcc:
    		return "CCC"
    	case FTPCommandCdup:
    		return "CDUP"
    	case FTPCommandConf:
    		return "CONF"
    	case FTPCommandCsid:
    		return "CSID"
    	case FTPCommandCwd:
    		return "CWD"
    	case FTPCommandDele:
    		return "DELE"
    	case FTPCommandDsiz:
    		return "DSIZ"
    	case FTPCommandEnc:
    		return "ENC"
    	case FTPCommandEprt:
    		return "EPRT"
    	case FTPCommandEpsv:
    		return "EPSV"
    	case FTPCommandFeat:
    		return "FEAT"
    	case FTPCommandHelp:
    		return "HELP"
    	case FTPCommandHost:
    		return "HOST"
    	case FTPCommandLang:
    		return "LANG"
    	case FTPCommandList:
    		return "LIST"
    	case FTPCommandLprt:
    		return "LPRT"
    	case FTPCommandLpsv:
    		return "LPSV"
    	case FTPCommandMdtm:
    		return "MDTM"
    	case FTPCommandMfct:
    		return "MFCT"
    	case FTPCommandMff:
    		return "MFF"
    	case FTPCommandMfmt:
    		return "MFMT"
    	case FTPCommandMic:
    		return "MIC"
    	case FTPCommandMkd:
    		return "MKD"
    	case FTPCommandMlsd:
    		return "MLSD"
    	case FTPCommandMlst:
    		return "MLST"
    	case FTPCommandMode:
    		return "MODE"
    	case FTPCommandNlst:
    		return "NLST"
    	case FTPCommandNoop:
    		return "NOOP"
    	case FTPCommandOpts:
    		return "OPTS"
    	case FTPCommandPass:
    		return "PASS"
    	case FTPCommandPasv:
    		return "PASV"
    	case FTPCommandPbsz:
    		return "PBSZ"
    	case FTPCommandPort:
    		return "PORT"
    	case FTPCommandProt:
    		return "PROT"
    	case FTPCommandPwd:
    		return "PWD"
    	case FTPCommandQuit:
    		return "QUIT"
    	case FTPCommandRein:
    		return "REIN"
    	case FTPCommandRest:
    		return "REST"
    	case FTPCommandRetr:
    		return "RETR"
    	case FTPCommandRmd:
    		return "RMD"
    	case FTPCommandRmda:
    		return "RMDA"
    	case FTPCommandRnfr:
    		return "RNFR"
    	case FTPCommandRnto:
    		return "RNTO"
    	case FTPCommandSite:
    		return "SITE"
    	case FTPCommandSize:
    		return "SIZE"
    	case FTPCommandSmnt:
    		return "SMNT"
    	case FTPCommandSpsv:
    		return "SPSV"
    	case FTPCommandStat:
    		return "STAT"
    	case FTPCommandStor:
    		return "STOR"
    	case FTPCommandStou:
    		return "STOU"
    	case FTPCommandStru:
    		return "STRU"
    	case FTPCommandSyst:
    		return "SYST"
    	case FTPCommandThmb:
    		return "THMB"
    	case FTPCommandType:
    		return "TYPE"
    	case FTPCommandUser:
    		return "USER"
    	case FTPCommandXcup:
    		return "XCUP"
    	case FTPCommandXmkd:
    		return "XMKD"
    	case FTPCommandXpwd:
    		return "XPWD"
    	case FTPCommandXrcp:
    		return "XRCP"
    	case FTPCommandXrmd:
    		return "XRMD"
    	case FTPCommandXrsq:
    		return "XRSQ"
    	case FTPCommandXsem:
    		return "XSEM"
    	case FTPCommandXsen:
    		return "XSEN"
    	default:
    		return "Unknown command"
    	}
    }
    
    // GetFTPCommand returns the constant of a FTP command from its string
    func GetFTPCommand(command string) (FTPCommand, error) {
    	switch strings.ToUpper(command) {
    	case "ABOR":
    		return FTPCommandAbor, nil
    	case "ACCT":
    		return FTPCommandAcct, nil
    	case "ADAT":
    		return FTPCommandAdat, nil
    	case "ALLO":
    		return FTPCommandAllo, nil
    	case "APPE":
    		return FTPCommandAppe, nil
    	case "AUTH":
    		return FTPCommandAuth, nil
    	case "AVBL":
    		return FTPCommandAvbl, nil
    	case "CCC":
    		return FTPCommandCcc, nil
    	case "CDUP":
    		return FTPCommandCdup, nil
    	case "CONF":
    		return FTPCommandConf, nil
    	case "CSID":
    		return FTPCommandCsid, nil
    	case "CWD":
    		return FTPCommandCwd, nil
    	case "DELE":
    		return FTPCommandDele, nil
    	case "DSIZ":
    		return FTPCommandDsiz, nil
    	case "ENC":
    		return FTPCommandEnc, nil
    	case "EPRT":
    		return FTPCommandEprt, nil
    	case "EPSV":
    		return FTPCommandEpsv, nil
    	case "FEAT":
    		return FTPCommandFeat, nil
    	case "HELP":
    		return FTPCommandHelp, nil
    	case "HOST":
    		return FTPCommandHost, nil
    	case "LANG":
    		return FTPCommandLang, nil
    	case "LIST":
    		return FTPCommandList, nil
    	case "LPRT":
    		return FTPCommandLprt, nil
    	case "LPSV":
    		return FTPCommandLpsv, nil
    	case "MDTM":
    		return FTPCommandMdtm, nil
    	case "MFCT":
    		return FTPCommandMfct, nil
    	case "MFF":
    		return FTPCommandMff, nil
    	case "MFMT":
    		return FTPCommandMfmt, nil
    	case "MIC":
    		return FTPCommandMic, nil
    	case "MKD":
    		return FTPCommandMkd, nil
    	case "MLSD":
    		return FTPCommandMlsd, nil
    	case "MLST":
    		return FTPCommandMlst, nil
    	case "MODE":
    		return FTPCommandMode, nil
    	case "NLST":
    		return FTPCommandNlst, nil
    	case "NOOP":
    		return FTPCommandNoop, nil
    	case "OPTS":
    		return FTPCommandOpts, nil
    	case "PASS":
    		return FTPCommandPass, nil
    	case "PASV":
    		return FTPCommandPasv, nil
    	case "PBSZ":
    		return FTPCommandPbsz, nil
    	case "PORT":
    		return FTPCommandPort, nil
    	case "PROT":
    		return FTPCommandProt, nil
    	case "PWD":
    		return FTPCommandPwd, nil
    	case "QUIT":
    		return FTPCommandQuit, nil
    	case "REIN":
    		return FTPCommandRein, nil
    	case "REST":
    		return FTPCommandRest, nil
    	case "RETR":
    		return FTPCommandRetr, nil
    	case "RMD":
    		return FTPCommandRmd, nil
    	case "RMDA":
    		return FTPCommandRmda, nil
    	case "RNFR":
    		return FTPCommandRnfr, nil
    	case "RNTO":
    		return FTPCommandRnto, nil
    	case "SITE":
    		return FTPCommandSite, nil
    	case "SIZE":
    		return FTPCommandSize, nil
    	case "SMNT":
    		return FTPCommandSmnt, nil
    	case "SPSV":
    		return FTPCommandSpsv, nil
    	case "STAT":
    		return FTPCommandStat, nil
    	case "STOR":
    		return FTPCommandStor, nil
    	case "STOU":
    		return FTPCommandStou, nil
    	case "STRU":
    		return FTPCommandStru, nil
    	case "SYST":
    		return FTPCommandSyst, nil
    	case "THMB":
    		return FTPCommandThmb, nil
    	case "TYPE":
    		return FTPCommandType, nil
    	case "USER":
    		return FTPCommandUser, nil
    	case "XCUP":
    		return FTPCommandXcup, nil
    	case "XMKD":
    		return FTPCommandXmkd, nil
    	case "XPWD":
    		return FTPCommandXpwd, nil
    	case "XRCP":
    		return FTPCommandXrcp, nil
    	case "XRMD":
    		return FTPCommandXrmd, nil
    	case "XRSQ":
    		return FTPCommandXrsq, nil
    	case "XSEM":
    		return FTPCommandXsem, nil
    	case "XSEN":
    		return FTPCommandXsen, nil
    	default:
    		return 0, fmt.Errorf("Unknown FTP command: '%s'", command)
    	}
    }
    
    // FTP object contains information about an FTP packet
    type FTPLayer struct {
    	//BaseLayer
    	Contents   []byte
    	Command    FTPCommand
    	CommandArg string
    
    	IsResponse     bool
    	ResponseCode   int
    	ResponseStatus string
    
    	Delimiter string
    }
    
    func DecodeFTP(data []byte, p gopacket.PacketBuilder) error {
    	f := &FTPLayer{}
    	err := f.DecodeFromBytes(data, p)
    	if err != nil {
    		return err
    	}
    	p.AddLayer(f)
    	p.SetApplicationLayer(f)
    	return nil
    
    }
    
    // LayerType returns gopacket.LayerTypeFTP
    func (f *FTPLayer) LayerType() gopacket.LayerType { return LayerTypeFTP }
    
    func (f *FTPLayer) LayerContents() []byte { return f.Contents }
    
    func (f *FTPLayer) LayerPayload() []byte {
    	var r []byte
    	return r
    }
    
    // Payload returns the base layer payload (nil)
    func (f *FTPLayer) Payload() []byte { return nil }
    
    // CanDecode returns gopacket.LayerTypeFTP
    func (f *FTPLayer) CanDecode() gopacket.LayerClass { return LayerTypeFTP }
    
    // NextLayerType returns gopacket.LayerTypeZero
    func (f *FTPLayer) NextLayerType() gopacket.LayerType { return gopacket.LayerTypeZero }
    
    // DecodeFromBytes decodes the slice into the FTP struct.
    func (f *FTPLayer) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
    	var countLines int
    	var line []byte
    	var err error
    
    	//f.BaseLayer = BaseLayer{Contents: data[:len(data)]}
    	f.Contents = data[:len(data)]
    	// Clean leading new line
    	data = bytes.Trim(data, "\n")
    
    	buffer := bytes.NewBuffer(data)
    
    	var lastLine bool
    	for {
    		// Read next line
    		line, err = buffer.ReadBytes(byte('\n'))
    		if err != nil {
    			if err == io.EOF {
    				lastLine = true
    			} else {
    				return err
    			}
    		}
    
    		// Trim the new line delimiters
    		line = bytes.Trim(line, "\r\n")
    
    		if countLines == 0 {
    			err = f.parseFirstLine(line)
    			if err != nil {
    				return err
    			}
    		} else {
    			err = f.parseFollowupLine(line)
    			if err != nil {
    				return err
    			}
    		}
    		countLines++
    		if lastLine {
    			break
    		}
    	}
    
    	return nil
    }
    
    func (f *FTPLayer) parseFirstLine(line []byte) error {
    	var err error
    	if len(line) < 3 {
    		return fmt.Errorf("invalid first FTP line: '%s'", string(line))
    	}
    
    	re := regexp.MustCompile("^([0-9]{3})(.?)(.*)")
    	if res := re.FindStringSubmatch(string(line)); res != nil {
    		f.IsResponse = true
    		f.ResponseCode, err = strconv.Atoi(res[1])
    		if err != nil {
    			return err
    		}
    		f.Delimiter = res[2]
    		f.ResponseStatus = res[3]
    	} else {
    		splits := strings.SplitN(string(line), " ", 2)
    		f.Command, err = GetFTPCommand(splits[0])
    		if err != nil {
    			return err
    		}
    		if len(splits) > 1 {
    			f.Delimiter = " "
    			f.CommandArg = splits[1]
    		}
    	}
    	return nil
    }
    
    func (f *FTPLayer) parseFollowupLine(line []byte) error {
    	if f.IsResponse {
    		f.ResponseStatus += "\n" + string(line)
    	} else {
    		f.CommandArg += "\n" + string(line)
    	}
    	return nil
    }
    
    // SerializeTo writes the serialized form of this layer into the
    // SerializationBuffer, implementing gopacket.SerializableLayer.
    func (f *FTPLayer) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
    	if f.IsResponse {
    		bytes, err := b.PrependBytes(len(f.ResponseStatus) + len(f.Delimiter) + 5)
    		if err != nil {
    			return err
    		}
    		copy(bytes[0:3], fmt.Sprintf("%03d", f.ResponseCode))
    		copy(bytes[3:], f.Delimiter+f.ResponseStatus+"\r\n")
    	} else {
    		bytes, err := b.PrependBytes(len(f.Command.String()) + len(f.Delimiter) + len(f.CommandArg) + 2)
    		if err != nil {
    			return err
    		}
    		copy(bytes[0:], f.Command.String()+f.Delimiter+f.CommandArg+"\r\n")
    	}
    	return nil
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427
    • 428
    • 429
    • 430
    • 431
    • 432
    • 433
    • 434
    • 435
    • 436
    • 437
    • 438
    • 439
    • 440
    • 441
    • 442
    • 443
    • 444
    • 445
    • 446
    • 447
    • 448
    • 449
    • 450
    • 451
    • 452
    • 453
    • 454
    • 455
    • 456
    • 457
    • 458
    • 459
    • 460
    • 461
    • 462
    • 463
    • 464
    • 465
    • 466
    • 467
    • 468
    • 469
    • 470
    • 471
    • 472
    • 473
    • 474
    • 475
    • 476
    • 477
    • 478
    • 479
    • 480
    • 481
    • 482
    • 483
    • 484
    • 485
    • 486
    • 487
    • 488
    • 489
    • 490
    • 491
    • 492
    • 493
    • 494
    • 495
    • 496
    • 497
    • 498
    • 499
    • 500
    • 501
    • 502
    • 503
    • 504
    • 505
    • 506
    • 507
    • 508
    • 509
    • 510
    • 511
    • 512
    • 513
    • 514
    • 515
    • 516
    • 517
    • 518
    • 519
    • 520
    • 521
    • 522
    • 523
    • 524
    • 525
    • 526
    • 527
    • 528
    • 529
    • 530
    • 531
    • 532
    • 533
    • 534
    • 535
    • 536
    • 537
    • 538
    • 539
    • 540
    • 541
    • 542
    • 543
    • 544

    IP重组

    下面我们编写一个程序来对IP分片进行重组

    package main
    
    import (
    	"fmt"
    	"log"
    	"time"
    
    	"github.com/google/gopacket/ip4defrag"
    	"github.com/google/gopacket/layers"
    
    	"github.com/google/gopacket"
    	"github.com/google/gopacket/pcap"
    )
    
    var (
    	device       string = "\\Device\\NPF_{C410B1B0-56DE-4CD5-BC7A-5A5ACAB7619F}"
    	snapshot_len int32  = 65536
    	promiscuous  bool   = true
    	err          error
    	timeout      time.Duration = -1 * time.Second
    	handle       *pcap.Handle
    )
    
    func main() {
    	// 打开设备
    	// 打开设备进行实时捕获
    	handle, err = pcap.OpenLive(device, snapshot_len, promiscuous, timeout)
    	if err != nil {
    		log.Fatal(err)
    	}
    	defer handle.Close()
    	// 构造一个数据包源
    	source := gopacket.NewPacketSource(handle, handle.LinkType())
    	defragger := ip4defrag.NewIPv4Defragmenter()
    
    	// 读取包
    	for packet := range source.Packets() {
    		//fmt.Println("=========================")
    		//fmt.Println(packet)
    		// Process packet here
    		ip4Layer := packet.Layer(layers.LayerTypeIPv4)
    		if ip4Layer == nil {
    			continue
    		}
    		ip4 := ip4Layer.(*layers.IPv4)
    		l := ip4.Length
    		newip4, err := defragger.DefragIPv4(ip4)
    		if err != nil {
    			log.Fatalln("Error while de-fragmenting", err)
    		} else if newip4 == nil {
    			fmt.Println("Fragment...\n")
    			continue // packet fragment, we don't have whole packet yet.
    		}
    		if newip4.Length != l {
    			//stats.ipdefrag++
    			fmt.Printf("Decoding re-assembled packet: %s\n", newip4.NextLayerType())
    			pb, ok := packet.(gopacket.PacketBuilder)
    			if !ok {
    				panic("Not a PacketBuilder")
    			}
    			nextDecoder := newip4.NextLayerType()
    			nextDecoder.Decode(newip4.Payload, pb)
    		}
    
    		udpLayer := packet.Layer(layers.LayerTypeUDP)
    		if udpLayer != nil {
    			udp := udpLayer.(*layers.UDP)
    			if udp.DstPort == 30000 {
    				fmt.Println(udp.Length)
    				fmt.Println(string(udp.LayerPayload()))
    				fmt.Println("=========================")
    			}
    
    		}
    
    	}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    然后我们编写有一个UDP server和client来验证下

    package main
    
    import (
    	"fmt"
    	"net"
    )
    
    func main() {
    	listen, err := net.ListenUDP("udp", &net.UDPAddr{
    		IP:   net.IPv4(0, 0, 0, 0),
    		Port: 30000,
    	})
    	if err != nil {
    		fmt.Println("listen failed, err:", err)
    		return
    	}
    	defer listen.Close()
    	for {
    		var data [1024]byte
    		_, _, err := listen.ReadFromUDP(data[:]) // 接收数据
    		if err != nil {
    			fmt.Println("read udp failed, err:", err)
    			continue
    		}
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    package main
    
    import (
    	"fmt"
    	"net"
    )
    
    func main() {
    	socket, err := net.DialUDP("udp", nil, &net.UDPAddr{
    		IP:   net.IPv4(192, 168, 3, 100),
    		Port: 30000,
    	})
    	if err != nil {
    		fmt.Println("连接服务端失败,err:", err)
    		return
    	}
    	defer socket.Close()
    	sendData := []byte("Hello server")
    	for i := 0; i < 1590; i++ {
    		sendData = append(sendData, 'a')
    	}
    	_, err = socket.Write(sendData) // 发送数据
    	if err != nil {
    		fmt.Println("发送数据失败,err:", err)
    		return
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    运行server,然后运行client,我们可以看到程序成功识别并将UDP重组

    Fragment...
    
    Decoding re-assembled packet: UDP
    1610
    Hello serveraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    =========================
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    wireshark抓包结果:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a3H5GDSN-1659279442634)(assets/image-20220728183147-m6tfgux.png)]

    推荐一个零声学院免费公开课程,个人觉得老师讲得不错,
    分享给大家:[Linux,Nginx,ZeroMQ,MySQL,Redis,
    fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,
    TCP/IP,协程,DPDK等技术内容,点击立即学习]


    1. OpenLive

      // device:指定网络要捕获的网络设备名称,可以是FindAllDevs返回的设备的Name
      // snaplen:每个数据包读取的最大长度
      // promisc:是否将网口设置为混杂模式,即是否接收目的地址不为本机的包
      // timeout:设置抓到包返回的超时。如果设置成30s,那么每30s才会刷新一次数据包;设置成负数,会立刻刷新数据包,即不做等待
      func OpenLive(device string, snaplen int32, promisc bool, timeout time.Duration) (handle *Handle, _ error)
      
      • 1
      • 2
      • 3
      • 4
      • 5
      ↩︎ ↩︎
    2. NewInactiveHandle

      创建一个pcap句柄,但是需要调用Active进行激活,使用或者你可以更加方便的更改其参数

      func NewInactiveHandle(device string) (*InactiveHandle, error)
      
      • 1
      ↩︎
    3. OpenOffline

      打开一个存储libpcap支持的文件

      func OpenOffline(file string) (handle *Handle, err error)
      
      • 1
      ↩︎
    4. OpenOfflineFile

      与OpenOffline类似,需要我们手动打开文件后返回的文件句柄作为参数

      func OpenOfflineFile(file * os . File ) (handle * Handle , err error )
      
      • 1
      ↩︎
    5. PacketSource

      PacketSource可以从 PacketDataSource 中读取数据包,对其进行解码并返回它们。其定义入下

      type PacketSource struct {
      	// 数据源
      	source  PacketDataSource
      	// 解码器
      	decoder Decoder
      	// 解码选项设置,可以在外部改变
      	DecodeOptions
      	// 数据通道
      	c chan Packet
      }
      
      // 数据源接口
      type PacketDataSource interface {
      	ReadPacketData() (data []byte, ci CaptureInfo, err error)
      }
      
      // 解码器接口
      type Decoder interface {
      	Decode([]byte, PacketBuilder) error
      }
      
      // 解码器选项
      type DecodeOptions struct {
      	// 是否延迟解码
      	//注意在并发时要小心因为*可能会改变数据包,导致并发函数调用互斥
      	Lazy bool
      	// 不拷贝到缓冲区
      	// 如果能够保证传递给NewPacket的片的底层自己不会被修改,那么这可能更快
      	// 如果可能被修改,这可能使数据无效
      	NoCopy bool
      	// 在包解码时跳过recover恢复
      	// 一般在发生panic时,将会被recover捕获,
      	//并在详细描述问题的包添加DecodeFailure层
      	SkipDecodeRecovery bool
      	// 可以在TCP解码器中实现应用层路由
      	// 默认false,因为重报应该在解码TCP负载后
      	DecodeStreamsAsDatagrams bool
      }
      
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40

      我们可以通过NewPacketSource方法来构造一个PacketSouce源

      // source:源,需要实现ReadPacketData接口
      // decorder:解码器需要实现Decodeer接口
      func NewPacketSource(source PacketDataSource, decoder Decoder) *PacketSource {
      	return &PacketSource{
      		source:  source,
      		decoder: decoder,
      	}
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

      目前有两种不同的方法可以通过 PacketSource 读取数据包:

      • Packets7
      • NextPacket10

      Packets

      内部启用一个协程调用NextPacket进行读Packet11,并将其写入到返回的管道中

      func (p *PacketSource) Packets() chan Packet {
      	if p.c == nil {
      		p.c = make(chan Packet, 1000)
      		go p.packetsToChannel()
      	}
      	return p.c
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

      使用示例:

      for packet := range packetSource.Packets() {
        ...
      }
      
      • 1
      • 2
      • 3

      NextPacket

      返回下一个数据包Packet11

      func (p *PacketSource) NextPacket() (Packet, error) {
      	// 读取元数据
      	data, ci, err := p.source.ReadPacketData()
      	if err != nil {
      		return nil, err
      	}
      	// 根据数据基础Packet对象
      	packet := NewPacket(data, p.decoder, p.DecodeOptions)
      	m := packet.Metadata()
      	m.CaptureInfo = ci
      	m.Truncated = m.Truncated || ci.CaptureLength < ci.Length
      	return packet, nil
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13

      使用示例:

      for {
        packet, err := packetSource.NextPacket()
        if err == io.EOF {
          break
        } else if err != nil {
          log.Println("Error:", err)
          continue
        }
        handlePacket(packet)  // Do something with each packet.
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      ↩︎ ↩︎
    6. // source:源,需要实现ReadPacketData接口
      // decorder:解码器需要实现Decodeer接口
      func NewPacketSource(source PacketDataSource, decoder Decoder) *PacketSource {
      	return &PacketSource{
      		source:  source,
      		decoder: decoder,
      	}
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      ↩︎
    7. Packets

      内部启用一个协程调用NextPacket进行读Packet11,并将其写入到返回的管道中

      func (p *PacketSource) Packets() chan Packet {
      	if p.c == nil {
      		p.c = make(chan Packet, 1000)
      		go p.packetsToChannel()
      	}
      	return p.c
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

      使用示例:

      for packet := range packetSource.Packets() {
        ...
      }
      
      • 1
      • 2
      • 3
      ↩︎ ↩︎
    8. NewWriter与NewWriterNanos

      返回一个新的 writer 对象,用于将数据包数据写入给定的 writer。如果这是一个新的空写入器(与追加相反),则必须在 WritePacket 之前调用 WriteFileHeader9。数据包时间戳以微秒精度写入。

      func NewWriter(w io . Writer ) * Writer
      func NewWriterNanos(w io . Writer ) * Writer
      
      • 1
      • 2

      示例:

      // 创建一个空文件
      f, _ := os.Create("/tmp/file.pcap")
      // 新建一个Writer对象
      w := pcapgo.NewWriter(f)
      // 新文件,必须写入头
      w.WriteFileHeader(65536, layers.LinkTypeEthernet)  
      // 写入包
      w.WritePacket(gopacket.CaptureInfo{...}, data1)
      f.Close()
      // 追加
      f2, _ := os.OpenFile("/tmp/file.pcap", os.O_APPEND, 0700)
      // 创建一个writer
      w2 := pcapgo.NewWriter(f2)
      // 
      w2.WritePacket(gopacket.CaptureInfo{...}, data2)
      f2.Close()
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      ↩︎
    9. WriteFileHeader

      写入文件头通过链路层类型,每次新建文件时必须首先调用此函数

      func (w *Writer) WriteFileHeader(snaplen uint32, linktype layers.LinkType) error
      
      • 1
      ↩︎ ↩︎
    10. NextPacket

      返回下一个数据包Packet11

      func (p *PacketSource) NextPacket() (Packet, error) {
      	// 读取元数据
      	data, ci, err := p.source.ReadPacketData()
      	if err != nil {
      		return nil, err
      	}
      	// 根据数据基础Packet对象
      	packet := NewPacket(data, p.decoder, p.DecodeOptions)
      	m := packet.Metadata()
      	m.CaptureInfo = ci
      	m.Truncated = m.Truncated || ci.CaptureLength < ci.Length
      	return packet, nil
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13

      使用示例:

      for {
        packet, err := packetSource.NextPacket()
        if err == io.EOF {
          break
        } else if err != nil {
          log.Println("Error:", err)
          continue
        }
        handlePacket(packet)  // Do something with each packet.
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      ↩︎
    11. Packet

      packet是gopacket的主要对象,其主要由Decoder创建,一个数据包由一组数据组成,数据在解码时被分解为多个层。

      type Packet interface {
      	// 输出可读性的字符串
      	String() string
      	// 使用LayerDump输出所有layer的16进制
      	Dump() string
      	// 返回所有layer
      	Layers() []Layer
      	// 返回指定层的数据,如果nil则返回第一层数据
      	Layer(LayerType) Layer
      	// 返回指
      	LayerClass(LayerClass) Layer
      
      	// 返回链路层
      	LinkLayer() LinkLayer
      	// 返回网络层
      	NetworkLayer() NetworkLayer
      	// 返回传输层
      	TransportLayer() TransportLayer
      	/// 返回应用层
      	ApplicationLayer() ApplicationLayer
      	// 返回错误层的信息
      	ErrorLayer() ErrorLayer
      
      	// 数据
      	Data() []byte
      	// 元数据
      	Metadata() *PacketMetadata
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      ↩︎ ↩︎ ↩︎ ↩︎
  • 相关阅读:
    逻辑漏洞挖掘
    UE5.3-基础蓝图类整理一
    神经网络(MLP多层感知器)
    揭秘亚马逊,eBay,沃尔玛的运营秘籍:如何实现爆款产品并获得更高流量?
    C# 巧妙计算小R输漏掉的一位同学
    C++11
    Java基础语法之数组
    Dubbo详解,用心看这一篇文章就够了【重点】
    计算机毕业论文微信小程序毕业设计项目ssm驾校教培服务系统小程序+后台管理系统|前后分离VUE[包运行成功]
    金融行业分布式数据库选型及实践经验
  • 原文地址:https://blog.csdn.net/hzb869168467/article/details/126092093