Heim  >  Artikel  >  Backend-Entwicklung  >  Erfassen Sie den Datenverkehr mit Golang

Erfassen Sie den Datenverkehr mit Golang

王林
王林Original
2024-09-04 11:07:29618Durchsuche

Capture traffic with Golang

Einführung

Die meisten Leute aus der Welt der Softwareentwicklung haben von TCPDump, WireShark usw. gehört.
Und höchstwahrscheinlich haben Sie von der Bibliothek libpcap1 gehört, die vom TCPDump-Team zur Erfassung des Datenverkehrs entwickelt und auch von Wireshark verwendet wird.

Diese Bibliothek1 bietet eine flexible Schnittstelle, um den Datenverkehr von einer Netzwerkschnittstelle zu erfassen und ihn in einem Code zu verarbeiten. Es bietet die Flexibilität, leistungsstarken Code zu schreiben und so viel Geschäftslogik wie nötig einzubinden, um nur die erforderlichen Daten zu erfassen.

Kürzlich habe ich eine Aufgabe identifiziert, bei der es eine gute Idee wäre, erforderliche Pakete zu sammeln, sie zu analysieren und für die zukünftige manuelle Überprüfung zu speichern. Zur manuellen Überprüfung kann WireShak verwendet werden, um die PCAP-Datei zu laden und die gesammelten Pakete manuell über eine schöne Benutzeroberfläche zu überprüfen.

Und das Wichtigste: Warum gehen? Go ist eine schöne, einfache Sprache, um Code zu schreiben und ihn von mehreren Teammitgliedern zu unterstützen. Es ist viel sicherer als C und C++ und erfordert viel weniger Erfahrung, damit andere es ohne unerwartete Überraschungen unterstützen können. Bis wir keine Anforderungen haben, bei denen wir auf eine leistungsfähigere Sprache (C, C++, Rust usw.) zurückgreifen MÜSSEN, wähle ich lieber Golang.

Aufgabendefinition

Bevor wir etwas tun, wäre es gut zu verstehen, was wir mit einem Ergebnis erreichen wollen. Lassen Sie uns eine kurze Liste von Anforderungen definieren.

Anforderungen

Um die Implementierung so einfach wie möglich zu halten, definieren wir nur einige Punkte:

  1. Wir möchten den ausgehenden Verkehr sammeln
  2. Lassen Sie uns den IPv4-Verkehr sammeln
  3. Privaten Netzwerkverkehr ignorieren
  4. Und behalten wir die UDP-Pakete

Diese einfachen Punkte reichen aus, um eine Vorstellung davon zu bekommen, wie man libpcap1von Golang verwendet.
Danach ist es nur noch eine Frage der Fantasie, welche Logik darüber hinaus hinzugefügt wird.

Durchführung

Bevor wir beginnen, definieren wir, dass der Code nicht produktionsbereit sein soll. Unser Ziel ist es, das minimale Beispiel zu sehen und zu testen, ob es gut funktioniert.

Wir werden diese Bibliotheken verwenden:

  1. slog für die Anmeldung
  2. github.com/google/gopacket zum Erfassen von Paketen und Formatieren des PCAP-Dateiformats

Eine Schnittstelle im zukünftigen Code wird eth0 sein, auch wenn Ihr System höchstwahrscheinlich einen anderen Schnittstellennamen haben wird.

Arbeitscode

Dies ist der Code mit Kommentaren, den Sie kopieren und in Ihrer eigenen Umgebung ausprobieren können.
Da wir libpcap1 verwenden, verwendet unsere Anwendung CGO und wir müssen die App vom root-Benutzer ausführen.

package main

import (
    "bytes"
    "log/slog"
    "net"
    "os"

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

const (
    interfaceName = "eth0"
    snaplen       = 1500
)

func main() {
    slog.Info("Running our applicaiton...")

    // Get handler attached to an interface.
    handle, err := pcap.OpenLive(interfaceName, snaplen, true, pcap.BlockForever)
    if err != nil {
        slog.Error("Could not OpenLive", slog.String("err", err.Error()))
        os.Exit(1)
    }

    iface, err := net.InterfaceByName(interfaceName)
    if err != nil {
        slog.Error("Could not OpenLive", slog.String("err", err.Error()))
        os.Exit(1)
    }

    // Start new Source reader.
    source := gopacket.NewPacketSource(handle, handle.LinkType())

    // This is suppose to be a file writer, but we will use memory, just for simplification.
    fileWriter := bytes.NewBuffer(nil)
    pcapWriter := pcapgo.NewWriterNanos(fileWriter)
    err = pcapWriter.WriteFileHeader(snaplen, handle.LinkType())
    if err != nil {
        slog.Error("Could not write pcap header", slog.String("err", err.Error()))
        os.Exit(1)
    }

    // Reading packages.
    for packet := range source.Packets() {
        // Filter by outcoming traffic only.
        // To filter it, we need to compare MAC addresses from out interface and source MAC.
        // To access a mac Address we need to get an Ethernet layer.
        layer := packet.Layer(layers.LayerTypeEthernet)

        ethernet, ok := layer.(*layers.Ethernet)
        if !ok {
            slog.Error("Could not get Ethernet layer")
            continue
        }

        if !bytes.Equal(ethernet.SrcMAC, iface.HardwareAddr) {
            // Our interface did not send this packet. It's not outcoming.
            continue
        }

        // Now we need to identify IPv4 layer.
        layer = packet.Layer(layers.LayerTypeIPv4)

        ipv4, ok := layer.(*layers.IPv4)
        if !ok {
            // It's not IPv4 traffic.
            continue
        }

        if ipv4.DstIP.IsPrivate() {
            // Do not collect private traffic.
            continue
        }

        if ipv4.Protocol != layers.IPProtocolUDP {
            // Ignore not UDP protocol.
            continue
        }

        err = pcapWriter.WritePacket(packet.Metadata().CaptureInfo, packet.Data())
        if err != nil {
            slog.Error("Could not write a packet to a pcap writer", slog.String("err", err.Error()))

            continue
        }

        slog.Info("Stored packet", slog.Any("packet", packet))

        // Let's collect ONLY 100K bytes, just for example perposes.
        if fileWriter.Len() > 100000 {
            break
        }
    }

    slog.Info("We have successfuly collected bytes", slog.Int("bytes", fileWriter.Len()))
}

Und nachdem es dort ausgeführt wurde, sieht die verkürzte Ausgabe so aus:

2024/08/31 13:35:36 INFO Running our applicaiton...
2024/08/31 13:37:48 INFO Stored packet packet="PACKET: 105 bytes, wire length 105 cap length 105 ..."
...
2024/08/31 13:37:48 INFO Stored packet packet="PACKET: 1291 bytes, wire length 1291 cap length 1291 ..."
2024/08/31 13:37:48 INFO We have successfuly collected bytes bytes=101018

Ich hoffe, dieses Minimalbeispiel hilft jemandem, seine Reise in diesem Bereich mit Go zu beginnen.

Nachwort

Wenn Sie bei Ihren alltäglichen Aufgaben auf neue Anforderungen stoßen, von denen Sie keine Ahnung haben, wie Sie sie bewältigen sollen. Zögern Sie nicht, Leute in der Umgebung zu befragen, schreiben Sie mir privat und recherchieren Sie selbst.

Forschung und Kommunikation sind der Schlüssel zur Lösung aller Probleme.


  1. libpcap ist eine portable C/C++-Bibliothek zur Erfassung des Netzwerkverkehrs ↩

Das obige ist der detaillierte Inhalt vonErfassen Sie den Datenverkehr mit Golang. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn