summaryrefslogtreecommitdiff
path: root/src/monitor-gui.cc
diff options
context:
space:
mode:
authorJoel Klinghed <the_jk@yahoo.com>2017-07-23 01:20:04 +0200
committerJoel Klinghed <the_jk@yahoo.com>2017-07-23 01:20:04 +0200
commit4f9cb7f330beab9fb09f52421b2dbd15835476e2 (patch)
tree328517eb3aeea310d0328c08953f57ae663e8d75 /src/monitor-gui.cc
parentc278eac390bd37c5ca8b319ed15605211822c08f (diff)
Add proxy to GUI
Access via "Setup..." in main menu Uses a socketpair to connect monitor so only proxy port is open
Diffstat (limited to 'src/monitor-gui.cc')
-rw-r--r--src/monitor-gui.cc252
1 files changed, 232 insertions, 20 deletions
diff --git a/src/monitor-gui.cc b/src/monitor-gui.cc
index fbbcfb9..c88bb8e 100644
--- a/src/monitor-gui.cc
+++ b/src/monitor-gui.cc
@@ -2,26 +2,34 @@
#include "common.hh"
+#include <fcntl.h>
#include <memory>
#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
#include <unordered_map>
#include <vector>
#include "config.hh"
#include "gui_about.hh"
+#include "gui_config.hh"
#include "gui_formapply.hh"
#include "gui_hexdump.hh"
#include "gui_listmodel.hh"
#include "gui_menu.hh"
#include "gui_main.hh"
#include "gui_statusbar.hh"
+#include "io.hh"
+#include "logger.hh"
#include "looper.hh"
#include "monitor.hh"
#include "observers.hh"
+#include "proxy.hh"
#include "resolver.hh"
namespace {
+std::string const ACTION_SETUP = "setup";
std::string const ACTION_CONNECT = "connect";
std::string const ACTION_DISCONNECT = "disconnect";
std::string const ACTION_EXIT = "exit";
@@ -223,6 +231,90 @@ const PackageList::Package PackageList::EMPTY;
// static
const std::string PackageList::empty_;
+class MemoryConfig : public GuiConfig {
+public:
+ using Config::get;
+ std::string const& get(std::string const& key,
+ std::string const& fallback) override {
+ auto it = memory_.find(key);
+ if (it == memory_.end()) return fallback;
+ return it->second;
+ }
+ char const* get(std::string const& key, char const* fallback) override {
+ auto it = memory_.find(key);
+ if (it == memory_.end()) return fallback;
+ return it->second.c_str();
+ }
+ bool is_set(std::string const& key) override {
+ return memory_.count(key);
+ }
+
+ void set(std::string const& key, std::string const& value) override {
+ memory_[key] = value;
+ }
+
+private:
+ std::unordered_map<std::string, std::string> memory_;
+};
+
+class StringLogger : public Logger {
+public:
+ void out(Level lvl, char const* format, ...) override {
+ if (lvl == DBG) {
+#ifdef NDEBUG
+ return;
+#endif
+ }
+ char* tmp;
+ va_list args;
+ va_start(args, format);
+ auto ret = vasprintf(&tmp, format, args);
+ va_end(args);
+ if (ret == -1) return;
+ switch (lvl) {
+ case ERR:
+ text_->append("Error", ATTR_ERROR);
+ break;
+ case WARN:
+ text_->append("Warning", ATTR_WARNING);
+ break;
+ case INFO:
+ text_->append("Info", ATTR_INFO);
+ break;
+ case DBG:
+ text_->append("Debug", ATTR_DEBUG);
+ break;
+ }
+ text_->append(": ");
+ text_->append(tmp, ret);
+ text_->append("\n");
+ free(tmp);
+ }
+
+ AttributedText const* text() const {
+ return text_.get();
+ }
+
+ void clear() {
+ text_->reset();
+ }
+
+ StringLogger()
+ : ATTR_ERROR(0xff, 0, 0),
+ ATTR_WARNING(0xff, 0xff, 0),
+ ATTR_INFO(),
+ ATTR_DEBUG(0, 0xff, 0),
+ text_(AttributedText::create()) {
+ }
+
+private:
+ const AttributedText::Attribute ATTR_ERROR;
+ const AttributedText::Attribute ATTR_WARNING;
+ const AttributedText::Attribute ATTR_INFO;
+ const AttributedText::Attribute ATTR_DEBUG;
+ std::unique_ptr<AttributedText> text_;
+};
+
class MonitorGui : GuiMenu::Listener, GuiMain::Listener, Monitor::Delegate {
private:
class ConnectFormListener : public GuiFormApply::Listener {
@@ -265,6 +357,82 @@ private:
Config* config_;
};
+ class SetupFormListener : public GuiFormApply::Listener {
+ public:
+ bool about_to_close(GuiForm* form) override {
+ auto const& port = form->get_string("port");
+ if (port.empty()) {
+ form->set_error("Empty proxy port");
+ return false;
+ }
+ return true;
+ }
+ };
+
+ class SetupFormDelegate : public GuiFormApply::Delegate {
+ public:
+ SetupFormDelegate(std::unique_ptr<Proxy>& proxy,
+ Config* proxy_config,
+ StringLogger* proxy_logger,
+ Monitor* monitor,
+ Config* config,
+ Looper* looper,
+ Resolver* resolver)
+ : proxy_(proxy), proxy_config_(proxy_config), proxy_logger_(proxy_logger),
+ monitor_(monitor), config_(config), looper_(looper),
+ resolver_(resolver) {
+ }
+
+ void apply(GuiFormApply* form) override {
+ auto const& bind = form->get_string("bind");
+ auto const& port = form->get_string("port");
+ if (port.empty()) {
+ form->set_error("Empty proxy port");
+ form->applied(false);
+ return;
+ }
+ config_->set("bind", bind);
+ config_->set("port", port);
+ proxy_config_->set("proxy_bind", bind);
+ proxy_config_->set("proxy_port", port);
+ proxy_config_->set("__one_single_monitor", "true");
+ io::auto_fd proxy_fd(
+ Proxy::setup_accept_socket(proxy_config_, proxy_logger_));
+ if (!proxy_fd) {
+ auto error = proxy_logger_->text()->text();
+ proxy_logger_->clear();
+ std::string errmsg =
+ "Unable to bind " + (bind.empty() ? "*" : bind) + ":" + port;
+ if (!error.empty()) errmsg += "\n" + error;
+ form->set_error(errmsg);
+ form->applied(false);
+ return;
+ }
+ int monitor_fd[2];
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, monitor_fd)) {
+ form->set_error("Unable to create socketpair");
+ form->applied(false);
+ return;
+ }
+ fcntl(monitor_fd[0], F_SETFL, O_NONBLOCK);
+ fcntl(monitor_fd[1], F_SETFL, O_NONBLOCK);
+ proxy_.reset(Proxy::create(proxy_config_, "",
+ nullptr, nullptr, proxy_logger_,
+ proxy_fd.release(), monitor_fd[0],
+ looper_, resolver_));
+ monitor_->connect(monitor_fd[1]);
+ }
+
+ private:
+ std::unique_ptr<Proxy>& proxy_;
+ Config* proxy_config_;
+ StringLogger* proxy_logger_;
+ Monitor* monitor_;
+ Config* config_;
+ Looper* looper_;
+ Resolver* resolver_;
+ };
+
public:
MonitorGui()
: packages_(new PackageList()),
@@ -275,6 +443,7 @@ public:
has_selection_(false),
selection_(0) {
auto file = menu_->add_menu("File");
+ file->add_item(ACTION_SETUP, "Setup...");
file->add_item(ACTION_CONNECT, "Connect...");
file->add_item(ACTION_DISCONNECT, "Disconnect");
file->add_separator();
@@ -318,6 +487,35 @@ public:
nullptr));
}
main_->show(about_.get());
+ } else if (id == ACTION_SETUP) {
+ setup_monitor();
+ setup_proxy();
+ proxy_logger_->clear();
+ auto dlg = std::unique_ptr<GuiFormApply::Delegate>(
+ new SetupFormDelegate(proxy_, proxy_config_.get(), proxy_logger_.get(),
+ monitor_.get(), main_->config(),
+ looper_.get(), resolver_.get()));
+ auto lst = std::unique_ptr<GuiFormApply::Listener>(
+ new SetupFormListener());
+ connect_.reset(
+ GuiFormApply::create("Setup...",
+ "Setup a proxy to start monitoring traffic."
+ " Leave bind empty to listen on all interfaces.",
+ "Setup",
+ dlg.get()));
+ connect_->add_string("bind", "Address",
+ main_->config()->get("bind", ""));
+ connect_->add_string("port", "port",
+ main_->config()->get("port", "8080"));
+ connect_->add_listener(lst.get());
+ if (connect_->show(main_.get())) {
+ monitor_->attach();
+ connect_.reset();
+ } else {
+ connect_.reset();
+ monitor_->disconnect();
+ proxy_.reset();
+ }
} else if (id == ACTION_CONNECT) {
setup_monitor();
auto dlg = std::unique_ptr<GuiFormApply::Delegate>(
@@ -343,6 +541,7 @@ public:
if (monitor_) {
monitor_->disconnect();
}
+ proxy_.reset();
} else if (id == ACTION_COPY_TEXT) {
if (!has_selection_) {
assert(false);
@@ -421,27 +620,28 @@ public:
}
bool allow_connect, allow_disconnect;
switch (state) {
- case Monitor::DISCONNECTED:
- statusbar_->set_status("Not connected");
- allow_connect = true;
- allow_disconnect = false;
- break;
- case Monitor::CONNECTED:
- statusbar_->set_status("Connected");
- allow_connect = false;
- allow_disconnect = true;
- break;
- case Monitor::CONNECTING:
- statusbar_->set_status("Connecting...");
- allow_connect = false;
- allow_disconnect = false;
- break;
- case Monitor::ATTACHED:
- statusbar_->set_status("Connected and attached");
- allow_connect = false;
- allow_disconnect = true;
- break;
+ case Monitor::DISCONNECTED:
+ statusbar_->set_status("Not connected");
+ allow_connect = true;
+ allow_disconnect = false;
+ break;
+ case Monitor::CONNECTED:
+ statusbar_->set_status("Connected");
+ allow_connect = false;
+ allow_disconnect = true;
+ break;
+ case Monitor::CONNECTING:
+ statusbar_->set_status("Connecting...");
+ allow_connect = false;
+ allow_disconnect = false;
+ break;
+ case Monitor::ATTACHED:
+ statusbar_->set_status("Connected and attached");
+ allow_connect = false;
+ allow_disconnect = true;
+ break;
}
+ menu_->enable_item(ACTION_SETUP, allow_connect);
menu_->enable_item(ACTION_CONNECT, allow_connect);
menu_->enable_item(ACTION_DISCONNECT, allow_disconnect);
}
@@ -474,6 +674,15 @@ private:
}
}
+ void setup_proxy() {
+ if (!proxy_config_) {
+ proxy_config_.reset(new MemoryConfig());
+ }
+ if (!proxy_logger_) {
+ proxy_logger_.reset(new StringLogger());
+ }
+ }
+
std::unique_ptr<PackageList> packages_;
std::unique_ptr<GuiMain> main_;
std::unique_ptr<GuiMenu> menu_;
@@ -483,6 +692,9 @@ private:
std::unique_ptr<Looper> looper_;
std::unique_ptr<Resolver> resolver_;
std::unique_ptr<Monitor> monitor_;
+ std::unique_ptr<Config> proxy_config_;
+ std::unique_ptr<StringLogger> proxy_logger_;
+ std::unique_ptr<Proxy> proxy_;
bool has_selection_;
size_t selection_;
};