Maison  >  Article  >  développement back-end  >  Capturez le trafic avec Golang

Capturez le trafic avec Golang

王林
王林original
2024-09-04 11:07:29622parcourir

Capture traffic with Golang

Introduction

La plupart des gens du monde du génie logiciel ont entendu parler de TCPDump, WireShark, etc.
Et vous avez probablement entendu parler de la bibliothèque libpcap1 développée par l'équipe TCPDump pour capturer le trafic et également utilisée par Wireshark.

Cette bibliothèque1 fournit une interface flexible pour capturer un trafic provenant d'une interface réseau et le traiter dans un code. Il offre la flexibilité d'écrire du code performant et d'inclure autant de logique métier que nécessaire pour collecter uniquement les données requises.

Récemment, j'ai identifié une tâche pour laquelle ce serait une bonne idée de collecter les paquets requis, de les analyser et de les conserver pour une future révision manuelle. Pour examiner manuellement, WireShak peut être utilisé pour charger le fichier pcap et examiner manuellement les paquets collectés à l'aide d'une interface utilisateur agréable.

Et la partie la plus importante, pourquoi y aller ? Go est un langage assez simple pour écrire du code et le prendre en charge par plusieurs membres de l'équipe. Il est beaucoup plus sûr que C et C++ et nécessite beaucoup moins d'expérience pour que d'autres personnes puissent le prendre en charge sans surprises inattendues. Jusqu'à ce que nous n'ayons pas d'exigences alors que nous DEVONS utiliser un langage très performant (C, C++, rust, etc.), je préfère choisir Golang.

Définition de la tâche

Avant de faire quelque chose, ce serait bien de comprendre, que voulons-nous obtenir comme résultat ? Définissons une courte liste d'exigences.

Exigences

Pour que la mise en œuvre soit aussi simple que possible, définissons seulement quelques points :

  1. Nous souhaitons collecter le trafic sortant
  2. Collectons le trafic IPv4
  3. Ignorer le trafic des réseaux privés
  4. Et gardons les paquets UDP

Ces quelques points simples suffiront pour se faire une idée sur la façon d'utiliser libpcap1 de Golang.
Après cela, ce n'est qu'une question d'imagination sur la logique qui sera ajoutée en plus.

Mise en œuvre

Avant de commencer, définissons que le code n'est pas censé être prêt pour la production. Notre objectif est de voir l'exemple minimum et de tester qu'il fonctionne bien.

Nous utiliserons ces bibliothèques :

  1. slog pour la connexion
  2. github.com/google/gopacket pour capturer les paquets et formater le format de fichier pcap

Une interface dans le futur code sera eth0, même si votre système aura probablement un nom d'interface différent.

Code de travail

Voici le code avec des commentaires que vous pouvez copier et essayer dans votre propre environnement.
Puisque nous utilisons libpcap1, notre application utilisera CGO et nous devrons exécuter l'application à partir de l'utilisateur root.

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()))
}

Et après avoir exécuté là-bas, la sortie tronquée ressemble à ceci :

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

J'espère que cet exemple minimum aidera quelqu'un à commencer son voyage dans cette zone en utilisant Go.

Épilogue

Si vous répondez à de nouvelles exigences dans vos tâches quotidiennes et que vous ne savez pas comment le faire. N'hésitez pas à demander aux gens autour de vous, écrivez-moi en privé et faites vos propres recherches.

La recherche et la communication sont la clé de la résolution de tous les problèmes.


  1. libpcap est une bibliothèque C/C++ portable pour la capture du trafic réseau ↩

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn