First version

This commit is contained in:
Stanislav Mykhailenko 2024-08-30 16:48:01 +03:00
commit d7a257af08
GPG key ID: 1E95E66A9C9D6A36
8 changed files with 732 additions and 0 deletions

75
.gitignore vendored Normal file
View file

@ -0,0 +1,75 @@
# This file is used to ignore files which are generated
# ----------------------------------------------------------------------------
*~
*.autosave
*.a
*.core
*.moc
*.o
*.obj
*.orig
*.rej
*.so
*.so.*
*_pch.h.cpp
*_resource.rc
*.qm
.#*
*.*#
core
!core/
tags
.DS_Store
.directory
*.debug
Makefile*
*.prl
*.app
moc_*.cpp
ui_*.h
qrc_*.cpp
Thumbs.db
*.res
*.rc
/.qmake.cache
/.qmake.stash
# qtcreator generated files
*.pro.user*
CMakeLists.txt.user*
# xemacs temporary files
*.flc
# Vim temporary files
.*.swp
# Visual Studio generated files
*.ib_pdb_index
*.idb
*.ilk
*.pdb
*.sln
*.suo
*.vcproj
*vcproj.*.*.user
*.ncb
*.sdf
*.opensdf
*.vcxproj
*vcxproj.*
# MinGW generated files
*.Debug
*.Release
# Python byte code
*.pyc
# Binaries
# --------
*.dll
*.exe
build

View file

@ -0,0 +1,28 @@
QT += core gui network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++17
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
packetanalyzer.cpp
HEADERS += \
packetanalyzer.h
FORMS += \
packetanalyzer.ui
INCLUDEPATH += /usr/include/pcapplusplus/
LIBS += -L/usr/lib/pcapplusplus -lPcap++ -lPacket++ -lCommon++
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

11
README.md Normal file
View file

@ -0,0 +1,11 @@
# New Generation 2024 Packet Analyzer
Graphical packet analyzer.
Features:
- Reading and writing .pcapng files.
- Using LLM to pretend it can detect anomalies.
- Selecting network interfaces.
- Packet sorting.
This program is Unlicensed, see UNLICENSE.

24
UNLICENSE Normal file
View file

@ -0,0 +1,24 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>

11
main.cpp Normal file
View file

@ -0,0 +1,11 @@
#include "packetanalyzer.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
PacketAnalyzer w;
w.show();
return a.exec();
}

338
packetanalyzer.cpp Normal file
View file

