Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Sniffing with pcap in a GUI application
Forum Updated to NodeBB v4.3 + New Features

Sniffing with pcap in a GUI application

Scheduled Pinned Locked Moved Unsolved General and Desktop
3 Posts 3 Posters 182 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    Mattia
    wrote on last edited by
    #1

    Hi everyone,

    I am trying to write an application than while it is sniffing packets using the pcap library, it plots the received data in a GUI.
    I arrived to this point...
    main.cpp

    #include <QApplication>
    
    #include "receiver.h"
    
    int main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
        Receiver receiver;
        receiver.setMinimumSize(900, 600);
        receiver.show();
        return app.exec();
    }
    

    receiver.h

    #ifndef RECEIVER_H
    #define RECEIVER_H
    
    #include <QWidget>
    #include "qcustomplot.h"
    
    using namespace std;
    
    QT_BEGIN_NAMESPACE
    class QLabel;
    QT_END_NAMESPACE
    
    class Receiver : public QWidget
    {
        Q_OBJECT
    
    public:
        explicit Receiver(QWidget *parent = nullptr);
    
    private slots:
        void stampa(int res);
    
    private:
        QCustomPlot* plot = new QCustomPlot;;
        QLabel *statusLabel = nullptr;
        int sniff();
    
    signals:
        void signalPacketReceived(int res);
    };
    
    #endif
    

    receiver.cpp

    #include <pcap.h>
    #include <QLabel>
    #include <QPushButton>
    #include <QVBoxLayout>
    #include "qcustomplot.h"
    
    #include <sstream>
    
    #include "receiver.h"
    
    Receiver::Receiver(QWidget *parent)
        : QWidget(parent)
    {
        statusLabel = new QLabel(tr("Listening for broadcasted messages"));
        statusLabel->setWordWrap(true);
    
        auto quitButton = new QPushButton(tr("&Quit"));
    
        connect(quitButton, &QPushButton::clicked,
                this, &Receiver::close);
    
        connect(this, SIGNAL(signalPacketReceived(int)),
            this, SLOT(stampa(int)));
    
        //auto plot = new QCustomPlot;
        plot->addGraph();
        plot->graph()->setScatterStyle(QCPScatterStyle::ssCircle);
        plot->graph()->setLineStyle(QCPGraph::LineStyle::lsNone);
        auto plotLayout = new QHBoxLayout;
        plotLayout->addWidget(plot);
        
        auto buttonLayout = new QHBoxLayout;
        buttonLayout->addStretch(1);
        buttonLayout->addWidget(quitButton);
        buttonLayout->addStretch(1);
    
        auto mainLayout = new QVBoxLayout;
        mainLayout->addWidget(statusLabel);
        mainLayout->addLayout(plotLayout, 1);
        mainLayout->addLayout(buttonLayout);
        
        setLayout(mainLayout);
    
        setWindowTitle(tr("Test"));
        
        sniff();
    }
    
    int Receiver::sniff()
    {
        pcap_t* handle;			/* Session handle */
        char* dev;			/* The device to sniff on */
        char errbuf[PCAP_ERRBUF_SIZE];	/* Error string */
        struct bpf_program fp;		/* The compiled filter */
        char filter_exp[] = "port 53";	/* The filter expression */
        bpf_u_int32 mask;		/* Our netmask */
        bpf_u_int32 net;		/* Our IP */
        struct pcap_pkthdr* header;	/* The header that pcap gives us */
        const u_char* packet;		/* The actual packet */
        int num_packets = -1;			/* number of packets to capture */
    
        /* Define the device */
        dev = pcap_lookupdev(errbuf);
        if (dev == NULL) {
            fprintf(stderr, "Couldn't find default device: %s\n", errbuf);
            return(2);
        }
        /* Find the properties for the device */
        if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
            fprintf(stderr, "Couldn't get netmask for device %s: %s\n", dev, errbuf);
            net = 0;
            mask = 0;
        }
        /* Open the session in promiscuous mode */
        handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
        if (handle == NULL) {
            fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
            return(2);
        }
        /* Compile and apply the filter */
        if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
            fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
            return(2);
        }
        if (pcap_setfilter(handle, &fp) == -1) {
            fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));
            return(2);
        }
        /* Grab a packets */
        //pcap_loop(handle, num_packets, got_packet, reinterpret_cast<u_char *>(this));
        statusLabel->setText(QString("Check 1"));
        
        while (true)
        {
            int res = pcap_next_ex(handle, &header, &packet);
            statusLabel->setText(QString::number(res));
            if (res == 0)
                continue; // timeout elapsed
            emit signalPacketReceived(res);
        }
        
        /* cleanup */
        pcap_freecode(&fp);
        pcap_close(handle);
    
        printf("\nCapture complete.\n");
        
        return(0);
    }
    
    void Receiver::stampa(int res)
    {
        statusLabel->setText(QString::number(res));
    }
    
    

    The program compiles and runs, but it freezes forever in the loop at the end of the sniff() function. How can I modify this program in a way that for every received packeges the status label in the main GUI is updated and that the GUI stays responsive for every other button I will implement later?

    Pl45m4P 1 Reply Last reply
    0
    • M Mattia

      Hi everyone,

      I am trying to write an application than while it is sniffing packets using the pcap library, it plots the received data in a GUI.
      I arrived to this point...
      main.cpp

      #include <QApplication>
      
      #include "receiver.h"
      
      int main(int argc, char *argv[])
      {
          QApplication app(argc, argv);
          Receiver receiver;
          receiver.setMinimumSize(900, 600);
          receiver.show();
          return app.exec();
      }
      

      receiver.h

      #ifndef RECEIVER_H
      #define RECEIVER_H
      
      #include <QWidget>
      #include "qcustomplot.h"
      
      using namespace std;
      
      QT_BEGIN_NAMESPACE
      class QLabel;
      QT_END_NAMESPACE
      
      class Receiver : public QWidget
      {
          Q_OBJECT
      
      public:
          explicit Receiver(QWidget *parent = nullptr);
      
      private slots:
          void stampa(int res);
      
      private:
          QCustomPlot* plot = new QCustomPlot;;
          QLabel *statusLabel = nullptr;
          int sniff();
      
      signals:
          void signalPacketReceived(int res);
      };
      
      #endif
      

      receiver.cpp

      #include <pcap.h>
      #include <QLabel>
      #include <QPushButton>
      #include <QVBoxLayout>
      #include "qcustomplot.h"
      
      #include <sstream>
      
      #include "receiver.h"
      
      Receiver::Receiver(QWidget *parent)
          : QWidget(parent)
      {
          statusLabel = new QLabel(tr("Listening for broadcasted messages"));
          statusLabel->setWordWrap(true);
      
          auto quitButton = new QPushButton(tr("&Quit"));
      
          connect(quitButton, &QPushButton::clicked,
                  this, &Receiver::close);
      
          connect(this, SIGNAL(signalPacketReceived(int)),
              this, SLOT(stampa(int)));
      
          //auto plot = new QCustomPlot;
          plot->addGraph();
          plot->graph()->setScatterStyle(QCPScatterStyle::ssCircle);
          plot->graph()->setLineStyle(QCPGraph::LineStyle::lsNone);
          auto plotLayout = new QHBoxLayout;
          plotLayout->addWidget(plot);
          
          auto buttonLayout = new QHBoxLayout;
          buttonLayout->addStretch(1);
          buttonLayout->addWidget(quitButton);
          buttonLayout->addStretch(1);
      
          auto mainLayout = new QVBoxLayout;
          mainLayout->addWidget(statusLabel);
          mainLayout->addLayout(plotLayout, 1);
          mainLayout->addLayout(buttonLayout);
          
          setLayout(mainLayout);
      
          setWindowTitle(tr("Test"));
          
          sniff();
      }
      
      int Receiver::sniff()
      {
          pcap_t* handle;			/* Session handle */
          char* dev;			/* The device to sniff on */
          char errbuf[PCAP_ERRBUF_SIZE];	/* Error string */
          struct bpf_program fp;		/* The compiled filter */
          char filter_exp[] = "port 53";	/* The filter expression */
          bpf_u_int32 mask;		/* Our netmask */
          bpf_u_int32 net;		/* Our IP */
          struct pcap_pkthdr* header;	/* The header that pcap gives us */
          const u_char* packet;		/* The actual packet */
          int num_packets = -1;			/* number of packets to capture */
      
          /* Define the device */
          dev = pcap_lookupdev(errbuf);
          if (dev == NULL) {
              fprintf(stderr, "Couldn't find default device: %s\n", errbuf);
              return(2);
          }
          /* Find the properties for the device */
          if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
              fprintf(stderr, "Couldn't get netmask for device %s: %s\n", dev, errbuf);
              net = 0;
              mask = 0;
          }
          /* Open the session in promiscuous mode */
          handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
          if (handle == NULL) {
              fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
              return(2);
          }
          /* Compile and apply the filter */
          if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
              fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
              return(2);
          }
          if (pcap_setfilter(handle, &fp) == -1) {
              fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));
              return(2);
          }
          /* Grab a packets */
          //pcap_loop(handle, num_packets, got_packet, reinterpret_cast<u_char *>(this));
          statusLabel->setText(QString("Check 1"));
          
          while (true)
          {
              int res = pcap_next_ex(handle, &header, &packet);
              statusLabel->setText(QString::number(res));
              if (res == 0)
                  continue; // timeout elapsed
              emit signalPacketReceived(res);
          }
          
          /* cleanup */
          pcap_freecode(&fp);
          pcap_close(handle);
      
          printf("\nCapture complete.\n");
          
          return(0);
      }
      
      void Receiver::stampa(int res)
      {
          statusLabel->setText(QString::number(res));
      }
      
      

      The program compiles and runs, but it freezes forever in the loop at the end of the sniff() function. How can I modify this program in a way that for every received packeges the status label in the main GUI is updated and that the GUI stays responsive for every other button I will implement later?

      Pl45m4P Offline
      Pl45m4P Offline
      Pl45m4
      wrote on last edited by
      #2

      @Mattia said in Sniffing with pcap in a GUI application:

      it freezes forever in the loop at the end of the sniff() function

      Oh, who could have expected that?

      while (true)
      {
          int res = pcap_next_ex(handle, &header, &packet);
          statusLabel->setText(QString::number(res));
          if (res == 0)
              continue; // timeout elapsed
          emit signalPacketReceived(res);
      }
      

      How can I modify this program in a way that for every received packeges the status label in the main GUI is updated and that the GUI stays responsive for every other button I will implement later?

      Use a proper multithreading technology or (if existing) an asynch API.

      while(true) in main GUI thread (and emitting signals from there) is deadly. It will always block/freeze your GUI.


      If debugging is the process of removing software bugs, then programming must be the process of putting them in.

      ~E. W. Dijkstra

      1 Reply Last reply
      1
      • JonBJ Offline
        JonBJ Offline
        JonB
        wrote on last edited by JonB
        #3

        If pcap calls block/are synchronous then it would presumably have to go into its own thread.
        If calls are non-blocking/asynchronous then you can use those from main thread. If it's suitable maybe you can make calls on a timer. E.g. call your code intermittently rather than in a blocking loop.

        1 Reply Last reply
        0

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved