From 739a6b7e069f4e6374b694ade1751663385de3df Mon Sep 17 00:00:00 2001 From: Tim Blume Date: Thu, 10 Sep 2020 21:26:41 +0200 Subject: [PATCH] added addon stubs --- CMakeLists.txt | 21 ++--- addonhandler.cpp | 66 ++++++++++++++ addonhandler.h | 61 +++++++++++++ addons/yararules/CMakeLists.txt | 9 ++ addons/yararules/yararules.cpp | 5 ++ editandresend.h | 5 +- editandresend.ui | 148 +++++++++++++++++++++++++++++++- historymodel.h | 20 ----- httpflow.h | 127 --------------------------- include/api.h | 68 +++++++++++++++ includes.h | 3 +- mainwindow.h | 2 + 12 files changed, 368 insertions(+), 167 deletions(-) create mode 100644 addonhandler.cpp create mode 100644 addonhandler.h create mode 100644 addons/yararules/CMakeLists.txt create mode 100644 addons/yararules/yararules.cpp create mode 100644 include/api.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 712c242..319624f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,19 +12,6 @@ set(CMAKE_AUTORCC ON) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) -# QtCreator supports the following variables for Android, which are identical to qmake Android variables. -# Check http://doc.qt.io/qt-5/deployment-android.html for more information. -# They need to be set before the find_package(Qt5 ...) call. - -#if(ANDROID) -# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android") -# if (ANDROID_ABI STREQUAL "armeabi-v7a") -# set(ANDROID_EXTRA_LIBS -# ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so -# ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so) -# endif() -#endif() - find_package(Qt5 COMPONENTS Widgets REQUIRED) find_package(cppzmq REQUIRED) find_package(nlohmann_json REQUIRED) @@ -39,6 +26,7 @@ add_executable(littlesnitch httpflow.cpp historymodel.cpp editandresend.cpp + addonhandler.cpp mainwindow.h httpflow.h networkthread.h @@ -46,6 +34,8 @@ add_executable(littlesnitch includes.h historymodel.h editandresend.h + addonhandler.h + include/api.h mainwindow.ui editandresend.ui ) @@ -61,6 +51,11 @@ add_executable(littlesnitch_tests target_include_directories(littlesnitch_tests PRIVATE /usr/local/include) target_link_libraries(littlesnitch_tests PRIVATE Qt5::Widgets cppzmq sqlite3 Catch2::Catch2) +file(GLOB_RECURSE addonfiles addons/CMakeLists.txt) +foreach(loopvar IN ITEMS ${addonfiles}) + include(${loopvar}) +endforeach(loopvar) + include(CTest) include(Catch) catch_discover_tests(littlesnitch_tests) diff --git a/addonhandler.cpp b/addonhandler.cpp new file mode 100644 index 0000000..8df7653 --- /dev/null +++ b/addonhandler.cpp @@ -0,0 +1,66 @@ +#include "addonhandler.h" +#include + +AddonHandler::AddonHandler() +{ + +} + +std::optional AddonHandler::load(std::filesystem::path path) +{ + // load library + void* lib = dlopen(path.c_str(), RTLD_LAZY); + if(!lib) { + qDebug() << "addon " << path.c_str() << " not loaded!"; + return std::nullopt; + } + + auto get_name = reinterpret_cast(dlsym(lib, "get_name")); + std::string name; + try { + get_name(); + } catch (...) { + return std::nullopt; + } + auto initialize = reinterpret_cast(dlsym(lib, "initialize")); + try { + if(initialize) { + initialize(); + } + } catch (...) { + return std::nullopt; + } + + on_request.append(name, dlsym(lib, "on_request")); + on_response.append(name, dlsym(lib, "on_response")); + + loaded_addon_paths.insert(std::make_pair(name, path)); + loaded_addon_libs.insert(std::make_pair(name, lib)); + + return name; +} + +void AddonHandler::unload(std::string name) +{ + on_request.remove(name); + on_response.remove(name); + void* lib = loaded_addon_libs.find(name)->second; + auto deinitialize = reinterpret_cast(dlsym(lib, "initialize")); + try { + if(deinitialize) { + deinitialize(); + } + } catch (...) { + qDebug() << "deinitialize failed"; + } +} + +bool AddonHandler::isLoaded(std::string name) +{ + return loaded_addon_libs.count(name); +} + +std::map AddonHandler::loadedAddons() +{ + return std::map(); +} diff --git a/addonhandler.h b/addonhandler.h new file mode 100644 index 0000000..46457f3 --- /dev/null +++ b/addonhandler.h @@ -0,0 +1,61 @@ +#pragma once + +#include +#include +#include + +template +class DLWrapper { +private: + std::map funcs; +public: + void append(std::string name, void* ptr) { + if(ptr) { + funcs.insert({name, ptr}); + } + } + + void remove(std::string name) { + for(auto it = funcs.begin(); it != funcs.end(); ) { + if(it->first == name) { + it = funcs.erase(it); + return; + } else { + ++it; + } + } + } + + template + void operator()(Args... args) const { + for(auto fun : funcs) { + (T)(fun)(args...); + } + } +}; + +/* +the addon handler loads addon shared library objects and calls +in every loaded addon the implemented events, when they're implemented. +*/ +class AddonHandler +{ +private: + //list of loaded addons with library pointer + std::map loaded_addon_paths; + std::map loaded_addon_libs; +public: + AddonHandler(); + // loads an addon and returns it's name, if successfully loaded + std::optional load(std::filesystem::path path); + // unload an addon + void unload(std::string name); + // returns whether an addon with name is loaded + bool isLoaded(std::string name); + // returns the list of loaded addons (name, path) + std::map loadedAddons(); + + DLWrapper on_request; + DLWrapper on_response; +}; + diff --git a/addons/yararules/CMakeLists.txt b/addons/yararules/CMakeLists.txt new file mode 100644 index 0000000..8ea8d34 --- /dev/null +++ b/addons/yararules/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.9) + +project(yararules VERSION 1.0.0 DESCRIPTION "addon for tagging using yara rules") + +add_library(yararules SHARED ${CMAKE_CURRENT_LIST_DIR}/yararules.cpp) +set_target_properties(yararules PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION 1) +target_include_directories(yararules PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../include/) diff --git a/addons/yararules/yararules.cpp b/addons/yararules/yararules.cpp new file mode 100644 index 0000000..683b3ed --- /dev/null +++ b/addons/yararules/yararules.cpp @@ -0,0 +1,5 @@ +#pragma once + +extern "C" const char* get_name() { + return "yararules"; +} diff --git a/editandresend.h b/editandresend.h index 17325de..3e24ce8 100644 --- a/editandresend.h +++ b/editandresend.h @@ -1,5 +1,4 @@ -#ifndef EDITANDRESEND_H -#define EDITANDRESEND_H +#pragma once #include @@ -18,5 +17,3 @@ public: private: Ui::EditAndResend *ui; }; - -#endif // EDITANDRESEND_H diff --git a/editandresend.ui b/editandresend.ui index d4244c2..15bbd75 100644 --- a/editandresend.ui +++ b/editandresend.ui @@ -6,13 +6,157 @@ 0 0 - 459 - 354 + 897 + 570 Dialog + + + + 9 + 9 + 871 + 100 + + + + + 1 + 1 + + + + + 400 + 100 + + + + + 1 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 730 + 20 + 80 + 23 + + + + PushButton + + + + + + 640 + 20 + 80 + 23 + + + + PushButton + + + + + + + 10 + 120 + 781 + 404 + + + + + 1 + 1 + + + + + 400 + 400 + + + + + 1 + 1 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + QLayout::SetMaximumSize + + + + + + 1 + 1 + + + + + 1 + 1 + + + + Qt::Horizontal + + + + + 1 + 1 + + + + Qt::Vertical + + + + + + + + 1 + 1 + + + + Qt::Vertical + + + + + + + + diff --git a/historymodel.h b/historymodel.h index b4b0c97..cb06cf3 100644 --- a/historymodel.h +++ b/historymodel.h @@ -5,26 +5,6 @@ #include #include -struct HistoryItem { - int id = -1; - double timestamp = 0; - std::string method; - std::string scheme; - std::string host; - unsigned short port = 0; - std::string path; - int status_code = 0; - std::string reason; - double rtt = 0.0; - size_t size = 0; - std::string request_http_version; - std::map request_headers; - std::string request_content; - std::string response_http_version; - std::map response_headers; - std::string response_content; -}; - class HistoryModel : public QAbstractTableModel { Q_OBJECT diff --git a/httpflow.h b/httpflow.h index f64d328..05e2699 100644 --- a/httpflow.h +++ b/httpflow.h @@ -2,135 +2,8 @@ #include -/* - -{ - "flow": { - "client_conn": { - "address": [ - "::1", - 37570, - 0, - 0 - ], - "alpn_proto_negotiated": "http/1.1", - "cipher_name": "TLS_AES_256_GCM_SHA384", - "clientcert": null, - "id": "a1e82917-2d58-4b99-be9e-2b962bc499b2", - "mitmcert": "mitmcertstring", - "sni": "yolo.jetzt", - "timestamp_end": null, - "timestamp_start": 1597284668.6260498, - "timestamp_tls_setup": 1597284669.8449724, - "tls_established": true, - "tls_extensions": [...], - "tls_version": "TLSv1.3" - }, - "error": null, - "id": "a6aa4e6e-ca31-4f58-bf47-2da7bfcf0000", - "intercepted": false, - "marked": false, - "metadata": {}, - "mode": "transparent", - "request": { - "content": "", - "first_line_format": "relative", - "headers": [ - [ - "Host", - "yolo.jetzt" - ], - [ - "User-Agent", - "curl/7.68.0" - ], - [ - "Accept", - ] - ], - "host": "yolo.jetzt", - "http_version": "HTTP/1.1", - "is_replay": false, - "method": "GET", - "path": "/", - "port": 443, - "scheme": "https", - "timestamp_end": 1597284669.92817, - "timestamp_start": 1597284669.8761458 - }, - "response": null, - "server_conn": { - "address": [ - "yolo.jetzt", - 443 - ], - "alpn_proto_negotiated": "http/1.1", - "cert": "certstring", - "id": "50a3b79d-2912-45f3-991b-c03406a1018f", - "ip_address": [ - "95.156.226.69", - 443 - ], - "sni": "yolo.jetzt", - "source_address": [ - "192.168.42.102", - 44949 - ], - "timestamp_end": null, - "timestamp_start": 1597284669.2133315, - "timestamp_tcp_setup": 1597284669.2892282, - "timestamp_tls_setup": 1597284669.584602, - "tls_established": true, - "tls_version": "TLSv1.2", - "via": null - }, - "type": "http", - "version": 7 - }, - "msg": "request" -} - - -*/ - namespace http { -struct Request -{ - std::string server_ip_address; - - bool tls; - std::string content; - std::string scheme; - std::string method; - std::string host; - unsigned short port; - std::string http_version; - std::string path; - double timestamp_start; - double timestamp_end; - std::vector> headers; - - std::string error; - -}; - -struct Response { - int status_code; - std::string http_version; - std::string reason; - std::string content; - double timestamp_start; - double timestamp_end; - std::vector> headers; -}; - -struct Flow { - std::string uid; - Request request; - Response response; -}; - inline void to_json(json& j, const Flow& flow) {} inline void from_json(const json& j, Flow& flow) { diff --git a/include/api.h b/include/api.h new file mode 100644 index 0000000..6ab935a --- /dev/null +++ b/include/api.h @@ -0,0 +1,68 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +struct HistoryItem { + int id = -1; + double timestamp = 0; + std::string method; + std::string scheme; + std::string host; + unsigned short port = 0; + std::string path; + int status_code = 0; + std::string reason; + double rtt = 0.0; + size_t size = 0; + std::string request_http_version; + std::map request_headers; + std::string request_content; + std::string response_http_version; + std::map response_headers; + std::string response_content; +}; + +namespace http { + +struct Request +{ + std::string server_ip_address; + + bool tls; + std::string content; + std::string scheme; + std::string method; + std::string host; + unsigned short port; + std::string http_version; + std::string path; + double timestamp_start; + double timestamp_end; + std::vector> headers; + + std::string error; + +}; + +struct Response { + int status_code; + std::string http_version; + std::string reason; + std::string content; + double timestamp_start; + double timestamp_end; + std::vector> headers; +}; + +struct Flow { + std::string uid; + Request request; + Response response; +}; + +} diff --git a/includes.h b/includes.h index 5281a57..054b16b 100644 --- a/includes.h +++ b/includes.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -12,7 +13,7 @@ using json = nlohmann::json; //major minor patch -#define LITTLESNITCH_VERSION 010 +#define LITTLESNITCH_VERSION 100 template bool json_get(json j, T& value, K key) noexcept { diff --git a/mainwindow.h b/mainwindow.h index 2f508f6..3bca165 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -5,6 +5,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } @@ -16,6 +17,7 @@ class MainWindow : public QMainWindow private: Ui::MainWindow *ui; + Ui::EditAndResend *ui_editandresend; QThread* thread; Session* current_session; HistoryModel history_model;