summaryrefslogtreecommitdiff
path: root/src/proxy.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/proxy.cc')
-rw-r--r--src/proxy.cc280
1 files changed, 266 insertions, 14 deletions
diff --git a/src/proxy.cc b/src/proxy.cc
index 3582b4f..293e9be 100644
--- a/src/proxy.cc
+++ b/src/proxy.cc
@@ -317,23 +317,35 @@ public:
private:
class MitmMonitor : public Mitm::Monitor {
public:
- MitmMonitor(ProxyImpl* proxy, uint32_t local_pkg_id, uint32_t remote_pkg_id)
- : proxy_(proxy), local_pkg_id_(local_pkg_id),
- remote_pkg_id_(remote_pkg_id) {
- assert(local_pkg_id_ && remote_pkg_id_);
- }
+ typedef std::function<uint32_t(bool remote)> NewPackageIdCallback;
- void local2remote(void const* data, size_t size) override {
- proxy_->send_attached_data(local_pkg_id_, data, size, false);
- }
- void remote2local(void const* data, size_t size) override {
- proxy_->send_attached_data(remote_pkg_id_, data, size, false);
- }
+ MitmMonitor(ProxyImpl* proxy, uint32_t local_pkg_id, uint32_t remote_pkg_id,
+ NewPackageIdCallback const& new_pkg_id_callback);
+
+ void local2remote(void const* data, size_t size) override;
+ void remote2local(void const* data, size_t size) override;
private:
+ enum State {
+ NEED_MORE,
+ HTTP,
+ UNKNOWN,
+ };
+
+ size_t handle_http_data(Content* content, std::string* buffer,
+ uint32_t pkg_id, void const* data, size_t size);
+
ProxyImpl* const proxy_;
- uint32_t const local_pkg_id_;
- uint32_t const remote_pkg_id_;
+ uint32_t local_pkg_id_;
+ uint32_t remote_pkg_id_;
+ bool first_local_;
+ bool first_remote_;
+ NewPackageIdCallback const new_pkg_id_callback_;
+ State state_;
+ std::string req_buffer_;
+ Content request_;
+ std::string resp_buffer_;
+ Content response_;
};
void setup();
@@ -384,6 +396,7 @@ private:
void send_attached_data(uint32_t id, void const* ptr, size_t size, bool last);
void send_attached(void const* header, size_t header_size,
void const* data, size_t data_size);
+ uint32_t new_package_id_for_connection(size_t index, bool remote);
Config* const config_;
std::string cwd_;
@@ -1048,7 +1061,10 @@ void ProxyImpl::client_empty_input(size_t index) {
client.connect->mitm_detect = Mitm::OTHER;
} else if (client.pkg_id != 0) {
client.connect->mitm_monitor.reset(
- new MitmMonitor(this, client.pkg_id, client.remote.pkg_id));
+ new MitmMonitor(
+ this, client.pkg_id, client.remote.pkg_id,
+ std::bind(&ProxyImpl::new_package_id_for_connection,
+ this, index, std::placeholders::_1)));
}
}
}
@@ -1966,6 +1982,242 @@ int setup_socket(char const* host, std::string const& port, Logger* logger) {
return ret.release();
}
+uint32_t ProxyImpl::new_package_id_for_connection(size_t index, bool remote) {
+ auto& client = clients_[index];
+ if (remote) {
+ if (client.remote.pkg_id != 0) {
+ send_attached_data(client.remote.pkg_id, nullptr, 0, true);
+ }
+ client.remote.pkg_id = get_next_package_id();
+ if (client.remote.pkg_id != 0) {
+ send_attached_package(client.remote.pkg_id, 0,
+ client.remote.host, client.remote.port,
+ client.source_host, client.source_port, false);
+ }
+ return client.remote.pkg_id;
+ }
+
+ if (client.pkg_id != 0) {
+ send_attached_data(client.pkg_id, nullptr, 0, true);
+ }
+ client.pkg_id = get_next_package_id();
+ if (client.pkg_id != 0) {
+ send_attached_package(client.pkg_id, 0,
+ client.source_host, client.source_port,
+ client.remote.host, client.remote.port, false);
+ }
+ return client.pkg_id;
+}
+
+ProxyImpl::MitmMonitor::MitmMonitor(
+ ProxyImpl* proxy, uint32_t local_pkg_id, uint32_t remote_pkg_id,
+ NewPackageIdCallback const& new_pkg_id_callback)
+ : proxy_(proxy), local_pkg_id_(local_pkg_id),
+ remote_pkg_id_(remote_pkg_id),
+ first_local_(true),
+ first_remote_(true),
+ new_pkg_id_callback_(new_pkg_id_callback),
+ state_(NEED_MORE) {
+ assert(local_pkg_id_ && remote_pkg_id_);
+ request_.type = CONTENT_NONE;
+ response_.type = CONTENT_NONE;
+}
+
+void ProxyImpl::MitmMonitor::local2remote(void const* data, size_t size) {
+ switch (state_) {
+ case NEED_MORE:
+ case HTTP: {
+ while (size) {
+ if (state_ == HTTP && request_.type != CONTENT_NONE) {
+ auto used = handle_http_data(&request_, &req_buffer_, local_pkg_id_,
+ data, size);
+ if (used == size) return;
+ data = reinterpret_cast<char const*>(data) + used;
+ size -= used;
+ }
+ auto d = reinterpret_cast<char const*>(data);
+ std::unique_ptr<HttpRequest> req;
+ size_t offset;
+ if (req_buffer_.empty()) {
+ req.reset(HttpRequest::parse(d, size, false));
+ if (!req) {
+ req_buffer_.assign(d, size);
+ break;
+ }
+ offset = 0;
+ } else {
+ offset = req_buffer_.size();
+ req_buffer_.append(d, size);
+ req.reset(HttpRequest::parse(req_buffer_.data(),
+ req_buffer_.size(), false));
+ if (!req) break;
+ }
+ if (!req->good()) {
+ state_ = UNKNOWN;
+ req_buffer_.clear();
+ break;
+ }
+ if (!setup_content(req.get(), &request_)) {
+ state_ = UNKNOWN;
+ req_buffer_.clear();
+ break;
+ }
+ req_buffer_.clear();
+ state_ = HTTP;
+ auto used = req->size() - offset;
+ if (first_local_) {
+ first_local_ = false;
+ } else {
+ local_pkg_id_ = new_pkg_id_callback_(false);
+ }
+ if (local_pkg_id_) {
+ proxy_->send_attached_data(local_pkg_id_, data, used, false);
+ }
+ size -= used;
+ data = d + used;
+ }
+ }
+ case UNKNOWN:
+ break;
+ }
+
+ if (local_pkg_id_) {
+ proxy_->send_attached_data(local_pkg_id_, data, size, false);
+ }
+}
+
+void ProxyImpl::MitmMonitor::remote2local(void const* data, size_t size) {
+ switch (state_) {
+ case NEED_MORE:
+ // If we're already getting a response then give up on detection
+ // on request
+ state_ = UNKNOWN;
+ req_buffer_.clear();
+ break;
+ case HTTP: {
+ while (size) {
+ if (response_.type != CONTENT_NONE) {
+ auto used = handle_http_data(&response_, &resp_buffer_, remote_pkg_id_,
+ data, size);
+ if (used == size) return;
+ data = reinterpret_cast<char const*>(data) + used;
+ size -= used;
+ }
+ auto d = reinterpret_cast<char const*>(data);
+ std::unique_ptr<HttpResponse> resp;
+ size_t offset;
+ if (resp_buffer_.empty()) {
+ resp.reset(HttpResponse::parse(d, size, false));
+ if (!resp) {
+ resp_buffer_.assign(d, size);
+ break;
+ }
+ offset = 0;
+ } else {
+ offset = resp_buffer_.size();
+ resp_buffer_.append(d, size);
+ resp.reset(HttpResponse::parse(resp_buffer_.data(),
+ resp_buffer_.size(), false));
+ if (!resp) break;
+ }
+ if (!resp->good()) {
+ resp_buffer_.clear();
+ break;
+ }
+ if (!setup_content(resp.get(), &response_)) {
+ resp_buffer_.clear();
+ break;
+ }
+ resp_buffer_.clear();
+ auto used = resp->size() - offset;
+ if (first_remote_) {
+ first_remote_ = false;
+ } else {
+ remote_pkg_id_ = new_pkg_id_callback_(true);
+ }
+ if (remote_pkg_id_) {
+ proxy_->send_attached_data(remote_pkg_id_, data, used, false);
+ }
+ size -= used;
+ data = d + used;
+ }
+ }
+ case UNKNOWN:
+ break;
+ }
+
+ if (remote_pkg_id_) {
+ proxy_->send_attached_data(remote_pkg_id_, data, size, false);
+ }
+}
+
+size_t ProxyImpl::MitmMonitor::handle_http_data(Content* content,
+ std::string* buffer,
+ uint32_t pkg_id,
+ void const* data,
+ size_t size) {
+ switch (content->type) {
+ case CONTENT_NONE:
+ assert(false);
+ return 0;
+ case CONTENT_CLOSE:
+ if (pkg_id) {
+ proxy_->send_attached_data(pkg_id, data, size, false);
+ }
+ return size;
+ case CONTENT_LEN:
+ if (size < content->len) {
+ if (pkg_id) {
+ proxy_->send_attached_data(pkg_id, data, size, false);
+ }
+ content->len -= size;
+ return size;
+ }
+ if (pkg_id) {
+ // Don't set last == true even tho it is because that is handled
+ // by new_package_id_callback
+ proxy_->send_attached_data(pkg_id, data, content->len, false);
+ }
+ content->type = CONTENT_NONE;
+ return content->len;
+ case CONTENT_CHUNKED: {
+ size_t used;
+ if (buffer->empty()) {
+ used = content->chunked->add(data, size);
+ } else {
+ auto offset = buffer->size();
+ buffer->append(reinterpret_cast<char const*>(data), size);
+ used = content->chunked->add(buffer->data(), buffer->size());
+ buffer->erase(0, used);
+ used -= offset;
+ }
+ if (!content->chunked->good()) {
+ // TODO: Can we handle this better?
+ content->type = CONTENT_NONE;
+ buffer->clear();
+ return used;
+ }
+ if (pkg_id) {
+ proxy_->send_attached_data(pkg_id, data, used, false);
+ }
+ if (content->chunked->eof()) {
+ assert(buffer->size() <= size - used);
+ content->type = CONTENT_NONE;
+ buffer->clear();
+ return used;
+ }
+ if (used < size) {
+ auto d = reinterpret_cast<char const*>(data);
+ buffer->append(d + used, size - used);
+ if (pkg_id) {
+ proxy_->send_attached_data(pkg_id, d + used, size - used, false);
+ }
+ }
+ return size;
+ }
+ }
+}
+
} // namespace
// static