DEV Community

Masui Masanori
Masui Masanori

Posted on

6

[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

Heroku

Build apps, not infrastructure.

Dealing with servers, hardware, and infrastructure can take up your valuable time. Discover the benefits of Heroku, the PaaS of choice for developers since 2007.

Visit Site

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs