This commit is contained in:
End 2020-08-08 13:44:16 +02:00
parent 103011f8f7
commit b8db080960
11 changed files with 262 additions and 92 deletions

2
.gitignore vendored
View file

@ -1,6 +1,6 @@
# This file is used to ignore files which are generated # This file is used to ignore files which are generated
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
build/
*~ *~
*.autosave *.autosave
*.a *.a

View file

@ -26,21 +26,15 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt5 COMPONENTS Widgets REQUIRED) find_package(Qt5 COMPONENTS Widgets REQUIRED)
find_package(cppzmq REQUIRED) find_package(cppzmq REQUIRED)
find_package(nlohmann_json REQUIRED)
find_package(SQLite3 REQUIRED)
if(ANDROID)
add_library(littlesnitch SHARED
main.cpp
mainwindow.cpp
mainwindow.h
mainwindow.ui
)
else()
add_executable(littlesnitch add_executable(littlesnitch
main.cpp main.cpp
mainwindow.cpp mainwindow.cpp
mainwindow.h networkthread.cpp
session.cpp
mainwindow.ui mainwindow.ui
) )
endif()
target_link_libraries(littlesnitch PRIVATE Qt5::Widgets cppzmq) target_link_libraries(littlesnitch PRIVATE Qt5::Widgets cppzmq sqlite3)

View file

@ -43,44 +43,3 @@ MainWindow::~MainWindow()
void MainWindow::httpMessage(HTTPData data) { void MainWindow::httpMessage(HTTPData data) {
qDebug() << data.index; qDebug() << data.index;
} }
Worker::Worker() { // Constructor
}
Worker::~Worker() { // Destructor
}
void Worker::process() {
qDebug("thread started");
zmq::context_t ctx(1);
zmq::socket_t sock(ctx, zmq::socket_type::pair);
try {
sock.bind("tcp://127.0.0.1:12345");
} catch (zmq::error_t err) {
qDebug() << "failed binding socket" << err.what();
emit error(err.what());
return;
};
qDebug("bound socket");
while(true) {
sock.send(zmq::str_buffer("littlesnitch_init"), zmq::send_flags::dontwait);
zmq::message_t msg;
const auto ret = sock.recv(msg, zmq::recv_flags::dontwait);
if(ret) {
qDebug() << "got message: " << msg.to_string().c_str();
if(msg.to_string() == "mitmaddon") {
qDebug("connected");
while(true) {
const auto ret = sock.recv(msg, zmq::recv_flags::dontwait);
if(ret) {
qDebug() << msg.to_string().c_str();
}
}
} else {
qDebug("not connected");
}
}
}
}

View file

