From 4f9cb7f330beab9fb09f52421b2dbd15835476e2 Mon Sep 17 00:00:00 2001 From: Joel Klinghed Date: Sun, 23 Jul 2017 01:20:04 +0200 Subject: Add proxy to GUI Access via "Setup..." in main menu Uses a socketpair to connect monitor so only proxy port is open --- src/monitor-gui.cc | 252 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 232 insertions(+), 20 deletions(-) (limited to 'src/monitor-gui.cc') 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 #include #include +#include +#include #include #include #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 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 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, + 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_; + 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( + new SetupFormDelegate(proxy_, proxy_config_.get(), proxy_logger_.get(), + monitor_.get(), main_->config(), + looper_.get(), resolver_.get())); + auto lst = std::unique_ptr( + 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( @@ -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 packages_; std::unique_ptr main_; std::unique_ptr menu_; @@ -483,6 +692,9 @@ private: std::unique_ptr looper_; std::unique_ptr resolver_; std::unique_ptr monitor_; + std::unique_ptr proxy_config_; + std::unique_ptr proxy_logger_; + std::unique_ptr proxy_; bool has_selection_; size_t selection_; }; -- cgit v1.2.3-70-g09d2