commit fd0b3b08e4ad0910a570388edd1540ed16edf186 Author: lumos Date: Sat Jun 7 23:36:39 2025 +0800 First. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..567609b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/log.h b/log.h new file mode 100644 index 0000000..04b8a90 --- /dev/null +++ b/log.h @@ -0,0 +1,80 @@ +#ifndef LOG_H +#define LOG_H + +#include // 使用 std::time 和 std::strftime +#include // 使用 printf +#include // 使用 va_list 和 va_start +#include // 使用 std::mutex + +// 定义打印等级 +#define LOG_LEVEL_DEBUG 0 +#define LOG_LEVEL_INFO 1 +#define LOG_LEVEL_WARN 2 +#define LOG_LEVEL_ERROR 3 + +// 默认日志等级为INFO +#ifndef LOG_LEVEL +#define LOG_LEVEL LOG_LEVEL_DEBUG +#endif + +// 颜色配置:用户空间启用颜色 +#define LOG_COLOR true + +// 颜色宏定义 +#if LOG_COLOR +#define RESET_COLOR "\033[0m" +#define COLOR_DEBUG "\033[34m" // 蓝色 +#define COLOR_INFO "\033[32m" // 绿色 +#define COLOR_WARN "\033[33m" // 黄色 +#define COLOR_ERROR "\033[31m" // 红色 +#else +#define RESET_COLOR "" +#define COLOR_DEBUG "" +#define COLOR_INFO "" +#define COLOR_WARN "" +#define COLOR_ERROR "" +#endif + +// 获取当前时间的字符串(用户空间实现) +inline const char* current_time() { + static char buffer[64]; + std::time_t now = std::time(nullptr); + std::tm* tm_now = std::localtime(&now); + + std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm_now); + return buffer; +} + +// 定义一个静态互斥锁,保证线程安全 +static std::mutex log_mutex; + +// 定义一个外部 FILE 变量,可以用来切换输出目标 +extern FILE* log_output; // 默认为 stdout + +// 用户空间打印日志 +#define LOG(level, format, ...) do {\ +if (level >= LOG_LEVEL) {\ + std::lock_guard lock(log_mutex); /* 自动锁住互斥锁 */\ + const char *level_str;\ + const char *color;\ + switch (level) {\ + case LOG_LEVEL_DEBUG: level_str = "[DEBUG]"; color = COLOR_DEBUG; break;\ + case LOG_LEVEL_INFO: level_str = "[INFO]"; color = COLOR_INFO; break;\ + case LOG_LEVEL_WARN: level_str = "[WARN]"; color = COLOR_WARN; break;\ + case LOG_LEVEL_ERROR: level_str = "[ERROR]"; color = COLOR_ERROR; break;\ + default: level_str = "[UNKNOWN]"; color = ""; break;\ + }\ + fprintf(log_output, "%s%s %s %s:%d - ", color, current_time(), level_str, __FILE__, __LINE__);\ + fprintf(log_output, format, ##__VA_ARGS__); /* 打印日志信息 */\ + fprintf(log_output, "%s\n", RESET_COLOR);\ + fflush(log_output); /* 强制刷新到指定输出目标 */\ +}\ +} while (0) + +// 简便宏,用于各个等级的日志 +#define LOG_DEBUG(format, ...) LOG(LOG_LEVEL_DEBUG, format, ##__VA_ARGS__) +#define LOG_INFO(format, ...) LOG(LOG_LEVEL_INFO, format, ##__VA_ARGS__) +#define LOG_WARN(format, ...) LOG(LOG_LEVEL_WARN, format, ##__VA_ARGS__) +#define LOG_ERROR(format, ...) LOG(LOG_LEVEL_ERROR, format, ##__VA_ARGS__) + +#endif // LOG_H diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..cbff9e6 --- /dev/null +++ b/main.cpp @@ -0,0 +1,12 @@ +#include "mainwindow.h" + +#include + +FILE* log_output = stdout; +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + return a.exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..f4d60b5 --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,57 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindow) +{ + ui->setupUi(this); + + +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +void MainWindow::on_pushButton_clicked() +{ + nh = new NetlinkHandler(this); + + connect(nh,&NetlinkHandler::errorOccurred,this,&MainWindow::onLogPrint); + connect(nh,&NetlinkHandler::messageReceived,this,&MainWindow::onLogRev); + + int protocalID = ui->lineEdit->text().toInt(); + nh->init(protocalID); +} + +void MainWindow::onLogPrint(const QString &msg){ + QDateTime cur = QDateTime::currentDateTime(); + QString tmp =cur.toString("yyyy-MM-dd HH:mm:ss"); + ui->textBrowser->append(tmp+" [ERROR] --> "+msg); +} + +void MainWindow::onLogRev(const QByteArray &data){ + QDateTime cur = QDateTime::currentDateTime(); + QString tmp =cur.toString("yyyy-MM-dd HH:mm:ss"); + QString data_; + for(int i =0;i(data.at(i)), 2, 16, QChar('0')); + if (i < data.size() - 1) { + data_ += " "; + } + } + + ui->textBrowser->append(tmp+" [REV] --> "+data_.toUpper()); +} + +void MainWindow::on_pushButton_2_clicked() +{ + QString tmp=ui->textEdit->toPlainText(); + nh->sendMessage(tmp.toUtf8()); + for(int i=0;i +#include "netlinkhandler.h" +#include "QDateTime" + +QT_BEGIN_NAMESPACE +namespace Ui { +class MainWindow; +} +QT_END_NAMESPACE + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + +public slots: + void onLogPrint(const QString &msg); + void onLogRev(const QByteArray &data); + +private slots: + void on_pushButton_clicked(); + + void on_pushButton_2_clicked(); + +private: + Ui::MainWindow *ui; + NetlinkHandler *nh; +}; +#endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui new file mode 100644 index 0000000..dcdeb01 --- /dev/null +++ b/mainwindow.ui @@ -0,0 +1,68 @@ + + + MainWindow + + + + 0 + 0 + 800 + 600 + + + + MainWindow + + + + + + + + + + protocol ID: + + + + + + + Init + + + + + + + Send + + + + + + + 16 + + + + + + + + + + + + 0 + 0 + 800 + 22 + + + + + + + + diff --git a/netlinkhandler.cpp b/netlinkhandler.cpp new file mode 100644 index 0000000..0c6ffe8 --- /dev/null +++ b/netlinkhandler.cpp @@ -0,0 +1,99 @@ +#include "netlinkhandler.h" +#include +#include +#include +#include +#include + +NetlinkHandler::NetlinkHandler(QObject *parent) : QObject(parent) {} + +NetlinkHandler::~NetlinkHandler() +{ + closeSocket(); +} + +bool NetlinkHandler::init(int protocol) +{ + LOG_DEBUG("protoal is %d",protocol); + if (!createSocket(protocol)) { + emit errorOccurred("Failed to create netlink socket"); + return false; + } + + m_notifier = new QSocketNotifier(m_sock, QSocketNotifier::Read, this); + connect(m_notifier, &QSocketNotifier::activated, this, &NetlinkHandler::onSocketReadyRead); + + return true; +} + +bool NetlinkHandler::createSocket(int protocol) +{ + m_sock = socket(AF_NETLINK, SOCK_RAW, protocol); + if (m_sock < 0) return false; + + sockaddr_nl local = {}; + local.nl_family = AF_NETLINK; + local.nl_pid = getpid(); // 用户态PID + local.nl_groups = 0; + + if (bind(m_sock, reinterpret_cast(&local), sizeof(local)) < 0) { + close(m_sock); + return false; + } + return true; +} + +void NetlinkHandler::closeSocket() +{ + if (m_sock >= 0) { + ::close(m_sock); + m_sock = -1; + } +} + +bool NetlinkHandler::sendMessage(const QByteArray &msg) +{ + if (m_sock < 0) return false; + + struct nlmsghdr *nlh; + struct sockaddr_nl kernel = {}; + struct iovec iov; + struct msghdr message = {}; + + char buffer[4096] = {}; + + nlh = reinterpret_cast(buffer); + nlh->nlmsg_len = NLMSG_LENGTH(msg.size()); + nlh->nlmsg_pid = getpid(); + nlh->nlmsg_flags = 0; + + memcpy(NLMSG_DATA(nlh), msg.data(), msg.size()); + + kernel.nl_family = AF_NETLINK; + + iov.iov_base = nlh; + iov.iov_len = nlh->nlmsg_len; + + message.msg_name = &kernel; + message.msg_namelen = sizeof(kernel); + message.msg_iov = &iov; + message.msg_iovlen = 1; + + return sendmsg(m_sock, &message, 0) >= 0; +} + +void NetlinkHandler::onSocketReadyRead() +{ + char buffer[4096] = {}; + int len = recv(m_sock, buffer, sizeof(buffer), 0); + if (len < 0) { + emit errorOccurred("recv failed"); + return; + } + + struct nlmsghdr *nlh = reinterpret_cast(buffer); + if (NLMSG_OK(nlh, len)) { + QByteArray data(reinterpret_cast(NLMSG_DATA(nlh)), nlh->nlmsg_len - NLMSG_HDRLEN); + emit messageReceived(data); + } +} diff --git a/netlinkhandler.h b/netlinkhandler.h new file mode 100644 index 0000000..23b3c00 --- /dev/null +++ b/netlinkhandler.h @@ -0,0 +1,35 @@ +#ifndef NETLINKHANDLER_H +#define NETLINKHANDLER_H + +#include +#include +#include +#include "log.h" + +class NetlinkHandler : public QObject +{ + Q_OBJECT +public: + explicit NetlinkHandler(QObject *parent = nullptr); + ~NetlinkHandler(); + + bool init(int protocol = 16); // 默认为 NETLINK_USERSOCK + bool sendMessage(const QByteArray &msg); + int socketFd() const { return m_sock; } + +signals: + void messageReceived(const QByteArray &msg); + void errorOccurred(const QString &err); + +private slots: + void onSocketReadyRead(); + +private: + int m_sock = -1; + QSocketNotifier *m_notifier = nullptr; + + bool createSocket(int protocol); + void closeSocket(); +}; + +#endif // NETLINKHANDLER_H diff --git a/upper_netlink.pro b/upper_netlink.pro new file mode 100644 index 0000000..114731a --- /dev/null +++ b/upper_netlink.pro @@ -0,0 +1,27 @@ +QT += core gui + +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 \ + mainwindow.cpp \ + netlinkhandler.cpp + +HEADERS += \ + log.h \ + mainwindow.h \ + netlinkhandler.h + +FORMS += \ + mainwindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/upper_netlink.pro.user b/upper_netlink.pro.user new file mode 100644 index 0000000..660e10d --- /dev/null +++ b/upper_netlink.pro.user @@ -0,0 +1,240 @@ + + + + + + EnvironmentId + {1ef3ffc4-a5a8-4c60-8a81-af3ba8bbb143} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + true + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 0 + 80 + true + true + 1 + 0 + false + true + false + 2 + true + true + 0 + 8 + true + false + 1 + true + true + true + *.md, *.MD, Makefile + false + true + true + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop Qt 5.15.2 GCC 64bit + Desktop Qt 5.15.2 GCC 64bit + qt.qt5.5152.gcc_64_kit + 0 + 0 + 0 + + 0 + /home/leo/devCode/outer/USBFilter_30/upper_netlink/build/Desktop_Qt_5_15_2_GCC_64bit-Debug + /home/leo/devCode/outer/USBFilter_30/upper_netlink/build/Desktop_Qt_5_15_2_GCC_64bit-Debug + + + true + QtProjectManager.QMakeBuildStep + false + + + + true + Qt4ProjectManager.MakeStep + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + clean + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Debug + Qt4ProjectManager.Qt4BuildConfiguration + 2 + + + /home/leo/devCode/outer/USBFilter_30/upper_netlink/build/Desktop_Qt_5_15_2_GCC_64bit-Release + /home/leo/devCode/outer/USBFilter_30/upper_netlink/build/Desktop_Qt_5_15_2_GCC_64bit-Release + + + true + QtProjectManager.QMakeBuildStep + false + + + + true + Qt4ProjectManager.MakeStep + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + clean + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Release + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 0 + + + 0 + /home/leo/devCode/outer/USBFilter_30/upper_netlink/build/Desktop_Qt_5_15_2_GCC_64bit-Profile + /home/leo/devCode/outer/USBFilter_30/upper_netlink/build/Desktop_Qt_5_15_2_GCC_64bit-Profile + + + true + QtProjectManager.QMakeBuildStep + false + + + + true + Qt4ProjectManager.MakeStep + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + clean + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Profile + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 0 + 0 + + 3 + + + 0 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + ProjectExplorer.DefaultDeployConfiguration + + 1 + + true + true + 0 + true + + 2 + + false + -e cpu-cycles --call-graph dwarf,4096 -F 250 + + ProjectExplorer.CustomExecutableRunConfiguration + + false + true + true + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 22 + + + Version + 22 + +