@ -0,0 +1,338 @@
#include "packetanalyzer.h"
#include "ui_packetanalyzer.h"
PacketAnalyzer::PacketAnalyzer(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::PacketAnalyzer)
{
ui->setupUi(this);
connect(ui->cb_interfaces, &QComboBox::currentTextChanged, this, &PacketAnalyzer::changeInterface);
connect(ui->b_refresh, &QPushButton::clicked, this, &PacketAnalyzer::refresh);
connect(ui->t_packets, &QTableWidget::itemSelectionChanged, this, &PacketAnalyzer::packetSelected);
connect(ui->b_start, &QPushButton::clicked, this, &PacketAnalyzer::start);
connect(ui->b_stop, &QPushButton::clicked, this, &PacketAnalyzer::stop);
connect(ui->b_save, &QPushButton::clicked, this, &PacketAnalyzer::save);
connect(ui->b_load, &QPushButton::clicked, this, &PacketAnalyzer::load);
connect(ui->b_llm, &QPushButton::clicked, this, &PacketAnalyzer::llmRequest);
connect (m_manager, &QNetworkAccessManager::finished, this, &PacketAnalyzer::llmResponse);
QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
for (QNetworkInterface &interface : interfaces)
ui->cb_interfaces->addItem(interface.name());
}
PacketAnalyzer::~PacketAnalyzer()
{
delete ui;
stop();
}
void PacketAnalyzer::changeInterface(QString)
{
stop();
clear();
m_packets.clear();
m_dev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByName(ui->cb_interfaces->currentText().toStdString());
}
void PacketAnalyzer::clear()
{
ui->t_packets->setRowCount(0);
ui->e_selected->clear();
}
void PacketAnalyzer::refresh()
{
clear();
for (pcpp::RawPacketVector::ConstVectorIterator iter = m_packets.begin(); iter != m_packets.end(); iter++) {
pcpp::Packet parsedPacket(*iter);
ui->t_packets->insertRow( ui->t_packets->rowCount() );
for (pcpp::Layer* curLayer = parsedPacket.getFirstLayer(); curLayer != NULL; curLayer = curLayer->getNextLayer())
{
QTableWidgetItem* numberItem = new QTableWidgetItem();
numberItem->setData(Qt::DisplayRole, ui->t_packets->rowCount());
ui->t_packets->setItem( ui->t_packets->rowCount()-1,
0,
numberItem);
ui->t_packets->setItem( ui->t_packets->rowCount()-1,
3,
new QTableWidgetItem(getProtocolTypeAsString(curLayer->getProtocol())));
ui->t_packets->setItem( ui->t_packets->rowCount()-1,
4,
new QTableWidgetItem(QString::number((int)curLayer->getDataLen())));
QString sourceIP = "Unknown";
QString destinationIP = "Unknown";
pcpp::IPv4Layer* ipv4Layer = parsedPacket.getLayerOfType<pcpp::IPv4Layer>();
if (ipv4Layer != NULL)
{
sourceIP = QString::fromStdString(ipv4Layer->getSrcIPAddress().toString());
destinationIP = QString::fromStdString(ipv4Layer->getSrcIPAddress().toString());
}
pcpp::IPv6Layer* ipv6Layer = parsedPacket.getLayerOfType<pcpp::IPv6Layer>();
if (ipv6Layer != NULL)
{
sourceIP = QString::fromStdString(ipv6Layer->getSrcIPAddress().toString());
destinationIP = QString::fromStdString(ipv6Layer->getSrcIPAddress().toString());
}
ui->t_packets->setItem( ui->t_packets->rowCount()-1,
1,
new QTableWidgetItem(sourceIP));
ui->t_packets->setItem( ui->t_packets->rowCount()-1,
2,
new QTableWidgetItem(destinationIP));
}
}
}
void PacketAnalyzer::packetSelected()
{
int packetId = ui->t_packets->selectedItems()[0]->text().toInt();
pcpp::RawPacket* packet = m_packets.at(packetId-1);
ui->e_selected->setText(QString::fromStdString(pcpp::byteArrayToHexString(packet->getRawData(), packet->getRawDataLen())));
ui->b_llm->setEnabled(true);
}
void PacketAnalyzer::start()
{
if (!m_dev->open())
{
QMessageBox::critical(
this,
tr("Error"),
tr("Cannot open device.") );
return;
}
clear();
m_packets.clear();
m_dev->startCapture(m_packets);
ui->b_start->setEnabled(false);
ui->b_stop->setEnabled(true);
ui->b_save->setEnabled(false);
}
void PacketAnalyzer::stop()
{
if (m_dev == NULL || !m_dev->captureActive())
return;
m_dev->stopCapture();
ui->b_start->setEnabled(true);
ui->b_stop->setEnabled(false);
ui->b_save->setEnabled(true);
}
void PacketAnalyzer::save()
{
QString fileName = QFileDialog::getSaveFileName(this, "Select file", "", "pcap-ng files (*.pcapng)");
if (fileName.isEmpty())
return;
pcpp::PcapNgFileWriterDevice writer(fileName.toStdString());
if (!writer.open())
{
QMessageBox::critical(
this,
tr("Error"),
tr("Cannot open output file for writing.") );
return;
}
writer.writePackets(m_packets);
writer.close();
}
void PacketAnalyzer::load()
{
QString fileName = QFileDialog::getOpenFileName(this, "Select file", "", "pcap-ng files (*.pcapng)");
if (fileName.isEmpty())
return;
pcpp::PcapNgFileReaderDevice reader(fileName.toStdString());
if (!reader.open())
{
QMessageBox::critical(
this,
tr("Error"),
tr("Cannot open input file for reading.") );
return;
}
stop();
clear();
m_packets.clear();
reader.getNextPackets(m_packets);
reader.close();
refresh();
}
void PacketAnalyzer::llmRequest()
{
QNetworkRequest request(QUrl("http://127.0.0.1:11434/api/generate"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QJsonObject json;
json["model"] = "llama3.1:8b";
json["prompt"] = "Please analyze the following packet for anomalies.\n" + ui->e_selected->toPlainText();
json["stream"] = false;
m_manager->post(request, QJsonDocument(json).toJson());
ui->b_llm->setEnabled(false);
ui->b_load->setEnabled(false);
ui->b_refresh->setEnabled(false);
if (m_dev == NULL || !m_dev->captureActive())
ui->b_start->setEnabled(false);
else
ui->b_stop->setEnabled(false);
ui->cb_interfaces->setEnabled(false);
ui->t_packets->setSelectionMode(QAbstractItemView::NoSelection);
}
void PacketAnalyzer::llmResponse(QNetworkReply *reply)
{
if (reply->error() == QNetworkReply::NoError) {
QByteArray textReply = reply->readAll();
QString responseText = QJsonDocument::fromJson(textReply).object().value("response").toString();
QMessageBox::information(
this,
tr("LLM response"),
responseText );
} else {
QMessageBox::critical(
this,
tr("Error"),
tr("Could not connect to LLM.") );
}
ui->b_llm->setEnabled(true);
ui->b_load->setEnabled(true);
ui->b_refresh->setEnabled(true);
if (m_dev == NULL || !m_dev->captureActive())
ui->b_start->setEnabled(true);
else
ui->b_stop->setEnabled(true);
ui->cb_interfaces->setEnabled(true);
ui->t_packets->setSelectionMode(QAbstractItemView::SingleSelection);
}
QString PacketAnalyzer::getProtocolTypeAsString(pcpp::ProtocolType protocolType)
{
switch (protocolType)
{
case pcpp::Ethernet:
return "Ethernet";
case pcpp::IPv4:
return "IPv4";
case pcpp::IPv6:
return "IPv6";
case pcpp::TCP:
return "TCP";
case pcpp::UDP:
return "UDP";
case pcpp::HTTPRequest:
case pcpp::HTTPResponse:
return "HTTP";
case pcpp::ARP:
return "ARP";
case pcpp::VLAN:
return "VLAN";
case pcpp::ICMP:
return "ICMP";
case pcpp::PPPoESession:
case pcpp::PPPoEDiscovery:
return "PPPoE";
case pcpp::DNS:
return "DNS";
case pcpp::MPLS:
return "MPLS";
case pcpp::GREv0:
case pcpp::GREv1:
return "GRE";
case pcpp::PPP_PPTP:
return "PPP_PPTP";
case pcpp::SSL:
return "SSL";
case pcpp::SLL:
return "SLL";
case pcpp::DHCP:
return "DHCP";
case pcpp::NULL_LOOPBACK:
return "NULL_LOOPBACK";
case pcpp::IGMPv1:
case pcpp::IGMPv2:
case pcpp::IGMPv3:
return "IGMP";
case pcpp::GenericPayload:
return "GenericPayload";
case pcpp::VXLAN:
return "VXLAN";
case pcpp::SIPRequest:
case pcpp::SIPResponse:
return "SIP";
case pcpp::SDP:
return "SDP";
case pcpp::PacketTrailer:
return "PacketTrailer";
case pcpp::Radius:
return "Radius";
case pcpp::GTPv1:
return "GTP";
case pcpp::EthernetDot3:
return "EthernetDot3";
case pcpp::BGP:
return "BGP";
case pcpp::SSH:
return "SSH";
case pcpp::AuthenticationHeader:
case pcpp::ESP:
return "IPsec";
case pcpp::DHCPv6:
return "DHCPv6";
case pcpp::NTP:
return "NTP";
case pcpp::Telnet:
return "Telnet";
case pcpp::FTP:
return "FTP";
case pcpp::ICMPv6:
return "ICMPv6";
case pcpp::STP:
return "STP";
case pcpp::LLC:
return "LLC";
case pcpp::SomeIP:
return "SomeIP";
case pcpp::WakeOnLan:
return "WakeOnLan";
case pcpp::NFLOG:
return "NFLOG";
case pcpp::TPKT:
return "TPKT";
case pcpp::VRRPv2:
case pcpp::VRRPv3:
return "VRRP";
case pcpp::COTP:
return "COTP";
case pcpp::SLL2:
return "SLL2";
case pcpp::S7COMM:
return "S7COMM";
default:
return "Unknown";
}
}

52
packetanalyzer.h Normal file
View file

@ -0,0 +1,52 @@
#ifndef PACKETANALYZER_H
#define PACKETANALYZER_H
#include <QFileDialog>
#include <QJsonDocument>
#include <QJsonObject>
#include <QMainWindow>
#include <QMessageBox>
#include <QNetworkInterface>
#include <QNetworkReply>
#include <QTableWidgetItem>
#include <GeneralUtils.h>
#include <IPv4Layer.h>
#include <IPv6Layer.h>
#include <PcapFileDevice.h>
#include <PcapLiveDeviceList.h>
#include <SystemUtils.h>
QT_BEGIN_NAMESPACE
namespace Ui {
class PacketAnalyzer;
}
QT_END_NAMESPACE
class PacketAnalyzer : public QMainWindow
{
Q_OBJECT
public:
PacketAnalyzer(QWidget *parent = nullptr);
~PacketAnalyzer();
private slots:
void changeInterface(QString);
void refresh();
void packetSelected();
void start();
void stop();
void save();
void load();
void llmRequest();
void llmResponse(QNetworkReply *);
private:
Ui::PacketAnalyzer *ui;
pcpp::PcapLiveDevice* m_dev = nullptr;
pcpp::RawPacketVector m_packets;
QNetworkAccessManager *m_manager = new QNetworkAccessManager();
QString getProtocolTypeAsString(pcpp::ProtocolType);
void clear();
};
#endif // PACKETANALYZER_H

193
packetanalyzer.ui Normal file
View file

@ -0,0 +1,193 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PacketAnalyzer</class>
<widget class="QMainWindow" name="PacketAnalyzer">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>PacketAnalyzer</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="b_save">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Save</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="b_load">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Load</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="b_refresh">
<property name="text">
<string>Refresh</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QPushButton" name="b_start">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Start</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="b_stop">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Stop</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Interface:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cb_interfaces"/>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Packets:</string>
</property>
</widget>
</item>
<item>
<widget class="QTableWidget" name="t_packets">
<property name="editTriggers">
<set>QAbstractItemView::EditTrigger::NoEditTriggers</set>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SelectionMode::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectionBehavior::SelectRows</enum>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<property name="columnCount">
<number>5</number>
</property>
<attribute name="horizontalHeaderVisible">
<bool>true</bool>
</attribute>
<attribute name="horizontalHeaderHighlightSections">
<bool>true</bool>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderHighlightSections">
<bool>true</bool>
</attribute>
<column>
<property name="text">
<string>No.</string>
</property>
</column>
<column>
<property name="text">
<string>Source</string>
</property>
</column>
<column>
<property name="text">
<string>Destination</string>
</property>
</column>
<column>
<property name="text">
<string>Protocol</string>
</property>
</column>
<column>
<property name="text">
<string>Length</string>
</property>
</column>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Selected packet:</string>
</property>
</widget>
</item>
<item>
<widget class="QTextEdit" name="e_selected">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="b_llm">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Pass to LLM</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>25</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>