DEV Community ๐Ÿ‘ฉโ€๐Ÿ’ป๐Ÿ‘จโ€๐Ÿ’ป

Masui Masanori
Masui Masanori

Posted on

[Go] Try capturing TCP packets

Intro

I will try capturing TCP packets.

TCP socket communication

To capture packets, I will create applications for TCP socket communication.

tcp-server-sample

package main

import (
    "fmt"
    "io"
    "log"
    "net"
)

func main() {
    ln, err := net.Listen("tcp", ":8099")
    if err != nil {
        fmt.Println("cannot listen", err)
    }
    for {
        conn, e := ln.Accept()
        if e != nil {
            log.Fatal(e)
            return
        }
        go echo_handler(conn)
    }
}

func echo_handler(conn net.Conn) {
    defer conn.Close()
    io.Copy(conn, conn)
}
Enter fullscreen mode Exit fullscreen mode

tcp-client-sample

package main

import (
    "fmt"
    "log"
    "net"
    "time"
)

func main() {
    ticker := time.NewTicker(time.Millisecond * 1000)
    var conn net.Conn
    var err error
    defer func() {
        ticker.Stop()
        if conn != nil {
            conn.Close()
        }
    }()

    count := 0
    for range ticker.C {
        if count > 1000 {
            break
        }
        conn, err = net.Dial("tcp", ":8099")
        if err != nil {
            log.Fatal(err)
        }
        sendData := []byte(fmt.Sprintf("Hello_%d", count))
        _, err = conn.Write(sendData)
        if err != nil {
            log.Fatal(err)
        }
        buf := make([]byte, 1024)
        n, err := conn.Read(buf)
        if err != nil {
            log.Fatal(err)
        }
        log.Println(string(buf[:n]))
        conn.Close()
        conn = nil
        count += 1
    }
}
Enter fullscreen mode Exit fullscreen mode

Capturing TCP packets

I will capturing TCP packets by gopacket/pcap.

libpcap-dev

Because I had already installed Wireshark on Windows and Xubuntu, I didn't need install any other software for Windows.

But when I tried executing gopacket/pcap on Xubuntu, I would get error.

# github.com/google/gopacket/pcap
../../../pkg/mod/github.com/google/gopacket@v1.1.19/pcap/pcap_unix.go:34:10: fatal error: pcap.h: No such file or directory
   34 | #include <pcap.h>
      |          ^~~~~~~~
compilation terminated.
Enter fullscreen mode Exit fullscreen mode

I should install "libpcap-dev".

sudo apt install -y libpcap-dev
Enter fullscreen mode Exit fullscreen mode

Capturing sample

tcp-capture-sample

package main

import (
    "fmt"
    "log"
    "strings"
    "time"

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

func main() {
    loopbackDevice := getLoopbackDeviceName()
    if loopbackDevice == "" {
        log.Println("No loopback devices")
        return
    }
    handle, err := pcap.OpenLive(loopbackDevice, 1024, false, 3*time.Second)
    if err != nil {
        log.Fatal(err)
    }
    defer handle.Close()
    // Filtering capture targets
    err = handle.SetBPFFilter("tcp and port 8099")
    if err != nil {
        log.Fatal(err)
    }
    packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
   // Get decoded packets through chann
    for packet := range packetSource.Packets() {
        log.Println("S-------S")
        log.Println(packet)
        log.Println("E-------E")
    }
}
func getLoopbackDeviceName() string {
    // Find all devices
    devices, err := pcap.FindAllDevs()
    if err != nil {
        log.Fatal(err.Error())
    }
    for _, device := range devices {
        // for Windows
        if strings.Contains(strings.ToLower(device.Name), "loopback") ||
            // for Xubuntu
            device.Name == "lo" {
            return device.Name
        }
    }
    return ""
}
Enter fullscreen mode Exit fullscreen mode

Results

...
2022/10/12 21:19:27 S-------S
2022/10/12 21:19:27 PACKET: 74 bytes, wire length 74 cap length 74 @ 2022-10-12 21:19:27.764308 +0900 JST
- Layer 1 (14 bytes) = Ethernet {Contents=[..14..] Payload=[..60..] SrcMAC=00:00:00:00:00:00 DstMAC=00:00:00:00:00:00 EthernetType=IPv4 Length=0}
- Layer 2 (20 bytes) = IPv4 {Contents=[..20..] Payload=[..40..] Version=4 IHL=5 TOS=0 Length=60 Id=36925 Flags=DF FragOffset=0 TTL=64 Protocol=TCP Checksum=44156 SrcIP=127.0.0.1 DstIP=127.0.0.1 Options=[] Padding=[]}
- Layer 3 (32 bytes) = TCP  {Contents=[..32..] Payload=[..8..] SrcPort=8099 DstPort=57632 Seq=2020353806 Ack=775619635 DataOffset=8 FIN=false SYN=false RST=false PSH=true ACK=true URG=false ECE=false CWR=false NS=false Window=512 Checksum=65072 Urgent=0 Options=[TCPOption(NOP:), TCPOption(NOP:), TCPOption(Timestamps:3776381494/3776381494 0xe1170236e1170236)] Padding=[]}
- Layer 4 (08 bytes) = Payload  8 byte(s)

2022/10/12 21:19:27 E-------E
...
Enter fullscreen mode Exit fullscreen mode

According to the result, the captured packet was decoded into several layer data.

...

func main() {
... 
   // Get decoded packets through chann
    for packet := range packetSource.Packets() {
        printPacketInfo(packet)
    }
}
...
func printPacketInfo(packet gopacket.Packet) {
   // TCP
    tcpLayer := packet.Layer(layers.LayerTypeTCP)
    if tcpLayer != nil {
        tcp, _ := tcpLayer.(*layers.TCP)

        fmt.Printf("From port %d to %d\n", tcp.SrcPort, tcp.DstPort)
        fmt.Println("Sequence number: ", tcp.Seq)
    }
   // TCP/IPV4 Payload
    applicationLayer := packet.ApplicationLayer()
    if applicationLayer != nil {
        fmt.Println("Application layer/Payload found.")
        fmt.Printf("%s\n", applicationLayer.Payload())
    }

    // Check for errors
    if err := packet.ErrorLayer(); err != nil {
        fmt.Println("Error decoding some part of the packet:", err)
    }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)

CLI tools you won't be able to live without ๐Ÿ”ง

CLI tools