// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved. // Licensed under the Apache License, Version 2.0 (the "License"); // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "http_transaction_data.h" #include #include #include #include "enum_array.h" #include "sasal.h" #include "buffer.h" #include "nginx_attachment_common.h" SASAL_START // HTTP Manager - Transaction data using namespace std; USE_DEBUG_FLAG(D_NGINX_ATTACHMENT); enum class ETransactionData { HTTP_PROTO, METHOD, HOST_NAME, LISTENING_IP, LISTENING_PORT, URI, CLIENT_IP, CLIENT_PORT, COUNT }; const string HttpTransactionData::http_proto_ctx = "transaction_http_proto"; const string HttpTransactionData::method_ctx = "transaction_method"; const string HttpTransactionData::host_name_ctx = "transaction_host_name"; const string HttpTransactionData::listening_ip_ctx = "transaction_listening_ip"; const string HttpTransactionData::listening_port_ctx = "transaction_listening_port"; const string HttpTransactionData::uri_ctx = "transaction_uri"; const string HttpTransactionData::uri_path_decoded = "transaction_uri_path_decoded"; const string HttpTransactionData::uri_query_decoded = "transaction_uri_query_decoded"; const string HttpTransactionData::client_ip_ctx = "transaction_client_ip"; const string HttpTransactionData::client_port_ctx = "transaction_client_port"; const string HttpTransactionData::req_headers = "transaction_request_headers"; const string HttpTransactionData::req_body = "transaction_request_body"; const string HttpTransactionData::source_identifier = "sourceIdentifiers"; const string HttpTransactionData::proxy_ip_ctx = "proxy_ip"; const CompressionType HttpTransactionData::default_response_content_encoding = CompressionType::NO_COMPRESSION; Maybe deserializeUintParam(const Buffer &data, uint &cur_pos) { // Int value is encoded in binary form auto value = data.getTypePtr(cur_pos); if (!value.ok()) { return genError("Failed to get Uint param " + value.getErr()); } cur_pos += sizeof(uint16_t); dbgTrace(D_NGINX_ATTACHMENT) << "Successfully parsed the number parameter. Value: " << *(value.unpack()); return *(value.unpack()); } Maybe deserializeStrParam(const Buffer &data, uint &cur_pos) { //String is encoded by 16-bit uint representing length followed by const c-type string data bytes Maybe str_size = deserializeUintParam(data, cur_pos); if (!str_size.ok()) return genError("Could Not parse string size value: " + str_size.getErr()); dbgTrace(D_NGINX_ATTACHMENT) << "Deserializing string parameter. Current position: " << cur_pos << ", String size: " << *str_size; string res = ""; if (*str_size > 0) { auto value = data.getPtr(cur_pos, *str_size); if (!value.ok()) { return genError("Failed to get String param " + value.getErr()); } const u_char *ptr = value.unpack(); res = string(reinterpret_cast(ptr), *str_size); } dbgTrace(D_NGINX_ATTACHMENT) << "Successfully parsed string parameter. Result: " << res << ", Length: " << to_string(*str_size); cur_pos += *str_size; return move(res); } Maybe deserializeIpAddrParam(const Buffer &data, uint &cur_pos) { Maybe str_value = deserializeStrParam(data, cur_pos); if (!str_value.ok()) return str_value.passErr(); Maybe ip = IPAddr::createIPAddr(str_value.unpackMove()); if (!ip.ok()) return genError("Could not parse IP Address: " + ip.getErr()); return move(ip.unpackMove()); } Maybe HttpTransactionData::createTransactionData(const Buffer &transaction_raw_data) { // Deserialize TransactionData from binary blob sent from attachment uint cur_pos = 0; dbgTrace(D_NGINX_ATTACHMENT) << "Parsing buffer " << dumpHex(transaction_raw_data) << " of size " << transaction_raw_data.size(); Maybe http_protocol = deserializeStrParam(transaction_raw_data, cur_pos); if (!http_protocol.ok()) { return genError("Could not deserialize HTTP protocol: " + http_protocol.getErr()); } else { dbgTrace(D_NGINX_ATTACHMENT) << "Successfully deserialized HTTP protocol: " << http_protocol.unpack(); } Maybe http_method = deserializeStrParam(transaction_raw_data, cur_pos); if (!http_method.ok()) { return genError("Could not deserialize HTTP method: " + http_method.getErr()); } else { dbgTrace(D_NGINX_ATTACHMENT) << "Successfully deserialized HTTP method: " << http_method.unpack(); } Maybe host_name = deserializeStrParam(transaction_raw_data, cur_pos); if (!host_name.ok()) { return genError("Could not deserialize host name: " + host_name.getErr()); } else { dbgTrace(D_NGINX_ATTACHMENT) << "Successfully deserialized host name: " << host_name.unpack(); } Maybe listening_addr = deserializeIpAddrParam(transaction_raw_data, cur_pos); if (!listening_addr.ok()) { return genError("Could not deserialize listening address: " + listening_addr.getErr()); } else { dbgTrace(D_NGINX_ATTACHMENT) << "Successfully deserialized listening address: " << listening_addr.unpack(); } Maybe listening_port = deserializeUintParam(transaction_raw_data, cur_pos); if (!listening_port.ok()) { return genError("Could not deserialize listening port: " + listening_port.getErr()); } else { dbgTrace(D_NGINX_ATTACHMENT) << "Successfully deserialized listening port: " << listening_port.unpack(); } Maybe uri = deserializeStrParam(transaction_raw_data, cur_pos); if (!uri.ok()) { return genError("Could not deserialize URI: " + uri.getErr()); } else { dbgTrace(D_NGINX_ATTACHMENT) << "Successfully deserialized URI: " << uri.unpack(); } Maybe client_addr = deserializeIpAddrParam(transaction_raw_data, cur_pos); if (!client_addr.ok()) { return genError("Could not deserialize client address: " + client_addr.getErr()); } else { dbgTrace(D_NGINX_ATTACHMENT) << "Successfully deserialized client address: " << client_addr.unpack(); } Maybe client_port = deserializeUintParam(transaction_raw_data, cur_pos); if (!client_port.ok()) { return genError("Could not deserialize client port: " + client_port.getErr()); } else { dbgTrace(D_NGINX_ATTACHMENT) << "Successfully deserialized client port: " << client_port.unpack(); } // Fail if after parsing exact number of items, we didn't exactly consume whole buffer if (cur_pos != transaction_raw_data.size()) { dbgWarning(D_NGINX_ATTACHMENT) << "Nothing to deserialize, but raw data still remain"; return genError("Finished deserialization and raw data still exist - Probably corrupted buffer."); } HttpTransactionData transaction( http_protocol.unpackMove(), http_method.unpackMove(), host_name.unpackMove(), listening_addr.unpackMove(), listening_port.unpackMove(), uri.unpackMove(), client_addr.unpackMove(), client_port.unpackMove() ); return move(transaction); } HttpTransactionData::HttpTransactionData ( string _http_proto, string _method, string _host_name, IPAddr _listening_ip, uint16_t _listening_port, string _uri, IPAddr _client_ip, uint16_t _client_port ) : http_proto(move(_http_proto)), method(move(_method)), host_name(move(_host_name)), listening_ip(move(_listening_ip)), listening_port(move(_listening_port)), uri(move(_uri)), client_ip(move(_client_ip)), client_port(move(_client_port)), is_request(true), response_content_encoding(default_response_content_encoding) { } HttpTransactionData::HttpTransactionData() : HttpTransactionData::HttpTransactionData( "", "GET", "", IPAddr(), -1, "", IPAddr(), -1 ) {} void HttpTransactionData::print(ostream &out_stream) const { out_stream << http_proto << " " << method << endl; out_stream << "From: " << client_ip << ":" << client_port << endl; out_stream << "To: " << host_name << uri << " (listening on " << listening_ip << ":" << listening_port << ")" << endl; } SASAL_END