@ -3,6 +3,8 @@
#include <QMainWindow> #include <QMainWindow>
#include <string> #include <string>
#include <zmq.hpp> #include <zmq.hpp>
#include <nlohmann/json.hpp>
#include <sqlite3.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; } namespace Ui { class MainWindow; }
@ -22,20 +24,6 @@ public:
std::string response_content; std::string response_content;
}; };
class Worker : public QObject {
Q_OBJECT
public:
Worker();
~Worker();
public slots:
void process();
signals:
void finished();
void error(QString err);
void httpMessage(HTTPData);
private:
// add your variables here
};
class MainWindow : public QMainWindow class MainWindow : public QMainWindow
{ {

View file

@ -62,7 +62,7 @@
</item> </item>
<item row="1" column="0" colspan="2"> <item row="1" column="0" colspan="2">
<widget class="QTabWidget" name="tabWidget"> <widget class="QTabWidget" name="tabWidget">
<widget class="QWidget" name="tabWidgetPage1" native="true"> <widget class="QWidget" name="tabWidgetPage1">
<attribute name="title"> <attribute name="title">
<string/> <string/>
</attribute> </attribute>
@ -86,11 +86,46 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>800</width> <width>800</width>
<height>20</height> <height>22</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="actionNew_Session"/>
<addaction name="actionOpen_Session"/>
</widget>
<widget class="QMenu" name="menuSettings">
<property name="title">
<string>Settings</string>
</property>
<addaction name="actionSettings"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuSettings"/>
</widget> </widget>
<widget class="QStatusBar" name="statusbar"/> <widget class="QStatusBar" name="statusbar"/>
<action name="actionOpen">
<property name="text">
<string>New Session</string>
</property>
</action>
<action name="actionNew_Session">
<property name="text">
<string>New Session</string>
</property>
</action>
<action name="actionOpen_Session">
<property name="text">
<string>Open Session</string>
</property>
</action>
<action name="actionSettings">
<property name="text">
<string>Settings</string>
</property>
</action>
</widget> </widget>
<resources/> <resources/>
<connections/> <connections/>

View file

@ -5,28 +5,75 @@ import threading
from queue import Queue from queue import Queue
import time import time
import zmq import zmq
import json
NO_MSG {"msg": None}
INIT_MSG = {"msg": "init"}
ACK_MSG = {"msg": "ack"}
PING_MSG = {"msg": "ping"}
PONG_MSG = {"msg": "pong"}
def convert_to_strings(obj):
if isinstance(obj, dict):
return {convert_to_strings(key): convert_to_strings(value)
for key, value in obj.items()}
elif isinstance(obj, list) or isinstance(obj, tuple):
return [convert_to_strings(element) for element in obj]
elif isinstance(obj, bytes):
return str(obj)[2:-1]
return obj
def get_msg(socket):
msg = socket.recv()
try:
if msg:
return json.loads(msg)
except json.JSONDecodeError:
print("malformed message received '{msg}'")
return NO_MSG
def send_msg(msg, socket):
a = convert_to_strings(msg)
socket.send(str.encode(json.dumps(a)))
def networking(q): def networking(q):
print("starting thread") print("starting thread")
context = zmq.Context() context = zmq.Context()
connected = False
while not connected:
socket = context.socket(zmq.PAIR) socket = context.socket(zmq.PAIR)
socket.connect("tcp://127.0.0.1:12345") socket.connect("tcp://127.0.0.1:12345")
msg = get_msg(socket)
if msg["msg"] == "init":
send_msg(ACK_MSG, socket)
connected = True
while True: timer = time.monotonic()
print("try recv") while connected:
message = socket.recv() if timer - time.monotonic() >= 5:
if message == b"littlesnitch_init": timer = time.monotonic()
print("connected") send_msg(PING_MSG,socket)
socket.send(b"mitmaddon") msg = get_msg(socket)
while True: if msg["msg"] != "pong":
a = q.get() connected = False
print(f"got {a}")
msg = get_msg(socket)
if msg['msg'] == "ping":
send_msg(PONG_MSG, socket)
timer = time.monotonic()
a = q.get(block=False)
if a: if a:
socket.send(str.encode(a)) msg = get_msg(socket)
if msg["msg"] == "ack":
q.task_done() q.task_done()
timer = time.monotonic()
else: else:
raise ValueError("init failed") connected = False
class Counter: class Counter:
def __init__(self): def __init__(self):
@ -36,13 +83,11 @@ class Counter:
self.q.join() self.q.join()
def request(self, flow): def request(self, flow):
data = flow.request.data self.q.put(flow.get_state())
self.q.put(f"{flow.id},REQ,{data.method},{data.scheme},{data.host},{data.port},{data.path},{data.http_version},{data.headers}")
self.q.join() self.q.join()
def response(self, flow): def response(self, flow):
data = flow.response.data self.q.put(flow.get_state())
self.q.put(f"{flow.id},RES,{data.status_code},{data.http_version},{data.reason},{data.headers},{data.content},{data.timestamp_start},{data.timestamp_end}")
self.q.join() self.q.join()

39
networkthread.cpp Normal file
View file

@ -0,0 +1,39 @@
#include "networkthread.h"
NetworkThread::NetworkThread(QObject *parent) : QObject(parent)
{
}
void NetworkThread::process() {
zmq::context_t ctx(1);
zmq::socket_t sock(ctx, zmq::socket_type::pair);
try {
sock.bind("tcp://127.0.0.1:12345");
} catch (zmq::error_t err) {
qDebug() << "failed binding socket" << err.what();
emit error(err.what());
return;
};
while(true){
bool connected = false;
while(!connected) {
sock.send(zmq::str_buffer("{'type': 'init'}"), zmq::send_flags::dontwait);
zmq::message_t msg;
const auto ret = sock.recv(msg, zmq::recv_flags::dontwait);
if(ret) {
if(msg.to_string() == "{'type': 'ack'}") {
connected = true;
}
}
}
while(connected) {
const auto ret = sock.recv(msg, zmq::recv_flags::dontwait);
if(ret) {
qDebug() << msg.to_string().c_str();
}
}
}
}

18
networkthread.h Normal file
View file

@ -0,0 +1,18 @@
#pragma once
#include <QObject>
class NetworkThread : public QObject
{
Q_OBJECT
public:
explicit NetworkThread(QObject *parent = nullptr);
public slots:
void process();
signals:
void finished();
void error(QString err);
void httpMessage(HTTPData);
private:
// add your variables here
};

31
session.cpp Normal file
View file

@ -0,0 +1,31 @@
#include "session.h"
Session::Session(QObject *parent) : QObject(parent)
{
}
Session::~Session() {
unload();
}
void Session::load(std::filesystem::path path)
{
if(db) {
unload();
}
auto rc = sqlite3_open(path.c_str(), &db);
if(rc) {
qDebug("cannot open database");
qDebug(sqlite3_errmsg(db));
unload();
throw;
}
}
void Session::unload() {
if(db) {
sqlite3_close(db);
}
}

53
session.h Normal file
View file

@ -0,0 +1,53 @@
#pragma once
#include <QObject>
#include <sqlite3.h>
// static int callback(void *NotUsed, int argc, char **argv, char **azColName){
// int i;
// for(i=0; i<argc; i++){
// printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
// }
// printf("\n");
// return 0;
// }
//
// int main(int argc, char **argv){
// sqlite3 *db;
// char *zErrMsg = 0;
// int rc;
//
// if( argc!=3 ){
// fprintf(stderr, "Usage: %s DATABASE SQL-STATEMENT\n", argv[0]);
// return(1);
// }
// rc = sqlite3_open(argv[1], &db);
// if( rc ){
// fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
// sqlite3_close(db);
// return(1);
// }
// rc = sqlite3_exec(db, argv[2], callback, 0, &zErrMsg);
// if( rc!=SQLITE_OK ){
// fprintf(stderr, "SQL error: %s\n", zErrMsg);
// sqlite3_free(zErrMsg);
// }
// sqlite3_close(db);
// return 0;
// }
class Session : public QObject
{
Q_OBJECT
private:
sqlite3* db;
public:
explicit Session(QObject *parent = nullptr);
signals:
};

8
test.sh Executable file
View file

@ -0,0 +1,8 @@
#!/bin/sh
mitmdump -p 8080 -s mitmaddon/littlesnitch.py &
./build/littlesnitch &
sleep 1
curl -x http://localhost:8080 -k https://yolo.jetzt